1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <memory>
6 
7 #include "src/base/atomic-utils.h"
8 #include "src/code-stubs.h"
9 
10 #include "src/macro-assembler.h"
11 #include "src/objects.h"
12 #include "src/property-descriptor.h"
13 #include "src/simulator.h"
14 #include "src/snapshot/snapshot.h"
15 #include "src/v8.h"
16 
17 #include "src/wasm/ast-decoder.h"
18 #include "src/wasm/module-decoder.h"
19 #include "src/wasm/wasm-js.h"
20 #include "src/wasm/wasm-module.h"
21 #include "src/wasm/wasm-objects.h"
22 #include "src/wasm/wasm-result.h"
23 
24 #include "src/compiler/wasm-compiler.h"
25 
26 using namespace v8::internal;
27 using namespace v8::internal::wasm;
28 namespace base = v8::base;
29 
30 #define TRACE(...)                                      \
31   do {                                                  \
32     if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
33   } while (false)
34 
35 #define TRACE_CHAIN(instance)        \
36   do {                               \
37     instance->PrintInstancesChain(); \
38   } while (false)
39 
40 namespace {
41 
42 static const int kInvalidSigIndex = -1;
43 static const int kPlaceholderMarker = 1000000000;
44 
raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer,int offset)45 byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) {
46   return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset;
47 }
48 
ExtractStringFromModuleBytes(Isolate * isolate,Handle<WasmCompiledModule> compiled_module,uint32_t offset,uint32_t size)49 MaybeHandle<String> ExtractStringFromModuleBytes(
50     Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
51     uint32_t offset, uint32_t size) {
52   // TODO(wasm): cache strings from modules if it's a performance win.
53   Handle<SeqOneByteString> module_bytes = compiled_module->module_bytes();
54   DCHECK_GE(static_cast<size_t>(module_bytes->length()), offset);
55   DCHECK_GE(static_cast<size_t>(module_bytes->length() - offset), size);
56   Address raw = module_bytes->GetCharsAddress() + offset;
57   if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size))
58     return {};  // UTF8 decoding error for name.
59   return isolate->factory()->NewStringFromUtf8SubString(
60       module_bytes, static_cast<int>(offset), static_cast<int>(size));
61 }
62 
ReplaceReferenceInCode(Handle<Code> code,Handle<Object> old_ref,Handle<Object> new_ref)63 void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref,
64                             Handle<Object> new_ref) {
65   for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done();
66        it.next()) {
67     if (it.rinfo()->target_object() == *old_ref) {
68       it.rinfo()->set_target_object(*new_ref);
69     }
70   }
71 }
72 
NewArrayBuffer(Isolate * isolate,size_t size)73 Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size) {
74   if (size > (WasmModule::kV8MaxPages * WasmModule::kPageSize)) {
75     // TODO(titzer): lift restriction on maximum memory allocated here.
76     return Handle<JSArrayBuffer>::null();
77   }
78   void* memory = isolate->array_buffer_allocator()->Allocate(size);
79   if (memory == nullptr) {
80     return Handle<JSArrayBuffer>::null();
81   }
82 
83 #if DEBUG
84   // Double check the API allocator actually zero-initialized the memory.
85   const byte* bytes = reinterpret_cast<const byte*>(memory);
86   for (size_t i = 0; i < size; ++i) {
87     DCHECK_EQ(0, bytes[i]);
88   }
89 #endif
90 
91   Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
92   JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size));
93   buffer->set_is_neuterable(false);
94   return buffer;
95 }
96 
RelocateMemoryReferencesInCode(Handle<FixedArray> code_table,Address old_start,Address start,uint32_t prev_size,uint32_t new_size)97 void RelocateMemoryReferencesInCode(Handle<FixedArray> code_table,
98                                     Address old_start, Address start,
99                                     uint32_t prev_size, uint32_t new_size) {
100   for (int i = 0; i < code_table->length(); ++i) {
101     DCHECK(code_table->get(i)->IsCode());
102     Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i)));
103     AllowDeferredHandleDereference embedding_raw_address;
104     int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) |
105                (1 << RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
106     for (RelocIterator it(*code, mask); !it.done(); it.next()) {
107       it.rinfo()->update_wasm_memory_reference(old_start, start, prev_size,
108                                                new_size);
109     }
110   }
111 }
112 
RelocateGlobals(Handle<FixedArray> code_table,Address old_start,Address globals_start)113 void RelocateGlobals(Handle<FixedArray> code_table, Address old_start,
114                      Address globals_start) {
115   for (int i = 0; i < code_table->length(); ++i) {
116     DCHECK(code_table->get(i)->IsCode());
117     Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i)));
118     AllowDeferredHandleDereference embedding_raw_address;
119     int mask = 1 << RelocInfo::WASM_GLOBAL_REFERENCE;
120     for (RelocIterator it(*code, mask); !it.done(); it.next()) {
121       it.rinfo()->update_wasm_global_reference(old_start, globals_start);
122     }
123   }
124 }
125 
CreatePlaceholder(Factory * factory,uint32_t index,Code::Kind kind)126 Handle<Code> CreatePlaceholder(Factory* factory, uint32_t index,
127                                Code::Kind kind) {
128   // Create a placeholder code object and encode the corresponding index in
129   // the {constant_pool_offset} field of the code object.
130   // TODO(titzer): instead of placeholders, use a reloc_info mode.
131   static byte buffer[] = {0, 0, 0, 0};  // fake instructions.
132   static CodeDesc desc = {
133       buffer, arraysize(buffer), arraysize(buffer), 0, 0, nullptr, 0, nullptr};
134   Handle<Code> code = factory->NewCode(desc, Code::KindField::encode(kind),
135                                        Handle<Object>::null());
136   code->set_constant_pool_offset(static_cast<int>(index) + kPlaceholderMarker);
137   return code;
138 }
139 
LinkFunction(Handle<Code> unlinked,std::vector<Handle<Code>> & code_table)140 bool LinkFunction(Handle<Code> unlinked,
141                   std::vector<Handle<Code>>& code_table) {
142   bool modified = false;
143   int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
144   AllowDeferredHandleDereference embedding_raw_address;
145   for (RelocIterator it(*unlinked, mode_mask); !it.done(); it.next()) {
146     RelocInfo::Mode mode = it.rinfo()->rmode();
147     if (RelocInfo::IsCodeTarget(mode)) {
148       Code* target =
149           Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
150       if (target->constant_pool_offset() < kPlaceholderMarker) continue;
151       switch (target->kind()) {
152         case Code::WASM_FUNCTION:        // fall through
153         case Code::WASM_TO_JS_FUNCTION:  // fall through
154         case Code::JS_TO_WASM_FUNCTION: {
155           // Patch direct calls to placeholder code objects.
156           uint32_t index = target->constant_pool_offset() - kPlaceholderMarker;
157           Handle<Code> new_target = code_table[index];
158           if (target != *new_target) {
159             it.rinfo()->set_target_address(new_target->instruction_start(),
160                                            UPDATE_WRITE_BARRIER,
161                                            SKIP_ICACHE_FLUSH);
162             modified = true;
163           }
164           break;
165         }
166         default:
167           break;
168       }
169     }
170   }
171   return modified;
172 }
173 
FlushICache(Isolate * isolate,Handle<FixedArray> code_table)174 void FlushICache(Isolate* isolate, Handle<FixedArray> code_table) {
175   for (int i = 0; i < code_table->length(); ++i) {
176     Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
177     Assembler::FlushICache(isolate, code->instruction_start(),
178                            code->instruction_size());
179   }
180 }
181 
182 // Fetches the compilation unit of a wasm function and executes its parallel
183 // phase.
FetchAndExecuteCompilationUnit(Isolate * isolate,std::vector<compiler::WasmCompilationUnit * > * compilation_units,std::queue<compiler::WasmCompilationUnit * > * executed_units,base::Mutex * result_mutex,base::AtomicNumber<size_t> * next_unit)184 bool FetchAndExecuteCompilationUnit(
185     Isolate* isolate,
186     std::vector<compiler::WasmCompilationUnit*>* compilation_units,
187     std::queue<compiler::WasmCompilationUnit*>* executed_units,
188     base::Mutex* result_mutex, base::AtomicNumber<size_t>* next_unit) {
189   DisallowHeapAllocation no_allocation;
190   DisallowHandleAllocation no_handles;
191   DisallowHandleDereference no_deref;
192   DisallowCodeDependencyChange no_dependency_change;
193 
194   // - 1 because AtomicIncrement returns the value after the atomic increment.
195   size_t index = next_unit->Increment(1) - 1;
196   if (index >= compilation_units->size()) {
197     return false;
198   }
199 
200   compiler::WasmCompilationUnit* unit = compilation_units->at(index);
201   if (unit != nullptr) {
202     unit->ExecuteCompilation();
203     base::LockGuard<base::Mutex> guard(result_mutex);
204     executed_units->push(unit);
205   }
206   return true;
207 }
208 
209 class WasmCompilationTask : public CancelableTask {
210  public:
WasmCompilationTask(Isolate * isolate,std::vector<compiler::WasmCompilationUnit * > * compilation_units,std::queue<compiler::WasmCompilationUnit * > * executed_units,base::Semaphore * on_finished,base::Mutex * result_mutex,base::AtomicNumber<size_t> * next_unit)211   WasmCompilationTask(
212       Isolate* isolate,
213       std::vector<compiler::WasmCompilationUnit*>* compilation_units,
214       std::queue<compiler::WasmCompilationUnit*>* executed_units,
215       base::Semaphore* on_finished, base::Mutex* result_mutex,
216       base::AtomicNumber<size_t>* next_unit)
217       : CancelableTask(isolate),
218         isolate_(isolate),
219         compilation_units_(compilation_units),
220         executed_units_(executed_units),
221         on_finished_(on_finished),
222         result_mutex_(result_mutex),
223         next_unit_(next_unit) {}
224 
RunInternal()225   void RunInternal() override {
226     while (FetchAndExecuteCompilationUnit(isolate_, compilation_units_,
227                                           executed_units_, result_mutex_,
228                                           next_unit_)) {
229     }
230     on_finished_->Signal();
231   }
232 
233   Isolate* isolate_;
234   std::vector<compiler::WasmCompilationUnit*>* compilation_units_;
235   std::queue<compiler::WasmCompilationUnit*>* executed_units_;
236   base::Semaphore* on_finished_;
237   base::Mutex* result_mutex_;
238   base::AtomicNumber<size_t>* next_unit_;
239 };
240 
RecordStats(Isolate * isolate,Code * code)241 static void RecordStats(Isolate* isolate, Code* code) {
242   isolate->counters()->wasm_generated_code_size()->Increment(code->body_size());
243   isolate->counters()->wasm_reloc_size()->Increment(
244       code->relocation_info()->length());
245 }
246 
RecordStats(Isolate * isolate,Handle<FixedArray> functions)247 static void RecordStats(Isolate* isolate, Handle<FixedArray> functions) {
248   DisallowHeapAllocation no_gc;
249   for (int i = 0; i < functions->length(); ++i) {
250     RecordStats(isolate, Code::cast(functions->get(i)));
251   }
252 }
253 
GetGlobalStartAddressFromCodeTemplate(Object * undefined,JSObject * object)254 Address GetGlobalStartAddressFromCodeTemplate(Object* undefined,
255                                               JSObject* object) {
256   auto instance = WasmInstanceObject::cast(object);
257   Address old_address = nullptr;
258   if (instance->has_globals_buffer()) {
259     old_address =
260         static_cast<Address>(instance->get_globals_buffer()->backing_store());
261   }
262   return old_address;
263 }
264 
InitializeParallelCompilation(Isolate * isolate,const std::vector<WasmFunction> & functions,std::vector<compiler::WasmCompilationUnit * > & compilation_units,ModuleEnv & module_env,ErrorThrower * thrower)265 void InitializeParallelCompilation(
266     Isolate* isolate, const std::vector<WasmFunction>& functions,
267     std::vector<compiler::WasmCompilationUnit*>& compilation_units,
268     ModuleEnv& module_env, ErrorThrower* thrower) {
269   for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) {
270     const WasmFunction* func = &functions[i];
271     compilation_units[i] =
272         func->imported ? nullptr : new compiler::WasmCompilationUnit(
273                                        thrower, isolate, &module_env, func, i);
274   }
275 }
276 
StartCompilationTasks(Isolate * isolate,std::vector<compiler::WasmCompilationUnit * > & compilation_units,std::queue<compiler::WasmCompilationUnit * > & executed_units,base::Semaphore * pending_tasks,base::Mutex & result_mutex,base::AtomicNumber<size_t> & next_unit)277 uint32_t* StartCompilationTasks(
278     Isolate* isolate,
279     std::vector<compiler::WasmCompilationUnit*>& compilation_units,
280     std::queue<compiler::WasmCompilationUnit*>& executed_units,
281     base::Semaphore* pending_tasks, base::Mutex& result_mutex,
282     base::AtomicNumber<size_t>& next_unit) {
283   const size_t num_tasks =
284       Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
285           V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
286   uint32_t* task_ids = new uint32_t[num_tasks];
287   for (size_t i = 0; i < num_tasks; ++i) {
288     WasmCompilationTask* task =
289         new WasmCompilationTask(isolate, &compilation_units, &executed_units,
290                                 pending_tasks, &result_mutex, &next_unit);
291     task_ids[i] = task->id();
292     V8::GetCurrentPlatform()->CallOnBackgroundThread(
293         task, v8::Platform::kShortRunningTask);
294   }
295   return task_ids;
296 }
297 
WaitForCompilationTasks(Isolate * isolate,uint32_t * task_ids,base::Semaphore * pending_tasks)298 void WaitForCompilationTasks(Isolate* isolate, uint32_t* task_ids,
299                              base::Semaphore* pending_tasks) {
300   const size_t num_tasks =
301       Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
302           V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
303   for (size_t i = 0; i < num_tasks; ++i) {
304     // If the task has not started yet, then we abort it. Otherwise we wait for
305     // it to finish.
306     if (isolate->cancelable_task_manager()->TryAbort(task_ids[i]) !=
307         CancelableTaskManager::kTaskAborted) {
308       pending_tasks->Wait();
309     }
310   }
311 }
312 
FinishCompilationUnits(std::queue<compiler::WasmCompilationUnit * > & executed_units,std::vector<Handle<Code>> & results,base::Mutex & result_mutex)313 void FinishCompilationUnits(
314     std::queue<compiler::WasmCompilationUnit*>& executed_units,
315     std::vector<Handle<Code>>& results, base::Mutex& result_mutex) {
316   while (true) {
317     compiler::WasmCompilationUnit* unit = nullptr;
318     {
319       base::LockGuard<base::Mutex> guard(&result_mutex);
320       if (executed_units.empty()) {
321         break;
322       }
323       unit = executed_units.front();
324       executed_units.pop();
325     }
326     int j = unit->index();
327     results[j] = unit->FinishCompilation();
328     delete unit;
329   }
330 }
331 
CompileInParallel(Isolate * isolate,const WasmModule * module,std::vector<Handle<Code>> & functions,ErrorThrower * thrower,ModuleEnv * module_env)332 void CompileInParallel(Isolate* isolate, const WasmModule* module,
333                        std::vector<Handle<Code>>& functions,
334                        ErrorThrower* thrower, ModuleEnv* module_env) {
335   // Data structures for the parallel compilation.
336   std::vector<compiler::WasmCompilationUnit*> compilation_units(
337       module->functions.size());
338   std::queue<compiler::WasmCompilationUnit*> executed_units;
339 
340   //-----------------------------------------------------------------------
341   // For parallel compilation:
342   // 1) The main thread allocates a compilation unit for each wasm function
343   //    and stores them in the vector {compilation_units}.
344   // 2) The main thread spawns {WasmCompilationTask} instances which run on
345   //    the background threads.
346   // 3.a) The background threads and the main thread pick one compilation
347   //      unit at a time and execute the parallel phase of the compilation
348   //      unit. After finishing the execution of the parallel phase, the
349   //      result is enqueued in {executed_units}.
350   // 3.b) If {executed_units} contains a compilation unit, the main thread
351   //      dequeues it and finishes the compilation.
352   // 4) After the parallel phase of all compilation units has started, the
353   //    main thread waits for all {WasmCompilationTask} instances to finish.
354   // 5) The main thread finishes the compilation.
355 
356   // Turn on the {CanonicalHandleScope} so that the background threads can
357   // use the node cache.
358   CanonicalHandleScope canonical(isolate);
359 
360   // 1) The main thread allocates a compilation unit for each wasm function
361   //    and stores them in the vector {compilation_units}.
362   InitializeParallelCompilation(isolate, module->functions, compilation_units,
363                                 *module_env, thrower);
364 
365   // Objects for the synchronization with the background threads.
366   base::Mutex result_mutex;
367   base::AtomicNumber<size_t> next_unit(
368       static_cast<size_t>(FLAG_skip_compiling_wasm_funcs));
369 
370   // 2) The main thread spawns {WasmCompilationTask} instances which run on
371   //    the background threads.
372   std::unique_ptr<uint32_t[]> task_ids(StartCompilationTasks(
373       isolate, compilation_units, executed_units, module->pending_tasks.get(),
374       result_mutex, next_unit));
375 
376   // 3.a) The background threads and the main thread pick one compilation
377   //      unit at a time and execute the parallel phase of the compilation
378   //      unit. After finishing the execution of the parallel phase, the
379   //      result is enqueued in {executed_units}.
380   while (FetchAndExecuteCompilationUnit(isolate, &compilation_units,
381                                         &executed_units, &result_mutex,
382                                         &next_unit)) {
383     // 3.b) If {executed_units} contains a compilation unit, the main thread
384     //      dequeues it and finishes the compilation unit. Compilation units
385     //      are finished concurrently to the background threads to save
386     //      memory.
387     FinishCompilationUnits(executed_units, functions, result_mutex);
388   }
389   // 4) After the parallel phase of all compilation units has started, the
390   //    main thread waits for all {WasmCompilationTask} instances to finish.
391   WaitForCompilationTasks(isolate, task_ids.get(), module->pending_tasks.get());
392   // Finish the compilation of the remaining compilation units.
393   FinishCompilationUnits(executed_units, functions, result_mutex);
394 }
395 
CompileSequentially(Isolate * isolate,const WasmModule * module,std::vector<Handle<Code>> & functions,ErrorThrower * thrower,ModuleEnv * module_env)396 void CompileSequentially(Isolate* isolate, const WasmModule* module,
397                          std::vector<Handle<Code>>& functions,
398                          ErrorThrower* thrower, ModuleEnv* module_env) {
399   DCHECK(!thrower->error());
400 
401   for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
402        i < module->functions.size(); ++i) {
403     const WasmFunction& func = module->functions[i];
404     if (func.imported) continue;  // Imports are compiled at instantiation time.
405 
406     WasmName str = module->GetName(func.name_offset, func.name_length);
407     Handle<Code> code = Handle<Code>::null();
408     // Compile the function.
409     code = compiler::WasmCompilationUnit::CompileWasmFunction(
410         thrower, isolate, module_env, &func);
411     if (code.is_null()) {
412       thrower->CompileError("Compilation of #%d:%.*s failed.", i, str.length(),
413                             str.start());
414       break;
415     }
416       // Install the code into the linker table.
417     functions[i] = code;
418   }
419 }
420 
PatchDirectCalls(Handle<FixedArray> old_functions,Handle<FixedArray> new_functions,int start)421 void PatchDirectCalls(Handle<FixedArray> old_functions,
422                       Handle<FixedArray> new_functions, int start) {
423   DCHECK_EQ(new_functions->length(), old_functions->length());
424 
425   DisallowHeapAllocation no_gc;
426   std::map<Code*, Code*> old_to_new_code;
427   for (int i = 0; i < new_functions->length(); ++i) {
428     old_to_new_code.insert(std::make_pair(Code::cast(old_functions->get(i)),
429                                           Code::cast(new_functions->get(i))));
430   }
431   int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
432   AllowDeferredHandleDereference embedding_raw_address;
433   for (int i = start; i < new_functions->length(); ++i) {
434     Code* wasm_function = Code::cast(new_functions->get(i));
435     for (RelocIterator it(wasm_function, mode_mask); !it.done(); it.next()) {
436       Code* old_code =
437           Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
438       if (old_code->kind() == Code::WASM_TO_JS_FUNCTION ||
439           old_code->kind() == Code::WASM_FUNCTION) {
440         auto found = old_to_new_code.find(old_code);
441         DCHECK(found != old_to_new_code.end());
442         Code* new_code = found->second;
443         if (new_code != old_code) {
444           it.rinfo()->set_target_address(new_code->instruction_start(),
445                                          UPDATE_WRITE_BARRIER,
446                                          SKIP_ICACHE_FLUSH);
447         }
448       }
449     }
450   }
451 }
452 
ResetCompiledModule(Isolate * isolate,WasmInstanceObject * owner,WasmCompiledModule * compiled_module)453 static void ResetCompiledModule(Isolate* isolate, WasmInstanceObject* owner,
454                                 WasmCompiledModule* compiled_module) {
455   TRACE("Resetting %d\n", compiled_module->instance_id());
456   Object* undefined = *isolate->factory()->undefined_value();
457   uint32_t old_mem_size = compiled_module->mem_size();
458   uint32_t default_mem_size = compiled_module->default_mem_size();
459   Object* mem_start = compiled_module->ptr_to_memory();
460   Address old_mem_address = nullptr;
461   Address globals_start =
462       GetGlobalStartAddressFromCodeTemplate(undefined, owner);
463 
464   // Reset function tables.
465   FixedArray* function_tables = nullptr;
466   FixedArray* empty_function_tables = nullptr;
467   if (compiled_module->has_function_tables()) {
468     function_tables = compiled_module->ptr_to_function_tables();
469     empty_function_tables = compiled_module->ptr_to_empty_function_tables();
470     compiled_module->set_ptr_to_function_tables(empty_function_tables);
471   }
472 
473   if (old_mem_size > 0) {
474     CHECK_NE(mem_start, undefined);
475     old_mem_address =
476         static_cast<Address>(JSArrayBuffer::cast(mem_start)->backing_store());
477   }
478   int mode_mask = RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_REFERENCE) |
479                   RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE) |
480                   RelocInfo::ModeMask(RelocInfo::WASM_GLOBAL_REFERENCE) |
481                   RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
482 
483   // Patch code to update memory references, global references, and function
484   // table references.
485   Object* fct_obj = compiled_module->ptr_to_code_table();
486   if (fct_obj != nullptr && fct_obj != undefined &&
487       (old_mem_size > 0 || globals_start != nullptr || function_tables)) {
488     FixedArray* functions = FixedArray::cast(fct_obj);
489     for (int i = 0; i < functions->length(); ++i) {
490       Code* code = Code::cast(functions->get(i));
491       bool changed = false;
492       for (RelocIterator it(code, mode_mask); !it.done(); it.next()) {
493         RelocInfo::Mode mode = it.rinfo()->rmode();
494         if (RelocInfo::IsWasmMemoryReference(mode) ||
495             RelocInfo::IsWasmMemorySizeReference(mode)) {
496           it.rinfo()->update_wasm_memory_reference(
497               old_mem_address, nullptr, old_mem_size, default_mem_size);
498           changed = true;
499         } else if (RelocInfo::IsWasmGlobalReference(mode)) {
500           it.rinfo()->update_wasm_global_reference(globals_start, nullptr);
501           changed = true;
502         } else if (RelocInfo::IsEmbeddedObject(mode) && function_tables) {
503           Object* old = it.rinfo()->target_object();
504           for (int j = 0; j < function_tables->length(); ++j) {
505             if (function_tables->get(j) == old) {
506               it.rinfo()->set_target_object(empty_function_tables->get(j));
507               changed = true;
508             }
509           }
510         }
511       }
512       if (changed) {
513         Assembler::FlushICache(isolate, code->instruction_start(),
514                                code->instruction_size());
515       }
516     }
517   }
518   compiled_module->reset_memory();
519 }
520 
InstanceFinalizer(const v8::WeakCallbackInfo<void> & data)521 static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
522   JSObject** p = reinterpret_cast<JSObject**>(data.GetParameter());
523   WasmInstanceObject* owner = reinterpret_cast<WasmInstanceObject*>(*p);
524   WasmCompiledModule* compiled_module = owner->get_compiled_module();
525   TRACE("Finalizing %d {\n", compiled_module->instance_id());
526   Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate());
527   DCHECK(compiled_module->has_weak_wasm_module());
528   WeakCell* weak_wasm_module = compiled_module->ptr_to_weak_wasm_module();
529 
530   // weak_wasm_module may have been cleared, meaning the module object
531   // was GC-ed. In that case, there won't be any new instances created,
532   // and we don't need to maintain the links between instances.
533   if (!weak_wasm_module->cleared()) {
534     JSObject* wasm_module = JSObject::cast(weak_wasm_module->value());
535     WasmCompiledModule* current_template =
536         WasmCompiledModule::cast(wasm_module->GetInternalField(0));
537 
538     TRACE("chain before {\n");
539     TRACE_CHAIN(current_template);
540     TRACE("}\n");
541 
542     DCHECK(!current_template->has_weak_prev_instance());
543     WeakCell* next = compiled_module->ptr_to_weak_next_instance();
544     WeakCell* prev = compiled_module->ptr_to_weak_prev_instance();
545 
546     if (current_template == compiled_module) {
547       if (next == nullptr) {
548         ResetCompiledModule(isolate, owner, compiled_module);
549       } else {
550         DCHECK(next->value()->IsFixedArray());
551         wasm_module->SetInternalField(0, next->value());
552         DCHECK_NULL(prev);
553         WasmCompiledModule::cast(next->value())->reset_weak_prev_instance();
554       }
555     } else {
556       DCHECK(!(prev == nullptr && next == nullptr));
557       // the only reason prev or next would be cleared is if the
558       // respective objects got collected, but if that happened,
559       // we would have relinked the list.
560       if (prev != nullptr) {
561         DCHECK(!prev->cleared());
562         if (next == nullptr) {
563           WasmCompiledModule::cast(prev->value())->reset_weak_next_instance();
564         } else {
565           WasmCompiledModule::cast(prev->value())
566               ->set_ptr_to_weak_next_instance(next);
567         }
568       }
569       if (next != nullptr) {
570         DCHECK(!next->cleared());
571         if (prev == nullptr) {
572           WasmCompiledModule::cast(next->value())->reset_weak_prev_instance();
573         } else {
574           WasmCompiledModule::cast(next->value())
575               ->set_ptr_to_weak_prev_instance(prev);
576         }
577       }
578     }
579     TRACE("chain after {\n");
580     TRACE_CHAIN(WasmCompiledModule::cast(wasm_module->GetInternalField(0)));
581     TRACE("}\n");
582   }
583   compiled_module->reset_weak_owning_instance();
584   GlobalHandles::Destroy(reinterpret_cast<Object**>(p));
585   TRACE("}\n");
586 }
587 
GetFunctionOffsetAndLength(Handle<WasmCompiledModule> compiled_module,int func_index)588 std::pair<int, int> GetFunctionOffsetAndLength(
589     Handle<WasmCompiledModule> compiled_module, int func_index) {
590   WasmModule* module = compiled_module->module();
591   if (func_index < 0 ||
592       static_cast<size_t>(func_index) > module->functions.size()) {
593     return {0, 0};
594   }
595   WasmFunction& func = module->functions[func_index];
596   return {static_cast<int>(func.code_start_offset),
597           static_cast<int>(func.code_end_offset - func.code_start_offset)};
598 }
599 
600 }  // namespace
601 
SectionName(WasmSectionCode code)602 const char* wasm::SectionName(WasmSectionCode code) {
603   switch (code) {
604     case kUnknownSectionCode:
605       return "Unknown";
606     case kTypeSectionCode:
607       return "Type";
608     case kImportSectionCode:
609       return "Import";
610     case kFunctionSectionCode:
611       return "Function";
612     case kTableSectionCode:
613       return "Table";
614     case kMemorySectionCode:
615       return "Memory";
616     case kGlobalSectionCode:
617       return "Global";
618     case kExportSectionCode:
619       return "Export";
620     case kStartSectionCode:
621       return "Start";
622     case kCodeSectionCode:
623       return "Code";
624     case kElementSectionCode:
625       return "Element";
626     case kDataSectionCode:
627       return "Data";
628     case kNameSectionCode:
629       return "Name";
630     default:
631       return "<unknown>";
632   }
633 }
634 
operator <<(std::ostream & os,const WasmModule & module)635 std::ostream& wasm::operator<<(std::ostream& os, const WasmModule& module) {
636   os << "WASM module with ";
637   os << (module.min_mem_pages * module.kPageSize) << " min mem";
638   os << (module.max_mem_pages * module.kPageSize) << " max mem";
639   os << module.functions.size() << " functions";
640   os << module.functions.size() << " globals";
641   os << module.functions.size() << " data segments";
642   return os;
643 }
644 
operator <<(std::ostream & os,const WasmFunction & function)645 std::ostream& wasm::operator<<(std::ostream& os, const WasmFunction& function) {
646   os << "WASM function with signature " << *function.sig;
647 
648   os << " code bytes: "
649      << (function.code_end_offset - function.code_start_offset);
650   return os;
651 }
652 
operator <<(std::ostream & os,const WasmFunctionName & pair)653 std::ostream& wasm::operator<<(std::ostream& os, const WasmFunctionName& pair) {
654   os << "#" << pair.function_->func_index << ":";
655   if (pair.function_->name_offset > 0) {
656     if (pair.module_) {
657       WasmName name = pair.module_->GetName(pair.function_->name_offset,
658                                             pair.function_->name_length);
659       os.write(name.start(), name.length());
660     } else {
661       os << "+" << pair.function_->func_index;
662     }
663   } else {
664     os << "?";
665   }
666   return os;
667 }
668 
GetOwningWasmInstance(Code * code)669 Object* wasm::GetOwningWasmInstance(Code* code) {
670   DCHECK(code->kind() == Code::WASM_FUNCTION);
671   DisallowHeapAllocation no_gc;
672   FixedArray* deopt_data = code->deoptimization_data();
673   DCHECK_NOT_NULL(deopt_data);
674   DCHECK(deopt_data->length() == 2);
675   Object* weak_link = deopt_data->get(0);
676   if (!weak_link->IsWeakCell()) return nullptr;
677   WeakCell* cell = WeakCell::cast(weak_link);
678   return cell->value();
679 }
680 
GetFunctionCodeOffset(Handle<WasmCompiledModule> compiled_module,int func_index)681 int wasm::GetFunctionCodeOffset(Handle<WasmCompiledModule> compiled_module,
682                                 int func_index) {
683   return GetFunctionOffsetAndLength(compiled_module, func_index).first;
684 }
685 
GetPositionInfo(Handle<WasmCompiledModule> compiled_module,uint32_t position,Script::PositionInfo * info)686 bool wasm::GetPositionInfo(Handle<WasmCompiledModule> compiled_module,
687                            uint32_t position, Script::PositionInfo* info) {
688   std::vector<WasmFunction>& functions = compiled_module->module()->functions;
689 
690   // Binary search for a function containing the given position.
691   int left = 0;                                    // inclusive
692   int right = static_cast<int>(functions.size());  // exclusive
693   if (right == 0) return false;
694   while (right - left > 1) {
695     int mid = left + (right - left) / 2;
696     if (functions[mid].code_start_offset <= position) {
697       left = mid;
698     } else {
699       right = mid;
700     }
701   }
702   // If the found entry does not contains the given position, return false.
703   WasmFunction& func = functions[left];
704   if (position < func.code_start_offset || position >= func.code_end_offset) {
705     return false;
706   }
707 
708   info->line = left;
709   info->column = position - func.code_start_offset;
710   info->line_start = func.code_start_offset;
711   info->line_end = func.code_end_offset;
712   return true;
713 }
714 
WasmModule(Zone * owned,const byte * module_start)715 WasmModule::WasmModule(Zone* owned, const byte* module_start)
716     : owned_zone(owned),
717       module_start(module_start),
718       pending_tasks(new base::Semaphore(0)) {}
719 
CompileFunctions(Isolate * isolate,Handle<WasmModuleWrapper> module_wrapper,ErrorThrower * thrower) const720 MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
721     Isolate* isolate, Handle<WasmModuleWrapper> module_wrapper,
722     ErrorThrower* thrower) const {
723   Factory* factory = isolate->factory();
724 
725   MaybeHandle<WasmCompiledModule> nothing;
726 
727   WasmInstance temp_instance(this);
728   temp_instance.context = isolate->native_context();
729   temp_instance.mem_size = WasmModule::kPageSize * this->min_mem_pages;
730   temp_instance.mem_start = nullptr;
731   temp_instance.globals_start = nullptr;
732 
733   // Initialize the indirect tables with placeholders.
734   int function_table_count = static_cast<int>(this->function_tables.size());
735   Handle<FixedArray> function_tables =
736       factory->NewFixedArray(function_table_count);
737   for (int i = 0; i < function_table_count; ++i) {
738     temp_instance.function_tables[i] = factory->NewFixedArray(0);
739     function_tables->set(i, *temp_instance.function_tables[i]);
740   }
741 
742   HistogramTimerScope wasm_compile_module_time_scope(
743       isolate->counters()->wasm_compile_module_time());
744 
745   ModuleEnv module_env;
746   module_env.module = this;
747   module_env.instance = &temp_instance;
748   module_env.origin = origin;
749 
750   // The {code_table} array contains import wrappers and functions (which
751   // are both included in {functions.size()}, and export wrappers.
752   int code_table_size =
753       static_cast<int>(functions.size() + num_exported_functions);
754   Handle<FixedArray> code_table =
755       factory->NewFixedArray(static_cast<int>(code_table_size), TENURED);
756 
757   // Initialize the code table with placeholders.
758   for (uint32_t i = 0; i < functions.size(); ++i) {
759     Code::Kind kind = Code::WASM_FUNCTION;
760     if (i < num_imported_functions) kind = Code::WASM_TO_JS_FUNCTION;
761     Handle<Code> placeholder = CreatePlaceholder(factory, i, kind);
762     code_table->set(static_cast<int>(i), *placeholder);
763     temp_instance.function_code[i] = placeholder;
764   }
765 
766   isolate->counters()->wasm_functions_per_module()->AddSample(
767       static_cast<int>(functions.size()));
768   if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) {
769     // Avoid a race condition by collecting results into a second vector.
770     std::vector<Handle<Code>> results;
771     results.reserve(temp_instance.function_code.size());
772     for (size_t i = 0; i < temp_instance.function_code.size(); ++i) {
773       results.push_back(temp_instance.function_code[i]);
774     }
775     CompileInParallel(isolate, this, results, thrower, &module_env);
776 
777     for (size_t i = 0; i < results.size(); ++i) {
778       temp_instance.function_code[i] = results[i];
779     }
780   } else {
781     CompileSequentially(isolate, this, temp_instance.function_code, thrower,
782                         &module_env);
783   }
784   if (thrower->error()) return nothing;
785 
786   // At this point, compilation has completed. Update the code table.
787   for (size_t i = FLAG_skip_compiling_wasm_funcs;
788        i < temp_instance.function_code.size(); ++i) {
789     Code* code = *temp_instance.function_code[i];
790     code_table->set(static_cast<int>(i), code);
791   }
792 
793   // Link the functions in the module.
794   for (size_t i = FLAG_skip_compiling_wasm_funcs;
795        i < temp_instance.function_code.size(); ++i) {
796     Handle<Code> code = temp_instance.function_code[i];
797     bool modified = LinkFunction(code, temp_instance.function_code);
798     if (modified) {
799       // TODO(mtrofin): do we need to flush the cache here?
800       Assembler::FlushICache(isolate, code->instruction_start(),
801                              code->instruction_size());
802     }
803   }
804 
805   // Create the compiled module object, and populate with compiled functions
806   // and information needed at instantiation time. This object needs to be
807   // serializable. Instantiation may occur off a deserialized version of this
808   // object.
809   Handle<WasmCompiledModule> ret =
810       WasmCompiledModule::New(isolate, module_wrapper);
811   ret->set_code_table(code_table);
812   ret->set_min_mem_pages(min_mem_pages);
813   ret->set_max_mem_pages(max_mem_pages);
814   if (function_table_count > 0) {
815     ret->set_function_tables(function_tables);
816     ret->set_empty_function_tables(function_tables);
817   }
818 
819   // Compile JS->WASM wrappers for exported functions.
820   int func_index = 0;
821   for (auto exp : export_table) {
822     if (exp.kind != kExternalFunction) continue;
823     Handle<Code> wasm_code =
824         code_table->GetValueChecked<Code>(isolate, exp.index);
825     Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper(
826         isolate, &module_env, wasm_code, exp.index);
827     int export_index = static_cast<int>(functions.size() + func_index);
828     code_table->set(export_index, *wrapper_code);
829     func_index++;
830   }
831 
832   {
833     // TODO(wasm): only save the sections necessary to deserialize a
834     // {WasmModule}. E.g. function bodies could be omitted.
835     size_t module_bytes_len = module_end - module_start;
836     DCHECK_LE(module_bytes_len, static_cast<size_t>(kMaxInt));
837     Vector<const uint8_t> module_bytes_vec(module_start,
838                                            static_cast<int>(module_bytes_len));
839     Handle<String> module_bytes_string =
840         factory->NewStringFromOneByte(module_bytes_vec, TENURED)
841             .ToHandleChecked();
842     DCHECK(module_bytes_string->IsSeqOneByteString());
843     ret->set_module_bytes(Handle<SeqOneByteString>::cast(module_bytes_string));
844   }
845 
846   return ret;
847 }
848 
GetWasmFunctionForImportWrapper(Isolate * isolate,Handle<Object> target)849 static WasmFunction* GetWasmFunctionForImportWrapper(Isolate* isolate,
850                                                      Handle<Object> target) {
851   if (target->IsJSFunction()) {
852     Handle<JSFunction> func = Handle<JSFunction>::cast(target);
853     if (func->code()->kind() == Code::JS_TO_WASM_FUNCTION) {
854       auto exported = Handle<WasmExportedFunction>::cast(func);
855       Handle<WasmInstanceObject> other_instance(exported->instance(), isolate);
856       int func_index = exported->function_index();
857       return &other_instance->module()->functions[func_index];
858     }
859   }
860   return nullptr;
861 }
862 
UnwrapImportWrapper(Handle<Object> target)863 static Handle<Code> UnwrapImportWrapper(Handle<Object> target) {
864   Handle<JSFunction> func = Handle<JSFunction>::cast(target);
865   Handle<Code> export_wrapper_code = handle(func->code());
866   int found = 0;
867   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
868   Handle<Code> code;
869   for (RelocIterator it(*export_wrapper_code, mask); !it.done(); it.next()) {
870     RelocInfo* rinfo = it.rinfo();
871     Address target_address = rinfo->target_address();
872     Code* target = Code::GetCodeFromTargetAddress(target_address);
873     if (target->kind() == Code::WASM_FUNCTION ||
874         target->kind() == Code::WASM_TO_JS_FUNCTION) {
875       ++found;
876       code = handle(target);
877     }
878   }
879   DCHECK(found == 1);
880   return code;
881 }
882 
CompileImportWrapper(Isolate * isolate,int index,FunctionSig * sig,Handle<JSReceiver> target,Handle<String> module_name,MaybeHandle<String> import_name)883 static Handle<Code> CompileImportWrapper(Isolate* isolate, int index,
884                                          FunctionSig* sig,
885                                          Handle<JSReceiver> target,
886                                          Handle<String> module_name,
887                                          MaybeHandle<String> import_name) {
888   Handle<Code> code;
889   WasmFunction* other_func = GetWasmFunctionForImportWrapper(isolate, target);
890   if (other_func) {
891     if (sig->Equals(other_func->sig)) {
892       // Signature matched. Unwrap the JS->WASM wrapper and return the raw
893       // WASM function code.
894       return UnwrapImportWrapper(target);
895     } else {
896       return Handle<Code>::null();
897     }
898   } else {
899     // Signature mismatch. Compile a new wrapper for the new signature.
900     return compiler::CompileWasmToJSWrapper(isolate, target, sig, index,
901                                             module_name, import_name);
902   }
903 }
904 
UpdateDispatchTablesInternal(Isolate * isolate,Handle<FixedArray> dispatch_tables,int index,WasmFunction * function,Handle<Code> code)905 static void UpdateDispatchTablesInternal(Isolate* isolate,
906                                          Handle<FixedArray> dispatch_tables,
907                                          int index, WasmFunction* function,
908                                          Handle<Code> code) {
909   DCHECK_EQ(0, dispatch_tables->length() % 3);
910   for (int i = 0; i < dispatch_tables->length(); i += 3) {
911     int table_index = Smi::cast(dispatch_tables->get(i + 1))->value();
912     Handle<FixedArray> dispatch_table(
913         FixedArray::cast(dispatch_tables->get(i + 2)), isolate);
914     if (function) {
915       // TODO(titzer): the signature might need to be copied to avoid
916       // a dangling pointer in the signature map.
917       Handle<WasmInstanceObject> instance(
918           WasmInstanceObject::cast(dispatch_tables->get(i)), isolate);
919       int sig_index = static_cast<int>(
920           instance->module()->function_tables[table_index].map.FindOrInsert(
921               function->sig));
922       dispatch_table->set(index, Smi::FromInt(sig_index));
923       dispatch_table->set(index + (dispatch_table->length() / 2), *code);
924     } else {
925       Code* code = nullptr;
926       dispatch_table->set(index, Smi::FromInt(-1));
927       dispatch_table->set(index + (dispatch_table->length() / 2), code);
928     }
929   }
930 }
931 
UpdateDispatchTables(Isolate * isolate,Handle<FixedArray> dispatch_tables,int index,Handle<JSFunction> function)932 void wasm::UpdateDispatchTables(Isolate* isolate,
933                                 Handle<FixedArray> dispatch_tables, int index,
934                                 Handle<JSFunction> function) {
935   if (function.is_null()) {
936     UpdateDispatchTablesInternal(isolate, dispatch_tables, index, nullptr,
937                                  Handle<Code>::null());
938   } else {
939     UpdateDispatchTablesInternal(
940         isolate, dispatch_tables, index,
941         GetWasmFunctionForImportWrapper(isolate, function),
942         UnwrapImportWrapper(function));
943   }
944 }
945 
946 // A helper class to simplify instantiating a module from a compiled module.
947 // It closes over the {Isolate}, the {ErrorThrower}, the {WasmCompiledModule},
948 // etc.
949 class WasmInstanceBuilder {
950  public:
WasmInstanceBuilder(Isolate * isolate,ErrorThrower * thrower,Handle<JSObject> module_object,Handle<JSReceiver> ffi,Handle<JSArrayBuffer> memory)951   WasmInstanceBuilder(Isolate* isolate, ErrorThrower* thrower,
952                       Handle<JSObject> module_object, Handle<JSReceiver> ffi,
953                       Handle<JSArrayBuffer> memory)
954       : isolate_(isolate),
955         thrower_(thrower),
956         module_object_(module_object),
957         ffi_(ffi),
958         memory_(memory) {}
959 
960   // Build an instance, in all of its glory.
Build()961   MaybeHandle<JSObject> Build() {
962     MaybeHandle<JSObject> nothing;
963     HistogramTimerScope wasm_instantiate_module_time_scope(
964         isolate_->counters()->wasm_instantiate_module_time());
965     Factory* factory = isolate_->factory();
966 
967     //--------------------------------------------------------------------------
968     // Reuse the compiled module (if no owner), otherwise clone.
969     //--------------------------------------------------------------------------
970     Handle<FixedArray> code_table;
971     Handle<FixedArray> old_code_table;
972     MaybeHandle<WasmInstanceObject> owner;
973 
974     TRACE("Starting new module instantiation\n");
975     {
976       // Root the owner, if any, before doing any allocations, which
977       // may trigger GC.
978       // Both owner and original template need to be in sync. Even
979       // after we lose the original template handle, the code
980       // objects we copied from it have data relative to the
981       // instance - such as globals addresses.
982       Handle<WasmCompiledModule> original;
983       {
984         DisallowHeapAllocation no_gc;
985         original = handle(
986             WasmCompiledModule::cast(module_object_->GetInternalField(0)));
987         if (original->has_weak_owning_instance()) {
988           owner = handle(WasmInstanceObject::cast(
989               original->weak_owning_instance()->value()));
990         }
991       }
992       DCHECK(!original.is_null());
993       // Always make a new copy of the code_table, since the old_code_table
994       // may still have placeholders for imports.
995       old_code_table = original->code_table();
996       code_table = factory->CopyFixedArray(old_code_table);
997 
998       if (original->has_weak_owning_instance()) {
999         // Clone, but don't insert yet the clone in the instances chain.
1000         // We do that last. Since we are holding on to the owner instance,
1001         // the owner + original state used for cloning and patching
1002         // won't be mutated by possible finalizer runs.
1003         DCHECK(!owner.is_null());
1004         TRACE("Cloning from %d\n", original->instance_id());
1005         compiled_module_ = WasmCompiledModule::Clone(isolate_, original);
1006         // Avoid creating too many handles in the outer scope.
1007         HandleScope scope(isolate_);
1008 
1009         // Clone the code for WASM functions and exports.
1010         for (int i = 0; i < code_table->length(); ++i) {
1011           Handle<Code> orig_code =
1012               code_table->GetValueChecked<Code>(isolate_, i);
1013           switch (orig_code->kind()) {
1014             case Code::WASM_TO_JS_FUNCTION:
1015               // Imports will be overwritten with newly compiled wrappers.
1016               break;
1017             case Code::JS_TO_WASM_FUNCTION:
1018             case Code::WASM_FUNCTION: {
1019               Handle<Code> code = factory->CopyCode(orig_code);
1020               code_table->set(i, *code);
1021               break;
1022             }
1023             default:
1024               UNREACHABLE();
1025           }
1026         }
1027         RecordStats(isolate_, code_table);
1028       } else {
1029         // There was no owner, so we can reuse the original.
1030         compiled_module_ = original;
1031         TRACE("Reusing existing instance %d\n",
1032               compiled_module_->instance_id());
1033       }
1034       compiled_module_->set_code_table(code_table);
1035     }
1036     module_ = reinterpret_cast<WasmModuleWrapper*>(
1037                   *compiled_module_->module_wrapper())
1038                   ->get();
1039 
1040     //--------------------------------------------------------------------------
1041     // Allocate the instance object.
1042     //--------------------------------------------------------------------------
1043     Handle<WasmInstanceObject> instance =
1044         WasmInstanceObject::New(isolate_, compiled_module_);
1045 
1046     //--------------------------------------------------------------------------
1047     // Set up the globals for the new instance.
1048     //--------------------------------------------------------------------------
1049     MaybeHandle<JSArrayBuffer> old_globals;
1050     uint32_t globals_size = module_->globals_size;
1051     if (globals_size > 0) {
1052       Handle<JSArrayBuffer> global_buffer =
1053           NewArrayBuffer(isolate_, globals_size);
1054       globals_ = global_buffer;
1055       if (globals_.is_null()) {
1056         thrower_->RangeError("Out of memory: wasm globals");
1057         return nothing;
1058       }
1059       Address old_address =
1060           owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate(
1061                                           isolate_->heap()->undefined_value(),
1062                                           *owner.ToHandleChecked());
1063       RelocateGlobals(code_table, old_address,
1064                       static_cast<Address>(global_buffer->backing_store()));
1065       instance->set_globals_buffer(*global_buffer);
1066     }
1067 
1068     //--------------------------------------------------------------------------
1069     // Prepare for initialization of function tables.
1070     //--------------------------------------------------------------------------
1071     int function_table_count =
1072         static_cast<int>(module_->function_tables.size());
1073     table_instances_.reserve(module_->function_tables.size());
1074     for (int index = 0; index < function_table_count; ++index) {
1075       table_instances_.push_back({Handle<WasmTableObject>::null(),
1076                                   Handle<FixedArray>::null(),
1077                                   Handle<FixedArray>::null()});
1078     }
1079 
1080     //--------------------------------------------------------------------------
1081     // Process the imports for the module.
1082     //--------------------------------------------------------------------------
1083     int num_imported_functions = ProcessImports(code_table, instance);
1084     if (num_imported_functions < 0) return nothing;
1085 
1086     //--------------------------------------------------------------------------
1087     // Process the initialization for the module's globals.
1088     //--------------------------------------------------------------------------
1089     InitGlobals();
1090 
1091     //--------------------------------------------------------------------------
1092     // Set up the memory for the new instance.
1093     //--------------------------------------------------------------------------
1094     MaybeHandle<JSArrayBuffer> old_memory;
1095 
1096     uint32_t min_mem_pages = module_->min_mem_pages;
1097     isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages);
1098 
1099     if (!memory_.is_null()) {
1100       // Set externally passed ArrayBuffer non neuterable.
1101       memory_->set_is_neuterable(false);
1102     } else if (min_mem_pages > 0) {
1103       memory_ = AllocateMemory(min_mem_pages);
1104       if (memory_.is_null()) return nothing;  // failed to allocate memory
1105     }
1106 
1107     if (!memory_.is_null()) {
1108       instance->set_memory_buffer(*memory_);
1109       Address mem_start = static_cast<Address>(memory_->backing_store());
1110       uint32_t mem_size =
1111           static_cast<uint32_t>(memory_->byte_length()->Number());
1112       LoadDataSegments(mem_start, mem_size);
1113 
1114       uint32_t old_mem_size = compiled_module_->mem_size();
1115       Address old_mem_start =
1116           compiled_module_->has_memory()
1117               ? static_cast<Address>(
1118                     compiled_module_->memory()->backing_store())
1119               : nullptr;
1120       RelocateMemoryReferencesInCode(code_table, old_mem_start, mem_start,
1121                                      old_mem_size, mem_size);
1122       compiled_module_->set_memory(memory_);
1123     } else {
1124       LoadDataSegments(nullptr, 0);
1125     }
1126 
1127     //--------------------------------------------------------------------------
1128     // Set up the runtime support for the new instance.
1129     //--------------------------------------------------------------------------
1130     Handle<WeakCell> weak_link = factory->NewWeakCell(instance);
1131 
1132     for (int i = num_imported_functions + FLAG_skip_compiling_wasm_funcs;
1133          i < code_table->length(); ++i) {
1134       Handle<Code> code = code_table->GetValueChecked<Code>(isolate_, i);
1135       if (code->kind() == Code::WASM_FUNCTION) {
1136         Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED);
1137         deopt_data->set(0, *weak_link);
1138         deopt_data->set(1, Smi::FromInt(static_cast<int>(i)));
1139         deopt_data->set_length(2);
1140         code->set_deoptimization_data(*deopt_data);
1141       }
1142     }
1143 
1144     //--------------------------------------------------------------------------
1145     // Set up the exports object for the new instance.
1146     //--------------------------------------------------------------------------
1147     ProcessExports(code_table, instance);
1148 
1149     //--------------------------------------------------------------------------
1150     // Set up the indirect function tables for the new instance.
1151     //--------------------------------------------------------------------------
1152     if (function_table_count > 0) InitializeTables(code_table, instance);
1153 
1154     if (num_imported_functions > 0 || !owner.is_null()) {
1155       // If the code was cloned, or new imports were compiled, patch.
1156       PatchDirectCalls(old_code_table, code_table, num_imported_functions);
1157     }
1158 
1159     FlushICache(isolate_, code_table);
1160 
1161     //--------------------------------------------------------------------------
1162     // Set up and link the new instance.
1163     //--------------------------------------------------------------------------
1164     {
1165       Handle<Object> global_handle =
1166           isolate_->global_handles()->Create(*instance);
1167       Handle<WeakCell> link_to_clone = factory->NewWeakCell(compiled_module_);
1168       Handle<WeakCell> link_to_owning_instance = factory->NewWeakCell(instance);
1169       MaybeHandle<WeakCell> link_to_original;
1170       MaybeHandle<WasmCompiledModule> original;
1171       if (!owner.is_null()) {
1172         // prepare the data needed for publishing in a chain, but don't link
1173         // just yet, because
1174         // we want all the publishing to happen free from GC interruptions, and
1175         // so we do it in
1176         // one GC-free scope afterwards.
1177         original = handle(owner.ToHandleChecked()->get_compiled_module());
1178         link_to_original = factory->NewWeakCell(original.ToHandleChecked());
1179       }
1180       // Publish the new instance to the instances chain.
1181       {
1182         DisallowHeapAllocation no_gc;
1183         if (!link_to_original.is_null()) {
1184           compiled_module_->set_weak_next_instance(
1185               link_to_original.ToHandleChecked());
1186           original.ToHandleChecked()->set_weak_prev_instance(link_to_clone);
1187           compiled_module_->set_weak_wasm_module(
1188               original.ToHandleChecked()->weak_wasm_module());
1189         }
1190         module_object_->SetInternalField(0, *compiled_module_);
1191         compiled_module_->set_weak_owning_instance(link_to_owning_instance);
1192         GlobalHandles::MakeWeak(global_handle.location(),
1193                                 global_handle.location(), &InstanceFinalizer,
1194                                 v8::WeakCallbackType::kFinalizer);
1195       }
1196     }
1197 
1198     DCHECK(wasm::IsWasmInstance(*instance));
1199     if (instance->has_memory_object()) {
1200       instance->get_memory_object()->AddInstance(*instance);
1201     }
1202 
1203     //--------------------------------------------------------------------------
1204     // Run the start function if one was specified.
1205     //--------------------------------------------------------------------------
1206     if (module_->start_function_index >= 0) {
1207       HandleScope scope(isolate_);
1208       ModuleEnv module_env;
1209       module_env.module = module_;
1210       module_env.instance = nullptr;
1211       module_env.origin = module_->origin;
1212       int start_index = module_->start_function_index;
1213       Handle<Code> startup_code =
1214           code_table->GetValueChecked<Code>(isolate_, start_index);
1215       FunctionSig* sig = module_->functions[start_index].sig;
1216       Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper(
1217           isolate_, &module_env, startup_code, start_index);
1218       Handle<WasmExportedFunction> startup_fct = WasmExportedFunction::New(
1219           isolate_, instance, factory->InternalizeUtf8String("start"),
1220           wrapper_code, static_cast<int>(sig->parameter_count()), start_index);
1221       RecordStats(isolate_, *startup_code);
1222       // Call the JS function.
1223       Handle<Object> undefined = factory->undefined_value();
1224       MaybeHandle<Object> retval =
1225           Execution::Call(isolate_, startup_fct, undefined, 0, nullptr);
1226 
1227       if (retval.is_null()) {
1228         DCHECK(isolate_->has_pending_exception());
1229         isolate_->OptionalRescheduleException(false);
1230         // It's unfortunate that the new instance is already linked in the
1231         // chain. However, we need to set up everything before executing the
1232         // start function, such that stack trace information can be generated
1233         // correctly already in the start function.
1234         return nothing;
1235       }
1236     }
1237 
1238     DCHECK(!isolate_->has_pending_exception());
1239     TRACE("Finishing instance %d\n", compiled_module_->instance_id());
1240     TRACE_CHAIN(WasmCompiledModule::cast(module_object_->GetInternalField(0)));
1241     return instance;
1242   }
1243 
1244  private:
1245   // Represents the initialized state of a table.
1246   struct TableInstance {
1247     Handle<WasmTableObject> table_object;    // WebAssembly.Table instance
1248     Handle<FixedArray> js_wrappers;          // JSFunctions exported
1249     Handle<FixedArray> dispatch_table;       // internal (code, sig) pairs
1250   };
1251 
1252   Isolate* isolate_;
1253   WasmModule* module_;
1254   ErrorThrower* thrower_;
1255   Handle<JSObject> module_object_;
1256   Handle<JSReceiver> ffi_;
1257   Handle<JSArrayBuffer> memory_;
1258   Handle<JSArrayBuffer> globals_;
1259   Handle<WasmCompiledModule> compiled_module_;
1260   std::vector<TableInstance> table_instances_;
1261   std::vector<Handle<JSFunction>> js_wrappers_;
1262 
1263   // Helper routine to print out errors with imports (FFI).
ReportFFIError(const char * error,uint32_t index,Handle<String> module_name,MaybeHandle<String> function_name)1264   MaybeHandle<JSFunction> ReportFFIError(const char* error, uint32_t index,
1265                                          Handle<String> module_name,
1266                                          MaybeHandle<String> function_name) {
1267     Handle<String> function_name_handle;
1268     if (function_name.ToHandle(&function_name_handle)) {
1269       thrower_->TypeError(
1270           "Import #%d module=\"%.*s\" function=\"%.*s\" error: %s", index,
1271           module_name->length(), module_name->ToCString().get(),
1272           function_name_handle->length(),
1273           function_name_handle->ToCString().get(), error);
1274     } else {
1275       thrower_->TypeError("Import #%d module=\"%.*s\" error: %s", index,
1276                           module_name->length(), module_name->ToCString().get(),
1277                           error);
1278     }
1279     thrower_->TypeError("Import ");
1280     return MaybeHandle<JSFunction>();
1281   }
1282 
1283   // Look up an import value in the {ffi_} object.
LookupImport(uint32_t index,Handle<String> module_name,MaybeHandle<String> import_name)1284   MaybeHandle<Object> LookupImport(uint32_t index, Handle<String> module_name,
1285                                    MaybeHandle<String> import_name) {
1286     if (ffi_.is_null()) {
1287       return ReportFFIError("FFI is not an object", index, module_name,
1288                             import_name);
1289     }
1290 
1291     // Look up the module first.
1292     MaybeHandle<Object> result = Object::GetProperty(ffi_, module_name);
1293     if (result.is_null()) {
1294       return ReportFFIError("module not found", index, module_name,
1295                             import_name);
1296     }
1297 
1298     Handle<Object> module = result.ToHandleChecked();
1299 
1300     if (!import_name.is_null()) {
1301       // Look up the value in the module.
1302       if (!module->IsJSReceiver()) {
1303         return ReportFFIError("module is not an object or function", index,
1304                               module_name, import_name);
1305       }
1306 
1307       result = Object::GetProperty(module, import_name.ToHandleChecked());
1308       if (result.is_null()) {
1309         return ReportFFIError("import not found", index, module_name,
1310                               import_name);
1311       }
1312     } else {
1313       // No function specified. Use the "default export".
1314       result = module;
1315     }
1316 
1317     return result;
1318   }
1319 
EvalUint32InitExpr(const WasmInitExpr & expr)1320   uint32_t EvalUint32InitExpr(const WasmInitExpr& expr) {
1321     switch (expr.kind) {
1322       case WasmInitExpr::kI32Const:
1323         return expr.val.i32_const;
1324       case WasmInitExpr::kGlobalIndex: {
1325         uint32_t offset = module_->globals[expr.val.global_index].offset;
1326         return *reinterpret_cast<uint32_t*>(raw_buffer_ptr(globals_, offset));
1327       }
1328       default:
1329         UNREACHABLE();
1330         return 0;
1331     }
1332   }
1333 
1334   // Load data segments into the memory.
LoadDataSegments(Address mem_addr,size_t mem_size)1335   void LoadDataSegments(Address mem_addr, size_t mem_size) {
1336     Handle<SeqOneByteString> module_bytes = compiled_module_->module_bytes();
1337     for (const WasmDataSegment& segment : module_->data_segments) {
1338       uint32_t source_size = segment.source_size;
1339       // Segments of size == 0 are just nops.
1340       if (source_size == 0) continue;
1341       uint32_t dest_offset = EvalUint32InitExpr(segment.dest_addr);
1342       if (dest_offset >= mem_size || source_size >= mem_size ||
1343           dest_offset > (mem_size - source_size)) {
1344         thrower_->TypeError("data segment (start = %" PRIu32 ", size = %" PRIu32
1345                             ") does not fit into memory (size = %" PRIuS ")",
1346                             dest_offset, source_size, mem_size);
1347         return;
1348       }
1349       byte* dest = mem_addr + dest_offset;
1350       const byte* src = reinterpret_cast<const byte*>(
1351           module_bytes->GetCharsAddress() + segment.source_offset);
1352       memcpy(dest, src, source_size);
1353     }
1354   }
1355 
WriteGlobalValue(WasmGlobal & global,Handle<Object> value)1356   void WriteGlobalValue(WasmGlobal& global, Handle<Object> value) {
1357     double num = 0;
1358     if (value->IsSmi()) {
1359       num = Smi::cast(*value)->value();
1360     } else if (value->IsHeapNumber()) {
1361       num = HeapNumber::cast(*value)->value();
1362     } else {
1363       UNREACHABLE();
1364     }
1365     TRACE("init [globals+%u] = %lf, type = %s\n", global.offset, num,
1366           WasmOpcodes::TypeName(global.type));
1367     switch (global.type) {
1368       case kAstI32:
1369         *GetRawGlobalPtr<int32_t>(global) = static_cast<int32_t>(num);
1370         break;
1371       case kAstI64:
1372         // TODO(titzer): initialization of imported i64 globals.
1373         UNREACHABLE();
1374         break;
1375       case kAstF32:
1376         *GetRawGlobalPtr<float>(global) = static_cast<float>(num);
1377         break;
1378       case kAstF64:
1379         *GetRawGlobalPtr<double>(global) = static_cast<double>(num);
1380         break;
1381       default:
1382         UNREACHABLE();
1383     }
1384   }
1385 
1386   // Process the imports, including functions, tables, globals, and memory, in
1387   // order, loading them from the {ffi_} object. Returns the number of imported
1388   // functions.
ProcessImports(Handle<FixedArray> code_table,Handle<WasmInstanceObject> instance)1389   int ProcessImports(Handle<FixedArray> code_table,
1390                      Handle<WasmInstanceObject> instance) {
1391     int num_imported_functions = 0;
1392     int num_imported_tables = 0;
1393     for (int index = 0; index < static_cast<int>(module_->import_table.size());
1394          ++index) {
1395       WasmImport& import = module_->import_table[index];
1396       Handle<String> module_name =
1397           ExtractStringFromModuleBytes(isolate_, compiled_module_,
1398                                        import.module_name_offset,
1399                                        import.module_name_length)
1400               .ToHandleChecked();
1401       Handle<String> function_name = Handle<String>::null();
1402       if (import.field_name_length > 0) {
1403         function_name = ExtractStringFromModuleBytes(isolate_, compiled_module_,
1404                                                      import.field_name_offset,
1405                                                      import.field_name_length)
1406                             .ToHandleChecked();
1407       }
1408 
1409       MaybeHandle<Object> result =
1410           LookupImport(index, module_name, function_name);
1411       if (thrower_->error()) return -1;
1412 
1413       switch (import.kind) {
1414         case kExternalFunction: {
1415           // Function imports must be callable.
1416           Handle<Object> function = result.ToHandleChecked();
1417           if (!function->IsCallable()) {
1418             ReportFFIError("function import requires a callable", index,
1419                            module_name, function_name);
1420             return -1;
1421           }
1422 
1423           Handle<Code> import_wrapper = CompileImportWrapper(
1424               isolate_, index, module_->functions[import.index].sig,
1425               Handle<JSReceiver>::cast(function), module_name, function_name);
1426           if (import_wrapper.is_null()) {
1427             ReportFFIError("imported function does not match the expected type",
1428                            index, module_name, function_name);
1429             return -1;
1430           }
1431           code_table->set(num_imported_functions, *import_wrapper);
1432           RecordStats(isolate_, *import_wrapper);
1433           num_imported_functions++;
1434           break;
1435         }
1436         case kExternalTable: {
1437           Handle<Object> value = result.ToHandleChecked();
1438           if (!WasmJs::IsWasmTableObject(isolate_, value)) {
1439             ReportFFIError("table import requires a WebAssembly.Table", index,
1440                            module_name, function_name);
1441             return -1;
1442           }
1443           WasmIndirectFunctionTable& table =
1444               module_->function_tables[num_imported_tables];
1445           TableInstance& table_instance = table_instances_[num_imported_tables];
1446           table_instance.table_object = Handle<WasmTableObject>::cast(value);
1447           table_instance.js_wrappers = Handle<FixedArray>(
1448               table_instance.table_object->get_functions(), isolate_);
1449 
1450           // TODO(titzer): import table size must match exactly for now.
1451           int table_size = table_instance.js_wrappers->length();
1452           if (table_size != static_cast<int>(table.min_size)) {
1453             thrower_->TypeError(
1454                 "table import %d is wrong size (%d), expected %u", index,
1455                 table_size, table.min_size);
1456             return -1;
1457           }
1458 
1459           // Allocate a new dispatch table.
1460           table_instance.dispatch_table =
1461               isolate_->factory()->NewFixedArray(table_size * 2);
1462           for (int i = 0; i < table_size * 2; ++i) {
1463             table_instance.dispatch_table->set(i,
1464                                                Smi::FromInt(kInvalidSigIndex));
1465           }
1466           // Initialize the dispatch table with the (foreign) JS functions
1467           // that are already in the table.
1468           for (int i = 0; i < table_size; ++i) {
1469             Handle<Object> val(table_instance.js_wrappers->get(i), isolate_);
1470             if (!val->IsJSFunction()) continue;
1471             WasmFunction* function =
1472                 GetWasmFunctionForImportWrapper(isolate_, val);
1473             if (function == nullptr) {
1474               thrower_->TypeError("table import %d[%d] is not a WASM function",
1475                                   index, i);
1476               return -1;
1477             }
1478             int sig_index = table.map.FindOrInsert(function->sig);
1479             table_instance.dispatch_table->set(i, Smi::FromInt(sig_index));
1480             table_instance.dispatch_table->set(i + table_size,
1481                                                *UnwrapImportWrapper(val));
1482           }
1483 
1484           num_imported_tables++;
1485           break;
1486         }
1487         case kExternalMemory: {
1488           Handle<Object> object = result.ToHandleChecked();
1489           if (!WasmJs::IsWasmMemoryObject(isolate_, object)) {
1490             ReportFFIError("memory import must be a WebAssembly.Memory object",
1491                            index, module_name, function_name);
1492             return -1;
1493           }
1494           auto memory = Handle<WasmMemoryObject>::cast(object);
1495           instance->set_memory_object(*memory);
1496           memory_ = Handle<JSArrayBuffer>(memory->get_buffer(), isolate_);
1497           break;
1498         }
1499         case kExternalGlobal: {
1500           // Global imports are converted to numbers and written into the
1501           // {globals_} array buffer.
1502           Handle<Object> object = result.ToHandleChecked();
1503           MaybeHandle<Object> number = Object::ToNumber(object);
1504           if (number.is_null()) {
1505             ReportFFIError("global import could not be converted to number",
1506                            index, module_name, function_name);
1507             return -1;
1508           }
1509           Handle<Object> val = number.ToHandleChecked();
1510           WriteGlobalValue(module_->globals[import.index], val);
1511           break;
1512         }
1513         default:
1514           UNREACHABLE();
1515           break;
1516       }
1517     }
1518     return num_imported_functions;
1519   }
1520 
1521   template <typename T>
GetRawGlobalPtr(WasmGlobal & global)1522   T* GetRawGlobalPtr(WasmGlobal& global) {
1523     return reinterpret_cast<T*>(raw_buffer_ptr(globals_, global.offset));
1524   }
1525 
1526   // Process initialization of globals.
InitGlobals()1527   void InitGlobals() {
1528     for (auto global : module_->globals) {
1529       switch (global.init.kind) {
1530         case WasmInitExpr::kI32Const:
1531           *GetRawGlobalPtr<int32_t>(global) = global.init.val.i32_const;
1532           break;
1533         case WasmInitExpr::kI64Const:
1534           *GetRawGlobalPtr<int64_t>(global) = global.init.val.i64_const;
1535           break;
1536         case WasmInitExpr::kF32Const:
1537           *GetRawGlobalPtr<float>(global) = global.init.val.f32_const;
1538           break;
1539         case WasmInitExpr::kF64Const:
1540           *GetRawGlobalPtr<double>(global) = global.init.val.f64_const;
1541           break;
1542         case WasmInitExpr::kGlobalIndex: {
1543           // Initialize with another global.
1544           uint32_t new_offset = global.offset;
1545           uint32_t old_offset =
1546               module_->globals[global.init.val.global_index].offset;
1547           TRACE("init [globals+%u] = [globals+%d]\n", global.offset,
1548                 old_offset);
1549           size_t size = (global.type == kAstI64 || global.type == kAstF64)
1550                             ? sizeof(double)
1551                             : sizeof(int32_t);
1552           memcpy(raw_buffer_ptr(globals_, new_offset),
1553                  raw_buffer_ptr(globals_, old_offset), size);
1554           break;
1555         }
1556         case WasmInitExpr::kNone:
1557           // Happens with imported globals.
1558           break;
1559         default:
1560           UNREACHABLE();
1561           break;
1562       }
1563     }
1564   }
1565 
1566   // Allocate memory for a module instance as a new JSArrayBuffer.
AllocateMemory(uint32_t min_mem_pages)1567   Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages) {
1568     if (min_mem_pages > WasmModule::kV8MaxPages) {
1569       thrower_->RangeError("Out of memory: wasm memory too large");
1570       return Handle<JSArrayBuffer>::null();
1571     }
1572     Handle<JSArrayBuffer> mem_buffer =
1573         NewArrayBuffer(isolate_, min_mem_pages * WasmModule::kPageSize);
1574 
1575     if (mem_buffer.is_null()) {
1576       thrower_->RangeError("Out of memory: wasm memory");
1577     }
1578     return mem_buffer;
1579   }
1580 
1581   // Process the exports, creating wrappers for functions, tables, memories,
1582   // and globals.
ProcessExports(Handle<FixedArray> code_table,Handle<WasmInstanceObject> instance)1583   void ProcessExports(Handle<FixedArray> code_table,
1584                       Handle<WasmInstanceObject> instance) {
1585     bool needs_wrappers = module_->num_exported_functions > 0;
1586     for (auto table_instance : table_instances_) {
1587       if (!table_instance.js_wrappers.is_null()) {
1588         needs_wrappers = true;
1589         break;
1590       }
1591     }
1592     for (auto table : module_->function_tables) {
1593       if (table.exported) {
1594         needs_wrappers = true;
1595         break;
1596       }
1597     }
1598     if (needs_wrappers) {
1599       // Fill the table to cache the exported JSFunction wrappers.
1600       js_wrappers_.insert(js_wrappers_.begin(), module_->functions.size(),
1601                           Handle<JSFunction>::null());
1602     }
1603 
1604     Handle<JSObject> exports_object = instance;
1605     if (module_->export_table.size() > 0 && module_->origin == kWasmOrigin) {
1606       // Create the "exports" object.
1607       Handle<JSFunction> object_function = Handle<JSFunction>(
1608           isolate_->native_context()->object_function(), isolate_);
1609       exports_object =
1610           isolate_->factory()->NewJSObject(object_function, TENURED);
1611       Handle<String> exports_name =
1612           isolate_->factory()->InternalizeUtf8String("exports");
1613       JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY);
1614     }
1615 
1616     PropertyDescriptor desc;
1617     desc.set_writable(false);
1618 
1619     // Process each export in the export table.
1620     int export_index = 0;
1621     for (auto exp : module_->export_table) {
1622       Handle<String> name =
1623           ExtractStringFromModuleBytes(isolate_, compiled_module_,
1624                                        exp.name_offset, exp.name_length)
1625               .ToHandleChecked();
1626       switch (exp.kind) {
1627         case kExternalFunction: {
1628           // Wrap and export the code as a JSFunction.
1629           WasmFunction& function = module_->functions[exp.index];
1630           int func_index =
1631               static_cast<int>(module_->functions.size() + export_index);
1632           Handle<JSFunction> js_function = js_wrappers_[exp.index];
1633           if (js_function.is_null()) {
1634             // Wrap the exported code as a JSFunction.
1635             Handle<Code> export_code =
1636                 code_table->GetValueChecked<Code>(isolate_, func_index);
1637             js_function = WasmExportedFunction::New(
1638                 isolate_, instance, name, export_code,
1639                 static_cast<int>(function.sig->parameter_count()),
1640                 function.func_index);
1641             js_wrappers_[exp.index] = js_function;
1642           }
1643           desc.set_value(js_function);
1644           export_index++;
1645           break;
1646         }
1647         case kExternalTable: {
1648           // Export a table as a WebAssembly.Table object.
1649           TableInstance& table_instance = table_instances_[exp.index];
1650           WasmIndirectFunctionTable& table =
1651               module_->function_tables[exp.index];
1652           if (table_instance.table_object.is_null()) {
1653             uint32_t maximum =
1654                 table.has_max ? table.max_size : WasmModule::kV8MaxTableSize;
1655             table_instance.table_object = WasmTableObject::New(
1656                 isolate_, table.min_size, maximum, &table_instance.js_wrappers);
1657           }
1658           desc.set_value(table_instance.table_object);
1659           break;
1660         }
1661         case kExternalMemory: {
1662           // Export the memory as a WebAssembly.Memory object.
1663           Handle<WasmMemoryObject> memory_object;
1664           if (!instance->has_memory_object()) {
1665             // If there was no imported WebAssembly.Memory object, create one.
1666             Handle<JSArrayBuffer> buffer(instance->get_memory_buffer(),
1667                                          isolate_);
1668             memory_object = WasmMemoryObject::New(
1669                 isolate_, buffer,
1670                 (module_->max_mem_pages != 0) ? module_->max_mem_pages : -1);
1671             instance->set_memory_object(*memory_object);
1672           } else {
1673             memory_object = Handle<WasmMemoryObject>(
1674                 instance->get_memory_object(), isolate_);
1675           }
1676 
1677           desc.set_value(memory_object);
1678           break;
1679         }
1680         case kExternalGlobal: {
1681           // Export the value of the global variable as a number.
1682           WasmGlobal& global = module_->globals[exp.index];
1683           double num = 0;
1684           switch (global.type) {
1685             case kAstI32:
1686               num = *GetRawGlobalPtr<int32_t>(global);
1687               break;
1688             case kAstF32:
1689               num = *GetRawGlobalPtr<float>(global);
1690               break;
1691             case kAstF64:
1692               num = *GetRawGlobalPtr<double>(global);
1693               break;
1694             default:
1695               UNREACHABLE();
1696           }
1697           desc.set_value(isolate_->factory()->NewNumber(num));
1698           break;
1699         }
1700         default:
1701           UNREACHABLE();
1702           break;
1703       }
1704 
1705       v8::Maybe<bool> status = JSReceiver::DefineOwnProperty(
1706           isolate_, exports_object, name, &desc, Object::THROW_ON_ERROR);
1707       if (!status.IsJust()) {
1708         thrower_->TypeError("export of %.*s failed.", name->length(),
1709                             name->ToCString().get());
1710         return;
1711       }
1712     }
1713   }
1714 
InitializeTables(Handle<FixedArray> code_table,Handle<WasmInstanceObject> instance)1715   void InitializeTables(Handle<FixedArray> code_table,
1716                         Handle<WasmInstanceObject> instance) {
1717     Handle<FixedArray> old_function_tables =
1718         compiled_module_->function_tables();
1719     int function_table_count =
1720         static_cast<int>(module_->function_tables.size());
1721     Handle<FixedArray> new_function_tables =
1722         isolate_->factory()->NewFixedArray(function_table_count);
1723     for (int index = 0; index < function_table_count; ++index) {
1724       WasmIndirectFunctionTable& table = module_->function_tables[index];
1725       TableInstance& table_instance = table_instances_[index];
1726       int table_size = static_cast<int>(table.min_size);
1727 
1728       if (table_instance.dispatch_table.is_null()) {
1729         // Create a new dispatch table if necessary.
1730         table_instance.dispatch_table =
1731             isolate_->factory()->NewFixedArray(table_size * 2);
1732         for (int i = 0; i < table_size; ++i) {
1733           // Fill the table with invalid signature indexes so that
1734           // uninitialized entries will always fail the signature check.
1735           table_instance.dispatch_table->set(i, Smi::FromInt(kInvalidSigIndex));
1736         }
1737       }
1738 
1739       new_function_tables->set(static_cast<int>(index),
1740                                *table_instance.dispatch_table);
1741 
1742       Handle<FixedArray> all_dispatch_tables;
1743       if (!table_instance.table_object.is_null()) {
1744         // Get the existing dispatch table(s) with the WebAssembly.Table object.
1745         all_dispatch_tables = WasmTableObject::AddDispatchTable(
1746             isolate_, table_instance.table_object,
1747             Handle<WasmInstanceObject>::null(), index,
1748             Handle<FixedArray>::null());
1749       }
1750 
1751       // TODO(titzer): this does redundant work if there are multiple tables,
1752       // since initializations are not sorted by table index.
1753       for (auto table_init : module_->table_inits) {
1754         uint32_t base = EvalUint32InitExpr(table_init.offset);
1755         if (base > static_cast<uint32_t>(table_size) ||
1756             (base + table_init.entries.size() >
1757              static_cast<uint32_t>(table_size))) {
1758           thrower_->CompileError("table initializer is out of bounds");
1759           continue;
1760         }
1761         for (int i = 0; i < static_cast<int>(table_init.entries.size()); ++i) {
1762           uint32_t func_index = table_init.entries[i];
1763           WasmFunction* function = &module_->functions[func_index];
1764           int table_index = static_cast<int>(i + base);
1765           int32_t sig_index = table.map.Find(function->sig);
1766           DCHECK_GE(sig_index, 0);
1767           table_instance.dispatch_table->set(table_index,
1768                                              Smi::FromInt(sig_index));
1769           table_instance.dispatch_table->set(table_index + table_size,
1770                                              code_table->get(func_index));
1771 
1772           if (!all_dispatch_tables.is_null()) {
1773             Handle<Code> wasm_code(Code::cast(code_table->get(func_index)),
1774                                    isolate_);
1775             if (js_wrappers_[func_index].is_null()) {
1776               // No JSFunction entry yet exists for this function. Create one.
1777               // TODO(titzer): We compile JS->WASM wrappers for functions are
1778               // not exported but are in an exported table. This should be done
1779               // at module compile time and cached instead.
1780               WasmInstance temp_instance(module_);
1781               temp_instance.context = isolate_->native_context();
1782               temp_instance.mem_size = 0;
1783               temp_instance.mem_start = nullptr;
1784               temp_instance.globals_start = nullptr;
1785 
1786               ModuleEnv module_env;
1787               module_env.module = module_;
1788               module_env.instance = &temp_instance;
1789               module_env.origin = module_->origin;
1790 
1791               Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper(
1792                   isolate_, &module_env, wasm_code, func_index);
1793               Handle<WasmExportedFunction> js_function =
1794                   WasmExportedFunction::New(
1795                       isolate_, instance, isolate_->factory()->empty_string(),
1796                       wrapper_code,
1797                       static_cast<int>(function->sig->parameter_count()),
1798                       func_index);
1799               js_wrappers_[func_index] = js_function;
1800             }
1801             table_instance.js_wrappers->set(table_index,
1802                                             *js_wrappers_[func_index]);
1803 
1804             UpdateDispatchTablesInternal(isolate_, all_dispatch_tables,
1805                                          table_index, function, wasm_code);
1806           }
1807         }
1808       }
1809 
1810       // TODO(titzer): we add the new dispatch table at the end to avoid
1811       // redundant work and also because the new instance is not yet fully
1812       // initialized.
1813       if (!table_instance.table_object.is_null()) {
1814         // Add the new dispatch table to the WebAssembly.Table object.
1815         all_dispatch_tables = WasmTableObject::AddDispatchTable(
1816             isolate_, table_instance.table_object, instance, index,
1817             table_instance.dispatch_table);
1818       }
1819     }
1820     // Patch all code that has references to the old indirect tables.
1821     for (int i = 0; i < code_table->length(); ++i) {
1822       if (!code_table->get(i)->IsCode()) continue;
1823       Handle<Code> code(Code::cast(code_table->get(i)), isolate_);
1824       for (int j = 0; j < function_table_count; ++j) {
1825         ReplaceReferenceInCode(
1826             code, Handle<Object>(old_function_tables->get(j), isolate_),
1827             Handle<Object>(new_function_tables->get(j), isolate_));
1828       }
1829     }
1830     compiled_module_->set_function_tables(new_function_tables);
1831   }
1832 };
1833 
1834 // Instantiates a WASM module, creating a WebAssembly.Instance from a
1835 // WebAssembly.Module.
Instantiate(Isolate * isolate,ErrorThrower * thrower,Handle<JSObject> wasm_module,Handle<JSReceiver> ffi,Handle<JSArrayBuffer> memory)1836 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
1837                                               ErrorThrower* thrower,
1838                                               Handle<JSObject> wasm_module,
1839                                               Handle<JSReceiver> ffi,
1840                                               Handle<JSArrayBuffer> memory) {
1841   WasmInstanceBuilder builder(isolate, thrower, wasm_module, ffi, memory);
1842   return builder.Build();
1843 }
1844 
GetWasmFunctionName(Isolate * isolate,Handle<Object> instance_or_undef,uint32_t func_index)1845 Handle<String> wasm::GetWasmFunctionName(Isolate* isolate,
1846                                          Handle<Object> instance_or_undef,
1847                                          uint32_t func_index) {
1848   if (!instance_or_undef->IsUndefined(isolate)) {
1849     Handle<WasmCompiledModule> compiled_module(
1850         Handle<WasmInstanceObject>::cast(instance_or_undef)
1851             ->get_compiled_module());
1852     MaybeHandle<String> maybe_name =
1853         WasmCompiledModule::GetFunctionName(compiled_module, func_index);
1854     if (!maybe_name.is_null()) return maybe_name.ToHandleChecked();
1855   }
1856   return isolate->factory()->NewStringFromStaticChars("<WASM UNNAMED>");
1857 }
1858 
IsWasmInstance(Object * object)1859 bool wasm::IsWasmInstance(Object* object) {
1860   return WasmInstanceObject::IsWasmInstanceObject(object);
1861 }
1862 
GetCompiledModule(Object * object)1863 WasmCompiledModule* wasm::GetCompiledModule(Object* object) {
1864   return WasmInstanceObject::cast(object)->get_compiled_module();
1865 }
1866 
WasmIsAsmJs(Object * instance,Isolate * isolate)1867 bool wasm::WasmIsAsmJs(Object* instance, Isolate* isolate) {
1868   if (instance->IsUndefined(isolate)) return false;
1869   DCHECK(IsWasmInstance(instance));
1870   WasmCompiledModule* compiled_module =
1871       GetCompiledModule(JSObject::cast(instance));
1872   DCHECK_EQ(compiled_module->has_asm_js_offset_tables(),
1873             compiled_module->script()->type() == Script::TYPE_NORMAL);
1874   return compiled_module->has_asm_js_offset_tables();
1875 }
1876 
GetScript(Handle<JSObject> instance)1877 Handle<Script> wasm::GetScript(Handle<JSObject> instance) {
1878   DCHECK(IsWasmInstance(*instance));
1879   WasmCompiledModule* compiled_module = GetCompiledModule(*instance);
1880   DCHECK(compiled_module->has_script());
1881   return compiled_module->script();
1882 }
1883 
GetAsmWasmSourcePosition(Handle<JSObject> instance,int func_index,int byte_offset)1884 int wasm::GetAsmWasmSourcePosition(Handle<JSObject> instance, int func_index,
1885                                    int byte_offset) {
1886   return WasmDebugInfo::GetAsmJsSourcePosition(GetDebugInfo(instance),
1887                                                func_index, byte_offset);
1888 }
1889 
GetWasmBytes(Handle<JSObject> object)1890 Handle<SeqOneByteString> wasm::GetWasmBytes(Handle<JSObject> object) {
1891   return Handle<WasmInstanceObject>::cast(object)
1892       ->get_compiled_module()
1893       ->module_bytes();
1894 }
1895 
GetDebugInfo(Handle<JSObject> object)1896 Handle<WasmDebugInfo> wasm::GetDebugInfo(Handle<JSObject> object) {
1897   auto instance = Handle<WasmInstanceObject>::cast(object);
1898   if (instance->has_debug_info()) {
1899     Handle<WasmDebugInfo> info(instance->get_debug_info(),
1900                                instance->GetIsolate());
1901     return info;
1902   }
1903   Handle<WasmDebugInfo> new_info = WasmDebugInfo::New(instance);
1904   instance->set_debug_info(*new_info);
1905   return new_info;
1906 }
1907 
GetNumberOfFunctions(Handle<JSObject> object)1908 int wasm::GetNumberOfFunctions(Handle<JSObject> object) {
1909   return static_cast<int>(
1910       Handle<WasmInstanceObject>::cast(object)->module()->functions.size());
1911 }
1912 
1913 // TODO(clemensh): origin can be inferred from asm_js_script; remove it.
CreateModuleObjectFromBytes(Isolate * isolate,const byte * start,const byte * end,ErrorThrower * thrower,ModuleOrigin origin,Handle<Script> asm_js_script,const byte * asm_js_offset_tables_start,const byte * asm_js_offset_tables_end)1914 MaybeHandle<WasmModuleObject> wasm::CreateModuleObjectFromBytes(
1915     Isolate* isolate, const byte* start, const byte* end, ErrorThrower* thrower,
1916     ModuleOrigin origin, Handle<Script> asm_js_script,
1917     const byte* asm_js_offset_tables_start,
1918     const byte* asm_js_offset_tables_end) {
1919   MaybeHandle<WasmModuleObject> nothing;
1920   ModuleResult result = DecodeWasmModule(isolate, start, end, false, origin);
1921   if (result.failed()) {
1922     if (result.val) delete result.val;
1923     thrower->CompileFailed("Wasm decoding failed", result);
1924     return nothing;
1925   }
1926   // The {module_wrapper} will take ownership of the {WasmModule} object,
1927   // and it will be destroyed when the GC reclaims the wrapper object.
1928   Handle<WasmModuleWrapper> module_wrapper =
1929       WasmModuleWrapper::New(isolate, const_cast<WasmModule*>(result.val));
1930 
1931   // Compile the functions of the module, producing a compiled module.
1932   MaybeHandle<WasmCompiledModule> maybe_compiled_module =
1933       result.val->CompileFunctions(isolate, module_wrapper, thrower);
1934 
1935   if (maybe_compiled_module.is_null()) return nothing;
1936 
1937   Handle<WasmCompiledModule> compiled_module =
1938       maybe_compiled_module.ToHandleChecked();
1939 
1940   DCHECK_EQ(origin == kAsmJsOrigin, !asm_js_script.is_null());
1941   DCHECK(!compiled_module->has_script());
1942   DCHECK(!compiled_module->has_asm_js_offset_tables());
1943   if (origin == kAsmJsOrigin) {
1944     // Set script for the asm.js source, and the offset table mapping wasm byte
1945     // offsets to source positions.
1946     compiled_module->set_script(asm_js_script);
1947     size_t offset_tables_len =
1948         asm_js_offset_tables_end - asm_js_offset_tables_start;
1949     DCHECK_GE(static_cast<size_t>(kMaxInt), offset_tables_len);
1950     Handle<ByteArray> offset_tables =
1951         isolate->factory()->NewByteArray(static_cast<int>(offset_tables_len));
1952     memcpy(offset_tables->GetDataStartAddress(), asm_js_offset_tables_start,
1953            offset_tables_len);
1954     compiled_module->set_asm_js_offset_tables(offset_tables);
1955   } else {
1956     // Create a new Script object representing this wasm module, store it in the
1957     // compiled wasm module, and register it at the debugger.
1958     Handle<Script> script =
1959         isolate->factory()->NewScript(isolate->factory()->empty_string());
1960     script->set_type(Script::TYPE_WASM);
1961 
1962     DCHECK_GE(kMaxInt, end - start);
1963     int hash = StringHasher::HashSequentialString(
1964         reinterpret_cast<const char*>(start), static_cast<int>(end - start),
1965         kZeroHashSeed);
1966 
1967     const int kBufferSize = 50;
1968     char buffer[kBufferSize];
1969     int url_chars = SNPrintF(ArrayVector(buffer), "wasm://wasm/%08x", hash);
1970     DCHECK(url_chars >= 0 && url_chars < kBufferSize);
1971     MaybeHandle<String> url_str = isolate->factory()->NewStringFromOneByte(
1972         Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), url_chars),
1973         TENURED);
1974     script->set_source_url(*url_str.ToHandleChecked());
1975 
1976     int name_chars = SNPrintF(ArrayVector(buffer), "wasm-%08x", hash);
1977     DCHECK(name_chars >= 0 && name_chars < kBufferSize);
1978     MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
1979         Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), name_chars),
1980         TENURED);
1981     script->set_name(*name_str.ToHandleChecked());
1982 
1983     script->set_wasm_compiled_module(*compiled_module);
1984     compiled_module->set_script(script);
1985     isolate->debug()->OnAfterCompile(script);
1986   }
1987 
1988   return WasmModuleObject::New(isolate, compiled_module);
1989 }
1990 
ValidateModuleBytes(Isolate * isolate,const byte * start,const byte * end,ErrorThrower * thrower,ModuleOrigin origin)1991 bool wasm::ValidateModuleBytes(Isolate* isolate, const byte* start,
1992                                const byte* end, ErrorThrower* thrower,
1993                                ModuleOrigin origin) {
1994   ModuleResult result = DecodeWasmModule(isolate, start, end, true, origin);
1995   if (result.val) {
1996     delete result.val;
1997   } else {
1998     DCHECK(!result.ok());
1999   }
2000   return result.ok();
2001 }
2002 
GetInstanceMemory(Isolate * isolate,Handle<JSObject> object)2003 MaybeHandle<JSArrayBuffer> wasm::GetInstanceMemory(Isolate* isolate,
2004                                                    Handle<JSObject> object) {
2005   auto instance = Handle<WasmInstanceObject>::cast(object);
2006   if (instance->has_memory_buffer()) {
2007     return Handle<JSArrayBuffer>(instance->get_memory_buffer(), isolate);
2008   }
2009   return MaybeHandle<JSArrayBuffer>();
2010 }
2011 
SetInstanceMemory(Handle<JSObject> object,JSArrayBuffer * buffer)2012 void SetInstanceMemory(Handle<JSObject> object, JSArrayBuffer* buffer) {
2013   DisallowHeapAllocation no_gc;
2014   auto instance = Handle<WasmInstanceObject>::cast(object);
2015   instance->set_memory_buffer(buffer);
2016   instance->get_compiled_module()->set_ptr_to_memory(buffer);
2017 }
2018 
GetInstanceMemorySize(Isolate * isolate,Handle<JSObject> instance)2019 int32_t wasm::GetInstanceMemorySize(Isolate* isolate,
2020                                     Handle<JSObject> instance) {
2021   MaybeHandle<JSArrayBuffer> maybe_mem_buffer =
2022       GetInstanceMemory(isolate, instance);
2023   Handle<JSArrayBuffer> buffer;
2024   if (!maybe_mem_buffer.ToHandle(&buffer)) {
2025     return 0;
2026   } else {
2027     return buffer->byte_length()->Number() / WasmModule::kPageSize;
2028   }
2029 }
2030 
GetMaxInstanceMemorySize(Isolate * isolate,Handle<WasmInstanceObject> instance)2031 uint32_t GetMaxInstanceMemorySize(Isolate* isolate,
2032                                   Handle<WasmInstanceObject> instance) {
2033   if (instance->has_memory_object()) {
2034     Handle<WasmMemoryObject> memory_object(instance->get_memory_object(),
2035                                            isolate);
2036 
2037     int maximum = memory_object->maximum_pages();
2038     if (maximum > 0) return static_cast<uint32_t>(maximum);
2039   }
2040   uint32_t compiled_max_pages =
2041       instance->get_compiled_module()->max_mem_pages();
2042   isolate->counters()->wasm_max_mem_pages_count()->AddSample(
2043       compiled_max_pages);
2044   if (compiled_max_pages != 0) return compiled_max_pages;
2045   return WasmModule::kV8MaxPages;
2046 }
2047 
GrowInstanceMemory(Isolate * isolate,Handle<JSObject> object,uint32_t pages)2048 int32_t wasm::GrowInstanceMemory(Isolate* isolate, Handle<JSObject> object,
2049                                  uint32_t pages) {
2050   if (!IsWasmInstance(*object)) return -1;
2051   auto instance = Handle<WasmInstanceObject>::cast(object);
2052   if (pages == 0) return GetInstanceMemorySize(isolate, instance);
2053   uint32_t max_pages = GetMaxInstanceMemorySize(isolate, instance);
2054 
2055   Address old_mem_start = nullptr;
2056   uint32_t old_size = 0, new_size = 0;
2057 
2058   MaybeHandle<JSArrayBuffer> maybe_mem_buffer =
2059       GetInstanceMemory(isolate, instance);
2060   Handle<JSArrayBuffer> old_buffer;
2061   if (!maybe_mem_buffer.ToHandle(&old_buffer) ||
2062       old_buffer->backing_store() == nullptr) {
2063     // If module object does not have linear memory associated with it,
2064     // Allocate new array buffer of given size.
2065     new_size = pages * WasmModule::kPageSize;
2066     if (max_pages < pages) return -1;
2067   } else {
2068     old_mem_start = static_cast<Address>(old_buffer->backing_store());
2069     old_size = old_buffer->byte_length()->Number();
2070     // If the old memory was zero-sized, we should have been in the
2071     // "undefined" case above.
2072     DCHECK_NOT_NULL(old_mem_start);
2073     DCHECK(old_size + pages * WasmModule::kPageSize <=
2074            std::numeric_limits<uint32_t>::max());
2075     new_size = old_size + pages * WasmModule::kPageSize;
2076   }
2077 
2078   if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size ||
2079       WasmModule::kV8MaxPages * WasmModule::kPageSize < new_size) {
2080     return -1;
2081   }
2082   Handle<JSArrayBuffer> buffer = NewArrayBuffer(isolate, new_size);
2083   if (buffer.is_null()) return -1;
2084   Address new_mem_start = static_cast<Address>(buffer->backing_store());
2085   if (old_size != 0) {
2086     memcpy(new_mem_start, old_mem_start, old_size);
2087   }
2088   SetInstanceMemory(instance, *buffer);
2089   Handle<FixedArray> code_table = instance->get_compiled_module()->code_table();
2090   RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start,
2091                                  old_size, new_size);
2092   if (instance->has_memory_object()) {
2093     instance->get_memory_object()->set_buffer(*buffer);
2094   }
2095 
2096   DCHECK(old_size % WasmModule::kPageSize == 0);
2097   return (old_size / WasmModule::kPageSize);
2098 }
2099 
ValidateInstancesChain(Isolate * isolate,Handle<JSObject> wasm_module,int instance_count)2100 void testing::ValidateInstancesChain(Isolate* isolate,
2101                                      Handle<JSObject> wasm_module,
2102                                      int instance_count) {
2103   CHECK_GE(instance_count, 0);
2104   DisallowHeapAllocation no_gc;
2105   WasmCompiledModule* compiled_module =
2106       WasmCompiledModule::cast(wasm_module->GetInternalField(0));
2107   CHECK_EQ(JSObject::cast(compiled_module->ptr_to_weak_wasm_module()->value()),
2108            *wasm_module);
2109   Object* prev = nullptr;
2110   int found_instances = compiled_module->has_weak_owning_instance() ? 1 : 0;
2111   WasmCompiledModule* current_instance = compiled_module;
2112   while (current_instance->has_weak_next_instance()) {
2113     CHECK((prev == nullptr && !current_instance->has_weak_prev_instance()) ||
2114           current_instance->ptr_to_weak_prev_instance()->value() == prev);
2115     CHECK_EQ(current_instance->ptr_to_weak_wasm_module()->value(),
2116              *wasm_module);
2117     CHECK(IsWasmInstance(
2118         current_instance->ptr_to_weak_owning_instance()->value()));
2119     prev = current_instance;
2120     current_instance = WasmCompiledModule::cast(
2121         current_instance->ptr_to_weak_next_instance()->value());
2122     ++found_instances;
2123     CHECK_LE(found_instances, instance_count);
2124   }
2125   CHECK_EQ(found_instances, instance_count);
2126 }
2127 
ValidateModuleState(Isolate * isolate,Handle<JSObject> wasm_module)2128 void testing::ValidateModuleState(Isolate* isolate,
2129                                   Handle<JSObject> wasm_module) {
2130   DisallowHeapAllocation no_gc;
2131   WasmCompiledModule* compiled_module =
2132       WasmCompiledModule::cast(wasm_module->GetInternalField(0));
2133   CHECK(compiled_module->has_weak_wasm_module());
2134   CHECK_EQ(compiled_module->ptr_to_weak_wasm_module()->value(), *wasm_module);
2135   CHECK(!compiled_module->has_weak_prev_instance());
2136   CHECK(!compiled_module->has_weak_next_instance());
2137   CHECK(!compiled_module->has_weak_owning_instance());
2138 }
2139 
ValidateOrphanedInstance(Isolate * isolate,Handle<JSObject> object)2140 void testing::ValidateOrphanedInstance(Isolate* isolate,
2141                                        Handle<JSObject> object) {
2142   DisallowHeapAllocation no_gc;
2143   WasmInstanceObject* instance = WasmInstanceObject::cast(*object);
2144   WasmCompiledModule* compiled_module = instance->get_compiled_module();
2145   CHECK(compiled_module->has_weak_wasm_module());
2146   CHECK(compiled_module->ptr_to_weak_wasm_module()->cleared());
2147 }
2148 
RecreateModuleWrapper(Isolate * isolate,Handle<FixedArray> array)2149 void WasmCompiledModule::RecreateModuleWrapper(Isolate* isolate,
2150                                                Handle<FixedArray> array) {
2151   Handle<WasmCompiledModule> compiled_module(
2152       reinterpret_cast<WasmCompiledModule*>(*array), isolate);
2153 
2154   WasmModule* module = nullptr;
2155   {
2156     Handle<SeqOneByteString> module_bytes = compiled_module->module_bytes();
2157     // We parse the module again directly from the module bytes, so
2158     // the underlying storage must not be moved meanwhile.
2159     DisallowHeapAllocation no_allocation;
2160     const byte* start =
2161         reinterpret_cast<const byte*>(module_bytes->GetCharsAddress());
2162     const byte* end = start + module_bytes->length();
2163     // TODO(titzer): remember the module origin in the compiled_module
2164     // For now, we assume serialized modules did not originate from asm.js.
2165     ModuleResult result =
2166         DecodeWasmModule(isolate, start, end, false, kWasmOrigin);
2167     CHECK(result.ok());
2168     CHECK_NOT_NULL(result.val);
2169     module = const_cast<WasmModule*>(result.val);
2170   }
2171 
2172   Handle<WasmModuleWrapper> module_wrapper =
2173       WasmModuleWrapper::New(isolate, module);
2174 
2175   compiled_module->set_module_wrapper(module_wrapper);
2176   DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
2177 }
2178 
GetFunctionName(Handle<WasmCompiledModule> compiled_module,uint32_t func_index)2179 MaybeHandle<String> WasmCompiledModule::GetFunctionName(
2180     Handle<WasmCompiledModule> compiled_module, uint32_t func_index) {
2181   DCHECK_LT(func_index, compiled_module->module()->functions.size());
2182   WasmFunction& function = compiled_module->module()->functions[func_index];
2183   Isolate* isolate = compiled_module->GetIsolate();
2184   MaybeHandle<String> string = ExtractStringFromModuleBytes(
2185       isolate, compiled_module, function.name_offset, function.name_length);
2186   if (!string.is_null()) return string.ToHandleChecked();
2187   return {};
2188 }
2189