1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/wasm/wasm-objects.h"
6
7#include "src/base/iterator.h"
8#include "src/base/vector.h"
9#include "src/codegen/assembler-inl.h"
10#include "src/codegen/code-factory.h"
11#include "src/compiler/wasm-compiler.h"
12#include "src/debug/debug-interface.h"
13#include "src/logging/counters.h"
14#include "src/objects/debug-objects-inl.h"
15#include "src/objects/managed-inl.h"
16#include "src/objects/objects-inl.h"
17#include "src/objects/shared-function-info.h"
18#include "src/objects/struct-inl.h"
19#include "src/trap-handler/trap-handler.h"
20#include "src/utils/utils.h"
21#include "src/wasm/code-space-access.h"
22#include "src/wasm/jump-table-assembler.h"
23#include "src/wasm/module-compiler.h"
24#include "src/wasm/module-decoder.h"
25#include "src/wasm/module-instantiate.h"
26#include "src/wasm/value-type.h"
27#include "src/wasm/wasm-code-manager.h"
28#include "src/wasm/wasm-engine.h"
29#include "src/wasm/wasm-limits.h"
30#include "src/wasm/wasm-module.h"
31#include "src/wasm/wasm-objects-inl.h"
32#include "src/wasm/wasm-subtyping.h"
33#include "src/wasm/wasm-value.h"
34
35#define TRACE_IFT(...)              \
36  do {                              \
37    if (false) PrintF(__VA_ARGS__); \
38  } while (false)
39
40namespace v8 {
41namespace internal {
42
43// Import a few often used types from the wasm namespace.
44using WasmFunction = wasm::WasmFunction;
45using WasmModule = wasm::WasmModule;
46
47namespace {
48
49// Manages the natively-allocated memory for a WasmInstanceObject. Since
50// an instance finalizer is not guaranteed to run upon isolate shutdown,
51// we must use a Managed<WasmInstanceNativeAllocations> to guarantee
52// it is freed.
53class WasmInstanceNativeAllocations {
54 public:
55  WasmInstanceNativeAllocations(Handle<WasmInstanceObject> instance,
56                                size_t num_imported_functions,
57                                size_t num_imported_mutable_globals,
58                                size_t num_data_segments,
59                                size_t num_elem_segments)
60      : imported_function_targets_(new Address[num_imported_functions]),
61        imported_mutable_globals_(new Address[num_imported_mutable_globals]),
62        data_segment_starts_(new Address[num_data_segments]),
63        data_segment_sizes_(new uint32_t[num_data_segments]),
64        dropped_elem_segments_(new uint8_t[num_elem_segments]) {
65    instance->set_imported_function_targets(imported_function_targets_.get());
66    instance->set_imported_mutable_globals(imported_mutable_globals_.get());
67    instance->set_data_segment_starts(data_segment_starts_.get());
68    instance->set_data_segment_sizes(data_segment_sizes_.get());
69    instance->set_dropped_elem_segments(dropped_elem_segments_.get());
70  }
71
72 private:
73  const std::unique_ptr<Address[]> imported_function_targets_;
74  const std::unique_ptr<Address[]> imported_mutable_globals_;
75  const std::unique_ptr<Address[]> data_segment_starts_;
76  const std::unique_ptr<uint32_t[]> data_segment_sizes_;
77  const std::unique_ptr<uint8_t[]> dropped_elem_segments_;
78};
79
80size_t EstimateNativeAllocationsSize(const WasmModule* module) {
81  size_t estimate =
82      sizeof(WasmInstanceNativeAllocations) +
83      (1 * kSystemPointerSize * module->num_imported_mutable_globals) +
84      (2 * kSystemPointerSize * module->num_imported_functions) +
85      ((kSystemPointerSize + sizeof(uint32_t) + sizeof(uint8_t)) *
86       module->num_declared_data_segments);
87  return estimate;
88}
89
90enum DispatchTableElements : int {
91  kDispatchTableInstanceOffset,
92  kDispatchTableIndexOffset,
93  // Marker:
94  kDispatchTableNumElements
95};
96
97}  // namespace
98
99// static
100Handle<WasmModuleObject> WasmModuleObject::New(
101    Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
102    Handle<Script> script) {
103  Handle<FixedArray> export_wrappers = isolate->factory()->NewFixedArray(0);
104  return New(isolate, std::move(native_module), script, export_wrappers);
105}
106
107// static
108Handle<WasmModuleObject> WasmModuleObject::New(
109    Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
110    Handle<Script> script, Handle<FixedArray> export_wrappers) {
111  Handle<Managed<wasm::NativeModule>> managed_native_module;
112  if (script->type() == Script::TYPE_WASM) {
113    managed_native_module = handle(
114        Managed<wasm::NativeModule>::cast(script->wasm_managed_native_module()),
115        isolate);
116  } else {
117    const WasmModule* module = native_module->module();
118    size_t memory_estimate =
119        native_module->committed_code_space() +
120        wasm::WasmCodeManager::EstimateNativeModuleMetaDataSize(module);
121    managed_native_module = Managed<wasm::NativeModule>::FromSharedPtr(
122        isolate, memory_estimate, std::move(native_module));
123  }
124  Handle<WasmModuleObject> module_object = Handle<WasmModuleObject>::cast(
125      isolate->factory()->NewJSObject(isolate->wasm_module_constructor()));
126  module_object->set_export_wrappers(*export_wrappers);
127  module_object->set_managed_native_module(*managed_native_module);
128  module_object->set_script(*script);
129  return module_object;
130}
131
132Handle<String> WasmModuleObject::ExtractUtf8StringFromModuleBytes(
133    Isolate* isolate, Handle<WasmModuleObject> module_object,
134    wasm::WireBytesRef ref, InternalizeString internalize) {
135  base::Vector<const uint8_t> wire_bytes =
136      module_object->native_module()->wire_bytes();
137  return ExtractUtf8StringFromModuleBytes(isolate, wire_bytes, ref,
138                                          internalize);
139}
140
141Handle<String> WasmModuleObject::ExtractUtf8StringFromModuleBytes(
142    Isolate* isolate, base::Vector<const uint8_t> wire_bytes,
143    wasm::WireBytesRef ref, InternalizeString internalize) {
144  base::Vector<const uint8_t> name_vec =
145      wire_bytes.SubVector(ref.offset(), ref.end_offset());
146  // UTF8 validation happens at decode time.
147  DCHECK(unibrow::Utf8::ValidateEncoding(name_vec.begin(), name_vec.length()));
148  auto* factory = isolate->factory();
149  return internalize
150             ? factory->InternalizeUtf8String(
151                   base::Vector<const char>::cast(name_vec))
152             : factory
153                   ->NewStringFromUtf8(base::Vector<const char>::cast(name_vec))
154                   .ToHandleChecked();
155}
156
157MaybeHandle<String> WasmModuleObject::GetModuleNameOrNull(
158    Isolate* isolate, Handle<WasmModuleObject> module_object) {
159  const WasmModule* module = module_object->module();
160  if (!module->name.is_set()) return {};
161  return ExtractUtf8StringFromModuleBytes(isolate, module_object, module->name,
162                                          kNoInternalize);
163}
164
165MaybeHandle<String> WasmModuleObject::GetFunctionNameOrNull(
166    Isolate* isolate, Handle<WasmModuleObject> module_object,
167    uint32_t func_index) {
168  DCHECK_LT(func_index, module_object->module()->functions.size());
169  wasm::WireBytesRef name =
170      module_object->module()->lazily_generated_names.LookupFunctionName(
171          wasm::ModuleWireBytes(module_object->native_module()->wire_bytes()),
172          func_index);
173  if (!name.is_set()) return {};
174  return ExtractUtf8StringFromModuleBytes(isolate, module_object, name,
175                                          kNoInternalize);
176}
177
178base::Vector<const uint8_t> WasmModuleObject::GetRawFunctionName(
179    int func_index) {
180  if (func_index == wasm::kAnonymousFuncIndex) {
181    return base::Vector<const uint8_t>({nullptr, 0});
182  }
183  DCHECK_GT(module()->functions.size(), func_index);
184  wasm::ModuleWireBytes wire_bytes(native_module()->wire_bytes());
185  wasm::WireBytesRef name_ref =
186      module()->lazily_generated_names.LookupFunctionName(wire_bytes,
187                                                          func_index);
188  wasm::WasmName name = wire_bytes.GetNameOrNull(name_ref);
189  return base::Vector<const uint8_t>::cast(name);
190}
191
192Handle<WasmTableObject> WasmTableObject::New(
193    Isolate* isolate, Handle<WasmInstanceObject> instance, wasm::ValueType type,
194    uint32_t initial, bool has_maximum, uint32_t maximum,
195    Handle<FixedArray>* entries, Handle<Object> initial_value) {
196  // TODO(7748): Make this work with other types when spec clears up.
197  {
198    const WasmModule* module =
199        instance.is_null() ? nullptr : instance->module();
200    CHECK(wasm::WasmTable::IsValidTableType(type, module));
201  }
202
203  Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(initial);
204  for (int i = 0; i < static_cast<int>(initial); ++i) {
205    backing_store->set(i, *initial_value);
206  }
207
208  Handle<Object> max;
209  if (has_maximum) {
210    max = isolate->factory()->NewNumberFromUint(maximum);
211  } else {
212    max = isolate->factory()->undefined_value();
213  }
214
215  Handle<JSFunction> table_ctor(
216      isolate->native_context()->wasm_table_constructor(), isolate);
217  auto table_obj = Handle<WasmTableObject>::cast(
218      isolate->factory()->NewJSObject(table_ctor));
219  DisallowGarbageCollection no_gc;
220
221  if (!instance.is_null()) table_obj->set_instance(*instance);
222  table_obj->set_entries(*backing_store);
223  table_obj->set_current_length(initial);
224  table_obj->set_maximum_length(*max);
225  table_obj->set_raw_type(static_cast<int>(type.raw_bit_field()));
226
227  table_obj->set_dispatch_tables(ReadOnlyRoots(isolate).empty_fixed_array());
228  if (entries != nullptr) {
229    *entries = backing_store;
230  }
231  return Handle<WasmTableObject>::cast(table_obj);
232}
233
234void WasmTableObject::AddDispatchTable(Isolate* isolate,
235                                       Handle<WasmTableObject> table_obj,
236                                       Handle<WasmInstanceObject> instance,
237                                       int table_index) {
238  Handle<FixedArray> dispatch_tables(table_obj->dispatch_tables(), isolate);
239  int old_length = dispatch_tables->length();
240  DCHECK_EQ(0, old_length % kDispatchTableNumElements);
241
242  if (instance.is_null()) return;
243  // TODO(titzer): use weak cells here to avoid leaking instances.
244
245  // Grow the dispatch table and add a new entry at the end.
246  Handle<FixedArray> new_dispatch_tables =
247      isolate->factory()->CopyFixedArrayAndGrow(dispatch_tables,
248                                                kDispatchTableNumElements);
249
250  new_dispatch_tables->set(old_length + kDispatchTableInstanceOffset,
251                           *instance);
252  new_dispatch_tables->set(old_length + kDispatchTableIndexOffset,
253                           Smi::FromInt(table_index));
254
255  table_obj->set_dispatch_tables(*new_dispatch_tables);
256}
257
258int WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table,
259                          uint32_t count, Handle<Object> init_value) {
260  uint32_t old_size = table->current_length();
261  if (count == 0) return old_size;  // Degenerate case: nothing to do.
262
263  // Check if growing by {count} is valid.
264  uint32_t max_size;
265  if (!table->maximum_length().ToUint32(&max_size)) {
266    max_size = FLAG_wasm_max_table_size;
267  }
268  max_size = std::min(max_size, FLAG_wasm_max_table_size);
269  DCHECK_LE(old_size, max_size);
270  if (max_size - old_size < count) return -1;
271
272  uint32_t new_size = old_size + count;
273  // Even with 2x over-allocation, there should not be an integer overflow.
274  STATIC_ASSERT(wasm::kV8MaxWasmTableSize <= kMaxInt / 2);
275  DCHECK_GE(kMaxInt, new_size);
276  int old_capacity = table->entries().length();
277  if (new_size > static_cast<uint32_t>(old_capacity)) {
278    int grow = static_cast<int>(new_size) - old_capacity;
279    // Grow at least by the old capacity, to implement exponential growing.
280    grow = std::max(grow, old_capacity);
281    // Never grow larger than the max size.
282    grow = std::min(grow, static_cast<int>(max_size - old_capacity));
283    auto new_store = isolate->factory()->CopyFixedArrayAndGrow(
284        handle(table->entries(), isolate), grow);
285    table->set_entries(*new_store, WriteBarrierMode::UPDATE_WRITE_BARRIER);
286  }
287  table->set_current_length(new_size);
288
289  Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
290  DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
291  // Tables are stored in the instance object, no code patching is
292  // necessary. We simply have to grow the raw tables in each instance
293  // that has imported this table.
294
295  // TODO(titzer): replace the dispatch table with a weak list of all
296  // the instances that import a given table.
297  for (int i = 0; i < dispatch_tables->length();
298       i += kDispatchTableNumElements) {
299    int table_index =
300        Smi::cast(dispatch_tables->get(i + kDispatchTableIndexOffset)).value();
301
302    Handle<WasmInstanceObject> instance(
303        WasmInstanceObject::cast(dispatch_tables->get(i)), isolate);
304
305    DCHECK_EQ(old_size,
306              instance->GetIndirectFunctionTable(isolate, table_index)->size());
307    WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
308        instance, table_index, new_size);
309  }
310
311  for (uint32_t entry = old_size; entry < new_size; ++entry) {
312    WasmTableObject::Set(isolate, table, entry, init_value);
313  }
314  return old_size;
315}
316
317bool WasmTableObject::IsInBounds(Isolate* isolate,
318                                 Handle<WasmTableObject> table,
319                                 uint32_t entry_index) {
320  return entry_index < static_cast<uint32_t>(table->current_length());
321}
322
323bool WasmTableObject::IsValidElement(Isolate* isolate,
324                                     Handle<WasmTableObject> table,
325                                     Handle<Object> entry) {
326  const char* error_message;
327  const WasmModule* module =
328      !table->instance().IsUndefined()
329          ? WasmInstanceObject::cast(table->instance()).module()
330          : nullptr;
331  if (entry->IsWasmInternalFunction()) {
332    entry =
333        handle(Handle<WasmInternalFunction>::cast(entry)->external(), isolate);
334  }
335  return wasm::TypecheckJSObject(isolate, module, entry, table->type(),
336                                 &error_message);
337}
338
339void WasmTableObject::SetFunctionTableEntry(Isolate* isolate,
340                                            Handle<WasmTableObject> table,
341                                            Handle<FixedArray> entries,
342                                            int entry_index,
343                                            Handle<Object> entry) {
344  if (entry->IsNull(isolate)) {
345    ClearDispatchTables(isolate, table, entry_index);  // Degenerate case.
346    entries->set(entry_index, ReadOnlyRoots(isolate).null_value());
347    return;
348  }
349
350  Handle<Object> external =
351      handle(Handle<WasmInternalFunction>::cast(entry)->external(), isolate);
352
353  if (WasmExportedFunction::IsWasmExportedFunction(*external)) {
354    auto exported_function = Handle<WasmExportedFunction>::cast(external);
355    Handle<WasmInstanceObject> target_instance(exported_function->instance(),
356                                               isolate);
357    int func_index = exported_function->function_index();
358    auto* wasm_function = &target_instance->module()->functions[func_index];
359    UpdateDispatchTables(isolate, *table, entry_index, wasm_function,
360                         *target_instance);
361  } else if (WasmJSFunction::IsWasmJSFunction(*external)) {
362    UpdateDispatchTables(isolate, table, entry_index,
363                         Handle<WasmJSFunction>::cast(external));
364  } else {
365    DCHECK(WasmCapiFunction::IsWasmCapiFunction(*external));
366    UpdateDispatchTables(isolate, table, entry_index,
367                         Handle<WasmCapiFunction>::cast(external));
368  }
369  entries->set(entry_index, *entry);
370}
371
372void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
373                          uint32_t index, Handle<Object> entry) {
374  // Callers need to perform bounds checks, type check, and error handling.
375  DCHECK(IsInBounds(isolate, table, index));
376  DCHECK(IsValidElement(isolate, table, entry));
377
378  Handle<FixedArray> entries(table->entries(), isolate);
379  // The FixedArray is addressed with int's.
380  int entry_index = static_cast<int>(index);
381
382  switch (table->type().heap_representation()) {
383    case wasm::HeapType::kAny:
384      entries->set(entry_index, *entry);
385      return;
386    case wasm::HeapType::kFunc:
387      SetFunctionTableEntry(isolate, table, entries, entry_index, entry);
388      return;
389    case wasm::HeapType::kEq:
390    case wasm::HeapType::kData:
391    case wasm::HeapType::kArray:
392    case wasm::HeapType::kI31:
393      // TODO(7748): Implement once we have struct/arrays/i31ref tables.
394      UNREACHABLE();
395    case wasm::HeapType::kBottom:
396      UNREACHABLE();
397    default:
398      DCHECK(!table->instance().IsUndefined());
399      // TODO(7748): Relax this once we have struct/array/i31ref tables.
400      DCHECK(WasmInstanceObject::cast(table->instance())
401                 .module()
402                 ->has_signature(table->type().ref_index()));
403      SetFunctionTableEntry(isolate, table, entries, entry_index, entry);
404      return;
405  }
406}
407
408Handle<Object> WasmTableObject::Get(Isolate* isolate,
409                                    Handle<WasmTableObject> table,
410                                    uint32_t index) {
411  Handle<FixedArray> entries(table->entries(), isolate);
412  // Callers need to perform bounds checks and error handling.
413  DCHECK(IsInBounds(isolate, table, index));
414
415  // The FixedArray is addressed with int's.
416  int entry_index = static_cast<int>(index);
417
418  Handle<Object> entry(entries->get(entry_index), isolate);
419
420  if (entry->IsNull(isolate)) {
421    return entry;
422  }
423
424  switch (table->type().heap_representation()) {
425    case wasm::HeapType::kAny:
426      return entry;
427    case wasm::HeapType::kFunc:
428      if (entry->IsWasmInternalFunction()) return entry;
429      break;
430    case wasm::HeapType::kEq:
431    case wasm::HeapType::kI31:
432    case wasm::HeapType::kData:
433    case wasm::HeapType::kArray:
434      // TODO(7748): Implement once we have a story for struct/arrays/i31ref in
435      // JS.
436      UNIMPLEMENTED();
437    case wasm::HeapType::kBottom:
438      UNREACHABLE();
439    default:
440      DCHECK(!table->instance().IsUndefined());
441      // TODO(7748): Relax this once we have struct/array/i31ref tables.
442      DCHECK(WasmInstanceObject::cast(table->instance())
443                 .module()
444                 ->has_signature(table->type().ref_index()));
445      if (entry->IsWasmInternalFunction()) return entry;
446      break;
447  }
448
449  // {entry} is not a valid entry in the table. It has to be a placeholder
450  // for lazy initialization.
451  Handle<Tuple2> tuple = Handle<Tuple2>::cast(entry);
452  auto instance = handle(WasmInstanceObject::cast(tuple->value1()), isolate);
453  int function_index = Smi::cast(tuple->value2()).value();
454
455  // Check if we already compiled a wrapper for the function but did not store
456  // it in the table slot yet.
457  Handle<WasmInternalFunction> internal =
458      WasmInstanceObject::GetOrCreateWasmInternalFunction(isolate, instance,
459                                                          function_index);
460  entries->set(entry_index, *internal);
461  return internal;
462}
463
464void WasmTableObject::Fill(Isolate* isolate, Handle<WasmTableObject> table,
465                           uint32_t start, Handle<Object> entry,
466                           uint32_t count) {
467  // Bounds checks must be done by the caller.
468  DCHECK_LE(start, table->current_length());
469  DCHECK_LE(count, table->current_length());
470  DCHECK_LE(start + count, table->current_length());
471
472  for (uint32_t i = 0; i < count; i++) {
473    WasmTableObject::Set(isolate, table, start + i, entry);
474  }
475}
476
477void WasmTableObject::UpdateDispatchTables(Isolate* isolate,
478                                           WasmTableObject table,
479                                           int entry_index,
480                                           const wasm::WasmFunction* func,
481                                           WasmInstanceObject target_instance) {
482  DisallowGarbageCollection no_gc;
483
484  // We simply need to update the IFTs for each instance that imports
485  // this table.
486  FixedArray dispatch_tables = table.dispatch_tables();
487  DCHECK_EQ(0, dispatch_tables.length() % kDispatchTableNumElements);
488
489  Object call_ref =
490      func->imported
491          // The function in the target instance was imported. Use its imports
492          // table, which contains a tuple needed by the import wrapper.
493          ? target_instance.imported_function_refs().get(func->func_index)
494          // For wasm functions, just pass the target instance.
495          : target_instance;
496  Address call_target = target_instance.GetCallTarget(func->func_index);
497
498  int original_sig_id = func->sig_index;
499
500  for (int i = 0, len = dispatch_tables.length(); i < len;
501       i += kDispatchTableNumElements) {
502    int table_index =
503        Smi::cast(dispatch_tables.get(i + kDispatchTableIndexOffset)).value();
504    WasmInstanceObject instance = WasmInstanceObject::cast(
505        dispatch_tables.get(i + kDispatchTableInstanceOffset));
506    const WasmModule* module = instance.module();
507    // Try to avoid the signature map lookup by checking if the signature in
508    // {module} at {original_sig_id} matches {func->sig}.
509    int sig_id;
510    // TODO(7748): wasm-gc signatures cannot be canonicalized this way because
511    // references could wrongly be detected as identical.
512    if (module->has_signature(original_sig_id) &&
513        *module->signature(original_sig_id) == *func->sig) {
514      sig_id = module->canonicalized_type_ids[original_sig_id];
515      DCHECK_EQ(sig_id, module->signature_map.Find(*func->sig));
516    } else {
517      // Note that {SignatureMap::Find} may return {-1} if the signature is
518      // not found; it will simply never match any check.
519      sig_id = module->signature_map.Find(*func->sig);
520    }
521    WasmIndirectFunctionTable ift = WasmIndirectFunctionTable::cast(
522        instance.indirect_function_tables().get(table_index));
523    ift.Set(entry_index, sig_id, call_target, call_ref);
524  }
525}
526
527void WasmTableObject::UpdateDispatchTables(Isolate* isolate,
528                                           Handle<WasmTableObject> table,
529                                           int entry_index,
530                                           Handle<WasmJSFunction> function) {
531  // We simply need to update the IFTs for each instance that imports
532  // this table.
533  Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
534  DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
535
536  for (int i = 0; i < dispatch_tables->length();
537       i += kDispatchTableNumElements) {
538    int table_index =
539        Smi::cast(dispatch_tables->get(i + kDispatchTableIndexOffset)).value();
540    Handle<WasmInstanceObject> instance(
541        WasmInstanceObject::cast(
542            dispatch_tables->get(i + kDispatchTableInstanceOffset)),
543        isolate);
544    WasmInstanceObject::ImportWasmJSFunctionIntoTable(
545        isolate, instance, table_index, entry_index, function);
546  }
547}
548
549void WasmTableObject::UpdateDispatchTables(
550    Isolate* isolate, Handle<WasmTableObject> table, int entry_index,
551    Handle<WasmCapiFunction> capi_function) {
552  // We simply need to update the IFTs for each instance that imports
553  // this table.
554  Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
555  DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
556
557  // Reconstruct signature.
558  // TODO(jkummerow): Unify with "SignatureHelper" in c-api.cc.
559  PodArray<wasm::ValueType> serialized_sig =
560      capi_function->GetSerializedSignature();
561  int total_count = serialized_sig.length() - 1;
562  std::unique_ptr<wasm::ValueType[]> reps(new wasm::ValueType[total_count]);
563  int result_count;
564  static const wasm::ValueType kMarker = wasm::kWasmVoid;
565  for (int i = 0, j = 0; i <= total_count; i++) {
566    if (serialized_sig.get(i) == kMarker) {
567      result_count = i;
568      continue;
569    }
570    reps[j++] = serialized_sig.get(i);
571  }
572  int param_count = total_count - result_count;
573  wasm::FunctionSig sig(result_count, param_count, reps.get());
574
575  for (int i = 0; i < dispatch_tables->length();
576       i += kDispatchTableNumElements) {
577    int table_index =
578        Smi::cast(dispatch_tables->get(i + kDispatchTableIndexOffset)).value();
579    Handle<WasmInstanceObject> instance(
580        WasmInstanceObject::cast(
581            dispatch_tables->get(i + kDispatchTableInstanceOffset)),
582        isolate);
583    wasm::NativeModule* native_module =
584        instance->module_object().native_module();
585    wasm::WasmImportWrapperCache* cache = native_module->import_wrapper_cache();
586    auto kind = compiler::WasmImportCallKind::kWasmToCapi;
587    wasm::WasmCode* wasm_code =
588        cache->MaybeGet(kind, &sig, param_count, wasm::kNoSuspend);
589    if (wasm_code == nullptr) {
590      wasm::WasmCodeRefScope code_ref_scope;
591      wasm::WasmImportWrapperCache::ModificationScope cache_scope(cache);
592      wasm_code = compiler::CompileWasmCapiCallWrapper(native_module, &sig);
593      wasm::WasmImportWrapperCache::CacheKey key(kind, &sig, param_count,
594                                                 wasm::kNoSuspend);
595      cache_scope[key] = wasm_code;
596      wasm_code->IncRef();
597      isolate->counters()->wasm_generated_code_size()->Increment(
598          wasm_code->instructions().length());
599      isolate->counters()->wasm_reloc_size()->Increment(
600          wasm_code->reloc_info().length());
601    }
602    // Note that {SignatureMap::Find} may return {-1} if the signature is
603    // not found; it will simply never match any check.
604    auto sig_id = instance->module()->signature_map.Find(sig);
605    instance->GetIndirectFunctionTable(isolate, table_index)
606        ->Set(entry_index, sig_id, wasm_code->instruction_start(),
607              WasmCapiFunctionData::cast(
608                  capi_function->shared().function_data(kAcquireLoad))
609                  .internal()
610                  .ref());
611  }
612}
613
614void WasmTableObject::ClearDispatchTables(Isolate* isolate,
615                                          Handle<WasmTableObject> table,
616                                          int index) {
617  Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
618  DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
619  for (int i = 0; i < dispatch_tables->length();
620       i += kDispatchTableNumElements) {
621    int table_index =
622        Smi::cast(dispatch_tables->get(i + kDispatchTableIndexOffset)).value();
623    Handle<WasmInstanceObject> target_instance(
624        WasmInstanceObject::cast(
625            dispatch_tables->get(i + kDispatchTableInstanceOffset)),
626        isolate);
627    Handle<WasmIndirectFunctionTable> function_table =
628        target_instance->GetIndirectFunctionTable(isolate, table_index);
629    DCHECK_LT(index, function_table->size());
630    function_table->Clear(index);
631  }
632}
633
634void WasmTableObject::SetFunctionTablePlaceholder(
635    Isolate* isolate, Handle<WasmTableObject> table, int entry_index,
636    Handle<WasmInstanceObject> instance, int func_index) {
637  // Put (instance, func_index) as a Tuple2 into the entry_index.
638  // The {WasmExportedFunction} will be created lazily.
639  // Allocate directly in old space as the tuples are typically long-lived, and
640  // we create many of them, which would result in lots of GC when initializing
641  // large tables.
642  Handle<Tuple2> tuple = isolate->factory()->NewTuple2(
643      instance, Handle<Smi>(Smi::FromInt(func_index), isolate),
644      AllocationType::kOld);
645  table->entries().set(entry_index, *tuple);
646}
647
648void WasmTableObject::GetFunctionTableEntry(
649    Isolate* isolate, const WasmModule* module, Handle<WasmTableObject> table,
650    int entry_index, bool* is_valid, bool* is_null,
651    MaybeHandle<WasmInstanceObject>* instance, int* function_index,
652    MaybeHandle<WasmJSFunction>* maybe_js_function) {
653  DCHECK(wasm::IsSubtypeOf(table->type(), wasm::kWasmFuncRef, module));
654  DCHECK_LT(entry_index, table->current_length());
655  // We initialize {is_valid} with {true}. We may change it later.
656  *is_valid = true;
657  Handle<Object> element(table->entries().get(entry_index), isolate);
658
659  *is_null = element->IsNull(isolate);
660  if (*is_null) return;
661
662  if (element->IsWasmInternalFunction()) {
663    element = handle(Handle<WasmInternalFunction>::cast(element)->external(),
664                     isolate);
665  }
666  if (WasmExportedFunction::IsWasmExportedFunction(*element)) {
667    auto target_func = Handle<WasmExportedFunction>::cast(element);
668    *instance = handle(target_func->instance(), isolate);
669    *function_index = target_func->function_index();
670    *maybe_js_function = MaybeHandle<WasmJSFunction>();
671    return;
672  }
673  if (WasmJSFunction::IsWasmJSFunction(*element)) {
674    *instance = MaybeHandle<WasmInstanceObject>();
675    *maybe_js_function = Handle<WasmJSFunction>::cast(element);
676    return;
677  }
678  if (element->IsTuple2()) {
679    auto tuple = Handle<Tuple2>::cast(element);
680    *instance = handle(WasmInstanceObject::cast(tuple->value1()), isolate);
681    *function_index = Smi::cast(tuple->value2()).value();
682    *maybe_js_function = MaybeHandle<WasmJSFunction>();
683    return;
684  }
685  *is_valid = false;
686}
687
688namespace {
689class IftNativeAllocations {
690 public:
691  IftNativeAllocations(Handle<WasmIndirectFunctionTable> table, uint32_t size)
692      : sig_ids_(size), targets_(size) {
693    table->set_sig_ids(sig_ids_.data());
694    table->set_targets(targets_.data());
695  }
696
697  static size_t SizeInMemory(uint32_t size) {
698    return size * (sizeof(Address) + sizeof(uint32_t));
699  }
700
701  void resize(Handle<WasmIndirectFunctionTable> table, uint32_t new_size) {
702    DCHECK_GE(new_size, sig_ids_.size());
703    DCHECK_EQ(this, Managed<IftNativeAllocations>::cast(
704                        table->managed_native_allocations())
705                        .raw());
706    sig_ids_.resize(new_size);
707    targets_.resize(new_size);
708    table->set_sig_ids(sig_ids_.data());
709    table->set_targets(targets_.data());
710  }
711
712 private:
713  std::vector<uint32_t> sig_ids_;
714  std::vector<Address> targets_;
715};
716}  // namespace
717
718Handle<WasmIndirectFunctionTable> WasmIndirectFunctionTable::New(
719    Isolate* isolate, uint32_t size) {
720  auto refs = isolate->factory()->NewFixedArray(static_cast<int>(size));
721  auto table = Handle<WasmIndirectFunctionTable>::cast(
722      isolate->factory()->NewStruct(WASM_INDIRECT_FUNCTION_TABLE_TYPE));
723  table->set_size(size);
724  table->set_refs(*refs);
725  auto native_allocations = Managed<IftNativeAllocations>::Allocate(
726      isolate, IftNativeAllocations::SizeInMemory(size), table, size);
727  table->set_managed_native_allocations(*native_allocations);
728  for (uint32_t i = 0; i < size; ++i) {
729    table->Clear(i);
730  }
731  return table;
732}
733void WasmIndirectFunctionTable::Set(uint32_t index, int sig_id,
734                                    Address call_target, Object ref) {
735  sig_ids()[index] = sig_id;
736  targets()[index] = call_target;
737  refs().set(index, ref);
738}
739
740void WasmIndirectFunctionTable::Clear(uint32_t index) {
741  sig_ids()[index] = -1;
742  targets()[index] = 0;
743  refs().set(
744      index,
745      ReadOnlyRoots(GetIsolateFromWritableObject(*this)).undefined_value());
746}
747
748void WasmIndirectFunctionTable::Resize(Isolate* isolate,
749                                       Handle<WasmIndirectFunctionTable> table,
750                                       uint32_t new_size) {
751  uint32_t old_size = table->size();
752  if (old_size >= new_size) return;  // Nothing to do.
753
754  table->set_size(new_size);
755
756  // Grow table exponentially to guarantee amortized constant allocation and gc
757  // time.
758  Handle<FixedArray> old_refs(table->refs(), isolate);
759  // Since we might have overallocated, {old_capacity} might be different than
760  // {old_size}.
761  uint32_t old_capacity = old_refs->length();
762  // If we have enough capacity, there is no need to reallocate.
763  if (new_size <= old_capacity) return;
764  uint32_t new_capacity = std::max(2 * old_capacity, new_size);
765
766  Managed<IftNativeAllocations>::cast(table->managed_native_allocations())
767      .raw()
768      ->resize(table, new_capacity);
769
770  Handle<FixedArray> new_refs = isolate->factory()->CopyFixedArrayAndGrow(
771      old_refs, static_cast<int>(new_capacity - old_capacity));
772  table->set_refs(*new_refs);
773  for (uint32_t i = old_capacity; i < new_capacity; ++i) {
774    table->Clear(i);
775  }
776}
777
778namespace {
779
780void SetInstanceMemory(Handle<WasmInstanceObject> instance,
781                       Handle<JSArrayBuffer> buffer) {
782  bool is_wasm_module = instance->module()->origin == wasm::kWasmOrigin;
783  bool use_trap_handler =
784      instance->module_object().native_module()->bounds_checks() ==
785      wasm::kTrapHandler;
786  // Wasm modules compiled to use the trap handler don't have bounds checks,
787  // so they must have a memory that has guard regions.
788  CHECK_IMPLIES(is_wasm_module && use_trap_handler,
789                buffer->GetBackingStore()->has_guard_regions());
790
791  instance->SetRawMemory(reinterpret_cast<byte*>(buffer->backing_store()),
792                         buffer->byte_length());
793#if DEBUG
794  if (!FLAG_mock_arraybuffer_allocator) {
795    // To flush out bugs earlier, in DEBUG mode, check that all pages of the
796    // memory are accessible by reading and writing one byte on each page.
797    // Don't do this if the mock ArrayBuffer allocator is enabled.
798    byte* mem_start = instance->memory_start();
799    size_t mem_size = instance->memory_size();
800    for (size_t offset = 0; offset < mem_size; offset += wasm::kWasmPageSize) {
801      byte val = mem_start[offset];
802      USE(val);
803      mem_start[offset] = val;
804    }
805  }
806#endif
807}
808}  // namespace
809
810MaybeHandle<WasmMemoryObject> WasmMemoryObject::New(
811    Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_buffer, int maximum) {
812  Handle<JSArrayBuffer> buffer;
813  if (!maybe_buffer.ToHandle(&buffer)) {
814    // If no buffer was provided, create a zero-length one.
815    auto backing_store =
816        BackingStore::AllocateWasmMemory(isolate, 0, 0, SharedFlag::kNotShared);
817    if (!backing_store) return {};
818    buffer = isolate->factory()->NewJSArrayBuffer(std::move(backing_store));
819  }
820
821  Handle<JSFunction> memory_ctor(
822      isolate->native_context()->wasm_memory_constructor(), isolate);
823
824  auto memory_object = Handle<WasmMemoryObject>::cast(
825      isolate->factory()->NewJSObject(memory_ctor, AllocationType::kOld));
826  memory_object->set_array_buffer(*buffer);
827  memory_object->set_maximum_pages(maximum);
828
829  if (buffer->is_shared()) {
830    auto backing_store = buffer->GetBackingStore();
831    backing_store->AttachSharedWasmMemoryObject(isolate, memory_object);
832  }
833
834  // For debugging purposes we memorize a link from the JSArrayBuffer
835  // to it's owning WasmMemoryObject instance.
836  Handle<Symbol> symbol = isolate->factory()->array_buffer_wasm_memory_symbol();
837  JSObject::SetProperty(isolate, buffer, symbol, memory_object).Check();
838
839  return memory_object;
840}
841
842MaybeHandle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate,
843                                                    int initial, int maximum,
844                                                    SharedFlag shared) {
845  bool has_maximum = maximum != kNoMaximum;
846  int heuristic_maximum = maximum;
847  if (!has_maximum) {
848    heuristic_maximum = static_cast<int>(wasm::max_mem_pages());
849  }
850
851#ifdef V8_TARGET_ARCH_32_BIT
852  // On 32-bit platforms we need an heuristic here to balance overall memory
853  // and address space consumption.
854  constexpr int kGBPages = 1024 * 1024 * 1024 / wasm::kWasmPageSize;
855  if (initial > kGBPages) {
856    // We always allocate at least the initial size.
857    heuristic_maximum = initial;
858  } else if (has_maximum) {
859    // We try to reserve the maximum, but at most 1GB to avoid OOMs.
860    heuristic_maximum = std::min(maximum, kGBPages);
861  } else if (shared == SharedFlag::kShared) {
862    // If shared memory has no maximum, we use an implicit maximum of 1GB.
863    heuristic_maximum = kGBPages;
864  } else {
865    // If non-shared memory has no maximum, we only allocate the initial size
866    // and then grow with realloc.
867    heuristic_maximum = initial;
868  }
869#endif
870
871  auto backing_store = BackingStore::AllocateWasmMemory(
872      isolate, initial, heuristic_maximum, shared);
873
874  if (!backing_store) return {};
875
876  Handle<JSArrayBuffer> buffer =
877      (shared == SharedFlag::kShared)
878          ? isolate->factory()->NewJSSharedArrayBuffer(std::move(backing_store))
879          : isolate->factory()->NewJSArrayBuffer(std::move(backing_store));
880
881  return New(isolate, buffer, maximum);
882}
883
884void WasmMemoryObject::AddInstance(Isolate* isolate,
885                                   Handle<WasmMemoryObject> memory,
886                                   Handle<WasmInstanceObject> instance) {
887  Handle<WeakArrayList> old_instances =
888      memory->has_instances()
889          ? Handle<WeakArrayList>(memory->instances(), isolate)
890          : handle(ReadOnlyRoots(isolate->heap()).empty_weak_array_list(),
891                   isolate);
892  Handle<WeakArrayList> new_instances = WeakArrayList::Append(
893      isolate, old_instances, MaybeObjectHandle::Weak(instance));
894  memory->set_instances(*new_instances);
895  Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate);
896  SetInstanceMemory(instance, buffer);
897}
898
899void WasmMemoryObject::update_instances(Isolate* isolate,
900                                        Handle<JSArrayBuffer> buffer) {
901  if (has_instances()) {
902    Handle<WeakArrayList> instances(this->instances(), isolate);
903    for (int i = 0; i < instances->length(); i++) {
904      MaybeObject elem = instances->Get(i);
905      HeapObject heap_object;
906      if (elem->GetHeapObjectIfWeak(&heap_object)) {
907        Handle<WasmInstanceObject> instance(
908            WasmInstanceObject::cast(heap_object), isolate);
909        SetInstanceMemory(instance, buffer);
910      } else {
911        DCHECK(elem->IsCleared());
912      }
913    }
914  }
915  set_array_buffer(*buffer);
916}
917
918// static
919int32_t WasmMemoryObject::Grow(Isolate* isolate,
920                               Handle<WasmMemoryObject> memory_object,
921                               uint32_t pages) {
922  TRACE_EVENT0("v8.wasm", "wasm.GrowMemory");
923  Handle<JSArrayBuffer> old_buffer(memory_object->array_buffer(), isolate);
924  // Any buffer used as an asmjs memory cannot be detached, and
925  // therefore this memory cannot be grown.
926  if (old_buffer->is_asmjs_memory()) return -1;
927
928  std::shared_ptr<BackingStore> backing_store = old_buffer->GetBackingStore();
929  if (!backing_store) return -1;
930
931  // Check for maximum memory size.
932  // Note: The {wasm::max_mem_pages()} limit is already checked in
933  // {BackingStore::CopyWasmMemory}, and is irrelevant for
934  // {GrowWasmMemoryInPlace} because memory is never allocated with more
935  // capacity than that limit.
936  size_t old_size = old_buffer->byte_length();
937  DCHECK_EQ(0, old_size % wasm::kWasmPageSize);
938  size_t old_pages = old_size / wasm::kWasmPageSize;
939  uint32_t max_pages = wasm::kSpecMaxMemoryPages;
940  if (memory_object->has_maximum_pages()) {
941    DCHECK_GE(max_pages, memory_object->maximum_pages());
942    max_pages = static_cast<uint32_t>(memory_object->maximum_pages());
943  }
944  DCHECK_GE(max_pages, old_pages);
945  if (pages > max_pages - old_pages) return -1;
946
947  base::Optional<size_t> result_inplace =
948      backing_store->GrowWasmMemoryInPlace(isolate, pages, max_pages);
949  // Handle shared memory first.
950  if (old_buffer->is_shared()) {
951    // Shared memories can only be grown in place; no copying.
952    if (!result_inplace.has_value()) {
953      // There are different limits per platform, thus crash if the correctness
954      // fuzzer is running.
955      if (FLAG_correctness_fuzzer_suppressions) {
956        FATAL("could not grow wasm memory");
957      }
958      return -1;
959    }
960
961    BackingStore::BroadcastSharedWasmMemoryGrow(isolate, backing_store);
962    // Broadcasting the update should update this memory object too.
963    CHECK_NE(*old_buffer, memory_object->array_buffer());
964    size_t new_pages = result_inplace.value() + pages;
965    // If the allocation succeeded, then this can't possibly overflow:
966    size_t new_byte_length = new_pages * wasm::kWasmPageSize;
967    // This is a less than check, as it is not guaranteed that the SAB
968    // length here will be equal to the stashed length above as calls to
969    // grow the same memory object can come in from different workers.
970    // It is also possible that a call to Grow was in progress when
971    // handling this call.
972    CHECK_LE(new_byte_length, memory_object->array_buffer().byte_length());
973    // As {old_pages} was read racefully, we return here the synchronized
974    // value provided by {GrowWasmMemoryInPlace}, to provide the atomic
975    // read-modify-write behavior required by the spec.
976    return static_cast<int32_t>(result_inplace.value());  // success
977  }
978
979  // Check if the non-shared memory could grow in-place.
980  if (result_inplace.has_value()) {
981    // Detach old and create a new one with the grown backing store.
982    old_buffer->Detach(true);
983    Handle<JSArrayBuffer> new_buffer =
984        isolate->factory()->NewJSArrayBuffer(std::move(backing_store));
985    memory_object->update_instances(isolate, new_buffer);
986    // For debugging purposes we memorize a link from the JSArrayBuffer
987    // to it's owning WasmMemoryObject instance.
988    Handle<Symbol> symbol =
989        isolate->factory()->array_buffer_wasm_memory_symbol();
990    JSObject::SetProperty(isolate, new_buffer, symbol, memory_object).Check();
991    DCHECK_EQ(result_inplace.value(), old_pages);
992    return static_cast<int32_t>(result_inplace.value());  // success
993  }
994
995  size_t new_pages = old_pages + pages;
996  DCHECK_LT(old_pages, new_pages);
997  // Try allocating a new backing store and copying.
998  // To avoid overall quadratic complexity of many small grow operations, we
999  // grow by at least 0.5 MB + 12.5% of the existing memory size.
1000  // These numbers are kept small because we must be careful about address
1001  // space consumption on 32-bit platforms.
1002  size_t min_growth = old_pages + 8 + (old_pages >> 3);
1003  size_t new_capacity = std::max(new_pages, min_growth);
1004  std::unique_ptr<BackingStore> new_backing_store =
1005      backing_store->CopyWasmMemory(isolate, new_pages, new_capacity);
1006  if (!new_backing_store) {
1007    // Crash on out-of-memory if the correctness fuzzer is running.
1008    if (FLAG_correctness_fuzzer_suppressions) {
1009      FATAL("could not grow wasm memory");
1010    }
1011    return -1;
1012  }
1013
1014  // Detach old and create a new one with the new backing store.
1015  old_buffer->Detach(true);
1016  Handle<JSArrayBuffer> new_buffer =
1017      isolate->factory()->NewJSArrayBuffer(std::move(new_backing_store));
1018  memory_object->update_instances(isolate, new_buffer);
1019  // For debugging purposes we memorize a link from the JSArrayBuffer
1020  // to it's owning WasmMemoryObject instance.
1021  Handle<Symbol> symbol = isolate->factory()->array_buffer_wasm_memory_symbol();
1022  JSObject::SetProperty(isolate, new_buffer, symbol, memory_object).Check();
1023  return static_cast<int32_t>(old_pages);  // success
1024}
1025
1026// static
1027MaybeHandle<WasmGlobalObject> WasmGlobalObject::New(
1028    Isolate* isolate, Handle<WasmInstanceObject> instance,
1029    MaybeHandle<JSArrayBuffer> maybe_untagged_buffer,
1030    MaybeHandle<FixedArray> maybe_tagged_buffer, wasm::ValueType type,
1031    int32_t offset, bool is_mutable) {
1032  Handle<JSFunction> global_ctor(
1033      isolate->native_context()->wasm_global_constructor(), isolate);
1034  auto global_obj = Handle<WasmGlobalObject>::cast(
1035      isolate->factory()->NewJSObject(global_ctor));
1036  {
1037    // Disallow GC until all fields have acceptable types.
1038    DisallowGarbageCollection no_gc;
1039    if (!instance.is_null()) global_obj->set_instance(*instance);
1040    global_obj->set_type(type);
1041    global_obj->set_offset(offset);
1042    global_obj->set_is_mutable(is_mutable);
1043  }
1044
1045  if (type.is_reference()) {
1046    DCHECK(maybe_untagged_buffer.is_null());
1047    Handle<FixedArray> tagged_buffer;
1048    if (!maybe_tagged_buffer.ToHandle(&tagged_buffer)) {
1049      // If no buffer was provided, create one.
1050      tagged_buffer =
1051          isolate->factory()->NewFixedArray(1, AllocationType::kOld);
1052      CHECK_EQ(offset, 0);
1053    }
1054    global_obj->set_tagged_buffer(*tagged_buffer);
1055  } else {
1056    DCHECK(maybe_tagged_buffer.is_null());
1057    uint32_t type_size = type.value_kind_size();
1058
1059    Handle<JSArrayBuffer> untagged_buffer;
1060    if (!maybe_untagged_buffer.ToHandle(&untagged_buffer)) {
1061      MaybeHandle<JSArrayBuffer> result =
1062          isolate->factory()->NewJSArrayBufferAndBackingStore(
1063              offset + type_size, InitializedFlag::kZeroInitialized);
1064
1065      if (!result.ToHandle(&untagged_buffer)) return {};
1066    }
1067
1068    // Check that the offset is in bounds.
1069    CHECK_LE(offset + type_size, untagged_buffer->byte_length());
1070
1071    global_obj->set_untagged_buffer(*untagged_buffer);
1072  }
1073
1074  return global_obj;
1075}
1076
1077FunctionTargetAndRef::FunctionTargetAndRef(
1078    Handle<WasmInstanceObject> target_instance, int target_func_index) {
1079  Isolate* isolate = target_instance->native_context().GetIsolate();
1080  if (target_func_index <
1081      static_cast<int>(target_instance->module()->num_imported_functions)) {
1082    // The function in the target instance was imported. Use its imports table,
1083    // which contains a tuple needed by the import wrapper.
1084    ImportedFunctionEntry entry(target_instance, target_func_index);
1085    ref_ = handle(entry.object_ref(), isolate);
1086    call_target_ = entry.target();
1087  } else {
1088    // The function in the target instance was not imported.
1089    ref_ = target_instance;
1090    call_target_ = target_instance->GetCallTarget(target_func_index);
1091  }
1092}
1093
1094void ImportedFunctionEntry::SetWasmToJs(
1095    Isolate* isolate, Handle<JSReceiver> callable,
1096    const wasm::WasmCode* wasm_to_js_wrapper, Handle<HeapObject> suspender) {
1097  TRACE_IFT("Import callable 0x%" PRIxPTR "[%d] = {callable=0x%" PRIxPTR
1098            ", target=%p}\n",
1099            instance_->ptr(), index_, callable->ptr(),
1100            wasm_to_js_wrapper->instructions().begin());
1101  DCHECK(wasm_to_js_wrapper->kind() == wasm::WasmCode::kWasmToJsWrapper ||
1102         wasm_to_js_wrapper->kind() == wasm::WasmCode::kWasmToCapiWrapper);
1103  Handle<WasmApiFunctionRef> ref =
1104      isolate->factory()->NewWasmApiFunctionRef(callable, suspender);
1105  instance_->imported_function_refs().set(index_, *ref);
1106  instance_->imported_function_targets()[index_] =
1107      wasm_to_js_wrapper->instruction_start();
1108}
1109
1110void ImportedFunctionEntry::SetWasmToWasm(WasmInstanceObject instance,
1111                                          Address call_target) {
1112  TRACE_IFT("Import Wasm 0x%" PRIxPTR "[%d] = {instance=0x%" PRIxPTR
1113            ", target=0x%" PRIxPTR "}\n",
1114            instance_->ptr(), index_, instance.ptr(), call_target);
1115  instance_->imported_function_refs().set(index_, instance);
1116  instance_->imported_function_targets()[index_] = call_target;
1117}
1118
1119// Returns an empty Object() if no callable is available, a JSReceiver
1120// otherwise.
1121Object ImportedFunctionEntry::maybe_callable() {
1122  Object value = object_ref();
1123  if (!value.IsWasmApiFunctionRef()) return Object();
1124  return JSReceiver::cast(WasmApiFunctionRef::cast(value).callable());
1125}
1126
1127JSReceiver ImportedFunctionEntry::callable() {
1128  return JSReceiver::cast(WasmApiFunctionRef::cast(object_ref()).callable());
1129}
1130
1131Object ImportedFunctionEntry::object_ref() {
1132  return instance_->imported_function_refs().get(index_);
1133}
1134
1135Address ImportedFunctionEntry::target() {
1136  return instance_->imported_function_targets()[index_];
1137}
1138
1139// static
1140constexpr uint16_t WasmInstanceObject::kTaggedFieldOffsets[];
1141
1142// static
1143bool WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
1144    Handle<WasmInstanceObject> instance, int table_index,
1145    uint32_t minimum_size) {
1146  Isolate* isolate = instance->GetIsolate();
1147  DCHECK_LT(table_index, instance->indirect_function_tables().length());
1148  Handle<WasmIndirectFunctionTable> table =
1149      instance->GetIndirectFunctionTable(isolate, table_index);
1150  WasmIndirectFunctionTable::Resize(isolate, table, minimum_size);
1151  if (table_index == 0) {
1152    instance->SetIndirectFunctionTableShortcuts(isolate);
1153  }
1154  return true;
1155}
1156
1157void WasmInstanceObject::SetRawMemory(byte* mem_start, size_t mem_size) {
1158  CHECK_LE(mem_size, wasm::max_mem_bytes());
1159#if V8_HOST_ARCH_64_BIT
1160  set_memory_start(mem_start);
1161  set_memory_size(mem_size);
1162#else
1163  // Must handle memory > 2GiB specially.
1164  CHECK_LE(mem_size, size_t{kMaxUInt32});
1165  set_memory_start(mem_start);
1166  set_memory_size(mem_size);
1167#endif
1168}
1169
1170const WasmModule* WasmInstanceObject::module() {
1171  return module_object().module();
1172}
1173
1174Handle<WasmInstanceObject> WasmInstanceObject::New(
1175    Isolate* isolate, Handle<WasmModuleObject> module_object) {
1176  Handle<JSFunction> instance_cons(
1177      isolate->native_context()->wasm_instance_constructor(), isolate);
1178  Handle<JSObject> instance_object =
1179      isolate->factory()->NewJSObject(instance_cons, AllocationType::kOld);
1180
1181  Handle<WasmInstanceObject> instance(
1182      WasmInstanceObject::cast(*instance_object), isolate);
1183  instance->clear_padding();
1184
1185  // Initialize the imported function arrays.
1186  auto module = module_object->module();
1187  auto num_imported_functions = module->num_imported_functions;
1188  auto num_imported_mutable_globals = module->num_imported_mutable_globals;
1189  auto num_data_segments = module->num_declared_data_segments;
1190  size_t native_allocations_size = EstimateNativeAllocationsSize(module);
1191  auto native_allocations = Managed<WasmInstanceNativeAllocations>::Allocate(
1192      isolate, native_allocations_size, instance, num_imported_functions,
1193      num_imported_mutable_globals, num_data_segments,
1194      module->elem_segments.size());
1195  instance->set_managed_native_allocations(*native_allocations);
1196
1197  Handle<FixedArray> imported_function_refs =
1198      isolate->factory()->NewFixedArray(num_imported_functions);
1199  instance->set_imported_function_refs(*imported_function_refs);
1200
1201  instance->SetRawMemory(reinterpret_cast<byte*>(EmptyBackingStoreBuffer()), 0);
1202  instance->set_isolate_root(isolate->isolate_root());
1203  instance->set_stack_limit_address(
1204      isolate->stack_guard()->address_of_jslimit());
1205  instance->set_real_stack_limit_address(
1206      isolate->stack_guard()->address_of_real_jslimit());
1207  instance->set_new_allocation_limit_address(
1208      isolate->heap()->NewSpaceAllocationLimitAddress());
1209  instance->set_new_allocation_top_address(
1210      isolate->heap()->NewSpaceAllocationTopAddress());
1211  instance->set_old_allocation_limit_address(
1212      isolate->heap()->OldSpaceAllocationLimitAddress());
1213  instance->set_old_allocation_top_address(
1214      isolate->heap()->OldSpaceAllocationTopAddress());
1215  instance->set_globals_start(nullptr);
1216  instance->set_indirect_function_table_size(0);
1217  instance->set_indirect_function_table_refs(
1218      ReadOnlyRoots(isolate).empty_fixed_array());
1219  instance->set_indirect_function_table_sig_ids(nullptr);
1220  instance->set_indirect_function_table_targets(nullptr);
1221  instance->set_native_context(*isolate->native_context());
1222  instance->set_module_object(*module_object);
1223  instance->set_jump_table_start(
1224      module_object->native_module()->jump_table_start());
1225  instance->set_hook_on_function_call_address(
1226      isolate->debug()->hook_on_function_call_address());
1227  instance->set_managed_object_maps(*isolate->factory()->empty_fixed_array());
1228  instance->set_feedback_vectors(*isolate->factory()->empty_fixed_array());
1229  instance->set_tiering_budget_array(
1230      module_object->native_module()->tiering_budget_array());
1231  instance->set_break_on_entry(module_object->script().break_on_entry());
1232
1233  // Insert the new instance into the scripts weak list of instances. This list
1234  // is used for breakpoints affecting all instances belonging to the script.
1235  if (module_object->script().type() == Script::TYPE_WASM) {
1236    Handle<WeakArrayList> weak_instance_list(
1237        module_object->script().wasm_weak_instance_list(), isolate);
1238    weak_instance_list = WeakArrayList::Append(
1239        isolate, weak_instance_list, MaybeObjectHandle::Weak(instance));
1240    module_object->script().set_wasm_weak_instance_list(*weak_instance_list);
1241  }
1242
1243  InitDataSegmentArrays(instance, module_object);
1244  InitElemSegmentArrays(instance, module_object);
1245
1246  return instance;
1247}
1248
1249// static
1250void WasmInstanceObject::InitDataSegmentArrays(
1251    Handle<WasmInstanceObject> instance,
1252    Handle<WasmModuleObject> module_object) {
1253  auto module = module_object->module();
1254  auto wire_bytes = module_object->native_module()->wire_bytes();
1255  auto num_data_segments = module->num_declared_data_segments;
1256  // The number of declared data segments will be zero if there is no DataCount
1257  // section. These arrays will not be allocated nor initialized in that case,
1258  // since they cannot be used (since the validator checks that number of
1259  // declared data segments when validating the memory.init and memory.drop
1260  // instructions).
1261  DCHECK(num_data_segments == 0 ||
1262         num_data_segments == module->data_segments.size());
1263  for (size_t i = 0; i < num_data_segments; ++i) {
1264    const wasm::WasmDataSegment& segment = module->data_segments[i];
1265    // Initialize the pointer and size of passive segments.
1266    auto source_bytes = wire_bytes.SubVector(segment.source.offset(),
1267                                             segment.source.end_offset());
1268    instance->data_segment_starts()[i] =
1269        reinterpret_cast<Address>(source_bytes.begin());
1270    // Set the active segments to being already dropped, since memory.init on
1271    // a dropped passive segment and an active segment have the same
1272    // behavior.
1273    instance->data_segment_sizes()[i] =
1274        segment.active ? 0 : source_bytes.length();
1275  }
1276}
1277
1278void WasmInstanceObject::InitElemSegmentArrays(
1279    Handle<WasmInstanceObject> instance,
1280    Handle<WasmModuleObject> module_object) {
1281  auto module = module_object->module();
1282  auto num_elem_segments = module->elem_segments.size();
1283  for (size_t i = 0; i < num_elem_segments; ++i) {
1284    instance->dropped_elem_segments()[i] =
1285        module->elem_segments[i].status ==
1286                wasm::WasmElemSegment::kStatusDeclarative
1287            ? 1
1288            : 0;
1289  }
1290}
1291
1292Address WasmInstanceObject::GetCallTarget(uint32_t func_index) {
1293  wasm::NativeModule* native_module = module_object().native_module();
1294  if (func_index < native_module->num_imported_functions()) {
1295    return imported_function_targets()[func_index];
1296  }
1297  return native_module->GetCallTargetForFunction(func_index);
1298}
1299
1300Handle<WasmIndirectFunctionTable> WasmInstanceObject::GetIndirectFunctionTable(
1301    Isolate* isolate, uint32_t table_index) {
1302  DCHECK_LT(table_index, indirect_function_tables().length());
1303  return handle(WasmIndirectFunctionTable::cast(
1304                    indirect_function_tables().get(table_index)),
1305                isolate);
1306}
1307
1308void WasmInstanceObject::SetIndirectFunctionTableShortcuts(Isolate* isolate) {
1309  if (indirect_function_tables().length() > 0 &&
1310      indirect_function_tables().get(0).IsWasmIndirectFunctionTable()) {
1311    HandleScope scope(isolate);
1312    Handle<WasmIndirectFunctionTable> table0 =
1313        GetIndirectFunctionTable(isolate, 0);
1314    set_indirect_function_table_size(table0->size());
1315    set_indirect_function_table_refs(table0->refs());
1316    set_indirect_function_table_sig_ids(table0->sig_ids());
1317    set_indirect_function_table_targets(table0->targets());
1318  }
1319}
1320
1321// static
1322bool WasmInstanceObject::CopyTableEntries(Isolate* isolate,
1323                                          Handle<WasmInstanceObject> instance,
1324                                          uint32_t table_dst_index,
1325                                          uint32_t table_src_index,
1326                                          uint32_t dst, uint32_t src,
1327                                          uint32_t count) {
1328  CHECK_LT(table_dst_index, instance->tables().length());
1329  CHECK_LT(table_src_index, instance->tables().length());
1330  auto table_dst = handle(
1331      WasmTableObject::cast(instance->tables().get(table_dst_index)), isolate);
1332  auto table_src = handle(
1333      WasmTableObject::cast(instance->tables().get(table_src_index)), isolate);
1334  uint32_t max_dst = table_dst->current_length();
1335  uint32_t max_src = table_src->current_length();
1336  bool copy_backward = src < dst;
1337  if (!base::IsInBounds(dst, count, max_dst) ||
1338      !base::IsInBounds(src, count, max_src)) {
1339    return false;
1340  }
1341
1342  // no-op
1343  if ((dst == src && table_dst_index == table_src_index) || count == 0) {
1344    return true;
1345  }
1346
1347  for (uint32_t i = 0; i < count; ++i) {
1348    uint32_t src_index = copy_backward ? (src + count - i - 1) : src + i;
1349    uint32_t dst_index = copy_backward ? (dst + count - i - 1) : dst + i;
1350    auto value = WasmTableObject::Get(isolate, table_src, src_index);
1351    WasmTableObject::Set(isolate, table_dst, dst_index, value);
1352  }
1353  return true;
1354}
1355
1356// static
1357bool WasmInstanceObject::InitTableEntries(Isolate* isolate,
1358                                          Handle<WasmInstanceObject> instance,
1359                                          uint32_t table_index,
1360                                          uint32_t segment_index, uint32_t dst,
1361                                          uint32_t src, uint32_t count) {
1362  // Note that this implementation just calls through to module instantiation.
1363  // This is intentional, so that the runtime only depends on the object
1364  // methods, and not the module instantiation logic.
1365  return wasm::LoadElemSegment(isolate, instance, table_index, segment_index,
1366                               dst, src, count);
1367}
1368
1369MaybeHandle<WasmInternalFunction> WasmInstanceObject::GetWasmInternalFunction(
1370    Isolate* isolate, Handle<WasmInstanceObject> instance, int index) {
1371  MaybeHandle<WasmInternalFunction> result;
1372  if (instance->has_wasm_internal_functions()) {
1373    Object val = instance->wasm_internal_functions().get(index);
1374    if (!val.IsUndefined(isolate)) {
1375      result = Handle<WasmInternalFunction>(WasmInternalFunction::cast(val),
1376                                            isolate);
1377    }
1378  }
1379  return result;
1380}
1381
1382Handle<WasmInternalFunction>
1383WasmInstanceObject::GetOrCreateWasmInternalFunction(
1384    Isolate* isolate, Handle<WasmInstanceObject> instance, int function_index) {
1385  MaybeHandle<WasmInternalFunction> maybe_result =
1386      WasmInstanceObject::GetWasmInternalFunction(isolate, instance,
1387                                                  function_index);
1388
1389  Handle<WasmInternalFunction> result;
1390  if (maybe_result.ToHandle(&result)) {
1391    return result;
1392  }
1393
1394  Handle<WasmModuleObject> module_object(instance->module_object(), isolate);
1395  const WasmModule* module = module_object->module();
1396  const WasmFunction& function = module->functions[function_index];
1397  int wrapper_index =
1398      GetExportWrapperIndex(module, function.sig_index, function.imported);
1399  DCHECK_EQ(wrapper_index,
1400            GetExportWrapperIndex(module, function.sig, function.imported));
1401
1402  Handle<Object> entry =
1403      FixedArray::get(module_object->export_wrappers(), wrapper_index, isolate);
1404
1405  Handle<CodeT> wrapper;
1406  if (entry->IsCodeT()) {
1407    wrapper = Handle<CodeT>::cast(entry);
1408  } else {
1409    // The wrapper may not exist yet if no function in the exports section has
1410    // this signature. We compile it and store the wrapper in the module for
1411    // later use.
1412    wrapper = ToCodeT(
1413        wasm::JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper(
1414            isolate, function.sig, instance->module(), function.imported),
1415        isolate);
1416    module_object->export_wrappers().set(wrapper_index, *wrapper);
1417  }
1418  auto external = Handle<WasmExternalFunction>::cast(WasmExportedFunction::New(
1419      isolate, instance, function_index,
1420      static_cast<int>(function.sig->parameter_count()), wrapper));
1421  result =
1422      WasmInternalFunction::FromExternal(external, isolate).ToHandleChecked();
1423
1424  WasmInstanceObject::SetWasmInternalFunction(isolate, instance, function_index,
1425                                              result);
1426  return result;
1427}
1428
1429void WasmInstanceObject::SetWasmInternalFunction(
1430    Isolate* isolate, Handle<WasmInstanceObject> instance, int index,
1431    Handle<WasmInternalFunction> val) {
1432  Handle<FixedArray> functions;
1433  if (!instance->has_wasm_internal_functions()) {
1434    // Lazily allocate the wasm external functions array.
1435    functions = isolate->factory()->NewFixedArray(
1436        static_cast<int>(instance->module()->functions.size()));
1437    instance->set_wasm_internal_functions(*functions);
1438  } else {
1439    functions =
1440        Handle<FixedArray>(instance->wasm_internal_functions(), isolate);
1441  }
1442  functions->set(index, *val);
1443}
1444
1445// static
1446void WasmInstanceObject::ImportWasmJSFunctionIntoTable(
1447    Isolate* isolate, Handle<WasmInstanceObject> instance, int table_index,
1448    int entry_index, Handle<WasmJSFunction> js_function) {
1449  // Deserialize the signature encapsulated with the {WasmJSFunction}.
1450  // Note that {SignatureMap::Find} may return {-1} if the signature is
1451  // not found; it will simply never match any check.
1452  Zone zone(isolate->allocator(), ZONE_NAME);
1453  const wasm::FunctionSig* sig = js_function->GetSignature(&zone);
1454  auto sig_id = instance->module()->signature_map.Find(*sig);
1455
1456  // Compile a wrapper for the target callable.
1457  Handle<JSReceiver> callable(js_function->GetCallable(), isolate);
1458  wasm::WasmCodeRefScope code_ref_scope;
1459  Address call_target = kNullAddress;
1460  if (sig_id >= 0) {
1461    wasm::NativeModule* native_module =
1462        instance->module_object().native_module();
1463    // TODO(wasm): Cache and reuse wrapper code, to avoid repeated compilation
1464    // and permissions switching.
1465    const wasm::WasmFeatures enabled = native_module->enabled_features();
1466    auto resolved = compiler::ResolveWasmImportCall(
1467        callable, sig, instance->module(), enabled);
1468    compiler::WasmImportCallKind kind = resolved.kind;
1469    callable = resolved.callable;  // Update to ultimate target.
1470    DCHECK_NE(compiler::WasmImportCallKind::kLinkError, kind);
1471    wasm::CompilationEnv env = native_module->CreateCompilationEnv();
1472    // {expected_arity} should only be used if kind != kJSFunctionArityMismatch.
1473    int expected_arity = -1;
1474    if (kind == compiler::WasmImportCallKind ::kJSFunctionArityMismatch) {
1475      expected_arity = Handle<JSFunction>::cast(callable)
1476                           ->shared()
1477                           .internal_formal_parameter_count_without_receiver();
1478    }
1479    wasm::Suspend suspend =
1480        resolved.suspender.is_null() || resolved.suspender->IsUndefined()
1481            ? wasm::kNoSuspend
1482            : wasm::kSuspend;
1483    // TODO(manoskouk): Reuse js_function->wasm_to_js_wrapper_code().
1484    wasm::WasmCompilationResult result = compiler::CompileWasmImportCallWrapper(
1485        &env, kind, sig, false, expected_arity, suspend);
1486    wasm::CodeSpaceWriteScope write_scope(native_module);
1487    std::unique_ptr<wasm::WasmCode> wasm_code = native_module->AddCode(
1488        result.func_index, result.code_desc, result.frame_slot_count,
1489        result.tagged_parameter_slots,
1490        result.protected_instructions_data.as_vector(),
1491        result.source_positions.as_vector(), GetCodeKind(result),
1492        wasm::ExecutionTier::kNone, wasm::kNoDebugging);
1493    wasm::WasmCode* published_code =
1494        native_module->PublishCode(std::move(wasm_code));
1495    isolate->counters()->wasm_generated_code_size()->Increment(
1496        published_code->instructions().length());
1497    isolate->counters()->wasm_reloc_size()->Increment(
1498        published_code->reloc_info().length());
1499    call_target = published_code->instruction_start();
1500  }
1501
1502  // Update the dispatch table.
1503  Handle<HeapObject> suspender = handle(js_function->GetSuspender(), isolate);
1504  Handle<WasmApiFunctionRef> ref =
1505      isolate->factory()->NewWasmApiFunctionRef(callable, suspender);
1506  WasmIndirectFunctionTable::cast(
1507      instance->indirect_function_tables().get(table_index))
1508      .Set(entry_index, sig_id, call_target, *ref);
1509}
1510
1511// static
1512uint8_t* WasmInstanceObject::GetGlobalStorage(
1513    Handle<WasmInstanceObject> instance, const wasm::WasmGlobal& global) {
1514  DCHECK(!global.type.is_reference());
1515  if (global.mutability && global.imported) {
1516    return reinterpret_cast<byte*>(
1517        instance->imported_mutable_globals()[global.index]);
1518  } else {
1519    return instance->globals_start() + global.offset;
1520  }
1521}
1522
1523// static
1524std::pair<Handle<FixedArray>, uint32_t>
1525WasmInstanceObject::GetGlobalBufferAndIndex(Handle<WasmInstanceObject> instance,
1526                                            const wasm::WasmGlobal& global) {
1527  DCHECK(global.type.is_reference());
1528  Isolate* isolate = instance->GetIsolate();
1529  if (global.mutability && global.imported) {
1530    Handle<FixedArray> buffer(
1531        FixedArray::cast(
1532            instance->imported_mutable_globals_buffers().get(global.index)),
1533        isolate);
1534    Address idx = instance->imported_mutable_globals()[global.index];
1535    DCHECK_LE(idx, std::numeric_limits<uint32_t>::max());
1536    return {buffer, static_cast<uint32_t>(idx)};
1537  }
1538  return {handle(instance->tagged_globals_buffer(), isolate), global.offset};
1539}
1540
1541// static
1542wasm::WasmValue WasmInstanceObject::GetGlobalValue(
1543    Handle<WasmInstanceObject> instance, const wasm::WasmGlobal& global) {
1544  Isolate* isolate = instance->GetIsolate();
1545  if (global.type.is_reference()) {
1546    Handle<FixedArray> global_buffer;  // The buffer of the global.
1547    uint32_t global_index = 0;         // The index into the buffer.
1548    std::tie(global_buffer, global_index) =
1549        GetGlobalBufferAndIndex(instance, global);
1550    return wasm::WasmValue(handle(global_buffer->get(global_index), isolate),
1551                           global.type);
1552  }
1553  Address ptr = reinterpret_cast<Address>(GetGlobalStorage(instance, global));
1554  using wasm::Simd128;
1555  switch (global.type.kind()) {
1556#define CASE_TYPE(valuetype, ctype) \
1557  case wasm::valuetype:             \
1558    return wasm::WasmValue(base::ReadUnalignedValue<ctype>(ptr));
1559    FOREACH_WASMVALUE_CTYPES(CASE_TYPE)
1560#undef CASE_TYPE
1561    default:
1562      UNREACHABLE();
1563  }
1564}
1565
1566wasm::WasmValue WasmStruct::GetFieldValue(uint32_t index) {
1567  wasm::ValueType field_type = type()->field(index);
1568  int field_offset = WasmStruct::kHeaderSize + type()->field_offset(index);
1569  Address field_address = GetFieldAddress(field_offset);
1570  using wasm::Simd128;
1571  switch (field_type.kind()) {
1572#define CASE_TYPE(valuetype, ctype) \
1573  case wasm::valuetype:             \
1574    return wasm::WasmValue(base::ReadUnalignedValue<ctype>(field_address));
1575    CASE_TYPE(kI8, int8_t)
1576    CASE_TYPE(kI16, int16_t)
1577    FOREACH_WASMVALUE_CTYPES(CASE_TYPE)
1578#undef CASE_TYPE
1579    case wasm::kRef:
1580    case wasm::kOptRef: {
1581      Handle<Object> ref(TaggedField<Object>::load(*this, field_offset),
1582                         GetIsolateFromWritableObject(*this));
1583      return wasm::WasmValue(ref, field_type);
1584    }
1585    case wasm::kRtt:
1586      // TODO(7748): Expose RTTs to DevTools.
1587      UNIMPLEMENTED();
1588    case wasm::kVoid:
1589    case wasm::kBottom:
1590      UNREACHABLE();
1591  }
1592}
1593
1594wasm::WasmValue WasmArray::GetElement(uint32_t index) {
1595  wasm::ValueType element_type = type()->element_type();
1596  int element_offset =
1597      WasmArray::kHeaderSize + index * element_type.value_kind_size();
1598  Address element_address = GetFieldAddress(element_offset);
1599  using wasm::Simd128;
1600  switch (element_type.kind()) {
1601#define CASE_TYPE(value_type, ctype) \
1602  case wasm::value_type:             \
1603    return wasm::WasmValue(base::ReadUnalignedValue<ctype>(element_address));
1604    CASE_TYPE(kI8, int8_t)
1605    CASE_TYPE(kI16, int16_t)
1606    FOREACH_WASMVALUE_CTYPES(CASE_TYPE)
1607#undef CASE_TYPE
1608    case wasm::kRef:
1609    case wasm::kOptRef: {
1610      Handle<Object> ref(TaggedField<Object>::load(*this, element_offset),
1611                         GetIsolateFromWritableObject(*this));
1612      return wasm::WasmValue(ref, element_type);
1613    }
1614    case wasm::kRtt:
1615      // TODO(7748): Expose RTTs to DevTools.
1616      UNIMPLEMENTED();
1617    case wasm::kVoid:
1618    case wasm::kBottom:
1619      UNREACHABLE();
1620  }
1621}
1622
1623// static
1624Handle<WasmTagObject> WasmTagObject::New(Isolate* isolate,
1625                                         const wasm::FunctionSig* sig,
1626                                         Handle<HeapObject> tag) {
1627  Handle<JSFunction> tag_cons(isolate->native_context()->wasm_tag_constructor(),
1628                              isolate);
1629
1630  // Serialize the signature.
1631  DCHECK_EQ(0, sig->return_count());
1632  DCHECK_LE(sig->parameter_count(), std::numeric_limits<int>::max());
1633  int sig_size = static_cast<int>(sig->parameter_count());
1634  Handle<PodArray<wasm::ValueType>> serialized_sig =
1635      PodArray<wasm::ValueType>::New(isolate, sig_size, AllocationType::kOld);
1636  int index = 0;  // Index into the {PodArray} above.
1637  for (wasm::ValueType param : sig->parameters()) {
1638    serialized_sig->set(index++, param);
1639  }
1640
1641  Handle<JSObject> tag_object =
1642      isolate->factory()->NewJSObject(tag_cons, AllocationType::kOld);
1643  Handle<WasmTagObject> tag_wrapper = Handle<WasmTagObject>::cast(tag_object);
1644  tag_wrapper->set_serialized_signature(*serialized_sig);
1645  tag_wrapper->set_tag(*tag);
1646
1647  return tag_wrapper;
1648}
1649
1650// TODO(9495): Update this if function type variance is introduced.
1651bool WasmTagObject::MatchesSignature(const wasm::FunctionSig* sig) {
1652  DCHECK_EQ(0, sig->return_count());
1653  DCHECK_LE(sig->parameter_count(), std::numeric_limits<int>::max());
1654  int sig_size = static_cast<int>(sig->parameter_count());
1655  if (sig_size != serialized_signature().length()) return false;
1656  for (int index = 0; index < sig_size; ++index) {
1657    if (sig->GetParam(index) != serialized_signature().get(index)) {
1658      return false;
1659    }
1660  }
1661  return true;
1662}
1663
1664// TODO(9495): Update this if function type variance is introduced.
1665bool WasmCapiFunction::MatchesSignature(const wasm::FunctionSig* sig) const {
1666  // TODO(jkummerow): Unify with "SignatureHelper" in c-api.cc.
1667  int param_count = static_cast<int>(sig->parameter_count());
1668  int result_count = static_cast<int>(sig->return_count());
1669  PodArray<wasm::ValueType> serialized_sig =
1670      shared().wasm_capi_function_data().serialized_signature();
1671  if (param_count + result_count + 1 != serialized_sig.length()) return false;
1672  int serialized_index = 0;
1673  for (int i = 0; i < result_count; i++, serialized_index++) {
1674    if (sig->GetReturn(i) != serialized_sig.get(serialized_index)) {
1675      return false;
1676    }
1677  }
1678  if (serialized_sig.get(serialized_index) != wasm::kWasmVoid) return false;
1679  serialized_index++;
1680  for (int i = 0; i < param_count; i++, serialized_index++) {
1681    if (sig->GetParam(i) != serialized_sig.get(serialized_index)) return false;
1682  }
1683  return true;
1684}
1685
1686// static
1687Handle<WasmExceptionPackage> WasmExceptionPackage::New(
1688    Isolate* isolate, Handle<WasmExceptionTag> exception_tag, int size) {
1689  Handle<FixedArray> values = isolate->factory()->NewFixedArray(size);
1690  return New(isolate, exception_tag, values);
1691}
1692
1693Handle<WasmExceptionPackage> WasmExceptionPackage::New(
1694    Isolate* isolate, Handle<WasmExceptionTag> exception_tag,
1695    Handle<FixedArray> values) {
1696  Handle<JSObject> exception = isolate->factory()->NewWasmExceptionError(
1697      MessageTemplate::kWasmExceptionError);
1698  CHECK(!Object::SetProperty(isolate, exception,
1699                             isolate->factory()->wasm_exception_tag_symbol(),
1700                             exception_tag, StoreOrigin::kMaybeKeyed,
1701                             Just(ShouldThrow::kThrowOnError))
1702             .is_null());
1703  CHECK(!Object::SetProperty(isolate, exception,
1704                             isolate->factory()->wasm_exception_values_symbol(),
1705                             values, StoreOrigin::kMaybeKeyed,
1706                             Just(ShouldThrow::kThrowOnError))
1707             .is_null());
1708  return Handle<WasmExceptionPackage>::cast(exception);
1709}
1710
1711// static
1712Handle<Object> WasmExceptionPackage::GetExceptionTag(
1713    Isolate* isolate, Handle<WasmExceptionPackage> exception_package) {
1714  Handle<Object> tag;
1715  if (JSReceiver::GetProperty(isolate, exception_package,
1716                              isolate->factory()->wasm_exception_tag_symbol())
1717          .ToHandle(&tag)) {
1718    return tag;
1719  }
1720  return ReadOnlyRoots(isolate).undefined_value_handle();
1721}
1722
1723// static
1724Handle<Object> WasmExceptionPackage::GetExceptionValues(
1725    Isolate* isolate, Handle<WasmExceptionPackage> exception_package) {
1726  Handle<Object> values;
1727  if (JSReceiver::GetProperty(
1728          isolate, exception_package,
1729          isolate->factory()->wasm_exception_values_symbol())
1730          .ToHandle(&values)) {
1731    DCHECK_IMPLIES(!values->IsUndefined(), values->IsFixedArray());
1732    return values;
1733  }
1734  return ReadOnlyRoots(isolate).undefined_value_handle();
1735}
1736
1737void EncodeI32ExceptionValue(Handle<FixedArray> encoded_values,
1738                             uint32_t* encoded_index, uint32_t value) {
1739  encoded_values->set((*encoded_index)++, Smi::FromInt(value >> 16));
1740  encoded_values->set((*encoded_index)++, Smi::FromInt(value & 0xffff));
1741}
1742
1743void EncodeI64ExceptionValue(Handle<FixedArray> encoded_values,
1744                             uint32_t* encoded_index, uint64_t value) {
1745  EncodeI32ExceptionValue(encoded_values, encoded_index,
1746                          static_cast<uint32_t>(value >> 32));
1747  EncodeI32ExceptionValue(encoded_values, encoded_index,
1748                          static_cast<uint32_t>(value));
1749}
1750
1751void DecodeI32ExceptionValue(Handle<FixedArray> encoded_values,
1752                             uint32_t* encoded_index, uint32_t* value) {
1753  uint32_t msb = Smi::cast(encoded_values->get((*encoded_index)++)).value();
1754  uint32_t lsb = Smi::cast(encoded_values->get((*encoded_index)++)).value();
1755  *value = (msb << 16) | (lsb & 0xffff);
1756}
1757
1758void DecodeI64ExceptionValue(Handle<FixedArray> encoded_values,
1759                             uint32_t* encoded_index, uint64_t* value) {
1760  uint32_t lsb = 0, msb = 0;
1761  DecodeI32ExceptionValue(encoded_values, encoded_index, &msb);
1762  DecodeI32ExceptionValue(encoded_values, encoded_index, &lsb);
1763  *value = (static_cast<uint64_t>(msb) << 32) | static_cast<uint64_t>(lsb);
1764}
1765
1766// static
1767Handle<WasmContinuationObject> WasmContinuationObject::New(
1768    Isolate* isolate, std::unique_ptr<wasm::StackMemory> stack,
1769    Handle<HeapObject> parent) {
1770  stack->jmpbuf()->stack_limit = stack->jslimit();
1771  stack->jmpbuf()->sp = stack->base();
1772  stack->jmpbuf()->fp = kNullAddress;
1773  wasm::JumpBuffer* jmpbuf = stack->jmpbuf();
1774  size_t external_size = stack->owned_size();
1775  Handle<Foreign> managed_stack = Managed<wasm::StackMemory>::FromUniquePtr(
1776      isolate, external_size, std::move(stack));
1777  Handle<Foreign> foreign_jmpbuf =
1778      isolate->factory()->NewForeign(reinterpret_cast<Address>(jmpbuf));
1779  Handle<WasmContinuationObject> result = Handle<WasmContinuationObject>::cast(
1780      isolate->factory()->NewStruct(WASM_CONTINUATION_OBJECT_TYPE));
1781  result->set_jmpbuf(*foreign_jmpbuf);
1782  result->set_stack(*managed_stack);
1783  result->set_parent(*parent);
1784  return result;
1785}
1786
1787// static
1788Handle<WasmContinuationObject> WasmContinuationObject::New(
1789    Isolate* isolate, std::unique_ptr<wasm::StackMemory> stack) {
1790  auto parent = ReadOnlyRoots(isolate).undefined_value();
1791  return New(isolate, std::move(stack), handle(parent, isolate));
1792}
1793
1794// static
1795Handle<WasmContinuationObject> WasmContinuationObject::New(
1796    Isolate* isolate, Handle<WasmContinuationObject> parent) {
1797  auto stack =
1798      std::unique_ptr<wasm::StackMemory>(wasm::StackMemory::New(isolate));
1799  return New(isolate, std::move(stack), parent);
1800}
1801
1802// static
1803Handle<WasmSuspenderObject> WasmSuspenderObject::New(Isolate* isolate) {
1804  Handle<JSFunction> suspender_cons(
1805      isolate->native_context()->wasm_suspender_constructor(), isolate);
1806  // Suspender objects should be at least as long-lived as the instances of
1807  // which it will wrap the imports/exports, allocate in old space too.
1808  auto suspender = Handle<WasmSuspenderObject>::cast(
1809      isolate->factory()->NewJSObject(suspender_cons, AllocationType::kOld));
1810  suspender->set_continuation(ReadOnlyRoots(isolate).undefined_value());
1811  suspender->set_parent(ReadOnlyRoots(isolate).undefined_value());
1812  suspender->set_state(Inactive);
1813  // Instantiate the callable object which resumes this Suspender. This will be
1814  // used implicitly as the onFulfilled callback of the returned JS promise.
1815  Handle<WasmOnFulfilledData> function_data =
1816      isolate->factory()->NewWasmOnFulfilledData(suspender);
1817  Handle<SharedFunctionInfo> shared =
1818      isolate->factory()->NewSharedFunctionInfoForWasmOnFulfilled(
1819          function_data);
1820  Handle<Context> context(isolate->native_context());
1821  Handle<JSObject> resume =
1822      Factory::JSFunctionBuilder{isolate, shared, context}.Build();
1823  suspender->set_resume(*resume);
1824  return suspender;
1825}
1826
1827#ifdef DEBUG
1828
1829namespace {
1830
1831constexpr uint32_t kBytesPerExceptionValuesArrayElement = 2;
1832
1833size_t ComputeEncodedElementSize(wasm::ValueType type) {
1834  size_t byte_size = type.value_kind_size();
1835  DCHECK_EQ(byte_size % kBytesPerExceptionValuesArrayElement, 0);
1836  DCHECK_LE(1, byte_size / kBytesPerExceptionValuesArrayElement);
1837  return byte_size / kBytesPerExceptionValuesArrayElement;
1838}
1839
1840}  // namespace
1841
1842#endif  // DEBUG
1843
1844// static
1845uint32_t WasmExceptionPackage::GetEncodedSize(const wasm::WasmTag* tag) {
1846  const wasm::WasmTagSig* sig = tag->sig;
1847  uint32_t encoded_size = 0;
1848  for (size_t i = 0; i < sig->parameter_count(); ++i) {
1849    switch (sig->GetParam(i).kind()) {
1850      case wasm::kI32:
1851      case wasm::kF32:
1852        DCHECK_EQ(2, ComputeEncodedElementSize(sig->GetParam(i)));
1853        encoded_size += 2;
1854        break;
1855      case wasm::kI64:
1856      case wasm::kF64:
1857        DCHECK_EQ(4, ComputeEncodedElementSize(sig->GetParam(i)));
1858        encoded_size += 4;
1859        break;
1860      case wasm::kS128:
1861        DCHECK_EQ(8, ComputeEncodedElementSize(sig->GetParam(i)));
1862        encoded_size += 8;
1863        break;
1864      case wasm::kRef:
1865      case wasm::kOptRef:
1866        encoded_size += 1;
1867        break;
1868      case wasm::kRtt:
1869      case wasm::kVoid:
1870      case wasm::kBottom:
1871      case wasm::kI8:
1872      case wasm::kI16:
1873        UNREACHABLE();
1874    }
1875  }
1876  return encoded_size;
1877}
1878
1879bool WasmExportedFunction::IsWasmExportedFunction(Object object) {
1880  if (!object.IsJSFunction()) return false;
1881  JSFunction js_function = JSFunction::cast(object);
1882  CodeT code = js_function.code();
1883  if (CodeKind::JS_TO_WASM_FUNCTION != code.kind() &&
1884      code.builtin_id() != Builtin::kGenericJSToWasmWrapper &&
1885      code.builtin_id() != Builtin::kWasmReturnPromiseOnSuspend) {
1886    return false;
1887  }
1888  DCHECK(js_function.shared().HasWasmExportedFunctionData());
1889  return true;
1890}
1891
1892bool WasmCapiFunction::IsWasmCapiFunction(Object object) {
1893  if (!object.IsJSFunction()) return false;
1894  JSFunction js_function = JSFunction::cast(object);
1895  // TODO(jkummerow): Enable this when there is a JavaScript wrapper
1896  // able to call this function.
1897  // if (js_function->code()->kind() != CodeKind::WASM_TO_CAPI_FUNCTION) {
1898  //   return false;
1899  // }
1900  // DCHECK(js_function->shared()->HasWasmCapiFunctionData());
1901  // return true;
1902  return js_function.shared().HasWasmCapiFunctionData();
1903}
1904
1905Handle<WasmCapiFunction> WasmCapiFunction::New(
1906    Isolate* isolate, Address call_target, Handle<Foreign> embedder_data,
1907    Handle<PodArray<wasm::ValueType>> serialized_signature) {
1908  // TODO(jkummerow): Install a JavaScript wrapper. For now, calling
1909  // these functions directly is unsupported; they can only be called
1910  // from Wasm code.
1911
1912  // To support simulator builds, we potentially have to redirect the
1913  // call target (which is an address pointing into the C++ binary).
1914  call_target = ExternalReference::Create(call_target).address();
1915
1916  // TODO(7748): Support proper typing for external functions. That requires
1917  // global (cross-module) canonicalization of signatures/RTTs.
1918  Handle<Map> rtt = isolate->factory()->wasm_internal_function_map();
1919  Handle<WasmCapiFunctionData> fun_data =
1920      isolate->factory()->NewWasmCapiFunctionData(
1921          call_target, embedder_data, BUILTIN_CODE(isolate, Illegal), rtt,
1922          serialized_signature);
1923  Handle<SharedFunctionInfo> shared =
1924      isolate->factory()->NewSharedFunctionInfoForWasmCapiFunction(fun_data);
1925  Handle<JSFunction> result =
1926      Factory::JSFunctionBuilder{isolate, shared, isolate->native_context()}
1927          .Build();
1928  fun_data->internal().set_external(*result);
1929  return Handle<WasmCapiFunction>::cast(result);
1930}
1931
1932WasmInstanceObject WasmExportedFunction::instance() {
1933  return shared().wasm_exported_function_data().instance();
1934}
1935
1936int WasmExportedFunction::function_index() {
1937  return shared().wasm_exported_function_data().function_index();
1938}
1939
1940Handle<WasmExportedFunction> WasmExportedFunction::New(
1941    Isolate* isolate, Handle<WasmInstanceObject> instance, int func_index,
1942    int arity, Handle<CodeT> export_wrapper) {
1943  DCHECK(
1944      CodeKind::JS_TO_WASM_FUNCTION == export_wrapper->kind() ||
1945      (export_wrapper->is_builtin() &&
1946       (export_wrapper->builtin_id() == Builtin::kGenericJSToWasmWrapper ||
1947        export_wrapper->builtin_id() == Builtin::kWasmReturnPromiseOnSuspend)));
1948  int num_imported_functions = instance->module()->num_imported_functions;
1949  Handle<Object> ref =
1950      func_index >= num_imported_functions
1951          ? instance
1952          : handle(instance->imported_function_refs().get(func_index), isolate);
1953
1954  Factory* factory = isolate->factory();
1955  const wasm::FunctionSig* sig = instance->module()->functions[func_index].sig;
1956  Address call_target = instance->GetCallTarget(func_index);
1957  Handle<Map> rtt;
1958  bool has_gc =
1959      instance->module_object().native_module()->enabled_features().has_gc();
1960  if (has_gc) {
1961    int sig_index = instance->module()->functions[func_index].sig_index;
1962    // TODO(7748): Create funcref RTTs lazily?
1963    rtt = handle(Map::cast(instance->managed_object_maps().get(sig_index)),
1964                 isolate);
1965  } else {
1966    rtt = factory->wasm_internal_function_map();
1967  }
1968  Handle<WasmExportedFunctionData> function_data =
1969      factory->NewWasmExportedFunctionData(
1970          export_wrapper, instance, call_target, ref, func_index,
1971          reinterpret_cast<Address>(sig), wasm::kGenericWrapperBudget, rtt);
1972
1973  MaybeHandle<String> maybe_name;
1974  bool is_asm_js_module = instance->module_object().is_asm_js();
1975  if (is_asm_js_module) {
1976    // We can use the function name only for asm.js. For WebAssembly, the
1977    // function name is specified as the function_index.toString().
1978    maybe_name = WasmModuleObject::GetFunctionNameOrNull(
1979        isolate, handle(instance->module_object(), isolate), func_index);
1980  }
1981  Handle<String> name;
1982  if (!maybe_name.ToHandle(&name)) {
1983    base::EmbeddedVector<char, 16> buffer;
1984    int length = SNPrintF(buffer, "%d", func_index);
1985    name = factory
1986               ->NewStringFromOneByte(
1987                   base::Vector<uint8_t>::cast(buffer.SubVector(0, length)))
1988               .ToHandleChecked();
1989  }
1990  Handle<Map> function_map;
1991  switch (instance->module()->origin) {
1992    case wasm::kWasmOrigin:
1993      function_map = isolate->wasm_exported_function_map();
1994      break;
1995    case wasm::kAsmJsSloppyOrigin:
1996      function_map = isolate->sloppy_function_map();
1997      break;
1998    case wasm::kAsmJsStrictOrigin:
1999      function_map = isolate->strict_function_map();
2000      break;
2001  }
2002
2003  Handle<NativeContext> context(isolate->native_context());
2004  Handle<SharedFunctionInfo> shared =
2005      factory->NewSharedFunctionInfoForWasmExportedFunction(name,
2006                                                            function_data);
2007  Handle<JSFunction> js_function =
2008      Factory::JSFunctionBuilder{isolate, shared, context}
2009          .set_map(function_map)
2010          .Build();
2011
2012  // According to the spec, exported functions should not have a [[Construct]]
2013  // method. This does not apply to functions exported from asm.js however.
2014  DCHECK_EQ(is_asm_js_module, js_function->IsConstructor());
2015  shared->set_length(arity);
2016  shared->set_internal_formal_parameter_count(JSParameterCount(arity));
2017  shared->set_script(instance->module_object().script());
2018  function_data->internal().set_external(*js_function);
2019  return Handle<WasmExportedFunction>::cast(js_function);
2020}
2021
2022Address WasmExportedFunction::GetWasmCallTarget() {
2023  return instance().GetCallTarget(function_index());
2024}
2025
2026const wasm::FunctionSig* WasmExportedFunction::sig() {
2027  return instance().module()->functions[function_index()].sig;
2028}
2029
2030bool WasmExportedFunction::MatchesSignature(
2031    const WasmModule* other_module, const wasm::FunctionSig* other_sig) {
2032  const wasm::FunctionSig* sig = this->sig();
2033  if (sig->parameter_count() != other_sig->parameter_count() ||
2034      sig->return_count() != other_sig->return_count()) {
2035    return false;
2036  }
2037
2038  for (int i = 0; i < sig->all().size(); i++) {
2039    if (!wasm::EquivalentTypes(sig->all()[i], other_sig->all()[i],
2040                               this->instance().module(), other_module)) {
2041      return false;
2042    }
2043  }
2044  return true;
2045}
2046
2047// static
2048std::unique_ptr<char[]> WasmExportedFunction::GetDebugName(
2049    const wasm::FunctionSig* sig) {
2050  constexpr const char kPrefix[] = "js-to-wasm:";
2051  // prefix + parameters + delimiter + returns + zero byte
2052  size_t len = strlen(kPrefix) + sig->all().size() + 2;
2053  auto buffer = base::OwnedVector<char>::New(len);
2054  memcpy(buffer.start(), kPrefix, strlen(kPrefix));
2055  PrintSignature(buffer.as_vector() + strlen(kPrefix), sig);
2056  return buffer.ReleaseData();
2057}
2058
2059// static
2060bool WasmJSFunction::IsWasmJSFunction(Object object) {
2061  if (!object.IsJSFunction()) return false;
2062  JSFunction js_function = JSFunction::cast(object);
2063  return js_function.shared().HasWasmJSFunctionData();
2064}
2065
2066Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
2067                                           const wasm::FunctionSig* sig,
2068                                           Handle<JSReceiver> callable,
2069                                           Handle<HeapObject> suspender) {
2070  DCHECK_LE(sig->all().size(), kMaxInt);
2071  int sig_size = static_cast<int>(sig->all().size());
2072  int return_count = static_cast<int>(sig->return_count());
2073  int parameter_count = static_cast<int>(sig->parameter_count());
2074  Handle<PodArray<wasm::ValueType>> serialized_sig =
2075      PodArray<wasm::ValueType>::New(isolate, sig_size, AllocationType::kOld);
2076  if (sig_size > 0) {
2077    serialized_sig->copy_in(0, sig->all().begin(), sig_size);
2078  }
2079  // TODO(wasm): Think about caching and sharing the JS-to-JS wrappers per
2080  // signature instead of compiling a new one for every instantiation.
2081  Handle<CodeT> wrapper_code = ToCodeT(
2082      compiler::CompileJSToJSWrapper(isolate, sig, nullptr).ToHandleChecked(),
2083      isolate);
2084
2085  // WasmJSFunctions use on-heap Code objects as call targets, so we can't
2086  // cache the target address, unless the WasmJSFunction wraps a
2087  // WasmExportedFunction.
2088  Address call_target = kNullAddress;
2089  if (WasmExportedFunction::IsWasmExportedFunction(*callable)) {
2090    call_target = WasmExportedFunction::cast(*callable).GetWasmCallTarget();
2091  }
2092
2093  Factory* factory = isolate->factory();
2094  // TODO(7748): Support proper typing for external functions. That requires
2095  // global (cross-module) canonicalization of signatures/RTTs.
2096  Handle<Map> rtt = factory->wasm_internal_function_map();
2097  Handle<WasmJSFunctionData> function_data = factory->NewWasmJSFunctionData(
2098      call_target, callable, return_count, parameter_count, serialized_sig,
2099      wrapper_code, rtt, suspender);
2100
2101  if (wasm::WasmFeatures::FromIsolate(isolate).has_typed_funcref()) {
2102    using CK = compiler::WasmImportCallKind;
2103    int expected_arity = parameter_count;
2104    CK kind = compiler::kDefaultImportCallKind;
2105    if (callable->IsJSFunction()) {
2106      SharedFunctionInfo shared = Handle<JSFunction>::cast(callable)->shared();
2107      expected_arity =
2108          shared.internal_formal_parameter_count_without_receiver();
2109      if (expected_arity != parameter_count) {
2110        kind = CK::kJSFunctionArityMismatch;
2111      }
2112    }
2113    // TODO(wasm): Think about caching and sharing the wasm-to-JS wrappers per
2114    // signature instead of compiling a new one for every instantiation.
2115    wasm::Suspend suspend =
2116        suspender.is_null() ? wasm::kNoSuspend : wasm::kSuspend;
2117    DCHECK_IMPLIES(!suspender.is_null(), !suspender->IsUndefined());
2118    Handle<CodeT> wasm_to_js_wrapper_code =
2119        ToCodeT(compiler::CompileWasmToJSWrapper(isolate, sig, kind,
2120                                                 expected_arity, suspend)
2121                    .ToHandleChecked(),
2122                isolate);
2123    function_data->internal().set_code(*wasm_to_js_wrapper_code);
2124  }
2125
2126  Handle<String> name = factory->Function_string();
2127  if (callable->IsJSFunction()) {
2128    name = JSFunction::GetDebugName(Handle<JSFunction>::cast(callable));
2129    name = String::Flatten(isolate, name);
2130  }
2131  Handle<NativeContext> context(isolate->native_context());
2132  Handle<SharedFunctionInfo> shared =
2133      factory->NewSharedFunctionInfoForWasmJSFunction(name, function_data);
2134  Handle<JSFunction> js_function =
2135      Factory::JSFunctionBuilder{isolate, shared, context}
2136          .set_map(isolate->wasm_exported_function_map())
2137          .Build();
2138  js_function->shared().set_internal_formal_parameter_count(
2139      JSParameterCount(parameter_count));
2140  function_data->internal().set_external(*js_function);
2141  return Handle<WasmJSFunction>::cast(js_function);
2142}
2143
2144JSReceiver WasmJSFunction::GetCallable() const {
2145  return JSReceiver::cast(WasmApiFunctionRef::cast(
2146                              shared().wasm_js_function_data().internal().ref())
2147                              .callable());
2148}
2149
2150HeapObject WasmJSFunction::GetSuspender() const {
2151  return WasmApiFunctionRef::cast(
2152             shared().wasm_js_function_data().internal().ref())
2153      .suspender();
2154}
2155
2156const wasm::FunctionSig* WasmJSFunction::GetSignature(Zone* zone) {
2157  WasmJSFunctionData function_data = shared().wasm_js_function_data();
2158  int sig_size = function_data.serialized_signature().length();
2159  wasm::ValueType* types = zone->NewArray<wasm::ValueType>(sig_size);
2160  if (sig_size > 0) {
2161    function_data.serialized_signature().copy_out(0, types, sig_size);
2162  }
2163  int return_count = function_data.serialized_return_count();
2164  int parameter_count = function_data.serialized_parameter_count();
2165  return zone->New<wasm::FunctionSig>(return_count, parameter_count, types);
2166}
2167
2168bool WasmJSFunction::MatchesSignatureForSuspend(const wasm::FunctionSig* sig) {
2169  DCHECK_LE(sig->all().size(), kMaxInt);
2170  int sig_size = static_cast<int>(sig->all().size());
2171  int parameter_count = static_cast<int>(sig->parameter_count());
2172  int return_count = static_cast<int>(sig->return_count());
2173  DisallowHeapAllocation no_alloc;
2174  WasmJSFunctionData function_data = shared().wasm_js_function_data();
2175  if (parameter_count != function_data.serialized_parameter_count()) {
2176    return false;
2177  }
2178  if (sig_size == 0) return true;  // Prevent undefined behavior.
2179  // This function is only called for functions wrapped by a
2180  // WebAssembly.Suspender object, so the return type has to be externref.
2181  CHECK_EQ(function_data.serialized_return_count(), 1);
2182  CHECK_EQ(function_data.serialized_signature().get(0), wasm::kWasmAnyRef);
2183  const wasm::ValueType* expected = sig->all().begin();
2184  return function_data.serialized_signature().matches(
2185      1, expected + return_count, parameter_count);
2186}
2187
2188// TODO(9495): Update this if function type variance is introduced.
2189bool WasmJSFunction::MatchesSignature(const wasm::FunctionSig* sig) {
2190  DCHECK_LE(sig->all().size(), kMaxInt);
2191  int sig_size = static_cast<int>(sig->all().size());
2192  int return_count = static_cast<int>(sig->return_count());
2193  int parameter_count = static_cast<int>(sig->parameter_count());
2194  DisallowHeapAllocation no_alloc;
2195  WasmJSFunctionData function_data = shared().wasm_js_function_data();
2196  if (return_count != function_data.serialized_return_count() ||
2197      parameter_count != function_data.serialized_parameter_count()) {
2198    return false;
2199  }
2200  if (sig_size == 0) return true;  // Prevent undefined behavior.
2201  const wasm::ValueType* expected = sig->all().begin();
2202  return function_data.serialized_signature().matches(expected, sig_size);
2203}
2204
2205PodArray<wasm::ValueType> WasmCapiFunction::GetSerializedSignature() const {
2206  return shared().wasm_capi_function_data().serialized_signature();
2207}
2208
2209bool WasmExternalFunction::IsWasmExternalFunction(Object object) {
2210  return WasmExportedFunction::IsWasmExportedFunction(object) ||
2211         WasmJSFunction::IsWasmJSFunction(object);
2212}
2213
2214// static
2215MaybeHandle<WasmInternalFunction> WasmInternalFunction::FromExternal(
2216    Handle<Object> external, Isolate* isolate) {
2217  if (WasmExportedFunction::IsWasmExportedFunction(*external) ||
2218      WasmJSFunction::IsWasmJSFunction(*external) ||
2219      WasmCapiFunction::IsWasmCapiFunction(*external)) {
2220    WasmFunctionData data = WasmFunctionData::cast(
2221        Handle<JSFunction>::cast(external)->shared().function_data(
2222            kAcquireLoad));
2223    return handle(data.internal(), isolate);
2224  }
2225  return MaybeHandle<WasmInternalFunction>();
2226}
2227
2228Handle<WasmExceptionTag> WasmExceptionTag::New(Isolate* isolate, int index) {
2229  Handle<WasmExceptionTag> result =
2230      Handle<WasmExceptionTag>::cast(isolate->factory()->NewStruct(
2231          WASM_EXCEPTION_TAG_TYPE, AllocationType::kOld));
2232  result->set_index(index);
2233  return result;
2234}
2235
2236Handle<AsmWasmData> AsmWasmData::New(
2237    Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
2238    Handle<FixedArray> export_wrappers, Handle<HeapNumber> uses_bitset) {
2239  const WasmModule* module = native_module->module();
2240  const bool kUsesLiftoff = false;
2241  size_t memory_estimate =
2242      wasm::WasmCodeManager::EstimateNativeModuleCodeSize(
2243          module, kUsesLiftoff, wasm::DynamicTiering::kDisabled) +
2244      wasm::WasmCodeManager::EstimateNativeModuleMetaDataSize(module);
2245  Handle<Managed<wasm::NativeModule>> managed_native_module =
2246      Managed<wasm::NativeModule>::FromSharedPtr(isolate, memory_estimate,
2247                                                 std::move(native_module));
2248  Handle<AsmWasmData> result = Handle<AsmWasmData>::cast(
2249      isolate->factory()->NewStruct(ASM_WASM_DATA_TYPE, AllocationType::kOld));
2250  result->set_managed_native_module(*managed_native_module);
2251  result->set_export_wrappers(*export_wrappers);
2252  result->set_uses_bitset(*uses_bitset);
2253  return result;
2254}
2255
2256namespace wasm {
2257
2258bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
2259                       Handle<Object> value, ValueType expected,
2260                       const char** error_message) {
2261  DCHECK(expected.is_reference());
2262  switch (expected.kind()) {
2263    case kOptRef:
2264      if (value->IsNull(isolate)) return true;
2265      V8_FALLTHROUGH;
2266    case kRef: {
2267      HeapType::Representation repr = expected.heap_representation();
2268      switch (repr) {
2269        case HeapType::kFunc: {
2270          if (!(WasmExternalFunction::IsWasmExternalFunction(*value) ||
2271                WasmCapiFunction::IsWasmCapiFunction(*value))) {
2272            *error_message =
2273                "function-typed object must be null (if nullable) or a Wasm "
2274                "function object";
2275            return false;
2276          }
2277          return true;
2278        }
2279        case HeapType::kAny:
2280          return true;
2281        case HeapType::kData:
2282        case HeapType::kArray:
2283        case HeapType::kEq:
2284        case HeapType::kI31: {
2285          // TODO(7748): Change this when we have a decision on the JS API for
2286          // structs/arrays.
2287          if (!FLAG_wasm_gc_js_interop) {
2288            Handle<Name> key = isolate->factory()->wasm_wrapped_object_symbol();
2289            LookupIterator it(isolate, value, key,
2290                              LookupIterator::OWN_SKIP_INTERCEPTOR);
2291            if (it.state() != LookupIterator::DATA) {
2292              *error_message =
2293                  "eqref/dataref/i31ref object must be null (if nullable) or "
2294                  "wrapped with the wasm object wrapper";
2295              return false;
2296            }
2297            value = it.GetDataValue();
2298          }
2299
2300          if (repr == HeapType::kI31) {
2301            if (!value->IsSmi()) {
2302              *error_message = "i31ref-typed object cannot be a heap object";
2303              return false;
2304            }
2305            return true;
2306          }
2307
2308          if (!((repr == HeapType::kEq && value->IsSmi()) ||
2309                (repr != HeapType::kArray && value->IsWasmStruct()) ||
2310                value->IsWasmArray())) {
2311            *error_message = "object incompatible with wasm type";
2312            return false;
2313          }
2314          return true;
2315        }
2316        default:
2317          if (module == nullptr) {
2318            *error_message =
2319                "an object defined in JavaScript cannot be compatible with a "
2320                "type defined in a Webassembly module";
2321            return false;
2322          }
2323          DCHECK(module->has_type(expected.ref_index()));
2324          if (module->has_signature(expected.ref_index())) {
2325            if (WasmExportedFunction::IsWasmExportedFunction(*value)) {
2326              WasmExportedFunction function =
2327                  WasmExportedFunction::cast(*value);
2328              const WasmModule* exporting_module = function.instance().module();
2329              ValueType real_type = ValueType::Ref(
2330                  exporting_module->functions[function.function_index()]
2331                      .sig_index,
2332                  kNonNullable);
2333              if (!IsSubtypeOf(real_type, expected, exporting_module, module)) {
2334                *error_message =
2335                    "assigned exported function has to be a subtype of the "
2336                    "expected type";
2337                return false;
2338              }
2339              return true;
2340            }
2341
2342            if (WasmJSFunction::IsWasmJSFunction(*value)) {
2343              // Since a WasmJSFunction cannot refer to indexed types (definable
2344              // only in a module), we do not need full function subtyping.
2345              // TODO(manoskouk): Change this if wasm types can be exported.
2346              if (!WasmJSFunction::cast(*value).MatchesSignature(
2347                      module->signature(expected.ref_index()))) {
2348                *error_message =
2349                    "assigned WasmJSFunction has to be a subtype of the "
2350                    "expected type";
2351                return false;
2352              }
2353              return true;
2354            }
2355
2356            if (WasmCapiFunction::IsWasmCapiFunction(*value)) {
2357              // Since a WasmCapiFunction cannot refer to indexed types
2358              // (definable only in a module), we do not need full function
2359              // subtyping.
2360              // TODO(manoskouk): Change this if wasm types can be exported.
2361              if (!WasmCapiFunction::cast(*value).MatchesSignature(
2362                      module->signature(expected.ref_index()))) {
2363                *error_message =
2364                    "assigned WasmCapiFunction has to be a subtype of the "
2365                    "expected type";
2366                return false;
2367              }
2368              return true;
2369            }
2370
2371            *error_message =
2372                "function-typed object must be null (if nullable) or a Wasm "
2373                "function object";
2374
2375            return false;
2376          }
2377          // TODO(7748): Implement when the JS API for structs/arrays is decided
2378          // on.
2379          *error_message =
2380              "passing struct/array-typed objects between Webassembly and "
2381              "Javascript is not supported yet.";
2382          return false;
2383      }
2384    }
2385    case kRtt:
2386      // TODO(7748): Implement when the JS API for rtts is decided on.
2387      *error_message =
2388          "passing rtts between Webassembly and Javascript is not supported "
2389          "yet.";
2390      return false;
2391    case kI8:
2392    case kI16:
2393    case kI32:
2394    case kI64:
2395    case kF32:
2396    case kF64:
2397    case kS128:
2398    case kVoid:
2399    case kBottom:
2400      UNREACHABLE();
2401  }
2402}
2403
2404}  // namespace wasm
2405
2406}  // namespace internal
2407}  // namespace v8
2408
2409#undef TRACE_IFT
2410