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
36namespace v8 {
37namespace internal {
38namespace wasm {
39
40namespace {
41
42byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) {
43  return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset;
44}
45
46using ImportWrapperQueue = WrapperQueue<WasmImportWrapperCache::CacheKey,
47                                        WasmImportWrapperCache::CacheKeyHash>;
48
49class CompileImportWrapperJob final : public JobTask {
50 public:
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
60  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
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
87Handle<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
121Handle<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
142Handle<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
169Handle<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
196Handle<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
213void 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.
269class 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
418MaybeHandle<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
434InstanceBuilder::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.
453MaybeHandle<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
811bool 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.
838MaybeHandle<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
868namespace {
869bool 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
900V8_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.
956MaybeHandle<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.
999void 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
1038void 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
1053void 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
1081bool 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
1098bool 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
1218bool 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
1267bool 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
1332bool 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
1385bool 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
1468bool 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
1567void 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.
1634int 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
1710template <typename T>
1711T* InstanceBuilder::GetRawUntaggedGlobalPtr(const WasmGlobal& global) {
1712  return reinterpret_cast<T*>(raw_buffer_ptr(untagged_globals_, global.offset));
1713}
1714
1715// Process initialization of globals.
1716void 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.
1736bool 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.
1757void 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
1934namespace {
1935V8_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
1958V8_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
1966void 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
2003namespace {
2004bool 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
2048void 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
2080void 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
2089bool 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