• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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