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