v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
wasm-js.cc
Go to the documentation of this file.
1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/wasm/wasm-js.h"
6
7#include <cinttypes>
8#include <cstring>
9#include <optional>
10
11#include "include/v8-function.h"
13#include "include/v8-promise.h"
14#include "include/v8-wasm.h"
15#include "src/api/api-inl.h"
16#include "src/api/api-natives.h"
17#include "src/base/fpu.h"
18#include "src/base/logging.h"
22#include "src/flags/flags.h"
23#include "src/handles/handles.h"
24#include "src/heap/factory.h"
34#include "src/wasm/value-type.h"
35#include "src/wasm/wasm-debug.h"
40#include "src/wasm/wasm-value.h"
41
42namespace v8 {
43
44using i::wasm::AddressType;
45using i::wasm::CompileTimeImport;
46using i::wasm::CompileTimeImports;
47using i::wasm::ErrorThrower;
48using i::wasm::WasmEnabledFeatures;
49
50namespace internal {
51
52// Note: The implementation of this function is in runtime-wasm.cc, in order
53// to be able to use helpers that aren't visible outside that file.
54void ToUtf8Lossy(Isolate* isolate, DirectHandle<String> string,
55 std::string& out);
56
57} // namespace internal
58
60 public:
62 i::Isolate* isolate, const char* api_method_name,
63 CompileTimeImports compile_imports,
64 std::shared_ptr<internal::wasm::CompilationResultResolver> resolver)
65 : i_isolate_(isolate),
66 enabled_features_(WasmEnabledFeatures::FromIsolate(i_isolate_)),
67 streaming_decoder_(i::wasm::GetWasmEngine()->StartStreamingCompilation(
68 i_isolate_, enabled_features_, std::move(compile_imports),
69 direct_handle(i_isolate_->context(), i_isolate_), api_method_name,
70 resolver)),
71 resolver_(std::move(resolver)) {}
72
73 void OnBytesReceived(const uint8_t* bytes, size_t size) {
74 streaming_decoder_->OnBytesReceived(base::VectorOf(bytes, size));
75 }
76 void Finish(bool can_use_compiled_module) {
77 streaming_decoder_->Finish(can_use_compiled_module);
78 }
79
82 streaming_decoder_->Abort();
83
84 // If no exception value is provided, we do not reject the promise. This can
85 // happen when streaming compilation gets aborted when no script execution
86 // is allowed anymore, e.g. when a browser tab gets refreshed.
87 if (exception.is_null()) return;
88
89 resolver_->OnCompilationFailed(exception.ToHandleChecked());
90 }
91
93 if (!i::wasm::IsSupportedVersion(bytes, enabled_features_)) return false;
94 streaming_decoder_->SetCompiledModuleBytes(bytes);
95 return true;
96 }
97
99 std::function<void(CompiledWasmModule)> callback) {
100 streaming_decoder_->SetMoreFunctionsCanBeSerializedCallback(
101 [callback = std::move(callback),
102 url = streaming_decoder_->shared_url()](
103 const std::shared_ptr<i::wasm::NativeModule>& native_module) {
104 callback(CompiledWasmModule{native_module, url->data(), url->size()});
105 });
106 }
107
108 void SetUrl(base::Vector<const char> url) { streaming_decoder_->SetUrl(url); }
109
110 private:
112 const WasmEnabledFeatures enabled_features_;
113 const std::shared_ptr<internal::wasm::StreamingDecoder> streaming_decoder_;
114 const std::shared_ptr<internal::wasm::CompilationResultResolver> resolver_;
115};
116
117WasmStreaming::WasmStreaming(std::unique_ptr<WasmStreamingImpl> impl)
118 : impl_(std::move(impl)) {
119 TRACE_EVENT0("v8.wasm", "wasm.InitializeStreaming");
120}
121
122// The destructor is defined here because we have a unique_ptr with forward
123// declaration.
125
126void WasmStreaming::OnBytesReceived(const uint8_t* bytes, size_t size) {
127 TRACE_EVENT1("v8.wasm", "wasm.OnBytesReceived", "bytes", size);
128 impl_->OnBytesReceived(bytes, size);
129}
130
131void WasmStreaming::Finish(bool can_use_compiled_module) {
132 TRACE_EVENT0("v8.wasm", "wasm.FinishStreaming");
133 impl_->Finish(can_use_compiled_module);
134}
135
136void WasmStreaming::Abort(MaybeLocal<Value> exception) {
137 TRACE_EVENT0("v8.wasm", "wasm.AbortStreaming");
138 i::MaybeHandle<i::JSAny> maybe_exception;
139 if (!exception.IsEmpty()) {
140 maybe_exception =
141 Cast<i::JSAny>(Utils::OpenHandle(*exception.ToLocalChecked()));
142 }
143 impl_->Abort(maybe_exception);
144}
145
146bool WasmStreaming::SetCompiledModuleBytes(const uint8_t* bytes, size_t size) {
147 TRACE_EVENT0("v8.wasm", "wasm.SetCompiledModuleBytes");
148 return impl_->SetCompiledModuleBytes(base::VectorOf(bytes, size));
149}
150
152 std::function<void(CompiledWasmModule)> callback) {
153 impl_->SetMoreFunctionsCanBeSerializedCallback(std::move(callback));
154}
155
156void WasmStreaming::SetUrl(const char* url, size_t length) {
157 DCHECK_EQ('\0', url[length]); // {url} is null-terminated.
158 TRACE_EVENT1("v8.wasm", "wasm.SetUrl", "url", url);
159 impl_->SetUrl(base::VectorOf(url, length));
160}
161
162// static
163std::shared_ptr<WasmStreaming> WasmStreaming::Unpack(Isolate* isolate,
164 Local<Value> value) {
165 TRACE_EVENT0("v8.wasm", "wasm.WasmStreaming.Unpack");
166 i::HandleScope scope(reinterpret_cast<i::Isolate*>(isolate));
167 auto managed =
169 return managed->get();
170}
171
172namespace {
173
174i::DirectHandle<i::String> v8_str(i::Isolate* isolate, const char* str) {
175 return isolate->factory()->NewStringFromAsciiChecked(str);
176}
177Local<String> v8_str(Isolate* isolate, const char* str) {
178 return Utils::ToLocal(v8_str(reinterpret_cast<i::Isolate*>(isolate), str));
179}
180
181#define GET_FIRST_ARGUMENT_AS(Type) \
182 i::MaybeDirectHandle<i::Wasm##Type##Object> GetFirstArgumentAs##Type( \
183 const v8::FunctionCallbackInfo<v8::Value>& info, \
184 ErrorThrower* thrower) { \
185 i::DirectHandle<i::Object> arg0 = Utils::OpenDirectHandle(*info[0]); \
186 if (!IsWasm##Type##Object(*arg0)) { \
187 thrower->TypeError("Argument 0 must be a WebAssembly." #Type); \
188 return {}; \
189 } \
190 return i::Cast<i::Wasm##Type##Object>(arg0); \
191 }
192
195
196#undef GET_FIRST_ARGUMENT_AS
197
198base::Vector<const uint8_t> GetFirstArgumentAsBytes(
199 const v8::FunctionCallbackInfo<v8::Value>& info, size_t max_length,
200 ErrorThrower* thrower, bool* is_shared) {
201 const uint8_t* start = nullptr;
202 size_t length = 0;
203 v8::Local<v8::Value> source = info[0];
204 if (source->IsArrayBuffer()) {
205 // A raw array buffer was passed.
206 Local<ArrayBuffer> buffer = Local<ArrayBuffer>::Cast(source);
207 auto backing_store = buffer->GetBackingStore();
208
209 start = reinterpret_cast<const uint8_t*>(backing_store->Data());
210 length = backing_store->ByteLength();
211 *is_shared = buffer->IsSharedArrayBuffer();
212 } else if (source->IsTypedArray()) {
213 // A TypedArray was passed.
214 Local<TypedArray> array = Local<TypedArray>::Cast(source);
215 Local<ArrayBuffer> buffer = array->Buffer();
216
217 auto backing_store = buffer->GetBackingStore();
218
219 start = reinterpret_cast<const uint8_t*>(backing_store->Data()) +
220 array->ByteOffset();
221 length = array->ByteLength();
222 *is_shared = buffer->IsSharedArrayBuffer();
223 } else {
224 thrower->TypeError("Argument 0 must be a buffer source");
225 return {};
226 }
227 DCHECK_IMPLIES(length, start != nullptr);
228 if (length == 0) {
229 thrower->CompileError("BufferSource argument is empty");
230 return {};
231 }
232 if (length > max_length) {
233 // The spec requires a CompileError for implementation-defined limits, see
234 // https://webassembly.github.io/spec/js-api/index.html#limits.
235 thrower->CompileError("buffer source exceeds maximum size of %zu (is %zu)",
236 max_length, length);
237 return {};
238 }
239
240 return base::VectorOf(start, length);
241}
242
243base::OwnedVector<const uint8_t> GetAndCopyFirstArgumentAsBytes(
244 const v8::FunctionCallbackInfo<v8::Value>& info, size_t max_length,
245 ErrorThrower* thrower) {
246 bool is_shared = false;
247 base::Vector<const uint8_t> bytes =
248 GetFirstArgumentAsBytes(info, max_length, thrower, &is_shared);
249 if (bytes.empty()) {
250 return {};
251 }
252
253 // Use relaxed reads (and writes, which is unnecessary here) to avoid TSan
254 // reports in case the buffer is shared and is being modified concurrently.
256 base::Relaxed_Memcpy(reinterpret_cast<base::Atomic8*>(result.begin()),
257 reinterpret_cast<const base::Atomic8*>(bytes.data()),
258 bytes.size());
259 return result;
260}
261
262namespace {
263i::MaybeDirectHandle<i::JSReceiver> ImportsAsMaybeReceiver(Local<Value> ffi) {
264 if (ffi->IsUndefined()) return {};
265
266 Local<Object> obj = Local<Object>::Cast(ffi);
268}
269
270// This class resolves the result of WebAssembly.compile. It just places the
271// compilation result in the supplied {promise}.
272class AsyncCompilationResolver : public i::wasm::CompilationResultResolver {
273 public:
274 AsyncCompilationResolver(Isolate* isolate, Local<Context> context,
275 Local<Promise::Resolver> promise_resolver)
276 : isolate_(isolate),
277 context_(isolate, context),
278 promise_resolver_(isolate, promise_resolver) {
279 context_.SetWeak();
280 promise_resolver_.AnnotateStrongRetainer(kGlobalPromiseHandle);
281 }
282
283 void OnCompilationSucceeded(
285 if (finished_) return;
286 finished_ = true;
287 if (context_.IsEmpty()) return;
288 auto callback = reinterpret_cast<i::Isolate*>(isolate_)
289 ->wasm_async_resolve_promise_callback();
291 callback(isolate_, context_.Get(isolate_), promise_resolver_.Get(isolate_),
292 Utils::ToLocal(i::Cast<i::Object>(result)),
293 WasmAsyncSuccess::kSuccess);
294 }
295
296 void OnCompilationFailed(i::DirectHandle<i::JSAny> error_reason) override {
297 if (finished_) return;
298 finished_ = true;
299 if (context_.IsEmpty()) return;
300 auto callback = reinterpret_cast<i::Isolate*>(isolate_)
301 ->wasm_async_resolve_promise_callback();
303 callback(isolate_, context_.Get(isolate_), promise_resolver_.Get(isolate_),
304 Utils::ToLocal(error_reason), WasmAsyncSuccess::kFail);
305 }
306
307 private:
308 static constexpr char kGlobalPromiseHandle[] =
309 "AsyncCompilationResolver::promise_";
310 bool finished_ = false;
311 Isolate* isolate_;
312 Global<Context> context_;
313 Global<Promise::Resolver> promise_resolver_;
314};
315
316constexpr char AsyncCompilationResolver::kGlobalPromiseHandle[];
317
318// This class resolves the result of WebAssembly.instantiate(module, imports).
319// It just places the instantiation result in the supplied {promise}.
320class InstantiateModuleResultResolver
321 : public i::wasm::InstantiationResultResolver {
322 public:
323 InstantiateModuleResultResolver(Isolate* isolate, Local<Context> context,
324 Local<Promise::Resolver> promise_resolver)
325 : isolate_(isolate),
326 context_(isolate, context),
327 promise_resolver_(isolate, promise_resolver) {
328 context_.SetWeak();
329 promise_resolver_.AnnotateStrongRetainer(kGlobalPromiseHandle);
330 }
331
332 void OnInstantiationSucceeded(
333 i::DirectHandle<i::WasmInstanceObject> instance) override {
334 if (context_.IsEmpty()) return;
335 auto callback = reinterpret_cast<i::Isolate*>(isolate_)
336 ->wasm_async_resolve_promise_callback();
338 callback(isolate_, context_.Get(isolate_), promise_resolver_.Get(isolate_),
339 Utils::ToLocal(i::Cast<i::Object>(instance)),
340 WasmAsyncSuccess::kSuccess);
341 }
342
343 void OnInstantiationFailed(i::DirectHandle<i::JSAny> error_reason) override {
344 if (context_.IsEmpty()) return;
345 auto callback = reinterpret_cast<i::Isolate*>(isolate_)
346 ->wasm_async_resolve_promise_callback();
348 callback(isolate_, context_.Get(isolate_), promise_resolver_.Get(isolate_),
349 Utils::ToLocal(error_reason), WasmAsyncSuccess::kFail);
350 }
351
352 private:
353 static constexpr char kGlobalPromiseHandle[] =
354 "InstantiateModuleResultResolver::promise_";
355 Isolate* isolate_;
356 Global<Context> context_;
357 Global<Promise::Resolver> promise_resolver_;
358};
359
360constexpr char InstantiateModuleResultResolver::kGlobalPromiseHandle[];
361
362// This class resolves the result of WebAssembly.instantiate(bytes, imports).
363// For that it creates a new {JSObject} which contains both the provided
364// {WasmModuleObject} and the resulting {WebAssemblyInstanceObject} itself.
365class InstantiateBytesResultResolver
366 : public i::wasm::InstantiationResultResolver {
367 public:
368 InstantiateBytesResultResolver(Isolate* isolate, Local<Context> context,
369 Local<Promise::Resolver> promise_resolver,
370 Local<Value> module)
371 : isolate_(isolate),
372 context_(isolate, context),
373 promise_resolver_(isolate, promise_resolver),
374 module_(isolate, module) {
375 context_.SetWeak();
376 promise_resolver_.AnnotateStrongRetainer(kGlobalPromiseHandle);
377 module_.AnnotateStrongRetainer(kGlobalModuleHandle);
378 }
379
380 void OnInstantiationSucceeded(
381 i::DirectHandle<i::WasmInstanceObject> instance) override {
382 if (context_.IsEmpty()) return;
383 Local<Context> context = context_.Get(isolate_);
384 WasmAsyncSuccess success = WasmAsyncSuccess::kSuccess;
385
386 // The result is a JSObject with 2 fields which contain the
387 // WasmInstanceObject and the WasmModuleObject.
388 Local<Object> result = Object::New(isolate_);
390 ->CreateDataProperty(context,
391 v8_str(isolate_, "module"),
392 module_.Get(isolate_))
393 .IsNothing())) {
394 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate_);
395 // We assume that a TerminationException is the only reason why
396 // `CreateDataProperty` can fail here. We should revisit
397 // https://crbug.com/1515227 again if this CHECK fails.
398 CHECK(i::IsTerminationException(i_isolate->exception()));
399 result = Utils::ToLocal(direct_handle(
400 i::Cast<i::JSObject>(i_isolate->exception()), i_isolate));
401 success = WasmAsyncSuccess::kFail;
402 }
404 ->CreateDataProperty(
405 context, v8_str(isolate_, "instance"),
406 Utils::ToLocal(i::Cast<i::Object>(instance)))
407 .IsNothing())) {
408 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate_);
409 CHECK(i::IsTerminationException(i_isolate->exception()));
410 result = Utils::ToLocal(direct_handle(
411 i::Cast<i::JSObject>(i_isolate->exception()), i_isolate));
412 success = WasmAsyncSuccess::kFail;
413 }
414
415 auto callback = reinterpret_cast<i::Isolate*>(isolate_)
416 ->wasm_async_resolve_promise_callback();
418 callback(isolate_, context, promise_resolver_.Get(isolate_), result,
419 success);
420 }
421
422 void OnInstantiationFailed(i::DirectHandle<i::JSAny> error_reason) override {
423 if (context_.IsEmpty()) return;
424 auto callback = reinterpret_cast<i::Isolate*>(isolate_)
425 ->wasm_async_resolve_promise_callback();
427 callback(isolate_, context_.Get(isolate_), promise_resolver_.Get(isolate_),
428 Utils::ToLocal(error_reason), WasmAsyncSuccess::kFail);
429 }
430
431 private:
432 static constexpr char kGlobalPromiseHandle[] =
433 "InstantiateBytesResultResolver::promise_";
434 static constexpr char kGlobalModuleHandle[] =
435 "InstantiateBytesResultResolver::module_";
436 Isolate* isolate_;
437 Global<Context> context_;
438 Global<Promise::Resolver> promise_resolver_;
439 Global<Value> module_;
440};
441
442constexpr char InstantiateBytesResultResolver::kGlobalPromiseHandle[];
443constexpr char InstantiateBytesResultResolver::kGlobalModuleHandle[];
444
445// This class is the {CompilationResultResolver} for
446// WebAssembly.instantiate(bytes, imports). When compilation finishes,
447// {AsyncInstantiate} is started on the compilation result.
448class AsyncInstantiateCompileResultResolver
449 : public i::wasm::CompilationResultResolver {
450 public:
451 AsyncInstantiateCompileResultResolver(
452 Isolate* isolate, Local<Context> context,
453 Local<Promise::Resolver> promise_resolver, Local<Value> imports)
454 : isolate_(isolate),
455 context_(isolate, context),
456 promise_resolver_(isolate, promise_resolver),
457 imports_(isolate, imports) {
458 context_.SetWeak();
459 promise_resolver_.AnnotateStrongRetainer(kGlobalPromiseHandle);
460 imports_.AnnotateStrongRetainer(kGlobalImportsHandle);
461 }
462
463 void OnCompilationSucceeded(
465 if (finished_) return;
466 finished_ = true;
467 i::wasm::GetWasmEngine()->AsyncInstantiate(
468 reinterpret_cast<i::Isolate*>(isolate_),
469 std::make_unique<InstantiateBytesResultResolver>(
470 isolate_, context_.Get(isolate_), promise_resolver_.Get(isolate_),
471 Utils::ToLocal(i::Cast<i::Object>(result))),
472 result, ImportsAsMaybeReceiver(imports_.Get(isolate_)));
473 }
474
475 void OnCompilationFailed(i::DirectHandle<i::JSAny> error_reason) override {
476 if (finished_) return;
477 finished_ = true;
478 if (context_.IsEmpty()) return;
479 auto callback = reinterpret_cast<i::Isolate*>(isolate_)
480 ->wasm_async_resolve_promise_callback();
482 callback(isolate_, context_.Get(isolate_), promise_resolver_.Get(isolate_),
483 Utils::ToLocal(error_reason), WasmAsyncSuccess::kFail);
484 }
485
486 private:
487 static constexpr char kGlobalPromiseHandle[] =
488 "AsyncInstantiateCompileResultResolver::promise_";
489 static constexpr char kGlobalImportsHandle[] =
490 "AsyncInstantiateCompileResultResolver::module_";
491 bool finished_ = false;
492 Isolate* isolate_;
493 Global<Context> context_;
494 Global<Promise::Resolver> promise_resolver_;
495 Global<Value> imports_;
496};
497
498constexpr char AsyncInstantiateCompileResultResolver::kGlobalPromiseHandle[];
499constexpr char AsyncInstantiateCompileResultResolver::kGlobalImportsHandle[];
500
501// TODO(clemensb): Make this less inefficient.
502std::string ToString(const char* name) { return std::string(name); }
503
504std::string ToString(const i::DirectHandle<i::String> name) {
505 return std::string("Property '") + name->ToCString().get() + "'";
506}
507
508// Web IDL: '[EnforceRange] unsigned long'
509// https://heycam.github.io/webidl/#EnforceRange
510template <typename Name>
511std::optional<uint32_t> EnforceUint32(Name argument_name, Local<v8::Value> v,
512 Local<Context> context,
513 ErrorThrower* thrower) {
514 double double_number;
515 if (!v->NumberValue(context).To(&double_number)) {
516 thrower->TypeError("%s must be convertible to a number",
517 ToString(argument_name).c_str());
518 return std::nullopt;
519 }
520 if (!std::isfinite(double_number)) {
521 thrower->TypeError("%s must be convertible to a valid number",
522 ToString(argument_name).c_str());
523 return std::nullopt;
524 }
525 if (double_number < 0) {
526 thrower->TypeError("%s must be non-negative",
527 ToString(argument_name).c_str());
528 return std::nullopt;
529 }
530 if (double_number > std::numeric_limits<uint32_t>::max()) {
531 thrower->TypeError("%s must be in the unsigned long range",
532 ToString(argument_name).c_str());
533 return std::nullopt;
534 }
535
536 return static_cast<uint32_t>(double_number);
537}
538
539// First step of AddressValueToU64, for addrtype == "i64".
540template <typename Name>
541std::optional<uint64_t> EnforceBigIntUint64(Name argument_name, Local<Value> v,
542 Local<Context> context,
543 ErrorThrower* thrower) {
544 // Use the internal API, as v8::Value::ToBigInt clears exceptions.
546 i::Isolate* i_isolate = i::Isolate::Current();
547 if (!i::BigInt::FromObject(i_isolate, Utils::OpenDirectHandle(*v))
548 .ToHandle(&bigint)) {
549 return std::nullopt;
550 }
551
552 bool lossless;
553 uint64_t result = bigint->AsUint64(&lossless);
554 if (!lossless) {
555 thrower->TypeError("%s must be in u64 range",
556 ToString(argument_name).c_str());
557 return std::nullopt;
558 }
559
560 return result;
561}
562
563// The enum values need to match "WasmCompilationMethod" in
564// tools/metrics/histograms/enums.xml.
565enum CompilationMethod {
566 kSyncCompilation = 0,
567 kAsyncCompilation = 1,
568 kStreamingCompilation = 2,
569 kAsyncInstantiation = 3,
570 kStreamingInstantiation = 4,
571};
572
573void RecordCompilationMethod(i::Isolate* isolate, CompilationMethod method) {
574 isolate->counters()->wasm_compilation_method()->AddSample(method);
575}
576
577CompileTimeImports ArgumentToCompileOptions(
578 Local<Value> arg_value, i::Isolate* isolate,
579 WasmEnabledFeatures enabled_features) {
580 CompileTimeImports result;
582 result.Add(CompileTimeImport::kDisableDenormalFloats);
583 }
584 if (!enabled_features.has_imported_strings()) return result;
586 if (!i::IsJSReceiver(*arg)) return result;
588
589 // ==================== Builtins ====================
591 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, builtins,
592 i::Cast<i::JSAny>(i::JSReceiver::GetProperty(
593 isolate, receiver, "builtins")),
594 {});
595 if (i::IsJSReceiver(*builtins)) {
598 isolate, length_obj,
599 i::Object::GetLengthFromArrayLike(isolate,
600 i::Cast<i::JSReceiver>(builtins)),
601 {});
602 double raw_length = i::Object::NumberValue(*length_obj);
603 // Technically we should probably iterate up to 2^53-1 if {length_obj} says
604 // so, but lengths above 2^32 probably don't happen in practice (and would
605 // be very slow if they do), so just use a saturating to-uint32 conversion
606 // for simplicity.
607 uint32_t len = raw_length >= i::kMaxUInt32
609 : static_cast<uint32_t>(raw_length);
610 for (uint32_t i = 0; i < len; i++) {
611 i::LookupIterator it(isolate, builtins, i);
612 Maybe<bool> maybe_found = i::JSReceiver::HasProperty(&it);
613 MAYBE_RETURN(maybe_found, {});
614 if (!maybe_found.FromJust()) continue;
617 i::Object::GetProperty(&it), {});
618 if (i::IsString(*value)) {
620 // TODO(jkummerow): We could make other string comparisons to known
621 // constants in this file more efficient by migrating them to this
622 // style (rather than `...->StringEquals(v8_str(...))`).
623 if (builtin->IsEqualTo(base::CStrVector("js-string"))) {
624 result.Add(CompileTimeImport::kJsString);
625 continue;
626 }
627 if (enabled_features.has_imported_strings_utf8()) {
628 if (builtin->IsEqualTo(base::CStrVector("text-encoder"))) {
629 result.Add(CompileTimeImport::kTextEncoder);
630 continue;
631 }
632 if (builtin->IsEqualTo(base::CStrVector("text-decoder"))) {
633 result.Add(CompileTimeImport::kTextDecoder);
634 continue;
635 }
636 }
637 }
638 }
639 }
640
641 // ==================== String constants ====================
642 i::DirectHandle<i::String> importedStringConstants =
643 isolate->factory()->InternalizeUtf8String("importedStringConstants");
644 if (i::JSReceiver::HasProperty(isolate, receiver, importedStringConstants)
645 .FromMaybe(false)) {
646 i::DirectHandle<i::Object> constants_value;
648 isolate, constants_value,
649 i::JSReceiver::GetProperty(isolate, receiver, importedStringConstants),
650 {});
651 if (i::IsString(*constants_value)) {
652 i::ToUtf8Lossy(isolate, i::Cast<i::String>(constants_value),
653 result.constants_module());
654 result.Add(CompileTimeImport::kStringConstants);
655 }
656 }
657
658 return result;
659}
660
661// A scope object with accessors and destructur DCHECKs to be used in
662// implementations of Wasm JS-API methods.
663class WasmJSApiScope {
664 public:
665 explicit WasmJSApiScope(
666 const v8::FunctionCallbackInfo<v8::Value>& callback_info,
667 const char* api_name)
668 : callback_info_(callback_info),
669 isolate_{callback_info.GetIsolate()},
670 handle_scope_{isolate_},
671 thrower_{reinterpret_cast<i::Isolate*>(isolate_), api_name} {
672 DCHECK(i::ValidateCallbackInfo(callback_info));
673 }
674
675 WasmJSApiScope(const WasmJSApiScope&) = delete;
676 WasmJSApiScope& operator=(const WasmJSApiScope&) = delete;
677
678 void AssertException() const {
679 DCHECK(i_isolate()->has_exception() || thrower_.error());
680 }
681
682 const v8::FunctionCallbackInfo<v8::Value>& callback_info() {
683 return callback_info_;
684 }
685
686 const char* api_name() const { return thrower_.context_name(); }
687
688 // Accessor for all essential fields. To be decomposed into individual aliases
689 // via structured binding.
690 std::tuple<v8::Isolate*, i::Isolate*, ErrorThrower&> isolates_and_thrower() {
691 return {isolate_, i_isolate(), thrower_};
692 }
693
694 private:
695 i::Isolate* i_isolate() const {
696 return reinterpret_cast<i::Isolate*>(isolate_);
697 }
698
699 const v8::FunctionCallbackInfo<v8::Value>& callback_info_;
700 v8::Isolate* const isolate_;
701 HandleScope handle_scope_;
702 ErrorThrower thrower_;
703};
704
705} // namespace
706
707// WebAssembly.compile(bytes, options) -> Promise
708void WebAssemblyCompileImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
709 WasmJSApiScope js_api_scope{info, "WebAssembly.compile()"};
710 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
711 RecordCompilationMethod(i_isolate, kAsyncCompilation);
712
713 Local<Context> context = isolate->GetCurrentContext();
714 Local<Promise::Resolver> promise_resolver;
715 if (!Promise::Resolver::New(context).ToLocal(&promise_resolver)) {
716 return js_api_scope.AssertException();
717 }
718 Local<Promise> promise = promise_resolver->GetPromise();
719 info.GetReturnValue().Set(promise);
720
721 std::shared_ptr<i::wasm::CompilationResultResolver> resolver(
722 new AsyncCompilationResolver(isolate, context, promise_resolver));
723
725 i_isolate->native_context();
726 if (!i::wasm::IsWasmCodegenAllowed(i_isolate, native_context)) {
728 i::wasm::ErrorStringForCodegen(i_isolate, native_context);
729 thrower.CompileError("%s", error->ToCString().get());
730 resolver->OnCompilationFailed(thrower.Reify());
731 return;
732 }
733
734 base::OwnedVector<const uint8_t> bytes = GetAndCopyFirstArgumentAsBytes(
735 info, i::wasm::max_module_size(), &thrower);
736 if (bytes.empty()) {
737 resolver->OnCompilationFailed(thrower.Reify());
738 return;
739 }
740 auto enabled_features = WasmEnabledFeatures::FromIsolate(i_isolate);
741 CompileTimeImports compile_imports =
742 ArgumentToCompileOptions(info[1], i_isolate, enabled_features);
743 if (i_isolate->has_exception()) {
744 if (i_isolate->is_execution_terminating()) return;
745 i::DirectHandle<i::JSAny> exception(Cast<i::JSAny>(i_isolate->exception()),
746 i_isolate);
747 i_isolate->clear_exception();
748 resolver->OnCompilationFailed(exception);
749 return;
750 }
751 i::wasm::GetWasmEngine()->AsyncCompile(
752 i_isolate, enabled_features, std::move(compile_imports),
753 std::move(resolver), std::move(bytes), js_api_scope.api_name());
754}
755
756void WasmStreamingCallbackForTesting(
758 WasmJSApiScope js_api_scope{info, "WebAssembly.compile()"};
759 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
760
761 std::shared_ptr<v8::WasmStreaming> streaming =
762 v8::WasmStreaming::Unpack(info.GetIsolate(), info.Data());
763
764 // We don't check the buffer length up front, to allow d8 to test that the
765 // streaming decoder implementation handles overly large inputs correctly.
766 size_t unlimited = std::numeric_limits<size_t>::max();
767 base::OwnedVector<const uint8_t> bytes =
768 GetAndCopyFirstArgumentAsBytes(info, unlimited, &thrower);
769 if (bytes.empty()) {
770 streaming->Abort(Utils::ToLocal(thrower.Reify()));
771 return;
772 }
773 streaming->OnBytesReceived(bytes.begin(), bytes.size());
774 streaming->Finish();
775 CHECK(!thrower.error());
776}
777
778void WasmStreamingPromiseFailedCallback(
781 std::shared_ptr<v8::WasmStreaming> streaming =
782 v8::WasmStreaming::Unpack(info.GetIsolate(), info.Data());
783 streaming->Abort(info[0]);
784}
785
786void StartAsyncCompilationWithResolver(
787 WasmJSApiScope& js_api_scope, Local<Value> response_or_promise,
788 Local<Value> options_arg_value,
789 std::shared_ptr<i::wasm::CompilationResultResolver> resolver) {
790 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
791
792 Local<Context> context = isolate->GetCurrentContext();
794 Utils::OpenHandle(*context);
795
796 if (!i::wasm::IsWasmCodegenAllowed(i_isolate, native_context)) {
798 i::wasm::ErrorStringForCodegen(i_isolate, native_context);
799 thrower.CompileError("%s", error->ToCString().get());
800 resolver->OnCompilationFailed(thrower.Reify());
801 return;
802 }
803
804 auto enabled_features = WasmEnabledFeatures::FromIsolate(i_isolate);
805 CompileTimeImports compile_imports =
806 ArgumentToCompileOptions(options_arg_value, i_isolate, enabled_features);
807 if (i_isolate->has_exception()) {
808 if (i_isolate->is_execution_terminating()) return;
809 i::DirectHandle<i::JSAny> exception(Cast<i::JSAny>(i_isolate->exception()),
810 i_isolate);
811 i_isolate->clear_exception();
812 resolver->OnCompilationFailed(exception);
813 return;
814 }
815
816 // Allocate the streaming decoder in a Managed so we can pass it to the
817 // embedder.
818 std::shared_ptr<WasmStreaming> streaming = std::make_shared<WasmStreaming>(
819 std::make_unique<WasmStreaming::WasmStreamingImpl>(
820 i_isolate, js_api_scope.api_name(), std::move(compile_imports),
821 resolver));
823 i::Managed<WasmStreaming>::From(i_isolate, 0, streaming);
824
825 DCHECK_NOT_NULL(i_isolate->wasm_streaming_callback());
826 Local<v8::Function> compile_callback, reject_callback;
827 if (!v8::Function::New(context, i_isolate->wasm_streaming_callback(),
828 Utils::ToLocal(i::Cast<i::Object>(data)), 1)
829 .ToLocal(&compile_callback) ||
830 !v8::Function::New(context, WasmStreamingPromiseFailedCallback,
831 Utils::ToLocal(i::Cast<i::Object>(data)), 1)
832 .ToLocal(&reject_callback)) {
833 return js_api_scope.AssertException();
834 }
835
836 // The parameter may be of type {Response} or of type {Promise<Response>}.
837 // Treat either case of parameter as Promise.resolve(parameter)
838 // as per https://www.w3.org/2001/tag/doc/promises-guide#resolve-arguments
839
840 // Ending with:
841 // return Promise.resolve(parameter).then(compile_callback);
842 Local<Promise::Resolver> input_resolver;
843 if (!Promise::Resolver::New(context).ToLocal(&input_resolver) ||
844 input_resolver->Resolve(context, response_or_promise).IsNothing()) {
845 return js_api_scope.AssertException();
846 }
847
848 // Calling `then` on the promise can fail if the user monkey-patched stuff,
849 // see https://crbug.com/374820218 / https://crbug.com/396461004.
850 // If this does not fail, then the {compile_callback} will start streaming
851 // compilation, which will eventually resolve the promise we set as result
852 // value.
853 if (input_resolver->GetPromise()
854 ->Then(context, compile_callback, reject_callback)
855 .IsEmpty()) {
856 streaming->Abort(MaybeLocal<Value>{});
857 return js_api_scope.AssertException();
858 }
859}
860
861// WebAssembly.compileStreaming(Response | Promise<Response>, options)
862// -> Promise<WebAssembly.Module>
863void WebAssemblyCompileStreaming(
865 WasmJSApiScope js_api_scope{info, "WebAssembly.compileStreaming()"};
866 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
867 RecordCompilationMethod(i_isolate, kStreamingCompilation);
868 Local<Context> context = isolate->GetCurrentContext();
869
870 // Create and assign the return value of this function.
871 Local<Promise::Resolver> promise_resolver;
872 if (!Promise::Resolver::New(context).ToLocal(&promise_resolver)) {
873 return js_api_scope.AssertException();
874 }
875 Local<Promise> promise = promise_resolver->GetPromise();
876 info.GetReturnValue().Set(promise);
877
878 // Prepare the CompilationResultResolver for the compilation.
879 auto resolver = std::make_shared<AsyncCompilationResolver>(isolate, context,
880 promise_resolver);
881
882 StartAsyncCompilationWithResolver(js_api_scope, info[0], info[1], resolver);
883}
884
885// WebAssembly.validate(bytes, options) -> bool
886void WebAssemblyValidateImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
887 WasmJSApiScope js_api_scope{info, "WebAssembly.validate()"};
888 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
889 v8::ReturnValue<v8::Value> return_value = info.GetReturnValue();
890
891 bool bytes_are_shared = false;
892 base::Vector<const uint8_t> bytes = GetFirstArgumentAsBytes(
893 info, i::wasm::max_module_size(), &thrower, &bytes_are_shared);
894 if (bytes.empty()) {
895 js_api_scope.AssertException();
896 // Propagate anything except wasm exceptions.
897 if (!thrower.wasm_error()) return;
898 // Clear wasm exceptions; return false instead.
899 thrower.Reset();
900 return_value.Set(v8::False(isolate));
901 return;
902 }
903
904 auto enabled_features = WasmEnabledFeatures::FromIsolate(i_isolate);
905 CompileTimeImports compile_imports =
906 ArgumentToCompileOptions(info[1], i_isolate, enabled_features);
907 if (i_isolate->has_exception()) {
908 if (i_isolate->is_execution_terminating()) return;
909 i_isolate->clear_exception();
910 return_value.Set(v8::False(isolate));
911 return;
912 }
913
914 bool validated = false;
915 if (bytes_are_shared) {
916 // Make a copy of the wire bytes to avoid concurrent modification.
917 // Use relaxed reads (and writes, which is unnecessary here) to avoid TSan
918 // reports in case the buffer is shared and is being modified concurrently.
919 auto bytes_copy = base::OwnedVector<uint8_t>::NewForOverwrite(bytes.size());
920 base::Relaxed_Memcpy(reinterpret_cast<base::Atomic8*>(bytes_copy.begin()),
921 reinterpret_cast<const base::Atomic8*>(bytes.data()),
922 bytes.size());
923 validated = i::wasm::GetWasmEngine()->SyncValidate(
924 i_isolate, enabled_features, std::move(compile_imports),
925 bytes_copy.as_vector());
926 } else {
927 // The wire bytes are not shared, OK to use them directly.
928 validated = i::wasm::GetWasmEngine()->SyncValidate(
929 i_isolate, enabled_features, std::move(compile_imports), bytes);
930 }
931
932 return_value.Set(validated);
933}
934
935namespace {
936bool TransferPrototype(i::Isolate* isolate,
940 i::JSObject::GetPrototype(isolate, source);
942 if (maybe_prototype.ToHandle(&prototype)) {
943 Maybe<bool> result = i::JSObject::SetPrototype(
944 isolate, destination, prototype,
945 /*from_javascript=*/false, internal::kThrowOnError);
946 if (!result.FromJust()) {
947 DCHECK(isolate->has_exception());
948 return false;
949 }
950 }
951 return true;
952}
953} // namespace
954
955// new WebAssembly.Module(bytes, options) -> WebAssembly.Module
956void WebAssemblyModuleImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
957 WasmJSApiScope js_api_scope{info, "WebAssembly.Module()"};
958 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
959 if (i_isolate->wasm_module_callback()(info)) return;
960 RecordCompilationMethod(i_isolate, kSyncCompilation);
961
962 if (!info.IsConstructCall()) {
963 thrower.TypeError("WebAssembly.Module must be invoked with 'new'");
964 return;
965 }
967 i_isolate->native_context();
968 if (!i::wasm::IsWasmCodegenAllowed(i_isolate, native_context)) {
970 i::wasm::ErrorStringForCodegen(i_isolate, native_context);
971 thrower.CompileError("%s", error->ToCString().get());
972 return;
973 }
974
975 base::OwnedVector<const uint8_t> bytes = GetAndCopyFirstArgumentAsBytes(
976 info, i::wasm::max_module_size(), &thrower);
977
978 if (bytes.empty()) return js_api_scope.AssertException();
979
980 auto enabled_features = WasmEnabledFeatures::FromIsolate(i_isolate);
981 CompileTimeImports compile_imports =
982 ArgumentToCompileOptions(info[1], i_isolate, enabled_features);
983 if (i_isolate->has_exception()) {
984 // TODO(14179): Does this need different error message handling?
985 return;
986 }
988
989 maybe_module_obj = i::wasm::GetWasmEngine()->SyncCompile(
990 i_isolate, enabled_features, std::move(compile_imports), &thrower,
991 std::move(bytes));
992
994 if (!maybe_module_obj.ToHandle(&module_obj)) return;
995
996 // The infrastructure for `new Foo` calls allocates an object, which is
997 // available here as {info.This()}. We're going to discard this object
998 // and use {module_obj} instead, but it does have the correct prototype,
999 // which we must harvest from it. This makes a difference when the JS
1000 // constructor function wasn't {WebAssembly.Module} directly, but some
1001 // subclass: {module_obj} has {WebAssembly.Module}'s prototype at this
1002 // point, so we must overwrite that with the correct prototype for {Foo}.
1003 if (!TransferPrototype(i_isolate, module_obj,
1004 Utils::OpenDirectHandle(*info.This()))) {
1005 return;
1006 }
1007
1008 v8::ReturnValue<v8::Value> return_value = info.GetReturnValue();
1009 return_value.Set(Utils::ToLocal(module_obj));
1010}
1011
1012// WebAssembly.Module.imports(module) -> Array<Import>
1013void WebAssemblyModuleImportsImpl(
1015 WasmJSApiScope js_api_scope{info, "WebAssembly.Module.imports()"};
1016 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
1017
1019 if (!GetFirstArgumentAsModule(info, &thrower).ToHandle(&module_object)) {
1020 return js_api_scope.AssertException();
1021 }
1022 auto imports = i::wasm::GetImports(i_isolate, module_object);
1023 info.GetReturnValue().Set(Utils::ToLocal(imports));
1024}
1025
1026// WebAssembly.Module.exports(module) -> Array<Export>
1027void WebAssemblyModuleExportsImpl(
1029 WasmJSApiScope js_api_scope{info, "WebAssembly.Module.exports()"};
1030 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
1031
1033 if (!GetFirstArgumentAsModule(info, &thrower).ToHandle(&module_object)) {
1034 return js_api_scope.AssertException();
1035 }
1036 auto exports = i::wasm::GetExports(i_isolate, module_object);
1037 info.GetReturnValue().Set(Utils::ToLocal(exports));
1038}
1039
1040// WebAssembly.Module.customSections(module, name) -> Array<Section>
1041void WebAssemblyModuleCustomSectionsImpl(
1043 WasmJSApiScope js_api_scope{info, "WebAssembly.Module.customSections()"};
1044 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
1045
1047 if (!GetFirstArgumentAsModule(info, &thrower).ToHandle(&module_object)) {
1048 return js_api_scope.AssertException();
1049 }
1050
1051 if (info[1]->IsUndefined()) {
1052 thrower.TypeError("Argument 1 is required");
1053 return;
1054 }
1055
1057 if (!i::Object::ToString(i_isolate, Utils::OpenDirectHandle(*info[1]))
1058 .ToHandle(&name)) {
1059 return js_api_scope.AssertException();
1060 }
1061 auto custom_sections = i::wasm::GetCustomSections(
1062 i_isolate, module_object, i::Cast<i::String>(name), &thrower);
1063 if (thrower.error()) return;
1064 info.GetReturnValue().Set(Utils::ToLocal(custom_sections));
1065}
1066
1067// new WebAssembly.Instance(module, imports) -> WebAssembly.Instance
1068void WebAssemblyInstanceImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
1069 WasmJSApiScope js_api_scope{info, "WebAssembly.Instance()"};
1070 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
1071 RecordCompilationMethod(i_isolate, kAsyncInstantiation);
1072 i_isolate->CountUsage(
1074
1075 if (i_isolate->wasm_instance_callback()(info)) return;
1076
1077 i::DirectHandle<i::JSObject> instance_obj;
1078 {
1079 if (!info.IsConstructCall()) {
1080 thrower.TypeError("WebAssembly.Instance must be invoked with 'new'");
1081 return;
1082 }
1083
1085 if (!GetFirstArgumentAsModule(info, &thrower).ToHandle(&module_object)) {
1086 return js_api_scope.AssertException();
1087 }
1088
1089 Local<Value> ffi = info[1];
1090
1091 if (!ffi->IsUndefined() && !ffi->IsObject()) {
1092 thrower.TypeError("Argument 1 must be an object");
1093 return;
1094 }
1095
1096 if (!i::wasm::GetWasmEngine()
1097 ->SyncInstantiate(i_isolate, &thrower, module_object,
1098 ImportsAsMaybeReceiver(ffi),
1100 .ToHandle(&instance_obj)) {
1101 return js_api_scope.AssertException();
1102 }
1103 }
1104
1105 // The infrastructure for `new Foo` calls allocates an object, which is
1106 // available here as {info.This()}. We're going to discard this object
1107 // and use {instance_obj} instead, but it does have the correct prototype,
1108 // which we must harvest from it. This makes a difference when the JS
1109 // constructor function wasn't {WebAssembly.Instance} directly, but some
1110 // subclass: {instance_obj} has {WebAssembly.Instance}'s prototype at this
1111 // point, so we must overwrite that with the correct prototype for {Foo}.
1112 if (!TransferPrototype(i_isolate, instance_obj,
1113 Utils::OpenDirectHandle(*info.This()))) {
1114 return js_api_scope.AssertException();
1115 }
1116
1117 info.GetReturnValue().Set(Utils::ToLocal(instance_obj));
1118}
1119
1120// WebAssembly.instantiateStreaming(
1121// Response | Promise<Response> [, imports [, options]])
1122// -> Promise<ResultObject>
1123// (where ResultObject has a "module" and an "instance" field)
1124void WebAssemblyInstantiateStreaming(
1126 WasmJSApiScope js_api_scope{info, "WebAssembly.instantiateStreaming()"};
1127 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
1128 RecordCompilationMethod(i_isolate, kStreamingInstantiation);
1129 i_isolate->CountUsage(
1131
1132 Local<Context> context = isolate->GetCurrentContext();
1133
1134 // Create and assign the return value of this function.
1135 Local<Promise::Resolver> result_resolver;
1136 if (!Promise::Resolver::New(context).ToLocal(&result_resolver)) {
1137 return js_api_scope.AssertException();
1138 }
1139 Local<Promise> promise = result_resolver->GetPromise();
1140 info.GetReturnValue().Set(promise);
1141
1142 // If info.Length < 2, this will be undefined - see FunctionCallbackInfo.
1143 Local<Value> ffi = info[1];
1144
1145 if (!ffi->IsUndefined() && !ffi->IsObject()) {
1146 thrower.TypeError("Argument 1 must be an object");
1147 InstantiateModuleResultResolver resolver(isolate, context, result_resolver);
1148 resolver.OnInstantiationFailed(thrower.Reify());
1149 return;
1150 }
1151
1152 auto compilation_resolver =
1153 std::make_shared<AsyncInstantiateCompileResultResolver>(
1154 isolate, context, result_resolver, ffi);
1155 StartAsyncCompilationWithResolver(js_api_scope, info[0], info[2],
1156 std::move(compilation_resolver));
1157}
1158
1159// WebAssembly.instantiate(module, imports) -> WebAssembly.Instance
1160// WebAssembly.instantiate(bytes, imports, options) ->
1161// {module: WebAssembly.Module, instance: WebAssembly.Instance}
1162void WebAssemblyInstantiateImpl(
1164 WasmJSApiScope js_api_scope{info, "WebAssembly.instantiate()"};
1165 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
1166 i_isolate->CountUsage(
1168
1169 Local<Context> context = isolate->GetCurrentContext();
1170
1171 Local<Promise::Resolver> promise_resolver;
1172 if (!Promise::Resolver::New(context).ToLocal(&promise_resolver)) {
1173 return js_api_scope.AssertException();
1174 }
1175 Local<Promise> promise = promise_resolver->GetPromise();
1176 info.GetReturnValue().Set(promise);
1177
1178 std::unique_ptr<i::wasm::InstantiationResultResolver> resolver(
1179 new InstantiateModuleResultResolver(isolate, context, promise_resolver));
1180
1181 Local<Value> first_arg_value = info[0];
1183 Utils::OpenDirectHandle(*first_arg_value);
1184 if (!IsJSObject(*first_arg)) {
1185 thrower.TypeError(
1186 "Argument 0 must be a buffer source or a WebAssembly.Module object");
1187 resolver->OnInstantiationFailed(thrower.Reify());
1188 return;
1189 }
1190
1191 // If info.Length < 2, this will be undefined - see FunctionCallbackInfo.
1192 Local<Value> ffi = info[1];
1193
1194 if (!ffi->IsUndefined() && !ffi->IsObject()) {
1195 thrower.TypeError("Argument 1 must be an object");
1196 resolver->OnInstantiationFailed(thrower.Reify());
1197 return;
1198 }
1199
1200 if (IsWasmModuleObject(*first_arg)) {
1203
1204 i::wasm::GetWasmEngine()->AsyncInstantiate(i_isolate, std::move(resolver),
1205 module_obj,
1206 ImportsAsMaybeReceiver(ffi));
1207 return;
1208 }
1209
1210 base::OwnedVector<const uint8_t> bytes = GetAndCopyFirstArgumentAsBytes(
1211 info, i::wasm::max_module_size(), &thrower);
1212 if (bytes.empty()) {
1213 resolver->OnInstantiationFailed(thrower.Reify());
1214 return;
1215 }
1216
1217 // We start compilation now, we have no use for the
1218 // {InstantiationResultResolver}.
1219 resolver.reset();
1220
1221 std::shared_ptr<i::wasm::CompilationResultResolver> compilation_resolver(
1222 new AsyncInstantiateCompileResultResolver(isolate, context,
1223 promise_resolver, ffi));
1224
1225 // The first parameter is a buffer source, we have to check if we are allowed
1226 // to compile it.
1228 i_isolate->native_context();
1229 if (!i::wasm::IsWasmCodegenAllowed(i_isolate, native_context)) {
1231 i::wasm::ErrorStringForCodegen(i_isolate, native_context);
1232 thrower.CompileError("%s", error->ToCString().get());
1233 compilation_resolver->OnCompilationFailed(thrower.Reify());
1234 return;
1235 }
1236
1237 auto enabled_features = WasmEnabledFeatures::FromIsolate(i_isolate);
1238 CompileTimeImports compile_imports =
1239 ArgumentToCompileOptions(info[2], i_isolate, enabled_features);
1240 if (i_isolate->has_exception()) {
1241 if (i_isolate->is_execution_terminating()) return;
1242 i::DirectHandle<i::JSAny> exception(Cast<i::JSAny>(i_isolate->exception()),
1243 i_isolate);
1244 i_isolate->clear_exception();
1245 compilation_resolver->OnCompilationFailed(exception);
1246 return;
1247 }
1248
1249 i::wasm::GetWasmEngine()->AsyncCompile(
1250 i_isolate, enabled_features, std::move(compile_imports),
1251 std::move(compilation_resolver), std::move(bytes),
1252 js_api_scope.api_name());
1253}
1254
1255namespace {
1256// {AddressValueToU64} as defined in the memory64 js-api spec.
1257// Returns std::nullopt on error (exception or error set in the thrower), and
1258// the address value otherwise.
1259template <typename Name>
1260std::optional<uint64_t> AddressValueToU64(ErrorThrower* thrower,
1261 Local<Context> context,
1263 Name property_name,
1264 AddressType address_type) {
1265 switch (address_type) {
1266 case AddressType::kI32:
1267 return EnforceUint32(property_name, value, context, thrower);
1268 case AddressType::kI64:
1269 return EnforceBigIntUint64(property_name, value, context, thrower);
1270 }
1271 // The enum value is coming from inside the sandbox and while the switch is
1272 // exhaustive, it's not guaranteed that value is one of the declared values.
1273 SBXCHECK(false);
1274}
1275
1276// {AddressValueToU64} plus additional bounds checks.
1277std::optional<uint64_t> AddressValueToBoundedU64(
1278 ErrorThrower* thrower, Local<Context> context, v8::Local<v8::Value> value,
1279 i::DirectHandle<i::String> property_name, AddressType address_type,
1280 uint64_t lower_bound, uint64_t upper_bound) {
1281 std::optional<uint64_t> maybe_address_value =
1282 AddressValueToU64(thrower, context, value, property_name, address_type);
1283 if (!maybe_address_value) return std::nullopt;
1284 uint64_t address_value = *maybe_address_value;
1285
1286 if (address_value < lower_bound) {
1287 thrower->RangeError(
1288 "Property '%s': value %" PRIu64 " is below the lower bound %" PRIx64,
1289 property_name->ToCString().get(), address_value, lower_bound);
1290 return std::nullopt;
1291 }
1292
1293 if (address_value > upper_bound) {
1294 thrower->RangeError(
1295 "Property '%s': value %" PRIu64 " is above the upper bound %" PRIu64,
1296 property_name->ToCString().get(), address_value, upper_bound);
1297 return std::nullopt;
1298 }
1299
1300 return address_value;
1301}
1302
1303// Returns std::nullopt on error (exception or error set in the thrower).
1304// The inner optional is std::nullopt if the property did not exist, and the
1305// address value otherwise.
1306std::optional<std::optional<uint64_t>> GetOptionalAddressValue(
1307 ErrorThrower* thrower, Local<Context> context, Local<v8::Object> descriptor,
1308 Local<String> property, AddressType address_type, int64_t lower_bound,
1309 uint64_t upper_bound) {
1311 if (!descriptor->Get(context, property).ToLocal(&value)) {
1312 return std::nullopt;
1313 }
1314
1315 // Web IDL: dictionary presence
1316 // https://heycam.github.io/webidl/#dfn-present
1317 if (value->IsUndefined()) {
1318 // No exception, but no value either.
1319 return std::optional<uint64_t>{};
1320 }
1321
1322 i::DirectHandle<i::String> property_name =
1323 v8::Utils::OpenDirectHandle(*property);
1324
1325 std::optional<uint64_t> maybe_address_value =
1326 AddressValueToBoundedU64(thrower, context, value, property_name,
1327 address_type, lower_bound, upper_bound);
1328 if (!maybe_address_value) return std::nullopt;
1329 return *maybe_address_value;
1330}
1331
1332// Fetch 'initial' or 'minimum' property from `descriptor`. If both are
1333// provided, a TypeError is thrown.
1334// Returns std::nullopt on error (exception or error set in the thrower).
1335// TODO(aseemgarg): change behavior when the following bug is resolved:
1336// https://github.com/WebAssembly/js-types/issues/6
1337std::optional<uint64_t> GetInitialOrMinimumProperty(
1338 v8::Isolate* isolate, ErrorThrower* thrower, Local<Context> context,
1339 Local<v8::Object> descriptor, AddressType address_type,
1340 uint64_t upper_bound) {
1341 auto maybe_maybe_initial = GetOptionalAddressValue(
1342 thrower, context, descriptor, v8_str(isolate, "initial"), address_type, 0,
1343 upper_bound);
1344 if (!maybe_maybe_initial) return std::nullopt;
1345 std::optional<uint64_t> maybe_initial = *maybe_maybe_initial;
1346
1347 auto enabled_features =
1348 WasmEnabledFeatures::FromIsolate(reinterpret_cast<i::Isolate*>(isolate));
1349 if (enabled_features.has_type_reflection()) {
1350 auto maybe_maybe_minimum = GetOptionalAddressValue(
1351 thrower, context, descriptor, v8_str(isolate, "minimum"), address_type,
1352 0, upper_bound);
1353 if (!maybe_maybe_minimum) return std::nullopt;
1354 std::optional<uint64_t> maybe_minimum = *maybe_maybe_minimum;
1355
1356 if (maybe_initial && maybe_minimum) {
1357 thrower->TypeError(
1358 "The properties 'initial' and 'minimum' are not allowed at the same "
1359 "time");
1360 return std::nullopt;
1361 }
1362 if (maybe_minimum) {
1363 // Only 'minimum' exists, so we use 'minimum' as 'initial'.
1364 return *maybe_minimum;
1365 }
1366 }
1367 if (!maybe_initial) {
1368 // TODO(aseemgarg): update error message when the spec issue is resolved.
1369 thrower->TypeError("Property 'initial' is required");
1370 return std::nullopt;
1371 }
1372 return *maybe_initial;
1373}
1374
1375v8::Local<Value> AddressValueFromUnsigned(Isolate* isolate,
1376 i::wasm::AddressType type,
1377 unsigned value) {
1378 return type == i::wasm::AddressType::kI64
1379 ? BigInt::NewFromUnsigned(isolate, value).As<Value>()
1380 : Integer::NewFromUnsigned(isolate, value).As<Value>();
1381}
1382
1383i::DirectHandle<i::HeapObject> DefaultReferenceValue(i::Isolate* isolate,
1384 i::wasm::ValueType type) {
1385 DCHECK(type.is_object_reference());
1386 // Use undefined for JS type (externref) but null for wasm types as wasm does
1387 // not know undefined.
1388 if (type.heap_representation() == i::wasm::HeapType::kExtern) {
1389 return isolate->factory()->undefined_value();
1390 } else if (!type.use_wasm_null()) {
1391 return isolate->factory()->null_value();
1392 }
1393 return isolate->factory()->wasm_null();
1394}
1395
1396// Read the address type from a Memory or Table descriptor.
1397std::optional<AddressType> GetAddressType(Isolate* isolate,
1398 Local<Context> context,
1399 Local<v8::Object> descriptor,
1400 ErrorThrower* thrower) {
1401 v8::Local<v8::Value> address_value;
1402 if (!descriptor->Get(context, v8_str(isolate, "address"))
1403 .ToLocal(&address_value)) {
1404 return std::nullopt;
1405 }
1406
1407 if (address_value->IsUndefined()) return AddressType::kI32;
1408
1410 if (!i::Object::ToString(reinterpret_cast<i::Isolate*>(isolate),
1411 Utils::OpenDirectHandle(*address_value))
1412 .ToHandle(&address)) {
1413 return std::nullopt;
1414 }
1415
1416 if (address->IsEqualTo(base::CStrVector("i64"))) return AddressType::kI64;
1417 if (address->IsEqualTo(base::CStrVector("i32"))) return AddressType::kI32;
1418
1419 thrower->TypeError("Unknown address type '%s'; pass 'i32' or 'i64'",
1420 address->ToCString().get());
1421 return std::nullopt;
1422}
1423} // namespace
1424
1425// new WebAssembly.Table(descriptor) -> WebAssembly.Table
1426void WebAssemblyTableImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
1427 WasmJSApiScope js_api_scope{info, "WebAssembly.Table()"};
1428 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
1429
1430 if (!info.IsConstructCall()) {
1431 thrower.TypeError("WebAssembly.Table must be invoked with 'new'");
1432 return;
1433 }
1434 if (!info[0]->IsObject()) {
1435 thrower.TypeError("Argument 0 must be a table descriptor");
1436 return;
1437 }
1438 Local<Context> context = isolate->GetCurrentContext();
1439 Local<v8::Object> descriptor = Local<Object>::Cast(info[0]);
1440 i::wasm::ValueType type;
1441 // Parse the 'element' property of the `descriptor`.
1442 {
1444 if (!descriptor->Get(context, v8_str(isolate, "element")).ToLocal(&value)) {
1445 return js_api_scope.AssertException();
1446 }
1448 if (!i::Object::ToString(reinterpret_cast<i::Isolate*>(isolate),
1450 .ToHandle(&string)) {
1451 return js_api_scope.AssertException();
1452 }
1453 auto enabled_features = WasmEnabledFeatures::FromIsolate(i_isolate);
1454 // The JS api uses 'anyfunc' instead of 'funcref'.
1455 if (string->IsEqualTo(base::CStrVector("anyfunc"))) {
1456 type = i::wasm::kWasmFuncRef;
1457 } else if (enabled_features.has_type_reflection() &&
1458 string->IsEqualTo(base::CStrVector("funcref"))) {
1459 // With the type reflection proposal, "funcref" replaces "anyfunc",
1460 // and anyfunc just becomes an alias for "funcref".
1461 type = i::wasm::kWasmFuncRef;
1462 } else if (string->IsEqualTo(base::CStrVector("externref"))) {
1463 type = i::wasm::kWasmExternRef;
1464 } else if (enabled_features.has_stringref() &&
1465 string->IsEqualTo(base::CStrVector("stringref"))) {
1466 type = i::wasm::kWasmStringRef;
1467 } else if (string->IsEqualTo(base::CStrVector("anyref"))) {
1468 type = i::wasm::kWasmAnyRef;
1469 } else if (string->IsEqualTo(base::CStrVector("eqref"))) {
1470 type = i::wasm::kWasmEqRef;
1471 } else if (string->IsEqualTo(base::CStrVector("structref"))) {
1472 type = i::wasm::kWasmStructRef;
1473 } else if (string->IsEqualTo(base::CStrVector("arrayref"))) {
1474 type = i::wasm::kWasmArrayRef;
1475 } else if (string->IsEqualTo(base::CStrVector("i31ref"))) {
1476 type = i::wasm::kWasmI31Ref;
1477 } else {
1478 thrower.TypeError(
1479 "Descriptor property 'element' must be a WebAssembly reference type");
1480 return;
1481 }
1482 // TODO(14616): Support shared types.
1483 }
1484
1485 // Parse the 'address' property of the `descriptor`.
1486 std::optional<AddressType> maybe_address_type =
1487 GetAddressType(isolate, context, descriptor, &thrower);
1488 if (!maybe_address_type) {
1489 DCHECK(i_isolate->has_exception() || thrower.error());
1490 return;
1491 }
1492 AddressType address_type = *maybe_address_type;
1493
1494 // Parse the 'initial' or 'minimum' property of the `descriptor`.
1495 std::optional<uint64_t> maybe_initial = GetInitialOrMinimumProperty(
1496 isolate, &thrower, context, descriptor, address_type,
1497 i::wasm::max_table_init_entries());
1498 if (!maybe_initial) return js_api_scope.AssertException();
1499 static_assert(i::wasm::kV8MaxWasmTableInitEntries <= i::kMaxUInt32);
1500 uint32_t initial = static_cast<uint32_t>(*maybe_initial);
1501
1502 // Parse the 'maximum' property of the `descriptor`.
1503 uint64_t kNoMaximum = i::kMaxUInt64;
1504 auto maybe_maybe_maximum = GetOptionalAddressValue(
1505 &thrower, context, descriptor, v8_str(isolate, "maximum"), address_type,
1506 initial, kNoMaximum);
1507 if (!maybe_maybe_maximum) return js_api_scope.AssertException();
1508 std::optional<uint64_t> maybe_maximum = *maybe_maybe_maximum;
1509
1510 DCHECK(!type.has_index()); // The JS API can't express type indices.
1511 i::wasm::CanonicalValueType canonical_type{type};
1512 i::DirectHandle<i::WasmTableObject> table_obj = i::WasmTableObject::New(
1514 canonical_type, initial, maybe_maximum.has_value(),
1515 maybe_maximum.value_or(0) /* note: unused if previous param is false */,
1516 DefaultReferenceValue(i_isolate, type), address_type);
1517
1518 // The infrastructure for `new Foo` calls allocates an object, which is
1519 // available here as {info.This()}. We're going to discard this object
1520 // and use {table_obj} instead, but it does have the correct prototype,
1521 // which we must harvest from it. This makes a difference when the JS
1522 // constructor function wasn't {WebAssembly.Table} directly, but some
1523 // subclass: {table_obj} has {WebAssembly.Table}'s prototype at this
1524 // point, so we must overwrite that with the correct prototype for {Foo}.
1525 if (!TransferPrototype(i_isolate, table_obj,
1526 Utils::OpenDirectHandle(*info.This()))) {
1527 return js_api_scope.AssertException();
1528 }
1529
1530 if (initial > 0 && info.Length() >= 2 && !info[1]->IsUndefined()) {
1532 const char* error_message;
1533 if (!i::WasmTableObject::JSToWasmElement(i_isolate, table_obj, element,
1534 &error_message)
1535 .ToHandle(&element)) {
1536 thrower.TypeError(
1537 "Argument 2 must be undefined or a value of type compatible "
1538 "with the type of the new table: %s.",
1539 error_message);
1540 return;
1541 }
1542 for (uint32_t index = 0; index < static_cast<uint32_t>(initial); ++index) {
1543 i::WasmTableObject::Set(i_isolate, table_obj, index, element);
1544 }
1545 } else if (initial > 0) {
1546 DCHECK_EQ(type, table_obj->unsafe_type());
1547 switch (type.heap_representation()) {
1548 case i::wasm::HeapType::kString:
1549 thrower.TypeError(
1550 "Missing initial value when creating stringref table");
1551 return;
1552 case i::wasm::HeapType::kStringViewWtf8:
1553 thrower.TypeError("stringview_wtf8 has no JS representation");
1554 return;
1555 case i::wasm::HeapType::kStringViewWtf16:
1556 thrower.TypeError("stringview_wtf16 has no JS representation");
1557 return;
1558 case i::wasm::HeapType::kStringViewIter:
1559 thrower.TypeError("stringview_iter has no JS representation");
1560 return;
1561 default:
1562 break;
1563 }
1564 }
1565 v8::ReturnValue<v8::Value> return_value = info.GetReturnValue();
1566 return_value.Set(Utils::ToLocal(i::Cast<i::JSObject>(table_obj)));
1567}
1568
1569// new WebAssembly.Memory(descriptor) -> WebAssembly.Memory
1570void WebAssemblyMemoryImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
1571 WasmJSApiScope js_api_scope{info, "WebAssembly.Memory()"};
1572 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
1573
1574 if (!info.IsConstructCall()) {
1575 thrower.TypeError("WebAssembly.Memory must be invoked with 'new'");
1576 return;
1577 }
1578 if (!info[0]->IsObject()) {
1579 thrower.TypeError("Argument 0 must be a memory descriptor");
1580 return;
1581 }
1582 Local<Context> context = isolate->GetCurrentContext();
1583 Local<v8::Object> descriptor = Local<Object>::Cast(info[0]);
1584
1585 // Parse the 'address' property of the `descriptor`.
1586 std::optional<AddressType> maybe_address_type =
1587 GetAddressType(isolate, context, descriptor, &thrower);
1588 if (!maybe_address_type) return js_api_scope.AssertException();
1589 AddressType address_type = *maybe_address_type;
1590 uint64_t max_supported_pages = address_type == AddressType::kI64
1591 ? i::wasm::kSpecMaxMemory64Pages
1592 : i::wasm::kSpecMaxMemory32Pages;
1593 // {max_supported_pages} will actually be in integer range. That's the type
1594 // {WasmMemoryObject::New} uses.
1595 static_assert(i::wasm::kSpecMaxMemory32Pages < i::kMaxInt);
1596 static_assert(i::wasm::kSpecMaxMemory64Pages < i::kMaxInt);
1597
1598 // Parse the 'initial' or 'minimum' property of the `descriptor`.
1599 std::optional<uint64_t> maybe_initial =
1600 GetInitialOrMinimumProperty(isolate, &thrower, context, descriptor,
1601 address_type, max_supported_pages);
1602 if (!maybe_initial) {
1603 return js_api_scope.AssertException();
1604 }
1605 uint64_t initial = *maybe_initial;
1606
1607 // Parse the 'maximum' property of the `descriptor`.
1608 auto maybe_maybe_maximum = GetOptionalAddressValue(
1609 &thrower, context, descriptor, v8_str(isolate, "maximum"), address_type,
1610 initial, max_supported_pages);
1611 if (!maybe_maybe_maximum) {
1612 return js_api_scope.AssertException();
1613 }
1614 std::optional<uint64_t> maybe_maximum = *maybe_maybe_maximum;
1615
1616 // Parse the 'shared' property of the `descriptor`.
1618 if (!descriptor->Get(context, v8_str(isolate, "shared")).ToLocal(&value)) {
1619 return js_api_scope.AssertException();
1620 }
1621
1622 auto shared = value->BooleanValue(isolate) ? i::SharedFlag::kShared
1623 : i::SharedFlag::kNotShared;
1624
1625 // Throw TypeError if shared is true, and the descriptor has no "maximum".
1626 if (shared == i::SharedFlag::kShared && !maybe_maximum.has_value()) {
1627 thrower.TypeError("If shared is true, maximum property should be defined.");
1628 return;
1629 }
1630
1632 if (!i::WasmMemoryObject::New(i_isolate, static_cast<int>(initial),
1633 maybe_maximum ? static_cast<int>(*maybe_maximum)
1634 : i::WasmMemoryObject::kNoMaximum,
1635 shared, address_type)
1636 .ToHandle(&memory_obj)) {
1637 thrower.RangeError("could not allocate memory");
1638 return;
1639 }
1640
1641 // The infrastructure for `new Foo` calls allocates an object, which is
1642 // available here as {info.This()}. We're going to discard this object
1643 // and use {memory_obj} instead, but it does have the correct prototype,
1644 // which we must harvest from it. This makes a difference when the JS
1645 // constructor function wasn't {WebAssembly.Memory} directly, but some
1646 // subclass: {memory_obj} has {WebAssembly.Memory}'s prototype at this
1647 // point, so we must overwrite that with the correct prototype for {Foo}.
1648 if (!TransferPrototype(i_isolate, memory_obj,
1649 Utils::OpenDirectHandle(*info.This()))) {
1650 return js_api_scope.AssertException();
1651 }
1652
1653 if (shared == i::SharedFlag::kShared) {
1655 i::Cast<i::WasmMemoryObject>(memory_obj)->array_buffer(), i_isolate);
1656 Maybe<bool> result =
1657 buffer->SetIntegrityLevel(i_isolate, buffer, i::FROZEN, i::kDontThrow);
1658 if (!result.FromJust()) {
1659 thrower.TypeError(
1660 "Status of setting SetIntegrityLevel of buffer is false.");
1661 return;
1662 }
1663 }
1664 info.GetReturnValue().Set(Utils::ToLocal(memory_obj));
1665}
1666
1667// new WebAssembly.MemoryMapDescriptor(size) -> WebAssembly.MemoryMapDescriptor
1668void WebAssemblyMemoryMapDescriptorImpl(
1670 CHECK(i::v8_flags.experimental_wasm_memory_control);
1671 WasmJSApiScope js_api_scope{info, "WebAssembly.MemoryMapDescriptor()"};
1672 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
1673 if (!info.IsConstructCall()) {
1674 thrower.TypeError(
1675 "WebAssembly.MemoryMapDescriptor must be invoked with 'new'");
1676 return js_api_scope.AssertException();
1677 }
1678
1679 std::optional<uint32_t> size =
1680 EnforceUint32("size", info[0], isolate->GetCurrentContext(), &thrower);
1681
1682 if (!size.has_value()) {
1683 return js_api_scope.AssertException();
1684 }
1685
1686 i::DirectHandle<i::JSObject> descriptor_obj;
1687 if (!i::WasmMemoryMapDescriptor::NewFromAnonymous(i_isolate, size.value())
1688 .ToHandle(&descriptor_obj)) {
1689 thrower.RuntimeError("Failed to create a MemoryMapDescriptor");
1690 return js_api_scope.AssertException();
1691 }
1692
1693 // The infrastructure for `new Foo` calls allocates an object, which is
1694 // available here as {info.This()}. We're going to discard this object
1695 // and use {memory_obj} instead, but it does have the correct prototype,
1696 // which we must harvest from it. This makes a difference when the JS
1697 // constructor function wasn't {WebAssembly.Memory} directly, but some
1698 // subclass: {memory_obj} has {WebAssembly.Memory}'s prototype at this
1699 // point, so we must overwrite that with the correct prototype for {Foo}.
1700 if (!TransferPrototype(i_isolate, descriptor_obj,
1701 Utils::OpenDirectHandle(*info.This()))) {
1702 DCHECK(i_isolate->has_exception());
1703 return js_api_scope.AssertException();
1704 }
1705
1706 info.GetReturnValue().Set(Utils::ToLocal(descriptor_obj));
1707}
1708
1709// Determines the type encoded in a value type property (e.g. type reflection).
1710// Returns false if there was an exception, true upon success. On success the
1711// outgoing {type} is set accordingly, or set to {wasm::kWasmVoid} in case the
1712// type could not be properly recognized.
1713std::optional<i::wasm::ValueType> GetValueType(
1714 Isolate* isolate, MaybeLocal<Value> maybe, Local<Context> context,
1715 WasmEnabledFeatures enabled_features) {
1717 if (!maybe.ToLocal(&value)) return std::nullopt;
1719 if (!i::Object::ToString(reinterpret_cast<i::Isolate*>(isolate),
1721 .ToHandle(&string)) {
1722 return std::nullopt;
1723 }
1724 if (string->IsEqualTo(base::CStrVector("i32"))) {
1725 return i::wasm::kWasmI32;
1726 } else if (string->IsEqualTo(base::CStrVector("f32"))) {
1727 return i::wasm::kWasmF32;
1728 } else if (string->IsEqualTo(base::CStrVector("i64"))) {
1729 return i::wasm::kWasmI64;
1730 } else if (string->IsEqualTo(base::CStrVector("f64"))) {
1731 return i::wasm::kWasmF64;
1732 } else if (string->IsEqualTo(base::CStrVector("v128"))) {
1733 return i::wasm::kWasmS128;
1734 } else if (string->IsEqualTo(base::CStrVector("externref"))) {
1735 return i::wasm::kWasmExternRef;
1736 } else if (enabled_features.has_type_reflection() &&
1737 string->IsEqualTo(base::CStrVector("funcref"))) {
1738 // The type reflection proposal renames "anyfunc" to "funcref", and makes
1739 // "anyfunc" an alias of "funcref".
1740 return i::wasm::kWasmFuncRef;
1741 } else if (string->IsEqualTo(base::CStrVector("anyfunc"))) {
1742 // The JS api spec uses 'anyfunc' instead of 'funcref'.
1743 return i::wasm::kWasmFuncRef;
1744 } else if (string->IsEqualTo(base::CStrVector("eqref"))) {
1745 return i::wasm::kWasmEqRef;
1746 } else if (enabled_features.has_stringref() &&
1747 string->IsEqualTo(base::CStrVector("stringref"))) {
1748 return i::wasm::kWasmStringRef;
1749 } else if (string->IsEqualTo(base::CStrVector("anyref"))) {
1750 return i::wasm::kWasmAnyRef;
1751 } else if (string->IsEqualTo(base::CStrVector("structref"))) {
1752 return i::wasm::kWasmStructRef;
1753 } else if (string->IsEqualTo(base::CStrVector("arrayref"))) {
1754 return i::wasm::kWasmArrayRef;
1755 } else if (string->IsEqualTo(base::CStrVector("i31ref"))) {
1756 return i::wasm::kWasmI31Ref;
1757 } else if (enabled_features.has_exnref() &&
1758 string->IsEqualTo(base::CStrVector("exnref"))) {
1759 return i::wasm::kWasmExnRef;
1760 }
1761 // Unrecognized type.
1762 return i::wasm::kWasmVoid;
1763}
1764
1765namespace {
1766
1767bool ToI32(Local<v8::Value> value, Local<Context> context, int32_t* i32_value) {
1768 if (!value->IsUndefined()) {
1769 v8::Local<v8::Int32> int32_value;
1770 if (!value->ToInt32(context).ToLocal(&int32_value)) return false;
1771 if (!int32_value->Int32Value(context).To(i32_value)) return false;
1772 }
1773 return true;
1774}
1775
1776bool ToI64(Local<v8::Value> value, Local<Context> context, int64_t* i64_value) {
1777 if (!value->IsUndefined()) {
1778 v8::Local<v8::BigInt> bigint_value;
1779 if (!value->ToBigInt(context).ToLocal(&bigint_value)) return false;
1780 *i64_value = bigint_value->Int64Value();
1781 }
1782 return true;
1783}
1784
1785bool ToF32(Local<v8::Value> value, Local<Context> context, float* f32_value) {
1786 if (!value->IsUndefined()) {
1787 double f64_value = 0;
1788 v8::Local<v8::Number> number_value;
1789 if (!value->ToNumber(context).ToLocal(&number_value)) return false;
1790 if (!number_value->NumberValue(context).To(&f64_value)) return false;
1791 *f32_value = i::DoubleToFloat32(f64_value);
1792 }
1793 return true;
1794}
1795
1796bool ToF64(Local<v8::Value> value, Local<Context> context, double* f64_value) {
1797 if (!value->IsUndefined()) {
1798 v8::Local<v8::Number> number_value;
1799 if (!value->ToNumber(context).ToLocal(&number_value)) return false;
1800 if (!number_value->NumberValue(context).To(f64_value)) return false;
1801 }
1802 return true;
1803}
1804} // namespace
1805
1806// WebAssembly.Global
1807void WebAssemblyGlobalImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
1808 WasmJSApiScope js_api_scope{info, "WebAssembly.Global()"};
1809 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
1810
1811 if (!info.IsConstructCall()) {
1812 thrower.TypeError("WebAssembly.Global must be invoked with 'new'");
1813 return;
1814 }
1815 if (!info[0]->IsObject()) {
1816 thrower.TypeError("Argument 0 must be a global descriptor");
1817 return;
1818 }
1819 Local<Context> context = isolate->GetCurrentContext();
1820 Local<v8::Object> descriptor = Local<Object>::Cast(info[0]);
1821 auto enabled_features = WasmEnabledFeatures::FromIsolate(i_isolate);
1822
1823 // The descriptor's 'mutable'.
1824 bool is_mutable;
1825 {
1827 if (!descriptor->Get(context, v8_str(isolate, "mutable")).ToLocal(&value)) {
1828 return js_api_scope.AssertException();
1829 }
1830 is_mutable = value->BooleanValue(isolate);
1831 }
1832
1833 // The descriptor's type, called 'value'. It is called 'value' because this
1834 // descriptor is planned to be reused as the global's type for reflection,
1835 // so calling it 'type' is redundant.
1836 i::wasm::ValueType type;
1837 {
1839 descriptor->Get(context, v8_str(isolate, "value"));
1840 std::optional<i::wasm::ValueType> maybe_type =
1841 GetValueType(isolate, maybe, context, enabled_features);
1842 if (!maybe_type) return js_api_scope.AssertException();
1843 type = *maybe_type;
1844 if (type == i::wasm::kWasmVoid) {
1845 thrower.TypeError(
1846 "Descriptor property 'value' must be a WebAssembly type");
1847 return;
1848 }
1849 }
1850
1851 const uint32_t offset = 0;
1853 i::WasmGlobalObject::New(
1856 i::MaybeDirectHandle<i::FixedArray>(), type, offset, is_mutable);
1857
1859 if (!maybe_global_obj.ToHandle(&global_obj)) {
1860 return js_api_scope.AssertException();
1861 }
1862
1863 // The infrastructure for `new Foo` calls allocates an object, which is
1864 // available here as {info.This()}. We're going to discard this object
1865 // and use {global_obj} instead, but it does have the correct prototype,
1866 // which we must harvest from it. This makes a difference when the JS
1867 // constructor function wasn't {WebAssembly.Global} directly, but some
1868 // subclass: {global_obj} has {WebAssembly.Global}'s prototype at this
1869 // point, so we must overwrite that with the correct prototype for {Foo}.
1870 if (!TransferPrototype(i_isolate, global_obj,
1871 Utils::OpenDirectHandle(*info.This()))) {
1872 return js_api_scope.AssertException();
1873 }
1874
1875 // Convert value to a WebAssembly value, the default value is 0.
1876 Local<v8::Value> value = Local<Value>::Cast(info[1]);
1877 switch (type.kind()) {
1878 case i::wasm::kI32: {
1879 int32_t i32_value = 0;
1880 if (!ToI32(value, context, &i32_value)) {
1881 return js_api_scope.AssertException();
1882 }
1883 global_obj->SetI32(i32_value);
1884 break;
1885 }
1886 case i::wasm::kI64: {
1887 int64_t i64_value = 0;
1888 if (!ToI64(value, context, &i64_value)) {
1889 return js_api_scope.AssertException();
1890 }
1891 global_obj->SetI64(i64_value);
1892 break;
1893 }
1894 case i::wasm::kF32: {
1895 float f32_value = 0;
1896 if (!ToF32(value, context, &f32_value)) {
1897 return js_api_scope.AssertException();
1898 }
1899 global_obj->SetF32(f32_value);
1900 break;
1901 }
1902 case i::wasm::kF64: {
1903 double f64_value = 0;
1904 if (!ToF64(value, context, &f64_value)) {
1905 return js_api_scope.AssertException();
1906 }
1907 global_obj->SetF64(f64_value);
1908 break;
1909 }
1910 case i::wasm::kRef:
1911 if (info.Length() < 2) {
1912 thrower.TypeError("Non-defaultable global needs initial value");
1913 return;
1914 }
1915 [[fallthrough]];
1916 case i::wasm::kRefNull: {
1917 // We need the wasm default value {null} over {undefined}.
1918 i::DirectHandle<i::Object> value_handle;
1919 if (info.Length() < 2) {
1920 value_handle = DefaultReferenceValue(i_isolate, type);
1921 } else {
1922 value_handle = Utils::OpenDirectHandle(*value);
1923 const char* error_message;
1924 // While the JS API generally allows indexed types, it currently has
1925 // no way to specify such types in `new WebAssembly.Global(...)`.
1926 // TODO(14034): Fix this if that changes.
1927 DCHECK(!type.has_index());
1928 i::wasm::CanonicalValueType canonical_type{type};
1929 if (!i::wasm::JSToWasmObject(i_isolate, value_handle, canonical_type,
1930 &error_message)
1931 .ToHandle(&value_handle)) {
1932 thrower.TypeError("%s", error_message);
1933 return;
1934 }
1935 }
1936 global_obj->SetRef(value_handle);
1937 break;
1938 }
1939 case i::wasm::kS128: {
1940 thrower.TypeError(
1941 "A global of type 'v128' cannot be created in JavaScript");
1942 return;
1943 }
1944 case i::wasm::kI8:
1945 case i::wasm::kI16:
1946 case i::wasm::kF16:
1947 case i::wasm::kVoid:
1948 case i::wasm::kTop:
1949 case i::wasm::kBottom:
1950 UNREACHABLE();
1951 }
1952
1953 i::DirectHandle<i::JSObject> global_js_object(global_obj);
1954 info.GetReturnValue().Set(Utils::ToLocal(global_js_object));
1955}
1956
1957namespace {
1958
1959uint32_t GetIterableLength(i::Isolate* isolate, Local<Context> context,
1960 Local<Object> iterable) {
1961 Local<String> length = Utils::ToLocal(isolate->factory()->length_string());
1962 MaybeLocal<Value> property = iterable->Get(context, length);
1963 if (property.IsEmpty()) return i::kMaxUInt32;
1964 MaybeLocal<Uint32> number = property.ToLocalChecked()->ToArrayIndex(context);
1965 if (number.IsEmpty()) return i::kMaxUInt32;
1966 DCHECK_NE(i::kMaxUInt32, number.ToLocalChecked()->Value());
1967 return number.ToLocalChecked()->Value();
1968}
1969
1970} // namespace
1971
1972// WebAssembly.Tag
1973void WebAssemblyTagImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
1974 WasmJSApiScope js_api_scope{info, "WebAssembly.Tag()"};
1975 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
1976
1977 if (!info.IsConstructCall()) {
1978 thrower.TypeError("WebAssembly.Tag must be invoked with 'new'");
1979 return;
1980 }
1981 if (!info[0]->IsObject()) {
1982 thrower.TypeError("Argument 0 must be a tag type");
1983 return;
1984 }
1985
1986 Local<Object> event_type = Local<Object>::Cast(info[0]);
1987 Local<Context> context = isolate->GetCurrentContext();
1988 auto enabled_features = WasmEnabledFeatures::FromIsolate(i_isolate);
1989
1990 // Load the 'parameters' property of the event type.
1991 Local<String> parameters_key = v8_str(isolate, "parameters");
1992 v8::MaybeLocal<v8::Value> parameters_maybe =
1993 event_type->Get(context, parameters_key);
1994 v8::Local<v8::Value> parameters_value;
1995 if (!parameters_maybe.ToLocal(&parameters_value) ||
1996 !parameters_value->IsObject()) {
1997 thrower.TypeError("Argument 0 must be a tag type with 'parameters'");
1998 return;
1999 }
2000 Local<Object> parameters = parameters_value.As<Object>();
2001 uint32_t parameters_len = GetIterableLength(i_isolate, context, parameters);
2002 if (parameters_len == i::kMaxUInt32) {
2003 thrower.TypeError("Argument 0 contains parameters without 'length'");
2004 return;
2005 }
2006 if (parameters_len > i::wasm::kV8MaxWasmFunctionParams) {
2007 thrower.TypeError("Argument 0 contains too many parameters");
2008 return;
2009 }
2010
2011 // Decode the tag type and construct a signature.
2012 std::vector<i::wasm::ValueType> param_types(parameters_len,
2013 i::wasm::kWasmVoid);
2014 for (uint32_t i = 0; i < parameters_len; ++i) {
2015 i::wasm::ValueType& type = param_types[i];
2016 MaybeLocal<Value> maybe = parameters->Get(context, i);
2017 std::optional<i::wasm::ValueType> maybe_type =
2018 GetValueType(isolate, maybe, context, enabled_features);
2019 if (!maybe_type) return;
2020 type = *maybe_type;
2021 if (type == i::wasm::kWasmVoid) {
2022 thrower.TypeError(
2023 "Argument 0 parameter type at index #%u must be a value type", i);
2024 return;
2025 }
2026 }
2027 const i::wasm::FunctionSig sig{0, parameters_len, param_types.data()};
2028 // Set the tag index to 0. It is only used for debugging purposes, and has no
2029 // meaningful value when declared outside of a wasm module.
2030 auto tag = i::WasmExceptionTag::New(i_isolate, 0);
2031
2032 i::wasm::CanonicalTypeIndex type_index =
2033 i::wasm::GetWasmEngine()->type_canonicalizer()->AddRecursiveGroup(&sig);
2034
2035 i::DirectHandle<i::JSObject> tag_object =
2036 i::WasmTagObject::New(i_isolate, &sig, type_index, tag,
2038 info.GetReturnValue().Set(Utils::ToLocal(tag_object));
2039}
2040
2041namespace {
2042
2043uint32_t GetEncodedSize(i::DirectHandle<i::WasmTagObject> tag_object) {
2044 auto serialized_sig = tag_object->serialized_signature();
2045 i::wasm::WasmTagSig sig{
2046 0, static_cast<size_t>(serialized_sig->length()),
2047 reinterpret_cast<i::wasm::ValueType*>(serialized_sig->begin())};
2048 return i::WasmExceptionPackage::GetEncodedSize(&sig);
2049}
2050
2051V8_WARN_UNUSED_RESULT bool EncodeExceptionValues(
2052 v8::Isolate* isolate,
2054 i::DirectHandle<i::WasmTagObject> tag_object, const Local<Value>& arg,
2055 ErrorThrower* thrower, i::DirectHandle<i::FixedArray> values_out) {
2056 Local<Context> context = isolate->GetCurrentContext();
2057 uint32_t index = 0;
2058 if (!arg->IsObject()) {
2059 thrower->TypeError("Exception values must be an iterable object");
2060 return false;
2061 }
2062 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2063 auto values = arg.As<Object>();
2064 uint32_t length = GetIterableLength(i_isolate, context, values);
2065 if (length == i::kMaxUInt32) {
2066 thrower->TypeError("Exception values argument has no length");
2067 return false;
2068 }
2069 if (length != static_cast<uint32_t>(signature->length())) {
2070 thrower->TypeError(
2071 "Number of exception values does not match signature length");
2072 return false;
2073 }
2074 for (int i = 0; i < signature->length(); ++i) {
2075 Local<Value> value;
2076 if (!values->Get(context, i).ToLocal(&value)) return false;
2077 i::wasm::ValueType type = signature->get(i);
2078 switch (type.kind()) {
2079 case i::wasm::kI32: {
2080 int32_t i32 = 0;
2081 if (!ToI32(value, context, &i32)) return false;
2082 i::EncodeI32ExceptionValue(values_out, &index, i32);
2083 break;
2084 }
2085 case i::wasm::kI64: {
2086 int64_t i64 = 0;
2087 if (!ToI64(value, context, &i64)) return false;
2088 i::EncodeI64ExceptionValue(values_out, &index, i64);
2089 break;
2090 }
2091 case i::wasm::kF32: {
2092 float f32 = 0;
2093 if (!ToF32(value, context, &f32)) return false;
2095 i::EncodeI32ExceptionValue(values_out, &index, i32);
2096 break;
2097 }
2098 case i::wasm::kF64: {
2099 double f64 = 0;
2100 if (!ToF64(value, context, &f64)) return false;
2101 int64_t i64 = base::bit_cast<int64_t>(f64);
2102 i::EncodeI64ExceptionValue(values_out, &index, i64);
2103 break;
2104 }
2105 case i::wasm::kRef:
2106 case i::wasm::kRefNull: {
2107 const char* error_message;
2108 i::DirectHandle<i::Object> value_handle =
2110 i::wasm::CanonicalValueType canonical_type = i::wasm::kWasmBottom;
2111 if (type.has_index()) {
2112 // Canonicalize the type using the tag's original module.
2113 // Indexed types are guaranteed to come from an instance.
2114 DCHECK(tag_object->has_trusted_data());
2116 tag_object->trusted_data(i_isolate);
2117 const i::wasm::WasmModule* module = wtid->module();
2118 canonical_type =
2119 type.Canonicalize(module->canonical_type_id(type.ref_index()));
2120 } else {
2121 canonical_type = i::wasm::CanonicalValueType{type};
2122 }
2123 if (!i::wasm::JSToWasmObject(i_isolate, value_handle, canonical_type,
2124 &error_message)
2125 .ToHandle(&value_handle)) {
2126 thrower->TypeError("%s", error_message);
2127 return false;
2128 }
2129 values_out->set(index++, *value_handle);
2130 break;
2131 }
2132 case i::wasm::kS128:
2133 thrower->TypeError("Invalid type v128");
2134 return false;
2135 case i::wasm::kI8:
2136 case i::wasm::kI16:
2137 case i::wasm::kF16:
2138 case i::wasm::kVoid:
2139 case i::wasm::kTop:
2140 case i::wasm::kBottom:
2141 UNREACHABLE();
2142 }
2143 }
2144 return true;
2145}
2146
2147} // namespace
2148
2149void WebAssemblyExceptionImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
2150 WasmJSApiScope js_api_scope{info, "WebAssembly.Exception()"};
2151 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2152
2153 if (!info.IsConstructCall()) {
2154 thrower.TypeError("WebAssembly.Exception must be invoked with 'new'");
2155 return;
2156 }
2157 if (!info[0]->IsObject()) {
2158 thrower.TypeError("Argument 0 must be a WebAssembly tag");
2159 return;
2160 }
2162 if (!IsWasmTagObject(i::Cast<i::HeapObject>(*arg0))) {
2163 thrower.TypeError("Argument 0 must be a WebAssembly tag");
2164 return;
2165 }
2166 auto tag_object = i::Cast<i::WasmTagObject>(arg0);
2168 i::Cast<i::WasmExceptionTag>(tag_object->tag()), i_isolate);
2169 auto js_tag = i::Cast<i::WasmTagObject>(i_isolate->context()->wasm_js_tag());
2170 if (*tag == js_tag->tag()) {
2171 thrower.TypeError("Argument 0 cannot be WebAssembly.JSTag");
2172 return;
2173 }
2174 const i::wasm::CanonicalSig* sig =
2175 i::wasm::GetTypeCanonicalizer()->LookupFunctionSignature(
2176 i::wasm::CanonicalTypeIndex{
2177 static_cast<uint32_t>(tag_object->canonical_type_index())});
2178
2179 if (sig->return_count() != 0) {
2180 thrower.TypeError(
2181 "Invalid WebAssembly tag (return values not permitted in Exception "
2182 "tag)");
2183 return;
2184 }
2185
2186 uint32_t size = GetEncodedSize(tag_object);
2188 i::WasmExceptionPackage::New(i_isolate, tag, size);
2189 // The constructor above should guarantee that the cast below succeeds.
2191 i::Cast<i::FixedArray>(i::WasmExceptionPackage::GetExceptionValues(
2192 i_isolate, runtime_exception));
2194 tag_object->serialized_signature(), i_isolate);
2195 if (!EncodeExceptionValues(isolate, signature, tag_object, info[1], &thrower,
2196 values)) {
2197 return js_api_scope.AssertException();
2198 }
2199
2200 // Third argument: optional ExceptionOption ({traceStack: <bool>}).
2201 if (!info[2]->IsNullOrUndefined() && !info[2]->IsObject()) {
2202 thrower.TypeError("Argument 2 is not an object");
2203 return;
2204 }
2205 if (info[2]->IsObject()) {
2206 Local<Context> context = isolate->GetCurrentContext();
2207 Local<Object> trace_stack_obj = Local<Object>::Cast(info[2]);
2208 Local<String> trace_stack_key = v8_str(isolate, "traceStack");
2209 v8::Local<Value> trace_stack_value;
2210 if (!trace_stack_obj->Get(context, trace_stack_key)
2211 .ToLocal(&trace_stack_value)) {
2212 return js_api_scope.AssertException();
2213 }
2214 if (trace_stack_value->BooleanValue(isolate)) {
2215 i::Handle<i::Object> caller = Utils::OpenHandle(*info.NewTarget());
2216
2217 i::DirectHandle<i::Object> capture_result;
2218 if (!i::ErrorUtils::CaptureStackTrace(i_isolate, runtime_exception,
2219 i::SKIP_NONE, caller)
2220 .ToHandle(&capture_result)) {
2221 return js_api_scope.AssertException();
2222 }
2223 }
2224 }
2225
2226 info.GetReturnValue().Set(
2227 Utils::ToLocal(i::Cast<i::Object>(runtime_exception)));
2228}
2229
2230i::DirectHandle<i::JSFunction> NewPromisingWasmExportedFunction(
2232 ErrorThrower& thrower) {
2233 i::DirectHandle<i::WasmTrustedInstanceData> trusted_instance_data{
2234 data->instance_data(), i_isolate};
2235 int func_index = data->function_index();
2236 const i::wasm::WasmModule* module = trusted_instance_data->module();
2237 i::wasm::ModuleTypeIndex sig_index = module->functions[func_index].sig_index;
2238 const i::wasm::CanonicalSig* sig =
2239 i::wasm::GetTypeCanonicalizer()->LookupFunctionSignature(
2240 module->canonical_sig_id(sig_index));
2243 // If the signature is incompatible with JS, the original export will have
2244 // compiled an incompatible signature wrapper, so just reuse that.
2245 wrapper =
2246 i::DirectHandle<i::Code>(data->wrapper_code(i_isolate), i_isolate);
2247 } else {
2248 wrapper = BUILTIN_CODE(i_isolate, WasmPromising);
2249 }
2250
2251 // TODO(14034): Create funcref RTTs lazily?
2254 trusted_instance_data->managed_object_maps()->get(sig_index.index)),
2255 i_isolate};
2256
2257 int num_imported_functions = module->num_imported_functions;
2259 if (func_index >= num_imported_functions) {
2260 implicit_arg = trusted_instance_data;
2261 } else {
2262 implicit_arg = i_isolate->factory()->NewWasmImportData(direct_handle(
2264 trusted_instance_data->dispatch_table_for_imports()->implicit_arg(
2265 func_index)),
2266 i_isolate));
2267 }
2268
2270 i_isolate->factory()->NewWasmInternalFunction(implicit_arg, func_index);
2272 i_isolate->factory()->NewWasmFuncRef(internal, rtt);
2273 internal->set_call_target(trusted_instance_data->GetCallTarget(func_index));
2274 if (func_index < num_imported_functions) {
2275 i::Cast<i::WasmImportData>(implicit_arg)->set_call_origin(*internal);
2276 }
2277
2278 i::DirectHandle<i::JSFunction> result = i::WasmExportedFunction::New(
2279 i_isolate, trusted_instance_data, func_ref, internal,
2280 static_cast<int>(data->sig()->parameter_count()), wrapper);
2281 return result;
2282}
2283
2284// WebAssembly.Function
2285void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
2286 WasmJSApiScope js_api_scope{info, "WebAssembly.Function()"};
2287 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2288
2289 if (!info.IsConstructCall()) {
2290 thrower.TypeError("WebAssembly.Function must be invoked with 'new'");
2291 return;
2292 }
2293 if (!info[0]->IsObject()) {
2294 thrower.TypeError("Argument 0 must be a function type");
2295 return;
2296 }
2297 Local<Object> function_type = Local<Object>::Cast(info[0]);
2298 Local<Context> context = isolate->GetCurrentContext();
2299 auto enabled_features = WasmEnabledFeatures::FromIsolate(i_isolate);
2300
2301 // Load the 'parameters' property of the function type.
2302 Local<String> parameters_key = v8_str(isolate, "parameters");
2303 v8::MaybeLocal<v8::Value> parameters_maybe =
2304 function_type->Get(context, parameters_key);
2305 v8::Local<v8::Value> parameters_value;
2306 if (!parameters_maybe.ToLocal(&parameters_value) ||
2307 !parameters_value->IsObject()) {
2308 thrower.TypeError("Argument 0 must be a function type with 'parameters'");
2309 return;
2310 }
2311 Local<Object> parameters = parameters_value.As<Object>();
2312 uint32_t parameters_len = GetIterableLength(i_isolate, context, parameters);
2313 if (parameters_len == i::kMaxUInt32) {
2314 thrower.TypeError("Argument 0 contains parameters without 'length'");
2315 return;
2316 }
2317 if (parameters_len > i::wasm::kV8MaxWasmFunctionParams) {
2318 thrower.TypeError("Argument 0 contains too many parameters");
2319 return;
2320 }
2321
2322 // Load the 'results' property of the function type.
2323 v8::Local<v8::Value> results_value;
2324 if (!function_type->Get(context, v8_str(isolate, "results"))
2325 .ToLocal(&results_value)) {
2326 return js_api_scope.AssertException();
2327 }
2328 if (!results_value->IsObject()) {
2329 thrower.TypeError("Argument 0 must be a function type with 'results'");
2330 return;
2331 }
2332 Local<Object> results = results_value.As<Object>();
2333 uint32_t results_len = GetIterableLength(i_isolate, context, results);
2334 if (results_len == i::kMaxUInt32) {
2335 thrower.TypeError("Argument 0 contains results without 'length'");
2336 return;
2337 }
2338 if (results_len > i::wasm::kV8MaxWasmFunctionReturns) {
2339 thrower.TypeError("Argument 0 contains too many results");
2340 return;
2341 }
2342
2343 // Decode the function type and construct a signature.
2344 i::Zone zone(i_isolate->allocator(), ZONE_NAME);
2345 i::wasm::FunctionSig::Builder builder(&zone, results_len, parameters_len);
2346 for (uint32_t i = 0; i < parameters_len; ++i) {
2347 MaybeLocal<Value> maybe = parameters->Get(context, i);
2348 std::optional<i::wasm::ValueType> maybe_type =
2349 GetValueType(isolate, maybe, context, enabled_features);
2350 if (!maybe_type) return;
2351 i::wasm::ValueType type = *maybe_type;
2352 if (type == i::wasm::kWasmVoid) {
2353 thrower.TypeError(
2354 "Argument 0 parameter type at index #%u must be a value type", i);
2355 return;
2356 }
2357 builder.AddParam(type);
2358 }
2359 for (uint32_t i = 0; i < results_len; ++i) {
2360 MaybeLocal<Value> maybe = results->Get(context, i);
2361 std::optional<i::wasm::ValueType> maybe_type =
2362 GetValueType(isolate, maybe, context, enabled_features);
2363 if (!maybe_type) return js_api_scope.AssertException();
2364 i::wasm::ValueType type = *maybe_type;
2365 if (type == i::wasm::kWasmVoid) {
2366 thrower.TypeError(
2367 "Argument 0 result type at index #%u must be a value type", i);
2368 return;
2369 }
2370 builder.AddReturn(type);
2371 }
2372
2373 if (!info[1]->IsObject()) {
2374 thrower.TypeError("Argument 1 must be a function");
2375 return;
2376 }
2377 const i::wasm::FunctionSig* sig = builder.Get();
2378 i::wasm::Suspend suspend = i::wasm::kNoSuspend;
2379
2381 Utils::OpenDirectHandle(*info[1].As<Object>());
2382 if (i::IsWasmSuspendingObject(*callable)) {
2383 suspend = i::wasm::kSuspend;
2384 callable = direct_handle(
2385 i::Cast<i::WasmSuspendingObject>(*callable)->callable(), i_isolate);
2386 DCHECK(i::IsCallable(*callable));
2387 } else if (!i::IsCallable(*callable)) {
2388 thrower.TypeError("Argument 1 must be a function");
2389 return;
2390 }
2391
2393 i::WasmJSFunction::New(i_isolate, sig, callable, suspend);
2394 info.GetReturnValue().Set(Utils::ToLocal(result));
2395}
2396
2397// WebAssembly.promising(Function) -> Function
2398void WebAssemblyPromising(const v8::FunctionCallbackInfo<v8::Value>& info) {
2399 WasmJSApiScope js_api_scope{info, "WebAssembly.promising()"};
2400 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2402
2403 if (!info[0]->IsFunction()) {
2404 thrower.TypeError("Argument 0 must be a function");
2405 return;
2406 }
2408 Utils::OpenDirectHandle(*info[0].As<Function>());
2409
2410 if (!i::WasmExportedFunction::IsWasmExportedFunction(*callable)) {
2411 thrower.TypeError("Argument 0 must be a WebAssembly exported function");
2412 return;
2413 }
2414 auto wasm_exported_function = i::Cast<i::WasmExportedFunction>(*callable);
2416 wasm_exported_function->shared()->wasm_exported_function_data(),
2417 i_isolate);
2418 if (data->instance_data()->module_object()->is_asm_js()) {
2419 thrower.TypeError("Argument 0 must be a WebAssembly exported function");
2420 return;
2421 }
2423 NewPromisingWasmExportedFunction(i_isolate, data, thrower);
2424 info.GetReturnValue().Set(Utils::ToLocal(i::Cast<i::JSObject>(result)));
2425}
2426
2427// WebAssembly.Suspending(Function) -> Suspending
2428void WebAssemblySuspendingImpl(
2430 WasmJSApiScope js_api_scope{info, "WebAssembly.Suspending()"};
2431 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2433
2434 if (!info.IsConstructCall()) {
2435 thrower.TypeError("WebAssembly.Suspending must be invoked with 'new'");
2436 return;
2437 }
2438 if (!info[0]->IsFunction()) {
2439 thrower.TypeError("Argument 0 must be a function");
2440 return;
2441 }
2442
2444 Utils::OpenDirectHandle(*info[0].As<Function>());
2445
2446 if (i::WasmExportedFunction::IsWasmExportedFunction(*callable) ||
2447 i::WasmJSFunction::IsWasmJSFunction(*callable)) {
2448 thrower.TypeError("Argument 0 must not be a WebAssembly function");
2449 return;
2450 }
2451
2453 i::WasmSuspendingObject::New(i_isolate, callable);
2454 info.GetReturnValue().Set(Utils::ToLocal(i::Cast<i::JSObject>(result)));
2455}
2456
2457// WebAssembly.Function.prototype.type() -> FunctionType
2458void WebAssemblyFunctionType(const v8::FunctionCallbackInfo<v8::Value>& info) {
2459 WasmJSApiScope js_api_scope{info, "WebAssembly.Function.type()"};
2460 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2461
2463
2465 if (i::WasmExportedFunction::IsWasmExportedFunction(*fun)) {
2466 auto wasm_exported_function = i::Cast<i::WasmExportedFunction>(fun);
2468 wasm_exported_function->shared()->wasm_exported_function_data();
2469 // Note: while {zone} is only referenced directly in the if-block below,
2470 // its lifetime must exceed that of {sig}.
2471 // TODO(42210967): Creating a Zone just to create a modified copy of a
2472 // single signature is rather expensive. It would be good to find a more
2473 // efficient approach, if this function is ever considered performance
2474 // relevant.
2475 i::Zone zone(i_isolate->allocator(), ZONE_NAME);
2476 const i::wasm::FunctionSig* sig =
2477 data->instance_data()->module()->functions[data->function_index()].sig;
2478 i::wasm::Promise promise_flags =
2479 i::WasmFunctionData::PromiseField::decode(data->js_promise_flags());
2480 if (promise_flags == i::wasm::kPromise) {
2481 // The wrapper function returns a promise as an externref instead of the
2482 // original return type.
2483 size_t param_count = sig->parameter_count();
2484 i::wasm::FunctionSig::Builder builder(&zone, 1, param_count);
2485 for (size_t i = 0; i < param_count; ++i) {
2486 builder.AddParam(sig->GetParam(i));
2487 }
2488 builder.AddReturn(i::wasm::kWasmExternRef);
2489 sig = builder.Get();
2490 }
2491 type = i::wasm::GetTypeForFunction(i_isolate, sig);
2492 } else if (i::WasmJSFunction::IsWasmJSFunction(*fun)) {
2493 const i::wasm::CanonicalSig* sig = i::Cast<i::WasmJSFunction>(fun)
2494 ->shared()
2495 ->wasm_js_function_data()
2496 ->GetSignature();
2497 // As long as WasmJSFunctions cannot use indexed types, their canonical
2498 // signatures are bit-compatible with module-specific signatures.
2499#if DEBUG
2500 for (i::wasm::CanonicalValueType t : sig->all()) {
2501 DCHECK(!t.has_index());
2502 }
2503#endif
2504 static_assert(sizeof(i::wasm::ValueType) ==
2505 sizeof(i::wasm::CanonicalValueType));
2506 type = i::wasm::GetTypeForFunction(
2507 i_isolate, reinterpret_cast<const i::wasm::FunctionSig*>(sig));
2508 } else {
2509 thrower.TypeError("Receiver must be a WebAssembly.Function");
2510 return;
2511 }
2512
2513 info.GetReturnValue().Set(Utils::ToLocal(type));
2514}
2515
2516constexpr const char* kName_WasmGlobalObject = "WebAssembly.Global";
2517constexpr const char* kName_WasmMemoryObject = "WebAssembly.Memory";
2518constexpr const char* kName_WasmMemoryMapDescriptor =
2519 "WebAssembly.MemoryMapDescriptor";
2520constexpr const char* kName_WasmInstanceObject = "WebAssembly.Instance";
2521constexpr const char* kName_WasmTableObject = "WebAssembly.Table";
2522constexpr const char* kName_WasmTagObject = "WebAssembly.Tag";
2523constexpr const char* kName_WasmExceptionPackage = "WebAssembly.Exception";
2524
2525#define EXTRACT_THIS(var, WasmType) \
2526 i::DirectHandle<i::WasmType> var; \
2527 { \
2528 i::DirectHandle<i::Object> this_arg = \
2529 Utils::OpenDirectHandle(*info.This()); \
2530 if (!Is##WasmType(*this_arg)) { \
2531 thrower.TypeError("Receiver is not a %s", kName_##WasmType); \
2532 return; \
2533 } \
2534 var = i::Cast<i::WasmType>(this_arg); \
2535 }
2536
2537void WebAssemblyInstanceGetExportsImpl(
2539 WasmJSApiScope js_api_scope{info, "WebAssembly.Instance.exports()"};
2540 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2541 EXTRACT_THIS(receiver, WasmInstanceObject);
2542 i::DirectHandle<i::JSObject> exports_object(receiver->exports_object(),
2543 i_isolate);
2544
2545 info.GetReturnValue().Set(Utils::ToLocal(exports_object));
2546}
2547
2548void WebAssemblyTableGetLengthImpl(
2550 WasmJSApiScope js_api_scope{info, "WebAssembly.Table.length()"};
2551 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2552 EXTRACT_THIS(receiver, WasmTableObject);
2553
2554 int length = receiver->current_length();
2555 DCHECK_LE(0, length);
2556 info.GetReturnValue().Set(
2557 AddressValueFromUnsigned(isolate, receiver->address_type(), length));
2558}
2559
2560// WebAssembly.Table.grow(num, init_value = null) -> num
2561void WebAssemblyTableGrowImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
2562 WasmJSApiScope js_api_scope{info, "WebAssembly.Table.grow()"};
2563 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2564 Local<Context> context = isolate->GetCurrentContext();
2565 EXTRACT_THIS(receiver, WasmTableObject);
2566
2567 std::optional<uint64_t> maybe_grow_by = AddressValueToU64(
2568 &thrower, context, info[0], "Argument 0", receiver->address_type());
2569 if (!maybe_grow_by) return js_api_scope.AssertException();
2570 uint64_t grow_by = *maybe_grow_by;
2571
2572 i::DirectHandle<i::Object> init_value;
2573
2574 if (info.Length() >= 2) {
2575 init_value = Utils::OpenDirectHandle(*info[1]);
2576 const char* error_message;
2577 if (!i::WasmTableObject::JSToWasmElement(i_isolate, receiver, init_value,
2578 &error_message)
2579 .ToHandle(&init_value)) {
2580 thrower.TypeError("Argument 1 is invalid: %s", error_message);
2581 return;
2582 }
2583 } else if (receiver->unsafe_type().is_non_nullable()) {
2584 thrower.TypeError(
2585 "Argument 1 must be specified for non-nullable element type");
2586 return;
2587 } else {
2588 init_value = DefaultReferenceValue(i_isolate, receiver->unsafe_type());
2589 }
2590
2591 static_assert(i::wasm::kV8MaxWasmTableSize <= i::kMaxUInt32);
2592 int old_size = grow_by > i::wasm::max_table_size()
2593 ? -1
2594 : i::WasmTableObject::Grow(i_isolate, receiver,
2595 static_cast<uint32_t>(grow_by),
2596 init_value);
2597 if (old_size < 0) {
2598 thrower.RangeError("failed to grow table by %" PRIu64, grow_by);
2599 return;
2600 }
2601 info.GetReturnValue().Set(
2602 AddressValueFromUnsigned(isolate, receiver->address_type(), old_size));
2603}
2604
2605namespace {
2606V8_WARN_UNUSED_RESULT bool WasmObjectToJSReturnValue(
2608 i::wasm::ValueType type, i::Isolate* isolate, ErrorThrower* thrower) {
2609 switch (type.heap_type().representation()) {
2611 thrower->TypeError("%s", "stringview_wtf8 has no JS representation");
2612 return false;
2614 thrower->TypeError("%s", "stringview_wtf16 has no JS representation");
2615 return false;
2617 thrower->TypeError("%s", "stringview_iter has no JS representation");
2618 return false;
2623 thrower->TypeError("invalid type %s", type.name().c_str());
2624 return false;
2625 default:
2626 return_value.Set(Utils::ToLocal(i::wasm::WasmToJSObject(isolate, value)));
2627 return true;
2628 }
2629}
2630} // namespace
2631
2632// WebAssembly.Table.get(num) -> any
2633void WebAssemblyTableGetImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
2634 WasmJSApiScope js_api_scope{info, "WebAssembly.Table.get()"};
2635 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2636 Local<Context> context = isolate->GetCurrentContext();
2637 EXTRACT_THIS(receiver, WasmTableObject);
2638
2639 std::optional<uint64_t> maybe_address = AddressValueToU64(
2640 &thrower, context, info[0], "Argument 0", receiver->address_type());
2641 if (!maybe_address) return;
2642 uint64_t address = *maybe_address;
2643
2644 if (address > i::kMaxUInt32 ||
2645 !receiver->is_in_bounds(static_cast<uint32_t>(address))) {
2646 thrower.RangeError("invalid address %" PRIu64 " in %s table of size %d",
2647 address, receiver->unsafe_type().name().c_str(),
2648 receiver->current_length());
2649 return;
2650 }
2651
2652 i::DirectHandle<i::Object> result = i::WasmTableObject::Get(
2653 i_isolate, receiver, static_cast<uint32_t>(address));
2654
2655 v8::ReturnValue<v8::Value> return_value = info.GetReturnValue();
2656 if (!WasmObjectToJSReturnValue(return_value, result, receiver->unsafe_type(),
2657 i_isolate, &thrower)) {
2658 return js_api_scope.AssertException();
2659 }
2660}
2661
2662// WebAssembly.Table.set(num, any)
2663void WebAssemblyTableSetImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
2664 WasmJSApiScope js_api_scope{info, "WebAssembly.Table.set()"};
2665 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2666 Local<Context> context = isolate->GetCurrentContext();
2667 EXTRACT_THIS(table_object, WasmTableObject);
2668
2669 std::optional<uint64_t> maybe_address = AddressValueToU64(
2670 &thrower, context, info[0], "Argument 0", table_object->address_type());
2671 if (!maybe_address) return js_api_scope.AssertException();
2672 uint64_t address = *maybe_address;
2673
2674 if (address > i::kMaxUInt32 ||
2675 !table_object->is_in_bounds(static_cast<uint32_t>(address))) {
2676 thrower.RangeError("invalid address %" PRIu64 " in %s table of size %d",
2677 address, table_object->unsafe_type().name().c_str(),
2678 table_object->current_length());
2679 return;
2680 }
2681
2683 if (info.Length() >= 2) {
2684 element = Utils::OpenDirectHandle(*info[1]);
2685 const char* error_message;
2686 if (!i::WasmTableObject::JSToWasmElement(i_isolate, table_object, element,
2687 &error_message)
2688 .ToHandle(&element)) {
2689 thrower.TypeError("Argument 1 is invalid for table: %s", error_message);
2690 return;
2691 }
2692 } else if (table_object->unsafe_type().is_defaultable()) {
2693 element = DefaultReferenceValue(i_isolate, table_object->unsafe_type());
2694 } else {
2695 thrower.TypeError("Table of non-defaultable type %s needs explicit element",
2696 table_object->unsafe_type().name().c_str());
2697 return;
2698 }
2699
2700 i::WasmTableObject::Set(i_isolate, table_object,
2701 static_cast<uint32_t>(address), element);
2702}
2703
2704// WebAssembly.Table.type() -> TableType
2705void WebAssemblyTableType(const v8::FunctionCallbackInfo<v8::Value>& info) {
2706 WasmJSApiScope js_api_scope{info, "WebAssembly.Table.type()"};
2707 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2708 EXTRACT_THIS(table, WasmTableObject);
2709 std::optional<uint64_t> max_size = table->maximum_length_u64();
2710 auto type = i::wasm::GetTypeForTable(i_isolate, table->unsafe_type(),
2711 table->current_length(), max_size,
2712 table->address_type());
2713 info.GetReturnValue().Set(Utils::ToLocal(type));
2714}
2715
2716// WebAssembly.MemoryMapDescriptor.map()
2717void WebAssemblyMemoryMapDescriptorMapImpl(
2719 CHECK(i::v8_flags.experimental_wasm_memory_control);
2720 WasmJSApiScope js_api_scope{info, "WebAssembly.MemoryMapDescriptor.map()"};
2721 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2722 EXTRACT_THIS(receiver, WasmMemoryMapDescriptor);
2723
2725 {
2726 i::DirectHandle<i::Object> memory_param = Utils::OpenDirectHandle(*info[0]);
2727 if (!i::IsWasmMemoryObject(*memory_param)) {
2728 thrower.TypeError("Parameter is not a WebAssembly.Memory");
2729 return js_api_scope.AssertException();
2730 }
2731 memory = i::Cast<i::WasmMemoryObject>(memory_param);
2732 }
2733
2734 Local<Context> context = isolate->GetCurrentContext();
2735 std::optional<uint32_t> offset =
2736 EnforceUint32("Argument 1", info[1], context, &thrower);
2737 if (!offset.has_value()) {
2738 return js_api_scope.AssertException();
2739 }
2740 size_t mapped_size = receiver->MapDescriptor(memory, offset.value());
2741 if (!mapped_size) {
2742 thrower.RuntimeError(
2743 "Failed to map the MemoryMapDescriptor to WebAssembly memory.");
2744 return js_api_scope.AssertException();
2745 }
2746 receiver->set_memory(MakeWeak(*memory));
2747 receiver->set_offset(offset.value());
2748 receiver->set_size(static_cast<uint32_t>(mapped_size));
2749 info.GetReturnValue().Set(static_cast<int64_t>(mapped_size));
2750}
2751
2752// WebAssembly.MemoryMapDescriptor.unmap()
2753void WebAssemblyMemoryMapDescriptorUnmapImpl(
2755 CHECK(i::v8_flags.experimental_wasm_memory_control);
2756 WasmJSApiScope js_api_scope{info, "WebAssembly.MemoryMapDescriptor.unmap()"};
2757 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2758 EXTRACT_THIS(receiver, WasmMemoryMapDescriptor);
2759
2760 if (!receiver->UnmapDescriptor()) {
2761 thrower.RangeError("Failed to unmap the MemoryMapDescriptor.");
2762 return;
2763 }
2764}
2765
2766// WebAssembly.Memory.grow(num) -> num
2767void WebAssemblyMemoryGrowImpl(
2769 WasmJSApiScope js_api_scope{info, "WebAssembly.Memory.grow()"};
2770 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2771 Local<Context> context = isolate->GetCurrentContext();
2772 EXTRACT_THIS(receiver, WasmMemoryObject);
2773
2774 std::optional<uint64_t> maybe_delta_pages = AddressValueToU64(
2775 &thrower, context, info[0], "Argument 0", receiver->address_type());
2776 if (!maybe_delta_pages) return js_api_scope.AssertException();
2777 uint64_t delta_pages = *maybe_delta_pages;
2778
2779 i::DirectHandle<i::JSArrayBuffer> old_buffer(receiver->array_buffer(),
2780 i_isolate);
2781
2782 uint64_t old_pages = old_buffer->GetByteLength() / i::wasm::kWasmPageSize;
2783 uint64_t max_pages = receiver->maximum_pages();
2784
2785 if (delta_pages > max_pages - old_pages) {
2786 thrower.RangeError("Maximum memory size exceeded");
2787 return;
2788 }
2789
2790 static_assert(i::wasm::kV8MaxWasmMemory64Pages <= i::kMaxUInt32);
2791 int32_t ret = i::WasmMemoryObject::Grow(i_isolate, receiver,
2792 static_cast<uint32_t>(delta_pages));
2793 if (ret == -1) {
2794 thrower.RangeError("Unable to grow instance memory");
2795 return;
2796 }
2797 info.GetReturnValue().Set(
2798 AddressValueFromUnsigned(isolate, receiver->address_type(), ret));
2799}
2800
2801// WebAssembly.Memory.buffer -> ArrayBuffer
2802void WebAssemblyMemoryGetBufferImpl(
2804 WasmJSApiScope js_api_scope{info, "WebAssembly.Memory.buffer"};
2805 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2806 EXTRACT_THIS(receiver, WasmMemoryObject);
2807
2808 i::DirectHandle<i::Object> buffer_obj(receiver->array_buffer(), i_isolate);
2809 DCHECK(IsJSArrayBuffer(*buffer_obj));
2811 i::Cast<i::JSArrayBuffer>(*buffer_obj), i_isolate);
2812 if (buffer->is_shared()) {
2813 // TODO(gdeepti): More needed here for when cached buffer, and current
2814 // buffer are out of sync, handle that here when bounds checks, and Grow
2815 // are handled correctly.
2816 Maybe<bool> result =
2817 buffer->SetIntegrityLevel(i_isolate, buffer, i::FROZEN, i::kDontThrow);
2818 if (!result.FromJust()) {
2819 thrower.TypeError(
2820 "Status of setting SetIntegrityLevel of buffer is false.");
2821 return;
2822 }
2823 }
2824 info.GetReturnValue().Set(Utils::ToLocal(buffer));
2825}
2826
2827// WebAssembly.Memory.toFixedLengthBuffer() -> ArrayBuffer
2828void WebAssemblyMemoryToFixedLengthBufferImpl(
2830 WasmJSApiScope js_api_scope{info, "WebAssembly.Memory.toFixedLengthBuffer()"};
2831 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2832 EXTRACT_THIS(receiver, WasmMemoryObject);
2833
2834 i::DirectHandle<i::Object> buffer_obj(receiver->array_buffer(), i_isolate);
2835 DCHECK(IsJSArrayBuffer(*buffer_obj));
2837 i::Cast<i::JSArrayBuffer>(*buffer_obj), i_isolate);
2838 if (buffer->is_resizable_by_js()) {
2839 buffer = i::WasmMemoryObject::ToFixedLengthBuffer(i_isolate, receiver);
2840 }
2841 if (buffer->is_shared()) {
2842 Maybe<bool> result =
2843 buffer->SetIntegrityLevel(i_isolate, buffer, i::FROZEN, i::kDontThrow);
2844 if (!result.FromJust()) {
2845 thrower.TypeError(
2846 "Status of setting SetIntegrityLevel of buffer is false.");
2847 return;
2848 }
2849 }
2850 v8::ReturnValue<v8::Value> return_value = info.GetReturnValue();
2851 return_value.Set(Utils::ToLocal(buffer));
2852}
2853
2854// WebAssembly.Memory.toResizableBuffer() -> ArrayBuffer
2855void WebAssemblyMemoryToResizableBufferImpl(
2857 WasmJSApiScope js_api_scope{info, "WebAssembly.Memory.toResizableBuffer()"};
2858 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2859 EXTRACT_THIS(receiver, WasmMemoryObject);
2860
2861 i::DirectHandle<i::Object> buffer_obj(receiver->array_buffer(), i_isolate);
2862 DCHECK(IsJSArrayBuffer(*buffer_obj));
2864 i::Cast<i::JSArrayBuffer>(*buffer_obj), i_isolate);
2865 if (!buffer->is_resizable_by_js()) {
2866 if (!receiver->has_maximum_pages()) {
2867 thrower.TypeError("Memory must have a maximum");
2868 return;
2869 }
2870 buffer = i::WasmMemoryObject::ToResizableBuffer(i_isolate, receiver);
2871 }
2872 if (buffer->is_shared()) {
2873 Maybe<bool> result =
2874 buffer->SetIntegrityLevel(i_isolate, buffer, i::FROZEN, i::kDontThrow);
2875 if (!result.FromJust()) {
2876 thrower.TypeError(
2877 "Status of setting SetIntegrityLevel of buffer is false.");
2878 return;
2879 }
2880 }
2881 v8::ReturnValue<v8::Value> return_value = info.GetReturnValue();
2882 return_value.Set(Utils::ToLocal(buffer));
2883}
2884
2885// WebAssembly.Memory.type() -> MemoryType
2886void WebAssemblyMemoryType(const v8::FunctionCallbackInfo<v8::Value>& info) {
2887 WasmJSApiScope js_api_scope{info, "WebAssembly.Memory.type()"};
2888 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2889 EXTRACT_THIS(memory, WasmMemoryObject);
2890
2891 i::DirectHandle<i::JSArrayBuffer> buffer(memory->array_buffer(), i_isolate);
2892 size_t curr_size = buffer->GetByteLength() / i::wasm::kWasmPageSize;
2893 DCHECK_LE(curr_size, std::numeric_limits<uint32_t>::max());
2894 uint32_t min_size = static_cast<uint32_t>(curr_size);
2895 std::optional<uint32_t> max_size;
2896 if (memory->has_maximum_pages()) {
2897 uint64_t max_size64 = memory->maximum_pages();
2898 DCHECK_LE(max_size64, std::numeric_limits<uint32_t>::max());
2899 max_size.emplace(static_cast<uint32_t>(max_size64));
2900 }
2901 bool shared = buffer->is_shared();
2902 auto type = i::wasm::GetTypeForMemory(i_isolate, min_size, max_size, shared,
2903 memory->address_type());
2904 info.GetReturnValue().Set(Utils::ToLocal(type));
2905}
2906
2907// WebAssembly.Tag.type() -> FunctionType
2908void WebAssemblyTagType(const v8::FunctionCallbackInfo<v8::Value>& info) {
2909 WasmJSApiScope js_api_scope{info, "WebAssembly.Tag.type()"};
2910 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2911 EXTRACT_THIS(tag, WasmTagObject);
2912
2913 int n = tag->serialized_signature()->length();
2914 std::vector<i::wasm::ValueType> data(n);
2915 if (n > 0) {
2916 tag->serialized_signature()->copy_out(0, data.data(), n);
2917 }
2918 const i::wasm::FunctionSig sig{0, data.size(), data.data()};
2919 constexpr bool kForException = true;
2920 auto type = i::wasm::GetTypeForFunction(i_isolate, &sig, kForException);
2921 info.GetReturnValue().Set(Utils::ToLocal(type));
2922}
2923
2924void WebAssemblyExceptionGetArgImpl(
2926 WasmJSApiScope js_api_scope{info, "WebAssembly.Exception.getArg()"};
2927 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
2928 EXTRACT_THIS(exception, WasmExceptionPackage);
2929
2931 if (!GetFirstArgumentAsTag(info, &thrower).ToHandle(&tag_object)) {
2932 return js_api_scope.AssertException();
2933 }
2934 Local<Context> context = isolate->GetCurrentContext();
2935 std::optional<uint32_t> maybe_index =
2936 EnforceUint32("Index", info[1], context, &thrower);
2937 if (!maybe_index) return js_api_scope.AssertException();
2938 uint32_t index = *maybe_index;
2939 auto maybe_values =
2940 i::WasmExceptionPackage::GetExceptionValues(i_isolate, exception);
2941
2942 auto this_tag =
2943 i::WasmExceptionPackage::GetExceptionTag(i_isolate, exception);
2944 DCHECK(IsWasmExceptionTag(*this_tag));
2945 if (tag_object->tag() != *this_tag) {
2946 thrower.TypeError("First argument does not match the exception tag");
2947 return;
2948 }
2949
2950 DCHECK(!IsUndefined(*maybe_values));
2951 auto values = i::Cast<i::FixedArray>(maybe_values);
2952 auto signature = tag_object->serialized_signature();
2953 if (index >= static_cast<uint32_t>(signature->length())) {
2954 thrower.RangeError("Index out of range");
2955 return;
2956 }
2957 // First, find the index in the values array.
2958 uint32_t decode_index = 0;
2959 // Since the bounds check above passed, the cast to int is safe.
2960 for (int i = 0; i < static_cast<int>(index); ++i) {
2961 switch (signature->get(i).kind()) {
2962 case i::wasm::kI32:
2963 case i::wasm::kF32:
2964 decode_index += 2;
2965 break;
2966 case i::wasm::kI64:
2967 case i::wasm::kF64:
2968 decode_index += 4;
2969 break;
2970 case i::wasm::kRef:
2971 case i::wasm::kRefNull:
2972 decode_index++;
2973 break;
2974 case i::wasm::kS128:
2975 decode_index += 8;
2976 break;
2977 case i::wasm::kI8:
2978 case i::wasm::kI16:
2979 case i::wasm::kF16:
2980 case i::wasm::kVoid:
2981 case i::wasm::kTop:
2982 case i::wasm::kBottom:
2983 UNREACHABLE();
2984 }
2985 }
2986 // Decode the value at {decode_index}.
2987 Local<Value> result;
2988 switch (signature->get(index).kind()) {
2989 case i::wasm::kI32: {
2990 uint32_t u32_bits = 0;
2991 i::DecodeI32ExceptionValue(values, &decode_index, &u32_bits);
2992 int32_t i32 = static_cast<int32_t>(u32_bits);
2993 result = v8::Integer::New(isolate, i32);
2994 break;
2995 }
2996 case i::wasm::kI64: {
2997 uint64_t u64_bits = 0;
2998 i::DecodeI64ExceptionValue(values, &decode_index, &u64_bits);
2999 int64_t i64 = static_cast<int64_t>(u64_bits);
3000 result = v8::BigInt::New(isolate, i64);
3001 break;
3002 }
3003 case i::wasm::kF32: {
3004 uint32_t f32_bits = 0;
3005 DecodeI32ExceptionValue(values, &decode_index, &f32_bits);
3006 float f32 = base::bit_cast<float>(f32_bits);
3007 result = v8::Number::New(isolate, f32);
3008 break;
3009 }
3010 case i::wasm::kF64: {
3011 uint64_t f64_bits = 0;
3012 DecodeI64ExceptionValue(values, &decode_index, &f64_bits);
3013 double f64 = base::bit_cast<double>(f64_bits);
3014 result = v8::Number::New(isolate, f64);
3015 break;
3016 }
3017 case i::wasm::kRef:
3018 case i::wasm::kRefNull: {
3019 i::DirectHandle<i::Object> obj(values->get(decode_index), i_isolate);
3020 ReturnValue<Value> return_value = info.GetReturnValue();
3021 if (!WasmObjectToJSReturnValue(return_value, obj, signature->get(index),
3022 i_isolate, &thrower)) {
3023 return js_api_scope.AssertException();
3024 }
3025 return;
3026 }
3027 case i::wasm::kS128:
3028 thrower.TypeError("Invalid type v128");
3029 return;
3030 case i::wasm::kI8:
3031 case i::wasm::kI16:
3032 case i::wasm::kF16:
3033 case i::wasm::kVoid:
3034 case i::wasm::kTop:
3035 case i::wasm::kBottom:
3036 UNREACHABLE();
3037 }
3038 info.GetReturnValue().Set(result);
3039}
3040
3041void WebAssemblyExceptionIsImpl(
3043 WasmJSApiScope js_api_scope{info, "WebAssembly.Exception.is()"};
3044 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
3045 EXTRACT_THIS(exception, WasmExceptionPackage);
3046
3047 auto tag = i::WasmExceptionPackage::GetExceptionTag(i_isolate, exception);
3048 DCHECK(IsWasmExceptionTag(*tag));
3049
3051 if (!GetFirstArgumentAsTag(info, &thrower).ToHandle(&tag_object)) {
3052 return js_api_scope.AssertException();
3053 }
3054 info.GetReturnValue().Set(tag_object->tag() == *tag);
3055}
3056
3057void WebAssemblyGlobalGetValueCommon(WasmJSApiScope& js_api_scope) {
3058 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
3059 auto& info = js_api_scope.callback_info(); // Needed by EXTRACT_THIS.
3060 EXTRACT_THIS(receiver, WasmGlobalObject);
3061
3062 v8::ReturnValue<v8::Value> return_value = info.GetReturnValue();
3063
3064 switch (receiver->type().kind()) {
3065 case i::wasm::kI32:
3066 return_value.Set(receiver->GetI32());
3067 break;
3068 case i::wasm::kI64: {
3069 Local<BigInt> value = BigInt::New(isolate, receiver->GetI64());
3070 return_value.Set(value);
3071 break;
3072 }
3073 case i::wasm::kF32:
3074 return_value.Set(receiver->GetF32());
3075 break;
3076 case i::wasm::kF64:
3077 return_value.Set(receiver->GetF64());
3078 break;
3079 case i::wasm::kS128:
3080 thrower.TypeError("Can't get the value of s128 WebAssembly.Global");
3081 break;
3082 case i::wasm::kRef:
3083 case i::wasm::kRefNull:
3084 if (!WasmObjectToJSReturnValue(return_value, receiver->GetRef(),
3085 receiver->type(), i_isolate, &thrower)) {
3086 return js_api_scope.AssertException();
3087 }
3088 break;
3089 case i::wasm::kI8:
3090 case i::wasm::kI16:
3091 case i::wasm::kF16:
3092 case i::wasm::kTop:
3093 case i::wasm::kBottom:
3094 case i::wasm::kVoid:
3095 UNREACHABLE();
3096 }
3097}
3098
3099// WebAssembly.Global.valueOf() -> num
3100void WebAssemblyGlobalValueOfImpl(
3102 WasmJSApiScope js_api_scope{info, "WebAssembly.Global.valueOf()"};
3103 return WebAssemblyGlobalGetValueCommon(js_api_scope);
3104}
3105
3106// get WebAssembly.Global.value -> num
3107void WebAssemblyGlobalGetValueImpl(
3109 WasmJSApiScope js_api_scope{info, "get WebAssembly.Global.value)"};
3110 return WebAssemblyGlobalGetValueCommon(js_api_scope);
3111}
3112
3113// set WebAssembly.Global.value(num)
3114void WebAssemblyGlobalSetValueImpl(
3116 WasmJSApiScope js_api_scope{info, "set WebAssembly.Global.value)"};
3117 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
3118 EXTRACT_THIS(receiver, WasmGlobalObject);
3119
3120 if (!receiver->is_mutable()) {
3121 thrower.TypeError("Can't set the value of an immutable global.");
3122 return;
3123 }
3124 if (info.Length() == 0) {
3125 thrower.TypeError("Argument 0 is required");
3126 return;
3127 }
3128
3129 Local<Context> context = isolate->GetCurrentContext();
3130 switch (receiver->type().kind()) {
3131 case i::wasm::kI32: {
3132 int32_t i32_value = 0;
3133 if (!info[0]->Int32Value(context).To(&i32_value)) {
3134 return js_api_scope.AssertException();
3135 }
3136 receiver->SetI32(i32_value);
3137 break;
3138 }
3139 case i::wasm::kI64: {
3140 v8::Local<v8::BigInt> bigint_value;
3141 if (!info[0]->ToBigInt(context).ToLocal(&bigint_value)) {
3142 return js_api_scope.AssertException();
3143 }
3144 receiver->SetI64(bigint_value->Int64Value());
3145 break;
3146 }
3147 case i::wasm::kF32: {
3148 double f64_value = 0;
3149 if (!info[0]->NumberValue(context).To(&f64_value)) {
3150 return js_api_scope.AssertException();
3151 }
3152 receiver->SetF32(i::DoubleToFloat32(f64_value));
3153 break;
3154 }
3155 case i::wasm::kF64: {
3156 double f64_value = 0;
3157 if (!info[0]->NumberValue(context).To(&f64_value)) {
3158 return js_api_scope.AssertException();
3159 }
3160 receiver->SetF64(f64_value);
3161 break;
3162 }
3163 case i::wasm::kS128:
3164 thrower.TypeError("Can't set the value of s128 WebAssembly.Global");
3165 break;
3166 case i::wasm::kRef:
3167 case i::wasm::kRefNull: {
3168 const i::wasm::WasmModule* module =
3169 receiver->has_trusted_data()
3170 ? receiver->trusted_data(i_isolate)->module()
3171 : nullptr;
3173 const char* error_message;
3174 if (!i::wasm::JSToWasmObject(i_isolate, module, value, receiver->type(),
3175 &error_message)
3176 .ToHandle(&value)) {
3177 thrower.TypeError("%s", error_message);
3178 return;
3179 }
3180 receiver->SetRef(value);
3181 return;
3182 }
3183 case i::wasm::kI8:
3184 case i::wasm::kI16:
3185 case i::wasm::kF16:
3186 case i::wasm::kTop:
3187 case i::wasm::kBottom:
3188 case i::wasm::kVoid:
3189 UNREACHABLE();
3190 }
3191}
3192
3193// WebAssembly.Global.type() -> GlobalType
3194void WebAssemblyGlobalType(const v8::FunctionCallbackInfo<v8::Value>& info) {
3195 WasmJSApiScope js_api_scope{info, "WebAssembly.Global.type())"};
3196 auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower();
3197 EXTRACT_THIS(global, WasmGlobalObject);
3198
3199 auto type = i::wasm::GetTypeForGlobal(i_isolate, global->is_mutable(),
3200 global->type());
3201 info.GetReturnValue().Set(Utils::ToLocal(type));
3202}
3203
3204} // namespace
3205
3206namespace internal {
3207namespace wasm {
3208
3209// Define the callbacks in v8::internal::wasm namespace. The implementation is
3210// in v8::internal directly.
3211#define DEF_WASM_JS_EXTERNAL_REFERENCE(Name) \
3212 void Name(const v8::FunctionCallbackInfo<v8::Value>& info) { \
3213 Name##Impl(info); \
3214 }
3216#undef DEF_WASM_JS_EXTERNAL_REFERENCE
3217
3218} // namespace wasm
3219} // namespace internal
3220
3221// TODO(titzer): we use the API to create the function template because the
3222// internal guts are too ugly to replicate here.
3224 i::Isolate* i_isolate, FunctionCallback func, bool has_prototype,
3226 Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
3227 ConstructorBehavior behavior =
3230 isolate, func, {}, {}, 0, behavior, side_effect_type);
3231 if (has_prototype) templ->ReadOnlyPrototype();
3232 return v8::Utils::OpenDirectHandle(*templ);
3233}
3234
3236 i::Isolate* i_isolate) {
3237 Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
3239 return v8::Utils::OpenDirectHandle(*templ);
3240}
3241
3242namespace internal {
3243namespace {
3244
3245DirectHandle<JSFunction> CreateFunc(
3246 Isolate* isolate, DirectHandle<String> name, FunctionCallback func,
3247 bool has_prototype,
3248 SideEffectType side_effect_type = SideEffectType::kHasSideEffect,
3249 DirectHandle<FunctionTemplateInfo> parent = {}) {
3250 DirectHandle<FunctionTemplateInfo> temp =
3251 NewFunctionTemplate(isolate, func, has_prototype, side_effect_type);
3252
3253 if (!parent.is_null()) {
3254 DCHECK(has_prototype);
3255 FunctionTemplateInfo::SetParentTemplate(isolate, temp, parent);
3256 }
3257
3258 DirectHandle<JSFunction> function =
3259 ApiNatives::InstantiateFunction(isolate, temp, name).ToHandleChecked();
3260 DCHECK(function->shared()->HasSharedName());
3261 return function;
3262}
3263
3264DirectHandle<JSFunction> InstallFunc(
3265 Isolate* isolate, DirectHandle<JSObject> object, DirectHandle<String> name,
3266 FunctionCallback func, int length, bool has_prototype = false,
3267 PropertyAttributes attributes = NONE,
3268 SideEffectType side_effect_type = SideEffectType::kHasSideEffect) {
3269 DirectHandle<JSFunction> function =
3270 CreateFunc(isolate, name, func, has_prototype, side_effect_type);
3271 function->shared()->set_length(length);
3272 CHECK(!JSObject::HasRealNamedProperty(isolate, object, name).FromMaybe(true));
3273 CHECK(object->map()->is_extensible());
3274 JSObject::AddProperty(isolate, object, name, function, attributes);
3275 return function;
3276}
3277
3278DirectHandle<JSFunction> InstallFunc(
3279 Isolate* isolate, DirectHandle<JSObject> object, const char* str,
3280 FunctionCallback func, int length, bool has_prototype = false,
3281 PropertyAttributes attributes = NONE,
3282 SideEffectType side_effect_type = SideEffectType::kHasSideEffect) {
3283 DirectHandle<String> name = v8_str(isolate, str);
3284 return InstallFunc(isolate, object, name, func, length, has_prototype,
3285 attributes, side_effect_type);
3286}
3287
3288DirectHandle<JSFunction> InstallConstructorFunc(Isolate* isolate,
3289 DirectHandle<JSObject> object,
3290 const char* str,
3291 FunctionCallback func) {
3292 return InstallFunc(isolate, object, str, func, 1, true, DONT_ENUM,
3293 SideEffectType::kHasNoSideEffect);
3294}
3295
3296DirectHandle<String> GetterName(Isolate* isolate, DirectHandle<String> name) {
3297 return Name::ToFunctionName(isolate, name, isolate->factory()->get_string())
3298 .ToHandleChecked();
3299}
3300
3301void InstallGetter(Isolate* isolate, DirectHandle<JSObject> object,
3302 const char* str, FunctionCallback func) {
3303 DirectHandle<String> name = v8_str(isolate, str);
3304 DirectHandle<JSFunction> function =
3305 CreateFunc(isolate, GetterName(isolate, name), func, false,
3306 SideEffectType::kHasNoSideEffect);
3307
3308 Utils::ToLocal(object)->SetAccessorProperty(Utils::ToLocal(name),
3309 Utils::ToLocal(function),
3310 Local<Function>(), v8::None);
3311}
3312
3313DirectHandle<String> SetterName(Isolate* isolate, DirectHandle<String> name) {
3314 return Name::ToFunctionName(isolate, name, isolate->factory()->set_string())
3315 .ToHandleChecked();
3316}
3317
3318void InstallGetterSetter(Isolate* isolate, DirectHandle<JSObject> object,
3319 const char* str, FunctionCallback getter,
3320 FunctionCallback setter) {
3321 DirectHandle<String> name = v8_str(isolate, str);
3322 DirectHandle<JSFunction> getter_func =
3323 CreateFunc(isolate, GetterName(isolate, name), getter, false,
3324 SideEffectType::kHasNoSideEffect);
3325 DirectHandle<JSFunction> setter_func =
3326 CreateFunc(isolate, SetterName(isolate, name), setter, false);
3327 setter_func->shared()->set_length(1);
3328
3329 Utils::ToLocal(object)->SetAccessorProperty(
3330 Utils::ToLocal(name), Utils::ToLocal(getter_func),
3331 Utils::ToLocal(setter_func), v8::None);
3332}
3333
3334// Assigns a dummy instance template to the given constructor function. Used to
3335// make sure the implicit receivers for the constructors in this file have an
3336// instance type different from the internal one, they allocate the resulting
3337// object explicitly and ignore implicit receiver.
3338void SetDummyInstanceTemplate(Isolate* isolate, DirectHandle<JSFunction> fun) {
3339 DirectHandle<ObjectTemplateInfo> instance_template =
3340 NewObjectTemplate(isolate);
3341 FunctionTemplateInfo::SetInstanceTemplate(
3342 isolate, direct_handle(fun->shared()->api_func_data(), isolate),
3343 instance_template);
3344}
3345
3346DirectHandle<JSObject> SetupConstructor(Isolate* isolate,
3347 DirectHandle<JSFunction> constructor,
3348 InstanceType instance_type,
3349 int instance_size,
3350 const char* name = nullptr,
3351 int in_object_properties = 0) {
3352 SetDummyInstanceTemplate(isolate, constructor);
3353 JSFunction::EnsureHasInitialMap(constructor);
3354 DirectHandle<JSObject> proto(
3355 Cast<JSObject>(constructor->instance_prototype()), isolate);
3356 DirectHandle<Map> map = isolate->factory()->NewContextfulMap(
3357 constructor, instance_type, instance_size, TERMINAL_FAST_ELEMENTS_KIND,
3358 in_object_properties);
3359 JSFunction::SetInitialMap(isolate, constructor, map, proto);
3360 constexpr PropertyAttributes ro_attributes =
3361 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
3362 if (name) {
3363 JSObject::AddProperty(isolate, proto,
3364 isolate->factory()->to_string_tag_symbol(),
3365 v8_str(isolate, name), ro_attributes);
3366 }
3367 return proto;
3368}
3369
3370constexpr wasm::ValueType kWasmExceptionTagParams[] = {
3371 wasm::kWasmExternRef,
3372};
3373constexpr wasm::FunctionSig kWasmExceptionTagSignature{
3374 0, arraysize(kWasmExceptionTagParams), kWasmExceptionTagParams};
3375} // namespace
3376
3377// static
3378void WasmJs::PrepareForSnapshot(Isolate* isolate) {
3379 DirectHandle<JSGlobalObject> global = isolate->global_object();
3380 DirectHandle<NativeContext> native_context(global->native_context(), isolate);
3381
3382 CHECK(IsUndefined(native_context->get(Context::WASM_WEBASSEMBLY_OBJECT_INDEX),
3383 isolate));
3384 CHECK(IsUndefined(native_context->get(Context::WASM_MODULE_CONSTRUCTOR_INDEX),
3385 isolate));
3386
3387 Factory* const f = isolate->factory();
3388 static constexpr PropertyAttributes ro_attributes =
3389 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
3390
3391 // Create the WebAssembly object.
3392 DirectHandle<JSObject> webassembly;
3393 {
3394 DirectHandle<String> WebAssembly_string = v8_str(isolate, "WebAssembly");
3395 // Not supposed to be called, hence using the kIllegal builtin as code.
3397 WebAssembly_string, Builtin::kIllegal, 0, kDontAdapt);
3398 sfi->set_language_mode(LanguageMode::kStrict);
3399
3402 JSFunction::SetPrototype(ctor, isolate->initial_object_prototype());
3403 webassembly = f->NewJSObject(ctor, AllocationType::kOld);
3404 native_context->set_wasm_webassembly_object(*webassembly);
3405
3406 JSObject::AddProperty(isolate, webassembly, f->to_string_tag_symbol(),
3407 WebAssembly_string, ro_attributes);
3408 InstallFunc(isolate, webassembly, "compile", wasm::WebAssemblyCompile, 1);
3409 InstallFunc(isolate, webassembly, "validate", wasm::WebAssemblyValidate, 1);
3410 InstallFunc(isolate, webassembly, "instantiate",
3411 wasm::WebAssemblyInstantiate, 1);
3412 }
3413
3414 // Create the Module object.
3415 InstallModule(isolate, webassembly);
3416
3417 // Create the Instance object.
3418 {
3419 DirectHandle<JSFunction> instance_constructor = InstallConstructorFunc(
3420 isolate, webassembly, "Instance", wasm::WebAssemblyInstance);
3421 DirectHandle<JSObject> instance_proto = SetupConstructor(
3422 isolate, instance_constructor, WASM_INSTANCE_OBJECT_TYPE,
3423 WasmInstanceObject::kHeaderSize, "WebAssembly.Instance");
3424 native_context->set_wasm_instance_constructor(*instance_constructor);
3425 InstallGetter(isolate, instance_proto, "exports",
3426 wasm::WebAssemblyInstanceGetExports);
3427 }
3428
3429 // Create the Table object.
3430 {
3431 DirectHandle<JSFunction> table_constructor = InstallConstructorFunc(
3432 isolate, webassembly, "Table", wasm::WebAssemblyTable);
3433 DirectHandle<JSObject> table_proto =
3434 SetupConstructor(isolate, table_constructor, WASM_TABLE_OBJECT_TYPE,
3435 WasmTableObject::kHeaderSize, "WebAssembly.Table");
3436 native_context->set_wasm_table_constructor(*table_constructor);
3437 InstallGetter(isolate, table_proto, "length",
3438 wasm::WebAssemblyTableGetLength);
3439 InstallFunc(isolate, table_proto, "grow", wasm::WebAssemblyTableGrow, 1);
3440 InstallFunc(isolate, table_proto, "set", wasm::WebAssemblyTableSet, 1);
3441 InstallFunc(isolate, table_proto, "get", wasm::WebAssemblyTableGet, 1,
3442 false, NONE, SideEffectType::kHasNoSideEffect);
3443 }
3444
3445 // Create the Memory object.
3446 {
3447 DirectHandle<JSFunction> memory_constructor = InstallConstructorFunc(
3448 isolate, webassembly, "Memory", wasm::WebAssemblyMemory);
3449 DirectHandle<JSObject> memory_proto =
3450 SetupConstructor(isolate, memory_constructor, WASM_MEMORY_OBJECT_TYPE,
3451 WasmMemoryObject::kHeaderSize, "WebAssembly.Memory");
3452 native_context->set_wasm_memory_constructor(*memory_constructor);
3453 InstallFunc(isolate, memory_proto, "grow", wasm::WebAssemblyMemoryGrow, 1);
3454 InstallGetter(isolate, memory_proto, "buffer",
3455 wasm::WebAssemblyMemoryGetBuffer);
3456 }
3457
3458 // Create the Global object.
3459 {
3460 DirectHandle<JSFunction> global_constructor = InstallConstructorFunc(
3461 isolate, webassembly, "Global", wasm::WebAssemblyGlobal);
3462 DirectHandle<JSObject> global_proto =
3463 SetupConstructor(isolate, global_constructor, WASM_GLOBAL_OBJECT_TYPE,
3464 WasmGlobalObject::kHeaderSize, "WebAssembly.Global");
3465 native_context->set_wasm_global_constructor(*global_constructor);
3466 InstallFunc(isolate, global_proto, "valueOf",
3467 wasm::WebAssemblyGlobalValueOf, 0, false, NONE,
3468 SideEffectType::kHasNoSideEffect);
3469 InstallGetterSetter(isolate, global_proto, "value",
3470 wasm::WebAssemblyGlobalGetValue,
3471 wasm::WebAssemblyGlobalSetValue);
3472 }
3473
3474 // Create the Exception object.
3475 {
3476 DirectHandle<JSFunction> tag_constructor = InstallConstructorFunc(
3477 isolate, webassembly, "Tag", wasm::WebAssemblyTag);
3478 SetupConstructor(isolate, tag_constructor, WASM_TAG_OBJECT_TYPE,
3479 WasmTagObject::kHeaderSize, "WebAssembly.Tag");
3480 native_context->set_wasm_tag_constructor(*tag_constructor);
3481 auto js_tag = WasmExceptionTag::New(isolate, 0);
3482 // Note the canonical_type_index is reset in WasmJs::Install s.t.
3483 // type_canonicalizer bookkeeping remains valid.
3484 static constexpr wasm::CanonicalTypeIndex kInitialCanonicalTypeIndex{0};
3485 DirectHandle<JSObject> js_tag_object = WasmTagObject::New(
3486 isolate, &kWasmExceptionTagSignature, kInitialCanonicalTypeIndex,
3488 native_context->set_wasm_js_tag(*js_tag_object);
3489 JSObject::AddProperty(isolate, webassembly, "JSTag", js_tag_object,
3490 ro_attributes);
3491 }
3492
3493 // Set up the runtime exception constructor.
3494 {
3495 DirectHandle<JSFunction> exception_constructor = InstallConstructorFunc(
3496 isolate, webassembly, "Exception", wasm::WebAssemblyException);
3497 SetDummyInstanceTemplate(isolate, exception_constructor);
3498 DirectHandle<JSObject> exception_proto = SetupConstructor(
3499 isolate, exception_constructor, WASM_EXCEPTION_PACKAGE_TYPE,
3500 WasmExceptionPackage::kSize, "WebAssembly.Exception",
3501 WasmExceptionPackage::kInObjectFieldCount);
3502 InstallFunc(isolate, exception_proto, "getArg",
3503 wasm::WebAssemblyExceptionGetArg, 2);
3504 InstallFunc(isolate, exception_proto, "is", wasm::WebAssemblyExceptionIs,
3505 1);
3506 native_context->set_wasm_exception_constructor(*exception_constructor);
3507
3508 DirectHandle<Map> initial_map(exception_constructor->initial_map(),
3509 isolate);
3510 Map::EnsureDescriptorSlack(isolate, initial_map, 2);
3511 {
3512 Descriptor d = Descriptor::DataField(
3513 isolate, f->wasm_exception_tag_symbol(),
3514 WasmExceptionPackage::kTagIndex, DONT_ENUM, Representation::Tagged());
3515 initial_map->AppendDescriptor(isolate, &d);
3516 }
3517 {
3518 Descriptor d =
3519 Descriptor::DataField(isolate, f->wasm_exception_values_symbol(),
3520 WasmExceptionPackage::kValuesIndex, DONT_ENUM,
3521 Representation::Tagged());
3522 initial_map->AppendDescriptor(isolate, &d);
3523 }
3524 }
3525
3526 // By default, make all exported functions an instance of {Function}.
3527 {
3528 DirectHandle<Map> function_map =
3529 isolate->sloppy_function_without_prototype_map();
3530 native_context->set_wasm_exported_function_map(*function_map);
3531 }
3532
3533 // Setup errors.
3534 {
3535 InstallError(isolate, webassembly, f->CompileError_string(),
3536 Context::WASM_COMPILE_ERROR_FUNCTION_INDEX);
3537 InstallError(isolate, webassembly, f->LinkError_string(),
3538 Context::WASM_LINK_ERROR_FUNCTION_INDEX);
3539 InstallError(isolate, webassembly, f->RuntimeError_string(),
3540 Context::WASM_RUNTIME_ERROR_FUNCTION_INDEX);
3541 }
3542}
3543
3544void WasmJs::InstallModule(Isolate* isolate,
3545 DirectHandle<JSObject> webassembly) {
3546 DirectHandle<JSGlobalObject> global = isolate->global_object();
3547 DirectHandle<NativeContext> native_context(global->native_context(), isolate);
3548
3549 DirectHandle<JSFunction> module_constructor;
3550 if (v8_flags.js_source_phase_imports) {
3552 intrinsic_abstract_module_source_interface_template =
3553 NewFunctionTemplate(isolate, nullptr, false);
3554 DirectHandle<JSObject> abstract_module_source_prototype =
3556 native_context->abstract_module_source_prototype(), isolate);
3557 ApiNatives::AddDataProperty(
3558 isolate, intrinsic_abstract_module_source_interface_template,
3559 isolate->factory()->prototype_string(),
3560 abstract_module_source_prototype, NONE);
3561
3562 // Check that this is a reinstallation of the Module object.
3563 DirectHandle<String> name = v8_str(isolate, "Module");
3564 CHECK(
3565 JSObject::HasRealNamedProperty(isolate, webassembly, name).ToChecked());
3566 // Reinstall the Module object with AbstractModuleSource as prototype.
3567 module_constructor =
3568 CreateFunc(isolate, name, wasm::WebAssemblyModule, true,
3569 SideEffectType::kHasNoSideEffect,
3570 intrinsic_abstract_module_source_interface_template);
3571 // WebAssembly.Module is a subclass of %AbstractModuleSource%, hence
3572 // Object.GetPrototypeOf(WebAssembly.Module) === %AbstractModuleSource%.
3573 JSObject::ForceSetPrototype(
3574 isolate, module_constructor,
3575 direct_handle(native_context->abstract_module_source_function(),
3576 isolate));
3577 module_constructor->shared()->set_length(1);
3578 JSObject::SetOwnPropertyIgnoreAttributes(webassembly, name,
3579 module_constructor, DONT_ENUM)
3580 .Assert();
3581 } else {
3582 module_constructor = InstallConstructorFunc(isolate, webassembly, "Module",
3583 wasm::WebAssemblyModule);
3584 }
3585 SetupConstructor(isolate, module_constructor, WASM_MODULE_OBJECT_TYPE,
3586 WasmModuleObject::kHeaderSize, "WebAssembly.Module");
3587 native_context->set_wasm_module_constructor(*module_constructor);
3588
3589 InstallFunc(isolate, module_constructor, "imports",
3590 wasm::WebAssemblyModuleImports, 1, false, NONE,
3591 SideEffectType::kHasNoSideEffect);
3592 InstallFunc(isolate, module_constructor, "exports",
3593 wasm::WebAssemblyModuleExports, 1, false, NONE,
3594 SideEffectType::kHasNoSideEffect);
3595 InstallFunc(isolate, module_constructor, "customSections",
3596 wasm::WebAssemblyModuleCustomSections, 2, false, NONE,
3597 SideEffectType::kHasNoSideEffect);
3598}
3599
3600// static
3601void WasmJs::Install(Isolate* isolate) {
3602 DirectHandle<JSGlobalObject> global = isolate->global_object();
3603 DirectHandle<NativeContext> native_context(global->native_context(), isolate);
3604
3605 if (native_context->is_wasm_js_installed() != Smi::zero()) return;
3606 native_context->set_is_wasm_js_installed(Smi::FromInt(1));
3607
3608 // We always use the WebAssembly object from the native context; as this code
3609 // is executed before any user code, this is expected to be the same as the
3610 // global "WebAssembly" property. But even later during execution we always
3611 // want to use this preallocated object instead of whatever user code
3612 // installed as "WebAssembly" property.
3613 DirectHandle<JSObject> webassembly(native_context->wasm_webassembly_object(),
3614 isolate);
3615 if (v8_flags.js_source_phase_imports) {
3616 // Reinstall the Module object with the experimental interface.
3617 InstallModule(isolate, webassembly);
3618 }
3619
3620 // Expose the API on the global object if not in jitless mode (with more
3621 // subtleties).
3622 //
3623 // Even in interpreter-only mode, wasm currently still creates executable
3624 // memory at runtime. Unexpose wasm until this changes.
3625 // The correctness fuzzers are a special case: many of their test cases are
3626 // built by fetching a random property from the the global object, and thus
3627 // the global object layout must not change between configs. That is why we
3628 // continue exposing wasm on correctness fuzzers even in jitless mode.
3629 // TODO(jgruber): Remove this once / if wasm can run without executable
3630 // memory.
3631 bool expose_wasm = !i::v8_flags.jitless ||
3632 i::v8_flags.correctness_fuzzer_suppressions ||
3633 i::v8_flags.wasm_jitless;
3634 if (expose_wasm) {
3635 DirectHandle<String> WebAssembly_string = v8_str(isolate, "WebAssembly");
3636 JSObject::AddProperty(isolate, global, WebAssembly_string, webassembly,
3637 DONT_ENUM);
3638 }
3639
3640 {
3641 // Reset the JSTag's canonical_type_index based on this Isolate's
3642 // type_canonicalizer.
3643 DirectHandle<WasmTagObject> js_tag_object(
3644 Cast<WasmTagObject>(native_context->wasm_js_tag()), isolate);
3645 js_tag_object->set_canonical_type_index(
3646 wasm::GetWasmEngine()
3647 ->type_canonicalizer()
3648 ->AddRecursiveGroup(&kWasmExceptionTagSignature)
3649 .index);
3650 }
3651
3652 if (v8_flags.wasm_test_streaming) {
3653 isolate->set_wasm_streaming_callback(WasmStreamingCallbackForTesting);
3654 }
3655
3656 if (isolate->wasm_streaming_callback() != nullptr) {
3657 InstallFunc(isolate, webassembly, "compileStreaming",
3658 WebAssemblyCompileStreaming, 1);
3659 InstallFunc(isolate, webassembly, "instantiateStreaming",
3660 WebAssemblyInstantiateStreaming, 1);
3661 }
3662
3663 // The native_context is not set up completely yet. That's why we cannot use
3664 // {WasmEnabledFeatures::FromIsolate} and have to use
3665 // {WasmEnabledFeatures::FromFlags} instead.
3666 const auto enabled_features = wasm::WasmEnabledFeatures::FromFlags();
3667
3668 if (enabled_features.has_type_reflection()) {
3669 InstallTypeReflection(isolate, native_context, webassembly);
3670 }
3671
3672 if (enabled_features.has_memory_control()) {
3673 InstallMemoryControl(isolate, native_context, webassembly);
3674 }
3675
3676 // Initialize and install JSPI feature.
3677 if (enabled_features.has_jspi()) {
3678 CHECK(native_context->is_wasm_jspi_installed() == Smi::zero());
3679 isolate->WasmInitJSPIFeature();
3680 InstallJSPromiseIntegration(isolate, native_context, webassembly);
3681 native_context->set_is_wasm_jspi_installed(Smi::FromInt(1));
3682 } else if (v8_flags.stress_wasm_stack_switching) {
3683 // Set up the JSPI objects necessary for stress-testing stack-switching, but
3684 // don't install WebAssembly.promising and WebAssembly.Suspending.
3685 isolate->WasmInitJSPIFeature();
3686 }
3687
3688 if (enabled_features.has_rab_integration()) {
3689 InstallResizableBufferIntegration(isolate, native_context, webassembly);
3690 }
3691}
3692
3693// static
3694void WasmJs::InstallConditionalFeatures(Isolate* isolate,
3696 DirectHandle<JSObject> webassembly{context->wasm_webassembly_object(),
3697 isolate};
3698 if (!webassembly->map()->is_extensible()) return;
3699 if (webassembly->map()->is_access_check_needed()) return;
3700
3701 // If you need to install some optional features, follow the pattern:
3702 //
3703 // if (isolate->IsMyWasmFeatureEnabled(context)) {
3704 // DirectHandle<String> feature = isolate->factory()->...;
3705 // if (!JSObject::HasRealNamedProperty(isolate, webassembly, feature)
3706 // .FromMaybe(true)) {
3707 // InstallFeature(isolate, webassembly);
3708 // }
3709 // }
3710
3711 // Install JSPI-related features.
3712 if (isolate->IsWasmJSPIRequested(context)) {
3713 if (context->is_wasm_jspi_installed() == Smi::zero()) {
3714 isolate->WasmInitJSPIFeature();
3715 if (InstallJSPromiseIntegration(isolate, context, webassembly) &&
3716 InstallTypeReflection(isolate, context, webassembly)) {
3717 context->set_is_wasm_jspi_installed(Smi::FromInt(1));
3718 }
3719 }
3720 }
3721}
3722
3723// static
3724// Return true if this call results in JSPI being installed.
3725bool WasmJs::InstallJSPromiseIntegration(Isolate* isolate,
3727 DirectHandle<JSObject> webassembly) {
3728 DirectHandle<String> suspender_string = v8_str(isolate, "Suspender");
3729 if (JSObject::HasRealNamedProperty(isolate, webassembly, suspender_string)
3730 .FromMaybe(true)) {
3731 return false;
3732 }
3733 DirectHandle<String> suspending_string = v8_str(isolate, "Suspending");
3734 if (JSObject::HasRealNamedProperty(isolate, webassembly, suspending_string)
3735 .FromMaybe(true)) {
3736 return false;
3737 }
3738 DirectHandle<String> promising_string = v8_str(isolate, "promising");
3739 if (JSObject::HasRealNamedProperty(isolate, webassembly, promising_string)
3740 .FromMaybe(true)) {
3741 return false;
3742 }
3743 DirectHandle<String> suspend_error_string = v8_str(isolate, "SuspendError");
3744 if (JSObject::HasRealNamedProperty(isolate, webassembly, suspend_error_string)
3745 .FromMaybe(true)) {
3746 return false;
3747 }
3748 DirectHandle<JSFunction> suspending_constructor = InstallConstructorFunc(
3749 isolate, webassembly, "Suspending", WebAssemblySuspendingImpl);
3750 context->set_wasm_suspending_constructor(*suspending_constructor);
3751 SetupConstructor(isolate, suspending_constructor, WASM_SUSPENDING_OBJECT_TYPE,
3752 WasmSuspendingObject::kHeaderSize, "WebAssembly.Suspending");
3753 InstallFunc(isolate, webassembly, "promising", WebAssemblyPromising, 1);
3754 InstallError(isolate, webassembly, isolate->factory()->SuspendError_string(),
3755 Context::WASM_SUSPEND_ERROR_FUNCTION_INDEX);
3756 return true;
3757}
3758
3759void WasmJs::InstallMemoryControl(Isolate* isolate,
3761 DirectHandle<JSObject> webassembly) {
3762 // Extensibility of the `WebAssembly` object should already have been checked
3763 // by the caller.
3764 DCHECK(webassembly->map()->is_extensible());
3765
3766 DirectHandle<JSFunction> descriptor_constructor =
3767 InstallConstructorFunc(isolate, webassembly, "MemoryMapDescriptor",
3768 wasm::WebAssemblyMemoryMapDescriptor);
3769 SetupConstructor(
3770 isolate, descriptor_constructor, WASM_MEMORY_MAP_DESCRIPTOR_TYPE,
3771 WasmMemoryMapDescriptor::kHeaderSize, "WebAssembly.MemoryMapDescriptor");
3772 context->set_wasm_memory_map_descriptor_constructor(*descriptor_constructor);
3773
3774 DirectHandle<JSObject> descriptor_proto = direct_handle(
3775 Cast<JSObject>(descriptor_constructor->instance_prototype()), isolate);
3776
3777 InstallFunc(isolate, descriptor_proto, "map",
3778 wasm::WebAssemblyMemoryMapDescriptorMap, 2);
3779 InstallFunc(isolate, descriptor_proto, "unmap",
3780 wasm::WebAssemblyMemoryMapDescriptorUnmap, 0);
3781}
3782
3783// Return true only if this call resulted in installation of type reflection.
3784// static
3785bool WasmJs::InstallTypeReflection(Isolate* isolate,
3787 DirectHandle<JSObject> webassembly) {
3788 // Extensibility of the `WebAssembly` object should already have been checked
3789 // by the caller.
3790 DCHECK(webassembly->map()->is_extensible());
3791
3792 // First check if any of the type reflection fields already exist. If so, bail
3793 // out and don't install any new fields.
3794 if (JSObject::HasRealNamedProperty(isolate, webassembly,
3795 isolate->factory()->Function_string())
3796 .FromMaybe(true)) {
3797 return false;
3798 }
3799
3800 auto GetProto = [isolate](Tagged<JSFunction> constructor) {
3801 return handle(Cast<JSObject>(constructor->instance_prototype()), isolate);
3802 };
3803 DirectHandle<JSObject> table_proto =
3804 GetProto(context->wasm_table_constructor());
3805 DirectHandle<JSObject> global_proto =
3806 GetProto(context->wasm_global_constructor());
3807 DirectHandle<JSObject> memory_proto =
3808 GetProto(context->wasm_memory_constructor());
3809 DirectHandle<JSObject> tag_proto = GetProto(context->wasm_tag_constructor());
3810
3811 DirectHandle<String> type_string = v8_str(isolate, "type");
3812 auto CheckProto = [isolate, type_string](DirectHandle<JSObject> proto) {
3813 if (JSObject::HasRealNamedProperty(isolate, proto, type_string)
3814 .FromMaybe(true)) {
3815 return false;
3816 }
3817 // Also check extensibility, otherwise adding properties will fail.
3818 if (!proto->map()->is_extensible()) return false;
3819 return true;
3820 };
3821 if (!CheckProto(table_proto)) return false;
3822 if (!CheckProto(global_proto)) return false;
3823 if (!CheckProto(memory_proto)) return false;
3824 if (!CheckProto(tag_proto)) return false;
3825
3826 // Checks are done, start installing the new fields.
3827 InstallFunc(isolate, table_proto, type_string, WebAssemblyTableType, 0, false,
3828 NONE, SideEffectType::kHasNoSideEffect);
3829 InstallFunc(isolate, memory_proto, type_string, WebAssemblyMemoryType, 0,
3830 false, NONE, SideEffectType::kHasNoSideEffect);
3831 InstallFunc(isolate, global_proto, type_string, WebAssemblyGlobalType, 0,
3832 false, NONE, SideEffectType::kHasNoSideEffect);
3833 InstallFunc(isolate, tag_proto, type_string, WebAssemblyTagType, 0, false,
3834 NONE, SideEffectType::kHasNoSideEffect);
3835
3836 // Create the Function object.
3837 DirectHandle<JSFunction> function_constructor = InstallConstructorFunc(
3838 isolate, webassembly, "Function", WebAssemblyFunction);
3839 SetDummyInstanceTemplate(isolate, function_constructor);
3840 JSFunction::EnsureHasInitialMap(function_constructor);
3841 DirectHandle<JSObject> function_proto(
3842 Cast<JSObject>(function_constructor->instance_prototype()), isolate);
3843 DirectHandle<Map> function_map =
3844 Map::Copy(isolate, isolate->sloppy_function_without_prototype_map(),
3845 "WebAssembly.Function");
3846 CHECK(JSObject::SetPrototype(
3847 isolate, function_proto,
3848 direct_handle(context->function_function()->prototype(), isolate),
3849 false, kDontThrow)
3850 .FromJust());
3851 JSFunction::SetInitialMap(isolate, function_constructor, function_map,
3852 function_proto);
3853
3854 constexpr PropertyAttributes ro_attributes =
3855 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
3856 JSObject::AddProperty(isolate, function_proto,
3857 isolate->factory()->to_string_tag_symbol(),
3858 v8_str(isolate, "WebAssembly.Function"), ro_attributes);
3859
3860 InstallFunc(isolate, function_proto, type_string, WebAssemblyFunctionType, 0);
3861 SimpleInstallFunction(isolate, function_proto, "bind",
3862 Builtin::kWebAssemblyFunctionPrototypeBind, 1,
3863 kDontAdapt);
3864 // Make all exported functions an instance of {WebAssembly.Function}.
3865 context->set_wasm_exported_function_map(*function_map);
3866 return true;
3867}
3868
3869// static
3870void WasmJs::InstallResizableBufferIntegration(
3871 Isolate* isolate, DirectHandle<NativeContext> context,
3872 DirectHandle<JSObject> webassembly) {
3873 // Extensibility of the `WebAssembly` object should already have been checked
3874 // by the caller.
3875 DCHECK(webassembly->map()->is_extensible());
3876
3878 Cast<JSObject>(context->wasm_memory_constructor()->instance_prototype()),
3879 isolate);
3880 InstallFunc(isolate, memory_proto, "toFixedLengthBuffer",
3881 wasm::WebAssemblyMemoryToFixedLengthBuffer, 0);
3882 InstallFunc(isolate, memory_proto, "toResizableBuffer",
3883 wasm::WebAssemblyMemoryToResizableBuffer, 0);
3884}
3885
3886namespace wasm {
3887// static
3888std::unique_ptr<WasmStreaming> StartStreamingForTesting(
3889 Isolate* isolate,
3890 std::shared_ptr<wasm::CompilationResultResolver> resolver) {
3891 return std::make_unique<WasmStreaming>(
3892 std::make_unique<WasmStreaming::WasmStreamingImpl>(
3893 isolate, "StartStreamingForTesting", CompileTimeImports{}, resolver));
3894}
3895} // namespace wasm
3896
3897#undef ASSIGN
3898#undef EXTRACT_THIS
3899
3900} // namespace internal
3901} // namespace v8
Isolate * isolate_
const char * name
Definition builtins.cc:39
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
#define BUILTIN_CODE(isolate, name)
Definition builtins.h:45
PropertyT * setter
PropertyT * getter
#define SBXCHECK(condition)
Definition check.h:61
static Local< BigInt > New(Isolate *isolate, int64_t value)
Definition api.cc:9591
static Local< BigInt > NewFromUnsigned(Isolate *isolate, uint64_t value)
Definition api.cc:9598
static Local< FunctionTemplate > New(Isolate *isolate, FunctionCallback callback=nullptr, Local< Value > data=Local< Value >(), Local< Signature > signature=Local< Signature >(), int length=0, ConstructorBehavior behavior=ConstructorBehavior::kAllow, SideEffectType side_effect_type=SideEffectType::kHasSideEffect, const CFunction *c_function=nullptr, uint16_t instance_type=0, uint16_t allowed_receiver_instance_type_range_start=0, uint16_t allowed_receiver_instance_type_range_end=0)
Definition api.cc:1101
static MaybeLocal< Function > New(Local< Context > context, FunctionCallback callback, Local< Value > data=Local< Value >(), int length=0, ConstructorBehavior behavior=ConstructorBehavior::kAllow, SideEffectType side_effect_type=SideEffectType::kHasSideEffect)
Definition api.cc:5348
static Local< Integer > New(Isolate *isolate, int32_t value)
Definition api.cc:9568
@ kWasmJavaScriptPromiseIntegration
Definition v8-isolate.h:602
@ kWebAssemblyInstantiation
Definition v8-isolate.h:515
V8_INLINE Local< S > As() const
static V8_INLINE Local< T > Cast(Local< S > that)
V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local< S > *out) const
static Local< Number > New(Isolate *isolate, double value)
Definition api.cc:9557
static Local< ObjectTemplate > New(Isolate *isolate, Local< FunctionTemplate > constructor=Local< FunctionTemplate >())
Definition api.cc:1376
static V8_WARN_UNUSED_RESULT MaybeLocal< Resolver > New(Local< Context > context)
Definition api.cc:8640
V8_INLINE void Set(const Global< S > &handle)
static v8::internal::Handle< To > OpenHandle(v8::Local< From > handle)
Definition api.h:274
static v8::internal::DirectHandle< To > OpenDirectHandle(v8::Local< From > handle)
Definition api.h:279
void SetMoreFunctionsCanBeSerializedCallback(std::function< void(CompiledWasmModule)> callback)
Definition wasm-js.cc:98
bool SetCompiledModuleBytes(base::Vector< const uint8_t > bytes)
Definition wasm-js.cc:92
void Abort(i::MaybeHandle< i::JSAny > exception)
Definition wasm-js.cc:80
const WasmEnabledFeatures enabled_features_
Definition wasm-js.cc:112
const std::shared_ptr< internal::wasm::CompilationResultResolver > resolver_
Definition wasm-js.cc:114
WasmStreamingImpl(i::Isolate *isolate, const char *api_method_name, CompileTimeImports compile_imports, std::shared_ptr< internal::wasm::CompilationResultResolver > resolver)
Definition wasm-js.cc:61
void Finish(bool can_use_compiled_module)
Definition wasm-js.cc:76
const std::shared_ptr< internal::wasm::StreamingDecoder > streaming_decoder_
Definition wasm-js.cc:113
void OnBytesReceived(const uint8_t *bytes, size_t size)
Definition wasm-js.cc:73
void SetUrl(base::Vector< const char > url)
Definition wasm-js.cc:108
std::unique_ptr< WasmStreamingImpl > impl_
Definition v8-wasm.h:199
void Finish(bool can_use_compiled_module=true)
Definition api.cc:11946
bool SetCompiledModuleBytes(const uint8_t *bytes, size_t size)
Definition api.cc:11950
void SetUrl(const char *url, size_t length)
Definition api.cc:11959
void SetMoreFunctionsCanBeSerializedCallback(std::function< void(CompiledWasmModule)>)
Definition api.cc:11954
void Abort(MaybeLocal< Value > exception)
Definition api.cc:11948
void OnBytesReceived(const uint8_t *bytes, size_t size)
Definition api.cc:11942
static std::shared_ptr< WasmStreaming > Unpack(Isolate *isolate, Local< Value > value)
Definition api.cc:11962
static V8_BASE_EXPORT bool GetFlushDenormals()
Definition fpu.cc:96
static OwnedVector< T > NewForOverwrite(size_t size)
Definition vector.h:294
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
Handle< JSObject > NewJSObject(DirectHandle< JSFunction > constructor, AllocationType allocation=AllocationType::kYoung, NewJSObjectType=NewJSObjectType::kNoAPIWrapper)
Definition factory.cc:2985
Tagged< Object > exception()
v8::internal::Factory * factory()
Definition isolate.h:1527
V8_WARN_UNUSED_RESULT V8_INLINE bool ToHandle(DirectHandle< S > *out) const
constexpr const char * ToString(DataViewOp op)
int start
Handle< SharedFunctionInfo > info
Handle< Context > context_
#define ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, value)
Definition isolate.h:276
#define MAYBE_RETURN(call, value)
Definition isolate.h:408
Isolate * isolate
std::ostream & impl_
OptionalOpIndex index
int32_t offset
TNode< Object > receiver
TNode< Object > callback
ZoneVector< RpoNumber > & result
ArgType first_arg
InstructionOperand destination
STL namespace.
int int32_t
Definition unicode.cc:40
void MakeWeak(i::Address *location, void *parameter, WeakCallbackInfo< void >::Callback weak_callback, WeakCallbackType type)
Definition api.cc:644
V8_INLINE Dest bit_cast(Source const &source)
Definition macros.h:95
void Relaxed_Memcpy(volatile Atomic8 *dst, volatile const Atomic8 *src, size_t bytes)
Definition atomicops.h:363
char Atomic8
Definition atomicops.h:57
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
Vector< const char > CStrVector(const char *data)
Definition vector.h:331
std::unique_ptr< WasmStreaming > StartStreamingForTesting(Isolate *isolate, std::shared_ptr< wasm::CompilationResultResolver > resolver)
Definition wasm-js.cc:3888
bool IsJSCompatibleSignature(const CanonicalSig *sig)
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
Handle< JSFunction > SimpleInstallFunction(Isolate *isolate, DirectHandle< JSObject > base, const char *name, Builtin call, int len, AdaptArguments adapt, PropertyAttributes attrs)
void EncodeI32ExceptionValue(DirectHandle< FixedArray > encoded_values, uint32_t *encoded_index, uint32_t value)
void DecodeI32ExceptionValue(DirectHandle< FixedArray > encoded_values, uint32_t *encoded_index, uint32_t *value)
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
bool IsNullOrUndefined(Tagged< Object > obj, Isolate *isolate)
constexpr uint64_t kMaxUInt64
Definition globals.h:390
void DecodeI64ExceptionValue(DirectHandle< FixedArray > encoded_values, uint32_t *encoded_index, uint64_t *value)
bool V8_EXPORT ValidateCallbackInfo(const FunctionCallbackInfo< void > &info)
Definition api.cc:12301
V8_INLINE constexpr bool IsObject(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:661
V8_EXPORT_PRIVATE FlagValues v8_flags
void ToUtf8Lossy(Isolate *isolate, DirectHandle< String > string, std::string &out)
float DoubleToFloat32(double x)
constexpr int kMaxInt
Definition globals.h:374
void InstallError(Isolate *isolate, DirectHandle< JSObject > global, DirectHandle< String > name, int context_index, Builtin error_constructor, int error_function_length)
JSArrayBuffer::IsDetachableBit is_shared
constexpr uint32_t kMaxUInt32
Definition globals.h:387
void EncodeI64ExceptionValue(DirectHandle< FixedArray > encoded_values, uint32_t *encoded_index, uint64_t value)
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
@ None
Definition v8-object.h:141
SideEffectType
Definition v8-object.h:198
V8_INLINE Local< Boolean > False(Isolate *isolate)
bool ToLocal(v8::internal::MaybeDirectHandle< v8::internal::Object > maybe, Local< T > *local)
Definition api.h:303
ConstructorBehavior
void(*)(const FunctionCallbackInfo< Value > &info) FunctionCallback
WasmAsyncSuccess
static i::DirectHandle< i::ObjectTemplateInfo > NewObjectTemplate(i::Isolate *i_isolate)
Definition wasm-js.cc:3235
static i::DirectHandle< i::FunctionTemplateInfo > NewFunctionTemplate(i::Isolate *i_isolate, FunctionCallback func, bool has_prototype, SideEffectType side_effect_type=SideEffectType::kHasSideEffect)
Definition wasm-js.cc:3223
Definition c-api.cc:87
#define UNREACHABLE()
Definition logging.h:67
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#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_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define arraysize(array)
Definition macros.h:67
Symbol method
#define TRACE_EVENT0(category_group, name)
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:671
#define V8_UNLIKELY(condition)
Definition v8config.h:660
std::unique_ptr< ValueMirror > value
wasm::ValueType type
const wasm::WasmModule * module_
#define DEF_WASM_JS_EXTERNAL_REFERENCE(Name)
Definition wasm-js.cc:3211
#define GET_FIRST_ARGUMENT_AS(Type)
Definition wasm-js.cc:181
#define EXTRACT_THIS(var, WasmType)
Definition wasm-js.cc:2525
#define WASM_JS_EXTERNAL_REFERENCE_LIST(V)
Definition wasm-js.h:32
#define ZONE_NAME
Definition zone.h:22