• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
40 namespace v8 {
41 namespace internal {
42 
43 // Import a few often used types from the wasm namespace.
44 using WasmFunction = wasm::WasmFunction;
45 using WasmModule = wasm::WasmModule;
46 
47 namespace {
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.
53 class WasmInstanceNativeAllocations {
54  public:
WasmInstanceNativeAllocations(Handle<WasmInstanceObject> instance,size_t num_imported_functions,size_t num_imported_mutable_globals,size_t num_data_segments,size_t num_elem_segments)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 
EstimateNativeAllocationsSize(const WasmModule * module)80 size_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 
90 enum DispatchTableElements : int {
91   kDispatchTableInstanceOffset,
92   kDispatchTableIndexOffset,
93   // Marker:
94   kDispatchTableNumElements
95 };
96 
97 }  // namespace
98 
99 // static
New(Isolate * isolate,std::shared_ptr<wasm::NativeModule> native_module,Handle<Script> script)100 Handle<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
New(Isolate * isolate,std::shared_ptr<wasm::NativeModule> native_module,Handle<Script> script,Handle<FixedArray> export_wrappers)108 Handle<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 
ExtractUtf8StringFromModuleBytes(Isolate * isolate,Handle<WasmModuleObject> module_object,wasm::WireBytesRef ref,InternalizeString internalize)132 Handle<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 
ExtractUtf8StringFromModuleBytes(Isolate * isolate,base::Vector<const uint8_t> wire_bytes,wasm::WireBytesRef ref,InternalizeString internalize)141 Handle<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 
GetModuleNameOrNull(Isolate * isolate,Handle<WasmModuleObject> module_object)157 MaybeHandle<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 
GetFunctionNameOrNull(Isolate * isolate,Handle<WasmModuleObject> module_object,uint32_t func_index)165 MaybeHandle<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 
GetRawFunctionName(int func_index)178 base::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 
New(Isolate * isolate,Handle<WasmInstanceObject> instance,wasm::ValueType type,uint32_t initial,bool has_maximum,uint32_t maximum,Handle<FixedArray> * entries,Handle<Object> initial_value)192 Handle<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 
AddDispatchTable(Isolate * isolate,Handle<WasmTableObject> table_obj,Handle<WasmInstanceObject> instance,int table_index)234 void 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 
Grow(Isolate * isolate,Handle<WasmTableObject> table,uint32_t count,Handle<Object> init_value)258 int 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 
IsInBounds(Isolate * isolate,Handle<WasmTableObject> table,uint32_t entry_index)317 bool 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 
IsValidElement(Isolate * isolate,Handle<WasmTableObject> table,Handle<Object> entry)323 bool 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 
SetFunctionTableEntry(Isolate * isolate,Handle<WasmTableObject> table,Handle<FixedArray> entries,int entry_index,Handle<Object> entry)339 void 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 
Set(Isolate * isolate,Handle<WasmTableObject> table,uint32_t index,Handle<Object> entry)372 void 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 
Get(Isolate * isolate,Handle<WasmTableObject> table,uint32_t index)408 Handle<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 
Fill(Isolate * isolate,Handle<WasmTableObject> table,uint32_t start,Handle<Object> entry,uint32_t count)464 void 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 
UpdateDispatchTables(Isolate * isolate,WasmTableObject table,int entry_index,const wasm::WasmFunction * func,WasmInstanceObject target_instance)477 void 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 
UpdateDispatchTables(Isolate * isolate,Handle<WasmTableObject> table,int entry_index,Handle<WasmJSFunction> function)527 void 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 
UpdateDispatchTables(Isolate * isolate,Handle<WasmTableObject> table,int entry_index,Handle<WasmCapiFunction> capi_function)549 void 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 
ClearDispatchTables(Isolate * isolate,Handle<WasmTableObject> table,int index)614 void 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 
SetFunctionTablePlaceholder(Isolate * isolate,Handle<WasmTableObject> table,int entry_index,Handle<WasmInstanceObject> instance,int func_index)634 void 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 
GetFunctionTableEntry(Isolate * isolate,const WasmModule * module,Handle<WasmTableObject> table,int entry_index,bool * is_valid,bool * is_null,MaybeHandle<WasmInstanceObject> * instance,int * function_index,MaybeHandle<WasmJSFunction> * maybe_js_function)648 void 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 
688 namespace {
689 class IftNativeAllocations {
690  public:
IftNativeAllocations(Handle<WasmIndirectFunctionTable> table,uint32_t size)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 
SizeInMemory(uint32_t size)697   static size_t SizeInMemory(uint32_t size) {
698     return size * (sizeof(Address) + sizeof(uint32_t));
699   }
700 
resize(Handle<WasmIndirectFunctionTable> table,uint32_t new_size)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 
New(Isolate * isolate,uint32_t size)718 Handle<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 }
Set(uint32_t index,int sig_id,Address call_target,Object ref)733 void 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 
Clear(uint32_t index)740 void 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 
Resize(Isolate * isolate,Handle<WasmIndirectFunctionTable> table,uint32_t new_size)748 void 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 
778 namespace {
779 
SetInstanceMemory(Handle<WasmInstanceObject> instance,Handle<JSArrayBuffer> buffer)780 void 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 
New(Isolate * isolate,MaybeHandle<JSArrayBuffer> maybe_buffer,int maximum)810 MaybeHandle<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 
New(Isolate * isolate,int initial,int maximum,SharedFlag shared)842 MaybeHandle<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 
AddInstance(Isolate * isolate,Handle<WasmMemoryObject> memory,Handle<WasmInstanceObject> instance)884 void 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 
update_instances(Isolate * isolate,Handle<JSArrayBuffer> buffer)899 void 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
Grow(Isolate * isolate,Handle<WasmMemoryObject> memory_object,uint32_t pages)919 int32_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
New(Isolate * isolate,Handle<WasmInstanceObject> instance,MaybeHandle<JSArrayBuffer> maybe_untagged_buffer,MaybeHandle<FixedArray> maybe_tagged_buffer,wasm::ValueType type,int32_t offset,bool is_mutable)1027 MaybeHandle<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 
FunctionTargetAndRef(Handle<WasmInstanceObject> target_instance,int target_func_index)1077 FunctionTargetAndRef::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 
SetWasmToJs(Isolate * isolate,Handle<JSReceiver> callable,const wasm::WasmCode * wasm_to_js_wrapper,Handle<HeapObject> suspender)1094 void 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 
SetWasmToWasm(WasmInstanceObject instance,Address call_target)1110 void 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.
maybe_callable()1121 Object ImportedFunctionEntry::maybe_callable() {
1122   Object value = object_ref();
1123   if (!value.IsWasmApiFunctionRef()) return Object();
1124   return JSReceiver::cast(WasmApiFunctionRef::cast(value).callable());
1125 }
1126 
callable()1127 JSReceiver ImportedFunctionEntry::callable() {
1128   return JSReceiver::cast(WasmApiFunctionRef::cast(object_ref()).callable());
1129 }
1130 
object_ref()1131 Object ImportedFunctionEntry::object_ref() {
1132   return instance_->imported_function_refs().get(index_);
1133 }
1134 
target()1135 Address ImportedFunctionEntry::target() {
1136   return instance_->imported_function_targets()[index_];
1137 }
1138 
1139 // static
1140 constexpr uint16_t WasmInstanceObject::kTaggedFieldOffsets[];
1141 
1142 // static
EnsureIndirectFunctionTableWithMinimumSize(Handle<WasmInstanceObject> instance,int table_index,uint32_t minimum_size)1143 bool 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 
SetRawMemory(byte * mem_start,size_t mem_size)1157 void 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 
module()1170 const WasmModule* WasmInstanceObject::module() {
1171   return module_object().module();
1172 }
1173 
New(Isolate * isolate,Handle<WasmModuleObject> module_object)1174 Handle<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
InitDataSegmentArrays(Handle<WasmInstanceObject> instance,Handle<WasmModuleObject> module_object)1250 void 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 
InitElemSegmentArrays(Handle<WasmInstanceObject> instance,Handle<WasmModuleObject> module_object)1278 void 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 
GetCallTarget(uint32_t func_index)1292 Address 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 
GetIndirectFunctionTable(Isolate * isolate,uint32_t table_index)1300 Handle<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 
SetIndirectFunctionTableShortcuts(Isolate * isolate)1308 void 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
CopyTableEntries(Isolate * isolate,Handle<WasmInstanceObject> instance,uint32_t table_dst_index,uint32_t table_src_index,uint32_t dst,uint32_t src,uint32_t count)1322 bool 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
InitTableEntries(Isolate * isolate,Handle<WasmInstanceObject> instance,uint32_t table_index,uint32_t segment_index,uint32_t dst,uint32_t src,uint32_t count)1357 bool 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 
GetWasmInternalFunction(Isolate * isolate,Handle<WasmInstanceObject> instance,int index)1369 MaybeHandle<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 
1382 Handle<WasmInternalFunction>
GetOrCreateWasmInternalFunction(Isolate * isolate,Handle<WasmInstanceObject> instance,int function_index)1383 WasmInstanceObject::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 
SetWasmInternalFunction(Isolate * isolate,Handle<WasmInstanceObject> instance,int index,Handle<WasmInternalFunction> val)1429 void 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
ImportWasmJSFunctionIntoTable(Isolate * isolate,Handle<WasmInstanceObject> instance,int table_index,int entry_index,Handle<WasmJSFunction> js_function)1446 void 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
GetGlobalStorage(Handle<WasmInstanceObject> instance,const wasm::WasmGlobal & global)1512 uint8_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
1524 std::pair<Handle<FixedArray>, uint32_t>
GetGlobalBufferAndIndex(Handle<WasmInstanceObject> instance,const wasm::WasmGlobal & global)1525 WasmInstanceObject::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
GetGlobalValue(Handle<WasmInstanceObject> instance,const wasm::WasmGlobal & global)1542 wasm::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 
GetFieldValue(uint32_t index)1566 wasm::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 
GetElement(uint32_t index)1594 wasm::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
New(Isolate * isolate,const wasm::FunctionSig * sig,Handle<HeapObject> tag)1624 Handle<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.
MatchesSignature(const wasm::FunctionSig * sig)1651 bool 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.
MatchesSignature(const wasm::FunctionSig * sig) const1665 bool 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
New(Isolate * isolate,Handle<WasmExceptionTag> exception_tag,int size)1687 Handle<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 
New(Isolate * isolate,Handle<WasmExceptionTag> exception_tag,Handle<FixedArray> values)1693 Handle<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
GetExceptionTag(Isolate * isolate,Handle<WasmExceptionPackage> exception_package)1712 Handle<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
GetExceptionValues(Isolate * isolate,Handle<WasmExceptionPackage> exception_package)1724 Handle<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 
EncodeI32ExceptionValue(Handle<FixedArray> encoded_values,uint32_t * encoded_index,uint32_t value)1737 void 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 
EncodeI64ExceptionValue(Handle<FixedArray> encoded_values,uint32_t * encoded_index,uint64_t value)1743 void 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 
DecodeI32ExceptionValue(Handle<FixedArray> encoded_values,uint32_t * encoded_index,uint32_t * value)1751 void 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 
DecodeI64ExceptionValue(Handle<FixedArray> encoded_values,uint32_t * encoded_index,uint64_t * value)1758 void 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
New(Isolate * isolate,std::unique_ptr<wasm::StackMemory> stack,Handle<HeapObject> parent)1767 Handle<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
New(Isolate * isolate,std::unique_ptr<wasm::StackMemory> stack)1788 Handle<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
New(Isolate * isolate,Handle<WasmContinuationObject> parent)1795 Handle<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
New(Isolate * isolate)1803 Handle<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 
1829 namespace {
1830 
1831 constexpr uint32_t kBytesPerExceptionValuesArrayElement = 2;
1832 
ComputeEncodedElementSize(wasm::ValueType type)1833 size_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
GetEncodedSize(const wasm::WasmTag * tag)1845 uint32_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 
IsWasmExportedFunction(Object object)1879 bool 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 
IsWasmCapiFunction(Object object)1892 bool 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 
New(Isolate * isolate,Address call_target,Handle<Foreign> embedder_data,Handle<PodArray<wasm::ValueType>> serialized_signature)1905 Handle<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 
instance()1932 WasmInstanceObject WasmExportedFunction::instance() {
1933   return shared().wasm_exported_function_data().instance();
1934 }
1935 
function_index()1936 int WasmExportedFunction::function_index() {
1937   return shared().wasm_exported_function_data().function_index();
1938 }
1939 
New(Isolate * isolate,Handle<WasmInstanceObject> instance,int func_index,int arity,Handle<CodeT> export_wrapper)1940 Handle<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 
GetWasmCallTarget()2022 Address WasmExportedFunction::GetWasmCallTarget() {
2023   return instance().GetCallTarget(function_index());
2024 }
2025 
sig()2026 const wasm::FunctionSig* WasmExportedFunction::sig() {
2027   return instance().module()->functions[function_index()].sig;
2028 }
2029 
MatchesSignature(const WasmModule * other_module,const wasm::FunctionSig * other_sig)2030 bool 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
GetDebugName(const wasm::FunctionSig * sig)2048 std::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
IsWasmJSFunction(Object object)2060 bool 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 
New(Isolate * isolate,const wasm::FunctionSig * sig,Handle<JSReceiver> callable,Handle<HeapObject> suspender)2066 Handle<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 
GetCallable() const2144 JSReceiver WasmJSFunction::GetCallable() const {
2145   return JSReceiver::cast(WasmApiFunctionRef::cast(
2146                               shared().wasm_js_function_data().internal().ref())
2147                               .callable());
2148 }
2149 
GetSuspender() const2150 HeapObject WasmJSFunction::GetSuspender() const {
2151   return WasmApiFunctionRef::cast(
2152              shared().wasm_js_function_data().internal().ref())
2153       .suspender();
2154 }
2155 
GetSignature(Zone * zone)2156 const 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 
MatchesSignatureForSuspend(const wasm::FunctionSig * sig)2168 bool 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.
MatchesSignature(const wasm::FunctionSig * sig)2189 bool 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 
GetSerializedSignature() const2205 PodArray<wasm::ValueType> WasmCapiFunction::GetSerializedSignature() const {
2206   return shared().wasm_capi_function_data().serialized_signature();
2207 }
2208 
IsWasmExternalFunction(Object object)2209 bool WasmExternalFunction::IsWasmExternalFunction(Object object) {
2210   return WasmExportedFunction::IsWasmExportedFunction(object) ||
2211          WasmJSFunction::IsWasmJSFunction(object);
2212 }
2213 
2214 // static
FromExternal(Handle<Object> external,Isolate * isolate)2215 MaybeHandle<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 
New(Isolate * isolate,int index)2228 Handle<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 
New(Isolate * isolate,std::shared_ptr<wasm::NativeModule> native_module,Handle<FixedArray> export_wrappers,Handle<HeapNumber> uses_bitset)2236 Handle<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 
2256 namespace wasm {
2257 
TypecheckJSObject(Isolate * isolate,const WasmModule * module,Handle<Object> value,ValueType expected,const char ** error_message)2258 bool 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