• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 "src/wasm/module-instantiate.h"
6 
7 #include "src/api/api-inl.h"
8 #include "src/asmjs/asm-js.h"
9 #include "src/base/atomicops.h"
10 #include "src/base/platform/wrappers.h"
11 #include "src/logging/counters-scopes.h"
12 #include "src/logging/metrics.h"
13 #include "src/numbers/conversions-inl.h"
14 #include "src/objects/descriptor-array-inl.h"
15 #include "src/objects/property-descriptor.h"
16 #include "src/tracing/trace-event.h"
17 #include "src/utils/utils.h"
18 #include "src/wasm/code-space-access.h"
19 #include "src/wasm/init-expr-interface.h"
20 #include "src/wasm/module-compiler.h"
21 #include "src/wasm/wasm-constants.h"
22 #include "src/wasm/wasm-engine.h"
23 #include "src/wasm/wasm-external-refs.h"
24 #include "src/wasm/wasm-import-wrapper-cache.h"
25 #include "src/wasm/wasm-module.h"
26 #include "src/wasm/wasm-objects-inl.h"
27 #include "src/wasm/wasm-opcodes-inl.h"
28 #include "src/wasm/wasm-subtyping.h"
29 #include "src/wasm/wasm-value.h"
30 
31 #define TRACE(...)                                      \
32   do {                                                  \
33     if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
34   } while (false)
35 
36 namespace v8 {
37 namespace internal {
38 namespace wasm {
39 
40 namespace {
41 
raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer,int offset)42 byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) {
43   return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset;
44 }
45 
46 using ImportWrapperQueue = WrapperQueue<WasmImportWrapperCache::CacheKey,
47                                         WasmImportWrapperCache::CacheKeyHash>;
48 
49 class CompileImportWrapperJob final : public JobTask {
50  public:
CompileImportWrapperJob(Counters * counters,NativeModule * native_module,ImportWrapperQueue * queue,WasmImportWrapperCache::ModificationScope * cache_scope)51   CompileImportWrapperJob(
52       Counters* counters, NativeModule* native_module,
53       ImportWrapperQueue* queue,
54       WasmImportWrapperCache::ModificationScope* cache_scope)
55       : counters_(counters),
56         native_module_(native_module),
57         queue_(queue),
58         cache_scope_(cache_scope) {}
59 
GetMaxConcurrency(size_t worker_count) const60   size_t GetMaxConcurrency(size_t worker_count) const override {
61     size_t flag_limit =
62         static_cast<size_t>(std::max(1, FLAG_wasm_num_compilation_tasks));
63     // Add {worker_count} to the queue size because workers might still be
64     // processing units that have already been popped from the queue.
65     return std::min(flag_limit, worker_count + queue_->size());
66   }
67 
Run(JobDelegate * delegate)68   void Run(JobDelegate* delegate) override {
69     TRACE_EVENT0("v8.wasm", "wasm.CompileImportWrapperJob.Run");
70     while (base::Optional<WasmImportWrapperCache::CacheKey> key =
71                queue_->pop()) {
72       // TODO(wasm): Batch code publishing, to avoid repeated locking and
73       // permission switching.
74       CompileImportWrapper(native_module_, counters_, key->kind, key->signature,
75                            key->expected_arity, key->suspend, cache_scope_);
76       if (delegate->ShouldYield()) return;
77     }
78   }
79 
80  private:
81   Counters* const counters_;
82   NativeModule* const native_module_;
83   ImportWrapperQueue* const queue_;
84   WasmImportWrapperCache::ModificationScope* const cache_scope_;
85 };
86 
CreateStructDescriptorArray(Isolate * isolate,const wasm::StructType * type)87 Handle<DescriptorArray> CreateStructDescriptorArray(
88     Isolate* isolate, const wasm::StructType* type) {
89   if (type->field_count() == 0) {
90     return isolate->factory()->empty_descriptor_array();
91   }
92   uint32_t field_count = type->field_count();
93   static_assert(kV8MaxWasmStructFields <= kMaxNumberOfDescriptors,
94                 "Bigger numbers of struct fields require different approach");
95   Handle<DescriptorArray> descriptors =
96       isolate->factory()->NewDescriptorArray(field_count);
97 
98   // TODO(ishell): cache Wasm field type in FieldType value.
99   MaybeObject any_type = MaybeObject::FromObject(FieldType::Any());
100   DCHECK(any_type->IsSmi());
101 
102   base::EmbeddedVector<char, 128> name_buffer;
103   for (uint32_t i = 0; i < field_count; i++) {
104     // TODO(ishell): consider introducing a cache of first N internalized field
105     // names similar to LookupSingleCharacterStringFromCode().
106     SNPrintF(name_buffer, "$field%d", i);
107     Handle<String> name =
108         isolate->factory()->InternalizeUtf8String(name_buffer.begin());
109 
110     PropertyAttributes attributes = type->mutability(i) ? SEALED : FROZEN;
111     PropertyDetails details(
112         PropertyKind::kData, attributes, PropertyLocation::kField,
113         PropertyConstness::kMutable,  // Don't track constness
114         Representation::WasmValue(), static_cast<int>(i));
115     descriptors->Set(InternalIndex(i), *name, any_type, details);
116   }
117   descriptors->Sort();
118   return descriptors;
119 }
120 
CreateArrayDescriptorArray(Isolate * isolate,const wasm::ArrayType * type)121 Handle<DescriptorArray> CreateArrayDescriptorArray(
122     Isolate* isolate, const wasm::ArrayType* type) {
123   uint32_t kDescriptorsCount = 1;
124   Handle<DescriptorArray> descriptors =
125       isolate->factory()->NewDescriptorArray(kDescriptorsCount);
126 
127   // TODO(ishell): cache Wasm field type in FieldType value.
128   MaybeObject any_type = MaybeObject::FromObject(FieldType::Any());
129   DCHECK(any_type->IsSmi());
130 
131   // Add descriptor for length property.
132   PropertyDetails details(PropertyKind::kData, FROZEN, PropertyLocation::kField,
133                           PropertyConstness::kConst,
134                           Representation::WasmValue(), static_cast<int>(0));
135   descriptors->Set(InternalIndex(0), *isolate->factory()->length_string(),
136                    any_type, details);
137 
138   descriptors->Sort();
139   return descriptors;
140 }
141 
CreateStructMap(Isolate * isolate,const WasmModule * module,int struct_index,Handle<Map> opt_rtt_parent,Handle<WasmInstanceObject> instance)142 Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
143                             int struct_index, Handle<Map> opt_rtt_parent,
144                             Handle<WasmInstanceObject> instance) {
145   const wasm::StructType* type = module->struct_type(struct_index);
146   const int inobject_properties = 0;
147   // We have to use the variable size sentinel because the instance size
148   // stored directly in a Map is capped at 255 pointer sizes.
149   const int map_instance_size = kVariableSizeSentinel;
150   const int real_instance_size = WasmStruct::Size(type);
151   const InstanceType instance_type = WASM_STRUCT_TYPE;
152   // TODO(jkummerow): If NO_ELEMENTS were supported, we could use that here.
153   const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
154   Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
155       reinterpret_cast<Address>(type), opt_rtt_parent, real_instance_size,
156       instance);
157   Handle<DescriptorArray> descriptors =
158       CreateStructDescriptorArray(isolate, type);
159   Handle<Map> map = isolate->factory()->NewMap(
160       instance_type, map_instance_size, elements_kind, inobject_properties);
161   map->set_wasm_type_info(*type_info);
162   map->SetInstanceDescriptors(isolate, *descriptors,
163                               descriptors->number_of_descriptors());
164   map->set_is_extensible(false);
165   WasmStruct::EncodeInstanceSizeInMap(real_instance_size, *map);
166   return map;
167 }
168 
CreateArrayMap(Isolate * isolate,const WasmModule * module,int array_index,Handle<Map> opt_rtt_parent,Handle<WasmInstanceObject> instance)169 Handle<Map> CreateArrayMap(Isolate* isolate, const WasmModule* module,
170                            int array_index, Handle<Map> opt_rtt_parent,
171                            Handle<WasmInstanceObject> instance) {
172   const wasm::ArrayType* type = module->array_type(array_index);
173   const int inobject_properties = 0;
174   const int instance_size = kVariableSizeSentinel;
175   // Wasm Arrays don't have a static instance size.
176   const int cached_instance_size = 0;
177   const InstanceType instance_type = WASM_ARRAY_TYPE;
178   const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
179   Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
180       reinterpret_cast<Address>(type), opt_rtt_parent, cached_instance_size,
181       instance);
182   // TODO(ishell): get canonical descriptor array for WasmArrays from roots.
183   Handle<DescriptorArray> descriptors =
184       CreateArrayDescriptorArray(isolate, type);
185   Handle<Map> map = isolate->factory()->NewMap(
186       instance_type, instance_size, elements_kind, inobject_properties);
187   map->set_wasm_type_info(*type_info);
188   map->SetInstanceDescriptors(isolate, *descriptors,
189                               descriptors->number_of_descriptors());
190   map->set_is_extensible(false);
191   WasmArray::EncodeElementSizeInMap(type->element_type().value_kind_size(),
192                                     *map);
193   return map;
194 }
195 
CreateFuncRefMap(Isolate * isolate,const WasmModule * module,Handle<Map> opt_rtt_parent,Handle<WasmInstanceObject> instance)196 Handle<Map> CreateFuncRefMap(Isolate* isolate, const WasmModule* module,
197                              Handle<Map> opt_rtt_parent,
198                              Handle<WasmInstanceObject> instance) {
199   const int inobject_properties = 0;
200   const int instance_size =
201       Map::cast(isolate->root(RootIndex::kWasmInternalFunctionMap))
202           .instance_size();
203   const InstanceType instance_type = WASM_INTERNAL_FUNCTION_TYPE;
204   const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
205   Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
206       kNullAddress, opt_rtt_parent, instance_size, instance);
207   Handle<Map> map = isolate->factory()->NewMap(
208       instance_type, instance_size, elements_kind, inobject_properties);
209   map->set_wasm_type_info(*type_info);
210   return map;
211 }
212 
CreateMapForType(Isolate * isolate,const WasmModule * module,int type_index,Handle<WasmInstanceObject> instance,Handle<FixedArray> maps)213 void CreateMapForType(Isolate* isolate, const WasmModule* module,
214                       int type_index, Handle<WasmInstanceObject> instance,
215                       Handle<FixedArray> maps) {
216   // Recursive calls for supertypes may already have created this map.
217   if (maps->get(type_index).IsMap()) return;
218 
219   Handle<WeakArrayList> canonical_rtts;
220   uint32_t canonical_type_index =
221       module->isorecursive_canonical_type_ids[type_index];
222 
223   if (FLAG_wasm_type_canonicalization) {
224     // Try to find the canonical map for this type in the isolate store.
225     canonical_rtts = handle(isolate->heap()->wasm_canonical_rtts(), isolate);
226     DCHECK_GT(static_cast<uint32_t>(canonical_rtts->length()),
227               canonical_type_index);
228     MaybeObject maybe_canonical_map = canonical_rtts->Get(canonical_type_index);
229     if (maybe_canonical_map.IsStrongOrWeak() &&
230         maybe_canonical_map.GetHeapObject().IsMap()) {
231       maps->set(type_index, maybe_canonical_map.GetHeapObject());
232       return;
233     }
234   }
235 
236   Handle<Map> rtt_parent;
237   // If the type with {type_index} has an explicit supertype, make sure the
238   // map for that supertype is created first, so that the supertypes list
239   // that's cached on every RTT can be set up correctly.
240   uint32_t supertype = module->supertype(type_index);
241   if (supertype != kNoSuperType) {
242     // This recursion is safe, because kV8MaxRttSubtypingDepth limits the
243     // number of recursive steps, so we won't overflow the stack.
244     CreateMapForType(isolate, module, supertype, instance, maps);
245     rtt_parent = handle(Map::cast(maps->get(supertype)), isolate);
246   }
247   Handle<Map> map;
248   switch (module->types[type_index].kind) {
249     case TypeDefinition::kStruct:
250       map = CreateStructMap(isolate, module, type_index, rtt_parent, instance);
251       break;
252     case TypeDefinition::kArray:
253       map = CreateArrayMap(isolate, module, type_index, rtt_parent, instance);
254       break;
255     case TypeDefinition::kFunction:
256       map = CreateFuncRefMap(isolate, module, rtt_parent, instance);
257       break;
258   }
259   if (FLAG_wasm_type_canonicalization) {
260     canonical_rtts->Set(canonical_type_index, HeapObjectReference::Weak(*map));
261   }
262   maps->set(type_index, *map);
263 }
264 
265 }  // namespace
266 
267 // A helper class to simplify instantiating a module from a module object.
268 // It closes over the {Isolate}, the {ErrorThrower}, etc.
269 class InstanceBuilder {
270  public:
271   InstanceBuilder(Isolate* isolate, v8::metrics::Recorder::ContextId context_id,
272                   ErrorThrower* thrower, Handle<WasmModuleObject> module_object,
273                   MaybeHandle<JSReceiver> ffi,
274                   MaybeHandle<JSArrayBuffer> memory_buffer);
275 
276   // Build an instance, in all of its glory.
277   MaybeHandle<WasmInstanceObject> Build();
278   // Run the start function, if any.
279   bool ExecuteStartFunction();
280 
281  private:
282   // A pre-evaluated value to use in import binding.
283   struct SanitizedImport {
284     Handle<String> module_name;
285     Handle<String> import_name;
286     Handle<Object> value;
287   };
288 
289   Isolate* isolate_;
290   v8::metrics::Recorder::ContextId context_id_;
291   const WasmFeatures enabled_;
292   const WasmModule* const module_;
293   ErrorThrower* thrower_;
294   Handle<WasmModuleObject> module_object_;
295   MaybeHandle<JSReceiver> ffi_;
296   MaybeHandle<JSArrayBuffer> memory_buffer_;
297   Handle<WasmMemoryObject> memory_object_;
298   Handle<JSArrayBuffer> untagged_globals_;
299   Handle<FixedArray> tagged_globals_;
300   std::vector<Handle<WasmTagObject>> tags_wrappers_;
301   Handle<WasmExportedFunction> start_function_;
302   std::vector<SanitizedImport> sanitized_imports_;
303   // We pass this {Zone} to the temporary {WasmFullDecoder} we allocate during
304   // each call to {EvaluateInitExpression}. This has been found to improve
305   // performance a bit over allocating a new {Zone} each time.
306   Zone init_expr_zone_;
307 
308 // Helper routines to print out errors with imports.
309 #define ERROR_THROWER_WITH_MESSAGE(TYPE)                                      \
310   void Report##TYPE(const char* error, uint32_t index,                        \
311                     Handle<String> module_name, Handle<String> import_name) { \
312     thrower_->TYPE("Import #%d module=\"%s\" function=\"%s\" error: %s",      \
313                    index, module_name->ToCString().get(),                     \
314                    import_name->ToCString().get(), error);                    \
315   }                                                                           \
316                                                                               \
317   MaybeHandle<Object> Report##TYPE(const char* error, uint32_t index,         \
318                                    Handle<String> module_name) {              \
319     thrower_->TYPE("Import #%d module=\"%s\" error: %s", index,               \
320                    module_name->ToCString().get(), error);                    \
321     return MaybeHandle<Object>();                                             \
322   }
323 
324   ERROR_THROWER_WITH_MESSAGE(LinkError)
325   ERROR_THROWER_WITH_MESSAGE(TypeError)
326 
327 #undef ERROR_THROWER_WITH_MESSAGE
328 
329   // Look up an import value in the {ffi_} object.
330   MaybeHandle<Object> LookupImport(uint32_t index, Handle<String> module_name,
331                                    Handle<String> import_name);
332 
333   // Look up an import value in the {ffi_} object specifically for linking an
334   // asm.js module. This only performs non-observable lookups, which allows
335   // falling back to JavaScript proper (and hence re-executing all lookups) if
336   // module instantiation fails.
337   MaybeHandle<Object> LookupImportAsm(uint32_t index,
338                                       Handle<String> import_name);
339 
340   // Load data segments into the memory.
341   void LoadDataSegments(Handle<WasmInstanceObject> instance);
342 
343   void WriteGlobalValue(const WasmGlobal& global, const WasmValue& value);
344 
345   void SanitizeImports();
346 
347   // Find the imported memory if there is one.
348   bool FindImportedMemory();
349 
350   // Allocate the memory.
351   bool AllocateMemory();
352 
353   // Processes a single imported function.
354   bool ProcessImportedFunction(Handle<WasmInstanceObject> instance,
355                                int import_index, int func_index,
356                                Handle<String> module_name,
357                                Handle<String> import_name,
358                                Handle<Object> value);
359 
360   // Initialize imported tables of type funcref.
361   bool InitializeImportedIndirectFunctionTable(
362       Handle<WasmInstanceObject> instance, int table_index, int import_index,
363       Handle<WasmTableObject> table_object);
364 
365   // Process a single imported table.
366   bool ProcessImportedTable(Handle<WasmInstanceObject> instance,
367                             int import_index, int table_index,
368                             Handle<String> module_name,
369                             Handle<String> import_name, Handle<Object> value);
370 
371   // Process a single imported memory.
372   bool ProcessImportedMemory(Handle<WasmInstanceObject> instance,
373                              int import_index, Handle<String> module_name,
374                              Handle<String> import_name, Handle<Object> value);
375 
376   // Process a single imported global.
377   bool ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
378                              int import_index, int global_index,
379                              Handle<String> module_name,
380                              Handle<String> import_name, Handle<Object> value);
381 
382   // Process a single imported WasmGlobalObject.
383   bool ProcessImportedWasmGlobalObject(Handle<WasmInstanceObject> instance,
384                                        int import_index,
385                                        Handle<String> module_name,
386                                        Handle<String> import_name,
387                                        const WasmGlobal& global,
388                                        Handle<WasmGlobalObject> global_object);
389 
390   // Compile import wrappers in parallel. The result goes into the native
391   // module's import_wrapper_cache.
392   void CompileImportWrappers(Handle<WasmInstanceObject> instance);
393 
394   // Process the imports, including functions, tables, globals, and memory, in
395   // order, loading them from the {ffi_} object. Returns the number of imported
396   // functions, or {-1} on error.
397   int ProcessImports(Handle<WasmInstanceObject> instance);
398 
399   template <typename T>
400   T* GetRawUntaggedGlobalPtr(const WasmGlobal& global);
401 
402   // Process initialization of globals.
403   void InitGlobals(Handle<WasmInstanceObject> instance);
404 
405   // Process the exports, creating wrappers for functions, tables, memories,
406   // and globals.
407   void ProcessExports(Handle<WasmInstanceObject> instance);
408 
409   void InitializeNonDefaultableTables(Handle<WasmInstanceObject> instance);
410 
411   void LoadTableSegments(Handle<WasmInstanceObject> instance);
412 
413   // Creates new tags. Note that some tags might already exist if they were
414   // imported, those tags will be re-used.
415   void InitializeTags(Handle<WasmInstanceObject> instance);
416 };
417 
InstantiateToInstanceObject(Isolate * isolate,ErrorThrower * thrower,Handle<WasmModuleObject> module_object,MaybeHandle<JSReceiver> imports,MaybeHandle<JSArrayBuffer> memory_buffer)418 MaybeHandle<WasmInstanceObject> InstantiateToInstanceObject(
419     Isolate* isolate, ErrorThrower* thrower,
420     Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
421     MaybeHandle<JSArrayBuffer> memory_buffer) {
422   v8::metrics::Recorder::ContextId context_id =
423       isolate->GetOrRegisterRecorderContextId(isolate->native_context());
424   InstanceBuilder builder(isolate, context_id, thrower, module_object, imports,
425                           memory_buffer);
426   auto instance = builder.Build();
427   if (!instance.is_null() && builder.ExecuteStartFunction()) {
428     return instance;
429   }
430   DCHECK(isolate->has_pending_exception() || thrower->error());
431   return {};
432 }
433 
InstanceBuilder(Isolate * isolate,v8::metrics::Recorder::ContextId context_id,ErrorThrower * thrower,Handle<WasmModuleObject> module_object,MaybeHandle<JSReceiver> ffi,MaybeHandle<JSArrayBuffer> memory_buffer)434 InstanceBuilder::InstanceBuilder(Isolate* isolate,
435                                  v8::metrics::Recorder::ContextId context_id,
436                                  ErrorThrower* thrower,
437                                  Handle<WasmModuleObject> module_object,
438                                  MaybeHandle<JSReceiver> ffi,
439                                  MaybeHandle<JSArrayBuffer> memory_buffer)
440     : isolate_(isolate),
441       context_id_(context_id),
442       enabled_(module_object->native_module()->enabled_features()),
443       module_(module_object->module()),
444       thrower_(thrower),
445       module_object_(module_object),
446       ffi_(ffi),
447       memory_buffer_(memory_buffer),
448       init_expr_zone_(isolate_->allocator(), "init. expression zone") {
449   sanitized_imports_.reserve(module_->import_table.size());
450 }
451 
452 // Build an instance, in all of its glory.
Build()453 MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
454   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
455                "wasm.InstanceBuilder.Build");
456   // Check that an imports argument was provided, if the module requires it.
457   // No point in continuing otherwise.
458   if (!module_->import_table.empty() && ffi_.is_null()) {
459     thrower_->TypeError(
460         "Imports argument must be present and must be an object");
461     return {};
462   }
463 
464   SanitizeImports();
465   if (thrower_->error()) return {};
466 
467   // From here on, we expect the build pipeline to run without exiting to JS.
468   DisallowJavascriptExecution no_js(isolate_);
469   // Record build time into correct bucket, then build instance.
470   TimedHistogramScope wasm_instantiate_module_time_scope(SELECT_WASM_COUNTER(
471       isolate_->counters(), module_->origin, wasm_instantiate, module_time));
472   v8::metrics::WasmModuleInstantiated wasm_module_instantiated;
473   base::ElapsedTimer timer;
474   timer.Start();
475   NativeModule* native_module = module_object_->native_module();
476 
477   //--------------------------------------------------------------------------
478   // Set up the memory buffer and memory objects.
479   //--------------------------------------------------------------------------
480   uint32_t initial_pages = module_->initial_pages;
481   auto initial_pages_counter = SELECT_WASM_COUNTER(
482       isolate_->counters(), module_->origin, wasm, min_mem_pages_count);
483   initial_pages_counter->AddSample(initial_pages);
484   if (module_->has_maximum_pages) {
485     DCHECK_EQ(kWasmOrigin, module_->origin);
486     auto max_pages_counter =
487         isolate_->counters()->wasm_wasm_max_mem_pages_count();
488     max_pages_counter->AddSample(module_->maximum_pages);
489   }
490 
491   if (is_asmjs_module(module_)) {
492     Handle<JSArrayBuffer> buffer;
493     if (memory_buffer_.ToHandle(&buffer)) {
494       // asm.js instantiation should have changed the state of the buffer.
495       CHECK(!buffer->is_detachable());
496       CHECK(buffer->is_asmjs_memory());
497     } else {
498       // Use an empty JSArrayBuffer for degenerate asm.js modules.
499       memory_buffer_ = isolate_->factory()->NewJSArrayBufferAndBackingStore(
500           0, InitializedFlag::kUninitialized);
501       if (!memory_buffer_.ToHandle(&buffer)) {
502         thrower_->RangeError("Out of memory: asm.js memory");
503         return {};
504       }
505       buffer->set_is_asmjs_memory(true);
506       buffer->set_is_detachable(false);
507     }
508 
509     // The maximum number of pages isn't strictly necessary for memory
510     // objects used for asm.js, as they are never visible, but we might
511     // as well make it accurate.
512     auto maximum_pages =
513         static_cast<int>(RoundUp(buffer->byte_length(), wasm::kWasmPageSize) /
514                          wasm::kWasmPageSize);
515     memory_object_ =
516         WasmMemoryObject::New(isolate_, memory_buffer_, maximum_pages)
517             .ToHandleChecked();
518   } else {
519     // Actual wasm module must have either imported or created memory.
520     CHECK(memory_buffer_.is_null());
521     if (!FindImportedMemory()) {
522       if (module_->has_memory && !AllocateMemory()) {
523         DCHECK(isolate_->has_pending_exception() || thrower_->error());
524         return {};
525       }
526     }
527   }
528 
529   //--------------------------------------------------------------------------
530   // Create the WebAssembly.Instance object.
531   //--------------------------------------------------------------------------
532   TRACE("New module instantiation for %p\n", native_module);
533   Handle<WasmInstanceObject> instance =
534       WasmInstanceObject::New(isolate_, module_object_);
535 
536   //--------------------------------------------------------------------------
537   // Attach the memory to the instance.
538   //--------------------------------------------------------------------------
539   if (module_->has_memory) {
540     DCHECK(!memory_object_.is_null());
541     if (!instance->has_memory_object()) {
542       instance->set_memory_object(*memory_object_);
543     }
544     // Add the instance object to the list of instances for this memory.
545     WasmMemoryObject::AddInstance(isolate_, memory_object_, instance);
546 
547     // Double-check the {memory} array buffer matches the instance.
548     Handle<JSArrayBuffer> memory = memory_buffer_.ToHandleChecked();
549     CHECK_EQ(instance->memory_size(), memory->byte_length());
550     CHECK_EQ(instance->memory_start(), memory->backing_store());
551   }
552 
553   //--------------------------------------------------------------------------
554   // Set up the globals for the new instance.
555   //--------------------------------------------------------------------------
556   uint32_t untagged_globals_buffer_size = module_->untagged_globals_buffer_size;
557   if (untagged_globals_buffer_size > 0) {
558     MaybeHandle<JSArrayBuffer> result =
559         isolate_->factory()->NewJSArrayBufferAndBackingStore(
560             untagged_globals_buffer_size, InitializedFlag::kZeroInitialized,
561             AllocationType::kOld);
562 
563     if (!result.ToHandle(&untagged_globals_)) {
564       thrower_->RangeError("Out of memory: wasm globals");
565       return {};
566     }
567 
568     instance->set_untagged_globals_buffer(*untagged_globals_);
569     instance->set_globals_start(
570         reinterpret_cast<byte*>(untagged_globals_->backing_store()));
571   }
572 
573   uint32_t tagged_globals_buffer_size = module_->tagged_globals_buffer_size;
574   if (tagged_globals_buffer_size > 0) {
575     tagged_globals_ = isolate_->factory()->NewFixedArray(
576         static_cast<int>(tagged_globals_buffer_size));
577     instance->set_tagged_globals_buffer(*tagged_globals_);
578   }
579 
580   //--------------------------------------------------------------------------
581   // Set up the array of references to imported globals' array buffers.
582   //--------------------------------------------------------------------------
583   if (module_->num_imported_mutable_globals > 0) {
584     // TODO(binji): This allocates one slot for each mutable global, which is
585     // more than required if multiple globals are imported from the same
586     // module.
587     Handle<FixedArray> buffers_array = isolate_->factory()->NewFixedArray(
588         module_->num_imported_mutable_globals, AllocationType::kOld);
589     instance->set_imported_mutable_globals_buffers(*buffers_array);
590   }
591 
592   //--------------------------------------------------------------------------
593   // Set up the tag table used for exception tag checks.
594   //--------------------------------------------------------------------------
595   int tags_count = static_cast<int>(module_->tags.size());
596   if (tags_count > 0) {
597     Handle<FixedArray> tag_table =
598         isolate_->factory()->NewFixedArray(tags_count, AllocationType::kOld);
599     instance->set_tags_table(*tag_table);
600     tags_wrappers_.resize(tags_count);
601   }
602 
603   //--------------------------------------------------------------------------
604   // Set up table storage space.
605   //--------------------------------------------------------------------------
606   int table_count = static_cast<int>(module_->tables.size());
607   {
608     for (int i = 0; i < table_count; i++) {
609       const WasmTable& table = module_->tables[i];
610       if (table.initial_size > FLAG_wasm_max_table_size) {
611         thrower_->RangeError(
612             "initial table size (%u elements) is larger than implementation "
613             "limit (%u elements)",
614             table.initial_size, FLAG_wasm_max_table_size);
615         return {};
616       }
617     }
618 
619     Handle<FixedArray> tables = isolate_->factory()->NewFixedArray(table_count);
620     for (int i = module_->num_imported_tables; i < table_count; i++) {
621       const WasmTable& table = module_->tables[i];
622       // Initialize tables with null for now. We will initialize non-defaultable
623       // tables later, in {InitializeNonDefaultableTables}.
624       Handle<WasmTableObject> table_obj = WasmTableObject::New(
625           isolate_, instance, table.type, table.initial_size,
626           table.has_maximum_size, table.maximum_size, nullptr,
627           isolate_->factory()->null_value());
628       tables->set(i, *table_obj);
629     }
630     instance->set_tables(*tables);
631   }
632 
633   {
634     Handle<FixedArray> tables = isolate_->factory()->NewFixedArray(table_count);
635     for (int i = 0; i < table_count; ++i) {
636       const WasmTable& table = module_->tables[i];
637       if (IsSubtypeOf(table.type, kWasmFuncRef, module_)) {
638         Handle<WasmIndirectFunctionTable> table_obj =
639             WasmIndirectFunctionTable::New(isolate_, table.initial_size);
640         tables->set(i, *table_obj);
641       }
642     }
643     instance->set_indirect_function_tables(*tables);
644   }
645 
646   instance->SetIndirectFunctionTableShortcuts(isolate_);
647 
648   //--------------------------------------------------------------------------
649   // Process the imports for the module.
650   //--------------------------------------------------------------------------
651   if (!module_->import_table.empty()) {
652     int num_imported_functions = ProcessImports(instance);
653     if (num_imported_functions < 0) return {};
654     wasm_module_instantiated.imported_function_count = num_imported_functions;
655   }
656 
657   //--------------------------------------------------------------------------
658   // Create maps for managed objects (GC proposal).
659   // Must happen before {InitGlobals} because globals can refer to these maps.
660   // We do not need to cache the canonical rtts to (rtt.canon any)'s subtype
661   // list.
662   //--------------------------------------------------------------------------
663   if (enabled_.has_gc()) {
664     if (FLAG_wasm_type_canonicalization) {
665       uint32_t maximum_canonical_type_index =
666           *std::max_element(module_->isorecursive_canonical_type_ids.begin(),
667                             module_->isorecursive_canonical_type_ids.end());
668       // Make sure all canonical indices have been set.
669       DCHECK_NE(maximum_canonical_type_index, kNoSuperType);
670       isolate_->heap()->EnsureWasmCanonicalRttsSize(
671           maximum_canonical_type_index + 1);
672     }
673     Handle<FixedArray> maps = isolate_->factory()->NewFixedArray(
674         static_cast<int>(module_->types.size()));
675     for (uint32_t index = 0; index < module_->types.size(); index++) {
676       CreateMapForType(isolate_, module_, index, instance, maps);
677     }
678     instance->set_managed_object_maps(*maps);
679   }
680 
681   //--------------------------------------------------------------------------
682   // Allocate type feedback vectors for functions.
683   //--------------------------------------------------------------------------
684   if (FLAG_wasm_speculative_inlining) {
685     int num_functions = static_cast<int>(module_->num_declared_functions);
686     Handle<FixedArray> vectors =
687         isolate_->factory()->NewFixedArray(num_functions, AllocationType::kOld);
688     instance->set_feedback_vectors(*vectors);
689     for (int i = 0; i < num_functions; i++) {
690       int func_index = module_->num_imported_functions + i;
691       int slots =
692           base::Relaxed_Load(&module_->functions[func_index].feedback_slots);
693       if (slots == 0) continue;
694       if (FLAG_trace_wasm_speculative_inlining) {
695         PrintF("[Function %d (declared %d): allocating %d feedback slots]\n",
696                func_index, i, slots);
697       }
698       Handle<FixedArray> feedback =
699           isolate_->factory()->NewFixedArrayWithZeroes(slots);
700       vectors->set(i, *feedback);
701     }
702   }
703 
704   //--------------------------------------------------------------------------
705   // Process the initialization for the module's globals.
706   //--------------------------------------------------------------------------
707   InitGlobals(instance);
708 
709   //--------------------------------------------------------------------------
710   // Initialize the indirect function tables and dispatch tables. We do this
711   // before initializing non-defaultable tables and loading element segments, so
712   // that indirect function tables in this module are included in the updates
713   // when we do so.
714   //--------------------------------------------------------------------------
715   for (int table_index = 0;
716        table_index < static_cast<int>(module_->tables.size()); ++table_index) {
717     const WasmTable& table = module_->tables[table_index];
718 
719     if (IsSubtypeOf(table.type, kWasmFuncRef, module_)) {
720       WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
721           instance, table_index, table.initial_size);
722       if (thrower_->error()) return {};
723       auto table_object = handle(
724           WasmTableObject::cast(instance->tables().get(table_index)), isolate_);
725       WasmTableObject::AddDispatchTable(isolate_, table_object, instance,
726                                         table_index);
727     }
728   }
729 
730   //--------------------------------------------------------------------------
731   // Initialize non-defaultable tables.
732   //--------------------------------------------------------------------------
733   if (FLAG_experimental_wasm_typed_funcref) {
734     InitializeNonDefaultableTables(instance);
735   }
736 
737   //--------------------------------------------------------------------------
738   // Initialize the tags table.
739   //--------------------------------------------------------------------------
740   if (tags_count > 0) {
741     InitializeTags(instance);
742   }
743 
744   //--------------------------------------------------------------------------
745   // Set up the exports object for the new instance.
746   //--------------------------------------------------------------------------
747   ProcessExports(instance);
748   if (thrower_->error()) return {};
749 
750   //--------------------------------------------------------------------------
751   // Load element segments into tables.
752   //--------------------------------------------------------------------------
753   if (table_count > 0) {
754     LoadTableSegments(instance);
755     if (thrower_->error()) return {};
756   }
757 
758   //--------------------------------------------------------------------------
759   // Initialize the memory by loading data segments.
760   //--------------------------------------------------------------------------
761   if (module_->data_segments.size() > 0) {
762     LoadDataSegments(instance);
763     if (thrower_->error()) return {};
764   }
765 
766   //--------------------------------------------------------------------------
767   // Create a wrapper for the start function.
768   //--------------------------------------------------------------------------
769   if (module_->start_function_index >= 0) {
770     int start_index = module_->start_function_index;
771     auto& function = module_->functions[start_index];
772     Handle<CodeT> wrapper_code =
773         ToCodeT(JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper(
774                     isolate_, function.sig, module_, function.imported),
775                 isolate_);
776     // TODO(clemensb): Don't generate an exported function for the start
777     // function. Use CWasmEntry instead.
778     start_function_ = WasmExportedFunction::New(
779         isolate_, instance, start_index,
780         static_cast<int>(function.sig->parameter_count()), wrapper_code);
781 
782     if (function.imported) {
783       ImportedFunctionEntry entry(instance, module_->start_function_index);
784       Object callable = entry.maybe_callable();
785       if (callable.IsJSFunction()) {
786         // If the start function was imported and calls into Blink, we have
787         // to pretend that the V8 API was used to enter its correct context.
788         // To get that context to {ExecuteStartFunction} below, we install it
789         // as the context of the wrapper we just compiled. That's a bit of a
790         // hack because it's not really the wrapper's context, only its wrapped
791         // target's context, but the end result is the same, and since the
792         // start function wrapper doesn't leak, neither does this
793         // implementation detail.
794         start_function_->set_context(JSFunction::cast(callable).context());
795       }
796     }
797   }
798 
799   DCHECK(!isolate_->has_pending_exception());
800   TRACE("Successfully built instance for module %p\n",
801         module_object_->native_module());
802   wasm_module_instantiated.success = true;
803   wasm_module_instantiated.wall_clock_duration_in_us =
804       timer.Elapsed().InMicroseconds();
805   timer.Stop();
806   isolate_->metrics_recorder()->DelayMainThreadEvent(wasm_module_instantiated,
807                                                      context_id_);
808   return instance;
809 }
810 
ExecuteStartFunction()811 bool InstanceBuilder::ExecuteStartFunction() {
812   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
813                "wasm.ExecuteStartFunction");
814   if (start_function_.is_null()) return true;  // No start function.
815 
816   HandleScope scope(isolate_);
817   // In case the start function calls out to Blink, we have to make sure that
818   // the correct "entered context" is available. This is the equivalent of
819   // v8::Context::Enter() and must happen in addition to the function call
820   // sequence doing the compiled version of "isolate->set_context(...)".
821   HandleScopeImplementer* hsi = isolate_->handle_scope_implementer();
822   hsi->EnterContext(start_function_->native_context());
823 
824   // Call the JS function.
825   Handle<Object> undefined = isolate_->factory()->undefined_value();
826   MaybeHandle<Object> retval =
827       Execution::Call(isolate_, start_function_, undefined, 0, nullptr);
828   hsi->LeaveContext();
829 
830   if (retval.is_null()) {
831     DCHECK(isolate_->has_pending_exception());
832     return false;
833   }
834   return true;
835 }
836 
837 // Look up an import value in the {ffi_} object.
LookupImport(uint32_t index,Handle<String> module_name,Handle<String> import_name)838 MaybeHandle<Object> InstanceBuilder::LookupImport(uint32_t index,
839                                                   Handle<String> module_name,
840                                                   Handle<String> import_name) {
841   // We pre-validated in the js-api layer that the ffi object is present, and
842   // a JSObject, if the module has imports.
843   DCHECK(!ffi_.is_null());
844   // Look up the module first.
845   MaybeHandle<Object> result = Object::GetPropertyOrElement(
846       isolate_, ffi_.ToHandleChecked(), module_name);
847   if (result.is_null()) {
848     return ReportTypeError("module not found", index, module_name);
849   }
850 
851   Handle<Object> module = result.ToHandleChecked();
852 
853   // Look up the value in the module.
854   if (!module->IsJSReceiver()) {
855     return ReportTypeError("module is not an object or function", index,
856                            module_name);
857   }
858 
859   result = Object::GetPropertyOrElement(isolate_, module, import_name);
860   if (result.is_null()) {
861     ReportLinkError("import not found", index, module_name, import_name);
862     return MaybeHandle<JSFunction>();
863   }
864 
865   return result;
866 }
867 
868 namespace {
HasDefaultToNumberBehaviour(Isolate * isolate,Handle<JSFunction> function)869 bool HasDefaultToNumberBehaviour(Isolate* isolate,
870                                  Handle<JSFunction> function) {
871   // Disallow providing a [Symbol.toPrimitive] member.
872   LookupIterator to_primitive_it{isolate, function,
873                                  isolate->factory()->to_primitive_symbol()};
874   if (to_primitive_it.state() != LookupIterator::NOT_FOUND) return false;
875 
876   // The {valueOf} member must be the default "ObjectPrototypeValueOf".
877   LookupIterator value_of_it{isolate, function,
878                              isolate->factory()->valueOf_string()};
879   if (value_of_it.state() != LookupIterator::DATA) return false;
880   Handle<Object> value_of = value_of_it.GetDataValue();
881   if (!value_of->IsJSFunction()) return false;
882   Builtin value_of_builtin_id =
883       Handle<JSFunction>::cast(value_of)->code().builtin_id();
884   if (value_of_builtin_id != Builtin::kObjectPrototypeValueOf) return false;
885 
886   // The {toString} member must be the default "FunctionPrototypeToString".
887   LookupIterator to_string_it{isolate, function,
888                               isolate->factory()->toString_string()};
889   if (to_string_it.state() != LookupIterator::DATA) return false;
890   Handle<Object> to_string = to_string_it.GetDataValue();
891   if (!to_string->IsJSFunction()) return false;
892   Builtin to_string_builtin_id =
893       Handle<JSFunction>::cast(to_string)->code().builtin_id();
894   if (to_string_builtin_id != Builtin::kFunctionPrototypeToString) return false;
895 
896   // Just a default function, which will convert to "Nan". Accept this.
897   return true;
898 }
899 
EvaluateInitExpression(Zone * zone,ConstantExpression expr,ValueType expected,Isolate * isolate,Handle<WasmInstanceObject> instance,ErrorThrower * thrower)900 V8_INLINE WasmValue EvaluateInitExpression(Zone* zone, ConstantExpression expr,
901                                            ValueType expected, Isolate* isolate,
902                                            Handle<WasmInstanceObject> instance,
903                                            ErrorThrower* thrower) {
904   switch (expr.kind()) {
905     case ConstantExpression::kEmpty:
906       UNREACHABLE();
907     case ConstantExpression::kI32Const:
908       return WasmValue(expr.i32_value());
909     case ConstantExpression::kRefNull:
910       return WasmValue(isolate->factory()->null_value(),
911                        ValueType::Ref(expr.repr(), kNullable));
912     case ConstantExpression::kRefFunc: {
913       uint32_t index = expr.index();
914       Handle<Object> value =
915           WasmInstanceObject::GetOrCreateWasmInternalFunction(isolate, instance,
916                                                               index);
917       return WasmValue(value, expected);
918     }
919     case ConstantExpression::kWireBytesRef: {
920       WireBytesRef ref = expr.wire_bytes_ref();
921 
922       base::Vector<const byte> module_bytes =
923           instance->module_object().native_module()->wire_bytes();
924 
925       const byte* start = module_bytes.begin() + ref.offset();
926       const byte* end = module_bytes.begin() + ref.end_offset();
927 
928       auto sig = FixedSizeSignature<ValueType>::Returns(expected);
929       FunctionBody body(&sig, ref.offset(), start, end);
930       WasmFeatures detected;
931       // We use kFullValidation so we do not have to create another template
932       // instance of WasmFullDecoder, which would cost us >50Kb binary code
933       // size.
934       WasmFullDecoder<Decoder::kFullValidation, InitExprInterface,
935                       kInitExpression>
936           decoder(zone, instance->module(), WasmFeatures::All(), &detected,
937                   body, instance->module(), isolate, instance);
938 
939       decoder.DecodeFunctionBody();
940 
941       if (decoder.interface().runtime_error()) {
942         thrower->RuntimeError("%s", decoder.interface().runtime_error_msg());
943         return {};
944       }
945 
946       return decoder.interface().result();
947     }
948   }
949 }
950 }  // namespace
951 
952 // Look up an import value in the {ffi_} object specifically for linking an
953 // asm.js module. This only performs non-observable lookups, which allows
954 // falling back to JavaScript proper (and hence re-executing all lookups) if
955 // module instantiation fails.
LookupImportAsm(uint32_t index,Handle<String> import_name)956 MaybeHandle<Object> InstanceBuilder::LookupImportAsm(
957     uint32_t index, Handle<String> import_name) {
958   // Check that a foreign function interface object was provided.
959   if (ffi_.is_null()) {
960     return ReportLinkError("missing imports object", index, import_name);
961   }
962 
963   // Perform lookup of the given {import_name} without causing any observable
964   // side-effect. We only accept accesses that resolve to data properties,
965   // which is indicated by the asm.js spec in section 7 ("Linking") as well.
966   PropertyKey key(isolate_, Handle<Name>::cast(import_name));
967   LookupIterator it(isolate_, ffi_.ToHandleChecked(), key);
968   switch (it.state()) {
969     case LookupIterator::ACCESS_CHECK:
970     case LookupIterator::INTEGER_INDEXED_EXOTIC:
971     case LookupIterator::INTERCEPTOR:
972     case LookupIterator::JSPROXY:
973     case LookupIterator::ACCESSOR:
974     case LookupIterator::TRANSITION:
975       return ReportLinkError("not a data property", index, import_name);
976     case LookupIterator::NOT_FOUND:
977       // Accepting missing properties as undefined does not cause any
978       // observable difference from JavaScript semantics, we are lenient.
979       return isolate_->factory()->undefined_value();
980     case LookupIterator::DATA: {
981       Handle<Object> value = it.GetDataValue();
982       // For legacy reasons, we accept functions for imported globals (see
983       // {ProcessImportedGlobal}), but only if we can easily determine that
984       // their Number-conversion is side effect free and returns NaN (which is
985       // the case as long as "valueOf" (or others) are not overwritten).
986       if (value->IsJSFunction() &&
987           module_->import_table[index].kind == kExternalGlobal &&
988           !HasDefaultToNumberBehaviour(isolate_,
989                                        Handle<JSFunction>::cast(value))) {
990         return ReportLinkError("function has special ToNumber behaviour", index,
991                                import_name);
992       }
993       return value;
994     }
995   }
996 }
997 
998 // Load data segments into the memory.
LoadDataSegments(Handle<WasmInstanceObject> instance)999 void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
1000   base::Vector<const uint8_t> wire_bytes =
1001       module_object_->native_module()->wire_bytes();
1002   for (const WasmDataSegment& segment : module_->data_segments) {
1003     uint32_t size = segment.source.length();
1004 
1005     // Passive segments are not copied during instantiation.
1006     if (!segment.active) continue;
1007 
1008     size_t dest_offset;
1009     if (module_->is_memory64) {
1010       uint64_t dest_offset_64 =
1011           EvaluateInitExpression(&init_expr_zone_, segment.dest_addr, kWasmI64,
1012                                  isolate_, instance, thrower_)
1013               .to_u64();
1014       if (thrower_->error()) return;
1015       // Clamp to {std::numeric_limits<size_t>::max()}, which is always an
1016       // invalid offset.
1017       DCHECK_GT(std::numeric_limits<size_t>::max(), instance->memory_size());
1018       dest_offset = static_cast<size_t>(std::min(
1019           dest_offset_64, uint64_t{std::numeric_limits<size_t>::max()}));
1020     } else {
1021       dest_offset =
1022           EvaluateInitExpression(&init_expr_zone_, segment.dest_addr, kWasmI32,
1023                                  isolate_, instance, thrower_)
1024               .to_u32();
1025       if (thrower_->error()) return;
1026     }
1027 
1028     if (!base::IsInBounds<size_t>(dest_offset, size, instance->memory_size())) {
1029       thrower_->RuntimeError("data segment is out of bounds");
1030       return;
1031     }
1032 
1033     std::memcpy(instance->memory_start() + dest_offset,
1034                 wire_bytes.begin() + segment.source.offset(), size);
1035   }
1036 }
1037 
WriteGlobalValue(const WasmGlobal & global,const WasmValue & value)1038 void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global,
1039                                        const WasmValue& value) {
1040   TRACE("init [globals_start=%p + %u] = %s, type = %s\n",
1041         global.type.is_reference()
1042             ? reinterpret_cast<byte*>(tagged_globals_->address())
1043             : raw_buffer_ptr(untagged_globals_, 0),
1044         global.offset, value.to_string().c_str(), global.type.name().c_str());
1045   DCHECK(IsSubtypeOf(value.type(), global.type, module_));
1046   if (global.type.is_numeric()) {
1047     value.CopyTo(GetRawUntaggedGlobalPtr<byte>(global));
1048   } else {
1049     tagged_globals_->set(global.offset, *value.to_ref());
1050   }
1051 }
1052 
SanitizeImports()1053 void InstanceBuilder::SanitizeImports() {
1054   base::Vector<const uint8_t> wire_bytes =
1055       module_object_->native_module()->wire_bytes();
1056   for (size_t index = 0; index < module_->import_table.size(); ++index) {
1057     const WasmImport& import = module_->import_table[index];
1058 
1059     Handle<String> module_name =
1060         WasmModuleObject::ExtractUtf8StringFromModuleBytes(
1061             isolate_, wire_bytes, import.module_name, kInternalize);
1062 
1063     Handle<String> import_name =
1064         WasmModuleObject::ExtractUtf8StringFromModuleBytes(
1065             isolate_, wire_bytes, import.field_name, kInternalize);
1066 
1067     int int_index = static_cast<int>(index);
1068     MaybeHandle<Object> result =
1069         is_asmjs_module(module_)
1070             ? LookupImportAsm(int_index, import_name)
1071             : LookupImport(int_index, module_name, import_name);
1072     if (thrower_->error()) {
1073       thrower_->LinkError("Could not find value for import %zu", index);
1074       return;
1075     }
1076     Handle<Object> value = result.ToHandleChecked();
1077     sanitized_imports_.push_back({module_name, import_name, value});
1078   }
1079 }
1080 
FindImportedMemory()1081 bool InstanceBuilder::FindImportedMemory() {
1082   DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
1083   for (size_t index = 0; index < module_->import_table.size(); index++) {
1084     WasmImport import = module_->import_table[index];
1085 
1086     if (import.kind == kExternalMemory) {
1087       auto& value = sanitized_imports_[index].value;
1088       if (!value->IsWasmMemoryObject()) return false;
1089       memory_object_ = Handle<WasmMemoryObject>::cast(value);
1090       memory_buffer_ =
1091           Handle<JSArrayBuffer>(memory_object_->array_buffer(), isolate_);
1092       return true;
1093     }
1094   }
1095   return false;
1096 }
1097 
ProcessImportedFunction(Handle<WasmInstanceObject> instance,int import_index,int func_index,Handle<String> module_name,Handle<String> import_name,Handle<Object> value)1098 bool InstanceBuilder::ProcessImportedFunction(
1099     Handle<WasmInstanceObject> instance, int import_index, int func_index,
1100     Handle<String> module_name, Handle<String> import_name,
1101     Handle<Object> value) {
1102   // Function imports must be callable.
1103   if (!value->IsCallable()) {
1104     ReportLinkError("function import requires a callable", import_index,
1105                     module_name, import_name);
1106     return false;
1107   }
1108   // Store any {WasmExternalFunction} callable in the instance before the call
1109   // is resolved to preserve its identity. This handles exported functions as
1110   // well as functions constructed via other means (e.g. WebAssembly.Function).
1111   if (WasmExternalFunction::IsWasmExternalFunction(*value)) {
1112     WasmInstanceObject::SetWasmInternalFunction(
1113         isolate_, instance, func_index,
1114         WasmInternalFunction::FromExternal(
1115             Handle<WasmExternalFunction>::cast(value), isolate_)
1116             .ToHandleChecked());
1117   }
1118   auto js_receiver = Handle<JSReceiver>::cast(value);
1119   const FunctionSig* expected_sig = module_->functions[func_index].sig;
1120   auto resolved = compiler::ResolveWasmImportCall(js_receiver, expected_sig,
1121                                                   module_, enabled_);
1122   compiler::WasmImportCallKind kind = resolved.kind;
1123   js_receiver = resolved.callable;
1124   switch (kind) {
1125     case compiler::WasmImportCallKind::kLinkError:
1126       ReportLinkError("imported function does not match the expected type",
1127                       import_index, module_name, import_name);
1128       return false;
1129     case compiler::WasmImportCallKind::kWasmToWasm: {
1130       // The imported function is a Wasm function from another instance.
1131       auto imported_function = Handle<WasmExportedFunction>::cast(js_receiver);
1132       Handle<WasmInstanceObject> imported_instance(
1133           imported_function->instance(), isolate_);
1134       // The import reference is the instance object itself.
1135       Address imported_target = imported_function->GetWasmCallTarget();
1136       ImportedFunctionEntry entry(instance, func_index);
1137       entry.SetWasmToWasm(*imported_instance, imported_target);
1138       break;
1139     }
1140     case compiler::WasmImportCallKind::kWasmToCapi: {
1141       NativeModule* native_module = instance->module_object().native_module();
1142       int expected_arity = static_cast<int>(expected_sig->parameter_count());
1143       WasmImportWrapperCache* cache = native_module->import_wrapper_cache();
1144       // TODO(jkummerow): Consider precompiling CapiCallWrappers in parallel,
1145       // just like other import wrappers.
1146       WasmCode* wasm_code =
1147           cache->MaybeGet(kind, expected_sig, expected_arity, kNoSuspend);
1148       if (wasm_code == nullptr) {
1149         WasmCodeRefScope code_ref_scope;
1150         WasmImportWrapperCache::ModificationScope cache_scope(cache);
1151         wasm_code =
1152             compiler::CompileWasmCapiCallWrapper(native_module, expected_sig);
1153         WasmImportWrapperCache::CacheKey key(kind, expected_sig, expected_arity,
1154                                              kNoSuspend);
1155         cache_scope[key] = wasm_code;
1156         wasm_code->IncRef();
1157         isolate_->counters()->wasm_generated_code_size()->Increment(
1158             wasm_code->instructions().length());
1159         isolate_->counters()->wasm_reloc_size()->Increment(
1160             wasm_code->reloc_info().length());
1161       }
1162 
1163       ImportedFunctionEntry entry(instance, func_index);
1164       // We re-use the SetWasmToJs infrastructure because it passes the
1165       // callable to the wrapper, which we need to get the function data.
1166       entry.SetWasmToJs(isolate_, js_receiver, wasm_code,
1167                         isolate_->factory()->undefined_value());
1168       break;
1169     }
1170     case compiler::WasmImportCallKind::kWasmToJSFastApi: {
1171       NativeModule* native_module = instance->module_object().native_module();
1172       DCHECK(js_receiver->IsJSFunction());
1173       Handle<JSFunction> function = Handle<JSFunction>::cast(js_receiver);
1174 
1175       WasmCodeRefScope code_ref_scope;
1176       WasmCode* wasm_code = compiler::CompileWasmJSFastCallWrapper(
1177           native_module, expected_sig, function);
1178       ImportedFunctionEntry entry(instance, func_index);
1179       entry.SetWasmToJs(isolate_, js_receiver, wasm_code,
1180                         isolate_->factory()->undefined_value());
1181       break;
1182     }
1183     default: {
1184       // The imported function is a callable.
1185 
1186       int expected_arity = static_cast<int>(expected_sig->parameter_count());
1187       if (kind == compiler::WasmImportCallKind::kJSFunctionArityMismatch) {
1188         Handle<JSFunction> function = Handle<JSFunction>::cast(js_receiver);
1189         SharedFunctionInfo shared = function->shared();
1190         expected_arity =
1191             shared.internal_formal_parameter_count_without_receiver();
1192       }
1193 
1194       NativeModule* native_module = instance->module_object().native_module();
1195       Suspend suspend =
1196           resolved.suspender.is_null() || resolved.suspender->IsUndefined()
1197               ? kNoSuspend
1198               : kSuspend;
1199       WasmCode* wasm_code = native_module->import_wrapper_cache()->Get(
1200           kind, expected_sig, expected_arity, suspend);
1201       DCHECK_NOT_NULL(wasm_code);
1202       ImportedFunctionEntry entry(instance, func_index);
1203       if (wasm_code->kind() == WasmCode::kWasmToJsWrapper) {
1204         // Wasm to JS wrappers are treated specially in the import table.
1205         entry.SetWasmToJs(isolate_, js_receiver, wasm_code, resolved.suspender);
1206       } else {
1207         // Wasm math intrinsics are compiled as regular Wasm functions.
1208         DCHECK(kind >= compiler::WasmImportCallKind::kFirstMathIntrinsic &&
1209                kind <= compiler::WasmImportCallKind::kLastMathIntrinsic);
1210         entry.SetWasmToWasm(*instance, wasm_code->instruction_start());
1211       }
1212       break;
1213     }
1214   }
1215   return true;
1216 }
1217 
InitializeImportedIndirectFunctionTable(Handle<WasmInstanceObject> instance,int table_index,int import_index,Handle<WasmTableObject> table_object)1218 bool InstanceBuilder::InitializeImportedIndirectFunctionTable(
1219     Handle<WasmInstanceObject> instance, int table_index, int import_index,
1220     Handle<WasmTableObject> table_object) {
1221   int imported_table_size = table_object->current_length();
1222   // Allocate a new dispatch table.
1223   WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
1224       instance, table_index, imported_table_size);
1225   // Initialize the dispatch table with the (foreign) JS functions
1226   // that are already in the table.
1227   for (int i = 0; i < imported_table_size; ++i) {
1228     bool is_valid;
1229     bool is_null;
1230     MaybeHandle<WasmInstanceObject> maybe_target_instance;
1231     int function_index;
1232     MaybeHandle<WasmJSFunction> maybe_js_function;
1233     WasmTableObject::GetFunctionTableEntry(
1234         isolate_, module_, table_object, i, &is_valid, &is_null,
1235         &maybe_target_instance, &function_index, &maybe_js_function);
1236     if (!is_valid) {
1237       thrower_->LinkError("table import %d[%d] is not a wasm function",
1238                           import_index, i);
1239       return false;
1240     }
1241     if (is_null) continue;
1242     Handle<WasmJSFunction> js_function;
1243     if (maybe_js_function.ToHandle(&js_function)) {
1244       WasmInstanceObject::ImportWasmJSFunctionIntoTable(
1245           isolate_, instance, table_index, i, js_function);
1246       continue;
1247     }
1248 
1249     Handle<WasmInstanceObject> target_instance =
1250         maybe_target_instance.ToHandleChecked();
1251     const FunctionSig* sig = target_instance->module_object()
1252                                  .module()
1253                                  ->functions[function_index]
1254                                  .sig;
1255 
1256     // Look up the signature's canonical id. If there is no canonical
1257     // id, then the signature does not appear at all in this module,
1258     // so putting {-1} in the table will cause checks to always fail.
1259     FunctionTargetAndRef entry(target_instance, function_index);
1260     instance->GetIndirectFunctionTable(isolate_, table_index)
1261         ->Set(i, module_->signature_map.Find(*sig), entry.call_target(),
1262               *entry.ref());
1263   }
1264   return true;
1265 }
1266 
ProcessImportedTable(Handle<WasmInstanceObject> instance,int import_index,int table_index,Handle<String> module_name,Handle<String> import_name,Handle<Object> value)1267 bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance,
1268                                            int import_index, int table_index,
1269                                            Handle<String> module_name,
1270                                            Handle<String> import_name,
1271                                            Handle<Object> value) {
1272   if (!value->IsWasmTableObject()) {
1273     ReportLinkError("table import requires a WebAssembly.Table", import_index,
1274                     module_name, import_name);
1275     return false;
1276   }
1277   const WasmTable& table = module_->tables[table_index];
1278 
1279   auto table_object = Handle<WasmTableObject>::cast(value);
1280 
1281   uint32_t imported_table_size =
1282       static_cast<uint32_t>(table_object->current_length());
1283   if (imported_table_size < table.initial_size) {
1284     thrower_->LinkError("table import %d is smaller than initial %u, got %u",
1285                         import_index, table.initial_size, imported_table_size);
1286     return false;
1287   }
1288 
1289   if (table.has_maximum_size) {
1290     if (table_object->maximum_length().IsUndefined(isolate_)) {
1291       thrower_->LinkError("table import %d has no maximum length, expected %u",
1292                           import_index, table.maximum_size);
1293       return false;
1294     }
1295     int64_t imported_maximum_size = table_object->maximum_length().Number();
1296     if (imported_maximum_size < 0) {
1297       thrower_->LinkError("table import %d has no maximum length, expected %u",
1298                           import_index, table.maximum_size);
1299       return false;
1300     }
1301     if (imported_maximum_size > table.maximum_size) {
1302       thrower_->LinkError("table import %d has a larger maximum size %" PRIx64
1303                           " than the module's declared maximum %u",
1304                           import_index, imported_maximum_size,
1305                           table.maximum_size);
1306       return false;
1307     }
1308   }
1309 
1310   const WasmModule* table_type_module =
1311       !table_object->instance().IsUndefined()
1312           ? WasmInstanceObject::cast(table_object->instance()).module()
1313           : instance->module();
1314 
1315   if (!EquivalentTypes(table.type, table_object->type(), module_,
1316                        table_type_module)) {
1317     ReportLinkError("imported table does not match the expected type",
1318                     import_index, module_name, import_name);
1319     return false;
1320   }
1321 
1322   if (IsSubtypeOf(table.type, kWasmFuncRef, module_) &&
1323       !InitializeImportedIndirectFunctionTable(instance, table_index,
1324                                                import_index, table_object)) {
1325     return false;
1326   }
1327 
1328   instance->tables().set(table_index, *value);
1329   return true;
1330 }
1331 
ProcessImportedMemory(Handle<WasmInstanceObject> instance,int import_index,Handle<String> module_name,Handle<String> import_name,Handle<Object> value)1332 bool InstanceBuilder::ProcessImportedMemory(Handle<WasmInstanceObject> instance,
1333                                             int import_index,
1334                                             Handle<String> module_name,
1335                                             Handle<String> import_name,
1336                                             Handle<Object> value) {
1337   if (!value->IsWasmMemoryObject()) {
1338     ReportLinkError("memory import must be a WebAssembly.Memory object",
1339                     import_index, module_name, import_name);
1340     return false;
1341   }
1342   auto memory_object = Handle<WasmMemoryObject>::cast(value);
1343 
1344   // The imported memory should have been already set up early.
1345   CHECK_EQ(instance->memory_object(), *memory_object);
1346 
1347   Handle<JSArrayBuffer> buffer(memory_object_->array_buffer(), isolate_);
1348   // memory_ should have already been assigned in Build().
1349   DCHECK_EQ(*memory_buffer_.ToHandleChecked(), *buffer);
1350   uint32_t imported_cur_pages =
1351       static_cast<uint32_t>(buffer->byte_length() / kWasmPageSize);
1352   if (imported_cur_pages < module_->initial_pages) {
1353     thrower_->LinkError("memory import %d is smaller than initial %u, got %u",
1354                         import_index, module_->initial_pages,
1355                         imported_cur_pages);
1356     return false;
1357   }
1358   int32_t imported_maximum_pages = memory_object_->maximum_pages();
1359   if (module_->has_maximum_pages) {
1360     if (imported_maximum_pages < 0) {
1361       thrower_->LinkError(
1362           "memory import %d has no maximum limit, expected at most %u",
1363           import_index, imported_maximum_pages);
1364       return false;
1365     }
1366     if (static_cast<uint32_t>(imported_maximum_pages) >
1367         module_->maximum_pages) {
1368       thrower_->LinkError(
1369           "memory import %d has a larger maximum size %u than the "
1370           "module's declared maximum %u",
1371           import_index, imported_maximum_pages, module_->maximum_pages);
1372       return false;
1373     }
1374   }
1375   if (module_->has_shared_memory != buffer->is_shared()) {
1376     thrower_->LinkError(
1377         "mismatch in shared state of memory, declared = %d, imported = %d",
1378         module_->has_shared_memory, buffer->is_shared());
1379     return false;
1380   }
1381 
1382   return true;
1383 }
1384 
ProcessImportedWasmGlobalObject(Handle<WasmInstanceObject> instance,int import_index,Handle<String> module_name,Handle<String> import_name,const WasmGlobal & global,Handle<WasmGlobalObject> global_object)1385 bool InstanceBuilder::ProcessImportedWasmGlobalObject(
1386     Handle<WasmInstanceObject> instance, int import_index,
1387     Handle<String> module_name, Handle<String> import_name,
1388     const WasmGlobal& global, Handle<WasmGlobalObject> global_object) {
1389   if (static_cast<bool>(global_object->is_mutable()) != global.mutability) {
1390     ReportLinkError("imported global does not match the expected mutability",
1391                     import_index, module_name, import_name);
1392     return false;
1393   }
1394 
1395   const WasmModule* global_type_module =
1396       !global_object->instance().IsUndefined()
1397           ? WasmInstanceObject::cast(global_object->instance()).module()
1398           : instance->module();
1399 
1400   bool valid_type =
1401       global.mutability
1402           ? EquivalentTypes(global_object->type(), global.type,
1403                             global_type_module, instance->module())
1404           : IsSubtypeOf(global_object->type(), global.type, global_type_module,
1405                         instance->module());
1406 
1407   if (!valid_type) {
1408     ReportLinkError("imported global does not match the expected type",
1409                     import_index, module_name, import_name);
1410     return false;
1411   }
1412   if (global.mutability) {
1413     DCHECK_LT(global.index, module_->num_imported_mutable_globals);
1414     Handle<Object> buffer;
1415     Address address_or_offset;
1416     if (global.type.is_reference()) {
1417       static_assert(sizeof(global_object->offset()) <= sizeof(Address),
1418                     "The offset into the globals buffer does not fit into "
1419                     "the imported_mutable_globals array");
1420       buffer = handle(global_object->tagged_buffer(), isolate_);
1421       // For externref globals we use a relative offset, not an absolute
1422       // address.
1423       address_or_offset = static_cast<Address>(global_object->offset());
1424     } else {
1425       buffer = handle(global_object->untagged_buffer(), isolate_);
1426       // It is safe in this case to store the raw pointer to the buffer
1427       // since the backing store of the JSArrayBuffer will not be
1428       // relocated.
1429       address_or_offset = reinterpret_cast<Address>(raw_buffer_ptr(
1430           Handle<JSArrayBuffer>::cast(buffer), global_object->offset()));
1431     }
1432     instance->imported_mutable_globals_buffers().set(global.index, *buffer);
1433     instance->imported_mutable_globals()[global.index] = address_or_offset;
1434     return true;
1435   }
1436 
1437   WasmValue value;
1438   switch (global_object->type().kind()) {
1439     case kI32:
1440       value = WasmValue(global_object->GetI32());
1441       break;
1442     case kI64:
1443       value = WasmValue(global_object->GetI64());
1444       break;
1445     case kF32:
1446       value = WasmValue(global_object->GetF32());
1447       break;
1448     case kF64:
1449       value = WasmValue(global_object->GetF64());
1450       break;
1451     case kRtt:
1452     case kRef:
1453     case kOptRef:
1454       value = WasmValue(global_object->GetRef(), global_object->type());
1455       break;
1456     case kVoid:
1457     case kS128:
1458     case kBottom:
1459     case kI8:
1460     case kI16:
1461       UNREACHABLE();
1462   }
1463 
1464   WriteGlobalValue(global, value);
1465   return true;
1466 }
1467 
ProcessImportedGlobal(Handle<WasmInstanceObject> instance,int import_index,int global_index,Handle<String> module_name,Handle<String> import_name,Handle<Object> value)1468 bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
1469                                             int import_index, int global_index,
1470                                             Handle<String> module_name,
1471                                             Handle<String> import_name,
1472                                             Handle<Object> value) {
1473   // Immutable global imports are converted to numbers and written into
1474   // the {untagged_globals_} array buffer.
1475   //
1476   // Mutable global imports instead have their backing array buffers
1477   // referenced by this instance, and store the address of the imported
1478   // global in the {imported_mutable_globals_} array.
1479   const WasmGlobal& global = module_->globals[global_index];
1480 
1481   // SIMD proposal allows modules to define an imported v128 global, and only
1482   // supports importing a WebAssembly.Global object for this global, but also
1483   // defines constructing a WebAssembly.Global of v128 to be a TypeError.
1484   // We *should* never hit this case in the JS API, but the module should should
1485   // be allowed to declare such a global (no validation error).
1486   if (global.type == kWasmS128 && !value->IsWasmGlobalObject()) {
1487     ReportLinkError("global import of type v128 must be a WebAssembly.Global",
1488                     import_index, module_name, import_name);
1489     return false;
1490   }
1491 
1492   if (is_asmjs_module(module_)) {
1493     // Accepting {JSFunction} on top of just primitive values here is a
1494     // workaround to support legacy asm.js code with broken binding. Note
1495     // that using {NaN} (or Smi::zero()) here is what using the observable
1496     // conversion via {ToPrimitive} would produce as well. {LookupImportAsm}
1497     // checked via {HasDefaultToNumberBehaviour} that "valueOf" or friends have
1498     // not been patched.
1499     if (value->IsJSFunction()) value = isolate_->factory()->nan_value();
1500     if (value->IsPrimitive()) {
1501       MaybeHandle<Object> converted = global.type == kWasmI32
1502                                           ? Object::ToInt32(isolate_, value)
1503                                           : Object::ToNumber(isolate_, value);
1504       if (!converted.ToHandle(&value)) {
1505         // Conversion is known to fail for Symbols and BigInts.
1506         ReportLinkError("global import must be a number", import_index,
1507                         module_name, import_name);
1508         return false;
1509       }
1510     }
1511   }
1512 
1513   if (value->IsWasmGlobalObject()) {
1514     auto global_object = Handle<WasmGlobalObject>::cast(value);
1515     return ProcessImportedWasmGlobalObject(instance, import_index, module_name,
1516                                            import_name, global, global_object);
1517   }
1518 
1519   if (global.mutability) {
1520     ReportLinkError(
1521         "imported mutable global must be a WebAssembly.Global object",
1522         import_index, module_name, import_name);
1523     return false;
1524   }
1525 
1526   if (global.type.is_reference()) {
1527     const char* error_message;
1528     if (!wasm::TypecheckJSObject(isolate_, module_, value, global.type,
1529                                  &error_message)) {
1530       ReportLinkError(error_message, global_index, module_name, import_name);
1531       return false;
1532     }
1533     if (IsSubtypeOf(global.type, kWasmFuncRef, module_) && !value->IsNull()) {
1534       value =
1535           WasmInternalFunction::FromExternal(value, isolate_).ToHandleChecked();
1536     }
1537     WriteGlobalValue(global, WasmValue(value, global.type));
1538     return true;
1539   }
1540 
1541   if (value->IsNumber() && global.type != kWasmI64) {
1542     double number_value = value->Number();
1543     // The Wasm-BigInt proposal currently says that i64 globals may
1544     // only be initialized with BigInts. See:
1545     // https://github.com/WebAssembly/JS-BigInt-integration/issues/12
1546     WasmValue wasm_value = global.type == kWasmI32
1547                                ? WasmValue(DoubleToInt32(number_value))
1548                                : global.type == kWasmF32
1549                                      ? WasmValue(DoubleToFloat32(number_value))
1550                                      : WasmValue(number_value);
1551     WriteGlobalValue(global, wasm_value);
1552     return true;
1553   }
1554 
1555   if (global.type == kWasmI64 && value->IsBigInt()) {
1556     WriteGlobalValue(global, WasmValue(BigInt::cast(*value).AsInt64()));
1557     return true;
1558   }
1559 
1560   ReportLinkError(
1561       "global import must be a number, valid Wasm reference, or "
1562       "WebAssembly.Global object",
1563       import_index, module_name, import_name);
1564   return false;
1565 }
1566 
CompileImportWrappers(Handle<WasmInstanceObject> instance)1567 void InstanceBuilder::CompileImportWrappers(
1568     Handle<WasmInstanceObject> instance) {
1569   int num_imports = static_cast<int>(module_->import_table.size());
1570   TRACE_EVENT1("v8.wasm", "wasm.CompileImportWrappers", "num_imports",
1571                num_imports);
1572   NativeModule* native_module = instance->module_object().native_module();
1573   WasmImportWrapperCache::ModificationScope cache_scope(
1574       native_module->import_wrapper_cache());
1575 
1576   // Compilation is done in two steps:
1577   // 1) Insert nullptr entries in the cache for wrappers that need to be
1578   // compiled. 2) Compile wrappers in background tasks using the
1579   // ImportWrapperQueue. This way the cache won't invalidate other iterators
1580   // when inserting a new WasmCode, since the key will already be there.
1581   ImportWrapperQueue import_wrapper_queue;
1582   for (int index = 0; index < num_imports; ++index) {
1583     Handle<Object> value = sanitized_imports_[index].value;
1584     if (module_->import_table[index].kind != kExternalFunction ||
1585         !value->IsCallable()) {
1586       continue;
1587     }
1588     auto js_receiver = Handle<JSReceiver>::cast(value);
1589     uint32_t func_index = module_->import_table[index].index;
1590     const FunctionSig* sig = module_->functions[func_index].sig;
1591     auto resolved =
1592         compiler::ResolveWasmImportCall(js_receiver, sig, module_, enabled_);
1593     compiler::WasmImportCallKind kind = resolved.kind;
1594     if (kind == compiler::WasmImportCallKind::kWasmToWasm ||
1595         kind == compiler::WasmImportCallKind::kLinkError ||
1596         kind == compiler::WasmImportCallKind::kWasmToCapi ||
1597         kind == compiler::WasmImportCallKind::kWasmToJSFastApi) {
1598       continue;
1599     }
1600 
1601     int expected_arity = static_cast<int>(sig->parameter_count());
1602     if (resolved.kind ==
1603         compiler::WasmImportCallKind::kJSFunctionArityMismatch) {
1604       Handle<JSFunction> function = Handle<JSFunction>::cast(resolved.callable);
1605       SharedFunctionInfo shared = function->shared();
1606       expected_arity =
1607           shared.internal_formal_parameter_count_without_receiver();
1608     }
1609 
1610     Suspend suspend =
1611         resolved.suspender.is_null() || resolved.suspender->IsUndefined()
1612             ? kNoSuspend
1613             : kSuspend;
1614     WasmImportWrapperCache::CacheKey key(kind, sig, expected_arity, suspend);
1615     if (cache_scope[key] != nullptr) {
1616       // Cache entry already exists, no need to compile it again.
1617       continue;
1618     }
1619     import_wrapper_queue.insert(key);
1620   }
1621 
1622   auto compile_job_task = std::make_unique<CompileImportWrapperJob>(
1623       isolate_->counters(), native_module, &import_wrapper_queue, &cache_scope);
1624   auto compile_job = V8::GetCurrentPlatform()->PostJob(
1625       TaskPriority::kUserVisible, std::move(compile_job_task));
1626 
1627   // Wait for the job to finish, while contributing in this thread.
1628   compile_job->Join();
1629 }
1630 
1631 // Process the imports, including functions, tables, globals, and memory, in
1632 // order, loading them from the {ffi_} object. Returns the number of imported
1633 // functions.
ProcessImports(Handle<WasmInstanceObject> instance)1634 int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
1635   int num_imported_functions = 0;
1636   int num_imported_tables = 0;
1637 
1638   DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
1639 
1640   CompileImportWrappers(instance);
1641   int num_imports = static_cast<int>(module_->import_table.size());
1642   for (int index = 0; index < num_imports; ++index) {
1643     const WasmImport& import = module_->import_table[index];
1644 
1645     Handle<String> module_name = sanitized_imports_[index].module_name;
1646     Handle<String> import_name = sanitized_imports_[index].import_name;
1647     Handle<Object> value = sanitized_imports_[index].value;
1648 
1649     switch (import.kind) {
1650       case kExternalFunction: {
1651         uint32_t func_index = import.index;
1652         DCHECK_EQ(num_imported_functions, func_index);
1653         if (!ProcessImportedFunction(instance, index, func_index, module_name,
1654                                      import_name, value)) {
1655           return -1;
1656         }
1657         num_imported_functions++;
1658         break;
1659       }
1660       case kExternalTable: {
1661         uint32_t table_index = import.index;
1662         DCHECK_EQ(table_index, num_imported_tables);
1663         if (!ProcessImportedTable(instance, index, table_index, module_name,
1664                                   import_name, value)) {
1665           return -1;
1666         }
1667         num_imported_tables++;
1668         USE(num_imported_tables);
1669         break;
1670       }
1671       case kExternalMemory: {
1672         if (!ProcessImportedMemory(instance, index, module_name, import_name,
1673                                    value)) {
1674           return -1;
1675         }
1676         break;
1677       }
1678       case kExternalGlobal: {
1679         if (!ProcessImportedGlobal(instance, index, import.index, module_name,
1680                                    import_name, value)) {
1681           return -1;
1682         }
1683         break;
1684       }
1685       case kExternalTag: {
1686         if (!value->IsWasmTagObject()) {
1687           ReportLinkError("tag import requires a WebAssembly.Tag", index,
1688                           module_name, import_name);
1689           return -1;
1690         }
1691         Handle<WasmTagObject> imported_tag = Handle<WasmTagObject>::cast(value);
1692         if (!imported_tag->MatchesSignature(module_->tags[import.index].sig)) {
1693           ReportLinkError("imported tag does not match the expected type",
1694                           index, module_name, import_name);
1695           return -1;
1696         }
1697         Object tag = imported_tag->tag();
1698         DCHECK(instance->tags_table().get(import.index).IsUndefined());
1699         instance->tags_table().set(import.index, tag);
1700         tags_wrappers_[import.index] = imported_tag;
1701         break;
1702       }
1703       default:
1704         UNREACHABLE();
1705     }
1706   }
1707   return num_imported_functions;
1708 }
1709 
1710 template <typename T>
GetRawUntaggedGlobalPtr(const WasmGlobal & global)1711 T* InstanceBuilder::GetRawUntaggedGlobalPtr(const WasmGlobal& global) {
1712   return reinterpret_cast<T*>(raw_buffer_ptr(untagged_globals_, global.offset));
1713 }
1714 
1715 // Process initialization of globals.
InitGlobals(Handle<WasmInstanceObject> instance)1716 void InstanceBuilder::InitGlobals(Handle<WasmInstanceObject> instance) {
1717   for (const WasmGlobal& global : module_->globals) {
1718     if (global.mutability && global.imported) continue;
1719     // Happens with imported globals.
1720     if (!global.init.is_set()) continue;
1721 
1722     WasmValue value =
1723         EvaluateInitExpression(&init_expr_zone_, global.init, global.type,
1724                                isolate_, instance, thrower_);
1725     if (thrower_->error()) return;
1726 
1727     if (global.type.is_reference()) {
1728       tagged_globals_->set(global.offset, *value.to_ref());
1729     } else {
1730       value.CopyTo(GetRawUntaggedGlobalPtr<byte>(global));
1731     }
1732   }
1733 }
1734 
1735 // Allocate memory for a module instance as a new JSArrayBuffer.
AllocateMemory()1736 bool InstanceBuilder::AllocateMemory() {
1737   int initial_pages = static_cast<int>(module_->initial_pages);
1738   int maximum_pages = module_->has_maximum_pages
1739                           ? static_cast<int>(module_->maximum_pages)
1740                           : WasmMemoryObject::kNoMaximum;
1741   auto shared = (module_->has_shared_memory && enabled_.has_threads())
1742                     ? SharedFlag::kShared
1743                     : SharedFlag::kNotShared;
1744 
1745   if (!WasmMemoryObject::New(isolate_, initial_pages, maximum_pages, shared)
1746            .ToHandle(&memory_object_)) {
1747     thrower_->RangeError("Out of memory: wasm memory");
1748     return false;
1749   }
1750   memory_buffer_ =
1751       Handle<JSArrayBuffer>(memory_object_->array_buffer(), isolate_);
1752   return true;
1753 }
1754 
1755 // Process the exports, creating wrappers for functions, tables, memories,
1756 // globals, and exceptions.
ProcessExports(Handle<WasmInstanceObject> instance)1757 void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
1758   std::unordered_map<int, Handle<Object>> imported_globals;
1759 
1760   // If an imported WebAssembly function or global gets exported, the export
1761   // has to be identical to to import. Therefore we cache all imported
1762   // WebAssembly functions in the instance, and all imported globals in a map
1763   // here.
1764   for (int index = 0, end = static_cast<int>(module_->import_table.size());
1765        index < end; ++index) {
1766     const WasmImport& import = module_->import_table[index];
1767     if (import.kind == kExternalFunction) {
1768       Handle<Object> value = sanitized_imports_[index].value;
1769       if (WasmExternalFunction::IsWasmExternalFunction(*value)) {
1770         WasmInstanceObject::SetWasmInternalFunction(
1771             isolate_, instance, import.index,
1772             WasmInternalFunction::FromExternal(
1773                 Handle<WasmExternalFunction>::cast(value), isolate_)
1774                 .ToHandleChecked());
1775       }
1776     } else if (import.kind == kExternalGlobal) {
1777       Handle<Object> value = sanitized_imports_[index].value;
1778       if (value->IsWasmGlobalObject()) {
1779         imported_globals[import.index] = value;
1780       }
1781     }
1782   }
1783 
1784   Handle<JSObject> exports_object;
1785   MaybeHandle<String> single_function_name;
1786   bool is_asm_js = is_asmjs_module(module_);
1787   if (is_asm_js) {
1788     Handle<JSFunction> object_function = Handle<JSFunction>(
1789         isolate_->native_context()->object_function(), isolate_);
1790     exports_object = isolate_->factory()->NewJSObject(object_function);
1791     single_function_name =
1792         isolate_->factory()->InternalizeUtf8String(AsmJs::kSingleFunctionName);
1793   } else {
1794     exports_object = isolate_->factory()->NewJSObjectWithNullProto();
1795   }
1796   instance->set_exports_object(*exports_object);
1797 
1798   PropertyDescriptor desc;
1799   desc.set_writable(is_asm_js);
1800   desc.set_enumerable(true);
1801   desc.set_configurable(is_asm_js);
1802 
1803   // Process each export in the export table.
1804   for (const WasmExport& exp : module_->export_table) {
1805     Handle<String> name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
1806         isolate_, module_object_, exp.name, kInternalize);
1807     Handle<JSObject> export_to = exports_object;
1808     switch (exp.kind) {
1809       case kExternalFunction: {
1810         // Wrap and export the code as a JSFunction.
1811         // TODO(wasm): reduce duplication with LoadElemSegment() further below
1812         Handle<WasmInternalFunction> internal =
1813             WasmInstanceObject::GetOrCreateWasmInternalFunction(
1814                 isolate_, instance, exp.index);
1815         Handle<WasmExternalFunction> wasm_external_function =
1816             handle(WasmExternalFunction::cast(internal->external()), isolate_);
1817         desc.set_value(wasm_external_function);
1818 
1819         if (is_asm_js &&
1820             String::Equals(isolate_, name,
1821                            single_function_name.ToHandleChecked())) {
1822           export_to = instance;
1823         }
1824         break;
1825       }
1826       case kExternalTable: {
1827         desc.set_value(handle(instance->tables().get(exp.index), isolate_));
1828         break;
1829       }
1830       case kExternalMemory: {
1831         // Export the memory as a WebAssembly.Memory object. A WasmMemoryObject
1832         // should already be available if the module has memory, since we always
1833         // create or import it when building an WasmInstanceObject.
1834         DCHECK(instance->has_memory_object());
1835         desc.set_value(
1836             Handle<WasmMemoryObject>(instance->memory_object(), isolate_));
1837         break;
1838       }
1839       case kExternalGlobal: {
1840         const WasmGlobal& global = module_->globals[exp.index];
1841         if (global.imported) {
1842           auto cached_global = imported_globals.find(exp.index);
1843           if (cached_global != imported_globals.end()) {
1844             desc.set_value(cached_global->second);
1845             break;
1846           }
1847         }
1848         Handle<JSArrayBuffer> untagged_buffer;
1849         Handle<FixedArray> tagged_buffer;
1850         uint32_t offset;
1851 
1852         if (global.mutability && global.imported) {
1853           Handle<FixedArray> buffers_array(
1854               instance->imported_mutable_globals_buffers(), isolate_);
1855           if (global.type.is_reference()) {
1856             tagged_buffer = handle(
1857                 FixedArray::cast(buffers_array->get(global.index)), isolate_);
1858             // For externref globals we store the relative offset in the
1859             // imported_mutable_globals array instead of an absolute address.
1860             Address addr = instance->imported_mutable_globals()[global.index];
1861             DCHECK_LE(addr, static_cast<Address>(
1862                                 std::numeric_limits<uint32_t>::max()));
1863             offset = static_cast<uint32_t>(addr);
1864           } else {
1865             untagged_buffer =
1866                 handle(JSArrayBuffer::cast(buffers_array->get(global.index)),
1867                        isolate_);
1868             Address global_addr =
1869                 instance->imported_mutable_globals()[global.index];
1870 
1871             size_t buffer_size = untagged_buffer->byte_length();
1872             Address backing_store =
1873                 reinterpret_cast<Address>(untagged_buffer->backing_store());
1874             CHECK(global_addr >= backing_store &&
1875                   global_addr < backing_store + buffer_size);
1876             offset = static_cast<uint32_t>(global_addr - backing_store);
1877           }
1878         } else {
1879           if (global.type.is_reference()) {
1880             tagged_buffer = handle(instance->tagged_globals_buffer(), isolate_);
1881           } else {
1882             untagged_buffer =
1883                 handle(instance->untagged_globals_buffer(), isolate_);
1884           }
1885           offset = global.offset;
1886         }
1887 
1888         // Since the global's array untagged_buffer is always provided,
1889         // allocation should never fail.
1890         Handle<WasmGlobalObject> global_obj =
1891             WasmGlobalObject::New(isolate_, instance, untagged_buffer,
1892                                   tagged_buffer, global.type, offset,
1893                                   global.mutability)
1894                 .ToHandleChecked();
1895         desc.set_value(global_obj);
1896         break;
1897       }
1898       case kExternalTag: {
1899         const WasmTag& tag = module_->tags[exp.index];
1900         Handle<WasmTagObject> wrapper = tags_wrappers_[exp.index];
1901         if (wrapper.is_null()) {
1902           Handle<HeapObject> tag_object(
1903               HeapObject::cast(instance->tags_table().get(exp.index)),
1904               isolate_);
1905           wrapper = WasmTagObject::New(isolate_, tag.sig, tag_object);
1906           tags_wrappers_[exp.index] = wrapper;
1907         }
1908         desc.set_value(wrapper);
1909         break;
1910       }
1911       default:
1912         UNREACHABLE();
1913     }
1914 
1915     v8::Maybe<bool> status = JSReceiver::DefineOwnProperty(
1916         isolate_, export_to, name, &desc, Just(kThrowOnError));
1917     if (!status.IsJust()) {
1918       DisallowGarbageCollection no_gc;
1919       TruncatedUserString<> trunc_name(name->GetCharVector<uint8_t>(no_gc));
1920       thrower_->LinkError("export of %.*s failed.", trunc_name.length(),
1921                           trunc_name.start());
1922       return;
1923     }
1924   }
1925 
1926   if (module_->origin == kWasmOrigin) {
1927     v8::Maybe<bool> success =
1928         JSReceiver::SetIntegrityLevel(exports_object, FROZEN, kDontThrow);
1929     DCHECK(success.FromMaybe(false));
1930     USE(success);
1931   }
1932 }
1933 
1934 namespace {
SetFunctionTablePlaceholder(Isolate * isolate,Handle<WasmInstanceObject> instance,Handle<WasmTableObject> table_object,uint32_t entry_index,uint32_t func_index)1935 V8_INLINE void SetFunctionTablePlaceholder(Isolate* isolate,
1936                                            Handle<WasmInstanceObject> instance,
1937                                            Handle<WasmTableObject> table_object,
1938                                            uint32_t entry_index,
1939                                            uint32_t func_index) {
1940   const WasmModule* module = instance->module();
1941   const WasmFunction* function = &module->functions[func_index];
1942   MaybeHandle<WasmInternalFunction> wasm_internal_function =
1943       WasmInstanceObject::GetWasmInternalFunction(isolate, instance,
1944                                                   func_index);
1945   if (wasm_internal_function.is_null()) {
1946     // No JSFunction entry yet exists for this function. Create a {Tuple2}
1947     // holding the information to lazily allocate one.
1948     WasmTableObject::SetFunctionTablePlaceholder(
1949         isolate, table_object, entry_index, instance, func_index);
1950   } else {
1951     table_object->entries().set(entry_index,
1952                                 *wasm_internal_function.ToHandleChecked());
1953   }
1954   WasmTableObject::UpdateDispatchTables(isolate, *table_object, entry_index,
1955                                         function, *instance);
1956 }
1957 
SetFunctionTableNullEntry(Isolate * isolate,Handle<WasmTableObject> table_object,uint32_t entry_index)1958 V8_INLINE void SetFunctionTableNullEntry(Isolate* isolate,
1959                                          Handle<WasmTableObject> table_object,
1960                                          uint32_t entry_index) {
1961   table_object->entries().set(entry_index, *isolate->factory()->null_value());
1962   WasmTableObject::ClearDispatchTables(isolate, table_object, entry_index);
1963 }
1964 }  // namespace
1965 
InitializeNonDefaultableTables(Handle<WasmInstanceObject> instance)1966 void InstanceBuilder::InitializeNonDefaultableTables(
1967     Handle<WasmInstanceObject> instance) {
1968   for (int table_index = 0;
1969        table_index < static_cast<int>(module_->tables.size()); ++table_index) {
1970     const WasmTable& table = module_->tables[table_index];
1971     if (!table.type.is_defaultable()) {
1972       auto table_object = handle(
1973           WasmTableObject::cast(instance->tables().get(table_index)), isolate_);
1974       bool is_function_table = IsSubtypeOf(table.type, kWasmFuncRef, module_);
1975       if (is_function_table &&
1976           table.initial_value.kind() == ConstantExpression::kRefFunc) {
1977         for (uint32_t entry_index = 0; entry_index < table.initial_size;
1978              entry_index++) {
1979           SetFunctionTablePlaceholder(isolate_, instance, table_object,
1980                                       entry_index, table.initial_value.index());
1981         }
1982       } else if (is_function_table &&
1983                  table.initial_value.kind() == ConstantExpression::kRefNull) {
1984         for (uint32_t entry_index = 0; entry_index < table.initial_size;
1985              entry_index++) {
1986           SetFunctionTableNullEntry(isolate_, table_object, entry_index);
1987         }
1988       } else {
1989         WasmValue value =
1990             EvaluateInitExpression(&init_expr_zone_, table.initial_value,
1991                                    table.type, isolate_, instance, thrower_);
1992         if (thrower_->error()) return;
1993         for (uint32_t entry_index = 0; entry_index < table.initial_size;
1994              entry_index++) {
1995           WasmTableObject::Set(isolate_, table_object, entry_index,
1996                                value.to_ref());
1997         }
1998       }
1999   }
2000 }
2001 }
2002 
2003 namespace {
LoadElemSegmentImpl(Zone * zone,Isolate * isolate,Handle<WasmInstanceObject> instance,Handle<WasmTableObject> table_object,uint32_t table_index,uint32_t segment_index,uint32_t dst,uint32_t src,size_t count)2004 bool LoadElemSegmentImpl(Zone* zone, Isolate* isolate,
2005                          Handle<WasmInstanceObject> instance,
2006                          Handle<WasmTableObject> table_object,
2007                          uint32_t table_index, uint32_t segment_index,
2008                          uint32_t dst, uint32_t src, size_t count) {
2009   DCHECK_LT(segment_index, instance->module()->elem_segments.size());
2010   auto& elem_segment = instance->module()->elem_segments[segment_index];
2011   // TODO(wasm): Move this functionality into wasm-objects, since it is used
2012   // for both instantiation and in the implementation of the table.init
2013   // instruction.
2014   if (!base::IsInBounds<uint64_t>(dst, count, table_object->current_length()) ||
2015       !base::IsInBounds<uint64_t>(
2016           src, count,
2017           instance->dropped_elem_segments()[segment_index] == 0
2018               ? elem_segment.entries.size()
2019               : 0)) {
2020     return false;
2021   }
2022 
2023   bool is_function_table =
2024       IsSubtypeOf(table_object->type(), kWasmFuncRef, instance->module());
2025 
2026   ErrorThrower thrower(isolate, "LoadElemSegment");
2027 
2028   for (size_t i = 0; i < count; ++i) {
2029     ConstantExpression entry = elem_segment.entries[src + i];
2030     int entry_index = static_cast<int>(dst + i);
2031     if (is_function_table && entry.kind() == ConstantExpression::kRefFunc) {
2032       SetFunctionTablePlaceholder(isolate, instance, table_object, entry_index,
2033                                   entry.index());
2034     } else if (is_function_table &&
2035                entry.kind() == ConstantExpression::kRefNull) {
2036       SetFunctionTableNullEntry(isolate, table_object, entry_index);
2037     } else {
2038       WasmValue value = EvaluateInitExpression(zone, entry, elem_segment.type,
2039                                                isolate, instance, &thrower);
2040       if (thrower.error()) return false;
2041       WasmTableObject::Set(isolate, table_object, entry_index, value.to_ref());
2042     }
2043   }
2044   return true;
2045 }
2046 }  // namespace
2047 
LoadTableSegments(Handle<WasmInstanceObject> instance)2048 void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
2049   for (uint32_t segment_index = 0;
2050        segment_index < module_->elem_segments.size(); ++segment_index) {
2051     auto& elem_segment = instance->module()->elem_segments[segment_index];
2052     // Passive segments are not copied during instantiation.
2053     if (elem_segment.status != WasmElemSegment::kStatusActive) continue;
2054 
2055     uint32_t table_index = elem_segment.table_index;
2056     uint32_t dst =
2057         EvaluateInitExpression(&init_expr_zone_, elem_segment.offset, kWasmI32,
2058                                isolate_, instance, thrower_)
2059             .to_u32();
2060     if (thrower_->error()) return;
2061     uint32_t src = 0;
2062     size_t count = elem_segment.entries.size();
2063 
2064     bool success = LoadElemSegmentImpl(
2065         &init_expr_zone_, isolate_, instance,
2066         handle(WasmTableObject::cast(
2067                    instance->tables().get(elem_segment.table_index)),
2068                isolate_),
2069         table_index, segment_index, dst, src, count);
2070     // Set the active segments to being already dropped, since table.init on
2071     // a dropped passive segment and an active segment have the same behavior.
2072     instance->dropped_elem_segments()[segment_index] = 1;
2073     if (!success) {
2074       thrower_->RuntimeError("table initializer is out of bounds");
2075       return;
2076     }
2077   }
2078 }
2079 
InitializeTags(Handle<WasmInstanceObject> instance)2080 void InstanceBuilder::InitializeTags(Handle<WasmInstanceObject> instance) {
2081   Handle<FixedArray> tags_table(instance->tags_table(), isolate_);
2082   for (int index = 0; index < tags_table->length(); ++index) {
2083     if (!tags_table->get(index).IsUndefined(isolate_)) continue;
2084     Handle<WasmExceptionTag> tag = WasmExceptionTag::New(isolate_, index);
2085     tags_table->set(index, *tag);
2086   }
2087 }
2088 
LoadElemSegment(Isolate * isolate,Handle<WasmInstanceObject> instance,uint32_t table_index,uint32_t segment_index,uint32_t dst,uint32_t src,uint32_t count)2089 bool LoadElemSegment(Isolate* isolate, Handle<WasmInstanceObject> instance,
2090                      uint32_t table_index, uint32_t segment_index, uint32_t dst,
2091                      uint32_t src, uint32_t count) {
2092   AccountingAllocator allocator;
2093   // This {Zone} will be used only by the temporary WasmFullDecoder allocated
2094   // down the line from this call. Therefore it is safe to stack-allocate it
2095   // here.
2096   Zone zone(&allocator, "LoadElemSegment");
2097   return LoadElemSegmentImpl(
2098       &zone, isolate, instance,
2099       handle(WasmTableObject::cast(instance->tables().get(table_index)),
2100              isolate),
2101       table_index, segment_index, dst, src, count);
2102 }
2103 
2104 }  // namespace wasm
2105 }  // namespace internal
2106 }  // namespace v8
2107 
2108 #undef TRACE
2109