v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
module-instantiate.cc
Go to the documentation of this file.
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
6
7#include "src/api/api-inl.h"
8#include "src/asmjs/asm-js.h"
13#include "src/logging/metrics.h"
20#include "src/utils/utils.h"
26#include "src/wasm/pgo.h"
36
37#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
39#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
40
41#define TRACE(...) \
42 do { \
43 if (v8_flags.trace_wasm_instances) PrintF(__VA_ARGS__); \
44 } while (false)
45
46namespace v8::internal::wasm {
47
48namespace {
49
50uint8_t* raw_buffer_ptr(MaybeDirectHandle<JSArrayBuffer> buffer, int offset) {
51 return static_cast<uint8_t*>(buffer.ToHandleChecked()->backing_store()) +
52 offset;
53}
54
55} // namespace
56
57void CreateMapForType(Isolate* isolate, const WasmModule* module,
58 ModuleTypeIndex type_index,
59 DirectHandle<FixedArray> maybe_shared_maps) {
60 // Recursive calls for supertypes may already have created this map.
61 if (IsMap(maybe_shared_maps->get(type_index.index))) return;
62
63 CanonicalTypeIndex canonical_type_index =
64 module->canonical_type_id(type_index);
65
66 // Try to find the canonical map for this type in the isolate store.
67 DirectHandle<WeakFixedArray> canonical_rtts =
68 direct_handle(isolate->heap()->wasm_canonical_rtts(), isolate);
69 DCHECK_GT(static_cast<uint32_t>(canonical_rtts->length()),
70 canonical_type_index.index);
71 Tagged<MaybeObject> maybe_canonical_map =
72 canonical_rtts->get(canonical_type_index.index);
73 if (!maybe_canonical_map.IsCleared()) {
74 maybe_shared_maps->set(type_index.index,
75 maybe_canonical_map.GetHeapObjectAssumeWeak());
76 return;
77 }
78
79 DirectHandle<Map> rtt_parent;
80 // If the type with {type_index} has an explicit supertype, make sure the
81 // map for that supertype is created first, so that the supertypes list
82 // that's cached on every RTT can be set up correctly.
83 ModuleTypeIndex supertype = module->supertype(type_index);
84 if (supertype.valid()) {
85 // This recursion is safe, because kV8MaxRttSubtypingDepth limits the
86 // number of recursive steps, so we won't overflow the stack.
87 CreateMapForType(isolate, module, supertype, maybe_shared_maps);
88 // We look up the supertype in {maybe_shared_maps} as a shared type can only
89 // inherit from a shared type and vice verca.
90 rtt_parent = direct_handle(
91 Cast<Map>(maybe_shared_maps->get(supertype.index)), isolate);
92 }
94 switch (module->type(type_index).kind) {
96 DirectHandle<NativeContext> context_independent;
97 map = CreateStructMap(isolate, canonical_type_index, rtt_parent,
98 context_independent);
99 break;
100 }
102 map = CreateArrayMap(isolate, canonical_type_index, rtt_parent);
103 break;
105 map = CreateFuncRefMap(isolate, canonical_type_index, rtt_parent);
106 break;
109 }
110 canonical_rtts->set(canonical_type_index.index, MakeWeak(*map));
111 maybe_shared_maps->set(type_index.index, *map);
112}
113
114namespace {
115
116bool CompareWithNormalizedCType(const CTypeInfo& info,
117 CanonicalValueType expected,
120 // Wasm representation of bool is i32 instead of i1.
121 if (t.semantic() == MachineSemantic::kBool) {
122 return expected == kWasmI32;
123 }
124 if (info.GetType() == CTypeInfo::Type::kSeqOneByteString) {
125 // WebAssembly does not support one byte strings in fast API calls as
126 // runtime type checks are not supported so far.
127 return false;
128 }
129
130 if (t.representation() == MachineRepresentation::kWord64) {
132 return expected == kWasmI64;
133 }
135 return expected == kWasmI32 || expected == kWasmF32 || expected == kWasmF64;
136 }
137 return t.representation() == expected.machine_representation();
138}
139
140enum class ReceiverKind { kFirstParamIsReceiver, kAnyReceiver };
141
142bool IsSupportedWasmFastApiFunction(Isolate* isolate,
143 const wasm::CanonicalSig* expected_sig,
145 ReceiverKind receiver_kind,
146 int* out_index) {
147 if (!shared->IsApiFunction()) {
148 return false;
149 }
150 if (shared->api_func_data()->GetCFunctionsCount() == 0) {
151 return false;
152 }
153 if (receiver_kind == ReceiverKind::kAnyReceiver &&
154 !shared->api_func_data()->accept_any_receiver()) {
155 return false;
156 }
157 if (receiver_kind == ReceiverKind::kAnyReceiver &&
158 !IsUndefined(shared->api_func_data()->signature())) {
159 // TODO(wasm): CFunctionInfo* signature check.
160 return false;
161 }
162
163 const auto log_imported_function_mismatch = [&shared, isolate](
164 int func_index,
165 const char* reason) {
166 if (v8_flags.trace_opt) {
167 CodeTracer::Scope scope(isolate->GetCodeTracer());
168 PrintF(scope.file(), "[disabled optimization for ");
169 ShortPrint(*shared, scope.file());
170 PrintF(scope.file(),
171 " for C function %d, reason: the signature of the imported "
172 "function in the Wasm module doesn't match that of the Fast API "
173 "function (%s)]\n",
174 func_index, reason);
175 }
176 };
177
178 // C functions only have one return value.
179 if (expected_sig->return_count() > 1) {
180 // Here and below, we log when the function we call is declared as an Api
181 // function but we cannot optimize the call, which might be unexpected. In
182 // that case we use the "slow" path making a normal Wasm->JS call and
183 // calling the "slow" callback specified in FunctionTemplate::New().
184 log_imported_function_mismatch(0, "too many return values");
185 return false;
186 }
187
188 for (int c_func_id = 0, end = shared->api_func_data()->GetCFunctionsCount();
189 c_func_id < end; ++c_func_id) {
190 const CFunctionInfo* info =
191 shared->api_func_data()->GetCSignature(isolate, c_func_id);
193 log_imported_function_mismatch(c_func_id,
194 "signature not supported by the fast API");
195 continue;
196 }
197
198 CTypeInfo return_info = info->ReturnInfo();
199 // Unsupported if return type doesn't match.
200 if (expected_sig->return_count() == 0 &&
201 return_info.GetType() != CTypeInfo::Type::kVoid) {
202 log_imported_function_mismatch(c_func_id, "too few return values");
203 continue;
204 }
205 // Unsupported if return type doesn't match.
206 if (expected_sig->return_count() == 1) {
207 if (return_info.GetType() == CTypeInfo::Type::kVoid) {
208 log_imported_function_mismatch(c_func_id, "too many return values");
209 continue;
210 }
211 if (!CompareWithNormalizedCType(return_info, expected_sig->GetReturn(0),
212 info->GetInt64Representation())) {
213 log_imported_function_mismatch(c_func_id, "mismatching return value");
214 continue;
215 }
216 }
217
218 if (receiver_kind == ReceiverKind::kFirstParamIsReceiver) {
219 if (expected_sig->parameter_count() < 1) {
220 log_imported_function_mismatch(
221 c_func_id, "at least one parameter is needed as the receiver");
222 continue;
223 }
224 if (!expected_sig->GetParam(0).is_reference()) {
225 log_imported_function_mismatch(c_func_id,
226 "the receiver has to be a reference");
227 continue;
228 }
229 }
230
231 int param_offset =
232 receiver_kind == ReceiverKind::kFirstParamIsReceiver ? 1 : 0;
233 // Unsupported if arity doesn't match.
234 if (expected_sig->parameter_count() - param_offset !=
235 info->ArgumentCount() - 1) {
236 log_imported_function_mismatch(c_func_id, "mismatched arity");
237 continue;
238 }
239 // Unsupported if any argument types don't match.
240 bool param_mismatch = false;
241 for (unsigned int i = 0; i < expected_sig->parameter_count() - param_offset;
242 ++i) {
243 int sig_index = i + param_offset;
244 // Arg 0 is the receiver, skip over it since either the receiver does not
245 // matter, or we already checked it above.
246 CTypeInfo arg = info->ArgumentInfo(i + 1);
247 if (!CompareWithNormalizedCType(arg, expected_sig->GetParam(sig_index),
248 info->GetInt64Representation())) {
249 log_imported_function_mismatch(c_func_id, "parameter type mismatch");
250 param_mismatch = true;
251 break;
252 }
254 if (arg.GetSequenceType() == CTypeInfo::SequenceType::kIsSequence) {
255 log_imported_function_mismatch(c_func_id,
256 "sequence types are not allowed");
257 param_mismatch = true;
258 break;
259 }
261 }
262 if (param_mismatch) {
263 continue;
264 }
265 *out_index = c_func_id;
266 return true;
267 }
268 return false;
269}
270
271bool ResolveBoundJSFastApiFunction(const wasm::CanonicalSig* expected_sig,
272 DirectHandle<JSReceiver> callable) {
273 Isolate* isolate = Isolate::Current();
274
275 DirectHandle<JSFunction> target;
276 if (IsJSBoundFunction(*callable)) {
277 auto bound_target = Cast<JSBoundFunction>(callable);
278 // Nested bound functions and arguments not supported yet.
279 if (bound_target->bound_arguments()->length() > 0) {
280 return false;
281 }
282 if (IsJSBoundFunction(bound_target->bound_target_function())) {
283 return false;
284 }
285 DirectHandle<JSReceiver> bound_target_function(
286 bound_target->bound_target_function(), isolate);
287 if (!IsJSFunction(*bound_target_function)) {
288 return false;
289 }
290 target = Cast<JSFunction>(bound_target_function);
291 } else if (IsJSFunction(*callable)) {
292 target = Cast<JSFunction>(callable);
293 } else {
294 return false;
295 }
296
297 DirectHandle<SharedFunctionInfo> shared(target->shared(), isolate);
298 int api_function_index = -1;
299 // The fast API call wrapper currently does not support function overloading.
300 // Therefore, if the matching function is not function 0, the fast API cannot
301 // be used.
302 return IsSupportedWasmFastApiFunction(isolate, expected_sig, *shared,
303 ReceiverKind::kAnyReceiver,
304 &api_function_index) &&
305 api_function_index == 0;
306}
307
308bool IsStringRef(wasm::CanonicalValueType type) {
309 return type.is_abstract_ref() && type.generic_kind() == GenericKind::kString;
310}
311
312bool IsExternRef(wasm::CanonicalValueType type) {
313 return type.is_abstract_ref() && type.generic_kind() == GenericKind::kExtern;
314}
315
316bool IsStringOrExternRef(wasm::CanonicalValueType type) {
317 return IsStringRef(type) || IsExternRef(type);
318}
319
320bool IsDataViewGetterSig(const wasm::CanonicalSig* sig,
321 wasm::CanonicalValueType return_type) {
322 return sig->parameter_count() == 3 && sig->return_count() == 1 &&
323 sig->GetParam(0) == wasm::kWasmExternRef &&
324 sig->GetParam(1) == wasm::kWasmI32 &&
325 sig->GetParam(2) == wasm::kWasmI32 && sig->GetReturn(0) == return_type;
326}
327
328bool IsDataViewSetterSig(const wasm::CanonicalSig* sig,
329 wasm::CanonicalValueType value_type) {
330 return sig->parameter_count() == 4 && sig->return_count() == 0 &&
331 sig->GetParam(0) == wasm::kWasmExternRef &&
332 sig->GetParam(1) == wasm::kWasmI32 && sig->GetParam(2) == value_type &&
333 sig->GetParam(3) == wasm::kWasmI32;
334}
335
336const MachineSignature* GetFunctionSigForFastApiImport(
337 Zone* zone, const CFunctionInfo* info) {
338 uint32_t arg_count = info->ArgumentCount();
339 uint32_t ret_count =
340 info->ReturnInfo().GetType() == CTypeInfo::Type::kVoid ? 0 : 1;
341 constexpr uint32_t param_offset = 1;
342
343 MachineSignature::Builder sig_builder(zone, ret_count,
344 arg_count - param_offset);
345 if (ret_count) {
346 sig_builder.AddReturn(MachineType::TypeForCType(info->ReturnInfo()));
347 }
348
349 for (uint32_t i = param_offset; i < arg_count; ++i) {
350 sig_builder.AddParam(MachineType::TypeForCType(info->ArgumentInfo(i)));
351 }
352 return sig_builder.Get();
353}
354
355// This detects imports of the forms:
356// - `Function.prototype.call.bind(foo)`, where `foo` is something that has a
357// Builtin id.
358// - JSFunction with Builtin id (e.g. `parseFloat`, `Math.sin`).
359WellKnownImport CheckForWellKnownImport(
360 DirectHandle<WasmTrustedInstanceData> trusted_instance_data, int func_index,
361 DirectHandle<JSReceiver> callable, const wasm::CanonicalSig* sig) {
363 if (trusted_instance_data.is_null()) return kGeneric;
364 // Check for plain JS functions.
365 if (IsJSFunction(*callable)) {
366 Tagged<SharedFunctionInfo> sfi = Cast<JSFunction>(*callable)->shared();
367 if (!sfi->HasBuiltinId()) return kGeneric;
368 // This needs to be a separate switch because it allows other cases than
369 // the one below. Merging them would be invalid, because we would then
370 // recognize receiver-requiring methods even when they're (erroneously)
371 // being imported such that they don't get a receiver.
372 switch (sfi->builtin_id()) {
373 // =================================================================
374 // String-related imports that aren't part of the JS String Builtins
375 // proposal.
376 case Builtin::kNumberParseFloat:
377 if (sig->parameter_count() == 1 && sig->return_count() == 1 &&
378 IsStringRef(sig->GetParam(0)) &&
379 sig->GetReturn(0) == wasm::kWasmF64) {
381 }
382 break;
383
384 // =================================================================
385 // Math functions.
386#define COMPARE_MATH_BUILTIN_F64(name) \
387 case Builtin::kMath##name: { \
388 if (!v8_flags.wasm_math_intrinsics) return kGeneric; \
389 const FunctionSig* builtin_sig = WasmOpcodes::Signature(kExprF64##name); \
390 if (!builtin_sig) { \
391 builtin_sig = WasmOpcodes::AsmjsSignature(kExprF64##name); \
392 } \
393 DCHECK_NOT_NULL(builtin_sig); \
394 if (EquivalentNumericSig(sig, builtin_sig)) { \
395 return WellKnownImport::kMathF64##name; \
396 } \
397 break; \
398 }
399
411
412#undef COMPARE_MATH_BUILTIN_F64
413
414 default:
415 break;
416 }
417 return kGeneric;
418 }
419
420 // Check for bound JS functions.
421 // First part: check that the callable is a bound function whose target
422 // is {Function.prototype.call}, and which only binds a receiver.
423 if (!IsJSBoundFunction(*callable)) return kGeneric;
424 auto bound = Cast<JSBoundFunction>(callable);
425 if (bound->bound_arguments()->length() != 0) return kGeneric;
426 if (!IsJSFunction(bound->bound_target_function())) return kGeneric;
428 Cast<JSFunction>(bound->bound_target_function())->shared();
429 if (!sfi->HasBuiltinId()) return kGeneric;
430 if (sfi->builtin_id() != Builtin::kFunctionPrototypeCall) return kGeneric;
431 // Second part: check if the bound receiver is one of the builtins for which
432 // we have special-cased support.
433 Tagged<Object> bound_this = bound->bound_this();
434 if (!IsJSFunction(bound_this)) return kGeneric;
435 sfi = Cast<JSFunction>(bound_this)->shared();
436 Isolate* isolate = Isolate::Current();
437 int out_api_function_index = -1;
438 if (v8_flags.wasm_fast_api &&
439 IsSupportedWasmFastApiFunction(isolate, sig, sfi,
440 ReceiverKind::kFirstParamIsReceiver,
441 &out_api_function_index)) {
442 Tagged<FunctionTemplateInfo> func_data = sfi->api_func_data();
443 NativeModule* native_module = trusted_instance_data->native_module();
444 if (!native_module->TrySetFastApiCallTarget(
445 func_index,
446 func_data->GetCFunction(isolate, out_api_function_index))) {
447 return kGeneric;
448 }
449#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
450 Address c_functions[] = {func_data->GetCFunction(isolate, 0)};
451 const v8::CFunctionInfo* const c_signatures[] = {
452 func_data->GetCSignature(isolate, 0)};
453 isolate->simulator_data()->RegisterFunctionsAndSignatures(c_functions,
454 c_signatures, 1);
455#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
456 // Store the signature of the C++ function in the native_module. We check
457 // first if the signature already exists in the native_module such that we
458 // do not create a copy of the signature unnecessarily. Since
459 // `has_fast_api_signature` and `set_fast_api_signature` don't happen
460 // atomically, it is still possible that multiple copies of the signature
461 // get created. However, the `TrySetFastApiCallTarget` above guarantees that
462 // if there are concurrent calls to `set_cast_api_signature`, then all calls
463 // would store the same signature to the native module.
464 if (!native_module->has_fast_api_signature(func_index)) {
465 native_module->set_fast_api_signature(
466 func_index,
467 GetFunctionSigForFastApiImport(
468 &native_module->module()->signature_zone,
469 func_data->GetCSignature(isolate, out_api_function_index)));
470 }
471
472 DirectHandle<HeapObject> js_signature(sfi->api_func_data()->signature(),
473 isolate);
474 DirectHandle<Object> callback_data(
475 sfi->api_func_data()->callback_data(kAcquireLoad), isolate);
476 DirectHandle<WasmFastApiCallData> fast_api_call_data =
477 isolate->factory()->NewWasmFastApiCallData(js_signature, callback_data);
478 trusted_instance_data->well_known_imports()->set(func_index,
479 *fast_api_call_data);
481 }
482 if (!sfi->HasBuiltinId()) return kGeneric;
483 switch (sfi->builtin_id()) {
484#if V8_INTL_SUPPORT
485 case Builtin::kStringPrototypeToLocaleLowerCase:
486 if (sig->parameter_count() == 2 && sig->return_count() == 1 &&
487 IsStringRef(sig->GetParam(0)) && IsStringRef(sig->GetParam(1)) &&
488 IsStringRef(sig->GetReturn(0))) {
489 DCHECK_GE(func_index, 0);
490 trusted_instance_data->well_known_imports()->set(func_index,
491 bound_this);
493 }
494 break;
495 case Builtin::kStringPrototypeToLowerCaseIntl:
496 if (sig->parameter_count() == 1 && sig->return_count() == 1 &&
497 IsStringRef(sig->GetParam(0)) && IsStringRef(sig->GetReturn(0))) {
499 } else if (sig->parameter_count() == 1 && sig->return_count() == 1 &&
500 sig->GetParam(0) == wasm::kWasmExternRef &&
501 sig->GetReturn(0) == wasm::kWasmExternRef) {
503 }
504 break;
505#endif
506 case Builtin::kDataViewPrototypeGetBigInt64:
507 if (IsDataViewGetterSig(sig, wasm::kWasmI64)) {
509 }
510 break;
511 case Builtin::kDataViewPrototypeGetBigUint64:
512 if (IsDataViewGetterSig(sig, wasm::kWasmI64)) {
514 }
515 break;
516 case Builtin::kDataViewPrototypeGetFloat32:
517 if (IsDataViewGetterSig(sig, wasm::kWasmF32)) {
519 }
520 break;
521 case Builtin::kDataViewPrototypeGetFloat64:
522 if (IsDataViewGetterSig(sig, wasm::kWasmF64)) {
524 }
525 break;
526 case Builtin::kDataViewPrototypeGetInt8:
527 if (sig->parameter_count() == 2 && sig->return_count() == 1 &&
528 sig->GetParam(0) == wasm::kWasmExternRef &&
529 sig->GetParam(1) == wasm::kWasmI32 &&
530 sig->GetReturn(0) == wasm::kWasmI32) {
532 }
533 break;
534 case Builtin::kDataViewPrototypeGetInt16:
535 if (IsDataViewGetterSig(sig, wasm::kWasmI32)) {
537 }
538 break;
539 case Builtin::kDataViewPrototypeGetInt32:
540 if (IsDataViewGetterSig(sig, wasm::kWasmI32)) {
542 }
543 break;
544 case Builtin::kDataViewPrototypeGetUint8:
545 if (sig->parameter_count() == 2 && sig->return_count() == 1 &&
546 sig->GetParam(0) == wasm::kWasmExternRef &&
547 sig->GetParam(1) == wasm::kWasmI32 &&
548 sig->GetReturn(0) == wasm::kWasmI32) {
550 }
551 break;
552 case Builtin::kDataViewPrototypeGetUint16:
553 if (IsDataViewGetterSig(sig, wasm::kWasmI32)) {
555 }
556 break;
557 case Builtin::kDataViewPrototypeGetUint32:
558 if (IsDataViewGetterSig(sig, wasm::kWasmI32)) {
560 }
561 break;
562
563 case Builtin::kDataViewPrototypeSetBigInt64:
564 if (IsDataViewSetterSig(sig, wasm::kWasmI64)) {
566 }
567 break;
568 case Builtin::kDataViewPrototypeSetBigUint64:
569 if (IsDataViewSetterSig(sig, wasm::kWasmI64)) {
571 }
572 break;
573 case Builtin::kDataViewPrototypeSetFloat32:
574 if (IsDataViewSetterSig(sig, wasm::kWasmF32)) {
576 }
577 break;
578 case Builtin::kDataViewPrototypeSetFloat64:
579 if (IsDataViewSetterSig(sig, wasm::kWasmF64)) {
581 }
582 break;
583 case Builtin::kDataViewPrototypeSetInt8:
584 if (sig->parameter_count() == 3 && sig->return_count() == 0 &&
585 sig->GetParam(0) == wasm::kWasmExternRef &&
586 sig->GetParam(1) == wasm::kWasmI32 &&
587 sig->GetParam(2) == wasm::kWasmI32) {
589 }
590 break;
591 case Builtin::kDataViewPrototypeSetInt16:
592 if (IsDataViewSetterSig(sig, wasm::kWasmI32)) {
594 }
595 break;
596 case Builtin::kDataViewPrototypeSetInt32:
597 if (IsDataViewSetterSig(sig, wasm::kWasmI32)) {
599 }
600 break;
601 case Builtin::kDataViewPrototypeSetUint8:
602 if (sig->parameter_count() == 3 && sig->return_count() == 0 &&
603 sig->GetParam(0) == wasm::kWasmExternRef &&
604 sig->GetParam(1) == wasm::kWasmI32 &&
605 sig->GetParam(2) == wasm::kWasmI32) {
607 }
608 break;
609 case Builtin::kDataViewPrototypeSetUint16:
610 if (IsDataViewSetterSig(sig, wasm::kWasmI32)) {
612 }
613 break;
614 case Builtin::kDataViewPrototypeSetUint32:
615 if (IsDataViewSetterSig(sig, wasm::kWasmI32)) {
617 }
618 break;
619 case Builtin::kDataViewPrototypeGetByteLength:
620 if (sig->parameter_count() == 1 && sig->return_count() == 1 &&
621 sig->GetParam(0) == wasm::kWasmExternRef &&
622 sig->GetReturn(0) == kWasmF64) {
624 }
625 break;
626 case Builtin::kNumberPrototypeToString:
627 if (sig->parameter_count() == 2 && sig->return_count() == 1 &&
628 sig->GetParam(0) == wasm::kWasmI32 &&
629 sig->GetParam(1) == wasm::kWasmI32 &&
630 IsStringOrExternRef(sig->GetReturn(0))) {
632 }
633 if (sig->parameter_count() == 1 && sig->return_count() == 1 &&
634 sig->GetParam(0) == wasm::kWasmF64 &&
635 IsStringOrExternRef(sig->GetReturn(0))) {
637 }
638 break;
639 case Builtin::kStringPrototypeIndexOf:
640 // (string, string, i32) -> (i32).
641 if (sig->parameter_count() == 3 && sig->return_count() == 1 &&
642 IsStringRef(sig->GetParam(0)) && IsStringRef(sig->GetParam(1)) &&
643 sig->GetParam(2) == wasm::kWasmI32 &&
644 sig->GetReturn(0) == wasm::kWasmI32) {
646 } else if (sig->parameter_count() == 3 && sig->return_count() == 1 &&
647 sig->GetParam(0) == wasm::kWasmExternRef &&
648 sig->GetParam(1) == wasm::kWasmExternRef &&
649 sig->GetParam(2) == wasm::kWasmI32 &&
650 sig->GetReturn(0) == wasm::kWasmI32) {
652 }
653 break;
654 default:
655 break;
656 }
657 return kGeneric;
658}
659
660} // namespace
661
663 DirectHandle<WasmTrustedInstanceData> trusted_instance_data, int func_index,
664 DirectHandle<JSReceiver> callable, const wasm::CanonicalSig* expected_sig,
665 CanonicalTypeIndex expected_sig_id, WellKnownImport preknown_import) {
666 DCHECK_EQ(expected_sig, wasm::GetTypeCanonicalizer()->LookupFunctionSignature(
667 expected_sig_id));
669 kind_ = ComputeKind(trusted_instance_data, func_index, expected_sig,
670 expected_sig_id, preknown_import);
671}
672
674 Tagged<JSReceiver> callable) {
675 SetCallable(isolate, direct_handle(callable, isolate));
676}
678 DirectHandle<JSReceiver> callable) {
681 if (!IsJSFunction(*callable)) return;
682 Tagged<SharedFunctionInfo> sfi = Cast<JSFunction>(*callable_)->shared();
683 if (sfi->HasWasmFunctionData()) {
684 trusted_function_data_ = direct_handle(sfi->wasm_function_data(), isolate);
685 }
686}
687
689 DirectHandle<WasmTrustedInstanceData> trusted_instance_data, int func_index,
690 const wasm::CanonicalSig* expected_sig, CanonicalTypeIndex expected_sig_id,
691 WellKnownImport preknown_import) {
692 // If we already have a compile-time import, simply pass that through.
693 if (IsCompileTimeImport(preknown_import)) {
694 well_known_status_ = preknown_import;
695 DCHECK(IsJSFunction(*callable_));
697 ->shared()
698 ->internal_formal_parameter_count_without_receiver(),
699 expected_sig->parameter_count());
701 }
702 Isolate* isolate = Isolate::Current();
703 if (IsWasmSuspendingObject(*callable_)) {
705 SetCallable(isolate, Cast<WasmSuspendingObject>(*callable_)->callable());
706 }
707 if (!trusted_function_data_.is_null() &&
708 IsWasmExportedFunctionData(*trusted_function_data_)) {
711 if (!data->MatchesSignature(expected_sig_id)) {
713 }
714 uint32_t function_index = static_cast<uint32_t>(data->function_index());
715 if (function_index >=
716 data->instance_data()->module()->num_imported_functions) {
718 }
719 // Resolve the shortcut to the underlying callable and continue.
720 ImportedFunctionEntry entry(direct_handle(data->instance_data(), isolate),
721 function_index);
722 suspend_ = Cast<WasmImportData>(entry.implicit_arg())->suspend();
723 SetCallable(isolate, entry.callable());
724 }
725 if (!trusted_function_data_.is_null() &&
726 IsWasmJSFunctionData(*trusted_function_data_)) {
727 Tagged<WasmJSFunctionData> js_function_data =
729 suspend_ = js_function_data->GetSuspend();
730 if (!js_function_data->MatchesSignature(expected_sig_id)) {
732 }
733 if (IsJSFunction(js_function_data->GetCallable())) {
735 Cast<JSFunction>(js_function_data->GetCallable())->shared();
736 if (sfi->HasWasmFunctionData()) {
737 // Special case if the underlying callable is a WasmJSFunction or
738 // WasmExportedFunction: link the outer WasmJSFunction itself and not
739 // the inner callable. Otherwise when the wrapper tiers up, we will try
740 // to link the inner WasmJSFunction/WamsExportedFunction which is
741 // incorrect.
743 }
744 }
745 SetCallable(isolate, js_function_data->GetCallable());
746 }
748 // TODO(jkummerow): Update this to follow the style of the other kinds of
749 // functions.
750 auto capi_function = Cast<WasmCapiFunction>(callable_);
751 if (!capi_function->MatchesSignature(expected_sig_id)) {
753 }
755 }
756 // Assuming we are calling to JS, check whether this would be a runtime error.
757 if (!wasm::IsJSCompatibleSignature(expected_sig)) {
759 }
760 // Check if this can be a JS fast API call.
761 if (v8_flags.turbo_fast_api_calls &&
762 ResolveBoundJSFastApiFunction(expected_sig, callable_)) {
764 }
765 well_known_status_ = CheckForWellKnownImport(
766 trusted_instance_data, func_index, callable_, expected_sig);
769 }
770 // TODO(jkummerow): It would be nice to return {kJSFunctionArityMatch} here
771 // whenever {well_known_status_ != kGeneric}, so that the generic wrapper
772 // can be used instead of a compiled wrapper; but that requires adding
773 // support for calling bound functions to the generic wrapper first.
774
775 // For JavaScript calls, determine whether the target has an arity match.
776 if (IsJSFunction(*callable_)) {
777 auto function = Cast<JSFunction>(callable_);
778 DirectHandle<SharedFunctionInfo> shared(function->shared(), isolate);
779
780 if (IsClassConstructor(shared->kind())) {
781 // Class constructor will throw anyway.
783 }
784
785 if (shared->internal_formal_parameter_count_without_receiver() ==
786 expected_sig->parameter_count()) {
788 }
789
791 }
792 // Unknown case. Use the call builtin.
794}
795
796// A helper class to simplify instantiating a module from a module object.
797// It closes over the {Isolate}, the {ErrorThrower}, etc.
799 public:
801 ErrorThrower* thrower,
802 DirectHandle<WasmModuleObject> module_object,
805
806 // Build an instance, in all of its glory.
808 // Run the start function, if any.
810
811 private:
815 const WasmModule* const module_;
828 std::vector<WellKnownImport> well_known_imports_;
829 // We pass this {Zone} to the temporary {WasmFullDecoder} we allocate during
830 // each call to {EvaluateConstantExpression}, and reset it after each such
831 // call. This has been found to improve performance a bit over allocating a
832 // new {Zone} each time.
834
835 std::string ImportName(uint32_t index) {
836 const WasmImport& import = module_->import_table[index];
837 const char* wire_bytes_start = reinterpret_cast<const char*>(
838 module_object_->native_module()->wire_bytes().data());
839 std::ostringstream oss;
840 oss << "Import #" << index << " \"";
841 oss.write(wire_bytes_start + import.module_name.offset(),
842 import.module_name.length());
843 oss << "\" \"";
844 oss.write(wire_bytes_start + import.field_name.offset(),
845 import.field_name.length());
846 oss << "\"";
847 return oss.str();
848 }
849
850 std::string ImportName(uint32_t index, DirectHandle<String> module_name) {
851 std::ostringstream oss;
852 oss << "Import #" << index << " \"" << module_name->ToCString().get()
853 << "\"";
854 return oss.str();
855 }
856
857 // Look up an import value in the {ffi_} object.
859 DirectHandle<String> module_name,
860 DirectHandle<String> import_name);
861
862 // Look up an import value in the {ffi_} object specifically for linking an
863 // asm.js module. This only performs non-observable lookups, which allows
864 // falling back to JavaScript proper (and hence re-executing all lookups) if
865 // module instantiation fails.
867 DirectHandle<String> import_name);
868
869 // Load data segments into the memory.
870 void LoadDataSegments(
871 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
872 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data);
873
874 void WriteGlobalValue(const WasmGlobal& global, const WasmValue& value);
875
876 void SanitizeImports();
877
878 // Creation of a Wasm instance with {Build()} is split into several phases:
879 //
880 // First phase: initializes (trusted) objects, so if it fails halfway
881 // through (when validation errors are encountered), it must not leave
882 // pointers to half-initialized objects elsewhere in memory (e.g. it
883 // must not register the instance in "uses" lists, nor write active
884 // element segments into imported tables).
886 const DisallowJavascriptExecution& no_js);
887 // The last part of the first phase finalizes initialization of trusted
888 // objects and creates pointers from elsewhere to them. This sub-phase
889 // can never fail, but should still happen under the lifetime of the
890 // TrustedPointerPublishingScope.
891 // When reaching the end of this phase, all created objects (for the
892 // instance, tables, globals, etc) must be in fully initialized and
893 // self-consistent state, ready to execute user code (such as the "start"
894 // function, or fallible user-provided initializers).
897 DirectHandle<WasmTrustedInstanceData> shared_trusted_data);
898 // Second phase: runs module-provided initializers and as such can fail,
899 // but may assume that just-created objects have been initialized to a
900 // consistent state, and *must* assume that these objects are already
901 // reachable from elsewhere (so must no longer be made inaccessible on
902 // failure).
905
906 // Allocate the memory.
908
909 // Processes a single imported function.
911 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
912 int import_index, int func_index, DirectHandle<Object> value,
913 WellKnownImport preknown_import);
914
915 // Process a single imported table.
917 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
918 int import_index, int table_index, DirectHandle<Object> value);
919
920 // Process a single imported global.
922 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
923 int import_index, int global_index, DirectHandle<Object> value);
924
925 // Process a single imported WasmGlobalObject.
927 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
928 int import_index, const WasmGlobal& global,
929 DirectHandle<WasmGlobalObject> global_object);
930
931 // Process the imports, including functions, tables, globals, and memory, in
932 // order, loading them from the {ffi_} object. Returns the number of imported
933 // functions, or {-1} on error.
934 int ProcessImports(
935 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
936 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data);
937
938 // Process all imported memories, placing the WasmMemoryObjects in the
939 // supplied {FixedArray}.
941 DirectHandle<FixedArray> imported_memory_objects);
942
943 template <typename T>
944 T* GetRawUntaggedGlobalPtr(const WasmGlobal& global);
945
946 // Process initialization of globals.
947 void InitGlobals(
948 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
949 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data);
950
951 // Process the exports, creating wrappers for functions, tables, memories,
952 // and globals.
953 void ProcessExports(
954 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
955 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data);
956
958 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
959 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data);
960
962 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
963 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data);
964
965 // Creates new tags. Note that some tags might already exist if they were
966 // imported, those tags will be reused.
967 void InitializeTags(
968 DirectHandle<WasmTrustedInstanceData> trusted_instance_data);
969};
970
971namespace {
972class WriteOutPGOTask : public v8::Task {
973 public:
974 explicit WriteOutPGOTask(std::weak_ptr<NativeModule> native_module)
975 : native_module_(std::move(native_module)) {}
976
977 void Run() final {
978 std::shared_ptr<NativeModule> native_module = native_module_.lock();
979 if (!native_module) return;
980 DumpProfileToFile(native_module->module(), native_module->wire_bytes(),
981 native_module->tiering_budget_array());
982 Schedule(std::move(native_module_));
983 }
984
985 static void Schedule(std::weak_ptr<NativeModule> native_module) {
986 // Write out PGO info every 10 seconds.
989 std::make_unique<WriteOutPGOTask>(std::move(native_module)), 10.0);
990 }
991
992 private:
993 const std::weak_ptr<NativeModule> native_module_;
994};
995
996} // namespace
997
999 Isolate* isolate, ErrorThrower* thrower,
1000 DirectHandle<WasmModuleObject> module_object,
1002 MaybeDirectHandle<JSArrayBuffer> memory_buffer) {
1004 isolate->GetOrRegisterRecorderContextId(isolate->native_context());
1005 InstanceBuilder builder(isolate, context_id, thrower, module_object, imports,
1006 memory_buffer);
1008 if (!instance_object.is_null()) {
1009 const std::shared_ptr<NativeModule>& native_module =
1010 module_object->shared_native_module();
1011 if (v8_flags.experimental_wasm_pgo_to_file &&
1012 native_module->ShouldPgoDataBeWritten() &&
1013 native_module->module()->num_declared_functions > 0) {
1014 WriteOutPGOTask::Schedule(native_module);
1015 }
1016 if (builder.ExecuteStartFunction()) {
1017 return instance_object;
1018 }
1019 }
1020 DCHECK(isolate->has_exception() || thrower->error());
1021 return {};
1022}
1023
1025 Isolate* isolate, v8::metrics::Recorder::ContextId context_id,
1026 ErrorThrower* thrower, DirectHandle<WasmModuleObject> module_object,
1028 MaybeDirectHandle<JSArrayBuffer> asmjs_memory_buffer)
1029 : isolate_(isolate),
1030 context_id_(context_id),
1031 enabled_(module_object->native_module()->enabled_features()),
1032 module_(module_object->module()),
1033 thrower_(thrower),
1034 module_object_(module_object),
1035 ffi_(ffi),
1036 asmjs_memory_buffer_(asmjs_memory_buffer),
1037 tags_wrappers_(isolate),
1038 shared_tags_wrappers_(isolate),
1039 sanitized_imports_(isolate),
1040 init_expr_zone_(isolate_->allocator(), "constant expression zone") {
1041 sanitized_imports_.reserve(module_->import_table.size());
1042 well_known_imports_.reserve(module_->num_imported_functions);
1043}
1044
1045// Build an instance, in all of its glory.
1047 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
1048 "wasm.InstanceBuilder.Build");
1049 // Will check whether {ffi_} is available.
1051 if (thrower_->error()) return {};
1052
1053 // From here on, we expect the build pipeline to run without exiting to JS.
1054 DisallowJavascriptExecution no_js(isolate_);
1055 // Start a timer for instantiation time, if we have a high resolution timer.
1056 base::ElapsedTimer timer;
1058 timer.Start();
1059 }
1060 v8::metrics::WasmModuleInstantiated wasm_module_instantiated;
1061
1063 // Phase 1: uses a {TrustedPointerPublishingScope} to make the new,
1064 // partially-initialized instance inaccessible in case of failure.
1065 if (!Build_Phase1(no_js).ToHandle(&instance_data)) return {};
1066 // Phase 2: assumes that the new instance is already sufficiently
1067 // consistently initialized to be exposed to user code.
1068 if (!Build_Phase2(instance_data).ToHandle(&instance_data)) return {};
1069
1070 wasm_module_instantiated.success = true;
1071 wasm_module_instantiated.imported_function_count =
1072 module_->num_imported_functions;
1073 if (timer.IsStarted()) {
1074 base::TimeDelta instantiation_time = timer.Elapsed();
1075 wasm_module_instantiated.wall_clock_duration_in_us =
1076 instantiation_time.InMicroseconds();
1077 SELECT_WASM_COUNTER(isolate_->counters(), module_->origin, wasm_instantiate,
1078 module_time)
1079 ->AddTimedSample(instantiation_time);
1080 isolate_->metrics_recorder()->DelayMainThreadEvent(wasm_module_instantiated,
1081 context_id_);
1082 }
1083
1084 return direct_handle(instance_data->instance_object(), isolate_);
1085}
1086
1088 const DisallowJavascriptExecution& no_js) {
1089 // Any trusted pointers created here will be zapped unless instantiation
1090 // successfully runs to completion, to prevent trusted objects that violate
1091 // their own internal invariants because they're only partially-initialized
1092 // from becoming accessible to untrusted code.
1093 // We assume failure for now, and will update to success later.
1094 TrustedPointerPublishingScope publish_trusted_objects(isolate_, no_js);
1095 publish_trusted_objects.MarkFailure();
1096 NativeModule* native_module = module_object_->native_module();
1097
1098 //--------------------------------------------------------------------------
1099 // Create the WebAssembly.Instance object.
1100 //--------------------------------------------------------------------------
1101 TRACE("New module instantiation for %p\n", native_module);
1104 bool shared = module_object_->module()->has_shared_part;
1105 DirectHandle<WasmTrustedInstanceData> shared_trusted_data;
1106 if (shared) {
1107 shared_trusted_data =
1109 trusted_data->set_shared_part(*shared_trusted_data);
1110 }
1111
1112 //--------------------------------------------------------------------------
1113 // Set up the memory buffers and memory objects and attach them to the
1114 // instance.
1115 //--------------------------------------------------------------------------
1116 if (is_asmjs_module(module_)) {
1117 CHECK_EQ(1, module_->memories.size());
1119 if (!asmjs_memory_buffer_.ToHandle(&buffer)) {
1120 // Use an empty JSArrayBuffer for degenerate asm.js modules.
1124 if (!new_buffer.ToHandle(&buffer)) {
1125 thrower_->RangeError("Out of memory: asm.js memory");
1126 return {};
1127 }
1128 buffer->set_is_detachable(false);
1129 }
1130 // asm.js instantiation should have changed the state of the buffer (or we
1131 // set it above).
1132 CHECK(!buffer->is_detachable());
1133
1134 // The maximum number of pages isn't strictly necessary for memory
1135 // objects used for asm.js, as they are never visible, but we might
1136 // as well make it accurate.
1137 auto maximum_pages =
1138 static_cast<int>(RoundUp(buffer->byte_length(), wasm::kWasmPageSize) /
1141 isolate_, buffer, maximum_pages, AddressType::kI32);
1142 constexpr int kMemoryIndexZero = 0;
1143 trusted_data->memory_objects()->set(kMemoryIndexZero, *memory_object);
1144 } else {
1145 CHECK(asmjs_memory_buffer_.is_null());
1147 isolate_};
1148 // First process all imported memories, then allocate non-imported ones.
1150 return {};
1151 }
1152 // Actual Wasm modules can have multiple memories.
1153 static_assert(kV8MaxWasmMemories <= kMaxUInt32);
1154 uint32_t num_memories = static_cast<uint32_t>(module_->memories.size());
1155 for (uint32_t memory_index = 0; memory_index < num_memories;
1156 ++memory_index) {
1157 if (!IsUndefined(memory_objects->get(memory_index))) continue;
1158 DirectHandle<WasmMemoryObject> memory_object;
1159 if (AllocateMemory(memory_index).ToHandle(&memory_object)) {
1160 memory_objects->set(memory_index, *memory_object);
1161 } else {
1163 return {};
1164 }
1165 }
1166 }
1167
1168 //--------------------------------------------------------------------------
1169 // Set up the globals for the new instance.
1170 //--------------------------------------------------------------------------
1171 uint32_t untagged_globals_buffer_size = module_->untagged_globals_buffer_size;
1172 if (untagged_globals_buffer_size > 0) {
1175 untagged_globals_buffer_size, InitializedFlag::kZeroInitialized,
1177
1178 if (!result.ToHandle(&untagged_globals_)) {
1179 thrower_->RangeError("Out of memory: wasm globals");
1180 return {};
1181 }
1182
1183 trusted_data->set_untagged_globals_buffer(*untagged_globals_);
1184 trusted_data->set_globals_start(
1185 reinterpret_cast<uint8_t*>(untagged_globals_->backing_store()));
1186
1187 // TODO(14616): Do this only if we have a shared untagged global.
1188 if (shared) {
1189 MaybeDirectHandle<JSArrayBuffer> shared_result =
1191 untagged_globals_buffer_size, InitializedFlag::kZeroInitialized,
1193
1194 if (!shared_result.ToHandle(&shared_untagged_globals_)) {
1195 thrower_->RangeError("Out of memory: wasm globals");
1196 return {};
1197 }
1198
1199 shared_trusted_data->set_untagged_globals_buffer(
1201 shared_trusted_data->set_globals_start(reinterpret_cast<uint8_t*>(
1202 shared_untagged_globals_->backing_store()));
1203 }
1204 }
1205
1206 uint32_t tagged_globals_buffer_size = module_->tagged_globals_buffer_size;
1207 if (tagged_globals_buffer_size > 0) {
1209 static_cast<int>(tagged_globals_buffer_size));
1210 trusted_data->set_tagged_globals_buffer(*tagged_globals_);
1211 if (shared) {
1213 static_cast<int>(tagged_globals_buffer_size));
1214 shared_trusted_data->set_tagged_globals_buffer(*shared_tagged_globals_);
1215 }
1216 }
1217
1218 //--------------------------------------------------------------------------
1219 // Set up the array of references to imported globals' array buffers.
1220 //--------------------------------------------------------------------------
1221 if (module_->num_imported_mutable_globals > 0) {
1222 // TODO(binji): This allocates one slot for each mutable global, which is
1223 // more than required if multiple globals are imported from the same
1224 // module.
1226 module_->num_imported_mutable_globals, AllocationType::kOld);
1227 trusted_data->set_imported_mutable_globals_buffers(*buffers_array);
1228 if (shared) {
1229 DirectHandle<FixedArray> shared_buffers_array =
1231 module_->num_imported_mutable_globals, AllocationType::kOld);
1232 shared_trusted_data->set_imported_mutable_globals_buffers(
1233 *shared_buffers_array);
1234 }
1235 }
1236
1237 //--------------------------------------------------------------------------
1238 // Set up the tag table used for exception tag checks.
1239 //--------------------------------------------------------------------------
1240 int tags_count = static_cast<int>(module_->tags.size());
1241 if (tags_count > 0) {
1242 DirectHandle<FixedArray> tag_table =
1244 trusted_data->set_tags_table(*tag_table);
1245 tags_wrappers_.resize(tags_count);
1246 if (shared) {
1247 DirectHandle<FixedArray> shared_tag_table =
1249 shared_trusted_data->set_tags_table(*shared_tag_table);
1250 shared_tags_wrappers_.resize(tags_count);
1251 }
1252 }
1253
1254 //--------------------------------------------------------------------------
1255 // Set up table storage space, and initialize it for non-imported tables.
1256 //--------------------------------------------------------------------------
1257 int table_count = static_cast<int>(module_->tables.size());
1258 if (table_count == 0) {
1259 trusted_data->set_tables(*isolate_->factory()->empty_fixed_array());
1260 if (shared) {
1261 shared_trusted_data->set_tables(
1262 *isolate_->factory()->empty_fixed_array());
1263 }
1264 } else {
1266 isolate_->factory()->NewFixedArray(table_count);
1267 DirectHandle<ProtectedFixedArray> dispatch_tables =
1268 isolate_->factory()->NewProtectedFixedArray(table_count);
1269 trusted_data->set_tables(*tables);
1270 trusted_data->set_dispatch_tables(*dispatch_tables);
1271 DirectHandle<FixedArray> shared_tables;
1272 DirectHandle<ProtectedFixedArray> shared_dispatch_tables;
1273 if (shared) {
1274 shared_tables = isolate_->factory()->NewFixedArray(table_count);
1275 shared_dispatch_tables =
1276 isolate_->factory()->NewProtectedFixedArray(table_count);
1277 shared_trusted_data->set_tables(*shared_tables);
1278 shared_trusted_data->set_dispatch_tables(*shared_dispatch_tables);
1279 }
1280 for (int i = module_->num_imported_tables; i < table_count; i++) {
1281 const WasmTable& table = module_->tables[i];
1282 CanonicalValueType canonical_type = module_->canonical_type(table.type);
1283 // Initialize tables with null for now. We will initialize non-defaultable
1284 // tables later, in {SetTableInitialValues}.
1285 DirectHandle<WasmDispatchTable> dispatch_table;
1287 isolate_, table.shared ? shared_trusted_data : trusted_data,
1288 table.type, canonical_type, table.initial_size,
1289 table.has_maximum_size, table.maximum_size,
1290 table.type.use_wasm_null()
1291 ? DirectHandle<HeapObject>{isolate_->factory()->wasm_null()}
1292 : DirectHandle<HeapObject>{isolate_->factory()->null_value()},
1293 table.address_type, &dispatch_table);
1294 (table.shared ? shared_tables : tables)->set(i, *table_obj);
1295 if (!dispatch_table.is_null()) {
1296 (table.shared ? shared_dispatch_tables : dispatch_tables)
1297 ->set(i, *dispatch_table);
1298 if (i == 0) {
1299 (table.shared ? shared_trusted_data : trusted_data)
1300 ->set_dispatch_table0(*dispatch_table);
1301 }
1302 }
1303 }
1304 }
1305
1306 //--------------------------------------------------------------------------
1307 // Process the imports for the module.
1308 //--------------------------------------------------------------------------
1309 if (!module_->import_table.empty()) {
1310 int num_imported_functions =
1311 ProcessImports(trusted_data, shared_trusted_data);
1312 if (num_imported_functions < 0) return {};
1313 }
1314
1315 //--------------------------------------------------------------------------
1316 // Create maps for managed objects (GC proposal).
1317 // Must happen before {InitGlobals} because globals can refer to these maps.
1318 //--------------------------------------------------------------------------
1319 if (!module_->isorecursive_canonical_type_ids.empty()) {
1320 // Make sure all canonical indices have been set.
1321 DCHECK(module_->MaxCanonicalTypeIndex().valid());
1323 isolate_, module_->MaxCanonicalTypeIndex());
1324 }
1326 static_cast<int>(module_->types.size()));
1327 DirectHandle<FixedArray> shared_maps =
1328 shared ? isolate_->factory()->NewFixedArray(
1329 static_cast<int>(module_->types.size()))
1331 for (uint32_t index = 0; index < module_->types.size(); index++) {
1332 bool type_is_shared = module_->types[index].is_shared;
1334 type_is_shared ? shared_maps : non_shared_maps);
1335 }
1336 trusted_data->set_managed_object_maps(*non_shared_maps);
1337 if (shared) shared_trusted_data->set_managed_object_maps(*shared_maps);
1338#if DEBUG
1339 for (uint32_t i = 0; i < module_->types.size(); i++) {
1341 module_->types[i].is_shared ? shared_maps : non_shared_maps;
1342 Tagged<Object> o = maps->get(i);
1343 DCHECK(IsMap(o));
1344 Tagged<Map> map = Cast<Map>(o);
1345 ModuleTypeIndex index{i};
1346 if (module_->has_signature(index)) {
1347 DCHECK_EQ(map->instance_type(), WASM_FUNC_REF_TYPE);
1348 } else if (module_->has_array(index)) {
1349 DCHECK_EQ(map->instance_type(), WASM_ARRAY_TYPE);
1350 } else if (module_->has_struct(index)) {
1351 DCHECK_EQ(map->instance_type(), WASM_STRUCT_TYPE);
1352 }
1353 }
1354#endif
1355
1356 //--------------------------------------------------------------------------
1357 // Allocate the array that will hold type feedback vectors.
1358 //--------------------------------------------------------------------------
1359 if (v8_flags.wasm_inlining) {
1360 int num_functions = static_cast<int>(module_->num_declared_functions);
1361 // Zero-fill the array so we can do a quick Smi-check to test if a given
1362 // slot was initialized.
1363 DirectHandle<FixedArray> vectors =
1364 isolate_->factory()->NewFixedArrayWithZeroes(num_functions,
1366 trusted_data->set_feedback_vectors(*vectors);
1367 if (shared) {
1368 DirectHandle<FixedArray> shared_vectors =
1369 isolate_->factory()->NewFixedArrayWithZeroes(num_functions,
1371 shared_trusted_data->set_feedback_vectors(*shared_vectors);
1372 }
1373 }
1374
1375 //--------------------------------------------------------------------------
1376 // Process the initialization for the module's globals.
1377 //--------------------------------------------------------------------------
1378 InitGlobals(trusted_data, shared_trusted_data);
1379
1380 //--------------------------------------------------------------------------
1381 // Initialize non-defaultable tables.
1382 //--------------------------------------------------------------------------
1383 SetTableInitialValues(trusted_data, shared_trusted_data);
1384
1385 //--------------------------------------------------------------------------
1386 // Initialize the tags table.
1387 //--------------------------------------------------------------------------
1388 if (tags_count > 0) {
1390 }
1391
1392 //--------------------------------------------------------------------------
1393 // Set up the exports object for the new instance.
1394 //--------------------------------------------------------------------------
1395 ProcessExports(trusted_data, shared_trusted_data);
1396 if (thrower_->error()) return {};
1397
1398 //--------------------------------------------------------------------------
1399 // Set up uninitialized element segments.
1400 //--------------------------------------------------------------------------
1401 if (!module_->elem_segments.empty()) {
1403 static_cast<int>(module_->elem_segments.size()));
1404 DirectHandle<FixedArray> shared_elements =
1405 shared ? isolate_->factory()->NewFixedArray(
1406 static_cast<int>(module_->elem_segments.size()))
1408 for (uint32_t i = 0; i < module_->elem_segments.size(); i++) {
1409 // Initialize declarative segments as empty. The rest remain
1410 // uninitialized.
1411 bool is_declarative = module_->elem_segments[i].status ==
1413 (module_->elem_segments[i].shared ? shared_elements : elements)
1414 ->set(i, is_declarative
1415 ? Cast<Object>(*isolate_->factory()->empty_fixed_array())
1416 : *isolate_->factory()->undefined_value());
1417 }
1418 trusted_data->set_element_segments(*elements);
1419 if (shared) shared_trusted_data->set_element_segments(*shared_elements);
1420 }
1421
1422 //--------------------------------------------------------------------------
1423 // Create a wrapper for the start function.
1424 //--------------------------------------------------------------------------
1425 if (module_->start_function_index >= 0) {
1426 int start_index = module_->start_function_index;
1427 auto& function = module_->functions[start_index];
1428
1429 DCHECK(start_function_.is_null());
1430 if (function.imported) {
1431 ImportedFunctionEntry entry(trusted_data, module_->start_function_index);
1432 Tagged<Object> callable = entry.maybe_callable();
1433 if (IsJSFunction(callable)) {
1434 // If the start function was imported and calls into Blink, we have
1435 // to pretend that the V8 API was used to enter its correct context.
1436 // In order to simplify entering the context in {ExecuteStartFunction}
1437 // below, we just record the callable as the start function.
1439 }
1440 }
1441 if (start_function_.is_null()) {
1442 // TODO(clemensb): Don't generate an exported function for the start
1443 // function. Use CWasmEntry instead.
1444 bool function_is_shared = module_->type(function.sig_index).is_shared;
1445 DirectHandle<WasmFuncRef> func_ref =
1447 isolate_, function_is_shared ? shared_trusted_data : trusted_data,
1448 start_index);
1450 isolate_};
1452 }
1453 }
1454
1456 TRACE("Successfully built instance for module %p\n",
1457 module_object_->native_module());
1458
1459#if V8_ENABLE_DRUMBRAKE
1460 // Skip this event because not (yet) supported by Chromium.
1461
1462 // v8::metrics::WasmInterpreterJitStatus jit_status;
1463 // jit_status.jitless = v8_flags.wasm_jitless;
1464 // isolate_->metrics_recorder()->DelayMainThreadEvent(jit_status,
1465 // context_id_);
1466#endif // V8_ENABLE_DRUMBRAKE
1467
1468 publish_trusted_objects.MarkSuccess();
1469 Build_Phase1_Infallible(trusted_data, shared_trusted_data);
1470 return trusted_data;
1471}
1472
1475 DirectHandle<WasmTrustedInstanceData> shared_trusted_data) {
1476 //--------------------------------------------------------------------------
1477 // Register with memories.
1478 //--------------------------------------------------------------------------
1479 size_t num_memories = module_->memories.size();
1481 isolate_};
1482 for (uint32_t i = 0; i < num_memories; i++) {
1486 shared_trusted_data, i);
1487 }
1488
1489 //--------------------------------------------------------------------------
1490 // Register with tables.
1491 //--------------------------------------------------------------------------
1492 size_t num_tables = module_->tables.size();
1493 for (uint32_t i = 0; i < num_tables; i++) {
1494 const WasmTable& table = module_->tables[i];
1496 table.shared ? shared_trusted_data : trusted_data;
1497 Tagged<Object> maybe_dispatch_table = data_part->dispatch_tables()->get(i);
1498 if (maybe_dispatch_table == Smi::zero()) continue; // Not a function table.
1499 DirectHandle<WasmDispatchTable> dispatch_table{
1500 Cast<WasmDispatchTable>(maybe_dispatch_table), isolate_};
1501 WasmDispatchTable::AddUse(isolate_, dispatch_table, data_part, i);
1502 }
1503}
1504
1507 DirectHandle<WasmTrustedInstanceData> shared_trusted_data;
1508 if (module_->has_shared_part) {
1509 shared_trusted_data = direct_handle(trusted_data->shared_part(), isolate_);
1510 }
1511
1512 //--------------------------------------------------------------------------
1513 // Load element segments into tables.
1514 //--------------------------------------------------------------------------
1515 if (module_->tables.size() > 0) {
1516 LoadTableSegments(trusted_data, shared_trusted_data);
1517 if (thrower_->error()) return {};
1518 }
1519
1520 //--------------------------------------------------------------------------
1521 // Initialize the memory by loading data segments.
1522 //--------------------------------------------------------------------------
1523 if (!module_->data_segments.empty()) {
1524 LoadDataSegments(trusted_data, shared_trusted_data);
1525 if (thrower_->error()) return {};
1526 }
1527
1528 return trusted_data;
1529}
1530
1532 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
1533 "wasm.ExecuteStartFunction");
1534 if (start_function_.is_null()) return true; // No start function.
1535
1536 HandleScope scope(isolate_);
1537 // In case the start function calls out to Blink, we have to make sure that
1538 // the correct "entered context" is available. This is the equivalent of
1539 // v8::Context::Enter() and must happen in addition to the function call
1540 // sequence doing the compiled version of "isolate->set_context(...)".
1542 hsi->EnterContext(start_function_->native_context());
1543
1544 // Call the JS function.
1545 DirectHandle<Object> undefined = isolate_->factory()->undefined_value();
1547 Execution::Call(isolate_, start_function_, undefined, {});
1548 hsi->LeaveContext();
1549 // {start_function_} has to be called only once.
1550 start_function_ = {};
1551
1552 if (retval.is_null()) {
1554 return false;
1555 }
1556 return true;
1557}
1558
1559// Look up an import value in the {ffi_} object.
1561 uint32_t index, DirectHandle<String> module_name,
1562 DirectHandle<String> import_name) {
1563 // The caller checked that the ffi object is present; and we checked in
1564 // the JS-API layer that the ffi object, if present, is a JSObject.
1565 DCHECK(!ffi_.is_null());
1566 // Look up the module first.
1567 DirectHandle<Object> module;
1568 DirectHandle<JSReceiver> module_recv;
1569 if (!Object::GetPropertyOrElement(isolate_, ffi_.ToHandleChecked(),
1570 module_name)
1571 .ToHandle(&module) ||
1572 !TryCast<JSReceiver>(module, &module_recv)) {
1573 const char* error = module.is_null()
1574 ? "module not found"
1575 : "module is not an object or function";
1576 thrower_->TypeError("%s: %s", ImportName(index, module_name).c_str(),
1577 error);
1578 return {};
1579 }
1580
1582 Object::GetPropertyOrElement(isolate_, module_recv, import_name);
1583 if (value.is_null()) {
1584 thrower_->LinkError("%s: import not found", ImportName(index).c_str());
1585 return {};
1586 }
1587
1588 return value;
1589}
1590
1591namespace {
1592bool HasDefaultToNumberBehaviour(Isolate* isolate,
1593 DirectHandle<JSFunction> function) {
1594 // Disallow providing a [Symbol.toPrimitive] member.
1595 LookupIterator to_primitive_it{isolate, function,
1596 isolate->factory()->to_primitive_symbol()};
1597 if (to_primitive_it.state() != LookupIterator::NOT_FOUND) return false;
1598
1599 // The {valueOf} member must be the default "ObjectPrototypeValueOf".
1600 LookupIterator value_of_it{isolate, function,
1601 isolate->factory()->valueOf_string()};
1602 if (value_of_it.state() != LookupIterator::DATA) return false;
1603 DirectHandle<Object> value_of = value_of_it.GetDataValue();
1604 if (!IsJSFunction(*value_of)) return false;
1605 Builtin value_of_builtin_id =
1606 Cast<JSFunction>(value_of)->code(isolate)->builtin_id();
1607 if (value_of_builtin_id != Builtin::kObjectPrototypeValueOf) return false;
1608
1609 // The {toString} member must be the default "FunctionPrototypeToString".
1610 LookupIterator to_string_it{isolate, function,
1611 isolate->factory()->toString_string()};
1612 if (to_string_it.state() != LookupIterator::DATA) return false;
1613 DirectHandle<Object> to_string = to_string_it.GetDataValue();
1614 if (!IsJSFunction(*to_string)) return false;
1615 Builtin to_string_builtin_id =
1616 Cast<JSFunction>(to_string)->code(isolate)->builtin_id();
1617 if (to_string_builtin_id != Builtin::kFunctionPrototypeToString) return false;
1618
1619 // Just a default function, which will convert to "Nan". Accept this.
1620 return true;
1621}
1622
1623bool MaybeMarkError(ValueOrError value, ErrorThrower* thrower) {
1624 if (is_error(value)) {
1625 thrower->RuntimeError("%s",
1627 return true;
1628 }
1629 return false;
1630}
1631} // namespace
1632
1633// Look up an import value in the {ffi_} object specifically for linking an
1634// asm.js module. This only performs non-observable lookups, which allows
1635// falling back to JavaScript proper (and hence re-executing all lookups) if
1636// module instantiation fails.
1638 uint32_t index, DirectHandle<String> import_name) {
1639 // The caller checked that the ffi object is present.
1640 DCHECK(!ffi_.is_null());
1641
1642 // Perform lookup of the given {import_name} without causing any observable
1643 // side-effect. We only accept accesses that resolve to data properties,
1644 // which is indicated by the asm.js spec in section 7 ("Linking") as well.
1645 PropertyKey key(isolate_, Cast<Name>(import_name));
1646 LookupIterator it(isolate_, ffi_.ToHandleChecked(), key);
1647 switch (it.state()) {
1655 thrower_->LinkError("%s: not a data property",
1656 ImportName(index, import_name).c_str());
1657 return {};
1659 // Accepting missing properties as undefined does not cause any
1660 // observable difference from JavaScript semantics, we are lenient.
1661 return isolate_->factory()->undefined_value();
1662 case LookupIterator::DATA: {
1663 DirectHandle<Object> value = it.GetDataValue();
1664 // For legacy reasons, we accept functions for imported globals (see
1665 // {ProcessImportedGlobal}), but only if we can easily determine that
1666 // their Number-conversion is side effect free and returns NaN (which is
1667 // the case as long as "valueOf" (or others) are not overwritten).
1668 if (IsJSFunction(*value) &&
1669 module_->import_table[index].kind == kExternalGlobal &&
1670 !HasDefaultToNumberBehaviour(isolate_, Cast<JSFunction>(value))) {
1671 thrower_->LinkError("%s: function has special ToNumber behaviour",
1672 ImportName(index, import_name).c_str());
1673 return {};
1674 }
1675 return value;
1676 }
1677 }
1678}
1679
1680// Load data segments into the memory.
1681// TODO(14616): Consider what to do with shared memories.
1683 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
1684 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data) {
1685 base::Vector<const uint8_t> wire_bytes =
1686 module_object_->native_module()->wire_bytes();
1687 for (const WasmDataSegment& segment : module_->data_segments) {
1688 uint32_t size = segment.source.length();
1689
1690 // Passive segments are not copied during instantiation.
1691 if (!segment.active) continue;
1692
1693 const WasmMemory& dst_memory = module_->memories[segment.memory_index];
1694 size_t dest_offset;
1696 &init_expr_zone_, segment.dest_addr,
1697 dst_memory.is_memory64() ? kWasmI64 : kWasmI32, module_, isolate_,
1698 trusted_instance_data, shared_trusted_instance_data);
1699 if (MaybeMarkError(result, thrower_)) return;
1700 if (dst_memory.is_memory64()) {
1701 uint64_t dest_offset_64 = to_value(result).to_u64();
1702
1703 // Clamp to {std::numeric_limits<size_t>::max()}, which is always an
1704 // invalid offset, so we always fail the bounds check below.
1705 DCHECK_GT(std::numeric_limits<size_t>::max(), dst_memory.max_memory_size);
1706 dest_offset = static_cast<size_t>(std::min(
1707 dest_offset_64, uint64_t{std::numeric_limits<size_t>::max()}));
1708 } else {
1709 dest_offset = to_value(result).to_u32();
1710 }
1711
1712 size_t memory_size =
1713 trusted_instance_data->memory_size(segment.memory_index);
1714 if (!base::IsInBounds<size_t>(dest_offset, size, memory_size)) {
1715 size_t segment_index = &segment - module_->data_segments.data();
1716 thrower_->RuntimeError(
1717 "data segment %zu is out of bounds (offset %zu, "
1718 "length %u, memory size %zu)",
1719 segment_index, dest_offset, size, memory_size);
1720 return;
1721 }
1722
1723 uint8_t* memory_base =
1724 trusted_instance_data->memory_base(segment.memory_index);
1725 std::memcpy(memory_base + dest_offset,
1726 wire_bytes.begin() + segment.source.offset(), size);
1727 }
1728}
1729
1731 const WasmValue& value) {
1732 TRACE("init [globals_start=%p + %u] = %s, type = %s\n",
1733 global.type.is_reference()
1734 ? reinterpret_cast<uint8_t*>(tagged_globals_->address())
1735 : raw_buffer_ptr(untagged_globals_, 0),
1736 global.offset, value.to_string().c_str(), global.type.name().c_str());
1737 DCHECK(global.mutability
1738 ? (value.type() == module_->canonical_type(global.type))
1739 : IsSubtypeOf(value.type(), module_->canonical_type(global.type)));
1740 if (global.type.is_numeric()) {
1741 value.CopyTo(GetRawUntaggedGlobalPtr<uint8_t>(global));
1742 } else {
1743 tagged_globals_->set(global.offset, *value.to_ref());
1744 }
1745}
1746
1747// Returns the name, Builtin ID, and "length" (in the JSFunction sense, i.e.
1748// number of parameters) for the function representing the given import.
1749std::tuple<const char*, Builtin, int> NameBuiltinLength(WellKnownImport wki) {
1750#define CASE(CamelName, name, length) \
1751 case WellKnownImport::kString##CamelName: \
1752 return std::make_tuple(name, Builtin::kWebAssemblyString##CamelName, length)
1753 switch (wki) {
1754 CASE(Cast, "cast", 1);
1755 CASE(CharCodeAt, "charCodeAt", 2);
1756 CASE(CodePointAt, "codePointAt", 2);
1757 CASE(Compare, "compare", 2);
1758 CASE(Concat, "concat", 2);
1759 CASE(Equals, "equals", 2);
1760 CASE(FromCharCode, "fromCharCode", 1);
1761 CASE(FromCodePoint, "fromCodePoint", 1);
1762 CASE(FromUtf8Array, "decodeStringFromUTF8Array", 3);
1763 CASE(FromWtf16Array, "fromCharCodeArray", 3);
1764 CASE(IntoUtf8Array, "encodeStringIntoUTF8Array", 3);
1765 CASE(Length, "length", 1);
1766 CASE(MeasureUtf8, "measureStringAsUTF8", 1);
1767 CASE(Substring, "substring", 3);
1768 CASE(Test, "test", 1);
1769 CASE(ToUtf8Array, "encodeStringToUTF8Array", 1);
1770 CASE(ToWtf16Array, "intoCharCodeArray", 3);
1771 default:
1772 UNREACHABLE(); // Only call this for compile-time imports.
1773 }
1774#undef CASE
1775}
1776
1778 Isolate* isolate, WellKnownImport wki) {
1779 auto [name, builtin, length] = NameBuiltinLength(wki);
1780 Factory* factory = isolate->factory();
1781 DirectHandle<NativeContext> context(isolate->native_context());
1782 DirectHandle<Map> map = isolate->strict_function_without_prototype_map();
1783 DirectHandle<String> name_str = factory->InternalizeUtf8String(name);
1785 factory->NewSharedFunctionInfoForBuiltin(name_str, builtin, length,
1786 kAdapt);
1787 info->set_native(true);
1788 info->set_language_mode(LanguageMode::kStrict);
1791 return fun;
1792}
1793
1795 NativeModule* native_module = module_object_->native_module();
1796 base::Vector<const uint8_t> wire_bytes = native_module->wire_bytes();
1797 const WellKnownImportsList& well_known_imports =
1798 module_->type_feedback.well_known_imports;
1799 const std::string& magic_string_constants =
1800 native_module->compile_imports().constants_module();
1801 const bool has_magic_string_constants =
1802 native_module->compile_imports().contains(
1804 for (uint32_t index = 0; index < module_->import_table.size(); ++index) {
1805 const WasmImport& import = module_->import_table[index];
1806
1807 if (import.kind == kExternalGlobal && has_magic_string_constants &&
1808 import.module_name.length() == magic_string_constants.size() &&
1809 std::equal(magic_string_constants.begin(), magic_string_constants.end(),
1810 wire_bytes.begin() + import.module_name.offset())) {
1811 DirectHandle<String> value =
1813 isolate_, wire_bytes, import.field_name, kNoInternalize);
1814 sanitized_imports_.push_back(value);
1815 continue;
1816 }
1817
1818 if (import.kind == kExternalFunction) {
1819 WellKnownImport wki = well_known_imports.get(import.index);
1820 if (IsCompileTimeImport(wki)) {
1823 sanitized_imports_.push_back(fun);
1824 continue;
1825 }
1826 }
1827
1828 if (ffi_.is_null()) {
1829 // No point in continuing if we don't have an imports object.
1830 thrower_->TypeError(
1831 "Imports argument must be present and must be an object");
1832 return;
1833 }
1834
1835 DirectHandle<String> module_name =
1837 isolate_, wire_bytes, import.module_name, kInternalize);
1838
1839 DirectHandle<String> import_name =
1841 isolate_, wire_bytes, import.field_name, kInternalize);
1842
1845 ? LookupImportAsm(index, import_name)
1846 : LookupImport(index, module_name, import_name);
1847 if (thrower_->error()) {
1848 return;
1849 }
1850 DirectHandle<Object> value = result.ToHandleChecked();
1851 sanitized_imports_.push_back(value);
1852 }
1853}
1854
1856 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
1857 int import_index, int func_index, DirectHandle<Object> value,
1858 WellKnownImport preknown_import) {
1859 // Function imports must be callable.
1860 if (!IsCallable(*value)) {
1861 if (!IsWasmSuspendingObject(*value)) {
1862 thrower_->LinkError("%s: function import requires a callable",
1863 ImportName(import_index).c_str());
1864 return false;
1865 }
1866 DCHECK(IsCallable(Cast<WasmSuspendingObject>(*value)->callable()));
1867 }
1868 // Store any {WasmExternalFunction} callable in the instance before the call
1869 // is resolved to preserve its identity. This handles exported functions as
1870 // well as functions constructed via other means (e.g. WebAssembly.Function).
1872 trusted_instance_data->func_refs()->set(
1873 func_index, Cast<WasmExternalFunction>(*value)->func_ref());
1874 }
1875 auto js_receiver = Cast<JSReceiver>(value);
1876 CanonicalTypeIndex sig_index =
1877 module_->canonical_sig_id(module_->functions[func_index].sig_index);
1878 const CanonicalSig* expected_sig =
1880 ResolvedWasmImport resolved(trusted_instance_data, func_index, js_receiver,
1881 expected_sig, sig_index, preknown_import);
1882 if (resolved.well_known_status() != WellKnownImport::kGeneric &&
1883 v8_flags.trace_wasm_inlining) {
1884 PrintF("[import %d is well-known built-in %s]\n", import_index,
1886 }
1887 well_known_imports_.push_back(resolved.well_known_status());
1888 ImportCallKind kind = resolved.kind();
1889 js_receiver = resolved.callable();
1890 DirectHandle<WasmFunctionData> trusted_function_data =
1891 resolved.trusted_function_data();
1892 ImportedFunctionEntry imported_entry(trusted_instance_data, func_index);
1893 switch (kind) {
1895 imported_entry.SetGenericWasmToJs(
1896 isolate_, js_receiver, resolved.suspend(), expected_sig, sig_index);
1897 break;
1899 thrower_->LinkError(
1900 "%s: imported function does not match the expected type",
1901 ImportName(import_index).c_str());
1902 return false;
1904 // The imported function is a Wasm function from another instance.
1905 auto function_data =
1906 Cast<WasmExportedFunctionData>(trusted_function_data);
1907 // The import reference is the trusted instance data itself.
1909 function_data->instance_data();
1910 CHECK_GE(function_data->function_index(),
1911 instance_data->module()->num_imported_functions);
1912 WasmCodePointer imported_target =
1913 instance_data->GetCallTarget(function_data->function_index());
1914 imported_entry.SetWasmToWasm(instance_data, imported_target, sig_index
1915#if V8_ENABLE_DRUMBRAKE
1916 ,
1917 function_data->function_index()
1918#endif // V8_ENABLE_DRUMBRAKE
1919 );
1920 break;
1921 }
1923 int expected_arity = static_cast<int>(expected_sig->parameter_count());
1925 WasmCodeRefScope code_ref_scope;
1926 WasmCode* wasm_code =
1927 cache->MaybeGet(kind, sig_index, expected_arity, kNoSuspend);
1928 if (wasm_code == nullptr) {
1929 {
1933 WasmImportWrapperCache::CacheKey key(kind, sig_index, expected_arity,
1934 kNoSuspend);
1935 wasm_code = cache_scope.AddWrapper(key, std::move(result),
1937 expected_sig->signature_hash());
1938 }
1939 // To avoid lock order inversion, code printing must happen after the
1940 // end of the {cache_scope}.
1941 wasm_code->MaybePrint();
1942 isolate_->counters()->wasm_generated_code_size()->Increment(
1943 wasm_code->instructions().length());
1944 isolate_->counters()->wasm_reloc_size()->Increment(
1945 wasm_code->reloc_info().length());
1946 }
1947
1948 // We reuse the SetCompiledWasmToJs infrastructure because it passes the
1949 // callable to the wrapper, which we need to get the function data.
1950 imported_entry.SetCompiledWasmToJs(isolate_, js_receiver, wasm_code,
1951 kNoSuspend, expected_sig, sig_index);
1952 break;
1953 }
1955 DCHECK(IsJSFunction(*js_receiver) || IsJSBoundFunction(*js_receiver));
1956 WasmCodeRefScope code_ref_scope;
1957 // Note: the wrapper we're about to compile is specific to this
1958 // instantiation, so it cannot be shared. However, its lifetime must
1959 // be managed by the WasmImportWrapperCache, so that it can be used
1960 // in WasmDispatchTables whose lifetime might exceed that of this
1961 // instance's NativeModule.
1962 // So the {CacheKey} is a dummy, and we don't look for an existing
1963 // wrapper. Key collisions are not a concern because lifetimes are
1964 // determined by refcounting.
1966 compiler::CompileWasmJSFastCallWrapper(expected_sig, js_receiver);
1967 WasmCode* wasm_code;
1968 {
1972 0, kNoSuspend);
1973 wasm_code = cache_scope.AddWrapper(dummy_key, std::move(result),
1975 expected_sig->signature_hash());
1976 }
1977 // To avoid lock order inversion, code printing must happen after the
1978 // end of the {cache_scope}.
1979 wasm_code->MaybePrint();
1980 imported_entry.SetCompiledWasmToJs(isolate_, js_receiver, wasm_code,
1981 kNoSuspend, expected_sig, sig_index);
1982 break;
1983 }
1984 default: {
1985 // The imported function is a callable.
1986 if (UseGenericWasmToJSWrapper(kind, expected_sig, resolved.suspend())) {
1989 imported_entry.SetGenericWasmToJs(
1990 isolate_, js_receiver, resolved.suspend(), expected_sig, sig_index);
1991 break;
1992 }
1993 if (v8_flags.wasm_jitless) {
1994 WasmCode* no_code = nullptr;
1995 imported_entry.SetCompiledWasmToJs(isolate_, js_receiver, no_code,
1996 resolved.suspend(), expected_sig,
1997 sig_index);
1998 break;
1999 }
2000 int expected_arity = static_cast<int>(expected_sig->parameter_count());
2002 auto function = Cast<JSFunction>(js_receiver);
2003 Tagged<SharedFunctionInfo> shared = function->shared();
2004 expected_arity =
2005 shared->internal_formal_parameter_count_without_receiver();
2006 }
2007
2009 WasmCodeRefScope code_ref_scope;
2010 WasmCode* wasm_code =
2011 cache->MaybeGet(kind, sig_index, expected_arity, resolved.suspend());
2012 if (!wasm_code) {
2013 // This should be a very rare fallback case. We expect that the
2014 // generic wrapper will be used (see above).
2015 bool source_positions =
2016 is_asmjs_module(trusted_instance_data->module());
2017 wasm_code = cache->CompileWasmImportCallWrapper(
2018 isolate_, kind, expected_sig, sig_index, source_positions,
2019 expected_arity, resolved.suspend());
2020 }
2021
2022 DCHECK_NOT_NULL(wasm_code);
2024 // Wasm to JS wrappers are treated specially in the import table.
2025 imported_entry.SetCompiledWasmToJs(isolate_, js_receiver, wasm_code,
2026 resolved.suspend(), expected_sig,
2027 sig_index);
2028 break;
2029 }
2030 }
2031 return true;
2032}
2033
2035 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
2036 int import_index, int table_index, DirectHandle<Object> value) {
2037 if (!IsWasmTableObject(*value)) {
2038 thrower_->LinkError("%s: table import requires a WebAssembly.Table",
2039 ImportName(import_index).c_str());
2040 return false;
2041 }
2042 const WasmTable& table = module_->tables[table_index];
2043
2045
2046 uint32_t imported_table_size =
2047 static_cast<uint32_t>(table_object->current_length());
2048 if (imported_table_size < table.initial_size) {
2049 thrower_->LinkError("table import %d is smaller than initial %u, got %u",
2050 import_index, table.initial_size, imported_table_size);
2051 return false;
2052 }
2053
2054 if (table.has_maximum_size) {
2055 std::optional<uint64_t> max_size = table_object->maximum_length_u64();
2056 if (!max_size) {
2057 thrower_->LinkError(
2058 "table import %d has no maximum length; required: %" PRIu64,
2059 import_index, table.maximum_size);
2060 return false;
2061 }
2062 if (*max_size > table.maximum_size) {
2063 thrower_->LinkError("table import %d has a larger maximum size %" PRIx64
2064 " than the module's declared maximum %" PRIu64,
2065 import_index, *max_size, table.maximum_size);
2066 return false;
2067 }
2068 }
2069
2070 if (table.address_type != table_object->address_type()) {
2071 thrower_->LinkError("cannot import %s table as %s",
2072 AddressTypeToStr(table_object->address_type()),
2073 AddressTypeToStr(table.address_type));
2074 return false;
2075 }
2076
2077 const WasmModule* table_type_module =
2078 table_object->has_trusted_data()
2079 ? table_object->trusted_data(isolate_)->module()
2080 : nullptr;
2081 // The security-relevant aspect of this DCHECK is covered by the SBXCHECK_EQ
2082 // below.
2083 DCHECK_IMPLIES(table_object->unsafe_type().has_index(),
2084 table_type_module != nullptr);
2085
2086 // We need to check type equivalence (rather than subtyping) because tables
2087 // are mutable: we cannot allow the importing module to write supertyped
2088 // values into a subtyped table.
2089 if (!EquivalentTypes(table.type, table_object->type(table_type_module),
2090 module_, table_type_module)) {
2091 thrower_->LinkError("%s: imported table does not match the expected type",
2092 ImportName(import_index).c_str());
2093 return false;
2094 }
2095
2096 // Note: {trusted_instance_data} is selected by the caller to be the
2097 // shared or non-shared part, depending on {table.shared}.
2098 trusted_instance_data->tables()->set(table_index, *table_object);
2099 if (table_object->has_trusted_dispatch_table()) {
2100 Tagged<WasmDispatchTable> dispatch_table =
2101 table_object->trusted_dispatch_table(isolate_);
2102 SBXCHECK_EQ(dispatch_table->table_type(),
2103 module_->canonical_type(table.type));
2104 SBXCHECK_GE(dispatch_table->length(), table.initial_size);
2105 trusted_instance_data->dispatch_tables()->set(table_index, dispatch_table);
2106 if (table_index == 0) {
2107 trusted_instance_data->set_dispatch_table0(dispatch_table);
2108 }
2109 } else {
2110 // Function tables are required to have a WasmDispatchTable.
2111 SBXCHECK(!IsSubtypeOf(table.type, kWasmFuncRef, module_));
2112 }
2113 return true;
2114}
2115
2117 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
2118 int import_index, const WasmGlobal& global,
2119 DirectHandle<WasmGlobalObject> global_object) {
2120 if (static_cast<bool>(global_object->is_mutable()) != global.mutability) {
2121 thrower_->LinkError(
2122 "%s: imported global does not match the expected mutability",
2123 ImportName(import_index).c_str());
2124 return false;
2125 }
2126
2127 wasm::ValueType actual_type = global_object->type();
2128 const WasmModule* source_module = nullptr;
2129 if (global_object->has_trusted_data()) {
2130 source_module = global_object->trusted_data(isolate_)->module();
2131 SBXCHECK(!actual_type.has_index() ||
2132 source_module->has_type(actual_type.ref_index()));
2133 } else {
2134 // We don't have a module, so we wouldn't know what to do with a
2135 // module-relative type index.
2136 // Note: since we just read a type from the untrusted heap, this can't
2137 // be a real security boundary; we just use SBXCHECK to make it obvious
2138 // to fuzzers that crashing here due to corruption is safe.
2139 SBXCHECK(!actual_type.has_index());
2140 }
2141
2142 bool valid_type =
2143 global.mutability
2144 ? EquivalentTypes(actual_type, global.type, source_module, module_)
2145 : IsSubtypeOf(actual_type, global.type, source_module, module_);
2146
2147 if (!valid_type) {
2148 thrower_->LinkError("%s: imported global does not match the expected type",
2149 ImportName(import_index).c_str());
2150 return false;
2151 }
2152 if (global.mutability) {
2153 DCHECK_LT(global.index, module_->num_imported_mutable_globals);
2154 DirectHandle<Object> buffer;
2155 if (global.type.is_reference()) {
2156 static_assert(sizeof(global_object->offset()) <= sizeof(Address),
2157 "The offset into the globals buffer does not fit into "
2158 "the imported_mutable_globals array");
2159 buffer = direct_handle(global_object->tagged_buffer(), isolate_);
2160 // For externref globals we use a relative offset, not an absolute
2161 // address.
2162 trusted_instance_data->imported_mutable_globals()->set(
2163 global.index, global_object->offset());
2164 } else {
2165 buffer = direct_handle(global_object->untagged_buffer(), isolate_);
2166 // It is safe in this case to store the raw pointer to the buffer
2167 // since the backing store of the JSArrayBuffer will not be
2168 // relocated.
2169 Address address = reinterpret_cast<Address>(
2170 raw_buffer_ptr(Cast<JSArrayBuffer>(buffer), global_object->offset()));
2171 trusted_instance_data->imported_mutable_globals()->set_sandboxed_pointer(
2172 global.index, address);
2173 }
2174 trusted_instance_data->imported_mutable_globals_buffers()->set(global.index,
2175 *buffer);
2176 return true;
2177 }
2178
2180 switch (global.type.kind()) {
2181 case kI32:
2182 value = WasmValue(global_object->GetI32());
2183 break;
2184 case kI64:
2185 value = WasmValue(global_object->GetI64());
2186 break;
2187 case kF32:
2188 value = WasmValue(global_object->GetF32());
2189 break;
2190 case kF64:
2191 value = WasmValue(global_object->GetF64());
2192 break;
2193 case kS128:
2194 value = WasmValue(global_object->GetS128RawBytes(), kWasmS128);
2195 break;
2196 case kRef:
2197 case kRefNull:
2198 value = WasmValue(global_object->GetRef(),
2199 module_->canonical_type(global.type));
2200 break;
2201 case kVoid:
2202 case kTop:
2203 case kBottom:
2204 case kI8:
2205 case kI16:
2206 case kF16:
2207 UNREACHABLE();
2208 }
2209
2210 WriteGlobalValue(global, value);
2211 return true;
2212}
2213
2215 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
2216 int import_index, int global_index, DirectHandle<Object> value) {
2217 // Immutable global imports are converted to numbers and written into
2218 // the {untagged_globals_} array buffer.
2219 //
2220 // Mutable global imports instead have their backing array buffers
2221 // referenced by this instance, and store the address of the imported
2222 // global in the {imported_mutable_globals_} array.
2223 const WasmGlobal& global = module_->globals[global_index];
2224
2225 // SIMD proposal allows modules to define an imported v128 global, and only
2226 // supports importing a WebAssembly.Global object for this global, but also
2227 // defines constructing a WebAssembly.Global of v128 to be a TypeError.
2228 // We *should* never hit this case in the JS API, but the module should should
2229 // be allowed to declare such a global (no validation error).
2230 if (global.type == kWasmS128 && !IsWasmGlobalObject(*value)) {
2231 thrower_->LinkError(
2232 "%s: global import of type v128 must be a WebAssembly.Global",
2233 ImportName(import_index).c_str());
2234 return false;
2235 }
2236
2237 if (is_asmjs_module(module_)) {
2238 // Accepting {JSFunction} on top of just primitive values here is a
2239 // workaround to support legacy asm.js code with broken binding. Note
2240 // that using {NaN} (or Smi::zero()) here is what using the observable
2241 // conversion via {ToPrimitive} would produce as well. {LookupImportAsm}
2242 // checked via {HasDefaultToNumberBehaviour} that "valueOf" or friends have
2243 // not been patched.
2244 if (IsJSFunction(*value)) value = isolate_->factory()->nan_value();
2245 if (IsPrimitive(*value)) {
2246 MaybeDirectHandle<Object> converted =
2247 global.type == kWasmI32 ? Object::ToInt32(isolate_, value)
2248 : Object::ToNumber(isolate_, value);
2249 if (!converted.ToHandle(&value)) {
2250 // Conversion is known to fail for Symbols and BigInts.
2251 thrower_->LinkError("%s: global import must be a number",
2252 ImportName(import_index).c_str());
2253 return false;
2254 }
2255 }
2256 }
2257
2258 if (IsWasmGlobalObject(*value)) {
2259 auto global_object = Cast<WasmGlobalObject>(value);
2260 return ProcessImportedWasmGlobalObject(trusted_instance_data, import_index,
2261 global, global_object);
2262 }
2263
2264 if (global.mutability) {
2265 thrower_->LinkError(
2266 "%s: imported mutable global must be a WebAssembly.Global object",
2267 ImportName(import_index).c_str());
2268 return false;
2269 }
2270
2271 if (global.type.is_reference()) {
2272 const char* error_message;
2273 DirectHandle<Object> wasm_value;
2274 if (!wasm::JSToWasmObject(isolate_, module_, value, global.type,
2275 &error_message)
2276 .ToHandle(&wasm_value)) {
2277 thrower_->LinkError("%s: %s", ImportName(import_index).c_str(),
2278 error_message);
2279 return false;
2280 }
2282 global, WasmValue(wasm_value, module_->canonical_type(global.type)));
2283 return true;
2284 }
2285
2286 if (IsNumber(*value) && global.type != kWasmI64) {
2287 double number_value = Object::NumberValue(*value);
2288 // The Wasm-BigInt proposal currently says that i64 globals may
2289 // only be initialized with BigInts. See:
2290 // https://github.com/WebAssembly/JS-BigInt-integration/issues/12
2291 WasmValue wasm_value =
2292 global.type == kWasmI32 ? WasmValue(DoubleToInt32(number_value))
2293 : global.type == kWasmF32 ? WasmValue(DoubleToFloat32(number_value))
2294 : WasmValue(number_value);
2295 WriteGlobalValue(global, wasm_value);
2296 return true;
2297 }
2298
2299 if (global.type == kWasmI64 && IsBigInt(*value)) {
2300 WriteGlobalValue(global, WasmValue(Cast<BigInt>(*value)->AsInt64()));
2301 return true;
2302 }
2303
2304 thrower_->LinkError(
2305 "%s: global import must be a number, valid Wasm reference, or "
2306 "WebAssembly.Global object",
2307 ImportName(import_index).c_str());
2308 return false;
2309}
2310
2311// Process the imports, including functions, tables, globals, and memory, in
2312// order, loading them from the {ffi_} object. Returns the number of imported
2313// functions.
2315 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
2316 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data) {
2317 int num_imported_functions = 0;
2318 int num_imported_tables = 0;
2319
2320 DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
2321
2322 const WellKnownImportsList& preknown_imports =
2323 module_->type_feedback.well_known_imports;
2324 int num_imports = static_cast<int>(module_->import_table.size());
2325 for (int index = 0; index < num_imports; ++index) {
2326 const WasmImport& import = module_->import_table[index];
2327
2329
2330 switch (import.kind) {
2331 case kExternalFunction: {
2332 uint32_t func_index = import.index;
2333 DCHECK_EQ(num_imported_functions, func_index);
2334 ModuleTypeIndex sig_index = module_->functions[func_index].sig_index;
2335 bool function_is_shared = module_->type(sig_index).is_shared;
2337 function_is_shared ? shared_trusted_instance_data
2338 : trusted_instance_data,
2339 index, func_index, value, preknown_imports.get(func_index))) {
2340 return -1;
2341 }
2342 num_imported_functions++;
2343 break;
2344 }
2345 case kExternalTable: {
2346 uint32_t table_index = import.index;
2347 DCHECK_EQ(table_index, num_imported_tables);
2348 bool table_is_shared = module_->tables[table_index].shared;
2349 if (!ProcessImportedTable(table_is_shared ? shared_trusted_instance_data
2350 : trusted_instance_data,
2351 index, table_index, value)) {
2352 return -1;
2353 }
2354 num_imported_tables++;
2355 USE(num_imported_tables);
2356 break;
2357 }
2358 case kExternalMemory:
2359 // Imported memories are already handled earlier via
2360 // {ProcessImportedMemories}.
2361 break;
2362 case kExternalGlobal: {
2363 bool global_is_shared = module_->globals[import.index].shared;
2364 if (!ProcessImportedGlobal(global_is_shared
2365 ? shared_trusted_instance_data
2366 : trusted_instance_data,
2367 index, import.index, value)) {
2368 return -1;
2369 }
2370 break;
2371 }
2372 case kExternalTag: {
2373 // TODO(14616): Implement shared tags.
2374 if (!IsWasmTagObject(*value)) {
2375 thrower_->LinkError("%s: tag import requires a WebAssembly.Tag",
2376 ImportName(index).c_str());
2377 return -1;
2378 }
2380 if (!imported_tag->MatchesSignature(module_->canonical_sig_id(
2381 module_->tags[import.index].sig_index))) {
2382 thrower_->LinkError(
2383 "%s: imported tag does not match the expected type",
2384 ImportName(index).c_str());
2385 return -1;
2386 }
2387 Tagged<Object> tag = imported_tag->tag();
2388 DCHECK(IsUndefined(
2389 trusted_instance_data->tags_table()->get(import.index)));
2390 trusted_instance_data->tags_table()->set(import.index, tag);
2391 tags_wrappers_[import.index] = imported_tag;
2392 break;
2393 }
2394 default:
2395 UNREACHABLE();
2396 }
2397 }
2398 if (num_imported_functions > 0) {
2399 module_object_->native_module()->UpdateWellKnownImports(
2401 }
2402 return num_imported_functions;
2403}
2404
2406 DirectHandle<FixedArray> imported_memory_objects) {
2407 DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
2408
2409 int num_imports = static_cast<int>(module_->import_table.size());
2410 for (int import_index = 0; import_index < num_imports; ++import_index) {
2411 const WasmImport& import = module_->import_table[import_index];
2412
2413 if (import.kind != kExternalMemory) continue;
2414
2415 DirectHandle<Object> value = sanitized_imports_[import_index];
2416
2417 if (!IsWasmMemoryObject(*value)) {
2418 thrower_->LinkError(
2419 "%s: memory import must be a WebAssembly.Memory object",
2420 ImportName(import_index).c_str());
2421 return false;
2422 }
2423 uint32_t memory_index = import.index;
2424 auto memory_object = Cast<WasmMemoryObject>(value);
2425
2426 DirectHandle<JSArrayBuffer> buffer{memory_object->array_buffer(), isolate_};
2427 uint32_t imported_cur_pages =
2428 static_cast<uint32_t>(buffer->GetByteLength() / kWasmPageSize);
2429 const WasmMemory* memory = &module_->memories[memory_index];
2430 if (memory->address_type != memory_object->address_type()) {
2431 thrower_->LinkError("cannot import %s memory as %s",
2432 AddressTypeToStr(memory_object->address_type()),
2433 AddressTypeToStr(memory->address_type));
2434 return false;
2435 }
2436 if (imported_cur_pages < memory->initial_pages) {
2437 thrower_->LinkError(
2438 "%s: memory import has %u pages which is smaller than the declared "
2439 "initial of %u",
2440 ImportName(import_index).c_str(), imported_cur_pages,
2441 memory->initial_pages);
2442 return false;
2443 }
2444 int32_t imported_maximum_pages = memory_object->maximum_pages();
2445 if (memory->has_maximum_pages) {
2446 if (imported_maximum_pages < 0) {
2447 thrower_->LinkError(
2448 "%s: memory import has no maximum limit, expected at most %u",
2449 ImportName(import_index).c_str(), imported_maximum_pages);
2450 return false;
2451 }
2452 if (static_cast<uint64_t>(imported_maximum_pages) >
2453 memory->maximum_pages) {
2454 thrower_->LinkError(
2455 "%s: memory import has a larger maximum size %u than the "
2456 "module's declared maximum %" PRIu64,
2457 ImportName(import_index).c_str(), imported_maximum_pages,
2458 memory->maximum_pages);
2459 return false;
2460 }
2461 }
2462 if (memory->is_shared != buffer->is_shared()) {
2463 thrower_->LinkError(
2464 "%s: mismatch in shared state of memory, declared = %d, imported = "
2465 "%d",
2466 ImportName(import_index).c_str(), memory->is_shared,
2467 buffer->is_shared());
2468 return false;
2469 }
2470
2471 DCHECK_EQ(ReadOnlyRoots{isolate_}.undefined_value(),
2472 imported_memory_objects->get(memory_index));
2473 imported_memory_objects->set(memory_index, *memory_object);
2474 }
2475 return true;
2476}
2477
2478template <typename T>
2480 return reinterpret_cast<T*>(raw_buffer_ptr(
2482 global.offset));
2483}
2484
2485// Process initialization of globals.
2487 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
2488 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data) {
2489 for (const WasmGlobal& global : module_->globals) {
2490 DCHECK_IMPLIES(global.imported, !global.init.is_set());
2491 if (!global.init.is_set()) continue;
2492
2494 &init_expr_zone_, global.init, global.type, module_, isolate_,
2495 trusted_instance_data, shared_trusted_instance_data);
2496 if (MaybeMarkError(result, thrower_)) return;
2497
2498 if (global.type.is_reference()) {
2500 ->set(global.offset, *to_value(result).to_ref());
2501 } else {
2503 }
2504 }
2505}
2506
2507// Allocate memory for a module instance as a new JSArrayBuffer.
2509 uint32_t memory_index) {
2510 const WasmMemory& memory = module_->memories[memory_index];
2511 int initial_pages = static_cast<int>(memory.initial_pages);
2512 int maximum_pages = memory.has_maximum_pages
2513 ? static_cast<int>(memory.maximum_pages)
2515 auto shared = memory.is_shared ? SharedFlag::kShared : SharedFlag::kNotShared;
2516
2517 MaybeDirectHandle<WasmMemoryObject> maybe_memory_object =
2518 WasmMemoryObject::New(isolate_, initial_pages, maximum_pages, shared,
2519 memory.address_type);
2520 if (maybe_memory_object.is_null()) {
2521 thrower_->RangeError(
2522 "Out of memory: Cannot allocate Wasm memory for new instance");
2523 return {};
2524 }
2525 return maybe_memory_object;
2526}
2527
2528// Process the exports, creating wrappers for functions, tables, memories,
2529// globals, and exceptions.
2531 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
2532 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data) {
2533 std::unordered_map<int, IndirectHandle<Object>> imported_globals;
2534
2535 // If an imported WebAssembly global gets exported, the export has to be
2536 // identical to to import. Therefore we cache all re-exported globals
2537 // in a map here.
2538 // Note: re-exported functions must also preserve their identity; they
2539 // have already been cached in the instance by {ProcessImportedFunction}.
2540 for (size_t index = 0, end = module_->import_table.size(); index < end;
2541 ++index) {
2542 const WasmImport& import = module_->import_table[index];
2543 if (import.kind == kExternalGlobal &&
2544 module_->globals[import.index].exported) {
2546 if (IsWasmGlobalObject(*value)) {
2547 imported_globals[import.index] = indirect_handle(value, isolate_);
2548 }
2549 }
2550 }
2551
2553 trusted_instance_data->instance_object(), isolate_};
2554 DirectHandle<JSObject> exports_object =
2555 direct_handle(instance_object->exports_object(), isolate_);
2556 MaybeDirectHandle<String> single_function_name;
2557 bool is_asm_js = is_asmjs_module(module_);
2558 if (is_asm_js) {
2560 isolate_->native_context()->object_function(), isolate_);
2561 exports_object = isolate_->factory()->NewJSObject(object_function);
2562 single_function_name =
2564 instance_object->set_exports_object(*exports_object);
2565 }
2566
2567 // Switch the exports object to dictionary mode and allocate enough storage
2568 // for the expected number of exports.
2569 DCHECK(exports_object->HasFastProperties());
2571 isolate_, exports_object, KEEP_INOBJECT_PROPERTIES,
2572 static_cast<int>(module_->export_table.size()), "WasmExportsObject");
2573
2574 PropertyDescriptor desc;
2575 desc.set_writable(is_asm_js);
2576 desc.set_enumerable(true);
2577 desc.set_configurable(is_asm_js);
2578
2579 const PropertyDetails details{PropertyKind::kData, desc.ToAttributes(),
2581
2582 // Process each export in the export table.
2583 for (const WasmExport& exp : module_->export_table) {
2588 switch (exp.kind) {
2589 case kExternalFunction: {
2590 // Wrap and export the code as a JSFunction.
2591 bool shared = module_->function_is_shared(exp.index);
2592 DirectHandle<WasmFuncRef> func_ref =
2594 isolate_,
2595 shared ? shared_trusted_instance_data : trusted_instance_data,
2596 exp.index);
2597 DirectHandle<WasmInternalFunction> internal_function{
2598 func_ref->internal(isolate_), isolate_};
2599 DirectHandle<JSFunction> wasm_external_function =
2601 value = wasm_external_function;
2602
2603 if (is_asm_js &&
2605 single_function_name.ToHandleChecked())) {
2606 desc.set_value(value);
2608 &desc, Just(kThrowOnError))
2609 .FromMaybe(false));
2610 continue;
2611 }
2612 break;
2613 }
2614 case kExternalTable: {
2615 bool shared = module_->tables[exp.index].shared;
2617 shared ? shared_trusted_instance_data : trusted_instance_data;
2618 value = direct_handle(Cast<JSAny>(data->tables()->get(exp.index)),
2619 isolate_);
2620 break;
2621 }
2622 case kExternalMemory: {
2623 // Export the memory as a WebAssembly.Memory object. A WasmMemoryObject
2624 // should already be available if the module has memory, since we always
2625 // create or import it when building an WasmInstanceObject.
2626 value = direct_handle(trusted_instance_data->memory_object(exp.index),
2627 isolate_);
2628 break;
2629 }
2630 case kExternalGlobal: {
2631 const WasmGlobal& global = module_->globals[exp.index];
2633 maybe_shared_trusted_instance_data =
2634 global.shared ? shared_trusted_instance_data
2635 : trusted_instance_data;
2636 if (global.imported) {
2637 auto cached_global = imported_globals.find(exp.index);
2638 if (cached_global != imported_globals.end()) {
2639 value = Cast<JSAny>(cached_global->second);
2640 break;
2641 }
2642 }
2643 DirectHandle<JSArrayBuffer> untagged_buffer;
2645 uint32_t offset;
2646
2647 if (global.mutability && global.imported) {
2648 DirectHandle<FixedArray> buffers_array(
2649 maybe_shared_trusted_instance_data
2650 ->imported_mutable_globals_buffers(),
2651 isolate_);
2652 if (global.type.is_reference()) {
2654 Cast<FixedArray>(buffers_array->get(global.index)), isolate_);
2655 // For externref globals we store the relative offset in the
2656 // imported_mutable_globals array instead of an absolute address.
2657 offset = static_cast<uint32_t>(
2658 maybe_shared_trusted_instance_data->imported_mutable_globals()
2659 ->get(global.index));
2660 } else {
2661 untagged_buffer = direct_handle(
2662 Cast<JSArrayBuffer>(buffers_array->get(global.index)),
2663 isolate_);
2664 Address global_addr =
2665 maybe_shared_trusted_instance_data->imported_mutable_globals()
2666 ->get_sandboxed_pointer(global.index);
2667
2668 size_t buffer_size = untagged_buffer->GetByteLength();
2669 Address backing_store =
2670 reinterpret_cast<Address>(untagged_buffer->backing_store());
2671 CHECK(global_addr >= backing_store &&
2672 global_addr < backing_store + buffer_size);
2673 offset = static_cast<uint32_t>(global_addr - backing_store);
2674 }
2675 } else {
2676 if (global.type.is_reference()) {
2678 maybe_shared_trusted_instance_data->tagged_globals_buffer(),
2679 isolate_);
2680 } else {
2681 untagged_buffer = direct_handle(
2682 maybe_shared_trusted_instance_data->untagged_globals_buffer(),
2683 isolate_);
2684 }
2685 offset = global.offset;
2686 }
2687
2688 // Since the global's array untagged_buffer is always provided,
2689 // allocation should never fail.
2692 global.shared ? shared_trusted_instance_data
2693 : trusted_instance_data,
2694 untagged_buffer, tagged_buffer, global.type,
2695 offset, global.mutability)
2696 .ToHandleChecked();
2697 value = global_obj;
2698 break;
2699 }
2700 case kExternalTag: {
2701 const WasmTag& tag = module_->tags[exp.index];
2702 DirectHandle<WasmTagObject> wrapper = tags_wrappers_[exp.index];
2703 if (wrapper.is_null()) {
2704 DirectHandle<HeapObject> tag_object(
2706 trusted_instance_data->tags_table()->get(exp.index)),
2707 isolate_);
2708 CanonicalTypeIndex sig_index =
2709 module_->canonical_sig_id(tag.sig_index);
2710 // TODO(42204563): Support shared tags.
2711 wrapper = WasmTagObject::New(isolate_, tag.sig, sig_index, tag_object,
2712 trusted_instance_data);
2713 tags_wrappers_[exp.index] = wrapper;
2714 }
2715 value = wrapper;
2716 break;
2717 }
2718 default:
2719 UNREACHABLE();
2720 }
2721
2722 uint32_t index;
2723 if (V8_UNLIKELY(name->AsArrayIndex(&index))) {
2724 // Add a data element.
2725 JSObject::AddDataElement(exports_object, index, value,
2726 details.attributes());
2727 } else {
2728 // Add a property to the dictionary.
2729 JSObject::SetNormalizedProperty(exports_object, name, value, details);
2730 }
2731 }
2732
2733 // Switch back to fast properties if possible.
2734 JSObject::MigrateSlowToFast(exports_object, 0, "WasmExportsObjectFinished");
2735
2736 if (module_->origin == kWasmOrigin) {
2738 kDontThrow)
2739 .FromMaybe(false));
2740 }
2741}
2742
2743namespace {
2744V8_INLINE void SetFunctionTablePlaceholder(
2745 Isolate* isolate,
2746 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
2747 DirectHandle<WasmTableObject> table_object, uint32_t entry_index,
2748 uint32_t func_index) {
2749 const WasmModule* module = trusted_instance_data->module();
2750 const WasmFunction* function = &module->functions[func_index];
2751 Tagged<WasmFuncRef> func_ref;
2752 if (trusted_instance_data->try_get_func_ref(func_index, &func_ref)) {
2753 table_object->entries()->set(entry_index, *func_ref);
2754 } else {
2756 isolate, table_object, entry_index, trusted_instance_data, func_index);
2757 }
2758 WasmTableObject::UpdateDispatchTable(isolate, table_object, entry_index,
2759 function, trusted_instance_data
2760#if V8_ENABLE_DRUMBRAKE
2761 ,
2762 func_index
2763#endif // V8_ENABLE_DRUMBRAKE
2764 );
2765}
2766
2767V8_INLINE void SetFunctionTableNullEntry(
2768 Isolate* isolate, DirectHandle<WasmTableObject> table_object,
2769 uint32_t entry_index) {
2770 table_object->entries()->set(entry_index, ReadOnlyRoots{isolate}.wasm_null());
2771 table_object->ClearDispatchTable(entry_index);
2772}
2773} // namespace
2774
2776 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
2777 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data) {
2778 for (int table_index = 0;
2779 table_index < static_cast<int>(module_->tables.size()); ++table_index) {
2780 const WasmTable& table = module_->tables[table_index];
2781 DirectHandle<WasmTrustedInstanceData> maybe_shared_trusted_instance_data =
2782 table.shared ? shared_trusted_instance_data : trusted_instance_data;
2783 // We must not modify imported tables yet when this is run, because
2784 // we can't know yet whether the new instance can be successfully
2785 // initialized.
2786 DCHECK_IMPLIES(table.imported, !table.initial_value.is_set());
2787 if (!table.initial_value.is_set()) continue;
2788 DirectHandle<WasmTableObject> table_object(
2790 maybe_shared_trusted_instance_data->tables()->get(table_index)),
2791 isolate_);
2792 bool is_function_table = IsSubtypeOf(table.type, kWasmFuncRef, module_);
2793 if (is_function_table &&
2794 table.initial_value.kind() == ConstantExpression::Kind::kRefFunc) {
2795 for (uint32_t entry_index = 0; entry_index < table.initial_size;
2796 entry_index++) {
2797 SetFunctionTablePlaceholder(
2798 isolate_, maybe_shared_trusted_instance_data, table_object,
2799 entry_index, table.initial_value.index());
2800 }
2801 } else if (is_function_table && table.initial_value.kind() ==
2803 for (uint32_t entry_index = 0; entry_index < table.initial_size;
2804 entry_index++) {
2805 SetFunctionTableNullEntry(isolate_, table_object, entry_index);
2806 }
2807 } else {
2809 &init_expr_zone_, table.initial_value, table.type, module_, isolate_,
2810 maybe_shared_trusted_instance_data, shared_trusted_instance_data);
2811 if (MaybeMarkError(result, thrower_)) return;
2812 for (uint32_t entry_index = 0; entry_index < table.initial_size;
2813 entry_index++) {
2814 WasmTableObject::Set(isolate_, table_object, entry_index,
2815 to_value(result).to_ref());
2816 }
2817 }
2818 }
2819}
2820
2821namespace {
2822
2823enum FunctionComputationMode { kLazyFunctionsAndNull, kStrictFunctionsAndNull };
2824
2825// If {function_mode == kLazyFunctionsAndNull}, may return a function index
2826// instead of computing a function object, and {WasmValue(-1)} instead of null.
2827// Assumes the underlying module is verified.
2828// Resets {zone}, so make sure it contains no useful data.
2829ValueOrError ConsumeElementSegmentEntry(
2830 Zone* zone, Isolate* isolate,
2831 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
2832 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data,
2833 const WasmElemSegment& segment, Decoder& decoder,
2834 FunctionComputationMode function_mode) {
2835 const WasmModule* module = trusted_instance_data->module();
2836 if (segment.element_type == WasmElemSegment::kFunctionIndexElements) {
2837 uint32_t function_index = decoder.consume_u32v();
2838 return function_mode == kStrictFunctionsAndNull
2840 zone, ConstantExpression::RefFunc(function_index),
2841 segment.type, module, isolate, trusted_instance_data,
2842 shared_trusted_instance_data)
2843 : ValueOrError(WasmValue(function_index));
2844 }
2845
2846 switch (static_cast<WasmOpcode>(*decoder.pc())) {
2847 case kExprRefFunc: {
2848 auto [function_index, length] =
2849 decoder.read_u32v<Decoder::FullValidationTag>(decoder.pc() + 1,
2850 "ref.func");
2851 if (V8_LIKELY(decoder.lookahead(1 + length, kExprEnd))) {
2852 decoder.consume_bytes(length + 2);
2853 return function_mode == kStrictFunctionsAndNull
2855 zone, ConstantExpression::RefFunc(function_index),
2856 segment.type, module, isolate, trusted_instance_data,
2857 shared_trusted_instance_data)
2858 : ValueOrError(WasmValue(function_index));
2859 }
2860 break;
2861 }
2862 case kExprRefNull: {
2863 auto [heap_type, length] =
2865 &decoder, decoder.pc() + 1, WasmEnabledFeatures::All());
2866 value_type_reader::Populate(&heap_type, module);
2867 if (V8_LIKELY(decoder.lookahead(1 + length, kExprEnd))) {
2868 decoder.consume_bytes(length + 2);
2869 return function_mode == kStrictFunctionsAndNull
2871 zone, ConstantExpression::RefNull(heap_type),
2872 segment.type, module, isolate, trusted_instance_data,
2873 shared_trusted_instance_data)
2874 : WasmValue(int32_t{-1});
2875 }
2876 break;
2877 }
2878 default:
2879 break;
2880 }
2881
2882 auto sig = FixedSizeSignature<ValueType>::Returns(segment.type);
2883 constexpr bool kIsShared = false; // TODO(14616): Is this correct?
2884 FunctionBody body(&sig, decoder.pc_offset(), decoder.pc(), decoder.end(),
2885 kIsShared);
2886 WasmDetectedFeatures detected;
2888 {
2889 // We need a scope for the decoder because its destructor resets some Zone
2890 // elements, which has to be done before we reset the Zone afterwards.
2891 // We use FullValidationTag so we do not have to create another template
2892 // instance of WasmFullDecoder, which would cost us >50Kb binary code
2893 // size.
2894 WasmFullDecoder<Decoder::FullValidationTag, ConstantExpressionInterface,
2896 full_decoder(zone, trusted_instance_data->module(),
2897 WasmEnabledFeatures::All(), &detected, body,
2898 trusted_instance_data->module(), isolate,
2899 trusted_instance_data, shared_trusted_instance_data);
2900
2901 full_decoder.DecodeFunctionBody();
2902
2903 decoder.consume_bytes(static_cast<int>(full_decoder.pc() - decoder.pc()));
2904
2905 result = full_decoder.interface().has_error()
2906 ? ValueOrError(full_decoder.interface().error())
2907 : ValueOrError(full_decoder.interface().computed_value());
2908 }
2909
2910 zone->Reset();
2911
2912 return result;
2913}
2914
2915} // namespace
2916
2917std::optional<MessageTemplate> InitializeElementSegment(
2918 Zone* zone, Isolate* isolate,
2919 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
2920 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data,
2921 uint32_t segment_index) {
2922 bool shared =
2923 trusted_instance_data->module()->elem_segments[segment_index].shared;
2925 shared ? shared_trusted_instance_data : trusted_instance_data;
2926 if (!IsUndefined(data->element_segments()->get(segment_index))) return {};
2927
2928 const NativeModule* native_module = data->native_module();
2929 const WasmModule* module = native_module->module();
2930 const WasmElemSegment& elem_segment = module->elem_segments[segment_index];
2931
2932 base::Vector<const uint8_t> module_bytes = native_module->wire_bytes();
2933
2934 Decoder decoder(module_bytes);
2935 decoder.consume_bytes(elem_segment.elements_wire_bytes_offset);
2936
2938 isolate->factory()->NewFixedArray(elem_segment.element_count);
2939
2940 for (size_t i = 0; i < elem_segment.element_count; ++i) {
2941 ValueOrError value = ConsumeElementSegmentEntry(
2942 zone, isolate, trusted_instance_data, shared_trusted_instance_data,
2943 elem_segment, decoder, kStrictFunctionsAndNull);
2944 if (is_error(value)) return {to_error(value)};
2945 result->set(static_cast<int>(i), *to_value(value).to_ref());
2946 }
2947
2948 data->element_segments()->set(segment_index, *result);
2949
2950 return {};
2951}
2952
2954 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
2955 DirectHandle<WasmTrustedInstanceData> shared_trusted_instance_data) {
2956 for (uint32_t segment_index = 0;
2957 segment_index < module_->elem_segments.size(); ++segment_index) {
2958 const WasmElemSegment& elem_segment = module_->elem_segments[segment_index];
2959 // Passive segments are not copied during instantiation.
2960 if (elem_segment.status != WasmElemSegment::kStatusActive) continue;
2961
2962 const uint32_t table_index = elem_segment.table_index;
2963
2964 const WasmTable* table = &module_->tables[table_index];
2965 size_t dest_offset;
2967 &init_expr_zone_, elem_segment.offset,
2968 table->is_table64() ? kWasmI64 : kWasmI32, module_, isolate_,
2969 trusted_instance_data, shared_trusted_instance_data);
2970 if (MaybeMarkError(result, thrower_)) return;
2971 if (table->is_table64()) {
2972 uint64_t dest_offset_64 = to_value(result).to_u64();
2973 // Clamp to {std::numeric_limits<size_t>::max()}, which is always an
2974 // invalid offset, so we always fail the bounds check below.
2975 DCHECK_GT(std::numeric_limits<size_t>::max(), wasm::max_table_size());
2976 dest_offset = static_cast<size_t>(std::min(
2977 dest_offset_64, uint64_t{std::numeric_limits<size_t>::max()}));
2978 } else {
2979 dest_offset = to_value(result).to_u32();
2980 }
2981
2982 const size_t count = elem_segment.element_count;
2983
2984 DirectHandle<WasmTableObject> table_object(
2985 Cast<WasmTableObject>((table->shared ? shared_trusted_instance_data
2986 : trusted_instance_data)
2987 ->tables()
2988 ->get(table_index)),
2989 isolate_);
2990 if (!base::IsInBounds<size_t>(dest_offset, count,
2991 table_object->current_length())) {
2992 thrower_->RuntimeError("%s",
2994 MessageTemplate::kWasmTrapTableOutOfBounds));
2995 return;
2996 }
2997
2998 base::Vector<const uint8_t> module_bytes =
2999 trusted_instance_data->native_module()->wire_bytes();
3000 Decoder decoder(module_bytes);
3001 decoder.consume_bytes(elem_segment.elements_wire_bytes_offset);
3002
3003 bool is_function_table =
3004 IsSubtypeOf(module_->tables[table_index].type, kWasmFuncRef, module_);
3005
3006 if (is_function_table) {
3007 for (size_t i = 0; i < count; i++) {
3008 int entry_index = static_cast<int>(dest_offset + i);
3009 ValueOrError computed_element = ConsumeElementSegmentEntry(
3010 &init_expr_zone_, isolate_, trusted_instance_data,
3011 shared_trusted_instance_data, elem_segment, decoder,
3012 kLazyFunctionsAndNull);
3013 if (MaybeMarkError(computed_element, thrower_)) return;
3014
3015 WasmValue computed_value = to_value(computed_element);
3016
3017 if (computed_value.type() == kWasmI32) {
3018 if (computed_value.to_i32() >= 0) {
3019 SetFunctionTablePlaceholder(isolate_, trusted_instance_data,
3020 table_object, entry_index,
3021 computed_value.to_i32());
3022 } else {
3023 SetFunctionTableNullEntry(isolate_, table_object, entry_index);
3024 }
3025 } else {
3026 WasmTableObject::Set(isolate_, table_object, entry_index,
3027 computed_value.to_ref());
3028 }
3029 }
3030 } else {
3031 for (size_t i = 0; i < count; i++) {
3032 int entry_index = static_cast<int>(dest_offset + i);
3033 ValueOrError computed_element = ConsumeElementSegmentEntry(
3034 &init_expr_zone_, isolate_, trusted_instance_data,
3035 shared_trusted_instance_data, elem_segment, decoder,
3036 kStrictFunctionsAndNull);
3037 if (MaybeMarkError(computed_element, thrower_)) return;
3038 WasmTableObject::Set(isolate_, table_object, entry_index,
3039 to_value(computed_element).to_ref());
3040 }
3041 }
3042 // Active segment have to be set to empty after instance initialization
3043 // (much like passive segments after dropping).
3044 (elem_segment.shared ? shared_trusted_instance_data : trusted_instance_data)
3046 ->set(segment_index, *isolate_->factory()->empty_fixed_array());
3047 }
3048}
3049
3051 DirectHandle<WasmTrustedInstanceData> trusted_instance_data) {
3052 DirectHandle<FixedArray> tags_table(trusted_instance_data->tags_table(),
3053 isolate_);
3054 for (int index = 0; index < tags_table->length(); ++index) {
3055 if (!IsUndefined(tags_table->get(index), isolate_)) continue;
3057 tags_table->set(index, *tag);
3058 }
3059}
3060
3061} // namespace v8::internal::wasm
3062
3063#undef TRACE
Isolate * isolate_
friend Zone
Definition asm-types.cc:195
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
Builtins::Kind kind
Definition builtins.cc:40
#define SBXCHECK_EQ(lhs, rhs)
Definition check.h:62
#define SBXCHECK_GE(lhs, rhs)
Definition check.h:65
#define SBXCHECK(condition)
Definition check.h:61
void PostDelayedTaskOnWorkerThread(TaskPriority priority, std::unique_ptr< Task > task, double delay_in_seconds, const SourceLocation &location=SourceLocation::Current())
int64_t InMicroseconds() const
Definition time.cc:251
static bool IsHighResolution()
Definition time.cc:763
int length() const
Definition vector.h:64
constexpr T * begin() const
Definition vector.h:96
static const char *const kSingleFunctionName
Definition asm-js.h:38
V8_INLINE bool is_null() const
Definition handles.h:693
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > Call(Isolate *isolate, DirectHandle< Object > callable, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args)
Definition execution.cc:523
Handle< ProtectedFixedArray > NewProtectedFixedArray(int length)
Handle< FixedArray > NewFixedArray(int length, AllocationType allocation=AllocationType::kYoung)
DirectHandle< FixedArray > NewFixedArrayWithZeroes(int length, AllocationType allocation=AllocationType::kYoung)
JSFunctionBuilder & set_map(DirectHandle< Map > v)
Definition factory.h:1116
V8_WARN_UNUSED_RESULT Handle< JSFunction > Build()
Definition factory.cc:4732
Handle< SharedFunctionInfo > NewSharedFunctionInfoForBuiltin(MaybeDirectHandle< String > name, Builtin builtin, int len, AdaptArguments adapt, FunctionKind kind=FunctionKind::kNormalFunction)
Definition factory.cc:3904
MaybeHandle< JSArrayBuffer > NewJSArrayBufferAndBackingStore(size_t byte_length, InitializedFlag initialized, AllocationType allocation=AllocationType::kYoung)
Definition factory.cc:3508
Handle< JSObject > NewJSObject(DirectHandle< JSFunction > constructor, AllocationType allocation=AllocationType::kYoung, NewJSObjectType=NewJSObjectType::kNoAPIWrapper)
Definition factory.cc:2985
Handle< String > InternalizeUtf8String(base::Vector< const char > str)
Definition factory.cc:608
auto Returns(ReturnTypes... return_types) const
Definition signature.h:166
void EnterContext(Tagged< NativeContext > context)
Definition api-inl.h:345
V8_EXPORT_PRIVATE void SetCompiledWasmToJs(Isolate *, DirectHandle< JSReceiver > callable, wasm::WasmCode *wasm_to_js_wrapper, wasm::Suspend suspend, const wasm::CanonicalSig *sig, wasm::CanonicalTypeIndex sig_id)
void SetGenericWasmToJs(Isolate *, DirectHandle< JSReceiver > callable, wasm::Suspend suspend, const wasm::CanonicalSig *sig, wasm::CanonicalTypeIndex sig_id)
void SetWasmToWasm(Tagged< WasmTrustedInstanceData > target_instance_object, WasmCodePointer call_target, wasm::CanonicalTypeIndex sig_id)
static V8_INLINE Isolate * Current()
Definition isolate-inl.h:35
Counters * counters()
Definition isolate.h:1180
HandleScopeImplementer * handle_scope_implementer() const
Definition isolate.h:1397
Handle< NativeContext > native_context()
Definition isolate-inl.h:48
v8::internal::Factory * factory()
Definition isolate.h:1527
const std::shared_ptr< metrics::Recorder > & metrics_recorder()
Definition isolate.h:1187
static V8_EXPORT_PRIVATE void MigrateSlowToFast(DirectHandle< JSObject > object, int unused_property_fields, const char *reason)
static void SetNormalizedProperty(DirectHandle< JSObject > object, DirectHandle< Name > name, DirectHandle< Object > value, PropertyDetails details)
static V8_EXPORT_PRIVATE void NormalizeProperties(Isolate *isolate, DirectHandle< JSObject > object, PropertyNormalizationMode mode, int expected_additional_properties, bool use_cache, const char *reason)
static V8_EXPORT_PRIVATE Maybe< bool > AddDataElement(DirectHandle< JSObject > receiver, uint32_t index, DirectHandle< Object > value, PropertyAttributes attributes)
static V8_WARN_UNUSED_RESULT Maybe< bool > SetIntegrityLevel(Isolate *isolate, DirectHandle< JSReceiver > object, IntegrityLevel lvl, ShouldThrow should_throw)
static V8_WARN_UNUSED_RESULT Maybe< bool > DefineOwnProperty(Isolate *isolate, DirectHandle< JSReceiver > object, DirectHandle< Object > key, PropertyDescriptor *desc, Maybe< ShouldThrow > should_throw)
Handle< Object > GetDataValue(AllocationPolicy allocation_policy=AllocationPolicy::kAllocationAllowed) const
Definition lookup.cc:1069
static MachineType TypeForCType(const CTypeInfo &type)
V8_INLINE DirectHandle< T > ToHandleChecked() const
V8_WARN_UNUSED_RESULT V8_INLINE bool ToHandle(DirectHandle< S > *out) const
V8_INLINE bool is_null() const
static V8_EXPORT_PRIVATE const char * TemplateString(MessageTemplate index)
Definition messages.cc:425
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetPropertyOrElement(Isolate *isolate, DirectHandle< JSAny > object, DirectHandle< Name > name)
static V8_WARN_UNUSED_RESULT HandleType< Number >::MaybeType ToNumber(Isolate *isolate, HandleType< T > input)
static double NumberValue(Tagged< Number > obj)
static V8_EXPORT_PRIVATE bool ToInt32(Tagged< Object > obj, int32_t *value)
Definition objects.cc:1438
SignatureBuilder< Signature< T >, T > Builder
Definition signature.h:130
size_t parameter_count() const
Definition signature.h:94
static constexpr Tagged< Smi > zero()
Definition smi.h:99
bool Equals(Tagged< String > other) const
Definition string-inl.h:535
constexpr bool IsCleared() const
Tagged< HeapObject > GetHeapObjectAssumeWeak() const
static V8_EXPORT_PRIVATE v8::Platform * GetCurrentPlatform()
Definition v8.cc:282
static bool IsWasmCapiFunction(Tagged< Object > object)
static void V8_EXPORT_PRIVATE AddUse(Isolate *isolate, DirectHandle< WasmDispatchTable > dispatch_table, DirectHandle< WasmTrustedInstanceData > instance, int table_index)
static V8_EXPORT_PRIVATE DirectHandle< WasmExceptionTag > New(Isolate *isolate, int index)
static bool IsWasmExternalFunction(Tagged< Object > object)
static V8_EXPORT_PRIVATE MaybeDirectHandle< WasmGlobalObject > New(Isolate *isolate, DirectHandle< WasmTrustedInstanceData > instance_object, MaybeDirectHandle< JSArrayBuffer > maybe_untagged_buffer, MaybeDirectHandle< FixedArray > maybe_tagged_buffer, wasm::ValueType type, int32_t offset, bool is_mutable)
static V8_EXPORT_PRIVATE DirectHandle< JSFunction > GetOrCreateExternal(DirectHandle< WasmInternalFunction > internal)
static constexpr int kNoMaximum
static V8_EXPORT_PRIVATE void UseInInstance(Isolate *isolate, DirectHandle< WasmMemoryObject > memory, DirectHandle< WasmTrustedInstanceData > trusted_instance_data, DirectHandle< WasmTrustedInstanceData > shared_trusted_instance_data, int memory_index_in_instance)
static V8_EXPORT_PRIVATE DirectHandle< WasmMemoryObject > New(Isolate *isolate, DirectHandle< JSArrayBuffer > buffer, int maximum, wasm::AddressType address_type)
static DirectHandle< String > ExtractUtf8StringFromModuleBytes(Isolate *, DirectHandle< WasmModuleObject >, wasm::WireBytesRef, InternalizeString)
static void UpdateDispatchTable(Isolate *isolate, DirectHandle< WasmTableObject > table, int entry_index, const wasm::WasmFunction *func, DirectHandle< WasmTrustedInstanceData > target_instance)
static V8_EXPORT_PRIVATE DirectHandle< WasmTableObject > New(Isolate *isolate, DirectHandle< WasmTrustedInstanceData > trusted_data, wasm::ValueType type, wasm::CanonicalValueType canonical_type, uint32_t initial, bool has_maximum, uint64_t maximum, DirectHandle< Object > initial_value, wasm::AddressType address_type, DirectHandle< WasmDispatchTable > *out_dispatch_table=nullptr)
static V8_EXPORT_PRIVATE void Set(Isolate *isolate, DirectHandle< WasmTableObject > table, uint32_t index, DirectHandle< Object > entry)
static V8_EXPORT_PRIVATE void SetFunctionTablePlaceholder(Isolate *isolate, DirectHandle< WasmTableObject > table, int entry_index, DirectHandle< WasmTrustedInstanceData > trusted_instance_data, int func_index)
static DirectHandle< WasmTagObject > New(Isolate *isolate, const wasm::FunctionSig *sig, wasm::CanonicalTypeIndex type_index, DirectHandle< HeapObject > tag, DirectHandle< WasmTrustedInstanceData > instance)
static DirectHandle< WasmTrustedInstanceData > New(Isolate *, DirectHandle< WasmModuleObject >, bool shared)
static DirectHandle< WasmFuncRef > GetOrCreateFuncRef(Isolate *isolate, DirectHandle< WasmTrustedInstanceData > trusted_instance_data, int function_index)
static constexpr ConstantExpression RefFunc(uint32_t index)
static constexpr ConstantExpression RefNull(HeapType type)
void consume_bytes(uint32_t size, const char *name="skip")
Definition decoder.h:297
void InitGlobals(DirectHandle< WasmTrustedInstanceData > trusted_instance_data, DirectHandle< WasmTrustedInstanceData > shared_trusted_instance_data)
bool ProcessImportedMemories(DirectHandle< FixedArray > imported_memory_objects)
MaybeDirectHandle< JSReceiver > ffi_
DirectHandle< JSFunction > start_function_
MaybeDirectHandle< Object > LookupImportAsm(uint32_t index, DirectHandle< String > import_name)
void LoadTableSegments(DirectHandle< WasmTrustedInstanceData > trusted_instance_data, DirectHandle< WasmTrustedInstanceData > shared_trusted_instance_data)
void Build_Phase1_Infallible(DirectHandle< WasmTrustedInstanceData > trusted_data, DirectHandle< WasmTrustedInstanceData > shared_trusted_data)
MaybeDirectHandle< Object > LookupImport(uint32_t index, DirectHandle< String > module_name, DirectHandle< String > import_name)
DirectHandleVector< Object > sanitized_imports_
DirectHandle< JSArrayBuffer > untagged_globals_
MaybeDirectHandle< WasmTrustedInstanceData > Build_Phase2(DirectHandle< WasmTrustedInstanceData > trusted_data)
std::vector< WellKnownImport > well_known_imports_
DirectHandle< FixedArray > tagged_globals_
DirectHandleVector< WasmTagObject > tags_wrappers_
MaybeDirectHandle< WasmTrustedInstanceData > Build_Phase1(const DisallowJavascriptExecution &no_js)
void InitializeTags(DirectHandle< WasmTrustedInstanceData > trusted_instance_data)
std::string ImportName(uint32_t index, DirectHandle< String > module_name)
bool ProcessImportedWasmGlobalObject(DirectHandle< WasmTrustedInstanceData > trusted_instance_data, int import_index, const WasmGlobal &global, DirectHandle< WasmGlobalObject > global_object)
MaybeDirectHandle< WasmInstanceObject > Build()
void SetTableInitialValues(DirectHandle< WasmTrustedInstanceData > trusted_instance_data, DirectHandle< WasmTrustedInstanceData > shared_trusted_instance_data)
bool ProcessImportedTable(DirectHandle< WasmTrustedInstanceData > trusted_instance_data, int import_index, int table_index, DirectHandle< Object > value)
int ProcessImports(DirectHandle< WasmTrustedInstanceData > trusted_instance_data, DirectHandle< WasmTrustedInstanceData > shared_trusted_instance_data)
bool ProcessImportedGlobal(DirectHandle< WasmTrustedInstanceData > trusted_instance_data, int import_index, int global_index, DirectHandle< Object > value)
std::string ImportName(uint32_t index)
DirectHandle< FixedArray > shared_tagged_globals_
T * GetRawUntaggedGlobalPtr(const WasmGlobal &global)
void ProcessExports(DirectHandle< WasmTrustedInstanceData > trusted_instance_data, DirectHandle< WasmTrustedInstanceData > shared_trusted_instance_data)
MaybeDirectHandle< JSArrayBuffer > asmjs_memory_buffer_
DirectHandleVector< WasmTagObject > shared_tags_wrappers_
v8::metrics::Recorder::ContextId context_id_
InstanceBuilder(Isolate *isolate, v8::metrics::Recorder::ContextId context_id, ErrorThrower *thrower, DirectHandle< WasmModuleObject > module_object, MaybeDirectHandle< JSReceiver > ffi, MaybeDirectHandle< JSArrayBuffer > memory_buffer)
DirectHandle< WasmModuleObject > module_object_
MaybeDirectHandle< WasmMemoryObject > AllocateMemory(uint32_t memory_index)
void LoadDataSegments(DirectHandle< WasmTrustedInstanceData > trusted_instance_data, DirectHandle< WasmTrustedInstanceData > shared_trusted_instance_data)
DirectHandle< JSArrayBuffer > shared_untagged_globals_
void WriteGlobalValue(const WasmGlobal &global, const WasmValue &value)
bool ProcessImportedFunction(DirectHandle< WasmTrustedInstanceData > trusted_instance_data, int import_index, int func_index, DirectHandle< Object > value, WellKnownImport preknown_import)
const WasmModule * module() const
base::Vector< const uint8_t > wire_bytes() const
const CompileTimeImports & compile_imports() const
DirectHandle< WasmFunctionData > trusted_function_data_
DirectHandle< WasmFunctionData > trusted_function_data() const
DirectHandle< JSReceiver > callable() const
ImportCallKind ComputeKind(DirectHandle< WasmTrustedInstanceData > trusted_instance_data, int func_index, const wasm::CanonicalSig *expected_sig, CanonicalTypeIndex expected_canonical_type_index, WellKnownImport preknown_import)
void SetCallable(Isolate *isolate, Tagged< JSReceiver > callable)
V8_EXPORT_PRIVATE ResolvedWasmImport(DirectHandle< WasmTrustedInstanceData > trusted_instance_data, int func_index, DirectHandle< JSReceiver > callable, const wasm::CanonicalSig *sig, CanonicalTypeIndex expected_sig_id, WellKnownImport preknown_import)
V8_EXPORT_PRIVATE const CanonicalSig * LookupFunctionSignature(CanonicalTypeIndex index) const
static V8_EXPORT_PRIVATE void PrepareForCanonicalTypeId(Isolate *isolate, CanonicalTypeIndex id)
constexpr ValueKind kind() const
Definition value-type.h:631
constexpr bool is_reference() const
Definition value-type.h:600
constexpr bool has_index() const
Definition value-type.h:367
constexpr bool is_numeric() const
Definition value-type.h:373
V8_EXPORT_PRIVATE std::string name() const
constexpr bool use_wasm_null() const
Definition value-type.h:462
constexpr ModuleTypeIndex ref_index() const
base::Vector< uint8_t > instructions() const
base::Vector< const uint8_t > reloc_info() const
static constexpr WasmEnabledFeatures All()
WasmCode * AddWrapper(const CacheKey &key, WasmCompilationResult result, WasmCode::Kind kind, uint64_t signature_hash)
DirectHandle< Object > to_ref() const
Definition wasm-value.h:85
void CopyTo(uint8_t *to) const
Definition wasm-value.h:103
CanonicalValueType type() const
Definition wasm-value.h:91
WellKnownImport get(int index) const
uint32_t count
Handle< SharedFunctionInfo > info
int end
Isolate * isolate
SourcePositionTable * source_positions
int32_t offset
TNode< Context > context
TNode< Object > target
SharedFunctionInfoRef shared
std::map< const std::string, const std::string > map
ZoneVector< RpoNumber > & result
#define TRACE(...)
Builtin builtin
std::shared_ptr< NativeModule > native_module_
v8::metrics::Recorder::ContextId context_id_
#define COMPARE_MATH_BUILTIN_F64(name)
STL namespace.
int int32_t
Definition unicode.cc:40
constexpr bool IsInBounds(T index, T length, T max)
Definition bounds.h:49
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
bool IsFastCallSupportedSignature(const v8::CFunctionInfo *sig)
wasm::WasmCompilationResult CompileWasmCapiCallWrapper(const wasm::CanonicalSig *sig)
wasm::WasmCompilationResult CompileWasmJSFastCallWrapper(const wasm::CanonicalSig *sig, DirectHandle< JSReceiver > callable)
static void Populate(HeapType *unfinished_type, const WasmModule *module)
std::pair< HeapType, uint32_t > read_heap_type(Decoder *decoder, const uint8_t *pc, WasmEnabledFeatures enabled)
bool IsCompileTimeImport(WellKnownImport wki)
const char * WellKnownImportName(WellKnownImport wki)
static ValueType value_type()
std::tuple< const char *, Builtin, int > NameBuiltinLength(WellKnownImport wki)
WasmImportWrapperCache * GetWasmImportWrapperCache()
uint32_t max_table_size()
V8_INLINE bool is_error(ValueOrError result)
MaybeDirectHandle< Object > JSToWasmObject(Isolate *isolate, DirectHandle< Object > value, CanonicalValueType expected, const char **error_message)
std::optional< MessageTemplate > InitializeElementSegment(Zone *zone, Isolate *isolate, DirectHandle< WasmTrustedInstanceData > trusted_instance_data, DirectHandle< WasmTrustedInstanceData > shared_trusted_instance_data, uint32_t segment_index)
std::variant< WasmValue, MessageTemplate > ValueOrError
V8_INLINE MessageTemplate to_error(ValueOrError result)
V8_INLINE WasmValue to_value(ValueOrError result)
constexpr IndependentValueType kWasmF32
V8_NOINLINE bool EquivalentTypes(ValueType type1, ValueType type2, const WasmModule *module1, const WasmModule *module2)
TypeCanonicalizer * GetTypeCanonicalizer()
bool is_asmjs_module(const WasmModule *module)
ValueOrError EvaluateConstantExpression(Zone *zone, ConstantExpression expr, ValueType expected, const WasmModule *module, Isolate *isolate, DirectHandle< WasmTrustedInstanceData > trusted_instance_data, DirectHandle< WasmTrustedInstanceData > shared_trusted_instance_data)
constexpr IndependentHeapType kWasmExternRef
bool IsJSCompatibleSignature(const CanonicalSig *sig)
MaybeDirectHandle< WasmInstanceObject > InstantiateToInstanceObject(Isolate *isolate, ErrorThrower *thrower, DirectHandle< WasmModuleObject > module_object, MaybeDirectHandle< JSReceiver > imports, MaybeDirectHandle< JSArrayBuffer > memory_buffer)
constexpr IndependentValueType kWasmI32
constexpr const char * AddressTypeToStr(AddressType address_type)
Definition wasm-module.h:48
constexpr IndependentHeapType kWasmFuncRef
void DumpProfileToFile(const WasmModule *module, base::Vector< const uint8_t > wire_bytes, std::atomic< uint32_t > *tiering_budget_array)
Definition pgo.cc:196
void CreateMapForType(Isolate *isolate, const WasmModule *module, ModuleTypeIndex type_index, DirectHandle< FixedArray > maybe_shared_maps)
constexpr size_t kV8MaxWasmMemories
Definition wasm-limits.h:61
constexpr size_t kWasmPageSize
V8_INLINE bool IsSubtypeOf(ValueType subtype, ValueType supertype, const WasmModule *sub_module, const WasmModule *super_module)
constexpr IndependentValueType kWasmS128
DirectHandle< JSFunction > CreateFunctionForCompileTimeImport(Isolate *isolate, WellKnownImport wki)
constexpr IndependentValueType kWasmF64
constexpr IndependentValueType kWasmI64
DirectHandle< Map > CreateStructMap(Isolate *isolate, wasm::CanonicalTypeIndex struct_index, DirectHandle< Map > opt_rtt_parent, DirectHandle< NativeContext > opt_native_context)
bool TryCast(Tagged< From > value, Tagged< To > *out)
Definition casting.h:77
bool IsClassConstructor(FunctionKind kind)
bool IsNumber(Tagged< Object > obj)
void PrintF(const char *format,...)
Definition utils.cc:39
Tagged(T object) -> Tagged< T >
kWasmInternalFunctionIndirectPointerTag instance_data
DirectHandle< Map > CreateArrayMap(Isolate *isolate, wasm::CanonicalTypeIndex array_index, DirectHandle< Map > opt_rtt_parent)
V8_INLINE IndirectHandle< T > indirect_handle(DirectHandle< T > handle)
Definition handles.h:757
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
bool UseGenericWasmToJSWrapper(wasm::ImportCallKind kind, const wasm::CanonicalSig *sig, wasm::Suspend suspend)
kMemory0SizeOffset Address kNewAllocationLimitAddressOffset Address kOldAllocationLimitAddressOffset uint8_t kGlobalsStartOffset kJumpTableStartOffset std::atomic< uint32_t > kTieringBudgetArrayOffset kDataSegmentStartsOffset kElementSegmentsOffset kInstanceObjectOffset memory_objects
Signature< MachineType > MachineSignature
Definition signature.h:151
kMemory0SizeOffset Address kNewAllocationLimitAddressOffset Address kOldAllocationLimitAddressOffset uint8_t kGlobalsStartOffset kJumpTableStartOffset std::atomic< uint32_t > kTieringBudgetArrayOffset kDataSegmentStartsOffset kElementSegmentsOffset kInstanceObjectOffset kMemoryObjectsOffset kTaggedGlobalsBufferOffset tables
bool IsPrimitive(Tagged< Object > obj)
void ShortPrint(Tagged< Object > obj, FILE *out)
Definition objects.cc:1865
Tagged< MaybeWeak< T > > MakeWeak(Tagged< T > value)
Definition tagged.h:893
int32_t DoubleToInt32(double x)
constexpr AdaptArguments kAdapt
Definition globals.h:2775
kMemory0SizeOffset Address kNewAllocationLimitAddressOffset Address kOldAllocationLimitAddressOffset uint8_t kGlobalsStartOffset kJumpTableStartOffset std::atomic< uint32_t > kTieringBudgetArrayOffset kDataSegmentStartsOffset element_segments
V8_EXPORT_PRIVATE FlagValues v8_flags
float DoubleToFloat32(double x)
return value
Definition map-inl.h:893
DirectHandle< Map > CreateFuncRefMap(Isolate *isolate, wasm::CanonicalTypeIndex type, DirectHandle< Map > opt_rtt_parent)
kMemory0SizeOffset Address kNewAllocationLimitAddressOffset Address kOldAllocationLimitAddressOffset uint8_t kGlobalsStartOffset kJumpTableStartOffset std::atomic< uint32_t > kTieringBudgetArrayOffset kDataSegmentStartsOffset kElementSegmentsOffset instance_object
constexpr uint32_t kMaxUInt32
Definition globals.h:387
@ KEEP_INOBJECT_PROPERTIES
Definition objects.h:62
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
static constexpr AcquireLoadTag kAcquireLoad
Definition globals.h:2908
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
int Compare(const T &a, const T &b)
#define CHECK_GE(lhs, rhs)
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define USE(...)
Definition macros.h:293
constexpr T RoundUp(T x, intptr_t m)
Definition macros.h:387
bool enabled_
Definition string.cc:1013
constexpr bool valid() const
Definition value-type.h:58
const TypeDefinition & type(ModuleTypeIndex index) const
bool has_type(ModuleTypeIndex index) const
const WasmTagSig * sig
#define TRACE_EVENT0(category_group, name)
#define TRACE_DISABLED_BY_DEFAULT(name)
#define V8_INLINE
Definition v8config.h:500
#define END_ALLOW_USE_DEPRECATED()
Definition v8config.h:634
#define V8_LIKELY(condition)
Definition v8config.h:661
#define V8_UNLIKELY(condition)
Definition v8config.h:660
#define START_ALLOW_USE_DEPRECATED()
Definition v8config.h:633
const wasm::WasmModule * module_
#define SELECT_WASM_COUNTER(counters, origin, prefix, suffix)