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 "src/api-inl.h"
8 #include "src/api-natives.h"
9 #include "src/assert-scope.h"
10 #include "src/ast/ast.h"
11 #include "src/execution.h"
12 #include "src/handles.h"
13 #include "src/heap/factory.h"
14 #include "src/isolate.h"
15 #include "src/objects-inl.h"
16 #include "src/objects/js-promise-inl.h"
17 #include "src/objects/templates.h"
18 #include "src/parsing/parse-info.h"
19 #include "src/trap-handler/trap-handler.h"
20 #include "src/wasm/streaming-decoder.h"
21 #include "src/wasm/wasm-engine.h"
22 #include "src/wasm/wasm-limits.h"
23 #include "src/wasm/wasm-memory.h"
24 #include "src/wasm/wasm-objects-inl.h"
25
26 using v8::internal::wasm::ErrorThrower;
27
28 namespace v8 {
29
30 class WasmStreaming::WasmStreamingImpl {
31 public:
WasmStreamingImpl(Isolate * isolate,std::shared_ptr<internal::wasm::CompilationResultResolver> resolver)32 WasmStreamingImpl(
33 Isolate* isolate,
34 std::shared_ptr<internal::wasm::CompilationResultResolver> resolver)
35 : isolate_(isolate), resolver_(std::move(resolver)) {
36 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate_);
37 auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
38 streaming_decoder_ = i_isolate->wasm_engine()->StartStreamingCompilation(
39 i_isolate, enabled_features, handle(i_isolate->context(), i_isolate),
40 resolver_);
41 }
42
OnBytesReceived(const uint8_t * bytes,size_t size)43 void OnBytesReceived(const uint8_t* bytes, size_t size) {
44 streaming_decoder_->OnBytesReceived(i::Vector<const uint8_t>(bytes, size));
45 }
Finish()46 void Finish() { streaming_decoder_->Finish(); }
47
Abort(MaybeLocal<Value> exception)48 void Abort(MaybeLocal<Value> exception) {
49 i::HandleScope scope(reinterpret_cast<i::Isolate*>(isolate_));
50 streaming_decoder_->Abort();
51
52 // If no exception value is provided, we do not reject the promise. This can
53 // happen when streaming compilation gets aborted when no script execution
54 // is allowed anymore, e.g. when a browser tab gets refreshed.
55 if (exception.IsEmpty()) return;
56
57 resolver_->OnCompilationFailed(
58 Utils::OpenHandle(*exception.ToLocalChecked()));
59 }
60
61 private:
62 Isolate* isolate_ = nullptr;
63 std::shared_ptr<internal::wasm::StreamingDecoder> streaming_decoder_;
64 std::shared_ptr<internal::wasm::CompilationResultResolver> resolver_;
65 };
66
WasmStreaming(std::unique_ptr<WasmStreamingImpl> impl)67 WasmStreaming::WasmStreaming(std::unique_ptr<WasmStreamingImpl> impl)
68 : impl_(std::move(impl)) {}
69
70 // The destructor is defined here because we have a unique_ptr with forward
71 // declaration.
72 WasmStreaming::~WasmStreaming() = default;
73
OnBytesReceived(const uint8_t * bytes,size_t size)74 void WasmStreaming::OnBytesReceived(const uint8_t* bytes, size_t size) {
75 impl_->OnBytesReceived(bytes, size);
76 }
77
Finish()78 void WasmStreaming::Finish() { impl_->Finish(); }
79
Abort(MaybeLocal<Value> exception)80 void WasmStreaming::Abort(MaybeLocal<Value> exception) {
81 impl_->Abort(exception);
82 }
83
84 // static
Unpack(Isolate * isolate,Local<Value> value)85 std::shared_ptr<WasmStreaming> WasmStreaming::Unpack(Isolate* isolate,
86 Local<Value> value) {
87 i::HandleScope scope(reinterpret_cast<i::Isolate*>(isolate));
88 auto managed =
89 i::Handle<i::Managed<WasmStreaming>>::cast(Utils::OpenHandle(*value));
90 return managed->get();
91 }
92
93 namespace {
94
95 #define ASSIGN(type, var, expr) \
96 Local<type> var; \
97 do { \
98 if (!expr.ToLocal(&var)) { \
99 DCHECK(i_isolate->has_scheduled_exception()); \
100 return; \
101 } else { \
102 DCHECK(!i_isolate->has_scheduled_exception()); \
103 } \
104 } while (false)
105
106 // Like an ErrorThrower, but turns all pending exceptions into scheduled
107 // exceptions when going out of scope. Use this in API methods.
108 // Note that pending exceptions are not necessarily created by the ErrorThrower,
109 // but e.g. by the wasm start function. There might also be a scheduled
110 // exception, created by another API call (e.g. v8::Object::Get). But there
111 // should never be both pending and scheduled exceptions.
112 class ScheduledErrorThrower : public ErrorThrower {
113 public:
ScheduledErrorThrower(i::Isolate * isolate,const char * context)114 ScheduledErrorThrower(i::Isolate* isolate, const char* context)
115 : ErrorThrower(isolate, context) {}
116
117 ~ScheduledErrorThrower();
118 };
119
~ScheduledErrorThrower()120 ScheduledErrorThrower::~ScheduledErrorThrower() {
121 // There should never be both a pending and a scheduled exception.
122 DCHECK(!isolate()->has_scheduled_exception() ||
123 !isolate()->has_pending_exception());
124 // Don't throw another error if there is already a scheduled error.
125 if (isolate()->has_scheduled_exception()) {
126 Reset();
127 } else if (isolate()->has_pending_exception()) {
128 Reset();
129 isolate()->OptionalRescheduleException(false);
130 } else if (error()) {
131 isolate()->ScheduleThrow(*Reify());
132 }
133 }
134
v8_str(i::Isolate * isolate,const char * str)135 i::Handle<i::String> v8_str(i::Isolate* isolate, const char* str) {
136 return isolate->factory()->NewStringFromAsciiChecked(str);
137 }
v8_str(Isolate * isolate,const char * str)138 Local<String> v8_str(Isolate* isolate, const char* str) {
139 return Utils::ToLocal(v8_str(reinterpret_cast<i::Isolate*>(isolate), str));
140 }
141
GetFirstArgumentAsModule(const v8::FunctionCallbackInfo<v8::Value> & args,ErrorThrower * thrower)142 i::MaybeHandle<i::WasmModuleObject> GetFirstArgumentAsModule(
143 const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
144 i::Handle<i::Object> arg0 = Utils::OpenHandle(*args[0]);
145 if (!arg0->IsWasmModuleObject()) {
146 thrower->TypeError("Argument 0 must be a WebAssembly.Module");
147 return {};
148 }
149
150 Local<Object> module_obj = Local<Object>::Cast(args[0]);
151 return i::Handle<i::WasmModuleObject>::cast(
152 v8::Utils::OpenHandle(*module_obj));
153 }
154
GetFirstArgumentAsBytes(const v8::FunctionCallbackInfo<v8::Value> & args,ErrorThrower * thrower,bool * is_shared)155 i::wasm::ModuleWireBytes GetFirstArgumentAsBytes(
156 const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower,
157 bool* is_shared) {
158 const uint8_t* start = nullptr;
159 size_t length = 0;
160 v8::Local<v8::Value> source = args[0];
161 if (source->IsArrayBuffer()) {
162 // A raw array buffer was passed.
163 Local<ArrayBuffer> buffer = Local<ArrayBuffer>::Cast(source);
164 ArrayBuffer::Contents contents = buffer->GetContents();
165
166 start = reinterpret_cast<const uint8_t*>(contents.Data());
167 length = contents.ByteLength();
168 *is_shared = buffer->IsSharedArrayBuffer();
169 } else if (source->IsTypedArray()) {
170 // A TypedArray was passed.
171 Local<TypedArray> array = Local<TypedArray>::Cast(source);
172 Local<ArrayBuffer> buffer = array->Buffer();
173
174 ArrayBuffer::Contents contents = buffer->GetContents();
175
176 start =
177 reinterpret_cast<const uint8_t*>(contents.Data()) + array->ByteOffset();
178 length = array->ByteLength();
179 *is_shared = buffer->IsSharedArrayBuffer();
180 } else {
181 thrower->TypeError("Argument 0 must be a buffer source");
182 }
183 DCHECK_IMPLIES(length, start != nullptr);
184 if (length == 0) {
185 thrower->CompileError("BufferSource argument is empty");
186 }
187 if (length > i::wasm::kV8MaxWasmModuleSize) {
188 thrower->RangeError("buffer source exceeds maximum size of %zu (is %zu)",
189 i::wasm::kV8MaxWasmModuleSize, length);
190 }
191 if (thrower->error()) return i::wasm::ModuleWireBytes(nullptr, nullptr);
192 return i::wasm::ModuleWireBytes(start, start + length);
193 }
194
GetValueAsImports(Local<Value> arg,ErrorThrower * thrower)195 i::MaybeHandle<i::JSReceiver> GetValueAsImports(Local<Value> arg,
196 ErrorThrower* thrower) {
197 if (arg->IsUndefined()) return {};
198
199 if (!arg->IsObject()) {
200 thrower->TypeError("Argument 1 must be an object");
201 return {};
202 }
203 Local<Object> obj = Local<Object>::Cast(arg);
204 return i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
205 }
206
207 namespace {
208 // This class resolves the result of WebAssembly.compile. It just places the
209 // compilation result in the supplied {promise}.
210 class AsyncCompilationResolver : public i::wasm::CompilationResultResolver {
211 public:
AsyncCompilationResolver(i::Isolate * isolate,i::Handle<i::JSPromise> promise)212 AsyncCompilationResolver(i::Isolate* isolate, i::Handle<i::JSPromise> promise)
213 : promise_(isolate->global_handles()->Create(*promise)) {}
214
~AsyncCompilationResolver()215 ~AsyncCompilationResolver() {
216 i::GlobalHandles::Destroy(i::Handle<i::Object>::cast(promise_).location());
217 }
218
OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result)219 void OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result) override {
220 if (finished_) return;
221 finished_ = true;
222 i::MaybeHandle<i::Object> promise_result =
223 i::JSPromise::Resolve(promise_, result);
224 CHECK_EQ(promise_result.is_null(),
225 promise_->GetIsolate()->has_pending_exception());
226 }
227
OnCompilationFailed(i::Handle<i::Object> error_reason)228 void OnCompilationFailed(i::Handle<i::Object> error_reason) override {
229 if (finished_) return;
230 finished_ = true;
231 i::MaybeHandle<i::Object> promise_result =
232 i::JSPromise::Reject(promise_, error_reason);
233 CHECK_EQ(promise_result.is_null(),
234 promise_->GetIsolate()->has_pending_exception());
235 }
236
237 private:
238 bool finished_ = false;
239 i::Handle<i::JSPromise> promise_;
240 };
241
242 // This class resolves the result of WebAssembly.instantiate(module, imports).
243 // It just places the instantiation result in the supplied {promise}.
244 class InstantiateModuleResultResolver
245 : public i::wasm::InstantiationResultResolver {
246 public:
InstantiateModuleResultResolver(i::Isolate * isolate,i::Handle<i::JSPromise> promise)247 InstantiateModuleResultResolver(i::Isolate* isolate,
248 i::Handle<i::JSPromise> promise)
249 : promise_(isolate->global_handles()->Create(*promise)) {}
250
~InstantiateModuleResultResolver()251 ~InstantiateModuleResultResolver() {
252 i::GlobalHandles::Destroy(i::Handle<i::Object>::cast(promise_).location());
253 }
254
OnInstantiationSucceeded(i::Handle<i::WasmInstanceObject> instance)255 void OnInstantiationSucceeded(
256 i::Handle<i::WasmInstanceObject> instance) override {
257 i::MaybeHandle<i::Object> promise_result =
258 i::JSPromise::Resolve(promise_, instance);
259 CHECK_EQ(promise_result.is_null(),
260 promise_->GetIsolate()->has_pending_exception());
261 }
262
OnInstantiationFailed(i::Handle<i::Object> error_reason)263 void OnInstantiationFailed(i::Handle<i::Object> error_reason) override {
264 i::MaybeHandle<i::Object> promise_result =
265 i::JSPromise::Reject(promise_, error_reason);
266 CHECK_EQ(promise_result.is_null(),
267 promise_->GetIsolate()->has_pending_exception());
268 }
269
270 private:
271 i::Handle<i::JSPromise> promise_;
272 };
273
274 // This class resolves the result of WebAssembly.instantiate(bytes, imports).
275 // For that it creates a new {JSObject} which contains both the provided
276 // {WasmModuleObject} and the resulting {WebAssemblyInstanceObject} itself.
277 class InstantiateBytesResultResolver
278 : public i::wasm::InstantiationResultResolver {
279 public:
InstantiateBytesResultResolver(i::Isolate * isolate,i::Handle<i::JSPromise> promise,i::Handle<i::WasmModuleObject> module)280 InstantiateBytesResultResolver(i::Isolate* isolate,
281 i::Handle<i::JSPromise> promise,
282 i::Handle<i::WasmModuleObject> module)
283 : isolate_(isolate),
284 promise_(isolate_->global_handles()->Create(*promise)),
285 module_(isolate_->global_handles()->Create(*module)) {}
286
~InstantiateBytesResultResolver()287 ~InstantiateBytesResultResolver() {
288 i::GlobalHandles::Destroy(i::Handle<i::Object>::cast(promise_).location());
289 i::GlobalHandles::Destroy(i::Handle<i::Object>::cast(module_).location());
290 }
291
OnInstantiationSucceeded(i::Handle<i::WasmInstanceObject> instance)292 void OnInstantiationSucceeded(
293 i::Handle<i::WasmInstanceObject> instance) override {
294 // The result is a JSObject with 2 fields which contain the
295 // WasmInstanceObject and the WasmModuleObject.
296 i::Handle<i::JSObject> result =
297 isolate_->factory()->NewJSObject(isolate_->object_function());
298
299 const uint8_t* instance_str = reinterpret_cast<const uint8_t*>("instance");
300 i::Handle<i::String> instance_name =
301 isolate_->factory()
302 ->NewStringFromOneByte(i::Vector<const uint8_t>(
303 instance_str,
304 i::StrLength(reinterpret_cast<const char*>(instance_str))))
305 .ToHandleChecked();
306
307 const uint8_t* module_str = reinterpret_cast<const uint8_t*>("module");
308 i::Handle<i::String> module_name =
309 isolate_->factory()
310 ->NewStringFromOneByte(i::Vector<const uint8_t>(
311 module_str,
312 i::StrLength(reinterpret_cast<const char*>(module_str))))
313 .ToHandleChecked();
314
315 i::JSObject::AddProperty(isolate_, result, instance_name, instance,
316 i::NONE);
317 i::JSObject::AddProperty(isolate_, result, module_name, module_, i::NONE);
318
319 i::MaybeHandle<i::Object> promise_result =
320 i::JSPromise::Resolve(promise_, result);
321 CHECK_EQ(promise_result.is_null(), isolate_->has_pending_exception());
322 }
323
OnInstantiationFailed(i::Handle<i::Object> error_reason)324 void OnInstantiationFailed(i::Handle<i::Object> error_reason) override {
325 i::MaybeHandle<i::Object> promise_result =
326 i::JSPromise::Reject(promise_, error_reason);
327 CHECK_EQ(promise_result.is_null(), isolate_->has_pending_exception());
328 }
329
330 private:
331 i::Isolate* isolate_;
332 i::Handle<i::JSPromise> promise_;
333 i::Handle<i::WasmModuleObject> module_;
334 };
335
336 // This class is the {CompilationResultResolver} for
337 // WebAssembly.instantiate(bytes, imports). When compilation finishes,
338 // {AsyncInstantiate} is started on the compilation result.
339 class AsyncInstantiateCompileResultResolver
340 : public i::wasm::CompilationResultResolver {
341 public:
AsyncInstantiateCompileResultResolver(i::Isolate * isolate,i::Handle<i::JSPromise> promise,i::MaybeHandle<i::JSReceiver> maybe_imports)342 AsyncInstantiateCompileResultResolver(
343 i::Isolate* isolate, i::Handle<i::JSPromise> promise,
344 i::MaybeHandle<i::JSReceiver> maybe_imports)
345 : isolate_(isolate),
346 promise_(isolate_->global_handles()->Create(*promise)),
347 maybe_imports_(maybe_imports.is_null()
348 ? maybe_imports
349 : isolate_->global_handles()->Create(
350 *maybe_imports.ToHandleChecked())) {}
351
~AsyncInstantiateCompileResultResolver()352 ~AsyncInstantiateCompileResultResolver() {
353 i::GlobalHandles::Destroy(i::Handle<i::Object>::cast(promise_).location());
354 if (!maybe_imports_.is_null()) {
355 i::GlobalHandles::Destroy(
356 i::Handle<i::Object>::cast(maybe_imports_.ToHandleChecked())
357 .location());
358 }
359 }
360
OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result)361 void OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result) override {
362 if (finished_) return;
363 finished_ = true;
364 isolate_->wasm_engine()->AsyncInstantiate(
365 isolate_,
366 base::make_unique<InstantiateBytesResultResolver>(isolate_, promise_,
367 result),
368 result, maybe_imports_);
369 }
370
OnCompilationFailed(i::Handle<i::Object> error_reason)371 void OnCompilationFailed(i::Handle<i::Object> error_reason) override {
372 if (finished_) return;
373 finished_ = true;
374 i::MaybeHandle<i::Object> promise_result =
375 i::JSPromise::Reject(promise_, error_reason);
376 CHECK_EQ(promise_result.is_null(), isolate_->has_pending_exception());
377 }
378
379 private:
380 bool finished_ = false;
381 i::Isolate* isolate_;
382 i::Handle<i::JSPromise> promise_;
383 i::MaybeHandle<i::JSReceiver> maybe_imports_;
384 };
385
386 } // namespace
387
388 // WebAssembly.compile(bytes) -> Promise
WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value> & args)389 void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
390 v8::Isolate* isolate = args.GetIsolate();
391 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
392 MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
393
394 HandleScope scope(isolate);
395 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.compile()");
396
397 if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
398 thrower.CompileError("Wasm code generation disallowed by embedder");
399 }
400
401 Local<Context> context = isolate->GetCurrentContext();
402 ASSIGN(Promise::Resolver, promise_resolver, Promise::Resolver::New(context));
403 Local<Promise> promise = promise_resolver->GetPromise();
404 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
405 return_value.Set(promise);
406
407 std::shared_ptr<i::wasm::CompilationResultResolver> resolver(
408 new AsyncCompilationResolver(i_isolate, Utils::OpenHandle(*promise)));
409
410 bool is_shared = false;
411 auto bytes = GetFirstArgumentAsBytes(args, &thrower, &is_shared);
412 if (thrower.error()) {
413 resolver->OnCompilationFailed(thrower.Reify());
414 return;
415 }
416 // Asynchronous compilation handles copying wire bytes if necessary.
417 auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
418 i_isolate->wasm_engine()->AsyncCompile(i_isolate, enabled_features,
419 std::move(resolver), bytes, is_shared);
420 }
421
422 // WebAssembly.compileStreaming(Promise<Response>) -> Promise
WebAssemblyCompileStreaming(const v8::FunctionCallbackInfo<v8::Value> & args)423 void WebAssemblyCompileStreaming(
424 const v8::FunctionCallbackInfo<v8::Value>& args) {
425 v8::Isolate* isolate = args.GetIsolate();
426 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
427 MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
428 HandleScope scope(isolate);
429 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.compile()");
430 Local<Context> context = isolate->GetCurrentContext();
431
432 // Create and assign the return value of this function.
433 ASSIGN(Promise::Resolver, result_resolver, Promise::Resolver::New(context));
434 Local<Promise> promise = result_resolver->GetPromise();
435 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
436 return_value.Set(promise);
437
438 // Prepare the CompilationResultResolver for the compilation.
439 auto resolver = std::make_shared<AsyncCompilationResolver>(
440 i_isolate, Utils::OpenHandle(*promise));
441
442 if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
443 thrower.CompileError("Wasm code generation disallowed by embedder");
444 resolver->OnCompilationFailed(thrower.Reify());
445 return;
446 }
447
448 // Allocate the streaming decoder in a Managed so we can pass it to the
449 // embedder.
450 i::Handle<i::Managed<WasmStreaming>> data =
451 i::Managed<WasmStreaming>::Allocate(
452 i_isolate, 0,
453 base::make_unique<WasmStreaming::WasmStreamingImpl>(isolate,
454 resolver));
455
456 DCHECK_NOT_NULL(i_isolate->wasm_streaming_callback());
457 ASSIGN(
458 v8::Function, compile_callback,
459 v8::Function::New(context, i_isolate->wasm_streaming_callback(),
460 Utils::ToLocal(i::Handle<i::Object>::cast(data)), 1));
461
462 // The parameter may be of type {Response} or of type {Promise<Response>}.
463 // Treat either case of parameter as Promise.resolve(parameter)
464 // as per https://www.w3.org/2001/tag/doc/promises-guide#resolve-arguments
465
466 // Ending with:
467 // return Promise.resolve(parameter).then(compile_callback);
468 ASSIGN(Promise::Resolver, input_resolver, Promise::Resolver::New(context));
469 if (!input_resolver->Resolve(context, args[0]).IsJust()) return;
470
471 // We do not have any use of the result here. The {compile_callback} will
472 // start streaming compilation, which will eventually resolve the promise we
473 // set as result value.
474 USE(input_resolver->GetPromise()->Then(context, compile_callback));
475 }
476
477 // WebAssembly.validate(bytes) -> bool
WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value> & args)478 void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
479 v8::Isolate* isolate = args.GetIsolate();
480 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
481 HandleScope scope(isolate);
482 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.validate()");
483
484 bool is_shared = false;
485 auto bytes = GetFirstArgumentAsBytes(args, &thrower, &is_shared);
486
487 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
488
489 if (thrower.error()) {
490 if (thrower.wasm_error()) thrower.Reset(); // Clear error.
491 return_value.Set(v8::False(isolate));
492 return;
493 }
494
495 auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
496 bool validated = false;
497 if (is_shared) {
498 // Make a copy of the wire bytes to avoid concurrent modification.
499 std::unique_ptr<uint8_t[]> copy(new uint8_t[bytes.length()]);
500 memcpy(copy.get(), bytes.start(), bytes.length());
501 i::wasm::ModuleWireBytes bytes_copy(copy.get(),
502 copy.get() + bytes.length());
503 validated = i_isolate->wasm_engine()->SyncValidate(
504 i_isolate, enabled_features, bytes_copy);
505 } else {
506 // The wire bytes are not shared, OK to use them directly.
507 validated = i_isolate->wasm_engine()->SyncValidate(i_isolate,
508 enabled_features, bytes);
509 }
510
511 return_value.Set(Boolean::New(isolate, validated));
512 }
513
514 // new WebAssembly.Module(bytes) -> WebAssembly.Module
WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value> & args)515 void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
516 v8::Isolate* isolate = args.GetIsolate();
517 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
518 if (i_isolate->wasm_module_callback()(args)) return;
519
520 HandleScope scope(isolate);
521 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module()");
522
523 if (!args.IsConstructCall()) {
524 thrower.TypeError("WebAssembly.Module must be invoked with 'new'");
525 return;
526 }
527 if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
528 thrower.CompileError("Wasm code generation disallowed by embedder");
529 return;
530 }
531
532 bool is_shared = false;
533 auto bytes = GetFirstArgumentAsBytes(args, &thrower, &is_shared);
534
535 if (thrower.error()) {
536 return;
537 }
538 auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
539 i::MaybeHandle<i::Object> module_obj;
540 if (is_shared) {
541 // Make a copy of the wire bytes to avoid concurrent modification.
542 std::unique_ptr<uint8_t[]> copy(new uint8_t[bytes.length()]);
543 memcpy(copy.get(), bytes.start(), bytes.length());
544 i::wasm::ModuleWireBytes bytes_copy(copy.get(),
545 copy.get() + bytes.length());
546 module_obj = i_isolate->wasm_engine()->SyncCompile(
547 i_isolate, enabled_features, &thrower, bytes_copy);
548 } else {
549 // The wire bytes are not shared, OK to use them directly.
550 module_obj = i_isolate->wasm_engine()->SyncCompile(
551 i_isolate, enabled_features, &thrower, bytes);
552 }
553
554 if (module_obj.is_null()) return;
555
556 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
557 return_value.Set(Utils::ToLocal(module_obj.ToHandleChecked()));
558 }
559
560 // WebAssembly.Module.imports(module) -> Array<Import>
WebAssemblyModuleImports(const v8::FunctionCallbackInfo<v8::Value> & args)561 void WebAssemblyModuleImports(const v8::FunctionCallbackInfo<v8::Value>& args) {
562 HandleScope scope(args.GetIsolate());
563 v8::Isolate* isolate = args.GetIsolate();
564 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
565 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module.imports()");
566
567 auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
568 if (thrower.error()) return;
569 auto imports = i::wasm::GetImports(i_isolate, maybe_module.ToHandleChecked());
570 args.GetReturnValue().Set(Utils::ToLocal(imports));
571 }
572
573 // WebAssembly.Module.exports(module) -> Array<Export>
WebAssemblyModuleExports(const v8::FunctionCallbackInfo<v8::Value> & args)574 void WebAssemblyModuleExports(const v8::FunctionCallbackInfo<v8::Value>& args) {
575 HandleScope scope(args.GetIsolate());
576 v8::Isolate* isolate = args.GetIsolate();
577 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
578 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module.exports()");
579
580 auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
581 if (thrower.error()) return;
582 auto exports = i::wasm::GetExports(i_isolate, maybe_module.ToHandleChecked());
583 args.GetReturnValue().Set(Utils::ToLocal(exports));
584 }
585
586 // WebAssembly.Module.customSections(module, name) -> Array<Section>
WebAssemblyModuleCustomSections(const v8::FunctionCallbackInfo<v8::Value> & args)587 void WebAssemblyModuleCustomSections(
588 const v8::FunctionCallbackInfo<v8::Value>& args) {
589 HandleScope scope(args.GetIsolate());
590 v8::Isolate* isolate = args.GetIsolate();
591 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
592 ScheduledErrorThrower thrower(i_isolate,
593 "WebAssembly.Module.customSections()");
594
595 auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
596 if (thrower.error()) return;
597
598 i::MaybeHandle<i::Object> maybe_name =
599 i::Object::ToString(i_isolate, Utils::OpenHandle(*args[1]));
600 i::Handle<i::Object> name;
601 if (!maybe_name.ToHandle(&name)) return;
602 auto custom_sections =
603 i::wasm::GetCustomSections(i_isolate, maybe_module.ToHandleChecked(),
604 i::Handle<i::String>::cast(name), &thrower);
605 if (thrower.error()) return;
606 args.GetReturnValue().Set(Utils::ToLocal(custom_sections));
607 }
608
WebAssemblyInstantiateImpl(Isolate * isolate,Local<Value> module,Local<Value> ffi)609 MaybeLocal<Value> WebAssemblyInstantiateImpl(Isolate* isolate,
610 Local<Value> module,
611 Local<Value> ffi) {
612 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
613
614 i::MaybeHandle<i::Object> instance_object;
615 {
616 ScheduledErrorThrower thrower(i_isolate, "WebAssembly Instantiation");
617
618 // TODO(ahaas): These checks on the module should not be necessary here They
619 // are just a workaround for https://crbug.com/837417.
620 i::Handle<i::Object> module_obj = Utils::OpenHandle(*module);
621 if (!module_obj->IsWasmModuleObject()) {
622 thrower.TypeError("Argument 0 must be a WebAssembly.Module object");
623 return {};
624 }
625
626 i::MaybeHandle<i::JSReceiver> maybe_imports =
627 GetValueAsImports(ffi, &thrower);
628 if (thrower.error()) return {};
629
630 instance_object = i_isolate->wasm_engine()->SyncInstantiate(
631 i_isolate, &thrower, i::Handle<i::WasmModuleObject>::cast(module_obj),
632 maybe_imports, i::MaybeHandle<i::JSArrayBuffer>());
633 }
634
635 DCHECK_EQ(instance_object.is_null(), i_isolate->has_scheduled_exception());
636 if (instance_object.is_null()) return {};
637 return Utils::ToLocal(instance_object.ToHandleChecked());
638 }
639
640 // new WebAssembly.Instance(module, imports) -> WebAssembly.Instance
WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value> & args)641 void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
642 Isolate* isolate = args.GetIsolate();
643 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
644 i_isolate->CountUsage(
645 v8::Isolate::UseCounterFeature::kWebAssemblyInstantiation);
646 MicrotasksScope does_not_run_microtasks(isolate,
647 MicrotasksScope::kDoNotRunMicrotasks);
648
649 HandleScope scope(args.GetIsolate());
650 if (i_isolate->wasm_instance_callback()(args)) return;
651
652 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Instance()");
653 if (!args.IsConstructCall()) {
654 thrower.TypeError("WebAssembly.Instance must be invoked with 'new'");
655 return;
656 }
657
658 GetFirstArgumentAsModule(args, &thrower);
659 if (thrower.error()) return;
660
661 // If args.Length < 2, this will be undefined - see FunctionCallbackInfo.
662 // We'll check for that in WebAssemblyInstantiateImpl.
663 Local<Value> data = args[1];
664
665 Local<Value> instance;
666 if (WebAssemblyInstantiateImpl(isolate, args[0], data).ToLocal(&instance)) {
667 args.GetReturnValue().Set(instance);
668 }
669 }
670
WebAssemblyInstantiateStreaming(const v8::FunctionCallbackInfo<v8::Value> & args)671 void WebAssemblyInstantiateStreaming(
672 const v8::FunctionCallbackInfo<v8::Value>& args) {
673 v8::Isolate* isolate = args.GetIsolate();
674 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
675 i_isolate->CountUsage(
676 v8::Isolate::UseCounterFeature::kWebAssemblyInstantiation);
677
678 MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
679 HandleScope scope(isolate);
680 Local<Context> context = isolate->GetCurrentContext();
681 ScheduledErrorThrower thrower(i_isolate,
682 "WebAssembly.instantiateStreaming()");
683
684 // Create and assign the return value of this function.
685 ASSIGN(Promise::Resolver, result_resolver, Promise::Resolver::New(context));
686 Local<Promise> promise = result_resolver->GetPromise();
687 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
688 return_value.Set(promise);
689
690 // Create an InstantiateResultResolver in case there is an issue with the
691 // passed parameters.
692 std::unique_ptr<i::wasm::InstantiationResultResolver> resolver(
693 new InstantiateModuleResultResolver(i_isolate,
694 Utils::OpenHandle(*promise)));
695
696 if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
697 thrower.CompileError("Wasm code generation disallowed by embedder");
698 resolver->OnInstantiationFailed(thrower.Reify());
699 return;
700 }
701
702 // If args.Length < 2, this will be undefined - see FunctionCallbackInfo.
703 Local<Value> ffi = args[1];
704 i::MaybeHandle<i::JSReceiver> maybe_imports =
705 GetValueAsImports(ffi, &thrower);
706
707 if (thrower.error()) {
708 resolver->OnInstantiationFailed(thrower.Reify());
709 return;
710 }
711
712 // We start compilation now, we have no use for the
713 // {InstantiationResultResolver}.
714 resolver.reset();
715
716 std::shared_ptr<i::wasm::CompilationResultResolver> compilation_resolver(
717 new AsyncInstantiateCompileResultResolver(
718 i_isolate, Utils::OpenHandle(*promise), maybe_imports));
719
720 // Allocate the streaming decoder in a Managed so we can pass it to the
721 // embedder.
722 i::Handle<i::Managed<WasmStreaming>> data =
723 i::Managed<WasmStreaming>::Allocate(
724 i_isolate, 0,
725 base::make_unique<WasmStreaming::WasmStreamingImpl>(
726 isolate, compilation_resolver));
727
728 DCHECK_NOT_NULL(i_isolate->wasm_streaming_callback());
729 ASSIGN(
730 v8::Function, compile_callback,
731 v8::Function::New(context, i_isolate->wasm_streaming_callback(),
732 Utils::ToLocal(i::Handle<i::Object>::cast(data)), 1));
733
734 // The parameter may be of type {Response} or of type {Promise<Response>}.
735 // Treat either case of parameter as Promise.resolve(parameter)
736 // as per https://www.w3.org/2001/tag/doc/promises-guide#resolve-arguments
737
738 // Ending with:
739 // return Promise.resolve(parameter).then(compile_callback);
740 ASSIGN(Promise::Resolver, input_resolver, Promise::Resolver::New(context));
741 if (!input_resolver->Resolve(context, args[0]).IsJust()) return;
742
743 // We do not have any use of the result here. The {compile_callback} will
744 // start streaming compilation, which will eventually resolve the promise we
745 // set as result value.
746 USE(input_resolver->GetPromise()->Then(context, compile_callback));
747 }
748
749 // WebAssembly.instantiate(module, imports) -> WebAssembly.Instance
750 // WebAssembly.instantiate(bytes, imports) ->
751 // {module: WebAssembly.Module, instance: WebAssembly.Instance}
WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value> & args)752 void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
753 v8::Isolate* isolate = args.GetIsolate();
754 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
755 i_isolate->CountUsage(
756 v8::Isolate::UseCounterFeature::kWebAssemblyInstantiation);
757 MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
758
759 ScheduledErrorThrower thrower(i_isolate, "WebAssembly Instantiation");
760
761 HandleScope scope(isolate);
762
763 Local<Context> context = isolate->GetCurrentContext();
764
765 ASSIGN(Promise::Resolver, promise_resolver, Promise::Resolver::New(context));
766 Local<Promise> promise = promise_resolver->GetPromise();
767 args.GetReturnValue().Set(promise);
768
769 std::unique_ptr<i::wasm::InstantiationResultResolver> resolver(
770 new InstantiateModuleResultResolver(i_isolate,
771 Utils::OpenHandle(*promise)));
772
773 Local<Value> first_arg_value = args[0];
774 i::Handle<i::Object> first_arg = Utils::OpenHandle(*first_arg_value);
775 if (!first_arg->IsJSObject()) {
776 thrower.TypeError(
777 "Argument 0 must be a buffer source or a WebAssembly.Module object");
778 resolver->OnInstantiationFailed(thrower.Reify());
779 return;
780 }
781
782 // If args.Length < 2, this will be undefined - see FunctionCallbackInfo.
783 Local<Value> ffi = args[1];
784 i::MaybeHandle<i::JSReceiver> maybe_imports =
785 GetValueAsImports(ffi, &thrower);
786
787 if (thrower.error()) {
788 resolver->OnInstantiationFailed(thrower.Reify());
789 return;
790 }
791
792 if (first_arg->IsWasmModuleObject()) {
793 i::Handle<i::WasmModuleObject> module_obj =
794 i::Handle<i::WasmModuleObject>::cast(first_arg);
795
796 i_isolate->wasm_engine()->AsyncInstantiate(i_isolate, std::move(resolver),
797 module_obj, maybe_imports);
798 return;
799 }
800
801 bool is_shared = false;
802 auto bytes = GetFirstArgumentAsBytes(args, &thrower, &is_shared);
803 if (thrower.error()) {
804 resolver->OnInstantiationFailed(thrower.Reify());
805 return;
806 }
807
808 // We start compilation now, we have no use for the
809 // {InstantiationResultResolver}.
810 resolver.reset();
811
812 std::shared_ptr<i::wasm::CompilationResultResolver> compilation_resolver(
813 new AsyncInstantiateCompileResultResolver(
814 i_isolate, Utils::OpenHandle(*promise), maybe_imports));
815
816 // The first parameter is a buffer source, we have to check if we are allowed
817 // to compile it.
818 if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
819 thrower.CompileError("Wasm code generation disallowed by embedder");
820 compilation_resolver->OnCompilationFailed(thrower.Reify());
821 return;
822 }
823
824 // Asynchronous compilation handles copying wire bytes if necessary.
825 auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
826 i_isolate->wasm_engine()->AsyncCompile(i_isolate, enabled_features,
827 std::move(compilation_resolver), bytes,
828 is_shared);
829 }
830
GetIntegerProperty(v8::Isolate * isolate,ErrorThrower * thrower,Local<Context> context,Local<v8::Object> object,Local<String> property,int64_t * result,int64_t lower_bound,uint64_t upper_bound)831 bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
832 Local<Context> context, Local<v8::Object> object,
833 Local<String> property, int64_t* result,
834 int64_t lower_bound, uint64_t upper_bound) {
835 v8::MaybeLocal<v8::Value> maybe = object->Get(context, property);
836 v8::Local<v8::Value> value;
837 if (maybe.ToLocal(&value)) {
838 int64_t number;
839 if (!value->IntegerValue(context).To(&number)) return false;
840 if (number < lower_bound) {
841 thrower->RangeError("Property value %" PRId64
842 " is below the lower bound %" PRIx64,
843 number, lower_bound);
844 return false;
845 }
846 if (number > static_cast<int64_t>(upper_bound)) {
847 thrower->RangeError("Property value %" PRId64
848 " is above the upper bound %" PRIu64,
849 number, upper_bound);
850 return false;
851 }
852 *result = static_cast<int>(number);
853 return true;
854 }
855 return false;
856 }
857
858 // new WebAssembly.Table(args) -> WebAssembly.Table
WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value> & args)859 void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
860 v8::Isolate* isolate = args.GetIsolate();
861 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
862 HandleScope scope(isolate);
863 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module()");
864 if (!args.IsConstructCall()) {
865 thrower.TypeError("WebAssembly.Table must be invoked with 'new'");
866 return;
867 }
868 if (!args[0]->IsObject()) {
869 thrower.TypeError("Argument 0 must be a table descriptor");
870 return;
871 }
872 Local<Context> context = isolate->GetCurrentContext();
873 Local<v8::Object> descriptor = Local<Object>::Cast(args[0]);
874 // The descriptor's 'element'.
875 {
876 v8::MaybeLocal<v8::Value> maybe =
877 descriptor->Get(context, v8_str(isolate, "element"));
878 v8::Local<v8::Value> value;
879 if (!maybe.ToLocal(&value)) return;
880 v8::Local<v8::String> string;
881 if (!value->ToString(context).ToLocal(&string)) return;
882 if (!string->StringEquals(v8_str(isolate, "anyfunc"))) {
883 thrower.TypeError("Descriptor property 'element' must be 'anyfunc'");
884 return;
885 }
886 }
887 // The descriptor's 'initial'.
888 int64_t initial = 0;
889 if (!GetIntegerProperty(isolate, &thrower, context, descriptor,
890 v8_str(isolate, "initial"), &initial, 0,
891 i::FLAG_wasm_max_table_size)) {
892 return;
893 }
894 // The descriptor's 'maximum'.
895 int64_t maximum = -1;
896 Local<String> maximum_key = v8_str(isolate, "maximum");
897 Maybe<bool> has_maximum = descriptor->Has(context, maximum_key);
898
899 if (!has_maximum.IsNothing() && has_maximum.FromJust()) {
900 if (!GetIntegerProperty(isolate, &thrower, context, descriptor, maximum_key,
901 &maximum, initial,
902 i::wasm::kSpecMaxWasmTableSize)) {
903 return;
904 }
905 }
906
907 i::Handle<i::FixedArray> fixed_array;
908 i::Handle<i::JSObject> table_obj = i::WasmTableObject::New(
909 i_isolate, static_cast<uint32_t>(initial), maximum, &fixed_array);
910 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
911 return_value.Set(Utils::ToLocal(table_obj));
912 }
913
WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value> & args)914 void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
915 v8::Isolate* isolate = args.GetIsolate();
916 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
917 HandleScope scope(isolate);
918 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory()");
919 if (!args.IsConstructCall()) {
920 thrower.TypeError("WebAssembly.Memory must be invoked with 'new'");
921 return;
922 }
923 if (!args[0]->IsObject()) {
924 thrower.TypeError("Argument 0 must be a memory descriptor");
925 return;
926 }
927 Local<Context> context = isolate->GetCurrentContext();
928 Local<v8::Object> descriptor = Local<Object>::Cast(args[0]);
929 // The descriptor's 'initial'.
930 int64_t initial = 0;
931 if (!GetIntegerProperty(isolate, &thrower, context, descriptor,
932 v8_str(isolate, "initial"), &initial, 0,
933 i::FLAG_wasm_max_mem_pages)) {
934 return;
935 }
936 // The descriptor's 'maximum'.
937 int64_t maximum = -1;
938 Local<String> maximum_key = v8_str(isolate, "maximum");
939 Maybe<bool> has_maximum = descriptor->Has(context, maximum_key);
940
941 if (!has_maximum.IsNothing() && has_maximum.FromJust()) {
942 if (!GetIntegerProperty(isolate, &thrower, context, descriptor, maximum_key,
943 &maximum, initial,
944 i::wasm::kSpecMaxWasmMemoryPages)) {
945 return;
946 }
947 }
948
949 bool is_shared_memory = false;
950 auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
951 if (enabled_features.threads) {
952 // Shared property of descriptor
953 Local<String> shared_key = v8_str(isolate, "shared");
954 Maybe<bool> has_shared = descriptor->Has(context, shared_key);
955 if (!has_shared.IsNothing() && has_shared.FromJust()) {
956 v8::MaybeLocal<v8::Value> maybe = descriptor->Get(context, shared_key);
957 v8::Local<v8::Value> value;
958 if (maybe.ToLocal(&value)) {
959 if (!value->BooleanValue(context).To(&is_shared_memory)) return;
960 }
961 }
962 // Throw TypeError if shared is true, and the descriptor has no "maximum"
963 if (is_shared_memory && maximum == -1) {
964 thrower.TypeError(
965 "If shared is true, maximum property should be defined.");
966 }
967 }
968
969 i::SharedFlag shared_flag =
970 is_shared_memory ? i::SharedFlag::kShared : i::SharedFlag::kNotShared;
971 i::Handle<i::JSArrayBuffer> buffer;
972 size_t size = static_cast<size_t>(i::wasm::kWasmPageSize) *
973 static_cast<size_t>(initial);
974 if (!i::wasm::NewArrayBuffer(i_isolate, size, shared_flag)
975 .ToHandle(&buffer)) {
976 thrower.RangeError("could not allocate memory");
977 return;
978 }
979 if (buffer->is_shared()) {
980 Maybe<bool> result =
981 buffer->SetIntegrityLevel(buffer, i::FROZEN, i::kDontThrow);
982 if (!result.FromJust()) {
983 thrower.TypeError(
984 "Status of setting SetIntegrityLevel of buffer is false.");
985 }
986 }
987 i::Handle<i::JSObject> memory_obj = i::WasmMemoryObject::New(
988 i_isolate, buffer, static_cast<int32_t>(maximum));
989 args.GetReturnValue().Set(Utils::ToLocal(memory_obj));
990 }
991
WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value> & args)992 void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
993 v8::Isolate* isolate = args.GetIsolate();
994 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
995 HandleScope scope(isolate);
996 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Global()");
997 if (!args.IsConstructCall()) {
998 thrower.TypeError("WebAssembly.Global must be invoked with 'new'");
999 return;
1000 }
1001 if (!args[0]->IsObject()) {
1002 thrower.TypeError("Argument 0 must be a global descriptor");
1003 return;
1004 }
1005 Local<Context> context = isolate->GetCurrentContext();
1006 Local<v8::Object> descriptor = Local<Object>::Cast(args[0]);
1007
1008 // The descriptor's 'mutable'.
1009 bool is_mutable = false;
1010 {
1011 Local<String> mutable_key = v8_str(isolate, "mutable");
1012 v8::MaybeLocal<v8::Value> maybe = descriptor->Get(context, mutable_key);
1013 v8::Local<v8::Value> value;
1014 if (maybe.ToLocal(&value)) {
1015 if (!value->BooleanValue(context).To(&is_mutable)) return;
1016 }
1017 }
1018
1019 // The descriptor's type, called 'value'. It is called 'value' because this
1020 // descriptor is planned to be re-used as the global's type for reflection,
1021 // so calling it 'type' is redundant.
1022 i::wasm::ValueType type;
1023 {
1024 v8::MaybeLocal<v8::Value> maybe =
1025 descriptor->Get(context, v8_str(isolate, "value"));
1026 v8::Local<v8::Value> value;
1027 if (!maybe.ToLocal(&value)) return;
1028 v8::Local<v8::String> string;
1029 if (!value->ToString(context).ToLocal(&string)) return;
1030
1031 if (string->StringEquals(v8_str(isolate, "i32"))) {
1032 type = i::wasm::kWasmI32;
1033 } else if (string->StringEquals(v8_str(isolate, "f32"))) {
1034 type = i::wasm::kWasmF32;
1035 } else if (string->StringEquals(v8_str(isolate, "f64"))) {
1036 type = i::wasm::kWasmF64;
1037 } else {
1038 thrower.TypeError(
1039 "Descriptor property 'value' must be 'i32', 'f32', or 'f64'");
1040 return;
1041 }
1042 }
1043
1044 const uint32_t offset = 0;
1045 i::MaybeHandle<i::WasmGlobalObject> maybe_global_obj =
1046 i::WasmGlobalObject::New(i_isolate, i::MaybeHandle<i::JSArrayBuffer>(),
1047 type, offset, is_mutable);
1048
1049 i::Handle<i::WasmGlobalObject> global_obj;
1050 if (!maybe_global_obj.ToHandle(&global_obj)) {
1051 thrower.RangeError("could not allocate memory");
1052 return;
1053 }
1054
1055 // Convert value to a WebAssembly value, the default value is 0.
1056 Local<v8::Value> value = Local<Value>::Cast(args[1]);
1057 switch (type) {
1058 case i::wasm::kWasmI32: {
1059 int32_t i32_value = 0;
1060 if (!value->IsUndefined()) {
1061 v8::Local<v8::Int32> int32_value;
1062 if (!value->ToInt32(context).ToLocal(&int32_value)) return;
1063 if (!int32_value->Int32Value(context).To(&i32_value)) return;
1064 }
1065 global_obj->SetI32(i32_value);
1066 break;
1067 }
1068 case i::wasm::kWasmF32: {
1069 float f32_value = 0;
1070 if (!value->IsUndefined()) {
1071 double f64_value = 0;
1072 v8::Local<v8::Number> number_value;
1073 if (!value->ToNumber(context).ToLocal(&number_value)) return;
1074 if (!number_value->NumberValue(context).To(&f64_value)) return;
1075 f32_value = static_cast<float>(f64_value);
1076 }
1077 global_obj->SetF32(f32_value);
1078 break;
1079 }
1080 case i::wasm::kWasmF64: {
1081 double f64_value = 0;
1082 if (!value->IsUndefined()) {
1083 v8::Local<v8::Number> number_value;
1084 if (!value->ToNumber(context).ToLocal(&number_value)) return;
1085 if (!number_value->NumberValue(context).To(&f64_value)) return;
1086 }
1087 global_obj->SetF64(f64_value);
1088 break;
1089 }
1090 default:
1091 UNREACHABLE();
1092 }
1093
1094 i::Handle<i::JSObject> global_js_object(global_obj);
1095 args.GetReturnValue().Set(Utils::ToLocal(global_js_object));
1096 }
1097
1098 constexpr const char* kName_WasmGlobalObject = "WebAssembly.Global";
1099 constexpr const char* kName_WasmMemoryObject = "WebAssembly.Memory";
1100 constexpr const char* kName_WasmInstanceObject = "WebAssembly.Instance";
1101 constexpr const char* kName_WasmTableObject = "WebAssembly.Table";
1102
1103 #define EXTRACT_THIS(var, WasmType) \
1104 i::Handle<i::WasmType> var; \
1105 { \
1106 i::Handle<i::Object> this_arg = Utils::OpenHandle(*args.This()); \
1107 if (!this_arg->Is##WasmType()) { \
1108 thrower.TypeError("Receiver is not a %s", kName_##WasmType); \
1109 return; \
1110 } \
1111 var = i::Handle<i::WasmType>::cast(this_arg); \
1112 }
1113
WebAssemblyInstanceGetExports(const v8::FunctionCallbackInfo<v8::Value> & args)1114 void WebAssemblyInstanceGetExports(
1115 const v8::FunctionCallbackInfo<v8::Value>& args) {
1116 v8::Isolate* isolate = args.GetIsolate();
1117 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1118 HandleScope scope(isolate);
1119 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Instance.exports()");
1120 EXTRACT_THIS(receiver, WasmInstanceObject);
1121 i::Handle<i::JSObject> exports_object(receiver->exports_object(), i_isolate);
1122 args.GetReturnValue().Set(Utils::ToLocal(exports_object));
1123 }
1124
WebAssemblyTableGetLength(const v8::FunctionCallbackInfo<v8::Value> & args)1125 void WebAssemblyTableGetLength(
1126 const v8::FunctionCallbackInfo<v8::Value>& args) {
1127 v8::Isolate* isolate = args.GetIsolate();
1128 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1129 HandleScope scope(isolate);
1130 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.length()");
1131 EXTRACT_THIS(receiver, WasmTableObject);
1132 args.GetReturnValue().Set(
1133 v8::Number::New(isolate, receiver->current_length()));
1134 }
1135
1136 // WebAssembly.Table.grow(num) -> num
WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value> & args)1137 void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
1138 v8::Isolate* isolate = args.GetIsolate();
1139 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1140 HandleScope scope(isolate);
1141 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.grow()");
1142 Local<Context> context = isolate->GetCurrentContext();
1143 EXTRACT_THIS(receiver, WasmTableObject);
1144
1145 int64_t grow_by = 0;
1146 if (!args[0]->IntegerValue(context).To(&grow_by)) return;
1147 i::Handle<i::FixedArray> old_array(receiver->functions(), i_isolate);
1148 int old_size = old_array->length();
1149
1150 int64_t max_size64 = receiver->maximum_length()->Number();
1151 if (max_size64 < 0 || max_size64 > i::FLAG_wasm_max_table_size) {
1152 max_size64 = i::FLAG_wasm_max_table_size;
1153 }
1154
1155 if (grow_by < 0 || grow_by > max_size64 - old_size) {
1156 thrower.RangeError(grow_by < 0 ? "trying to shrink table"
1157 : "maximum table size exceeded");
1158 return;
1159 }
1160
1161 int new_size = static_cast<int>(old_size + grow_by);
1162 receiver->Grow(i_isolate, static_cast<uint32_t>(new_size - old_size));
1163
1164 if (new_size != old_size) {
1165 i::Handle<i::FixedArray> new_array =
1166 i_isolate->factory()->NewFixedArray(new_size);
1167 for (int i = 0; i < old_size; ++i) new_array->set(i, old_array->get(i));
1168 i::Object* null = i::ReadOnlyRoots(i_isolate).null_value();
1169 for (int i = old_size; i < new_size; ++i) new_array->set(i, null);
1170 receiver->set_functions(*new_array);
1171 }
1172
1173 // TODO(gdeepti): use weak links for instances
1174 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
1175 return_value.Set(old_size);
1176 }
1177
1178 // WebAssembly.Table.get(num) -> JSFunction
WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value> & args)1179 void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) {
1180 v8::Isolate* isolate = args.GetIsolate();
1181 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1182 HandleScope scope(isolate);
1183 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.get()");
1184 Local<Context> context = isolate->GetCurrentContext();
1185 EXTRACT_THIS(receiver, WasmTableObject);
1186 i::Handle<i::FixedArray> array(receiver->functions(), i_isolate);
1187 int64_t i = 0;
1188 if (!args[0]->IntegerValue(context).To(&i)) return;
1189 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
1190 if (i < 0 || i >= array->length()) {
1191 thrower.RangeError("index out of bounds");
1192 return;
1193 }
1194
1195 i::Handle<i::Object> value(array->get(static_cast<int>(i)), i_isolate);
1196 return_value.Set(Utils::ToLocal(value));
1197 }
1198
1199 // WebAssembly.Table.set(num, JSFunction)
WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value> & args)1200 void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
1201 v8::Isolate* isolate = args.GetIsolate();
1202 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1203 HandleScope scope(isolate);
1204 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.set()");
1205 Local<Context> context = isolate->GetCurrentContext();
1206 EXTRACT_THIS(receiver, WasmTableObject);
1207
1208 // Parameter 0.
1209 int64_t index;
1210 if (!args[0]->IntegerValue(context).To(&index)) return;
1211
1212 // Parameter 1.
1213 i::Handle<i::Object> value = Utils::OpenHandle(*args[1]);
1214 if (!value->IsNull(i_isolate) &&
1215 !i::WasmExportedFunction::IsWasmExportedFunction(*value)) {
1216 thrower.TypeError("Argument 1 must be null or a WebAssembly function");
1217 return;
1218 }
1219
1220 if (index < 0 || index >= receiver->functions()->length()) {
1221 thrower.RangeError("index out of bounds");
1222 return;
1223 }
1224
1225 i::WasmTableObject::Set(i_isolate, receiver, static_cast<int32_t>(index),
1226 value->IsNull(i_isolate)
1227 ? i::Handle<i::JSFunction>::null()
1228 : i::Handle<i::JSFunction>::cast(value));
1229 }
1230
1231 // WebAssembly.Memory.grow(num) -> num
WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value> & args)1232 void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
1233 v8::Isolate* isolate = args.GetIsolate();
1234 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1235 HandleScope scope(isolate);
1236 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory.grow()");
1237 Local<Context> context = isolate->GetCurrentContext();
1238 EXTRACT_THIS(receiver, WasmMemoryObject);
1239
1240 int64_t delta_size = 0;
1241 if (!args[0]->IntegerValue(context).To(&delta_size)) return;
1242
1243 int64_t max_size64 = receiver->maximum_pages();
1244 if (max_size64 < 0 ||
1245 max_size64 > static_cast<int64_t>(i::FLAG_wasm_max_mem_pages)) {
1246 max_size64 = i::FLAG_wasm_max_mem_pages;
1247 }
1248 i::Handle<i::JSArrayBuffer> old_buffer(receiver->array_buffer(), i_isolate);
1249 if (!old_buffer->is_growable()) {
1250 thrower.RangeError("This memory cannot be grown");
1251 return;
1252 }
1253 uint32_t old_size =
1254 old_buffer->byte_length()->Number() / i::wasm::kWasmPageSize;
1255 int64_t new_size64 = old_size + delta_size;
1256 if (delta_size < 0 || max_size64 < new_size64 || new_size64 < old_size) {
1257 thrower.RangeError(new_size64 < old_size ? "trying to shrink memory"
1258 : "maximum memory size exceeded");
1259 return;
1260 }
1261 int32_t ret = i::WasmMemoryObject::Grow(i_isolate, receiver,
1262 static_cast<uint32_t>(delta_size));
1263 if (ret == -1) {
1264 thrower.RangeError("Unable to grow instance memory.");
1265 return;
1266 }
1267 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
1268 return_value.Set(ret);
1269 }
1270
1271 // WebAssembly.Memory.buffer -> ArrayBuffer
WebAssemblyMemoryGetBuffer(const v8::FunctionCallbackInfo<v8::Value> & args)1272 void WebAssemblyMemoryGetBuffer(
1273 const v8::FunctionCallbackInfo<v8::Value>& args) {
1274 v8::Isolate* isolate = args.GetIsolate();
1275 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1276 HandleScope scope(isolate);
1277 ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory.buffer");
1278 EXTRACT_THIS(receiver, WasmMemoryObject);
1279
1280 i::Handle<i::Object> buffer_obj(receiver->array_buffer(), i_isolate);
1281 DCHECK(buffer_obj->IsJSArrayBuffer());
1282 i::Handle<i::JSArrayBuffer> buffer(i::JSArrayBuffer::cast(*buffer_obj),
1283 i_isolate);
1284 if (buffer->is_shared()) {
1285 // TODO(gdeepti): More needed here for when cached buffer, and current
1286 // buffer are out of sync, handle that here when bounds checks, and Grow
1287 // are handled correctly.
1288 Maybe<bool> result =
1289 buffer->SetIntegrityLevel(buffer, i::FROZEN, i::kDontThrow);
1290 if (!result.FromJust()) {
1291 thrower.TypeError(
1292 "Status of setting SetIntegrityLevel of buffer is false.");
1293 }
1294 }
1295 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
1296 return_value.Set(Utils::ToLocal(buffer));
1297 }
1298
WebAssemblyGlobalGetValueCommon(const v8::FunctionCallbackInfo<v8::Value> & args,const char * name)1299 void WebAssemblyGlobalGetValueCommon(
1300 const v8::FunctionCallbackInfo<v8::Value>& args, const char* name) {
1301 v8::Isolate* isolate = args.GetIsolate();
1302 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1303 HandleScope scope(isolate);
1304 ScheduledErrorThrower thrower(i_isolate, name);
1305 EXTRACT_THIS(receiver, WasmGlobalObject);
1306
1307 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
1308
1309 switch (receiver->type()) {
1310 case i::wasm::kWasmI32:
1311 return_value.Set(receiver->GetI32());
1312 break;
1313 case i::wasm::kWasmI64:
1314 thrower.TypeError("Can't get the value of i64 WebAssembly.Global");
1315 break;
1316 case i::wasm::kWasmF32:
1317 return_value.Set(receiver->GetF32());
1318 break;
1319 case i::wasm::kWasmF64:
1320 return_value.Set(receiver->GetF64());
1321 break;
1322 default:
1323 UNREACHABLE();
1324 }
1325 }
1326
1327 // WebAssembly.Global.valueOf() -> num
WebAssemblyGlobalValueOf(const v8::FunctionCallbackInfo<v8::Value> & args)1328 void WebAssemblyGlobalValueOf(const v8::FunctionCallbackInfo<v8::Value>& args) {
1329 return WebAssemblyGlobalGetValueCommon(args, "WebAssembly.Global.valueOf()");
1330 }
1331
1332 // get WebAssembly.Global.value -> num
WebAssemblyGlobalGetValue(const v8::FunctionCallbackInfo<v8::Value> & args)1333 void WebAssemblyGlobalGetValue(
1334 const v8::FunctionCallbackInfo<v8::Value>& args) {
1335 return WebAssemblyGlobalGetValueCommon(args, "get WebAssembly.Global.value");
1336 }
1337
1338 // set WebAssembly.Global.value(num)
WebAssemblyGlobalSetValue(const v8::FunctionCallbackInfo<v8::Value> & args)1339 void WebAssemblyGlobalSetValue(
1340 const v8::FunctionCallbackInfo<v8::Value>& args) {
1341 v8::Isolate* isolate = args.GetIsolate();
1342 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1343 HandleScope scope(isolate);
1344 Local<Context> context = isolate->GetCurrentContext();
1345 ScheduledErrorThrower thrower(i_isolate, "set WebAssembly.Global.value");
1346 EXTRACT_THIS(receiver, WasmGlobalObject);
1347
1348 if (!receiver->is_mutable()) {
1349 thrower.TypeError("Can't set the value of an immutable global.");
1350 return;
1351 }
1352
1353 switch (receiver->type()) {
1354 case i::wasm::kWasmI32: {
1355 int32_t i32_value = 0;
1356 if (!args[0]->Int32Value(context).To(&i32_value)) return;
1357 receiver->SetI32(i32_value);
1358 break;
1359 }
1360 case i::wasm::kWasmI64:
1361 thrower.TypeError("Can't set the value of i64 WebAssembly.Global");
1362 break;
1363 case i::wasm::kWasmF32: {
1364 double f64_value = 0;
1365 if (!args[0]->NumberValue(context).To(&f64_value)) return;
1366 receiver->SetF32(static_cast<float>(f64_value));
1367 break;
1368 }
1369 case i::wasm::kWasmF64: {
1370 double f64_value = 0;
1371 if (!args[0]->NumberValue(context).To(&f64_value)) return;
1372 receiver->SetF64(f64_value);
1373 break;
1374 }
1375 default:
1376 UNREACHABLE();
1377 }
1378 }
1379
1380 } // namespace
1381
1382 // TODO(titzer): we use the API to create the function template because the
1383 // internal guts are too ugly to replicate here.
NewFunctionTemplate(i::Isolate * i_isolate,FunctionCallback func)1384 static i::Handle<i::FunctionTemplateInfo> NewFunctionTemplate(
1385 i::Isolate* i_isolate, FunctionCallback func) {
1386 Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
1387 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate, func);
1388 templ->ReadOnlyPrototype();
1389 return v8::Utils::OpenHandle(*templ);
1390 }
1391
NewObjectTemplate(i::Isolate * i_isolate)1392 static i::Handle<i::ObjectTemplateInfo> NewObjectTemplate(
1393 i::Isolate* i_isolate) {
1394 Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
1395 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1396 return v8::Utils::OpenHandle(*templ);
1397 }
1398
1399 namespace internal {
1400
CreateFunc(Isolate * isolate,Handle<String> name,FunctionCallback func)1401 Handle<JSFunction> CreateFunc(Isolate* isolate, Handle<String> name,
1402 FunctionCallback func) {
1403 Handle<FunctionTemplateInfo> temp = NewFunctionTemplate(isolate, func);
1404 Handle<JSFunction> function =
1405 ApiNatives::InstantiateFunction(temp, name).ToHandleChecked();
1406 DCHECK(function->shared()->HasSharedName());
1407 return function;
1408 }
1409
InstallFunc(Isolate * isolate,Handle<JSObject> object,const char * str,FunctionCallback func,int length=0)1410 Handle<JSFunction> InstallFunc(Isolate* isolate, Handle<JSObject> object,
1411 const char* str, FunctionCallback func,
1412 int length = 0) {
1413 Handle<String> name = v8_str(isolate, str);
1414 Handle<JSFunction> function = CreateFunc(isolate, name, func);
1415 function->shared()->set_length(length);
1416 PropertyAttributes attributes = static_cast<PropertyAttributes>(DONT_ENUM);
1417 JSObject::AddProperty(isolate, object, name, function, attributes);
1418 return function;
1419 }
1420
GetterName(Isolate * isolate,Handle<String> name)1421 Handle<String> GetterName(Isolate* isolate, Handle<String> name) {
1422 return Name::ToFunctionName(isolate, name, isolate->factory()->get_string())
1423 .ToHandleChecked();
1424 }
1425
InstallGetter(Isolate * isolate,Handle<JSObject> object,const char * str,FunctionCallback func)1426 void InstallGetter(Isolate* isolate, Handle<JSObject> object,
1427 const char* str, FunctionCallback func) {
1428 Handle<String> name = v8_str(isolate, str);
1429 Handle<JSFunction> function =
1430 CreateFunc(isolate, GetterName(isolate, name), func);
1431
1432 v8::PropertyAttribute attributes =
1433 static_cast<v8::PropertyAttribute>(v8::DontEnum);
1434 Utils::ToLocal(object)->SetAccessorProperty(Utils::ToLocal(name),
1435 Utils::ToLocal(function),
1436 Local<Function>(), attributes);
1437 }
1438
SetterName(Isolate * isolate,Handle<String> name)1439 Handle<String> SetterName(Isolate* isolate, Handle<String> name) {
1440 return Name::ToFunctionName(isolate, name, isolate->factory()->set_string())
1441 .ToHandleChecked();
1442 }
1443
InstallGetterSetter(Isolate * isolate,Handle<JSObject> object,const char * str,FunctionCallback getter,FunctionCallback setter)1444 void InstallGetterSetter(Isolate* isolate, Handle<JSObject> object,
1445 const char* str, FunctionCallback getter,
1446 FunctionCallback setter) {
1447 Handle<String> name = v8_str(isolate, str);
1448 Handle<JSFunction> getter_func =
1449 CreateFunc(isolate, GetterName(isolate, name), getter);
1450 Handle<JSFunction> setter_func =
1451 CreateFunc(isolate, SetterName(isolate, name), setter);
1452 setter_func->shared()->set_length(1);
1453
1454 v8::PropertyAttribute attributes =
1455 static_cast<v8::PropertyAttribute>(v8::DontEnum);
1456
1457 Utils::ToLocal(object)->SetAccessorProperty(
1458 Utils::ToLocal(name), Utils::ToLocal(getter_func),
1459 Utils::ToLocal(setter_func), attributes);
1460 }
1461
1462 // Assigns a dummy instance template to the given constructor function. Used to
1463 // make sure the implicit receivers for the constructors in this file have an
1464 // instance type different from the internal one, they allocate the resulting
1465 // object explicitly and ignore implicit receiver.
SetDummyInstanceTemplate(Isolate * isolate,Handle<JSFunction> fun)1466 void SetDummyInstanceTemplate(Isolate* isolate, Handle<JSFunction> fun) {
1467 Handle<ObjectTemplateInfo> instance_template = NewObjectTemplate(isolate);
1468 fun->shared()->get_api_func_data()->set_instance_template(*instance_template);
1469 }
1470
Install(Isolate * isolate,bool exposed_on_global_object)1471 void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
1472 Handle<JSGlobalObject> global = isolate->global_object();
1473 Handle<Context> context(global->native_context(), isolate);
1474 // Install the JS API once only.
1475 Object* prev = context->get(Context::WASM_MODULE_CONSTRUCTOR_INDEX);
1476 if (!prev->IsUndefined(isolate)) {
1477 DCHECK(prev->IsJSFunction());
1478 return;
1479 }
1480
1481 Factory* factory = isolate->factory();
1482
1483 // Setup WebAssembly
1484 Handle<String> name = v8_str(isolate, "WebAssembly");
1485 NewFunctionArgs args = NewFunctionArgs::ForFunctionWithoutCode(
1486 name, isolate->strict_function_map(), LanguageMode::kStrict);
1487 Handle<JSFunction> cons = factory->NewFunction(args);
1488 JSFunction::SetPrototype(cons, isolate->initial_object_prototype());
1489 Handle<JSObject> webassembly = factory->NewJSObject(cons, TENURED);
1490 PropertyAttributes attributes = static_cast<PropertyAttributes>(DONT_ENUM);
1491
1492 PropertyAttributes ro_attributes =
1493 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
1494 JSObject::AddProperty(isolate, webassembly, factory->to_string_tag_symbol(),
1495 name, ro_attributes);
1496 InstallFunc(isolate, webassembly, "compile", WebAssemblyCompile, 1);
1497 InstallFunc(isolate, webassembly, "validate", WebAssemblyValidate, 1);
1498 InstallFunc(isolate, webassembly, "instantiate", WebAssemblyInstantiate, 1);
1499
1500 if (isolate->wasm_streaming_callback() != nullptr) {
1501 InstallFunc(isolate, webassembly, "compileStreaming",
1502 WebAssemblyCompileStreaming, 1);
1503 InstallFunc(isolate, webassembly, "instantiateStreaming",
1504 WebAssemblyInstantiateStreaming, 1);
1505 }
1506
1507 // Expose the API on the global object if configured to do so.
1508 if (exposed_on_global_object) {
1509 JSObject::AddProperty(isolate, global, name, webassembly, attributes);
1510 }
1511
1512 // Setup Module
1513 Handle<JSFunction> module_constructor =
1514 InstallFunc(isolate, webassembly, "Module", WebAssemblyModule, 1);
1515 context->set_wasm_module_constructor(*module_constructor);
1516 SetDummyInstanceTemplate(isolate, module_constructor);
1517 JSFunction::EnsureHasInitialMap(module_constructor);
1518 Handle<JSObject> module_proto(
1519 JSObject::cast(module_constructor->instance_prototype()), isolate);
1520 i::Handle<i::Map> module_map =
1521 isolate->factory()->NewMap(i::WASM_MODULE_TYPE, WasmModuleObject::kSize);
1522 JSFunction::SetInitialMap(module_constructor, module_map, module_proto);
1523 InstallFunc(isolate, module_constructor, "imports", WebAssemblyModuleImports,
1524 1);
1525 InstallFunc(isolate, module_constructor, "exports", WebAssemblyModuleExports,
1526 1);
1527 InstallFunc(isolate, module_constructor, "customSections",
1528 WebAssemblyModuleCustomSections, 2);
1529 JSObject::AddProperty(isolate, module_proto, factory->to_string_tag_symbol(),
1530 v8_str(isolate, "WebAssembly.Module"), ro_attributes);
1531
1532 // Setup Instance
1533 Handle<JSFunction> instance_constructor =
1534 InstallFunc(isolate, webassembly, "Instance", WebAssemblyInstance, 1);
1535 context->set_wasm_instance_constructor(*instance_constructor);
1536 SetDummyInstanceTemplate(isolate, instance_constructor);
1537 JSFunction::EnsureHasInitialMap(instance_constructor);
1538 Handle<JSObject> instance_proto(
1539 JSObject::cast(instance_constructor->instance_prototype()), isolate);
1540 i::Handle<i::Map> instance_map = isolate->factory()->NewMap(
1541 i::WASM_INSTANCE_TYPE, WasmInstanceObject::kSize);
1542 JSFunction::SetInitialMap(instance_constructor, instance_map, instance_proto);
1543 InstallGetter(isolate, instance_proto, "exports",
1544 WebAssemblyInstanceGetExports);
1545 JSObject::AddProperty(isolate, instance_proto,
1546 factory->to_string_tag_symbol(),
1547 v8_str(isolate, "WebAssembly.Instance"), ro_attributes);
1548
1549 // Setup Table
1550 Handle<JSFunction> table_constructor =
1551 InstallFunc(isolate, webassembly, "Table", WebAssemblyTable, 1);
1552 context->set_wasm_table_constructor(*table_constructor);
1553 SetDummyInstanceTemplate(isolate, table_constructor);
1554 JSFunction::EnsureHasInitialMap(table_constructor);
1555 Handle<JSObject> table_proto(
1556 JSObject::cast(table_constructor->instance_prototype()), isolate);
1557 i::Handle<i::Map> table_map =
1558 isolate->factory()->NewMap(i::WASM_TABLE_TYPE, WasmTableObject::kSize);
1559 JSFunction::SetInitialMap(table_constructor, table_map, table_proto);
1560 InstallGetter(isolate, table_proto, "length", WebAssemblyTableGetLength);
1561 InstallFunc(isolate, table_proto, "grow", WebAssemblyTableGrow, 1);
1562 InstallFunc(isolate, table_proto, "get", WebAssemblyTableGet, 1);
1563 InstallFunc(isolate, table_proto, "set", WebAssemblyTableSet, 2);
1564 JSObject::AddProperty(isolate, table_proto, factory->to_string_tag_symbol(),
1565 v8_str(isolate, "WebAssembly.Table"), ro_attributes);
1566
1567 // Setup Memory
1568 Handle<JSFunction> memory_constructor =
1569 InstallFunc(isolate, webassembly, "Memory", WebAssemblyMemory, 1);
1570 context->set_wasm_memory_constructor(*memory_constructor);
1571 SetDummyInstanceTemplate(isolate, memory_constructor);
1572 JSFunction::EnsureHasInitialMap(memory_constructor);
1573 Handle<JSObject> memory_proto(
1574 JSObject::cast(memory_constructor->instance_prototype()), isolate);
1575 i::Handle<i::Map> memory_map =
1576 isolate->factory()->NewMap(i::WASM_MEMORY_TYPE, WasmMemoryObject::kSize);
1577 JSFunction::SetInitialMap(memory_constructor, memory_map, memory_proto);
1578 InstallFunc(isolate, memory_proto, "grow", WebAssemblyMemoryGrow, 1);
1579 InstallGetter(isolate, memory_proto, "buffer", WebAssemblyMemoryGetBuffer);
1580 JSObject::AddProperty(isolate, memory_proto, factory->to_string_tag_symbol(),
1581 v8_str(isolate, "WebAssembly.Memory"), ro_attributes);
1582
1583 // Setup Global
1584
1585 // The context is not set up completely yet. That's why we cannot use
1586 // {WasmFeaturesFromIsolate} and have to use {WasmFeaturesFromFlags} instead.
1587 auto enabled_features = i::wasm::WasmFeaturesFromFlags();
1588 if (enabled_features.mut_global) {
1589 Handle<JSFunction> global_constructor =
1590 InstallFunc(isolate, webassembly, "Global", WebAssemblyGlobal, 1);
1591 context->set_wasm_global_constructor(*global_constructor);
1592 SetDummyInstanceTemplate(isolate, global_constructor);
1593 JSFunction::EnsureHasInitialMap(global_constructor);
1594 Handle<JSObject> global_proto(
1595 JSObject::cast(global_constructor->instance_prototype()), isolate);
1596 i::Handle<i::Map> global_map = isolate->factory()->NewMap(
1597 i::WASM_GLOBAL_TYPE, WasmGlobalObject::kSize);
1598 JSFunction::SetInitialMap(global_constructor, global_map, global_proto);
1599 InstallFunc(isolate, global_proto, "valueOf", WebAssemblyGlobalValueOf, 0);
1600 InstallGetterSetter(isolate, global_proto, "value",
1601 WebAssemblyGlobalGetValue, WebAssemblyGlobalSetValue);
1602 JSObject::AddProperty(isolate, global_proto,
1603 factory->to_string_tag_symbol(),
1604 v8_str(isolate, "WebAssembly.Global"), ro_attributes);
1605 }
1606
1607 // Setup errors
1608 attributes = static_cast<PropertyAttributes>(DONT_ENUM);
1609 Handle<JSFunction> compile_error(
1610 isolate->native_context()->wasm_compile_error_function(), isolate);
1611 JSObject::AddProperty(isolate, webassembly,
1612 isolate->factory()->CompileError_string(),
1613 compile_error, attributes);
1614 Handle<JSFunction> link_error(
1615 isolate->native_context()->wasm_link_error_function(), isolate);
1616 JSObject::AddProperty(isolate, webassembly,
1617 isolate->factory()->LinkError_string(), link_error,
1618 attributes);
1619 Handle<JSFunction> runtime_error(
1620 isolate->native_context()->wasm_runtime_error_function(), isolate);
1621 JSObject::AddProperty(isolate, webassembly,
1622 isolate->factory()->RuntimeError_string(),
1623 runtime_error, attributes);
1624 }
1625
1626 #undef ASSIGN
1627 #undef EXTRACT_THIS
1628
1629 } // namespace internal
1630 } // namespace v8
1631