Line data Source code
1 : // Copyright 2019 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/wasm/module-instantiate.h"
6 :
7 : #include "src/asmjs/asm-js.h"
8 : #include "src/conversions-inl.h"
9 : #include "src/counters.h"
10 : #include "src/property-descriptor.h"
11 : #include "src/tracing/trace-event.h"
12 : #include "src/utils.h"
13 : #include "src/wasm/module-compiler.h"
14 : #include "src/wasm/wasm-external-refs.h"
15 : #include "src/wasm/wasm-import-wrapper-cache.h"
16 : #include "src/wasm/wasm-module.h"
17 : #include "src/wasm/wasm-objects-inl.h"
18 :
19 : #define TRACE(...) \
20 : do { \
21 : if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
22 : } while (false)
23 :
24 : namespace v8 {
25 : namespace internal {
26 : namespace wasm {
27 :
28 : namespace {
29 : byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) {
30 8402 : return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset;
31 : }
32 :
33 3126 : uint32_t EvalUint32InitExpr(Handle<WasmInstanceObject> instance,
34 : const WasmInitExpr& expr) {
35 3126 : switch (expr.kind) {
36 : case WasmInitExpr::kI32Const:
37 2414 : return expr.val.i32_const;
38 : case WasmInitExpr::kGlobalIndex: {
39 : uint32_t offset =
40 2136 : instance->module()->globals[expr.val.global_index].offset;
41 : auto raw_addr =
42 : reinterpret_cast<Address>(
43 712 : instance->untagged_globals_buffer()->backing_store()) +
44 712 : offset;
45 : return ReadLittleEndianValue<uint32_t>(raw_addr);
46 : }
47 : default:
48 0 : UNREACHABLE();
49 : }
50 : }
51 : } // namespace
52 :
53 : // A helper class to simplify instantiating a module from a module object.
54 : // It closes over the {Isolate}, the {ErrorThrower}, etc.
55 274752 : class InstanceBuilder {
56 : public:
57 : InstanceBuilder(Isolate* isolate, ErrorThrower* thrower,
58 : Handle<WasmModuleObject> module_object,
59 : MaybeHandle<JSReceiver> ffi,
60 : MaybeHandle<JSArrayBuffer> memory);
61 :
62 : // Build an instance, in all of its glory.
63 : MaybeHandle<WasmInstanceObject> Build();
64 : // Run the start function, if any.
65 : bool ExecuteStartFunction();
66 :
67 : private:
68 : // A pre-evaluated value to use in import binding.
69 : struct SanitizedImport {
70 : Handle<String> module_name;
71 : Handle<String> import_name;
72 : Handle<Object> value;
73 : };
74 :
75 : Isolate* isolate_;
76 : const WasmFeatures enabled_;
77 : const WasmModule* const module_;
78 : ErrorThrower* thrower_;
79 : Handle<WasmModuleObject> module_object_;
80 : MaybeHandle<JSReceiver> ffi_;
81 : MaybeHandle<JSArrayBuffer> memory_;
82 : Handle<JSArrayBuffer> untagged_globals_;
83 : Handle<FixedArray> tagged_globals_;
84 : std::vector<Handle<WasmExceptionObject>> exception_wrappers_;
85 : Handle<WasmExportedFunction> start_function_;
86 : std::vector<SanitizedImport> sanitized_imports_;
87 :
88 : UseTrapHandler use_trap_handler() const {
89 518928 : return module_object_->native_module()->use_trap_handler() ? kUseTrapHandler
90 259464 : : kNoTrapHandler;
91 : }
92 :
93 : // Helper routines to print out errors with imports.
94 : #define ERROR_THROWER_WITH_MESSAGE(TYPE) \
95 : void Report##TYPE(const char* error, uint32_t index, \
96 : Handle<String> module_name, Handle<String> import_name) { \
97 : thrower_->TYPE("Import #%d module=\"%s\" function=\"%s\" error: %s", \
98 : index, module_name->ToCString().get(), \
99 : import_name->ToCString().get(), error); \
100 : } \
101 : \
102 : MaybeHandle<Object> Report##TYPE(const char* error, uint32_t index, \
103 : Handle<String> module_name) { \
104 : thrower_->TYPE("Import #%d module=\"%s\" error: %s", index, \
105 : module_name->ToCString().get(), error); \
106 : return MaybeHandle<Object>(); \
107 : }
108 :
109 10686 : ERROR_THROWER_WITH_MESSAGE(LinkError)
110 1536 : ERROR_THROWER_WITH_MESSAGE(TypeError)
111 :
112 : #undef ERROR_THROWER_WITH_MESSAGE
113 :
114 : // Look up an import value in the {ffi_} object.
115 : MaybeHandle<Object> LookupImport(uint32_t index, Handle<String> module_name,
116 : Handle<String> import_name);
117 :
118 : // Look up an import value in the {ffi_} object specifically for linking an
119 : // asm.js module. This only performs non-observable lookups, which allows
120 : // falling back to JavaScript proper (and hence re-executing all lookups) if
121 : // module instantiation fails.
122 : MaybeHandle<Object> LookupImportAsm(uint32_t index,
123 : Handle<String> import_name);
124 :
125 : // Load data segments into the memory.
126 : void LoadDataSegments(Handle<WasmInstanceObject> instance);
127 :
128 : void WriteGlobalValue(const WasmGlobal& global, double value);
129 : void WriteGlobalValue(const WasmGlobal& global, int64_t num);
130 : void WriteGlobalValue(const WasmGlobal& global,
131 : Handle<WasmGlobalObject> value);
132 :
133 : void WriteGlobalAnyRef(const WasmGlobal& global, Handle<Object> value);
134 :
135 : void SanitizeImports();
136 :
137 : // Find the imported memory buffer if there is one. This is used to see if we
138 : // need to recompile with bounds checks before creating the instance.
139 : MaybeHandle<JSArrayBuffer> FindImportedMemoryBuffer() const;
140 :
141 : // Processes a single imported function.
142 : bool ProcessImportedFunction(Handle<WasmInstanceObject> instance,
143 : int import_index, int func_index,
144 : Handle<String> module_name,
145 : Handle<String> import_name,
146 : Handle<Object> value);
147 :
148 : // Process a single imported table.
149 : bool ProcessImportedTable(Handle<WasmInstanceObject> instance,
150 : int import_index, int table_index,
151 : Handle<String> module_name,
152 : Handle<String> import_name, Handle<Object> value);
153 :
154 : // Process a single imported memory.
155 : bool ProcessImportedMemory(Handle<WasmInstanceObject> instance,
156 : int import_index, Handle<String> module_name,
157 : Handle<String> import_name, Handle<Object> value);
158 :
159 : // Process a single imported global.
160 : bool ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
161 : int import_index, int global_index,
162 : Handle<String> module_name,
163 : Handle<String> import_name, Handle<Object> value);
164 :
165 : // Process a single imported WasmGlobalObject.
166 : bool ProcessImportedWasmGlobalObject(Handle<WasmInstanceObject> instance,
167 : int import_index,
168 : Handle<String> module_name,
169 : Handle<String> import_name,
170 : const WasmGlobal& global,
171 : Handle<WasmGlobalObject> global_object);
172 :
173 : // Process the imports, including functions, tables, globals, and memory, in
174 : // order, loading them from the {ffi_} object. Returns the number of imported
175 : // functions.
176 : int ProcessImports(Handle<WasmInstanceObject> instance);
177 :
178 : template <typename T>
179 : T* GetRawGlobalPtr(const WasmGlobal& global);
180 :
181 : // Process initialization of globals.
182 : void InitGlobals();
183 :
184 : // Allocate memory for a module instance as a new JSArrayBuffer.
185 : Handle<JSArrayBuffer> AllocateMemory(uint32_t initial_pages,
186 : uint32_t maximum_pages);
187 :
188 : bool NeedsWrappers() const;
189 :
190 : // Process the exports, creating wrappers for functions, tables, memories,
191 : // and globals.
192 : void ProcessExports(Handle<WasmInstanceObject> instance);
193 :
194 : void InitializeTables(Handle<WasmInstanceObject> instance);
195 :
196 : void LoadTableSegments(Handle<WasmInstanceObject> instance);
197 :
198 : // Creates new exception tags for all exceptions. Note that some tags might
199 : // already exist if they were imported, those tags will be re-used.
200 : void InitializeExceptions(Handle<WasmInstanceObject> instance);
201 : };
202 :
203 137374 : MaybeHandle<WasmInstanceObject> InstantiateToInstanceObject(
204 : Isolate* isolate, ErrorThrower* thrower,
205 : Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
206 : MaybeHandle<JSArrayBuffer> memory) {
207 274751 : InstanceBuilder builder(isolate, thrower, module_object, imports, memory);
208 137377 : auto instance = builder.Build();
209 137375 : if (!instance.is_null() && builder.ExecuteStartFunction()) {
210 134589 : return instance;
211 : }
212 : DCHECK(isolate->has_pending_exception() || thrower->error());
213 2788 : return {};
214 : }
215 :
216 137374 : InstanceBuilder::InstanceBuilder(Isolate* isolate, ErrorThrower* thrower,
217 : Handle<WasmModuleObject> module_object,
218 : MaybeHandle<JSReceiver> ffi,
219 : MaybeHandle<JSArrayBuffer> memory)
220 : : isolate_(isolate),
221 274749 : enabled_(module_object->native_module()->enabled_features()),
222 274751 : module_(module_object->module()),
223 : thrower_(thrower),
224 : module_object_(module_object),
225 : ffi_(ffi),
226 549501 : memory_(memory) {
227 137376 : sanitized_imports_.reserve(module_->import_table.size());
228 137377 : }
229 :
230 : // Build an instance, in all of its glory.
231 137376 : MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
232 412128 : TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "InstanceBuilder::Build");
233 : // Check that an imports argument was provided, if the module requires it.
234 : // No point in continuing otherwise.
235 259675 : if (!module_->import_table.empty() && ffi_.is_null()) {
236 93 : thrower_->TypeError(
237 93 : "Imports argument must be present and must be an object");
238 93 : return {};
239 : }
240 :
241 137283 : SanitizeImports();
242 137284 : if (thrower_->error()) return {};
243 :
244 : // From here on, we expect the build pipeline to run without exiting to JS.
245 273762 : DisallowJavascriptExecution no_js(isolate_);
246 : // Record build time into correct bucket, then build instance.
247 273762 : TimedHistogramScope wasm_instantiate_module_time_scope(SELECT_WASM_COUNTER(
248 136881 : isolate_->counters(), module_->origin, wasm_instantiate, module_time));
249 :
250 : //--------------------------------------------------------------------------
251 : // Allocate the memory array buffer.
252 : //--------------------------------------------------------------------------
253 : // We allocate the memory buffer before cloning or reusing the compiled module
254 : // so we will know whether we need to recompile with bounds checks.
255 136882 : uint32_t initial_pages = module_->initial_pages;
256 141746 : auto initial_pages_counter = SELECT_WASM_COUNTER(
257 : isolate_->counters(), module_->origin, wasm, min_mem_pages_count);
258 136882 : initial_pages_counter->AddSample(initial_pages);
259 136882 : if (module_->has_maximum_pages) {
260 : DCHECK_EQ(kWasmOrigin, module_->origin);
261 : auto max_pages_counter =
262 3749 : isolate_->counters()->wasm_wasm_max_mem_pages_count();
263 3749 : max_pages_counter->AddSample(module_->maximum_pages);
264 : }
265 : // Asm.js has memory_ already set at this point, so we don't want to
266 : // overwrite it.
267 136882 : if (memory_.is_null()) {
268 135642 : memory_ = FindImportedMemoryBuffer();
269 : }
270 136882 : if (!memory_.is_null()) {
271 : // Set externally passed ArrayBuffer non detachable.
272 : Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
273 : memory->set_is_detachable(false);
274 :
275 : DCHECK_IMPLIES(use_trap_handler(), module_->origin == kAsmJsOrigin ||
276 : memory->is_wasm_memory() ||
277 : memory->backing_store() == nullptr);
278 258747 : } else if (initial_pages > 0 || use_trap_handler()) {
279 : // We need to unconditionally create a guard region if using trap handlers,
280 : // even when the size is zero to prevent null-dereference issues
281 : // (e.g. https://crbug.com/769637).
282 : // Allocate memory if the initial size is more than 0 pages.
283 131223 : memory_ = AllocateMemory(initial_pages, module_->maximum_pages);
284 131223 : if (memory_.is_null()) {
285 : // failed to allocate memory
286 : DCHECK(isolate_->has_pending_exception() || thrower_->error());
287 16 : return {};
288 : }
289 : }
290 :
291 : //--------------------------------------------------------------------------
292 : // Recompile module if using trap handlers but could not get guarded memory
293 : //--------------------------------------------------------------------------
294 268868 : if (module_->origin == kWasmOrigin && use_trap_handler()) {
295 : // Make sure the memory has suitable guard regions.
296 : WasmMemoryTracker* const memory_tracker =
297 131941 : isolate_->wasm_engine()->memory_tracker();
298 :
299 131941 : if (!memory_tracker->HasFullGuardRegions(
300 : memory_.ToHandleChecked()->backing_store())) {
301 38 : if (!FLAG_wasm_trap_handler_fallback) {
302 0 : thrower_->LinkError(
303 : "Provided memory is lacking guard regions but fallback was "
304 0 : "disabled.");
305 0 : return {};
306 : }
307 :
308 : TRACE("Recompiling module without bounds checks\n");
309 76 : ErrorThrower thrower(isolate_, "recompile");
310 38 : auto native_module = module_object_->native_module();
311 38 : CompileNativeModuleWithExplicitBoundsChecks(isolate_, &thrower, module_,
312 38 : native_module);
313 38 : if (thrower.error()) {
314 0 : return {};
315 : }
316 : DCHECK(!native_module->use_trap_handler());
317 : }
318 : }
319 :
320 : //--------------------------------------------------------------------------
321 : // Create the WebAssembly.Instance object.
322 : //--------------------------------------------------------------------------
323 136866 : NativeModule* native_module = module_object_->native_module();
324 : TRACE("New module instantiation for %p\n", native_module);
325 : Handle<WasmInstanceObject> instance =
326 136866 : WasmInstanceObject::New(isolate_, module_object_);
327 273729 : NativeModuleModificationScope native_modification_scope(native_module);
328 :
329 : //--------------------------------------------------------------------------
330 : // Set up the globals for the new instance.
331 : //--------------------------------------------------------------------------
332 136864 : uint32_t untagged_globals_buffer_size = module_->untagged_globals_buffer_size;
333 136864 : if (untagged_globals_buffer_size > 0) {
334 6534 : void* backing_store = isolate_->array_buffer_allocator()->Allocate(
335 6534 : untagged_globals_buffer_size);
336 3267 : if (backing_store == nullptr) {
337 0 : thrower_->RangeError("Out of memory: wasm globals");
338 0 : return {};
339 : }
340 3267 : untagged_globals_ = isolate_->factory()->NewJSArrayBuffer(
341 3267 : SharedFlag::kNotShared, AllocationType::kOld);
342 : constexpr bool is_external = false;
343 : constexpr bool is_wasm_memory = false;
344 3267 : JSArrayBuffer::Setup(untagged_globals_, isolate_, is_external,
345 : backing_store, untagged_globals_buffer_size,
346 3267 : SharedFlag::kNotShared, is_wasm_memory);
347 3267 : if (untagged_globals_.is_null()) {
348 0 : thrower_->RangeError("Out of memory: wasm globals");
349 0 : return {};
350 : }
351 : instance->set_globals_start(
352 : reinterpret_cast<byte*>(untagged_globals_->backing_store()));
353 3267 : instance->set_untagged_globals_buffer(*untagged_globals_);
354 : }
355 :
356 136864 : uint32_t tagged_globals_buffer_size = module_->tagged_globals_buffer_size;
357 136864 : if (tagged_globals_buffer_size > 0) {
358 400 : tagged_globals_ = isolate_->factory()->NewFixedArray(
359 800 : static_cast<int>(tagged_globals_buffer_size));
360 400 : instance->set_tagged_globals_buffer(*tagged_globals_);
361 : }
362 :
363 : //--------------------------------------------------------------------------
364 : // Set up the array of references to imported globals' array buffers.
365 : //--------------------------------------------------------------------------
366 136864 : if (module_->num_imported_mutable_globals > 0) {
367 : // TODO(binji): This allocates one slot for each mutable global, which is
368 : // more than required if multiple globals are imported from the same
369 : // module.
370 264 : Handle<FixedArray> buffers_array = isolate_->factory()->NewFixedArray(
371 528 : module_->num_imported_mutable_globals, AllocationType::kOld);
372 264 : instance->set_imported_mutable_globals_buffers(*buffers_array);
373 : }
374 :
375 : //--------------------------------------------------------------------------
376 : // Set up the exception table used for exception tag checks.
377 : //--------------------------------------------------------------------------
378 273728 : int exceptions_count = static_cast<int>(module_->exceptions.size());
379 136864 : if (exceptions_count > 0) {
380 616 : Handle<FixedArray> exception_table = isolate_->factory()->NewFixedArray(
381 616 : exceptions_count, AllocationType::kOld);
382 616 : instance->set_exceptions_table(*exception_table);
383 616 : exception_wrappers_.resize(exceptions_count);
384 : }
385 :
386 : //--------------------------------------------------------------------------
387 : // Set up table storage space.
388 : //--------------------------------------------------------------------------
389 273728 : int table_count = static_cast<int>(module_->tables.size());
390 136864 : Handle<FixedArray> tables = isolate_->factory()->NewFixedArray(table_count);
391 138232 : for (int i = module_->num_imported_tables; i < table_count; i++) {
392 1369 : const WasmTable& table = module_->tables[i];
393 : Handle<WasmTableObject> table_obj = WasmTableObject::New(
394 2738 : isolate_, table.type, table.initial_size, table.has_maximum_size,
395 4107 : table.maximum_size, nullptr);
396 2738 : tables->set(i, *table_obj);
397 : }
398 136863 : instance->set_tables(*tables);
399 :
400 : //--------------------------------------------------------------------------
401 : // Process the imports for the module.
402 : //--------------------------------------------------------------------------
403 136864 : int num_imported_functions = ProcessImports(instance);
404 136866 : if (num_imported_functions < 0) return {};
405 :
406 : //--------------------------------------------------------------------------
407 : // Process the initialization for the module's globals.
408 : //--------------------------------------------------------------------------
409 134905 : InitGlobals();
410 :
411 : //--------------------------------------------------------------------------
412 : // Initialize the indirect tables.
413 : //--------------------------------------------------------------------------
414 134904 : if (table_count > 0) {
415 2353 : InitializeTables(instance);
416 : }
417 :
418 : //--------------------------------------------------------------------------
419 : // Initialize the exceptions table.
420 : //--------------------------------------------------------------------------
421 134905 : if (exceptions_count > 0) {
422 576 : InitializeExceptions(instance);
423 : }
424 :
425 : //--------------------------------------------------------------------------
426 : // Create the WebAssembly.Memory object.
427 : //--------------------------------------------------------------------------
428 134905 : if (module_->has_memory) {
429 13507 : if (!instance->has_memory_object()) {
430 : // No memory object exists. Create one.
431 : Handle<WasmMemoryObject> memory_object = WasmMemoryObject::New(
432 : isolate_, memory_,
433 9238 : module_->maximum_pages != 0 ? module_->maximum_pages : -1);
434 9238 : instance->set_memory_object(*memory_object);
435 : }
436 :
437 : // Add the instance object to the list of instances for this memory.
438 13507 : Handle<WasmMemoryObject> memory_object(instance->memory_object(), isolate_);
439 13505 : WasmMemoryObject::AddInstance(isolate_, memory_object, instance);
440 :
441 13507 : if (!memory_.is_null()) {
442 : // Double-check the {memory} array buffer matches the instance.
443 : Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
444 13495 : CHECK_EQ(instance->memory_size(), memory->byte_length());
445 13495 : CHECK_EQ(instance->memory_start(), memory->backing_store());
446 : }
447 : }
448 :
449 : // The bulk memory proposal changes the MVP behavior here; the segments are
450 : // written as if `memory.init` and `table.init` are executed directly, and
451 : // not bounds checked ahead of time.
452 134905 : if (!enabled_.bulk_memory) {
453 : //--------------------------------------------------------------------------
454 : // Check that indirect function table segments are within bounds.
455 : //--------------------------------------------------------------------------
456 4851 : for (const WasmElemSegment& elem_segment : module_->elem_segments) {
457 101 : if (!elem_segment.active) continue;
458 : DCHECK_LT(elem_segment.table_index, table_count);
459 101 : uint32_t base = EvalUint32InitExpr(instance, elem_segment.offset);
460 : // Because of imported tables, {table_size} has to come from the table
461 : // object itself.
462 : auto table_object = handle(WasmTableObject::cast(instance->tables()->get(
463 101 : elem_segment.table_index)),
464 202 : isolate_);
465 101 : size_t table_size = table_object->elements()->length();
466 202 : if (!IsInBounds(base, elem_segment.entries.size(), table_size)) {
467 0 : thrower_->LinkError("table initializer is out of bounds");
468 0 : return {};
469 : }
470 : }
471 :
472 : //--------------------------------------------------------------------------
473 : // Check that memory segments are within bounds.
474 : //--------------------------------------------------------------------------
475 4851 : for (const WasmDataSegment& seg : module_->data_segments) {
476 0 : if (!seg.active) continue;
477 0 : uint32_t base = EvalUint32InitExpr(instance, seg.dest_addr);
478 0 : if (!IsInBounds(base, seg.source.length(), instance->memory_size())) {
479 0 : thrower_->LinkError("data segment is out of bounds");
480 0 : return {};
481 : }
482 : }
483 : }
484 :
485 : //--------------------------------------------------------------------------
486 : // Set up the exports object for the new instance.
487 : //--------------------------------------------------------------------------
488 134905 : ProcessExports(instance);
489 134905 : if (thrower_->error()) return {};
490 :
491 : //--------------------------------------------------------------------------
492 : // Initialize the indirect function tables.
493 : //--------------------------------------------------------------------------
494 134905 : if (table_count > 0) {
495 2353 : LoadTableSegments(instance);
496 2353 : if (thrower_->error()) return {};
497 : }
498 :
499 : //--------------------------------------------------------------------------
500 : // Initialize the memory by loading data segments.
501 : //--------------------------------------------------------------------------
502 269570 : if (module_->data_segments.size() > 0) {
503 724 : LoadDataSegments(instance);
504 724 : if (thrower_->error()) return {};
505 : }
506 :
507 : //--------------------------------------------------------------------------
508 : // Debugging support.
509 : //--------------------------------------------------------------------------
510 : // Set all breakpoints that were set on the shared module.
511 134657 : WasmModuleObject::SetBreakpointsOnNewInstance(module_object_, instance);
512 :
513 : //--------------------------------------------------------------------------
514 : // Create a wrapper for the start function.
515 : //--------------------------------------------------------------------------
516 134655 : if (module_->start_function_index >= 0) {
517 : int start_index = module_->start_function_index;
518 5027 : auto& function = module_->functions[start_index];
519 10054 : Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper(
520 5027 : isolate_, function.sig, function.imported)
521 5027 : .ToHandleChecked();
522 : // TODO(clemensh): Don't generate an exported function for the start
523 : // function. Use CWasmEntry instead.
524 : start_function_ = WasmExportedFunction::New(
525 : isolate_, instance, MaybeHandle<String>(), start_index,
526 5027 : static_cast<int>(function.sig->parameter_count()), wrapper_code);
527 : }
528 :
529 : DCHECK(!isolate_->has_pending_exception());
530 : TRACE("Successfully built instance for module %p\n",
531 : module_object_->native_module());
532 134655 : return instance;
533 : }
534 :
535 134655 : bool InstanceBuilder::ExecuteStartFunction() {
536 403965 : TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
537 : "InstanceBuilder::ExecuteStartFunction");
538 134655 : if (start_function_.is_null()) return true; // No start function.
539 :
540 5027 : HandleScope scope(isolate_);
541 : // Call the JS function.
542 5027 : Handle<Object> undefined = isolate_->factory()->undefined_value();
543 : MaybeHandle<Object> retval =
544 5027 : Execution::Call(isolate_, start_function_, undefined, 0, nullptr);
545 :
546 5027 : if (retval.is_null()) {
547 : DCHECK(isolate_->has_pending_exception());
548 : return false;
549 : }
550 4959 : return true;
551 : }
552 :
553 : // Look up an import value in the {ffi_} object.
554 123778 : MaybeHandle<Object> InstanceBuilder::LookupImport(uint32_t index,
555 : Handle<String> module_name,
556 :
557 : Handle<String> import_name) {
558 : // We pre-validated in the js-api layer that the ffi object is present, and
559 : // a JSObject, if the module has imports.
560 : DCHECK(!ffi_.is_null());
561 : // Look up the module first.
562 : MaybeHandle<Object> result = Object::GetPropertyOrElement(
563 123778 : isolate_, ffi_.ToHandleChecked(), module_name);
564 123778 : if (result.is_null()) {
565 24 : return ReportTypeError("module not found", index, module_name);
566 : }
567 :
568 : Handle<Object> module = result.ToHandleChecked();
569 :
570 : // Look up the value in the module.
571 123754 : if (!module->IsJSReceiver()) {
572 : return ReportTypeError("module is not an object or function", index,
573 360 : module_name);
574 : }
575 :
576 123394 : result = Object::GetPropertyOrElement(isolate_, module, import_name);
577 123397 : if (result.is_null()) {
578 0 : ReportLinkError("import not found", index, module_name, import_name);
579 0 : return MaybeHandle<JSFunction>();
580 : }
581 :
582 123397 : return result;
583 : }
584 :
585 : // Look up an import value in the {ffi_} object specifically for linking an
586 : // asm.js module. This only performs non-observable lookups, which allows
587 : // falling back to JavaScript proper (and hence re-executing all lookups) if
588 : // module instantiation fails.
589 4787 : MaybeHandle<Object> InstanceBuilder::LookupImportAsm(
590 : uint32_t index, Handle<String> import_name) {
591 : // Check that a foreign function interface object was provided.
592 4787 : if (ffi_.is_null()) {
593 0 : return ReportLinkError("missing imports object", index, import_name);
594 : }
595 :
596 : // Perform lookup of the given {import_name} without causing any observable
597 : // side-effect. We only accept accesses that resolve to data properties,
598 : // which is indicated by the asm.js spec in section 7 ("Linking") as well.
599 : Handle<Object> result;
600 : LookupIterator it = LookupIterator::PropertyOrElement(
601 4787 : isolate_, ffi_.ToHandleChecked(), import_name);
602 : switch (it.state()) {
603 : case LookupIterator::ACCESS_CHECK:
604 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
605 : case LookupIterator::INTERCEPTOR:
606 : case LookupIterator::JSPROXY:
607 : case LookupIterator::ACCESSOR:
608 : case LookupIterator::TRANSITION:
609 18 : return ReportLinkError("not a data property", index, import_name);
610 : case LookupIterator::NOT_FOUND:
611 : // Accepting missing properties as undefined does not cause any
612 : // observable difference from JavaScript semantics, we are lenient.
613 72 : result = isolate_->factory()->undefined_value();
614 72 : break;
615 : case LookupIterator::DATA:
616 4697 : result = it.GetDataValue();
617 4697 : break;
618 : }
619 :
620 4769 : return result;
621 : }
622 :
623 : // Load data segments into the memory.
624 724 : void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
625 : Vector<const uint8_t> wire_bytes =
626 1448 : module_object_->native_module()->wire_bytes();
627 724 : for (const WasmDataSegment& segment : module_->data_segments) {
628 : uint32_t size = segment.source.length();
629 :
630 964 : if (enabled_.bulk_memory) {
631 : // Passive segments are not copied during instantiation.
632 964 : if (!segment.active) continue;
633 :
634 916 : uint32_t dest_offset = EvalUint32InitExpr(instance, segment.dest_addr);
635 916 : bool ok = ClampToBounds(dest_offset, &size,
636 : static_cast<uint32_t>(instance->memory_size()));
637 : Address dest_addr =
638 916 : reinterpret_cast<Address>(instance->memory_start()) + dest_offset;
639 916 : Address src_addr = reinterpret_cast<Address>(wire_bytes.start()) +
640 916 : segment.source.offset();
641 916 : memory_copy_wrapper(dest_addr, src_addr, size);
642 916 : if (!ok) {
643 128 : thrower_->LinkError("data segment is out of bounds");
644 : return;
645 : }
646 : } else {
647 : DCHECK(segment.active);
648 : // Segments of size == 0 are just nops.
649 0 : if (size == 0) continue;
650 :
651 0 : uint32_t dest_offset = EvalUint32InitExpr(instance, segment.dest_addr);
652 : DCHECK(IsInBounds(dest_offset, size, instance->memory_size()));
653 0 : byte* dest = instance->memory_start() + dest_offset;
654 0 : const byte* src = wire_bytes.start() + segment.source.offset();
655 0 : memcpy(dest, src, size);
656 : }
657 : }
658 : }
659 :
660 2219 : void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, double num) {
661 : TRACE("init [globals_start=%p + %u] = %lf, type = %s\n",
662 : reinterpret_cast<void*>(raw_buffer_ptr(untagged_globals_, 0)),
663 : global.offset, num, ValueTypes::TypeName(global.type));
664 2219 : switch (global.type) {
665 : case kWasmI32:
666 1807 : WriteLittleEndianValue<int32_t>(GetRawGlobalPtr<int32_t>(global),
667 : DoubleToInt32(num));
668 : break;
669 : case kWasmI64:
670 : // The Wasm-BigInt proposal currently says that i64 globals may
671 : // only be initialized with BigInts. See:
672 : // https://github.com/WebAssembly/JS-BigInt-integration/issues/12
673 0 : UNREACHABLE();
674 : break;
675 : case kWasmF32:
676 40 : WriteLittleEndianValue<float>(GetRawGlobalPtr<float>(global),
677 : DoubleToFloat32(num));
678 : break;
679 : case kWasmF64:
680 372 : WriteLittleEndianValue<double>(GetRawGlobalPtr<double>(global), num);
681 : break;
682 : default:
683 0 : UNREACHABLE();
684 : }
685 2219 : }
686 :
687 24 : void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, int64_t num) {
688 : TRACE("init [globals_start=%p + %u] = %" PRId64 ", type = %s\n",
689 : reinterpret_cast<void*>(raw_buffer_ptr(untagged_globals_, 0)),
690 : global.offset, num, ValueTypes::TypeName(global.type));
691 : DCHECK_EQ(kWasmI64, global.type);
692 24 : WriteLittleEndianValue<int64_t>(GetRawGlobalPtr<int64_t>(global), num);
693 24 : }
694 :
695 40 : void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global,
696 : Handle<WasmGlobalObject> value) {
697 : TRACE("init [globals_start=%p + %u] = ",
698 : reinterpret_cast<void*>(raw_buffer_ptr(untagged_globals_, 0)),
699 : global.offset);
700 40 : switch (global.type) {
701 : case kWasmI32: {
702 : int32_t num = value->GetI32();
703 24 : WriteLittleEndianValue<int32_t>(GetRawGlobalPtr<int32_t>(global), num);
704 : TRACE("%d", num);
705 : break;
706 : }
707 : case kWasmI64: {
708 : int64_t num = value->GetI64();
709 8 : WriteLittleEndianValue<int64_t>(GetRawGlobalPtr<int64_t>(global), num);
710 : TRACE("%" PRId64, num);
711 : break;
712 : }
713 : case kWasmF32: {
714 : float num = value->GetF32();
715 8 : WriteLittleEndianValue<float>(GetRawGlobalPtr<float>(global), num);
716 : TRACE("%f", num);
717 : break;
718 : }
719 : case kWasmF64: {
720 : double num = value->GetF64();
721 0 : WriteLittleEndianValue<double>(GetRawGlobalPtr<double>(global), num);
722 : TRACE("%lf", num);
723 : break;
724 : }
725 : default:
726 0 : UNREACHABLE();
727 : }
728 : TRACE(", type = %s (from WebAssembly.Global)\n",
729 : ValueTypes::TypeName(global.type));
730 40 : }
731 :
732 0 : void InstanceBuilder::WriteGlobalAnyRef(const WasmGlobal& global,
733 : Handle<Object> value) {
734 320 : tagged_globals_->set(global.offset, *value, UPDATE_WRITE_BARRIER);
735 0 : }
736 :
737 137280 : void InstanceBuilder::SanitizeImports() {
738 : Vector<const uint8_t> wire_bytes =
739 274564 : module_object_->native_module()->wire_bytes();
740 659066 : for (size_t index = 0; index < module_->import_table.size(); ++index) {
741 : const WasmImport& import = module_->import_table[index];
742 :
743 : Handle<String> module_name;
744 : MaybeHandle<String> maybe_module_name =
745 : WasmModuleObject::ExtractUtf8StringFromModuleBytes(isolate_, wire_bytes,
746 128568 : import.module_name);
747 128568 : if (!maybe_module_name.ToHandle(&module_name)) {
748 0 : thrower_->LinkError("Could not resolve module name for import %zu",
749 0 : index);
750 0 : return;
751 : }
752 :
753 : Handle<String> import_name;
754 : MaybeHandle<String> maybe_import_name =
755 : WasmModuleObject::ExtractUtf8StringFromModuleBytes(isolate_, wire_bytes,
756 128568 : import.field_name);
757 128567 : if (!maybe_import_name.ToHandle(&import_name)) {
758 0 : thrower_->LinkError("Could not resolve import name for import %zu",
759 0 : index);
760 0 : return;
761 : }
762 :
763 : int int_index = static_cast<int>(index);
764 : MaybeHandle<Object> result =
765 128567 : module_->origin == kAsmJsOrigin
766 4787 : ? LookupImportAsm(int_index, import_name)
767 133354 : : LookupImport(int_index, module_name, import_name);
768 128568 : if (thrower_->error()) {
769 402 : thrower_->LinkError("Could not find value for import %zu", index);
770 402 : return;
771 : }
772 : Handle<Object> value = result.ToHandleChecked();
773 256332 : sanitized_imports_.push_back({module_name, import_name, value});
774 : }
775 : }
776 :
777 135642 : MaybeHandle<JSArrayBuffer> InstanceBuilder::FindImportedMemoryBuffer() const {
778 : DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
779 629283 : for (size_t index = 0; index < module_->import_table.size(); index++) {
780 : const WasmImport& import = module_->import_table[index];
781 :
782 124102 : if (import.kind == kExternalMemory) {
783 : const auto& value = sanitized_imports_[index].value;
784 4769 : if (!value->IsWasmMemoryObject()) {
785 412 : return {};
786 : }
787 : auto memory = Handle<WasmMemoryObject>::cast(value);
788 4357 : Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate_);
789 4357 : return buffer;
790 : }
791 : }
792 130873 : return {};
793 : }
794 :
795 118437 : bool InstanceBuilder::ProcessImportedFunction(
796 : Handle<WasmInstanceObject> instance, int import_index, int func_index,
797 : Handle<String> module_name, Handle<String> import_name,
798 : Handle<Object> value) {
799 : // Function imports must be callable.
800 118437 : if (!value->IsCallable()) {
801 400 : ReportLinkError("function import requires a callable", import_index,
802 400 : module_name, import_name);
803 400 : return false;
804 : }
805 118037 : auto js_receiver = Handle<JSReceiver>::cast(value);
806 236074 : FunctionSig* expected_sig = module_->functions[func_index].sig;
807 118037 : auto kind = compiler::GetWasmImportCallKind(js_receiver, expected_sig,
808 236074 : enabled_.bigint);
809 118037 : switch (kind) {
810 : case compiler::WasmImportCallKind::kLinkError:
811 152 : ReportLinkError("imported function does not match the expected type",
812 152 : import_index, module_name, import_name);
813 152 : return false;
814 : case compiler::WasmImportCallKind::kWasmToWasm: {
815 : // The imported function is a WASM function from another instance.
816 : auto imported_function = Handle<WasmExportedFunction>::cast(value);
817 : Handle<WasmInstanceObject> imported_instance(
818 321192 : imported_function->instance(), isolate_);
819 : // The import reference is the instance object itself.
820 107064 : Address imported_target = imported_function->GetWasmCallTarget();
821 : ImportedFunctionEntry entry(instance, func_index);
822 107064 : entry.SetWasmToWasm(*imported_instance, imported_target);
823 : break;
824 : }
825 : default: {
826 : // The imported function is a callable.
827 10821 : NativeModule* native_module = instance->module_object()->native_module();
828 : WasmCode* wasm_code = native_module->import_wrapper_cache()->GetOrCompile(
829 21642 : isolate_->wasm_engine(), isolate_->counters(), kind, expected_sig);
830 : ImportedFunctionEntry entry(instance, func_index);
831 10821 : if (wasm_code->kind() == WasmCode::kWasmToJsWrapper) {
832 : // Wasm to JS wrappers are treated specially in the import table.
833 10597 : entry.SetWasmToJs(isolate_, js_receiver, wasm_code);
834 : } else {
835 : // Wasm math intrinsics are compiled as regular Wasm functions.
836 : DCHECK(kind >= compiler::WasmImportCallKind::kFirstMathIntrinsic &&
837 : kind <= compiler::WasmImportCallKind::kLastMathIntrinsic);
838 224 : entry.SetWasmToWasm(*instance, wasm_code->instruction_start());
839 : }
840 : break;
841 : }
842 : }
843 : return true;
844 : }
845 :
846 1516 : bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance,
847 : int import_index, int table_index,
848 : Handle<String> module_name,
849 : Handle<String> import_name,
850 : Handle<Object> value) {
851 1516 : if (!value->IsWasmTableObject()) {
852 336 : ReportLinkError("table import requires a WebAssembly.Table", import_index,
853 336 : module_name, import_name);
854 336 : return false;
855 : }
856 1180 : const WasmTable& table = module_->tables[table_index];
857 :
858 1180 : instance->tables()->set(table_index, *value);
859 : auto table_object = Handle<WasmTableObject>::cast(value);
860 :
861 : int imported_table_size = table_object->elements().length();
862 1180 : if (imported_table_size < static_cast<int>(table.initial_size)) {
863 40 : thrower_->LinkError("table import %d is smaller than initial %d, got %u",
864 40 : import_index, table.initial_size, imported_table_size);
865 40 : return false;
866 : }
867 :
868 1140 : if (table.has_maximum_size) {
869 1728 : if (table_object->maximum_length()->IsUndefined(isolate_)) {
870 16 : thrower_->LinkError("table import %d has no maximum length, expected %d",
871 32 : import_index, table.maximum_size);
872 16 : return false;
873 : }
874 848 : int64_t imported_maximum_size = table_object->maximum_length()->Number();
875 848 : if (imported_maximum_size < 0) {
876 0 : thrower_->LinkError("table import %d has no maximum length, expected %d",
877 0 : import_index, table.maximum_size);
878 0 : return false;
879 : }
880 848 : if (imported_maximum_size > table.maximum_size) {
881 48 : thrower_->LinkError("table import %d has a larger maximum size %" PRIx64
882 : " than the module's declared maximum %u",
883 : import_index, imported_maximum_size,
884 48 : table.maximum_size);
885 48 : return false;
886 : }
887 : }
888 :
889 : // Allocate a new dispatch table.
890 1076 : if (!instance->has_indirect_function_table()) {
891 1052 : WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
892 1052 : instance, imported_table_size);
893 : }
894 : // Initialize the dispatch table with the (foreign) JS functions
895 : // that are already in the table.
896 4220068 : for (int i = 0; i < imported_table_size; ++i) {
897 : bool is_valid;
898 : bool is_null;
899 2109496 : MaybeHandle<WasmInstanceObject> maybe_target_instance;
900 : int function_index;
901 2109496 : WasmTableObject::GetFunctionTableEntry(isolate_, table_object, i, &is_valid,
902 : &is_null, &maybe_target_instance,
903 2109496 : &function_index);
904 2109496 : if (!is_valid) {
905 0 : thrower_->LinkError("table import %d[%d] is not a wasm function",
906 0 : import_index, i);
907 0 : return false;
908 : }
909 4216324 : if (is_null) continue;
910 :
911 : Handle<WasmInstanceObject> target_instance =
912 : maybe_target_instance.ToHandleChecked();
913 5336 : FunctionSig* sig = target_instance->module_object()
914 : ->module()
915 2668 : ->functions[function_index]
916 2668 : .sig;
917 :
918 : // Look up the signature's canonical id. If there is no canonical
919 : // id, then the signature does not appear at all in this module,
920 : // so putting {-1} in the table will cause checks to always fail.
921 : IndirectFunctionTableEntry(instance, i)
922 5336 : .Set(module_->signature_map.Find(*sig), target_instance,
923 5336 : function_index);
924 : }
925 : return true;
926 : }
927 :
928 4759 : bool InstanceBuilder::ProcessImportedMemory(Handle<WasmInstanceObject> instance,
929 : int import_index,
930 : Handle<String> module_name,
931 : Handle<String> import_name,
932 : Handle<Object> value) {
933 : // Validation should have failed if more than one memory object was
934 : // provided.
935 : DCHECK(!instance->has_memory_object());
936 4759 : if (!value->IsWasmMemoryObject()) {
937 404 : ReportLinkError("memory import must be a WebAssembly.Memory object",
938 404 : import_index, module_name, import_name);
939 404 : return false;
940 : }
941 : auto memory = Handle<WasmMemoryObject>::cast(value);
942 4355 : instance->set_memory_object(*memory);
943 4355 : Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate_);
944 : // memory_ should have already been assigned in Build().
945 : DCHECK_EQ(*memory_.ToHandleChecked(), *buffer);
946 : uint32_t imported_cur_pages =
947 4357 : static_cast<uint32_t>(buffer->byte_length() / kWasmPageSize);
948 4357 : if (imported_cur_pages < module_->initial_pages) {
949 24 : thrower_->LinkError("memory import %d is smaller than initial %u, got %u",
950 : import_index, module_->initial_pages,
951 24 : imported_cur_pages);
952 24 : return false;
953 : }
954 : int32_t imported_maximum_pages = memory->maximum_pages();
955 4333 : if (module_->has_maximum_pages) {
956 1454 : if (imported_maximum_pages < 0) {
957 8 : thrower_->LinkError(
958 : "memory import %d has no maximum limit, expected at most %u",
959 8 : import_index, imported_maximum_pages);
960 8 : return false;
961 : }
962 1446 : if (static_cast<uint32_t>(imported_maximum_pages) >
963 1446 : module_->maximum_pages) {
964 40 : thrower_->LinkError(
965 : "memory import %d has a larger maximum size %u than the "
966 : "module's declared maximum %u",
967 40 : import_index, imported_maximum_pages, module_->maximum_pages);
968 40 : return false;
969 : }
970 : }
971 8570 : if (module_->has_shared_memory != buffer->is_shared()) {
972 16 : thrower_->LinkError(
973 : "mismatch in shared state of memory, declared = %d, imported = %d",
974 16 : module_->has_shared_memory, buffer->is_shared());
975 16 : return false;
976 : }
977 :
978 : return true;
979 : }
980 :
981 436 : bool InstanceBuilder::ProcessImportedWasmGlobalObject(
982 : Handle<WasmInstanceObject> instance, int import_index,
983 : Handle<String> module_name, Handle<String> import_name,
984 : const WasmGlobal& global, Handle<WasmGlobalObject> global_object) {
985 436 : if (global_object->type() != global.type) {
986 8 : ReportLinkError("imported global does not match the expected type",
987 8 : import_index, module_name, import_name);
988 8 : return false;
989 : }
990 428 : if (global_object->is_mutable() != global.mutability) {
991 24 : ReportLinkError("imported global does not match the expected mutability",
992 24 : import_index, module_name, import_name);
993 24 : return false;
994 : }
995 404 : if (global.mutability) {
996 : DCHECK_LT(global.index, module_->num_imported_mutable_globals);
997 : Handle<Object> buffer;
998 : Address address_or_offset;
999 364 : if (ValueTypes::IsReferenceType(global.type)) {
1000 : static_assert(sizeof(global_object->offset()) <= sizeof(Address),
1001 : "The offset into the globals buffer does not fit into "
1002 : "the imported_mutable_globals array");
1003 224 : buffer = handle(global_object->tagged_buffer(), isolate_);
1004 : // For anyref globals we use a relative offset, not an absolute address.
1005 224 : address_or_offset = static_cast<Address>(global_object->offset());
1006 : } else {
1007 140 : buffer = handle(global_object->untagged_buffer(), isolate_);
1008 : // It is safe in this case to store the raw pointer to the buffer
1009 : // since the backing store of the JSArrayBuffer will not be
1010 : // relocated.
1011 : address_or_offset = reinterpret_cast<Address>(raw_buffer_ptr(
1012 140 : Handle<JSArrayBuffer>::cast(buffer), global_object->offset()));
1013 : }
1014 728 : instance->imported_mutable_globals_buffers()->set(global.index, *buffer);
1015 364 : instance->imported_mutable_globals()[global.index] = address_or_offset;
1016 : return true;
1017 : }
1018 :
1019 40 : WriteGlobalValue(global, global_object);
1020 40 : return true;
1021 : }
1022 :
1023 3244 : bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
1024 : int import_index, int global_index,
1025 : Handle<String> module_name,
1026 : Handle<String> import_name,
1027 : Handle<Object> value) {
1028 : // Immutable global imports are converted to numbers and written into
1029 : // the {untagged_globals_} array buffer.
1030 : //
1031 : // Mutable global imports instead have their backing array buffers
1032 : // referenced by this instance, and store the address of the imported
1033 : // global in the {imported_mutable_globals_} array.
1034 3244 : const WasmGlobal& global = module_->globals[global_index];
1035 :
1036 : // The mutable-global proposal allows importing i64 values, but only if
1037 : // they are passed as a WebAssembly.Global object.
1038 : //
1039 : // However, the bigint proposal allows importing constant i64 values,
1040 : // as non WebAssembly.Global object.
1041 3292 : if (global.type == kWasmI64 && !enabled_.bigint &&
1042 : !value->IsWasmGlobalObject()) {
1043 32 : ReportLinkError("global import cannot have type i64", import_index,
1044 32 : module_name, import_name);
1045 32 : return false;
1046 : }
1047 3212 : if (module_->origin == kAsmJsOrigin) {
1048 : // Accepting {JSFunction} on top of just primitive values here is a
1049 : // workaround to support legacy asm.js code with broken binding. Note
1050 : // that using {NaN} (or Smi::kZero) here is what using the observable
1051 : // conversion via {ToPrimitive} would produce as well.
1052 : // TODO(mstarzinger): Still observable if Function.prototype.valueOf
1053 : // or friends are patched, we might need to check for that as well.
1054 1208 : if (value->IsJSFunction()) value = isolate_->factory()->nan_value();
1055 2407 : if (value->IsPrimitive() && !value->IsSymbol()) {
1056 1195 : if (global.type == kWasmI32) {
1057 855 : value = Object::ToInt32(isolate_, value).ToHandleChecked();
1058 : } else {
1059 680 : value = Object::ToNumber(isolate_, value).ToHandleChecked();
1060 : }
1061 : }
1062 : }
1063 :
1064 3212 : if (value->IsWasmGlobalObject()) {
1065 436 : auto global_object = Handle<WasmGlobalObject>::cast(value);
1066 : return ProcessImportedWasmGlobalObject(instance, import_index, module_name,
1067 436 : import_name, global, global_object);
1068 : }
1069 :
1070 2776 : if (global.mutability) {
1071 16 : ReportLinkError(
1072 : "imported mutable global must be a WebAssembly.Global object",
1073 16 : import_index, module_name, import_name);
1074 16 : return false;
1075 : }
1076 :
1077 5520 : if (ValueTypes::IsReferenceType(global.type)) {
1078 : // There shouldn't be any null-ref globals.
1079 : DCHECK_NE(ValueType::kWasmNullRef, global.type);
1080 176 : if (global.type == ValueType::kWasmAnyFunc) {
1081 128 : if (!value->IsNull(isolate_) &&
1082 32 : !WasmExportedFunction::IsWasmExportedFunction(*value)) {
1083 16 : ReportLinkError(
1084 : "imported anyfunc global must be null or an exported function",
1085 16 : import_index, module_name, import_name);
1086 16 : return false;
1087 : }
1088 : }
1089 : WriteGlobalAnyRef(global, value);
1090 160 : return true;
1091 : }
1092 :
1093 2584 : if (value->IsNumber() && global.type != kWasmI64) {
1094 2219 : WriteGlobalValue(global, value->Number());
1095 2219 : return true;
1096 : }
1097 :
1098 365 : if (enabled_.bigint && global.type == kWasmI64) {
1099 : Handle<BigInt> bigint;
1100 :
1101 48 : if (!BigInt::FromObject(isolate_, value).ToHandle(&bigint)) {
1102 : return false;
1103 : }
1104 24 : WriteGlobalValue(global, bigint->AsInt64());
1105 24 : return true;
1106 : }
1107 :
1108 341 : ReportLinkError("global import must be a number or WebAssembly.Global object",
1109 341 : import_index, module_name, import_name);
1110 341 : return false;
1111 : }
1112 :
1113 : // Process the imports, including functions, tables, globals, and memory, in
1114 : // order, loading them from the {ffi_} object. Returns the number of imported
1115 : // functions.
1116 136863 : int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
1117 : int num_imported_functions = 0;
1118 : int num_imported_tables = 0;
1119 :
1120 : DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
1121 273726 : int num_imports = static_cast<int>(module_->import_table.size());
1122 389033 : for (int index = 0; index < num_imports; ++index) {
1123 128043 : const WasmImport& import = module_->import_table[index];
1124 :
1125 128043 : Handle<String> module_name = sanitized_imports_[index].module_name;
1126 128043 : Handle<String> import_name = sanitized_imports_[index].import_name;
1127 128043 : Handle<Object> value = sanitized_imports_[index].value;
1128 :
1129 128043 : switch (import.kind) {
1130 : case kExternalFunction: {
1131 118437 : uint32_t func_index = import.index;
1132 : DCHECK_EQ(num_imported_functions, func_index);
1133 118437 : if (!ProcessImportedFunction(instance, index, func_index, module_name,
1134 : import_name, value)) {
1135 1961 : return -1;
1136 : }
1137 117885 : num_imported_functions++;
1138 117885 : break;
1139 : }
1140 : case kExternalTable: {
1141 1516 : uint32_t table_index = import.index;
1142 : DCHECK_EQ(table_index, num_imported_tables);
1143 1516 : if (!ProcessImportedTable(instance, index, table_index, module_name,
1144 : import_name, value)) {
1145 : return -1;
1146 : }
1147 : num_imported_tables++;
1148 : break;
1149 : }
1150 : case kExternalMemory: {
1151 4758 : if (!ProcessImportedMemory(instance, index, module_name, import_name,
1152 : value)) {
1153 : return -1;
1154 : }
1155 : break;
1156 : }
1157 : case kExternalGlobal: {
1158 3244 : if (!ProcessImportedGlobal(instance, index, import.index, module_name,
1159 : import_name, value)) {
1160 : return -1;
1161 : }
1162 : break;
1163 : }
1164 : case kExternalException: {
1165 88 : if (!value->IsWasmExceptionObject()) {
1166 32 : ReportLinkError("exception import requires a WebAssembly.Exception",
1167 32 : index, module_name, import_name);
1168 32 : return -1;
1169 : }
1170 : Handle<WasmExceptionObject> imported_exception =
1171 : Handle<WasmExceptionObject>::cast(value);
1172 56 : if (!imported_exception->IsSignatureEqual(
1173 112 : module_->exceptions[import.index].sig)) {
1174 8 : ReportLinkError("imported exception does not match the expected type",
1175 8 : index, module_name, import_name);
1176 8 : return -1;
1177 : }
1178 48 : Object exception_tag = imported_exception->exception_tag();
1179 : DCHECK(instance->exceptions_table()->get(import.index)->IsUndefined());
1180 96 : instance->exceptions_table()->set(import.index, exception_tag);
1181 96 : exception_wrappers_[import.index] = imported_exception;
1182 48 : break;
1183 : }
1184 : default:
1185 0 : UNREACHABLE();
1186 : break;
1187 : }
1188 : }
1189 : return num_imported_functions;
1190 : }
1191 :
1192 : template <typename T>
1193 8158 : T* InstanceBuilder::GetRawGlobalPtr(const WasmGlobal& global) {
1194 16316 : return reinterpret_cast<T*>(raw_buffer_ptr(untagged_globals_, global.offset));
1195 : }
1196 :
1197 : // Process initialization of globals.
1198 134904 : void InstanceBuilder::InitGlobals() {
1199 134904 : for (auto global : module_->globals) {
1200 9214 : if (global.mutability && global.imported) {
1201 : continue;
1202 : }
1203 :
1204 8850 : switch (global.init.kind) {
1205 : case WasmInitExpr::kI32Const:
1206 4745 : WriteLittleEndianValue<int32_t>(GetRawGlobalPtr<int32_t>(global),
1207 : global.init.val.i32_const);
1208 : break;
1209 : case WasmInitExpr::kI64Const:
1210 88 : WriteLittleEndianValue<int64_t>(GetRawGlobalPtr<int64_t>(global),
1211 : global.init.val.i64_const);
1212 : break;
1213 : case WasmInitExpr::kF32Const:
1214 188 : WriteLittleEndianValue<float>(GetRawGlobalPtr<float>(global),
1215 : global.init.val.f32_const);
1216 : break;
1217 : case WasmInitExpr::kF64Const:
1218 854 : WriteLittleEndianValue<double>(GetRawGlobalPtr<double>(global),
1219 : global.init.val.f64_const);
1220 : break;
1221 : case WasmInitExpr::kRefNullConst:
1222 : DCHECK(enabled_.anyref || enabled_.eh);
1223 464 : if (global.imported) break; // We already initialized imported globals.
1224 :
1225 1392 : tagged_globals_->set(global.offset,
1226 1392 : ReadOnlyRoots(isolate_).null_value(),
1227 464 : SKIP_WRITE_BARRIER);
1228 464 : break;
1229 : case WasmInitExpr::kGlobalIndex: {
1230 : // Initialize with another global.
1231 : uint32_t new_offset = global.offset;
1232 : uint32_t old_offset =
1233 136 : module_->globals[global.init.val.global_index].offset;
1234 : TRACE("init [globals+%u] = [globals+%d]\n", global.offset, old_offset);
1235 68 : if (ValueTypes::IsReferenceType(global.type)) {
1236 : DCHECK(enabled_.anyref || enabled_.eh);
1237 48 : tagged_globals_->set(new_offset, tagged_globals_->get(old_offset));
1238 : } else {
1239 52 : size_t size = (global.type == kWasmI64 || global.type == kWasmF64)
1240 : ? sizeof(double)
1241 52 : : sizeof(int32_t);
1242 52 : memcpy(raw_buffer_ptr(untagged_globals_, new_offset),
1243 52 : raw_buffer_ptr(untagged_globals_, old_offset), size);
1244 : }
1245 : break;
1246 : }
1247 : case WasmInitExpr::kNone:
1248 : // Happens with imported globals.
1249 : break;
1250 : default:
1251 0 : UNREACHABLE();
1252 : break;
1253 : }
1254 : }
1255 134904 : }
1256 :
1257 : // Allocate memory for a module instance as a new JSArrayBuffer.
1258 131223 : Handle<JSArrayBuffer> InstanceBuilder::AllocateMemory(uint32_t initial_pages,
1259 : uint32_t maximum_pages) {
1260 131223 : if (initial_pages > max_mem_pages()) {
1261 16 : thrower_->RangeError("Out of memory: wasm memory too large");
1262 : return Handle<JSArrayBuffer>::null();
1263 : }
1264 131207 : const bool is_shared_memory = module_->has_shared_memory && enabled_.threads;
1265 : Handle<JSArrayBuffer> mem_buffer;
1266 131207 : if (is_shared_memory) {
1267 504 : if (!NewSharedArrayBuffer(isolate_, initial_pages * kWasmPageSize,
1268 252 : maximum_pages * kWasmPageSize)
1269 : .ToHandle(&mem_buffer)) {
1270 0 : thrower_->RangeError("Out of memory: wasm shared memory");
1271 : }
1272 : } else {
1273 261910 : if (!NewArrayBuffer(isolate_, initial_pages * kWasmPageSize)
1274 : .ToHandle(&mem_buffer)) {
1275 0 : thrower_->RangeError("Out of memory: wasm memory");
1276 : }
1277 : }
1278 131207 : return mem_buffer;
1279 : }
1280 :
1281 0 : bool InstanceBuilder::NeedsWrappers() const {
1282 134902 : if (module_->num_exported_functions > 0) return true;
1283 4556 : for (auto& table : module_->tables) {
1284 900 : if (table.type == kWasmAnyFunc) return true;
1285 : }
1286 : return false;
1287 : }
1288 :
1289 : // Process the exports, creating wrappers for functions, tables, memories,
1290 : // globals, and exceptions.
1291 134903 : void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
1292 : Handle<FixedArray> export_wrappers(module_object_->export_wrappers(),
1293 134903 : isolate_);
1294 134902 : if (NeedsWrappers()) {
1295 : // If an imported WebAssembly function gets exported, the exported function
1296 : // has to be identical to to imported function. Therefore we cache all
1297 : // imported WebAssembly functions in the instance.
1298 256488 : for (int index = 0, end = static_cast<int>(module_->import_table.size());
1299 256488 : index < end; ++index) {
1300 125242 : const WasmImport& import = module_->import_table[index];
1301 125242 : if (import.kind == kExternalFunction) {
1302 117605 : Handle<Object> value = sanitized_imports_[index].value;
1303 117605 : if (WasmExportedFunction::IsWasmExportedFunction(*value)) {
1304 107024 : WasmInstanceObject::SetWasmExportedFunction(
1305 107024 : isolate_, instance, import.index,
1306 107024 : Handle<WasmExportedFunction>::cast(value));
1307 : }
1308 : }
1309 : }
1310 : }
1311 :
1312 : Handle<JSObject> exports_object;
1313 : bool is_asm_js = false;
1314 134902 : switch (module_->origin) {
1315 : case kWasmOrigin: {
1316 : // Create the "exports" object.
1317 130051 : exports_object = isolate_->factory()->NewJSObjectWithNullProto();
1318 130053 : break;
1319 : }
1320 : case kAsmJsOrigin: {
1321 : Handle<JSFunction> object_function = Handle<JSFunction>(
1322 14553 : isolate_->native_context()->object_function(), isolate_);
1323 4851 : exports_object = isolate_->factory()->NewJSObject(object_function);
1324 : is_asm_js = true;
1325 : break;
1326 : }
1327 : default:
1328 0 : UNREACHABLE();
1329 : }
1330 134904 : instance->set_exports_object(*exports_object);
1331 :
1332 : Handle<String> single_function_name =
1333 134904 : isolate_->factory()->InternalizeUtf8String(AsmJs::kSingleFunctionName);
1334 :
1335 : PropertyDescriptor desc;
1336 : desc.set_writable(is_asm_js);
1337 : desc.set_enumerable(true);
1338 : desc.set_configurable(is_asm_js);
1339 :
1340 : // Process each export in the export table.
1341 : int export_index = 0; // Index into {export_wrappers}.
1342 134907 : for (const WasmExport& exp : module_->export_table) {
1343 460057 : Handle<String> name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
1344 230029 : isolate_, module_object_, exp.name)
1345 : .ToHandleChecked();
1346 : Handle<JSObject> export_to;
1347 238274 : if (is_asm_js && exp.kind == kExternalFunction &&
1348 8246 : String::Equals(isolate_, name, single_function_name)) {
1349 : export_to = instance;
1350 : } else {
1351 : export_to = exports_object;
1352 : }
1353 :
1354 230028 : switch (exp.kind) {
1355 : case kExternalFunction: {
1356 : // Wrap and export the code as a JSFunction.
1357 : // TODO(wasm): reduce duplication with LoadElemSegment() further below
1358 226908 : const WasmFunction& function = module_->functions[exp.index];
1359 : MaybeHandle<WasmExportedFunction> wasm_exported_function =
1360 : WasmInstanceObject::GetWasmExportedFunction(isolate_, instance,
1361 226908 : exp.index);
1362 226908 : if (wasm_exported_function.is_null()) {
1363 : // Wrap the exported code as a JSFunction.
1364 : Handle<Code> export_code =
1365 453288 : export_wrappers->GetValueChecked<Code>(isolate_, export_index);
1366 226644 : MaybeHandle<String> func_name;
1367 226644 : if (is_asm_js) {
1368 : // For modules arising from asm.js, honor the names section.
1369 8226 : WireBytesRef func_name_ref = module_->LookupFunctionName(
1370 : ModuleWireBytes(module_object_->native_module()->wire_bytes()),
1371 24678 : function.func_index);
1372 16452 : func_name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
1373 8226 : isolate_, module_object_, func_name_ref)
1374 8226 : .ToHandleChecked();
1375 : }
1376 : wasm_exported_function = WasmExportedFunction::New(
1377 226644 : isolate_, instance, func_name, function.func_index,
1378 453288 : static_cast<int>(function.sig->parameter_count()), export_code);
1379 226644 : WasmInstanceObject::SetWasmExportedFunction(
1380 226644 : isolate_, instance, exp.index,
1381 226644 : wasm_exported_function.ToHandleChecked());
1382 : }
1383 : desc.set_value(wasm_exported_function.ToHandleChecked());
1384 226908 : export_index++;
1385 : break;
1386 : }
1387 : case kExternalTable: {
1388 540 : desc.set_value(handle(instance->tables()->get(exp.index), isolate_));
1389 540 : break;
1390 : }
1391 : case kExternalMemory: {
1392 : // Export the memory as a WebAssembly.Memory object. A WasmMemoryObject
1393 : // should already be available if the module has memory, since we always
1394 : // create or import it when building an WasmInstanceObject.
1395 : DCHECK(instance->has_memory_object());
1396 1632 : desc.set_value(
1397 : Handle<WasmMemoryObject>(instance->memory_object(), isolate_));
1398 1632 : break;
1399 : }
1400 : case kExternalGlobal: {
1401 836 : const WasmGlobal& global = module_->globals[exp.index];
1402 : Handle<JSArrayBuffer> untagged_buffer;
1403 : Handle<FixedArray> tagged_buffer;
1404 : uint32_t offset;
1405 :
1406 836 : if (global.mutability && global.imported) {
1407 : Handle<FixedArray> buffers_array(
1408 148 : instance->imported_mutable_globals_buffers(), isolate_);
1409 296 : if (ValueTypes::IsReferenceType(global.type)) {
1410 : tagged_buffer = buffers_array->GetValueChecked<FixedArray>(
1411 192 : isolate_, global.index);
1412 : // For anyref globals we store the relative offset in the
1413 : // imported_mutable_globals array instead of an absolute address.
1414 96 : Address addr = instance->imported_mutable_globals()[global.index];
1415 : DCHECK_LE(addr, static_cast<Address>(
1416 : std::numeric_limits<uint32_t>::max()));
1417 96 : offset = static_cast<uint32_t>(addr);
1418 : } else {
1419 : untagged_buffer = buffers_array->GetValueChecked<JSArrayBuffer>(
1420 104 : isolate_, global.index);
1421 : Address global_addr =
1422 52 : instance->imported_mutable_globals()[global.index];
1423 :
1424 : size_t buffer_size = untagged_buffer->byte_length();
1425 : Address backing_store =
1426 52 : reinterpret_cast<Address>(untagged_buffer->backing_store());
1427 52 : CHECK(global_addr >= backing_store &&
1428 : global_addr < backing_store + buffer_size);
1429 52 : offset = static_cast<uint32_t>(global_addr - backing_store);
1430 : }
1431 : } else {
1432 1376 : if (ValueTypes::IsReferenceType(global.type)) {
1433 208 : tagged_buffer = handle(instance->tagged_globals_buffer(), isolate_);
1434 : } else {
1435 : untagged_buffer =
1436 480 : handle(instance->untagged_globals_buffer(), isolate_);
1437 : }
1438 688 : offset = global.offset;
1439 : }
1440 :
1441 : // Since the global's array untagged_buffer is always provided,
1442 : // allocation should never fail.
1443 : Handle<WasmGlobalObject> global_obj =
1444 1672 : WasmGlobalObject::New(isolate_, untagged_buffer, tagged_buffer,
1445 2508 : global.type, offset, global.mutability)
1446 : .ToHandleChecked();
1447 : desc.set_value(global_obj);
1448 : break;
1449 : }
1450 : case kExternalException: {
1451 112 : const WasmException& exception = module_->exceptions[exp.index];
1452 112 : Handle<WasmExceptionObject> wrapper = exception_wrappers_[exp.index];
1453 112 : if (wrapper.is_null()) {
1454 : Handle<HeapObject> exception_tag(
1455 : HeapObject::cast(instance->exceptions_table()->get(exp.index)),
1456 96 : isolate_);
1457 : wrapper =
1458 96 : WasmExceptionObject::New(isolate_, exception.sig, exception_tag);
1459 192 : exception_wrappers_[exp.index] = wrapper;
1460 : }
1461 : desc.set_value(wrapper);
1462 : break;
1463 : }
1464 : default:
1465 0 : UNREACHABLE();
1466 : break;
1467 : }
1468 :
1469 : v8::Maybe<bool> status = JSReceiver::DefineOwnProperty(
1470 230028 : isolate_, export_to, name, &desc, Just(kThrowOnError));
1471 230026 : if (!status.IsJust()) {
1472 : DisallowHeapAllocation no_gc;
1473 0 : TruncatedUserString<> trunc_name(name->GetCharVector<uint8_t>(no_gc));
1474 0 : thrower_->LinkError("export of %.*s failed.", trunc_name.length(),
1475 0 : trunc_name.start());
1476 : return;
1477 : }
1478 : }
1479 : DCHECK_EQ(export_index, export_wrappers->length());
1480 :
1481 134904 : if (module_->origin == kWasmOrigin) {
1482 : v8::Maybe<bool> success =
1483 130053 : JSReceiver::SetIntegrityLevel(exports_object, FROZEN, kDontThrow);
1484 : DCHECK(success.FromMaybe(false));
1485 : USE(success);
1486 : }
1487 : }
1488 :
1489 2353 : void InstanceBuilder::InitializeTables(Handle<WasmInstanceObject> instance) {
1490 2353 : size_t table_count = module_->tables.size();
1491 7235 : for (size_t index = 0; index < table_count; ++index) {
1492 2441 : const WasmTable& table = module_->tables[index];
1493 :
1494 3754 : if (!instance->has_indirect_function_table() &&
1495 1313 : table.type == kWasmAnyFunc) {
1496 : WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
1497 1313 : instance, table.initial_size);
1498 : }
1499 : }
1500 2353 : }
1501 :
1502 2445 : bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
1503 : Handle<WasmTableObject> table_object,
1504 : const WasmElemSegment& elem_segment, uint32_t dst,
1505 : uint32_t src, size_t count) {
1506 : // TODO(wasm): Move this functionality into wasm-objects, since it is used
1507 : // for both instantiation and in the implementation of the table.init
1508 : // instruction.
1509 : bool ok =
1510 2445 : ClampToBounds<size_t>(dst, &count, table_object->elements()->length());
1511 : // Use & instead of && so the clamp is not short-circuited.
1512 2445 : ok &= ClampToBounds<size_t>(src, &count, elem_segment.entries.size());
1513 :
1514 2445 : const WasmModule* module = instance->module();
1515 22727 : for (size_t i = 0; i < count; ++i) {
1516 20282 : uint32_t func_index = elem_segment.entries[src + i];
1517 10141 : int entry_index = static_cast<int>(dst + i);
1518 :
1519 10141 : if (func_index == WasmElemSegment::kNullIndex) {
1520 0 : IndirectFunctionTableEntry(instance, entry_index).clear();
1521 0 : WasmTableObject::Set(isolate, table_object, entry_index,
1522 0 : isolate->factory()->null_value());
1523 : continue;
1524 : }
1525 :
1526 10141 : const WasmFunction* function = &module->functions[func_index];
1527 :
1528 : // Update the local dispatch table first.
1529 20282 : uint32_t sig_id = module->signature_ids[function->sig_index];
1530 : IndirectFunctionTableEntry(instance, entry_index)
1531 20282 : .Set(sig_id, instance, func_index);
1532 :
1533 : // Update the table object's other dispatch tables.
1534 : MaybeHandle<WasmExportedFunction> wasm_exported_function =
1535 : WasmInstanceObject::GetWasmExportedFunction(isolate, instance,
1536 10141 : func_index);
1537 10141 : if (wasm_exported_function.is_null()) {
1538 : // No JSFunction entry yet exists for this function. Create a {Tuple2}
1539 : // holding the information to lazily allocate one.
1540 : WasmTableObject::SetFunctionTablePlaceholder(
1541 9489 : isolate, table_object, entry_index, instance, func_index);
1542 : } else {
1543 1956 : table_object->elements()->set(entry_index,
1544 652 : *wasm_exported_function.ToHandleChecked());
1545 : }
1546 : // UpdateDispatchTables() updates all other dispatch tables, since
1547 : // we have not yet added the dispatch table we are currently building.
1548 : WasmTableObject::UpdateDispatchTables(isolate, table_object, entry_index,
1549 10141 : function->sig, instance, func_index);
1550 : }
1551 2445 : return ok;
1552 : }
1553 :
1554 2353 : void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
1555 2353 : for (auto& elem_segment : module_->elem_segments) {
1556 : // Passive segments are not copied during instantiation.
1557 2125 : if (!elem_segment.active) continue;
1558 :
1559 2109 : uint32_t dst = EvalUint32InitExpr(instance, elem_segment.offset);
1560 : uint32_t src = 0;
1561 : size_t count = elem_segment.entries.size();
1562 :
1563 6327 : bool success = LoadElemSegmentImpl(
1564 : isolate_, instance,
1565 : handle(WasmTableObject::cast(
1566 2109 : instance->tables()->get(elem_segment.table_index)),
1567 : isolate_),
1568 2109 : elem_segment, dst, src, count);
1569 2109 : if (enabled_.bulk_memory) {
1570 2008 : if (!success) {
1571 120 : thrower_->LinkError("table initializer is out of bounds");
1572 : // Break out instead of returning; we don't want to continue to
1573 : // initialize any further element segments, but still need to add
1574 : // dispatch tables below.
1575 120 : break;
1576 : }
1577 : } else {
1578 101 : CHECK(success);
1579 : }
1580 : }
1581 :
1582 4706 : int table_count = static_cast<int>(module_->tables.size());
1583 7235 : for (int index = 0; index < table_count; ++index) {
1584 4882 : if (module_->tables[index].type == kWasmAnyFunc) {
1585 : auto table_object = handle(
1586 4850 : WasmTableObject::cast(instance->tables()->get(index)), isolate_);
1587 :
1588 : // Add the new dispatch table at the end to avoid redundant lookups.
1589 2425 : WasmTableObject::AddDispatchTable(isolate_, table_object, instance,
1590 2425 : index);
1591 : }
1592 : }
1593 2353 : }
1594 :
1595 576 : void InstanceBuilder::InitializeExceptions(
1596 : Handle<WasmInstanceObject> instance) {
1597 576 : Handle<FixedArray> exceptions_table(instance->exceptions_table(), isolate_);
1598 1984 : for (int index = 0; index < exceptions_table->length(); ++index) {
1599 1456 : if (!exceptions_table->get(index)->IsUndefined(isolate_)) continue;
1600 : Handle<WasmExceptionTag> exception_tag =
1601 656 : WasmExceptionTag::New(isolate_, index);
1602 1312 : exceptions_table->set(index, *exception_tag);
1603 : }
1604 576 : }
1605 :
1606 336 : bool LoadElemSegment(Isolate* isolate, Handle<WasmInstanceObject> instance,
1607 : uint32_t table_index, uint32_t segment_index, uint32_t dst,
1608 : uint32_t src, uint32_t count) {
1609 1008 : auto& elem_segment = instance->module()->elem_segments[segment_index];
1610 336 : return LoadElemSegmentImpl(
1611 : isolate, instance,
1612 : handle(WasmTableObject::cast(instance->tables()->get(table_index)),
1613 : isolate),
1614 336 : elem_segment, dst, src, count);
1615 : }
1616 :
1617 : } // namespace wasm
1618 : } // namespace internal
1619 122004 : } // namespace v8
1620 :
1621 : #undef TRACE
|