• 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 <cinttypes>
8 #include <cstring>
9 
10 #include "include/v8-function.h"
11 #include "include/v8-wasm.h"
12 #include "src/api/api-inl.h"
13 #include "src/api/api-natives.h"
14 #include "src/ast/ast.h"
15 #include "src/base/logging.h"
16 #include "src/base/overflowing-math.h"
17 #include "src/base/platform/wrappers.h"
18 #include "src/common/assert-scope.h"
19 #include "src/execution/execution.h"
20 #include "src/execution/frames-inl.h"
21 #include "src/execution/isolate.h"
22 #include "src/handles/global-handles-inl.h"
23 #include "src/handles/handles.h"
24 #include "src/heap/factory.h"
25 #include "src/init/v8.h"
26 #include "src/objects/fixed-array.h"
27 #include "src/objects/instance-type.h"
28 #include "src/objects/js-function.h"
29 #include "src/objects/js-promise-inl.h"
30 #include "src/objects/managed-inl.h"
31 #include "src/objects/objects-inl.h"
32 #include "src/objects/shared-function-info.h"
33 #include "src/objects/templates.h"
34 #include "src/parsing/parse-info.h"
35 #include "src/tasks/task-utils.h"
36 #include "src/trap-handler/trap-handler.h"
37 #include "src/wasm/function-compiler.h"
38 #include "src/wasm/streaming-decoder.h"
39 #include "src/wasm/value-type.h"
40 #include "src/wasm/wasm-debug.h"
41 #include "src/wasm/wasm-engine.h"
42 #include "src/wasm/wasm-limits.h"
43 #include "src/wasm/wasm-objects-inl.h"
44 #include "src/wasm/wasm-serialization.h"
45 #include "src/wasm/wasm-value.h"
46 
47 using v8::internal::wasm::ErrorThrower;
48 using v8::internal::wasm::ScheduledErrorThrower;
49 
50 namespace v8 {
51 
52 class WasmStreaming::WasmStreamingImpl {
53  public:
WasmStreamingImpl(Isolate * isolate,const char * api_method_name,std::shared_ptr<internal::wasm::CompilationResultResolver> resolver)54   WasmStreamingImpl(
55       Isolate* isolate, const char* api_method_name,
56       std::shared_ptr<internal::wasm::CompilationResultResolver> resolver)
57       : isolate_(isolate), resolver_(std::move(resolver)) {
58     i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate_);
59     auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
60     streaming_decoder_ = i::wasm::GetWasmEngine()->StartStreamingCompilation(
61         i_isolate, enabled_features, handle(i_isolate->context(), i_isolate),
62         api_method_name, resolver_);
63   }
64 
OnBytesReceived(const uint8_t * bytes,size_t size)65   void OnBytesReceived(const uint8_t* bytes, size_t size) {
66     streaming_decoder_->OnBytesReceived(base::VectorOf(bytes, size));
67   }
Finish(bool can_use_compiled_module)68   void Finish(bool can_use_compiled_module) {
69     streaming_decoder_->Finish(can_use_compiled_module);
70   }
71 
Abort(MaybeLocal<Value> exception)72   void Abort(MaybeLocal<Value> exception) {
73     i::HandleScope scope(reinterpret_cast<i::Isolate*>(isolate_));
74     streaming_decoder_->Abort();
75 
76     // If no exception value is provided, we do not reject the promise. This can
77     // happen when streaming compilation gets aborted when no script execution
78     // is allowed anymore, e.g. when a browser tab gets refreshed.
79     if (exception.IsEmpty()) return;
80 
81     resolver_->OnCompilationFailed(
82         Utils::OpenHandle(*exception.ToLocalChecked()));
83   }
84 
SetCompiledModuleBytes(const uint8_t * bytes,size_t size)85   bool SetCompiledModuleBytes(const uint8_t* bytes, size_t size) {
86     if (!i::wasm::IsSupportedVersion({bytes, size})) return false;
87     return streaming_decoder_->SetCompiledModuleBytes({bytes, size});
88   }
89 
SetClient(std::shared_ptr<Client> client)90   void SetClient(std::shared_ptr<Client> client) {
91     streaming_decoder_->SetModuleCompiledCallback(
92         [client, streaming_decoder = streaming_decoder_](
93             const std::shared_ptr<i::wasm::NativeModule>& native_module) {
94           base::Vector<const char> url = streaming_decoder->url();
95           auto compiled_wasm_module =
96               CompiledWasmModule(native_module, url.begin(), url.size());
97           client->OnModuleCompiled(compiled_wasm_module);
98         });
99   }
100 
SetUrl(base::Vector<const char> url)101   void SetUrl(base::Vector<const char> url) { streaming_decoder_->SetUrl(url); }
102 
103  private:
104   Isolate* const isolate_;
105   std::shared_ptr<internal::wasm::StreamingDecoder> streaming_decoder_;
106   std::shared_ptr<internal::wasm::CompilationResultResolver> resolver_;
107 };
108 
WasmStreaming(std::unique_ptr<WasmStreamingImpl> impl)109 WasmStreaming::WasmStreaming(std::unique_ptr<WasmStreamingImpl> impl)
110     : impl_(std::move(impl)) {
111   TRACE_EVENT0("v8.wasm", "wasm.InitializeStreaming");
112 }
113 
114 // The destructor is defined here because we have a unique_ptr with forward
115 // declaration.
116 WasmStreaming::~WasmStreaming() = default;
117 
OnBytesReceived(const uint8_t * bytes,size_t size)118 void WasmStreaming::OnBytesReceived(const uint8_t* bytes, size_t size) {
119   TRACE_EVENT1("v8.wasm", "wasm.OnBytesReceived", "bytes", size);
120   impl_->OnBytesReceived(bytes, size);
121 }
122 
Finish(bool can_use_compiled_module)123 void WasmStreaming::Finish(bool can_use_compiled_module) {
124   TRACE_EVENT0("v8.wasm", "wasm.FinishStreaming");
125   impl_->Finish(can_use_compiled_module);
126 }
127 
Abort(MaybeLocal<Value> exception)128 void WasmStreaming::Abort(MaybeLocal<Value> exception) {
129   TRACE_EVENT0("v8.wasm", "wasm.AbortStreaming");
130   impl_->Abort(exception);
131 }
132 
SetCompiledModuleBytes(const uint8_t * bytes,size_t size)133 bool WasmStreaming::SetCompiledModuleBytes(const uint8_t* bytes, size_t size) {
134   TRACE_EVENT0("v8.wasm", "wasm.SetCompiledModuleBytes");
135   return impl_->SetCompiledModuleBytes(bytes, size);
136 }
137 
SetClient(std::shared_ptr<Client> client)138 void WasmStreaming::SetClient(std::shared_ptr<Client> client) {
139   TRACE_EVENT0("v8.wasm", "wasm.WasmStreaming.SetClient");
140   impl_->SetClient(client);
141 }
142 
SetUrl(const char * url,size_t length)143 void WasmStreaming::SetUrl(const char* url, size_t length) {
144   DCHECK_EQ('\0', url[length]);  // {url} is null-terminated.
145   TRACE_EVENT1("v8.wasm", "wasm.SetUrl", "url", url);
146   impl_->SetUrl(base::VectorOf(url, length));
147 }
148 
149 // static
Unpack(Isolate * isolate,Local<Value> value)150 std::shared_ptr<WasmStreaming> WasmStreaming::Unpack(Isolate* isolate,
151                                                      Local<Value> value) {
152   TRACE_EVENT0("v8.wasm", "wasm.WasmStreaming.Unpack");
153   i::HandleScope scope(reinterpret_cast<i::Isolate*>(isolate));
154   auto managed =
155       i::Handle<i::Managed<WasmStreaming>>::cast(Utils::OpenHandle(*value));
156   return managed->get();
157 }
158 
159 namespace {
160 
161 #define ASSIGN(type, var, expr)                      \
162   Local<type> var;                                   \
163   do {                                               \
164     if (!expr.ToLocal(&var)) {                       \
165       DCHECK(i_isolate->has_scheduled_exception());  \
166       return;                                        \
167     } else {                                         \
168       DCHECK(!i_isolate->has_scheduled_exception()); \
169     }                                                \
170   } while (false)
171 
v8_str(i::Isolate * isolate,const char * str)172 i::Handle<i::String> v8_str(i::Isolate* isolate, const char* str) {
173   return isolate->factory()->NewStringFromAsciiChecked(str);
174 }
v8_str(Isolate * isolate,const char * str)175 Local<String> v8_str(Isolate* isolate, const char* str) {
176   return Utils::ToLocal(v8_str(reinterpret_cast<i::Isolate*>(isolate), str));
177 }
178 
179 #define GET_FIRST_ARGUMENT_AS(Type)                                  \
180   i::MaybeHandle<i::Wasm##Type##Object> GetFirstArgumentAs##Type(    \
181       const v8::FunctionCallbackInfo<v8::Value>& args,               \
182       ErrorThrower* thrower) {                                       \
183     i::Handle<i::Object> arg0 = Utils::OpenHandle(*args[0]);         \
184     if (!arg0->IsWasm##Type##Object()) {                             \
185       thrower->TypeError("Argument 0 must be a WebAssembly." #Type); \
186       return {};                                                     \
187     }                                                                \
188     return i::Handle<i::Wasm##Type##Object>::cast(arg0);             \
189   }
190 
191 GET_FIRST_ARGUMENT_AS(Module)
GET_FIRST_ARGUMENT_AS(Tag)192 GET_FIRST_ARGUMENT_AS(Tag)
193 
194 #undef GET_FIRST_ARGUMENT_AS
195 
196 i::wasm::ModuleWireBytes GetFirstArgumentAsBytes(
197     const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower,
198     bool* is_shared) {
199   const uint8_t* start = nullptr;
200   size_t length = 0;
201   v8::Local<v8::Value> source = args[0];
202   if (source->IsArrayBuffer()) {
203     // A raw array buffer was passed.
204     Local<ArrayBuffer> buffer = Local<ArrayBuffer>::Cast(source);
205     auto backing_store = buffer->GetBackingStore();
206 
207     start = reinterpret_cast<const uint8_t*>(backing_store->Data());
208     length = backing_store->ByteLength();
209     *is_shared = buffer->IsSharedArrayBuffer();
210   } else if (source->IsTypedArray()) {
211     // A TypedArray was passed.
212     Local<TypedArray> array = Local<TypedArray>::Cast(source);
213     Local<ArrayBuffer> buffer = array->Buffer();
214 
215     auto backing_store = buffer->GetBackingStore();
216 
217     start = reinterpret_cast<const uint8_t*>(backing_store->Data()) +
218             array->ByteOffset();
219     length = array->ByteLength();
220     *is_shared = buffer->IsSharedArrayBuffer();
221   } else {
222     thrower->TypeError("Argument 0 must be a buffer source");
223   }
224   DCHECK_IMPLIES(length, start != nullptr);
225   if (length == 0) {
226     thrower->CompileError("BufferSource argument is empty");
227   }
228   size_t max_length = i::wasm::max_module_size();
229   if (length > max_length) {
230     thrower->RangeError("buffer source exceeds maximum size of %zu (is %zu)",
231                         max_length, length);
232   }
233   if (thrower->error()) return i::wasm::ModuleWireBytes(nullptr, nullptr);
234   return i::wasm::ModuleWireBytes(start, start + length);
235 }
236 
GetFirstArgumentAsJSFunction(const v8::FunctionCallbackInfo<v8::Value> & args,ErrorThrower * thrower)237 i::MaybeHandle<i::JSFunction> GetFirstArgumentAsJSFunction(
238     const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
239   i::Handle<i::Object> arg0 = Utils::OpenHandle(*args[0]);
240   if (!arg0->IsJSFunction()) {
241     thrower->TypeError("Argument 0 must be a function");
242     return {};
243   }
244   return i::Handle<i::JSFunction>::cast(arg0);
245 }
246 
GetValueAsImports(Local<Value> arg,ErrorThrower * thrower)247 i::MaybeHandle<i::JSReceiver> GetValueAsImports(Local<Value> arg,
248                                                 ErrorThrower* thrower) {
249   if (arg->IsUndefined()) return {};
250 
251   if (!arg->IsObject()) {
252     thrower->TypeError("Argument 1 must be an object");
253     return {};
254   }
255   Local<Object> obj = Local<Object>::Cast(arg);
256   return i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
257 }
258 
259 namespace {
260 // This class resolves the result of WebAssembly.compile. It just places the
261 // compilation result in the supplied {promise}.
262 class AsyncCompilationResolver : public i::wasm::CompilationResultResolver {
263  public:
AsyncCompilationResolver(i::Isolate * isolate,i::Handle<i::JSPromise> promise)264   AsyncCompilationResolver(i::Isolate* isolate, i::Handle<i::JSPromise> promise)
265       : promise_(isolate->global_handles()->Create(*promise)) {
266     i::GlobalHandles::AnnotateStrongRetainer(promise_.location(),
267                                              kGlobalPromiseHandle);
268   }
269 
~AsyncCompilationResolver()270   ~AsyncCompilationResolver() override {
271     i::GlobalHandles::Destroy(promise_.location());
272   }
273 
OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result)274   void OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result) override {
275     if (finished_) return;
276     finished_ = true;
277     i::MaybeHandle<i::Object> promise_result =
278         i::JSPromise::Resolve(promise_, result);
279     CHECK_EQ(promise_result.is_null(),
280              promise_->GetIsolate()->has_pending_exception());
281   }
282 
OnCompilationFailed(i::Handle<i::Object> error_reason)283   void OnCompilationFailed(i::Handle<i::Object> error_reason) override {
284     if (finished_) return;
285     finished_ = true;
286     i::MaybeHandle<i::Object> promise_result =
287         i::JSPromise::Reject(promise_, error_reason);
288     CHECK_EQ(promise_result.is_null(),
289              promise_->GetIsolate()->has_pending_exception());
290   }
291 
292  private:
293   static constexpr char kGlobalPromiseHandle[] =
294       "AsyncCompilationResolver::promise_";
295   bool finished_ = false;
296   i::Handle<i::JSPromise> promise_;
297 };
298 
299 constexpr char AsyncCompilationResolver::kGlobalPromiseHandle[];
300 
301 // This class resolves the result of WebAssembly.instantiate(module, imports).
302 // It just places the instantiation result in the supplied {promise}.
303 class InstantiateModuleResultResolver
304     : public i::wasm::InstantiationResultResolver {
305  public:
InstantiateModuleResultResolver(i::Isolate * isolate,i::Handle<i::JSPromise> promise)306   InstantiateModuleResultResolver(i::Isolate* isolate,
307                                   i::Handle<i::JSPromise> promise)
308       : promise_(isolate->global_handles()->Create(*promise)) {
309     i::GlobalHandles::AnnotateStrongRetainer(promise_.location(),
310                                              kGlobalPromiseHandle);
311   }
312 
~InstantiateModuleResultResolver()313   ~InstantiateModuleResultResolver() override {
314     i::GlobalHandles::Destroy(promise_.location());
315   }
316 
OnInstantiationSucceeded(i::Handle<i::WasmInstanceObject> instance)317   void OnInstantiationSucceeded(
318       i::Handle<i::WasmInstanceObject> instance) override {
319     i::MaybeHandle<i::Object> promise_result =
320         i::JSPromise::Resolve(promise_, instance);
321     CHECK_EQ(promise_result.is_null(),
322              promise_->GetIsolate()->has_pending_exception());
323   }
324 
OnInstantiationFailed(i::Handle<i::Object> error_reason)325   void OnInstantiationFailed(i::Handle<i::Object> error_reason) override {
326     i::MaybeHandle<i::Object> promise_result =
327         i::JSPromise::Reject(promise_, error_reason);
328     CHECK_EQ(promise_result.is_null(),
329              promise_->GetIsolate()->has_pending_exception());
330   }
331 
332  private:
333   static constexpr char kGlobalPromiseHandle[] =
334       "InstantiateModuleResultResolver::promise_";
335   i::Handle<i::JSPromise> promise_;
336 };
337 
338 constexpr char InstantiateModuleResultResolver::kGlobalPromiseHandle[];
339 
340 // This class resolves the result of WebAssembly.instantiate(bytes, imports).
341 // For that it creates a new {JSObject} which contains both the provided
342 // {WasmModuleObject} and the resulting {WebAssemblyInstanceObject} itself.
343 class InstantiateBytesResultResolver
344     : public i::wasm::InstantiationResultResolver {
345  public:
InstantiateBytesResultResolver(i::Isolate * isolate,i::Handle<i::JSPromise> promise,i::Handle<i::WasmModuleObject> module)346   InstantiateBytesResultResolver(i::Isolate* isolate,
347                                  i::Handle<i::JSPromise> promise,
348                                  i::Handle<i::WasmModuleObject> module)
349       : isolate_(isolate),
350         promise_(isolate_->global_handles()->Create(*promise)),
351         module_(isolate_->global_handles()->Create(*module)) {
352     i::GlobalHandles::AnnotateStrongRetainer(promise_.location(),
353                                              kGlobalPromiseHandle);
354     i::GlobalHandles::AnnotateStrongRetainer(module_.location(),
355                                              kGlobalModuleHandle);
356   }
357 
~InstantiateBytesResultResolver()358   ~InstantiateBytesResultResolver() override {
359     i::GlobalHandles::Destroy(promise_.location());
360     i::GlobalHandles::Destroy(module_.location());
361   }
362 
OnInstantiationSucceeded(i::Handle<i::WasmInstanceObject> instance)363   void OnInstantiationSucceeded(
364       i::Handle<i::WasmInstanceObject> instance) override {
365     // The result is a JSObject with 2 fields which contain the
366     // WasmInstanceObject and the WasmModuleObject.
367     i::Handle<i::JSObject> result =
368         isolate_->factory()->NewJSObject(isolate_->object_function());
369 
370     i::Handle<i::String> instance_name =
371         isolate_->factory()->NewStringFromStaticChars("instance");
372 
373     i::Handle<i::String> module_name =
374         isolate_->factory()->NewStringFromStaticChars("module");
375 
376     i::JSObject::AddProperty(isolate_, result, instance_name, instance,
377                              i::NONE);
378     i::JSObject::AddProperty(isolate_, result, module_name, module_, i::NONE);
379 
380     i::MaybeHandle<i::Object> promise_result =
381         i::JSPromise::Resolve(promise_, result);
382     CHECK_EQ(promise_result.is_null(), isolate_->has_pending_exception());
383   }
384 
OnInstantiationFailed(i::Handle<i::Object> error_reason)385   void OnInstantiationFailed(i::Handle<i::Object> error_reason) override {
386     i::MaybeHandle<i::Object> promise_result =
387         i::JSPromise::Reject(promise_, error_reason);
388     CHECK_EQ(promise_result.is_null(), isolate_->has_pending_exception());
389   }
390 
391  private:
392   static constexpr char kGlobalPromiseHandle[] =
393       "InstantiateBytesResultResolver::promise_";
394   static constexpr char kGlobalModuleHandle[] =
395       "InstantiateBytesResultResolver::module_";
396   i::Isolate* isolate_;
397   i::Handle<i::JSPromise> promise_;
398   i::Handle<i::WasmModuleObject> module_;
399 };
400 
401 constexpr char InstantiateBytesResultResolver::kGlobalPromiseHandle[];
402 constexpr char InstantiateBytesResultResolver::kGlobalModuleHandle[];
403 
404 // This class is the {CompilationResultResolver} for
405 // WebAssembly.instantiate(bytes, imports). When compilation finishes,
406 // {AsyncInstantiate} is started on the compilation result.
407 class AsyncInstantiateCompileResultResolver
408     : public i::wasm::CompilationResultResolver {
409  public:
AsyncInstantiateCompileResultResolver(i::Isolate * isolate,i::Handle<i::JSPromise> promise,i::MaybeHandle<i::JSReceiver> maybe_imports)410   AsyncInstantiateCompileResultResolver(
411       i::Isolate* isolate, i::Handle<i::JSPromise> promise,
412       i::MaybeHandle<i::JSReceiver> maybe_imports)
413       : isolate_(isolate),
414         promise_(isolate_->global_handles()->Create(*promise)),
415         maybe_imports_(maybe_imports.is_null()
416                            ? maybe_imports
417                            : isolate_->global_handles()->Create(
418                                  *maybe_imports.ToHandleChecked())) {
419     i::GlobalHandles::AnnotateStrongRetainer(promise_.location(),
420                                              kGlobalPromiseHandle);
421     if (!maybe_imports_.is_null()) {
422       i::GlobalHandles::AnnotateStrongRetainer(
423           maybe_imports_.ToHandleChecked().location(), kGlobalImportsHandle);
424     }
425   }
426 
~AsyncInstantiateCompileResultResolver()427   ~AsyncInstantiateCompileResultResolver() override {
428     i::GlobalHandles::Destroy(promise_.location());
429     if (!maybe_imports_.is_null()) {
430       i::GlobalHandles::Destroy(maybe_imports_.ToHandleChecked().location());
431     }
432   }
433 
OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result)434   void OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result) override {
435     if (finished_) return;
436     finished_ = true;
437     i::wasm::GetWasmEngine()->AsyncInstantiate(
438         isolate_,
439         std::make_unique<InstantiateBytesResultResolver>(isolate_, promise_,
440                                                          result),
441         result, maybe_imports_);
442   }
443 
OnCompilationFailed(i::Handle<i::Object> error_reason)444   void OnCompilationFailed(i::Handle<i::Object> error_reason) override {
445     if (finished_) return;
446     finished_ = true;
447     i::MaybeHandle<i::Object> promise_result =
448         i::JSPromise::Reject(promise_, error_reason);
449     CHECK_EQ(promise_result.is_null(), isolate_->has_pending_exception());
450   }
451 
452  private:
453   static constexpr char kGlobalPromiseHandle[] =
454       "AsyncInstantiateCompileResultResolver::promise_";
455   static constexpr char kGlobalImportsHandle[] =
456       "AsyncInstantiateCompileResultResolver::module_";
457   bool finished_ = false;
458   i::Isolate* isolate_;
459   i::Handle<i::JSPromise> promise_;
460   i::MaybeHandle<i::JSReceiver> maybe_imports_;
461 };
462 
463 constexpr char AsyncInstantiateCompileResultResolver::kGlobalPromiseHandle[];
464 constexpr char AsyncInstantiateCompileResultResolver::kGlobalImportsHandle[];
465 
ToString(const char * name)466 std::string ToString(const char* name) { return std::string(name); }
467 
ToString(const i::Handle<i::String> name)468 std::string ToString(const i::Handle<i::String> name) {
469   return std::string("Property '") + name->ToCString().get() + "'";
470 }
471 
472 // Web IDL: '[EnforceRange] unsigned long'
473 // Previously called ToNonWrappingUint32 in the draft WebAssembly JS spec.
474 // https://heycam.github.io/webidl/#EnforceRange
475 template <typename T>
EnforceUint32(T argument_name,Local<v8::Value> v,Local<Context> context,ErrorThrower * thrower,uint32_t * res)476 bool EnforceUint32(T argument_name, Local<v8::Value> v, Local<Context> context,
477                    ErrorThrower* thrower, uint32_t* res) {
478   double double_number;
479 
480   if (!v->NumberValue(context).To(&double_number)) {
481     thrower->TypeError("%s must be convertible to a number",
482                        ToString(argument_name).c_str());
483     return false;
484   }
485   if (!std::isfinite(double_number)) {
486     thrower->TypeError("%s must be convertible to a valid number",
487                        ToString(argument_name).c_str());
488     return false;
489   }
490   if (double_number < 0) {
491     thrower->TypeError("%s must be non-negative",
492                        ToString(argument_name).c_str());
493     return false;
494   }
495   if (double_number > std::numeric_limits<uint32_t>::max()) {
496     thrower->TypeError("%s must be in the unsigned long range",
497                        ToString(argument_name).c_str());
498     return false;
499   }
500 
501   *res = static_cast<uint32_t>(double_number);
502   return true;
503 }
504 }  // namespace
505 
506 // WebAssembly.compile(bytes) -> Promise
WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value> & args)507 void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
508   constexpr const char* kAPIMethodName = "WebAssembly.compile()";
509   v8::Isolate* isolate = args.GetIsolate();
510   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
511 
512   HandleScope scope(isolate);
513   ScheduledErrorThrower thrower(i_isolate, kAPIMethodName);
514 
515   if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
516     thrower.CompileError("Wasm code generation disallowed by embedder");
517   }
518 
519   Local<Context> context = isolate->GetCurrentContext();
520   ASSIGN(Promise::Resolver, promise_resolver, Promise::Resolver::New(context));
521   Local<Promise> promise = promise_resolver->GetPromise();
522   v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
523   return_value.Set(promise);
524 
525   std::shared_ptr<i::wasm::CompilationResultResolver> resolver(
526       new AsyncCompilationResolver(i_isolate, Utils::OpenHandle(*promise)));
527 
528   bool is_shared = false;
529   auto bytes = GetFirstArgumentAsBytes(args, &thrower, &is_shared);
530   if (thrower.error()) {
531     resolver->OnCompilationFailed(thrower.Reify());
532     return;
533   }
534   // Asynchronous compilation handles copying wire bytes if necessary.
535   auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
536   i::wasm::GetWasmEngine()->AsyncCompile(i_isolate, enabled_features,
537                                          std::move(resolver), bytes, is_shared,
538                                          kAPIMethodName);
539 }
540 
WasmStreamingCallbackForTesting(const v8::FunctionCallbackInfo<v8::Value> & args)541 void WasmStreamingCallbackForTesting(
542     const v8::FunctionCallbackInfo<v8::Value>& args) {
543   v8::Isolate* isolate = args.GetIsolate();
544   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
545 
546   HandleScope scope(isolate);
547   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.compile()");
548 
549   std::shared_ptr<v8::WasmStreaming> streaming =
550       v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
551 
552   bool is_shared = false;
553   i::wasm::ModuleWireBytes bytes =
554       GetFirstArgumentAsBytes(args, &thrower, &is_shared);
555   if (thrower.error()) {
556     streaming->Abort(Utils::ToLocal(thrower.Reify()));
557     return;
558   }
559   streaming->OnBytesReceived(bytes.start(), bytes.length());
560   streaming->Finish();
561   CHECK(!thrower.error());
562 }
563 
WasmStreamingPromiseFailedCallback(const v8::FunctionCallbackInfo<v8::Value> & args)564 void WasmStreamingPromiseFailedCallback(
565     const v8::FunctionCallbackInfo<v8::Value>& args) {
566   std::shared_ptr<v8::WasmStreaming> streaming =
567       v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
568   streaming->Abort(args[0]);
569 }
570 
571 // WebAssembly.compileStreaming(Response | Promise<Response>)
572 //   -> Promise<WebAssembly.Module>
WebAssemblyCompileStreaming(const v8::FunctionCallbackInfo<v8::Value> & args)573 void WebAssemblyCompileStreaming(
574     const v8::FunctionCallbackInfo<v8::Value>& args) {
575   v8::Isolate* isolate = args.GetIsolate();
576   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
577   HandleScope scope(isolate);
578   const char* const kAPIMethodName = "WebAssembly.compileStreaming()";
579   ScheduledErrorThrower thrower(i_isolate, kAPIMethodName);
580   Local<Context> context = isolate->GetCurrentContext();
581 
582   // Create and assign the return value of this function.
583   ASSIGN(Promise::Resolver, result_resolver, Promise::Resolver::New(context));
584   Local<Promise> promise = result_resolver->GetPromise();
585   v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
586   return_value.Set(promise);
587 
588   // Prepare the CompilationResultResolver for the compilation.
589   auto resolver = std::make_shared<AsyncCompilationResolver>(
590       i_isolate, Utils::OpenHandle(*promise));
591 
592   if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
593     thrower.CompileError("Wasm code generation disallowed by embedder");
594     resolver->OnCompilationFailed(thrower.Reify());
595     return;
596   }
597 
598   // Allocate the streaming decoder in a Managed so we can pass it to the
599   // embedder.
600   i::Handle<i::Managed<WasmStreaming>> data =
601       i::Managed<WasmStreaming>::Allocate(
602           i_isolate, 0,
603           std::make_unique<WasmStreaming::WasmStreamingImpl>(
604               isolate, kAPIMethodName, resolver));
605 
606   DCHECK_NOT_NULL(i_isolate->wasm_streaming_callback());
607   ASSIGN(
608       v8::Function, compile_callback,
609       v8::Function::New(context, i_isolate->wasm_streaming_callback(),
610                         Utils::ToLocal(i::Handle<i::Object>::cast(data)), 1));
611   ASSIGN(
612       v8::Function, reject_callback,
613       v8::Function::New(context, WasmStreamingPromiseFailedCallback,
614                         Utils::ToLocal(i::Handle<i::Object>::cast(data)), 1));
615 
616   // The parameter may be of type {Response} or of type {Promise<Response>}.
617   // Treat either case of parameter as Promise.resolve(parameter)
618   // as per https://www.w3.org/2001/tag/doc/promises-guide#resolve-arguments
619 
620   // Ending with:
621   //    return Promise.resolve(parameter).then(compile_callback);
622   ASSIGN(Promise::Resolver, input_resolver, Promise::Resolver::New(context));
623   if (!input_resolver->Resolve(context, args[0]).IsJust()) return;
624 
625   // We do not have any use of the result here. The {compile_callback} will
626   // start streaming compilation, which will eventually resolve the promise we
627   // set as result value.
628   USE(input_resolver->GetPromise()->Then(context, compile_callback,
629                                          reject_callback));
630 }
631 
632 // WebAssembly.validate(bytes) -> bool
WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value> & args)633 void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
634   v8::Isolate* isolate = args.GetIsolate();
635   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
636   HandleScope scope(isolate);
637   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.validate()");
638 
639   bool is_shared = false;
640   auto bytes = GetFirstArgumentAsBytes(args, &thrower, &is_shared);
641 
642   v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
643 
644   if (thrower.error()) {
645     if (thrower.wasm_error()) thrower.Reset();  // Clear error.
646     return_value.Set(v8::False(isolate));
647     return;
648   }
649 
650   auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
651   bool validated = false;
652   if (is_shared) {
653     // Make a copy of the wire bytes to avoid concurrent modification.
654     std::unique_ptr<uint8_t[]> copy(new uint8_t[bytes.length()]);
655     memcpy(copy.get(), bytes.start(), bytes.length());
656     i::wasm::ModuleWireBytes bytes_copy(copy.get(),
657                                         copy.get() + bytes.length());
658     validated = i::wasm::GetWasmEngine()->SyncValidate(
659         i_isolate, enabled_features, bytes_copy);
660   } else {
661     // The wire bytes are not shared, OK to use them directly.
662     validated = i::wasm::GetWasmEngine()->SyncValidate(i_isolate,
663                                                        enabled_features, bytes);
664   }
665 
666   return_value.Set(Boolean::New(isolate, validated));
667 }
668 
669 namespace {
TransferPrototype(i::Isolate * isolate,i::Handle<i::JSObject> destination,i::Handle<i::JSReceiver> source)670 bool TransferPrototype(i::Isolate* isolate, i::Handle<i::JSObject> destination,
671                        i::Handle<i::JSReceiver> source) {
672   i::MaybeHandle<i::HeapObject> maybe_prototype =
673       i::JSObject::GetPrototype(isolate, source);
674   i::Handle<i::HeapObject> prototype;
675   if (maybe_prototype.ToHandle(&prototype)) {
676     Maybe<bool> result = i::JSObject::SetPrototype(
677         isolate, destination, prototype,
678         /*from_javascript=*/false, internal::kThrowOnError);
679     if (!result.FromJust()) {
680       DCHECK(isolate->has_pending_exception());
681       return false;
682     }
683   }
684   return true;
685 }
686 }  // namespace
687 
688 // new WebAssembly.Module(bytes) -> WebAssembly.Module
WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value> & args)689 void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
690   v8::Isolate* isolate = args.GetIsolate();
691   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
692   if (i_isolate->wasm_module_callback()(args)) return;
693 
694   HandleScope scope(isolate);
695   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module()");
696 
697   if (!args.IsConstructCall()) {
698     thrower.TypeError("WebAssembly.Module must be invoked with 'new'");
699     return;
700   }
701   if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
702     thrower.CompileError("Wasm code generation disallowed by embedder");
703     return;
704   }
705 
706   bool is_shared = false;
707   auto bytes = GetFirstArgumentAsBytes(args, &thrower, &is_shared);
708 
709   if (thrower.error()) {
710     return;
711   }
712   auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
713   i::MaybeHandle<i::WasmModuleObject> maybe_module_obj;
714   if (is_shared) {
715     // Make a copy of the wire bytes to avoid concurrent modification.
716     std::unique_ptr<uint8_t[]> copy(new uint8_t[bytes.length()]);
717     memcpy(copy.get(), bytes.start(), bytes.length());
718     i::wasm::ModuleWireBytes bytes_copy(copy.get(),
719                                         copy.get() + bytes.length());
720     maybe_module_obj = i::wasm::GetWasmEngine()->SyncCompile(
721         i_isolate, enabled_features, &thrower, bytes_copy);
722   } else {
723     // The wire bytes are not shared, OK to use them directly.
724     maybe_module_obj = i::wasm::GetWasmEngine()->SyncCompile(
725         i_isolate, enabled_features, &thrower, bytes);
726   }
727 
728   i::Handle<i::WasmModuleObject> module_obj;
729   if (!maybe_module_obj.ToHandle(&module_obj)) return;
730 
731   // The infrastructure for `new Foo` calls allocates an object, which is
732   // available here as {args.This()}. We're going to discard this object
733   // and use {module_obj} instead, but it does have the correct prototype,
734   // which we must harvest from it. This makes a difference when the JS
735   // constructor function wasn't {WebAssembly.Module} directly, but some
736   // subclass: {module_obj} has {WebAssembly.Module}'s prototype at this
737   // point, so we must overwrite that with the correct prototype for {Foo}.
738   if (!TransferPrototype(i_isolate, module_obj,
739                          Utils::OpenHandle(*args.This()))) {
740     return;
741   }
742 
743   v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
744   return_value.Set(Utils::ToLocal(i::Handle<i::JSObject>::cast(module_obj)));
745 }
746 
747 // WebAssembly.Module.imports(module) -> Array<Import>
WebAssemblyModuleImports(const v8::FunctionCallbackInfo<v8::Value> & args)748 void WebAssemblyModuleImports(const v8::FunctionCallbackInfo<v8::Value>& args) {
749   HandleScope scope(args.GetIsolate());
750   v8::Isolate* isolate = args.GetIsolate();
751   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
752   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module.imports()");
753 
754   auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
755   if (thrower.error()) return;
756   auto imports = i::wasm::GetImports(i_isolate, maybe_module.ToHandleChecked());
757   args.GetReturnValue().Set(Utils::ToLocal(imports));
758 }
759 
760 // WebAssembly.Module.exports(module) -> Array<Export>
WebAssemblyModuleExports(const v8::FunctionCallbackInfo<v8::Value> & args)761 void WebAssemblyModuleExports(const v8::FunctionCallbackInfo<v8::Value>& args) {
762   HandleScope scope(args.GetIsolate());
763   v8::Isolate* isolate = args.GetIsolate();
764   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
765   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module.exports()");
766 
767   auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
768   if (thrower.error()) return;
769   auto exports = i::wasm::GetExports(i_isolate, maybe_module.ToHandleChecked());
770   args.GetReturnValue().Set(Utils::ToLocal(exports));
771 }
772 
773 // WebAssembly.Module.customSections(module, name) -> Array<Section>
WebAssemblyModuleCustomSections(const v8::FunctionCallbackInfo<v8::Value> & args)774 void WebAssemblyModuleCustomSections(
775     const v8::FunctionCallbackInfo<v8::Value>& args) {
776   HandleScope scope(args.GetIsolate());
777   v8::Isolate* isolate = args.GetIsolate();
778   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
779   ScheduledErrorThrower thrower(i_isolate,
780                                 "WebAssembly.Module.customSections()");
781 
782   auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
783   if (thrower.error()) return;
784 
785   if (args[1]->IsUndefined()) {
786     thrower.TypeError("Argument 1 is required");
787     return;
788   }
789 
790   i::MaybeHandle<i::Object> maybe_name =
791       i::Object::ToString(i_isolate, Utils::OpenHandle(*args[1]));
792   i::Handle<i::Object> name;
793   if (!maybe_name.ToHandle(&name)) return;
794   auto custom_sections =
795       i::wasm::GetCustomSections(i_isolate, maybe_module.ToHandleChecked(),
796                                  i::Handle<i::String>::cast(name), &thrower);
797   if (thrower.error()) return;
798   args.GetReturnValue().Set(Utils::ToLocal(custom_sections));
799 }
800 
801 // new WebAssembly.Instance(module, imports) -> WebAssembly.Instance
WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value> & args)802 void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
803   Isolate* isolate = args.GetIsolate();
804   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
805   i_isolate->CountUsage(
806       v8::Isolate::UseCounterFeature::kWebAssemblyInstantiation);
807 
808   HandleScope scope(args.GetIsolate());
809   if (i_isolate->wasm_instance_callback()(args)) return;
810 
811   i::MaybeHandle<i::JSObject> maybe_instance_obj;
812   {
813     ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Instance()");
814     if (!args.IsConstructCall()) {
815       thrower.TypeError("WebAssembly.Instance must be invoked with 'new'");
816       return;
817     }
818 
819     i::MaybeHandle<i::WasmModuleObject> maybe_module =
820         GetFirstArgumentAsModule(args, &thrower);
821     if (thrower.error()) return;
822 
823     i::Handle<i::WasmModuleObject> module_obj = maybe_module.ToHandleChecked();
824 
825     i::MaybeHandle<i::JSReceiver> maybe_imports =
826         GetValueAsImports(args[1], &thrower);
827     if (thrower.error()) return;
828 
829     maybe_instance_obj = i::wasm::GetWasmEngine()->SyncInstantiate(
830         i_isolate, &thrower, module_obj, maybe_imports,
831         i::MaybeHandle<i::JSArrayBuffer>());
832   }
833 
834   i::Handle<i::JSObject> instance_obj;
835   if (!maybe_instance_obj.ToHandle(&instance_obj)) {
836     DCHECK(i_isolate->has_scheduled_exception());
837     return;
838   }
839 
840   // The infrastructure for `new Foo` calls allocates an object, which is
841   // available here as {args.This()}. We're going to discard this object
842   // and use {instance_obj} instead, but it does have the correct prototype,
843   // which we must harvest from it. This makes a difference when the JS
844   // constructor function wasn't {WebAssembly.Instance} directly, but some
845   // subclass: {instance_obj} has {WebAssembly.Instance}'s prototype at this
846   // point, so we must overwrite that with the correct prototype for {Foo}.
847   if (!TransferPrototype(i_isolate, instance_obj,
848                          Utils::OpenHandle(*args.This()))) {
849     return;
850   }
851 
852   args.GetReturnValue().Set(Utils::ToLocal(instance_obj));
853 }
854 
855 // WebAssembly.instantiateStreaming(Response | Promise<Response> [, imports])
856 //   -> Promise<ResultObject>
857 // (where ResultObject has a "module" and an "instance" field)
WebAssemblyInstantiateStreaming(const v8::FunctionCallbackInfo<v8::Value> & args)858 void WebAssemblyInstantiateStreaming(
859     const v8::FunctionCallbackInfo<v8::Value>& args) {
860   v8::Isolate* isolate = args.GetIsolate();
861   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
862   i_isolate->CountUsage(
863       v8::Isolate::UseCounterFeature::kWebAssemblyInstantiation);
864 
865   HandleScope scope(isolate);
866   Local<Context> context = isolate->GetCurrentContext();
867   const char* const kAPIMethodName = "WebAssembly.instantiateStreaming()";
868   ScheduledErrorThrower thrower(i_isolate, kAPIMethodName);
869 
870   // Create and assign the return value of this function.
871   ASSIGN(Promise::Resolver, result_resolver, Promise::Resolver::New(context));
872   Local<Promise> promise = result_resolver->GetPromise();
873   v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
874   return_value.Set(promise);
875 
876   // Create an InstantiateResultResolver in case there is an issue with the
877   // passed parameters.
878   std::unique_ptr<i::wasm::InstantiationResultResolver> resolver(
879       new InstantiateModuleResultResolver(i_isolate,
880                                           Utils::OpenHandle(*promise)));
881 
882   if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
883     thrower.CompileError("Wasm code generation disallowed by embedder");
884     resolver->OnInstantiationFailed(thrower.Reify());
885     return;
886   }
887 
888   // If args.Length < 2, this will be undefined - see FunctionCallbackInfo.
889   Local<Value> ffi = args[1];
890   i::MaybeHandle<i::JSReceiver> maybe_imports =
891       GetValueAsImports(ffi, &thrower);
892 
893   if (thrower.error()) {
894     resolver->OnInstantiationFailed(thrower.Reify());
895     return;
896   }
897 
898   // We start compilation now, we have no use for the
899   // {InstantiationResultResolver}.
900   resolver.reset();
901 
902   std::shared_ptr<i::wasm::CompilationResultResolver> compilation_resolver(
903       new AsyncInstantiateCompileResultResolver(
904           i_isolate, Utils::OpenHandle(*promise), maybe_imports));
905 
906   // Allocate the streaming decoder in a Managed so we can pass it to the
907   // embedder.
908   i::Handle<i::Managed<WasmStreaming>> data =
909       i::Managed<WasmStreaming>::Allocate(
910           i_isolate, 0,
911           std::make_unique<WasmStreaming::WasmStreamingImpl>(
912               isolate, kAPIMethodName, compilation_resolver));
913 
914   DCHECK_NOT_NULL(i_isolate->wasm_streaming_callback());
915   ASSIGN(
916       v8::Function, compile_callback,
917       v8::Function::New(context, i_isolate->wasm_streaming_callback(),
918                         Utils::ToLocal(i::Handle<i::Object>::cast(data)), 1));
919   ASSIGN(
920       v8::Function, reject_callback,
921       v8::Function::New(context, WasmStreamingPromiseFailedCallback,
922                         Utils::ToLocal(i::Handle<i::Object>::cast(data)), 1));
923 
924   // The parameter may be of type {Response} or of type {Promise<Response>}.
925   // Treat either case of parameter as Promise.resolve(parameter)
926   // as per https://www.w3.org/2001/tag/doc/promises-guide#resolve-arguments
927 
928   // Ending with:
929   //    return Promise.resolve(parameter).then(compile_callback);
930   ASSIGN(Promise::Resolver, input_resolver, Promise::Resolver::New(context));
931   if (!input_resolver->Resolve(context, args[0]).IsJust()) return;
932 
933   // We do not have any use of the result here. The {compile_callback} will
934   // start streaming compilation, which will eventually resolve the promise we
935   // set as result value.
936   USE(input_resolver->GetPromise()->Then(context, compile_callback,
937                                          reject_callback));
938 }
939 
940 // WebAssembly.instantiate(module, imports) -> WebAssembly.Instance
941 // WebAssembly.instantiate(bytes, imports) ->
942 //     {module: WebAssembly.Module, instance: WebAssembly.Instance}
WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value> & args)943 void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
944   constexpr const char* kAPIMethodName = "WebAssembly.instantiate()";
945   v8::Isolate* isolate = args.GetIsolate();
946   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
947   i_isolate->CountUsage(
948       v8::Isolate::UseCounterFeature::kWebAssemblyInstantiation);
949 
950   ScheduledErrorThrower thrower(i_isolate, kAPIMethodName);
951 
952   HandleScope scope(isolate);
953 
954   Local<Context> context = isolate->GetCurrentContext();
955 
956   ASSIGN(Promise::Resolver, promise_resolver, Promise::Resolver::New(context));
957   Local<Promise> promise = promise_resolver->GetPromise();
958   args.GetReturnValue().Set(promise);
959 
960   std::unique_ptr<i::wasm::InstantiationResultResolver> resolver(
961       new InstantiateModuleResultResolver(i_isolate,
962                                           Utils::OpenHandle(*promise)));
963 
964   Local<Value> first_arg_value = args[0];
965   i::Handle<i::Object> first_arg = Utils::OpenHandle(*first_arg_value);
966   if (!first_arg->IsJSObject()) {
967     thrower.TypeError(
968         "Argument 0 must be a buffer source or a WebAssembly.Module object");
969     resolver->OnInstantiationFailed(thrower.Reify());
970     return;
971   }
972 
973   // If args.Length < 2, this will be undefined - see FunctionCallbackInfo.
974   Local<Value> ffi = args[1];
975   i::MaybeHandle<i::JSReceiver> maybe_imports =
976       GetValueAsImports(ffi, &thrower);
977 
978   if (thrower.error()) {
979     resolver->OnInstantiationFailed(thrower.Reify());
980     return;
981   }
982 
983   if (first_arg->IsWasmModuleObject()) {
984     i::Handle<i::WasmModuleObject> module_obj =
985         i::Handle<i::WasmModuleObject>::cast(first_arg);
986 
987     i::wasm::GetWasmEngine()->AsyncInstantiate(i_isolate, std::move(resolver),
988                                                module_obj, maybe_imports);
989     return;
990   }
991 
992   bool is_shared = false;
993   auto bytes = GetFirstArgumentAsBytes(args, &thrower, &is_shared);
994   if (thrower.error()) {
995     resolver->OnInstantiationFailed(thrower.Reify());
996     return;
997   }
998 
999   // We start compilation now, we have no use for the
1000   // {InstantiationResultResolver}.
1001   resolver.reset();
1002 
1003   std::shared_ptr<i::wasm::CompilationResultResolver> compilation_resolver(
1004       new AsyncInstantiateCompileResultResolver(
1005           i_isolate, Utils::OpenHandle(*promise), maybe_imports));
1006 
1007   // The first parameter is a buffer source, we have to check if we are allowed
1008   // to compile it.
1009   if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
1010     thrower.CompileError("Wasm code generation disallowed by embedder");
1011     compilation_resolver->OnCompilationFailed(thrower.Reify());
1012     return;
1013   }
1014 
1015   // Asynchronous compilation handles copying wire bytes if necessary.
1016   auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
1017   i::wasm::GetWasmEngine()->AsyncCompile(i_isolate, enabled_features,
1018                                          std::move(compilation_resolver), bytes,
1019                                          is_shared, kAPIMethodName);
1020 }
1021 
GetIntegerProperty(v8::Isolate * isolate,ErrorThrower * thrower,Local<Context> context,v8::Local<v8::Value> value,i::Handle<i::String> property_name,int64_t * result,int64_t lower_bound,uint64_t upper_bound)1022 bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
1023                         Local<Context> context, v8::Local<v8::Value> value,
1024                         i::Handle<i::String> property_name, int64_t* result,
1025                         int64_t lower_bound, uint64_t upper_bound) {
1026   uint32_t number;
1027   if (!EnforceUint32(property_name, value, context, thrower, &number)) {
1028     return false;
1029   }
1030   if (number < lower_bound) {
1031     thrower->RangeError("Property '%s': value %" PRIu32
1032                         " is below the lower bound %" PRIx64,
1033                         property_name->ToCString().get(), number, lower_bound);
1034     return false;
1035   }
1036   if (number > upper_bound) {
1037     thrower->RangeError("Property '%s': value %" PRIu32
1038                         " is above the upper bound %" PRIu64,
1039                         property_name->ToCString().get(), number, upper_bound);
1040     return false;
1041   }
1042 
1043   *result = static_cast<int64_t>(number);
1044   return true;
1045 }
1046 
GetOptionalIntegerProperty(v8::Isolate * isolate,ErrorThrower * thrower,Local<Context> context,Local<v8::Object> object,Local<String> property,bool * has_property,int64_t * result,int64_t lower_bound,uint64_t upper_bound)1047 bool GetOptionalIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
1048                                 Local<Context> context,
1049                                 Local<v8::Object> object,
1050                                 Local<String> property, bool* has_property,
1051                                 int64_t* result, int64_t lower_bound,
1052                                 uint64_t upper_bound) {
1053   v8::Local<v8::Value> value;
1054   if (!object->Get(context, property).ToLocal(&value)) {
1055     return false;
1056   }
1057 
1058   // Web IDL: dictionary presence
1059   // https://heycam.github.io/webidl/#dfn-present
1060   if (value->IsUndefined()) {
1061     if (has_property != nullptr) *has_property = false;
1062     return true;
1063   }
1064 
1065   if (has_property != nullptr) *has_property = true;
1066   i::Handle<i::String> property_name = v8::Utils::OpenHandle(*property);
1067 
1068   return GetIntegerProperty(isolate, thrower, context, value, property_name,
1069                             result, lower_bound, upper_bound);
1070 }
1071 
1072 // Fetch 'initial' or 'minimum' property from object. If both are provided,
1073 // a TypeError is thrown.
1074 // TODO(aseemgarg): change behavior when the following bug is resolved:
1075 // https://github.com/WebAssembly/js-types/issues/6
GetInitialOrMinimumProperty(v8::Isolate * isolate,ErrorThrower * thrower,Local<Context> context,Local<v8::Object> object,int64_t * result,int64_t lower_bound,uint64_t upper_bound)1076 bool GetInitialOrMinimumProperty(v8::Isolate* isolate, ErrorThrower* thrower,
1077                                  Local<Context> context,
1078                                  Local<v8::Object> object, int64_t* result,
1079                                  int64_t lower_bound, uint64_t upper_bound) {
1080   bool has_initial = false;
1081   if (!GetOptionalIntegerProperty(isolate, thrower, context, object,
1082                                   v8_str(isolate, "initial"), &has_initial,
1083                                   result, lower_bound, upper_bound)) {
1084     return false;
1085   }
1086   auto enabled_features = i::wasm::WasmFeatures::FromIsolate(
1087       reinterpret_cast<i::Isolate*>(isolate));
1088   if (enabled_features.has_type_reflection()) {
1089     bool has_minimum = false;
1090     int64_t minimum = 0;
1091     if (!GetOptionalIntegerProperty(isolate, thrower, context, object,
1092                                     v8_str(isolate, "minimum"), &has_minimum,
1093                                     &minimum, lower_bound, upper_bound)) {
1094       return false;
1095     }
1096     if (has_initial && has_minimum) {
1097       thrower->TypeError(
1098           "The properties 'initial' and 'minimum' are not allowed at the same "
1099           "time");
1100       return false;
1101     }
1102     if (has_minimum) {
1103       // Only {minimum} exists, so we use {minimum} as {initial}.
1104       has_initial = true;
1105       *result = minimum;
1106     }
1107   }
1108   if (!has_initial) {
1109     // TODO(aseemgarg): update error message when the spec issue is resolved.
1110     thrower->TypeError("Property 'initial' is required");
1111     return false;
1112   }
1113   return true;
1114 }
1115 
1116 namespace {
DefaultReferenceValue(i::Isolate * isolate,i::wasm::ValueType type)1117 i::Handle<i::Object> DefaultReferenceValue(i::Isolate* isolate,
1118                                            i::wasm::ValueType type) {
1119   if (type == i::wasm::kWasmFuncRef) {
1120     return isolate->factory()->null_value();
1121   }
1122   if (type.is_reference()) {
1123     return isolate->factory()->undefined_value();
1124   }
1125   UNREACHABLE();
1126 }
1127 }  // namespace
1128 
1129 // new WebAssembly.Table(args) -> WebAssembly.Table
WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value> & args)1130 void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
1131   v8::Isolate* isolate = args.GetIsolate();
1132   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1133   HandleScope scope(isolate);
1134   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table()");
1135   if (!args.IsConstructCall()) {
1136     thrower.TypeError("WebAssembly.Table must be invoked with 'new'");
1137     return;
1138   }
1139   if (!args[0]->IsObject()) {
1140     thrower.TypeError("Argument 0 must be a table descriptor");
1141     return;
1142   }
1143   Local<Context> context = isolate->GetCurrentContext();
1144   Local<v8::Object> descriptor = Local<Object>::Cast(args[0]);
1145   i::wasm::ValueType type;
1146   // The descriptor's 'element'.
1147   {
1148     v8::MaybeLocal<v8::Value> maybe =
1149         descriptor->Get(context, v8_str(isolate, "element"));
1150     v8::Local<v8::Value> value;
1151     if (!maybe.ToLocal(&value)) return;
1152     v8::Local<v8::String> string;
1153     if (!value->ToString(context).ToLocal(&string)) return;
1154     auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
1155     // The JS api uses 'anyfunc' instead of 'funcref'.
1156     if (string->StringEquals(v8_str(isolate, "anyfunc"))) {
1157       type = i::wasm::kWasmFuncRef;
1158     } else if (enabled_features.has_type_reflection() &&
1159                string->StringEquals(v8_str(isolate, "funcref"))) {
1160       // With the type reflection proposal, "funcref" replaces "anyfunc",
1161       // and anyfunc just becomes an alias for "funcref".
1162       type = i::wasm::kWasmFuncRef;
1163     } else if (string->StringEquals(v8_str(isolate, "externref"))) {
1164       // externref is known as anyref as of wasm-gc.
1165       type = i::wasm::kWasmAnyRef;
1166     } else {
1167       thrower.TypeError(
1168           "Descriptor property 'element' must be a WebAssembly reference type");
1169       return;
1170     }
1171   }
1172 
1173   int64_t initial = 0;
1174   if (!GetInitialOrMinimumProperty(isolate, &thrower, context, descriptor,
1175                                    &initial, 0,
1176                                    i::wasm::max_table_init_entries())) {
1177     return;
1178   }
1179   // The descriptor's 'maximum'.
1180   int64_t maximum = -1;
1181   bool has_maximum = true;
1182   if (!GetOptionalIntegerProperty(isolate, &thrower, context, descriptor,
1183                                   v8_str(isolate, "maximum"), &has_maximum,
1184                                   &maximum, initial,
1185                                   std::numeric_limits<uint32_t>::max())) {
1186     return;
1187   }
1188 
1189   i::Handle<i::FixedArray> fixed_array;
1190   i::Handle<i::WasmTableObject> table_obj =
1191       i::WasmTableObject::New(i_isolate, i::Handle<i::WasmInstanceObject>(),
1192                               type, static_cast<uint32_t>(initial), has_maximum,
1193                               static_cast<uint32_t>(maximum), &fixed_array,
1194                               DefaultReferenceValue(i_isolate, type));
1195 
1196   // The infrastructure for `new Foo` calls allocates an object, which is
1197   // available here as {args.This()}. We're going to discard this object
1198   // and use {table_obj} instead, but it does have the correct prototype,
1199   // which we must harvest from it. This makes a difference when the JS
1200   // constructor function wasn't {WebAssembly.Table} directly, but some
1201   // subclass: {table_obj} has {WebAssembly.Table}'s prototype at this
1202   // point, so we must overwrite that with the correct prototype for {Foo}.
1203   if (!TransferPrototype(i_isolate, table_obj,
1204                          Utils::OpenHandle(*args.This()))) {
1205     return;
1206   }
1207 
1208   if (initial > 0 && args.Length() >= 2 && !args[1]->IsUndefined()) {
1209     i::Handle<i::Object> element = Utils::OpenHandle(*args[1]);
1210     if (!i::WasmTableObject::IsValidElement(i_isolate, table_obj, element)) {
1211       thrower.TypeError(
1212           "Argument 2 must be undefined, null, or a value of type compatible "
1213           "with the type of the new table.");
1214       return;
1215     }
1216     // TODO(7748): Generalize this if other table types are allowed.
1217     if (type == i::wasm::kWasmFuncRef && !element->IsNull()) {
1218       element = i::WasmInternalFunction::FromExternal(element, i_isolate)
1219                     .ToHandleChecked();
1220     }
1221     for (uint32_t index = 0; index < static_cast<uint32_t>(initial); ++index) {
1222       i::WasmTableObject::Set(i_isolate, table_obj, index, element);
1223     }
1224   }
1225   v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
1226   return_value.Set(Utils::ToLocal(i::Handle<i::JSObject>::cast(table_obj)));
1227 }
1228 
WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value> & args)1229 void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
1230   v8::Isolate* isolate = args.GetIsolate();
1231   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1232   HandleScope scope(isolate);
1233   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory()");
1234   if (!args.IsConstructCall()) {
1235     thrower.TypeError("WebAssembly.Memory must be invoked with 'new'");
1236     return;
1237   }
1238   if (!args[0]->IsObject()) {
1239     thrower.TypeError("Argument 0 must be a memory descriptor");
1240     return;
1241   }
1242   Local<Context> context = isolate->GetCurrentContext();
1243   Local<v8::Object> descriptor = Local<Object>::Cast(args[0]);
1244 
1245   int64_t initial = 0;
1246   if (!GetInitialOrMinimumProperty(isolate, &thrower, context, descriptor,
1247                                    &initial, 0, i::wasm::kSpecMaxMemoryPages)) {
1248     return;
1249   }
1250   // The descriptor's 'maximum'.
1251   int64_t maximum = i::WasmMemoryObject::kNoMaximum;
1252   if (!GetOptionalIntegerProperty(isolate, &thrower, context, descriptor,
1253                                   v8_str(isolate, "maximum"), nullptr, &maximum,
1254                                   initial, i::wasm::kSpecMaxMemoryPages)) {
1255     return;
1256   }
1257 
1258   auto shared = i::SharedFlag::kNotShared;
1259   auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
1260   if (enabled_features.has_threads()) {
1261     // Shared property of descriptor
1262     Local<String> shared_key = v8_str(isolate, "shared");
1263     v8::MaybeLocal<v8::Value> maybe_value =
1264         descriptor->Get(context, shared_key);
1265     v8::Local<v8::Value> value;
1266     if (maybe_value.ToLocal(&value)) {
1267       shared = value->BooleanValue(isolate) ? i::SharedFlag::kShared
1268                                             : i::SharedFlag::kNotShared;
1269     } else {
1270       DCHECK(i_isolate->has_scheduled_exception());
1271       return;
1272     }
1273 
1274     // Throw TypeError if shared is true, and the descriptor has no "maximum"
1275     if (shared == i::SharedFlag::kShared && maximum == -1) {
1276       thrower.TypeError(
1277           "If shared is true, maximum property should be defined.");
1278       return;
1279     }
1280   }
1281 
1282   i::Handle<i::JSObject> memory_obj;
1283   if (!i::WasmMemoryObject::New(i_isolate, static_cast<int>(initial),
1284                                 static_cast<int>(maximum), shared)
1285            .ToHandle(&memory_obj)) {
1286     thrower.RangeError("could not allocate memory");
1287     return;
1288   }
1289 
1290   // The infrastructure for `new Foo` calls allocates an object, which is
1291   // available here as {args.This()}. We're going to discard this object
1292   // and use {memory_obj} instead, but it does have the correct prototype,
1293   // which we must harvest from it. This makes a difference when the JS
1294   // constructor function wasn't {WebAssembly.Memory} directly, but some
1295   // subclass: {memory_obj} has {WebAssembly.Memory}'s prototype at this
1296   // point, so we must overwrite that with the correct prototype for {Foo}.
1297   if (!TransferPrototype(i_isolate, memory_obj,
1298                          Utils::OpenHandle(*args.This()))) {
1299     return;
1300   }
1301 
1302   if (shared == i::SharedFlag::kShared) {
1303     i::Handle<i::JSArrayBuffer> buffer(
1304         i::Handle<i::WasmMemoryObject>::cast(memory_obj)->array_buffer(),
1305         i_isolate);
1306     Maybe<bool> result =
1307         buffer->SetIntegrityLevel(buffer, i::FROZEN, i::kDontThrow);
1308     if (!result.FromJust()) {
1309       thrower.TypeError(
1310           "Status of setting SetIntegrityLevel of buffer is false.");
1311       return;
1312     }
1313   }
1314   args.GetReturnValue().Set(Utils::ToLocal(memory_obj));
1315 }
1316 
1317 // Determines the type encoded in a value type property (e.g. type reflection).
1318 // Returns false if there was an exception, true upon success. On success the
1319 // outgoing {type} is set accordingly, or set to {wasm::kWasmVoid} in case the
1320 // type could not be properly recognized.
GetValueType(Isolate * isolate,MaybeLocal<Value> maybe,Local<Context> context,i::wasm::ValueType * type,i::wasm::WasmFeatures enabled_features)1321 bool GetValueType(Isolate* isolate, MaybeLocal<Value> maybe,
1322                   Local<Context> context, i::wasm::ValueType* type,
1323                   i::wasm::WasmFeatures enabled_features) {
1324   v8::Local<v8::Value> value;
1325   if (!maybe.ToLocal(&value)) return false;
1326   v8::Local<v8::String> string;
1327   if (!value->ToString(context).ToLocal(&string)) return false;
1328   if (string->StringEquals(v8_str(isolate, "i32"))) {
1329     *type = i::wasm::kWasmI32;
1330   } else if (string->StringEquals(v8_str(isolate, "f32"))) {
1331     *type = i::wasm::kWasmF32;
1332   } else if (string->StringEquals(v8_str(isolate, "i64"))) {
1333     *type = i::wasm::kWasmI64;
1334   } else if (string->StringEquals(v8_str(isolate, "f64"))) {
1335     *type = i::wasm::kWasmF64;
1336   } else if (string->StringEquals(v8_str(isolate, "externref"))) {
1337     *type = i::wasm::kWasmAnyRef;
1338   } else if (enabled_features.has_type_reflection() &&
1339              string->StringEquals(v8_str(isolate, "funcref"))) {
1340     // The type reflection proposal renames "anyfunc" to "funcref", and makes
1341     // "anyfunc" an alias of "funcref".
1342     *type = i::wasm::kWasmFuncRef;
1343   } else if (string->StringEquals(v8_str(isolate, "anyfunc"))) {
1344     // The JS api spec uses 'anyfunc' instead of 'funcref'.
1345     *type = i::wasm::kWasmFuncRef;
1346   } else if (enabled_features.has_gc() &&
1347              string->StringEquals(v8_str(isolate, "eqref"))) {
1348     *type = i::wasm::kWasmEqRef;
1349   } else {
1350     // Unrecognized type.
1351     *type = i::wasm::kWasmVoid;
1352   }
1353   return true;
1354 }
1355 
1356 namespace {
1357 
ToI32(Local<v8::Value> value,Local<Context> context,int32_t * i32_value)1358 bool ToI32(Local<v8::Value> value, Local<Context> context, int32_t* i32_value) {
1359   if (!value->IsUndefined()) {
1360     v8::Local<v8::Int32> int32_value;
1361     if (!value->ToInt32(context).ToLocal(&int32_value)) return false;
1362     if (!int32_value->Int32Value(context).To(i32_value)) return false;
1363   }
1364   return true;
1365 }
1366 
ToI64(Local<v8::Value> value,Local<Context> context,int64_t * i64_value)1367 bool ToI64(Local<v8::Value> value, Local<Context> context, int64_t* i64_value) {
1368   if (!value->IsUndefined()) {
1369     v8::Local<v8::BigInt> bigint_value;
1370     if (!value->ToBigInt(context).ToLocal(&bigint_value)) return false;
1371     *i64_value = bigint_value->Int64Value();
1372   }
1373   return true;
1374 }
1375 
ToF32(Local<v8::Value> value,Local<Context> context,float * f32_value)1376 bool ToF32(Local<v8::Value> value, Local<Context> context, float* f32_value) {
1377   if (!value->IsUndefined()) {
1378     double f64_value = 0;
1379     v8::Local<v8::Number> number_value;
1380     if (!value->ToNumber(context).ToLocal(&number_value)) return false;
1381     if (!number_value->NumberValue(context).To(&f64_value)) return false;
1382     *f32_value = i::DoubleToFloat32(f64_value);
1383   }
1384   return true;
1385 }
1386 
ToF64(Local<v8::Value> value,Local<Context> context,double * f64_value)1387 bool ToF64(Local<v8::Value> value, Local<Context> context, double* f64_value) {
1388   if (!value->IsUndefined()) {
1389     v8::Local<v8::Number> number_value;
1390     if (!value->ToNumber(context).ToLocal(&number_value)) return false;
1391     if (!number_value->NumberValue(context).To(f64_value)) return false;
1392   }
1393   return true;
1394 }
1395 
1396 }  // namespace
1397 
1398 // WebAssembly.Global
WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value> & args)1399 void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
1400   v8::Isolate* isolate = args.GetIsolate();
1401   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1402   HandleScope scope(isolate);
1403   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Global()");
1404   if (!args.IsConstructCall()) {
1405     thrower.TypeError("WebAssembly.Global must be invoked with 'new'");
1406     return;
1407   }
1408   if (!args[0]->IsObject()) {
1409     thrower.TypeError("Argument 0 must be a global descriptor");
1410     return;
1411   }
1412   Local<Context> context = isolate->GetCurrentContext();
1413   Local<v8::Object> descriptor = Local<Object>::Cast(args[0]);
1414   auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
1415 
1416   // The descriptor's 'mutable'.
1417   bool is_mutable = false;
1418   {
1419     Local<String> mutable_key = v8_str(isolate, "mutable");
1420     v8::MaybeLocal<v8::Value> maybe = descriptor->Get(context, mutable_key);
1421     v8::Local<v8::Value> value;
1422     if (maybe.ToLocal(&value)) {
1423       is_mutable = value->BooleanValue(isolate);
1424     } else {
1425       DCHECK(i_isolate->has_scheduled_exception());
1426       return;
1427     }
1428   }
1429 
1430   // The descriptor's type, called 'value'. It is called 'value' because this
1431   // descriptor is planned to be re-used as the global's type for reflection,
1432   // so calling it 'type' is redundant.
1433   i::wasm::ValueType type;
1434   {
1435     v8::MaybeLocal<v8::Value> maybe =
1436         descriptor->Get(context, v8_str(isolate, "value"));
1437     if (!GetValueType(isolate, maybe, context, &type, enabled_features)) return;
1438     if (type == i::wasm::kWasmVoid) {
1439       thrower.TypeError(
1440           "Descriptor property 'value' must be a WebAssembly type");
1441       return;
1442     }
1443   }
1444 
1445   const uint32_t offset = 0;
1446   i::MaybeHandle<i::WasmGlobalObject> maybe_global_obj =
1447       i::WasmGlobalObject::New(i_isolate, i::Handle<i::WasmInstanceObject>(),
1448                                i::MaybeHandle<i::JSArrayBuffer>(),
1449                                i::MaybeHandle<i::FixedArray>(), type, offset,
1450                                is_mutable);
1451 
1452   i::Handle<i::WasmGlobalObject> global_obj;
1453   if (!maybe_global_obj.ToHandle(&global_obj)) {
1454     thrower.RangeError("could not allocate memory");
1455     return;
1456   }
1457 
1458   // The infrastructure for `new Foo` calls allocates an object, which is
1459   // available here as {args.This()}. We're going to discard this object
1460   // and use {global_obj} instead, but it does have the correct prototype,
1461   // which we must harvest from it. This makes a difference when the JS
1462   // constructor function wasn't {WebAssembly.Global} directly, but some
1463   // subclass: {global_obj} has {WebAssembly.Global}'s prototype at this
1464   // point, so we must overwrite that with the correct prototype for {Foo}.
1465   if (!TransferPrototype(i_isolate, global_obj,
1466                          Utils::OpenHandle(*args.This()))) {
1467     return;
1468   }
1469 
1470   // Convert value to a WebAssembly value, the default value is 0.
1471   Local<v8::Value> value = Local<Value>::Cast(args[1]);
1472   switch (type.kind()) {
1473     case i::wasm::kI32: {
1474       int32_t i32_value = 0;
1475       if (!ToI32(value, context, &i32_value)) return;
1476       global_obj->SetI32(i32_value);
1477       break;
1478     }
1479     case i::wasm::kI64: {
1480       int64_t i64_value = 0;
1481       if (!ToI64(value, context, &i64_value)) return;
1482       global_obj->SetI64(i64_value);
1483       break;
1484     }
1485     case i::wasm::kF32: {
1486       float f32_value = 0;
1487       if (!ToF32(value, context, &f32_value)) return;
1488       global_obj->SetF32(f32_value);
1489       break;
1490     }
1491     case i::wasm::kF64: {
1492       double f64_value = 0;
1493       if (!ToF64(value, context, &f64_value)) return;
1494       global_obj->SetF64(f64_value);
1495       break;
1496     }
1497     case i::wasm::kRef:
1498     case i::wasm::kOptRef: {
1499       switch (type.heap_representation()) {
1500         case i::wasm::HeapType::kAny: {
1501           if (args.Length() < 2) {
1502             // When no initial value is provided, we have to use the WebAssembly
1503             // default value 'null', and not the JS default value 'undefined'.
1504             global_obj->SetExternRef(i_isolate->factory()->null_value());
1505             break;
1506           }
1507           global_obj->SetExternRef(Utils::OpenHandle(*value));
1508           break;
1509         }
1510         case i::wasm::HeapType::kFunc: {
1511           if (args.Length() < 2) {
1512             // When no initial value is provided, we have to use the WebAssembly
1513             // default value 'null', and not the JS default value 'undefined'.
1514             global_obj->SetFuncRef(i_isolate,
1515                                    i_isolate->factory()->null_value());
1516             break;
1517           }
1518 
1519           if (!global_obj->SetFuncRef(i_isolate, Utils::OpenHandle(*value))) {
1520             thrower.TypeError(
1521                 "The value of funcref globals must be null or an "
1522                 "exported function");
1523           }
1524           break;
1525         }
1526         case internal::wasm::HeapType::kBottom:
1527           UNREACHABLE();
1528         case i::wasm::HeapType::kEq:
1529         case internal::wasm::HeapType::kI31:
1530         case internal::wasm::HeapType::kData:
1531         case internal::wasm::HeapType::kArray:
1532         default:
1533           // TODO(7748): Implement these.
1534           UNIMPLEMENTED();
1535       }
1536       break;
1537     }
1538     case i::wasm::kRtt:
1539       // TODO(7748): Implement.
1540       UNIMPLEMENTED();
1541     case i::wasm::kI8:
1542     case i::wasm::kI16:
1543     case i::wasm::kVoid:
1544     case i::wasm::kS128:
1545     case i::wasm::kBottom:
1546       UNREACHABLE();
1547   }
1548 
1549   i::Handle<i::JSObject> global_js_object(global_obj);
1550   args.GetReturnValue().Set(Utils::ToLocal(global_js_object));
1551 }
1552 
1553 namespace {
1554 
GetIterableLength(i::Isolate * isolate,Local<Context> context,Local<Object> iterable)1555 uint32_t GetIterableLength(i::Isolate* isolate, Local<Context> context,
1556                            Local<Object> iterable) {
1557   Local<String> length = Utils::ToLocal(isolate->factory()->length_string());
1558   MaybeLocal<Value> property = iterable->Get(context, length);
1559   if (property.IsEmpty()) return i::kMaxUInt32;
1560   MaybeLocal<Uint32> number = property.ToLocalChecked()->ToArrayIndex(context);
1561   if (number.IsEmpty()) return i::kMaxUInt32;
1562   DCHECK_NE(i::kMaxUInt32, number.ToLocalChecked()->Value());
1563   return number.ToLocalChecked()->Value();
1564 }
1565 
1566 }  // namespace
1567 
1568 // WebAssembly.Tag
WebAssemblyTag(const v8::FunctionCallbackInfo<v8::Value> & args)1569 void WebAssemblyTag(const v8::FunctionCallbackInfo<v8::Value>& args) {
1570   v8::Isolate* isolate = args.GetIsolate();
1571   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1572   HandleScope scope(isolate);
1573 
1574   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Tag()");
1575   if (!args.IsConstructCall()) {
1576     thrower.TypeError("WebAssembly.Tag must be invoked with 'new'");
1577     return;
1578   }
1579   if (!args[0]->IsObject()) {
1580     thrower.TypeError("Argument 0 must be a tag type");
1581     return;
1582   }
1583 
1584   Local<Object> event_type = Local<Object>::Cast(args[0]);
1585   Local<Context> context = isolate->GetCurrentContext();
1586   auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
1587 
1588   // Load the 'parameters' property of the event type.
1589   Local<String> parameters_key = v8_str(isolate, "parameters");
1590   v8::MaybeLocal<v8::Value> parameters_maybe =
1591       event_type->Get(context, parameters_key);
1592   v8::Local<v8::Value> parameters_value;
1593   if (!parameters_maybe.ToLocal(&parameters_value) ||
1594       !parameters_value->IsObject()) {
1595     thrower.TypeError("Argument 0 must be a tag type with 'parameters'");
1596     return;
1597   }
1598   Local<Object> parameters = parameters_value.As<Object>();
1599   uint32_t parameters_len = GetIterableLength(i_isolate, context, parameters);
1600   if (parameters_len == i::kMaxUInt32) {
1601     thrower.TypeError("Argument 0 contains parameters without 'length'");
1602     return;
1603   }
1604   if (parameters_len > i::wasm::kV8MaxWasmFunctionParams) {
1605     thrower.TypeError("Argument 0 contains too many parameters");
1606     return;
1607   }
1608 
1609   // Decode the tag type and construct a signature.
1610   std::vector<i::wasm::ValueType> param_types(parameters_len,
1611                                               i::wasm::kWasmVoid);
1612   for (uint32_t i = 0; i < parameters_len; ++i) {
1613     i::wasm::ValueType& type = param_types[i];
1614     MaybeLocal<Value> maybe = parameters->Get(context, i);
1615     if (!GetValueType(isolate, maybe, context, &type, enabled_features) ||
1616         type == i::wasm::kWasmVoid) {
1617       thrower.TypeError(
1618           "Argument 0 parameter type at index #%u must be a value type", i);
1619       return;
1620     }
1621   }
1622   const i::wasm::FunctionSig sig{0, parameters_len, param_types.data()};
1623   // Set the tag index to 0. It is only used for debugging purposes, and has no
1624   // meaningful value when declared outside of a wasm module.
1625   auto tag = i::WasmExceptionTag::New(i_isolate, 0);
1626   i::Handle<i::JSObject> tag_object =
1627       i::WasmTagObject::New(i_isolate, &sig, tag);
1628   args.GetReturnValue().Set(Utils::ToLocal(tag_object));
1629 }
1630 
1631 // WebAssembly.Suspender
WebAssemblySuspender(const v8::FunctionCallbackInfo<v8::Value> & args)1632 void WebAssemblySuspender(const v8::FunctionCallbackInfo<v8::Value>& args) {
1633   v8::Isolate* isolate = args.GetIsolate();
1634   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1635   HandleScope scope(isolate);
1636 
1637   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Suspender()");
1638   if (!args.IsConstructCall()) {
1639     thrower.TypeError("WebAssembly.Suspender must be invoked with 'new'");
1640     return;
1641   }
1642 
1643   i::Handle<i::JSObject> suspender = i::WasmSuspenderObject::New(i_isolate);
1644 
1645   // The infrastructure for `new Foo` calls allocates an object, which is
1646   // available here as {args.This()}. We're going to discard this object
1647   // and use {suspender} instead, but it does have the correct prototype,
1648   // which we must harvest from it. This makes a difference when the JS
1649   // constructor function wasn't {WebAssembly.Suspender} directly, but some
1650   // subclass: {suspender} has {WebAssembly.Suspender}'s prototype at this
1651   // point, so we must overwrite that with the correct prototype for {Foo}.
1652   if (!TransferPrototype(i_isolate, suspender,
1653                          Utils::OpenHandle(*args.This()))) {
1654     return;
1655   }
1656   args.GetReturnValue().Set(Utils::ToLocal(suspender));
1657 }
1658 
1659 namespace {
1660 
GetEncodedSize(i::Handle<i::WasmTagObject> tag_object)1661 uint32_t GetEncodedSize(i::Handle<i::WasmTagObject> tag_object) {
1662   auto serialized_sig = tag_object->serialized_signature();
1663   i::wasm::WasmTagSig sig{0, static_cast<size_t>(serialized_sig.length()),
1664                           reinterpret_cast<i::wasm::ValueType*>(
1665                               serialized_sig.GetDataStartAddress())};
1666   i::wasm::WasmTag tag(&sig);
1667   return i::WasmExceptionPackage::GetEncodedSize(&tag);
1668 }
1669 
EncodeExceptionValues(v8::Isolate * isolate,i::Handle<i::PodArray<i::wasm::ValueType>> signature,const Local<Value> & arg,ScheduledErrorThrower * thrower,i::Handle<i::FixedArray> values_out)1670 void EncodeExceptionValues(v8::Isolate* isolate,
1671                            i::Handle<i::PodArray<i::wasm::ValueType>> signature,
1672                            const Local<Value>& arg,
1673                            ScheduledErrorThrower* thrower,
1674                            i::Handle<i::FixedArray> values_out) {
1675   Local<Context> context = isolate->GetCurrentContext();
1676   uint32_t index = 0;
1677   if (!arg->IsObject()) {
1678     thrower->TypeError("Exception values must be an iterable object");
1679     return;
1680   }
1681   auto values = arg.As<Object>();
1682   for (int i = 0; i < signature->length(); ++i) {
1683     MaybeLocal<Value> maybe_value = values->Get(context, i);
1684     Local<Value> value = maybe_value.ToLocalChecked();
1685     i::wasm::ValueType type = signature->get(i);
1686     switch (type.kind()) {
1687       case i::wasm::kI32: {
1688         int32_t i32 = 0;
1689         if (!ToI32(value, context, &i32)) return;
1690         i::EncodeI32ExceptionValue(values_out, &index, i32);
1691         break;
1692       }
1693       case i::wasm::kI64: {
1694         int64_t i64 = 0;
1695         if (!ToI64(value, context, &i64)) return;
1696         i::EncodeI64ExceptionValue(values_out, &index, i64);
1697         break;
1698       }
1699       case i::wasm::kF32: {
1700         float f32 = 0;
1701         if (!ToF32(value, context, &f32)) return;
1702         int32_t i32 = bit_cast<int32_t>(f32);
1703         i::EncodeI32ExceptionValue(values_out, &index, i32);
1704         break;
1705       }
1706       case i::wasm::kF64: {
1707         double f64 = 0;
1708         if (!ToF64(value, context, &f64)) return;
1709         int64_t i64 = bit_cast<int64_t>(f64);
1710         i::EncodeI64ExceptionValue(values_out, &index, i64);
1711         break;
1712       }
1713       case i::wasm::kRef:
1714       case i::wasm::kOptRef:
1715         switch (type.heap_representation()) {
1716           case i::wasm::HeapType::kFunc:
1717           case i::wasm::HeapType::kAny:
1718           case i::wasm::HeapType::kEq:
1719           case i::wasm::HeapType::kI31:
1720           case i::wasm::HeapType::kData:
1721           case i::wasm::HeapType::kArray:
1722             values_out->set(index++, *Utils::OpenHandle(*value));
1723             break;
1724           case internal::wasm::HeapType::kBottom:
1725             UNREACHABLE();
1726           default:
1727             // TODO(7748): Add support for custom struct/array types.
1728             UNIMPLEMENTED();
1729         }
1730         break;
1731       case i::wasm::kRtt:
1732       case i::wasm::kI8:
1733       case i::wasm::kI16:
1734       case i::wasm::kVoid:
1735       case i::wasm::kBottom:
1736       case i::wasm::kS128:
1737         UNREACHABLE();
1738     }
1739   }
1740 }
1741 
1742 }  // namespace
1743 
WebAssemblyException(const v8::FunctionCallbackInfo<v8::Value> & args)1744 void WebAssemblyException(const v8::FunctionCallbackInfo<v8::Value>& args) {
1745   v8::Isolate* isolate = args.GetIsolate();
1746   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1747   HandleScope scope(isolate);
1748 
1749   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Exception()");
1750   if (!args.IsConstructCall()) {
1751     thrower.TypeError("WebAssembly.Exception must be invoked with 'new'");
1752     return;
1753   }
1754   if (!args[0]->IsObject()) {
1755     thrower.TypeError("Argument 0 must be a WebAssembly tag");
1756     return;
1757   }
1758   i::Handle<i::Object> arg0 = Utils::OpenHandle(*args[0]);
1759   if (!i::HeapObject::cast(*arg0).IsWasmTagObject()) {
1760     thrower.TypeError("Argument 0 must be a WebAssembly tag");
1761     return;
1762   }
1763   i::Handle<i::WasmTagObject> tag_object =
1764       i::Handle<i::WasmTagObject>::cast(arg0);
1765   i::Handle<i::WasmExceptionTag> tag(
1766       i::WasmExceptionTag::cast(tag_object->tag()), i_isolate);
1767   uint32_t size = GetEncodedSize(tag_object);
1768   i::Handle<i::WasmExceptionPackage> runtime_exception =
1769       i::WasmExceptionPackage::New(i_isolate, tag, size);
1770   // The constructor above should guarantee that the cast below succeeds.
1771   i::Handle<i::FixedArray> values = i::Handle<i::FixedArray>::cast(
1772       i::WasmExceptionPackage::GetExceptionValues(i_isolate,
1773                                                   runtime_exception));
1774   i::Handle<i::PodArray<i::wasm::ValueType>> signature(
1775       tag_object->serialized_signature(), i_isolate);
1776   EncodeExceptionValues(isolate, signature, args[1], &thrower, values);
1777   if (thrower.error()) return;
1778   args.GetReturnValue().Set(
1779       Utils::ToLocal(i::Handle<i::Object>::cast(runtime_exception)));
1780 }
1781 
1782 // WebAssembly.Function
WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value> & args)1783 void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
1784   v8::Isolate* isolate = args.GetIsolate();
1785   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1786   HandleScope scope(isolate);
1787   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Function()");
1788   if (!args.IsConstructCall()) {
1789     thrower.TypeError("WebAssembly.Function must be invoked with 'new'");
1790     return;
1791   }
1792   if (!args[0]->IsObject()) {
1793     thrower.TypeError("Argument 0 must be a function type");
1794     return;
1795   }
1796   Local<Object> function_type = Local<Object>::Cast(args[0]);
1797   Local<Context> context = isolate->GetCurrentContext();
1798   auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
1799 
1800   // Load the 'parameters' property of the function type.
1801   Local<String> parameters_key = v8_str(isolate, "parameters");
1802   v8::MaybeLocal<v8::Value> parameters_maybe =
1803       function_type->Get(context, parameters_key);
1804   v8::Local<v8::Value> parameters_value;
1805   if (!parameters_maybe.ToLocal(&parameters_value) ||
1806       !parameters_value->IsObject()) {
1807     thrower.TypeError("Argument 0 must be a function type with 'parameters'");
1808     return;
1809   }
1810   Local<Object> parameters = parameters_value.As<Object>();
1811   uint32_t parameters_len = GetIterableLength(i_isolate, context, parameters);
1812   if (parameters_len == i::kMaxUInt32) {
1813     thrower.TypeError("Argument 0 contains parameters without 'length'");
1814     return;
1815   }
1816   if (parameters_len > i::wasm::kV8MaxWasmFunctionParams) {
1817     thrower.TypeError("Argument 0 contains too many parameters");
1818     return;
1819   }
1820 
1821   // Load the 'results' property of the function type.
1822   Local<String> results_key = v8_str(isolate, "results");
1823   v8::MaybeLocal<v8::Value> results_maybe =
1824       function_type->Get(context, results_key);
1825   v8::Local<v8::Value> results_value;
1826   if (!results_maybe.ToLocal(&results_value)) return;
1827   if (!results_value->IsObject()) {
1828     thrower.TypeError("Argument 0 must be a function type with 'results'");
1829     return;
1830   }
1831   Local<Object> results = results_value.As<Object>();
1832   uint32_t results_len = GetIterableLength(i_isolate, context, results);
1833   if (results_len == i::kMaxUInt32) {
1834     thrower.TypeError("Argument 0 contains results without 'length'");
1835     return;
1836   }
1837   if (results_len > i::wasm::kV8MaxWasmFunctionReturns) {
1838     thrower.TypeError("Argument 0 contains too many results");
1839     return;
1840   }
1841 
1842   // Decode the function type and construct a signature.
1843   i::Zone zone(i_isolate->allocator(), ZONE_NAME);
1844   i::wasm::FunctionSig::Builder builder(&zone, results_len, parameters_len);
1845   for (uint32_t i = 0; i < parameters_len; ++i) {
1846     i::wasm::ValueType type;
1847     MaybeLocal<Value> maybe = parameters->Get(context, i);
1848     if (!GetValueType(isolate, maybe, context, &type, enabled_features) ||
1849         type == i::wasm::kWasmVoid) {
1850       thrower.TypeError(
1851           "Argument 0 parameter type at index #%u must be a value type", i);
1852       return;
1853     }
1854     builder.AddParam(type);
1855   }
1856   for (uint32_t i = 0; i < results_len; ++i) {
1857     i::wasm::ValueType type;
1858     MaybeLocal<Value> maybe = results->Get(context, i);
1859     if (!GetValueType(isolate, maybe, context, &type, enabled_features)) return;
1860     if (type == i::wasm::kWasmVoid) {
1861       thrower.TypeError(
1862           "Argument 0 result type at index #%u must be a value type", i);
1863       return;
1864     }
1865     builder.AddReturn(type);
1866   }
1867 
1868   if (!args[1]->IsFunction()) {
1869     thrower.TypeError("Argument 1 must be a function");
1870     return;
1871   }
1872   const i::wasm::FunctionSig* sig = builder.Build();
1873 
1874   i::Handle<i::JSReceiver> callable =
1875       Utils::OpenHandle(*args[1].As<Function>());
1876   if (i::WasmExportedFunction::IsWasmExportedFunction(*callable)) {
1877     if (*i::Handle<i::WasmExportedFunction>::cast(callable)->sig() == *sig) {
1878       args.GetReturnValue().Set(Utils::ToLocal(callable));
1879       return;
1880     }
1881 
1882     thrower.TypeError(
1883         "The signature of Argument 1 (a WebAssembly function) does "
1884         "not match the signature specified in Argument 0");
1885     return;
1886   }
1887 
1888   if (i::WasmJSFunction::IsWasmJSFunction(*callable)) {
1889     if (i::Handle<i::WasmJSFunction>::cast(callable)->MatchesSignature(sig)) {
1890       args.GetReturnValue().Set(Utils::ToLocal(callable));
1891       return;
1892     }
1893 
1894     thrower.TypeError(
1895         "The signature of Argument 1 (a WebAssembly function) does "
1896         "not match the signature specified in Argument 0");
1897     return;
1898   }
1899 
1900   i::Handle<i::JSFunction> result = i::WasmJSFunction::New(
1901       i_isolate, sig, callable, i::Handle<i::HeapObject>());
1902   args.GetReturnValue().Set(Utils::ToLocal(result));
1903 }
1904 
1905 // WebAssembly.Function.type(WebAssembly.Function) -> FunctionType
WebAssemblyFunctionType(const v8::FunctionCallbackInfo<v8::Value> & args)1906 void WebAssemblyFunctionType(const v8::FunctionCallbackInfo<v8::Value>& args) {
1907   v8::Isolate* isolate = args.GetIsolate();
1908   HandleScope scope(isolate);
1909   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1910   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Function.type()");
1911 
1912   const i::wasm::FunctionSig* sig;
1913   i::Zone zone(i_isolate->allocator(), ZONE_NAME);
1914   i::Handle<i::Object> arg0 = Utils::OpenHandle(*args[0]);
1915   if (i::WasmExportedFunction::IsWasmExportedFunction(*arg0)) {
1916     auto wasm_exported_function =
1917         i::Handle<i::WasmExportedFunction>::cast(arg0);
1918     auto sfi = handle(wasm_exported_function->shared(), i_isolate);
1919     i::Handle<i::WasmExportedFunctionData> data =
1920         handle(sfi->wasm_exported_function_data(), i_isolate);
1921     sig = wasm_exported_function->sig();
1922     if (!data->suspender().IsUndefined()) {
1923       // If this export is wrapped by a Suspender, the function returns a
1924       // promise as an externref instead of the original return type.
1925       size_t param_count = sig->parameter_count();
1926       i::wasm::FunctionSig::Builder builder(&zone, 1, param_count);
1927       for (size_t i = 0; i < param_count; ++i) {
1928         builder.AddParam(sig->GetParam(0));
1929       }
1930       builder.AddReturn(i::wasm::kWasmAnyRef);
1931       sig = builder.Build();
1932     }
1933   } else if (i::WasmJSFunction::IsWasmJSFunction(*arg0)) {
1934     sig = i::Handle<i::WasmJSFunction>::cast(arg0)->GetSignature(&zone);
1935   } else {
1936     thrower.TypeError("Argument 0 must be a WebAssembly.Function");
1937     return;
1938   }
1939 
1940   auto type = i::wasm::GetTypeForFunction(i_isolate, sig);
1941   args.GetReturnValue().Set(Utils::ToLocal(type));
1942 }
1943 
1944 constexpr const char* kName_WasmGlobalObject = "WebAssembly.Global";
1945 constexpr const char* kName_WasmMemoryObject = "WebAssembly.Memory";
1946 constexpr const char* kName_WasmInstanceObject = "WebAssembly.Instance";
1947 constexpr const char* kName_WasmSuspenderObject = "WebAssembly.Suspender";
1948 constexpr const char* kName_WasmTableObject = "WebAssembly.Table";
1949 constexpr const char* kName_WasmTagObject = "WebAssembly.Tag";
1950 constexpr const char* kName_WasmExceptionPackage = "WebAssembly.Exception";
1951 
1952 #define EXTRACT_THIS(var, WasmType)                                  \
1953   i::Handle<i::WasmType> var;                                        \
1954   {                                                                  \
1955     i::Handle<i::Object> this_arg = Utils::OpenHandle(*args.This()); \
1956     if (!this_arg->Is##WasmType()) {                                 \
1957       thrower.TypeError("Receiver is not a %s", kName_##WasmType);   \
1958       return;                                                        \
1959     }                                                                \
1960     var = i::Handle<i::WasmType>::cast(this_arg);                    \
1961   }
1962 
WebAssemblyInstanceGetExports(const v8::FunctionCallbackInfo<v8::Value> & args)1963 void WebAssemblyInstanceGetExports(
1964     const v8::FunctionCallbackInfo<v8::Value>& args) {
1965   v8::Isolate* isolate = args.GetIsolate();
1966   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1967   HandleScope scope(isolate);
1968   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Instance.exports()");
1969   EXTRACT_THIS(receiver, WasmInstanceObject);
1970   i::Handle<i::JSObject> exports_object(receiver->exports_object(), i_isolate);
1971   args.GetReturnValue().Set(Utils::ToLocal(exports_object));
1972 }
1973 
WebAssemblyTableGetLength(const v8::FunctionCallbackInfo<v8::Value> & args)1974 void WebAssemblyTableGetLength(
1975     const v8::FunctionCallbackInfo<v8::Value>& args) {
1976   v8::Isolate* isolate = args.GetIsolate();
1977   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1978   HandleScope scope(isolate);
1979   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.length()");
1980   EXTRACT_THIS(receiver, WasmTableObject);
1981   args.GetReturnValue().Set(
1982       v8::Number::New(isolate, receiver->current_length()));
1983 }
1984 
1985 // WebAssembly.Table.grow(num, init_value = null) -> num
WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value> & args)1986 void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
1987   v8::Isolate* isolate = args.GetIsolate();
1988   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1989   HandleScope scope(isolate);
1990   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.grow()");
1991   Local<Context> context = isolate->GetCurrentContext();
1992   EXTRACT_THIS(receiver, WasmTableObject);
1993 
1994   uint32_t grow_by;
1995   if (!EnforceUint32("Argument 0", args[0], context, &thrower, &grow_by)) {
1996     return;
1997   }
1998 
1999   i::Handle<i::Object> init_value;
2000 
2001   if (args.Length() >= 2 && !args[1]->IsUndefined()) {
2002     init_value = Utils::OpenHandle(*args[1]);
2003     if (!i::WasmTableObject::IsValidElement(i_isolate, receiver, init_value)) {
2004       thrower.TypeError("Argument 1 must be a valid type for the table");
2005       return;
2006     }
2007   } else {
2008     init_value = DefaultReferenceValue(i_isolate, receiver->type());
2009   }
2010 
2011   // TODO(7748): Generalize this if other table types are allowed.
2012   bool has_function_type =
2013       receiver->type() == i::wasm::kWasmFuncRef || receiver->type().has_index();
2014   if (has_function_type && !init_value->IsNull()) {
2015     init_value = i::WasmInternalFunction::FromExternal(init_value, i_isolate)
2016                      .ToHandleChecked();
2017   }
2018 
2019   int old_size =
2020       i::WasmTableObject::Grow(i_isolate, receiver, grow_by, init_value);
2021 
2022   if (old_size < 0) {
2023     thrower.RangeError("failed to grow table by %u", grow_by);
2024     return;
2025   }
2026   v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
2027   return_value.Set(old_size);
2028 }
2029 
2030 // WebAssembly.Table.get(num) -> any
WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value> & args)2031 void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) {
2032   v8::Isolate* isolate = args.GetIsolate();
2033   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2034   HandleScope scope(isolate);
2035   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.get()");
2036   Local<Context> context = isolate->GetCurrentContext();
2037   EXTRACT_THIS(receiver, WasmTableObject);
2038 
2039   uint32_t index;
2040   if (!EnforceUint32("Argument 0", args[0], context, &thrower, &index)) {
2041     return;
2042   }
2043   if (!i::WasmTableObject::IsInBounds(i_isolate, receiver, index)) {
2044     thrower.RangeError("invalid index %u into function table", index);
2045     return;
2046   }
2047 
2048   i::Handle<i::Object> result =
2049       i::WasmTableObject::Get(i_isolate, receiver, index);
2050   if (result->IsWasmInternalFunction()) {
2051     result =
2052         handle(i::Handle<i::WasmInternalFunction>::cast(result)->external(),
2053                i_isolate);
2054   }
2055 
2056   v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
2057   return_value.Set(Utils::ToLocal(result));
2058 }
2059 
2060 // WebAssembly.Table.set(num, any)
WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value> & args)2061 void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
2062   v8::Isolate* isolate = args.GetIsolate();
2063   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2064   HandleScope scope(isolate);
2065   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.set()");
2066   Local<Context> context = isolate->GetCurrentContext();
2067   EXTRACT_THIS(table_object, WasmTableObject);
2068 
2069   // Parameter 0.
2070   uint32_t index;
2071   if (!EnforceUint32("Argument 0", args[0], context, &thrower, &index)) {
2072     return;
2073   }
2074   if (!i::WasmTableObject::IsInBounds(i_isolate, table_object, index)) {
2075     thrower.RangeError("invalid index %u into function table", index);
2076     return;
2077   }
2078 
2079   i::Handle<i::Object> element =
2080       args.Length() >= 2
2081           ? Utils::OpenHandle(*args[1])
2082           : DefaultReferenceValue(i_isolate, table_object->type());
2083 
2084   if (!i::WasmTableObject::IsValidElement(i_isolate, table_object, element)) {
2085     thrower.TypeError("Argument 1 is invalid for table of type %s",
2086                       table_object->type().name().c_str());
2087     return;
2088   }
2089 
2090   i::Handle<i::Object> external_element;
2091   bool is_external = i::WasmInternalFunction::FromExternal(element, i_isolate)
2092                          .ToHandle(&external_element);
2093 
2094   i::WasmTableObject::Set(i_isolate, table_object, index,
2095                           is_external ? external_element : element);
2096 }
2097 
2098 // WebAssembly.Table.type() -> TableType
WebAssemblyTableType(const v8::FunctionCallbackInfo<v8::Value> & args)2099 void WebAssemblyTableType(const v8::FunctionCallbackInfo<v8::Value>& args) {
2100   v8::Isolate* isolate = args.GetIsolate();
2101   HandleScope scope(isolate);
2102   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2103   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.type()");
2104 
2105   EXTRACT_THIS(table, WasmTableObject);
2106   base::Optional<uint32_t> max_size;
2107   if (!table->maximum_length().IsUndefined()) {
2108     uint64_t max_size64 = table->maximum_length().Number();
2109     DCHECK_LE(max_size64, std::numeric_limits<uint32_t>::max());
2110     max_size.emplace(static_cast<uint32_t>(max_size64));
2111   }
2112   auto type = i::wasm::GetTypeForTable(i_isolate, table->type(),
2113                                        table->current_length(), max_size);
2114   args.GetReturnValue().Set(Utils::ToLocal(type));
2115 }
2116 
2117 // WebAssembly.Memory.grow(num) -> num
WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value> & args)2118 void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
2119   v8::Isolate* isolate = args.GetIsolate();
2120   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2121   HandleScope scope(isolate);
2122   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory.grow()");
2123   Local<Context> context = isolate->GetCurrentContext();
2124   EXTRACT_THIS(receiver, WasmMemoryObject);
2125 
2126   uint32_t delta_pages;
2127   if (!EnforceUint32("Argument 0", args[0], context, &thrower, &delta_pages)) {
2128     return;
2129   }
2130 
2131   i::Handle<i::JSArrayBuffer> old_buffer(receiver->array_buffer(), i_isolate);
2132 
2133   uint64_t old_pages64 = old_buffer->byte_length() / i::wasm::kWasmPageSize;
2134   uint64_t new_pages64 = old_pages64 + static_cast<uint64_t>(delta_pages);
2135 
2136   if (new_pages64 > static_cast<uint64_t>(receiver->maximum_pages())) {
2137     thrower.RangeError("Maximum memory size exceeded");
2138     return;
2139   }
2140 
2141   int32_t ret = i::WasmMemoryObject::Grow(i_isolate, receiver, delta_pages);
2142   if (ret == -1) {
2143     thrower.RangeError("Unable to grow instance memory");
2144     return;
2145   }
2146   v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
2147   return_value.Set(ret);
2148 }
2149 
2150 // WebAssembly.Memory.buffer -> ArrayBuffer
WebAssemblyMemoryGetBuffer(const v8::FunctionCallbackInfo<v8::Value> & args)2151 void WebAssemblyMemoryGetBuffer(
2152     const v8::FunctionCallbackInfo<v8::Value>& args) {
2153   v8::Isolate* isolate = args.GetIsolate();
2154   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2155   HandleScope scope(isolate);
2156   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory.buffer");
2157   EXTRACT_THIS(receiver, WasmMemoryObject);
2158 
2159   i::Handle<i::Object> buffer_obj(receiver->array_buffer(), i_isolate);
2160   DCHECK(buffer_obj->IsJSArrayBuffer());
2161   i::Handle<i::JSArrayBuffer> buffer(i::JSArrayBuffer::cast(*buffer_obj),
2162                                      i_isolate);
2163   if (buffer->is_shared()) {
2164     // TODO(gdeepti): More needed here for when cached buffer, and current
2165     // buffer are out of sync, handle that here when bounds checks, and Grow
2166     // are handled correctly.
2167     Maybe<bool> result =
2168         buffer->SetIntegrityLevel(buffer, i::FROZEN, i::kDontThrow);
2169     if (!result.FromJust()) {
2170       thrower.TypeError(
2171           "Status of setting SetIntegrityLevel of buffer is false.");
2172     }
2173   }
2174   v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
2175   return_value.Set(Utils::ToLocal(buffer));
2176 }
2177 
2178 // WebAssembly.Memory.type() -> MemoryType
WebAssemblyMemoryType(const v8::FunctionCallbackInfo<v8::Value> & args)2179 void WebAssemblyMemoryType(const v8::FunctionCallbackInfo<v8::Value>& args) {
2180   v8::Isolate* isolate = args.GetIsolate();
2181   HandleScope scope(isolate);
2182   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2183   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory.type()");
2184 
2185   EXTRACT_THIS(memory, WasmMemoryObject);
2186   i::Handle<i::JSArrayBuffer> buffer(memory->array_buffer(), i_isolate);
2187   size_t curr_size = buffer->byte_length() / i::wasm::kWasmPageSize;
2188   DCHECK_LE(curr_size, std::numeric_limits<uint32_t>::max());
2189   uint32_t min_size = static_cast<uint32_t>(curr_size);
2190   base::Optional<uint32_t> max_size;
2191   if (memory->has_maximum_pages()) {
2192     uint64_t max_size64 = memory->maximum_pages();
2193     DCHECK_LE(max_size64, std::numeric_limits<uint32_t>::max());
2194     max_size.emplace(static_cast<uint32_t>(max_size64));
2195   }
2196   bool shared = buffer->is_shared();
2197   auto type = i::wasm::GetTypeForMemory(i_isolate, min_size, max_size, shared);
2198   args.GetReturnValue().Set(Utils::ToLocal(type));
2199 }
2200 
2201 // WebAssembly.Tag.type() -> FunctionType
WebAssemblyTagType(const v8::FunctionCallbackInfo<v8::Value> & args)2202 void WebAssemblyTagType(const v8::FunctionCallbackInfo<v8::Value>& args) {
2203   v8::Isolate* isolate = args.GetIsolate();
2204   HandleScope scope(isolate);
2205   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2206   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Tag.type()");
2207 
2208   EXTRACT_THIS(tag, WasmTagObject);
2209   if (thrower.error()) return;
2210 
2211   int n = tag->serialized_signature().length();
2212   std::vector<i::wasm::ValueType> data(n);
2213   if (n > 0) {
2214     tag->serialized_signature().copy_out(0, data.data(), n);
2215   }
2216   const i::wasm::FunctionSig sig{0, data.size(), data.data()};
2217   constexpr bool kForException = true;
2218   auto type = i::wasm::GetTypeForFunction(i_isolate, &sig, kForException);
2219   args.GetReturnValue().Set(Utils::ToLocal(type));
2220 }
2221 
WebAssemblyExceptionGetArg(const v8::FunctionCallbackInfo<v8::Value> & args)2222 void WebAssemblyExceptionGetArg(
2223     const v8::FunctionCallbackInfo<v8::Value>& args) {
2224   v8::Isolate* isolate = args.GetIsolate();
2225   HandleScope scope(isolate);
2226   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2227   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Exception.getArg()");
2228 
2229   EXTRACT_THIS(exception, WasmExceptionPackage);
2230   if (thrower.error()) return;
2231 
2232   i::MaybeHandle<i::WasmTagObject> maybe_tag =
2233       GetFirstArgumentAsTag(args, &thrower);
2234   if (thrower.error()) return;
2235   auto tag = maybe_tag.ToHandleChecked();
2236   Local<Context> context = isolate->GetCurrentContext();
2237   uint32_t index;
2238   if (!EnforceUint32("Index", args[1], context, &thrower, &index)) {
2239     return;
2240   }
2241   auto maybe_values =
2242       i::WasmExceptionPackage::GetExceptionValues(i_isolate, exception);
2243 
2244   auto this_tag =
2245       i::WasmExceptionPackage::GetExceptionTag(i_isolate, exception);
2246   if (this_tag->IsUndefined()) {
2247     thrower.TypeError("Expected a WebAssembly.Exception object");
2248     return;
2249   }
2250   DCHECK(this_tag->IsWasmExceptionTag());
2251   if (tag->tag() != *this_tag) {
2252     thrower.TypeError("First argument does not match the exception tag");
2253     return;
2254   }
2255 
2256   DCHECK(!maybe_values->IsUndefined());
2257   auto values = i::Handle<i::FixedArray>::cast(maybe_values);
2258   auto signature = tag->serialized_signature();
2259   if (index >= static_cast<uint32_t>(signature.length())) {
2260     thrower.RangeError("Index out of range");
2261     return;
2262   }
2263   // First, find the index in the values array.
2264   uint32_t decode_index = 0;
2265   // Since the bounds check above passed, the cast to int is safe.
2266   for (int i = 0; i < static_cast<int>(index); ++i) {
2267     switch (signature.get(i).kind()) {
2268       case i::wasm::kI32:
2269       case i::wasm::kF32:
2270         decode_index += 2;
2271         break;
2272       case i::wasm::kI64:
2273       case i::wasm::kF64:
2274         decode_index += 4;
2275         break;
2276       case i::wasm::kRef:
2277       case i::wasm::kOptRef:
2278         switch (signature.get(i).heap_representation()) {
2279           case i::wasm::HeapType::kFunc:
2280           case i::wasm::HeapType::kAny:
2281           case i::wasm::HeapType::kEq:
2282           case i::wasm::HeapType::kI31:
2283           case i::wasm::HeapType::kData:
2284           case i::wasm::HeapType::kArray:
2285             decode_index++;
2286             break;
2287           case i::wasm::HeapType::kBottom:
2288             UNREACHABLE();
2289           default:
2290             // TODO(7748): Add support for custom struct/array types.
2291             UNIMPLEMENTED();
2292         }
2293         break;
2294       case i::wasm::kRtt:
2295       case i::wasm::kI8:
2296       case i::wasm::kI16:
2297       case i::wasm::kVoid:
2298       case i::wasm::kBottom:
2299       case i::wasm::kS128:
2300         UNREACHABLE();
2301     }
2302   }
2303   // Decode the value at {decode_index}.
2304   Local<Value> result;
2305   switch (signature.get(index).kind()) {
2306     case i::wasm::kI32: {
2307       uint32_t u32_bits = 0;
2308       i::DecodeI32ExceptionValue(values, &decode_index, &u32_bits);
2309       int32_t i32 = static_cast<int32_t>(u32_bits);
2310       result = v8::Integer::New(isolate, i32);
2311       break;
2312     }
2313     case i::wasm::kI64: {
2314       uint64_t u64_bits = 0;
2315       i::DecodeI64ExceptionValue(values, &decode_index, &u64_bits);
2316       int64_t i64 = static_cast<int64_t>(u64_bits);
2317       result = v8::BigInt::New(isolate, i64);
2318       break;
2319     }
2320     case i::wasm::kF32: {
2321       uint32_t f32_bits = 0;
2322       DecodeI32ExceptionValue(values, &decode_index, &f32_bits);
2323       float f32 = bit_cast<float>(f32_bits);
2324       result = v8::Number::New(isolate, f32);
2325       break;
2326     }
2327     case i::wasm::kF64: {
2328       uint64_t f64_bits = 0;
2329       DecodeI64ExceptionValue(values, &decode_index, &f64_bits);
2330       double f64 = bit_cast<double>(f64_bits);
2331       result = v8::Number::New(isolate, f64);
2332       break;
2333     }
2334     case i::wasm::kRef:
2335     case i::wasm::kOptRef:
2336       switch (signature.get(index).heap_representation()) {
2337         case i::wasm::HeapType::kFunc:
2338         case i::wasm::HeapType::kAny:
2339         case i::wasm::HeapType::kEq:
2340         case i::wasm::HeapType::kI31:
2341         case i::wasm::HeapType::kArray:
2342         case i::wasm::HeapType::kData: {
2343           auto obj = values->get(decode_index);
2344           result = Utils::ToLocal(i::Handle<i::Object>(obj, i_isolate));
2345           break;
2346         }
2347         case i::wasm::HeapType::kBottom:
2348           UNREACHABLE();
2349         default:
2350           // TODO(7748): Add support for custom struct/array types.
2351           UNIMPLEMENTED();
2352       }
2353       break;
2354     case i::wasm::kRtt:
2355     case i::wasm::kI8:
2356     case i::wasm::kI16:
2357     case i::wasm::kVoid:
2358     case i::wasm::kBottom:
2359     case i::wasm::kS128:
2360       UNREACHABLE();
2361   }
2362   args.GetReturnValue().Set(result);
2363 }
2364 
WebAssemblyExceptionIs(const v8::FunctionCallbackInfo<v8::Value> & args)2365 void WebAssemblyExceptionIs(const v8::FunctionCallbackInfo<v8::Value>& args) {
2366   v8::Isolate* isolate = args.GetIsolate();
2367   HandleScope scope(isolate);
2368   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2369   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Exception.is()");
2370 
2371   EXTRACT_THIS(exception, WasmExceptionPackage);
2372   if (thrower.error()) return;
2373 
2374   auto tag = i::WasmExceptionPackage::GetExceptionTag(i_isolate, exception);
2375   if (tag->IsUndefined()) {
2376     thrower.TypeError("Expected a WebAssembly.Exception object");
2377     return;
2378   }
2379   DCHECK(tag->IsWasmExceptionTag());
2380 
2381   auto maybe_tag = GetFirstArgumentAsTag(args, &thrower);
2382   if (thrower.error()) {
2383     return;
2384   }
2385   auto tag_arg = maybe_tag.ToHandleChecked();
2386   args.GetReturnValue().Set(tag_arg->tag() == *tag);
2387 }
2388 
WebAssemblyGlobalGetValueCommon(const v8::FunctionCallbackInfo<v8::Value> & args,const char * name)2389 void WebAssemblyGlobalGetValueCommon(
2390     const v8::FunctionCallbackInfo<v8::Value>& args, const char* name) {
2391   v8::Isolate* isolate = args.GetIsolate();
2392   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2393   HandleScope scope(isolate);
2394   ScheduledErrorThrower thrower(i_isolate, name);
2395   EXTRACT_THIS(receiver, WasmGlobalObject);
2396 
2397   v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
2398 
2399   switch (receiver->type().kind()) {
2400     case i::wasm::kI32:
2401       return_value.Set(receiver->GetI32());
2402       break;
2403     case i::wasm::kI64: {
2404       Local<BigInt> value = BigInt::New(isolate, receiver->GetI64());
2405       return_value.Set(value);
2406       break;
2407     }
2408     case i::wasm::kF32:
2409       return_value.Set(receiver->GetF32());
2410       break;
2411     case i::wasm::kF64:
2412       return_value.Set(receiver->GetF64());
2413       break;
2414     case i::wasm::kS128:
2415       thrower.TypeError("Can't get the value of s128 WebAssembly.Global");
2416       break;
2417     case i::wasm::kRef:
2418     case i::wasm::kOptRef:
2419       switch (receiver->type().heap_representation()) {
2420         case i::wasm::HeapType::kAny:
2421           return_value.Set(Utils::ToLocal(receiver->GetRef()));
2422           break;
2423         case i::wasm::HeapType::kFunc: {
2424           i::Handle<i::Object> result = receiver->GetRef();
2425           if (result->IsWasmInternalFunction()) {
2426             result = handle(
2427                 i::Handle<i::WasmInternalFunction>::cast(result)->external(),
2428                 i_isolate);
2429           }
2430           return_value.Set(Utils::ToLocal(result));
2431           break;
2432         }
2433         case i::wasm::HeapType::kBottom:
2434           UNREACHABLE();
2435         case i::wasm::HeapType::kI31:
2436         case i::wasm::HeapType::kData:
2437         case i::wasm::HeapType::kArray:
2438         case i::wasm::HeapType::kEq:
2439         default:
2440           // TODO(7748): Implement these.
2441           UNIMPLEMENTED();
2442       }
2443       break;
2444     case i::wasm::kRtt:
2445       UNIMPLEMENTED();  // TODO(7748): Implement.
2446     case i::wasm::kI8:
2447     case i::wasm::kI16:
2448     case i::wasm::kBottom:
2449     case i::wasm::kVoid:
2450       UNREACHABLE();
2451   }
2452 }
2453 
2454 // WebAssembly.Global.valueOf() -> num
WebAssemblyGlobalValueOf(const v8::FunctionCallbackInfo<v8::Value> & args)2455 void WebAssemblyGlobalValueOf(const v8::FunctionCallbackInfo<v8::Value>& args) {
2456   return WebAssemblyGlobalGetValueCommon(args, "WebAssembly.Global.valueOf()");
2457 }
2458 
2459 // get WebAssembly.Global.value -> num
WebAssemblyGlobalGetValue(const v8::FunctionCallbackInfo<v8::Value> & args)2460 void WebAssemblyGlobalGetValue(
2461     const v8::FunctionCallbackInfo<v8::Value>& args) {
2462   return WebAssemblyGlobalGetValueCommon(args, "get WebAssembly.Global.value");
2463 }
2464 
2465 // set WebAssembly.Global.value(num)
WebAssemblyGlobalSetValue(const v8::FunctionCallbackInfo<v8::Value> & args)2466 void WebAssemblyGlobalSetValue(
2467     const v8::FunctionCallbackInfo<v8::Value>& args) {
2468   v8::Isolate* isolate = args.GetIsolate();
2469   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2470   HandleScope scope(isolate);
2471   Local<Context> context = isolate->GetCurrentContext();
2472   ScheduledErrorThrower thrower(i_isolate, "set WebAssembly.Global.value");
2473   EXTRACT_THIS(receiver, WasmGlobalObject);
2474 
2475   if (!receiver->is_mutable()) {
2476     thrower.TypeError("Can't set the value of an immutable global.");
2477     return;
2478   }
2479   if (args.Length() == 0) {
2480     thrower.TypeError("Argument 0 is required");
2481     return;
2482   }
2483 
2484   switch (receiver->type().kind()) {
2485     case i::wasm::kI32: {
2486       int32_t i32_value = 0;
2487       if (!args[0]->Int32Value(context).To(&i32_value)) return;
2488       receiver->SetI32(i32_value);
2489       break;
2490     }
2491     case i::wasm::kI64: {
2492       v8::Local<v8::BigInt> bigint_value;
2493       if (!args[0]->ToBigInt(context).ToLocal(&bigint_value)) return;
2494       receiver->SetI64(bigint_value->Int64Value());
2495       break;
2496     }
2497     case i::wasm::kF32: {
2498       double f64_value = 0;
2499       if (!args[0]->NumberValue(context).To(&f64_value)) return;
2500       receiver->SetF32(i::DoubleToFloat32(f64_value));
2501       break;
2502     }
2503     case i::wasm::kF64: {
2504       double f64_value = 0;
2505       if (!args[0]->NumberValue(context).To(&f64_value)) return;
2506       receiver->SetF64(f64_value);
2507       break;
2508     }
2509     case i::wasm::kS128:
2510       thrower.TypeError("Can't set the value of s128 WebAssembly.Global");
2511       break;
2512     case i::wasm::kRef:
2513     case i::wasm::kOptRef:
2514       switch (receiver->type().heap_representation()) {
2515         case i::wasm::HeapType::kAny:
2516           receiver->SetExternRef(Utils::OpenHandle(*args[0]));
2517           break;
2518         case i::wasm::HeapType::kFunc: {
2519           if (!receiver->SetFuncRef(i_isolate, Utils::OpenHandle(*args[0]))) {
2520             thrower.TypeError(
2521                 "value of an funcref reference must be either null or an "
2522                 "exported function");
2523           }
2524           break;
2525         }
2526         case i::wasm::HeapType::kBottom:
2527           UNREACHABLE();
2528         case i::wasm::HeapType::kI31:
2529         case i::wasm::HeapType::kData:
2530         case i::wasm::HeapType::kArray:
2531         case i::wasm::HeapType::kEq:
2532         default:
2533           // TODO(7748): Implement these.
2534           UNIMPLEMENTED();
2535       }
2536       break;
2537     case i::wasm::kRtt:
2538       // TODO(7748): Implement.
2539       UNIMPLEMENTED();
2540     case i::wasm::kI8:
2541     case i::wasm::kI16:
2542     case i::wasm::kBottom:
2543     case i::wasm::kVoid:
2544       UNREACHABLE();
2545   }
2546 }
2547 
2548 // WebAssembly.Global.type() -> GlobalType
WebAssemblyGlobalType(const v8::FunctionCallbackInfo<v8::Value> & args)2549 void WebAssemblyGlobalType(const v8::FunctionCallbackInfo<v8::Value>& args) {
2550   v8::Isolate* isolate = args.GetIsolate();
2551   HandleScope scope(isolate);
2552   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2553   ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Global.type()");
2554 
2555   EXTRACT_THIS(global, WasmGlobalObject);
2556   auto type = i::wasm::GetTypeForGlobal(i_isolate, global->is_mutable(),
2557                                         global->type());
2558   args.GetReturnValue().Set(Utils::ToLocal(type));
2559 }
2560 
2561 // WebAssembly.Suspender.returnPromiseOnSuspend(WebAssembly.Function) ->
2562 // WebAssembly.Function
WebAssemblySuspenderReturnPromiseOnSuspend(const v8::FunctionCallbackInfo<v8::Value> & args)2563 void WebAssemblySuspenderReturnPromiseOnSuspend(
2564     const v8::FunctionCallbackInfo<v8::Value>& args) {
2565   Isolate* isolate = args.GetIsolate();
2566   HandleScope scope(isolate);
2567   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2568   ScheduledErrorThrower thrower(
2569       i_isolate, "WebAssembly.Suspender.returnPromiseOnSuspend()");
2570   if (args.Length() == 0) {
2571     thrower.TypeError("Argument 0 is required");
2572     return;
2573   }
2574   auto maybe_function = GetFirstArgumentAsJSFunction(args, &thrower);
2575   if (thrower.error()) return;
2576   i::Handle<i::JSFunction> function = maybe_function.ToHandleChecked();
2577   i::SharedFunctionInfo sfi = function->shared();
2578   if (!sfi.HasWasmExportedFunctionData()) {
2579     thrower.TypeError("Argument 0 must be a wasm function");
2580   }
2581   i::WasmExportedFunctionData data = sfi.wasm_exported_function_data();
2582   if (data.sig()->return_count() != 1) {
2583     thrower.TypeError(
2584         "Expected a WebAssembly.Function with exactly one return type");
2585   }
2586   int index = data.function_index();
2587   i::Handle<i::WasmInstanceObject> instance(
2588       i::WasmInstanceObject::cast(data.internal().ref()), i_isolate);
2589   i::Handle<i::CodeT> wrapper =
2590       BUILTIN_CODE(i_isolate, WasmReturnPromiseOnSuspend);
2591   // Upcast to JSFunction to re-use the existing ToLocal helper below.
2592   i::Handle<i::JSFunction> result =
2593       i::Handle<i::WasmExternalFunction>::cast(i::WasmExportedFunction::New(
2594           i_isolate, instance, index,
2595           static_cast<int>(data.sig()->parameter_count()), wrapper));
2596   EXTRACT_THIS(suspender, WasmSuspenderObject);
2597   auto function_data = i::WasmExportedFunctionData::cast(
2598       result->shared().function_data(kAcquireLoad));
2599   function_data.set_suspender(*suspender);
2600   args.GetReturnValue().Set(Utils::ToLocal(result));
2601 }
2602 
2603 // WebAssembly.Suspender.suspendOnReturnedPromise(Function) -> Function
WebAssemblySuspenderSuspendOnReturnedPromise(const v8::FunctionCallbackInfo<v8::Value> & args)2604 void WebAssemblySuspenderSuspendOnReturnedPromise(
2605     const v8::FunctionCallbackInfo<v8::Value>& args) {
2606   v8::Isolate* isolate = args.GetIsolate();
2607   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2608   HandleScope scope(isolate);
2609   ScheduledErrorThrower thrower(
2610       i_isolate, "WebAssembly.Suspender.suspendOnReturnedPromise()");
2611   if (!args[0]->IsObject()) {
2612     thrower.TypeError("Argument 0 must be a WebAssembly.Function");
2613     return;
2614   }
2615   i::Zone zone(i_isolate->allocator(), ZONE_NAME);
2616   const i::wasm::FunctionSig* sig;
2617   i::Handle<i::Object> arg0 = Utils::OpenHandle(*args[0]);
2618 
2619   if (i::WasmExportedFunction::IsWasmExportedFunction(*arg0)) {
2620     // TODO(thibaudm): Suspend on wrapped wasm-to-wasm calls too.
2621     UNIMPLEMENTED();
2622   } else if (!i::WasmJSFunction::IsWasmJSFunction(*arg0)) {
2623     thrower.TypeError("Argument 0 must be a WebAssembly.Function");
2624     return;
2625   }
2626   sig = i::Handle<i::WasmJSFunction>::cast(arg0)->GetSignature(&zone);
2627   if (sig->return_count() != 1 || sig->GetReturn(0) != i::wasm::kWasmAnyRef) {
2628     thrower.TypeError("Expected a WebAssembly.Function with return type %s",
2629                       i::wasm::kWasmAnyRef.name().c_str());
2630   }
2631 
2632   auto callable = handle(
2633       i::Handle<i::WasmJSFunction>::cast(arg0)->GetCallable(), i_isolate);
2634   EXTRACT_THIS(suspender, WasmSuspenderObject);
2635   i::Handle<i::JSFunction> result =
2636       i::WasmJSFunction::New(i_isolate, sig, callable, suspender);
2637   args.GetReturnValue().Set(Utils::ToLocal(result));
2638 }
2639 }  // namespace
2640 
2641 // TODO(titzer): we use the API to create the function template because the
2642 // internal guts are too ugly to replicate here.
NewFunctionTemplate(i::Isolate * i_isolate,FunctionCallback func,bool has_prototype,SideEffectType side_effect_type=SideEffectType::kHasSideEffect)2643 static i::Handle<i::FunctionTemplateInfo> NewFunctionTemplate(
2644     i::Isolate* i_isolate, FunctionCallback func, bool has_prototype,
2645     SideEffectType side_effect_type = SideEffectType::kHasSideEffect) {
2646   Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
2647   ConstructorBehavior behavior =
2648       has_prototype ? ConstructorBehavior::kAllow : ConstructorBehavior::kThrow;
2649   Local<FunctionTemplate> templ = FunctionTemplate::New(
2650       isolate, func, {}, {}, 0, behavior, side_effect_type);
2651   if (has_prototype) templ->ReadOnlyPrototype();
2652   return v8::Utils::OpenHandle(*templ);
2653 }
2654 
NewObjectTemplate(i::Isolate * i_isolate)2655 static i::Handle<i::ObjectTemplateInfo> NewObjectTemplate(
2656     i::Isolate* i_isolate) {
2657   Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
2658   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2659   return v8::Utils::OpenHandle(*templ);
2660 }
2661 
2662 namespace internal {
2663 
CreateFunc(Isolate * isolate,Handle<String> name,FunctionCallback func,bool has_prototype,SideEffectType side_effect_type=SideEffectType::kHasSideEffect)2664 Handle<JSFunction> CreateFunc(
2665     Isolate* isolate, Handle<String> name, FunctionCallback func,
2666     bool has_prototype,
2667     SideEffectType side_effect_type = SideEffectType::kHasSideEffect) {
2668   Handle<FunctionTemplateInfo> temp =
2669       NewFunctionTemplate(isolate, func, has_prototype, side_effect_type);
2670   Handle<JSFunction> function =
2671       ApiNatives::InstantiateFunction(temp, name).ToHandleChecked();
2672   DCHECK(function->shared().HasSharedName());
2673   return function;
2674 }
2675 
InstallFunc(Isolate * isolate,Handle<JSObject> object,const char * str,FunctionCallback func,int length,bool has_prototype=false,PropertyAttributes attributes=NONE,SideEffectType side_effect_type=SideEffectType::kHasSideEffect)2676 Handle<JSFunction> InstallFunc(
2677     Isolate* isolate, Handle<JSObject> object, const char* str,
2678     FunctionCallback func, int length, bool has_prototype = false,
2679     PropertyAttributes attributes = NONE,
2680     SideEffectType side_effect_type = SideEffectType::kHasSideEffect) {
2681   Handle<String> name = v8_str(isolate, str);
2682   Handle<JSFunction> function =
2683       CreateFunc(isolate, name, func, has_prototype, side_effect_type);
2684   function->shared().set_length(length);
2685   JSObject::AddProperty(isolate, object, name, function, attributes);
2686   return function;
2687 }
2688 
InstallConstructorFunc(Isolate * isolate,Handle<JSObject> object,const char * str,FunctionCallback func)2689 Handle<JSFunction> InstallConstructorFunc(Isolate* isolate,
2690                                           Handle<JSObject> object,
2691                                           const char* str,
2692                                           FunctionCallback func) {
2693   return InstallFunc(isolate, object, str, func, 1, true, DONT_ENUM,
2694                      SideEffectType::kHasNoSideEffect);
2695 }
2696 
GetterName(Isolate * isolate,Handle<String> name)2697 Handle<String> GetterName(Isolate* isolate, Handle<String> name) {
2698   return Name::ToFunctionName(isolate, name, isolate->factory()->get_string())
2699       .ToHandleChecked();
2700 }
2701 
InstallGetter(Isolate * isolate,Handle<JSObject> object,const char * str,FunctionCallback func)2702 void InstallGetter(Isolate* isolate, Handle<JSObject> object, const char* str,
2703                    FunctionCallback func) {
2704   Handle<String> name = v8_str(isolate, str);
2705   Handle<JSFunction> function =
2706       CreateFunc(isolate, GetterName(isolate, name), func, false,
2707                  SideEffectType::kHasNoSideEffect);
2708 
2709   Utils::ToLocal(object)->SetAccessorProperty(Utils::ToLocal(name),
2710                                               Utils::ToLocal(function),
2711                                               Local<Function>(), v8::None);
2712 }
2713 
SetterName(Isolate * isolate,Handle<String> name)2714 Handle<String> SetterName(Isolate* isolate, Handle<String> name) {
2715   return Name::ToFunctionName(isolate, name, isolate->factory()->set_string())
2716       .ToHandleChecked();
2717 }
2718 
InstallGetterSetter(Isolate * isolate,Handle<JSObject> object,const char * str,FunctionCallback getter,FunctionCallback setter)2719 void InstallGetterSetter(Isolate* isolate, Handle<JSObject> object,
2720                          const char* str, FunctionCallback getter,
2721                          FunctionCallback setter) {
2722   Handle<String> name = v8_str(isolate, str);
2723   Handle<JSFunction> getter_func =
2724       CreateFunc(isolate, GetterName(isolate, name), getter, false,
2725                  SideEffectType::kHasNoSideEffect);
2726   Handle<JSFunction> setter_func =
2727       CreateFunc(isolate, SetterName(isolate, name), setter, false);
2728   setter_func->shared().set_length(1);
2729 
2730   Utils::ToLocal(object)->SetAccessorProperty(
2731       Utils::ToLocal(name), Utils::ToLocal(getter_func),
2732       Utils::ToLocal(setter_func), v8::None);
2733 }
2734 
2735 // Assigns a dummy instance template to the given constructor function. Used to
2736 // make sure the implicit receivers for the constructors in this file have an
2737 // instance type different from the internal one, they allocate the resulting
2738 // object explicitly and ignore implicit receiver.
SetDummyInstanceTemplate(Isolate * isolate,Handle<JSFunction> fun)2739 void SetDummyInstanceTemplate(Isolate* isolate, Handle<JSFunction> fun) {
2740   Handle<ObjectTemplateInfo> instance_template = NewObjectTemplate(isolate);
2741   FunctionTemplateInfo::SetInstanceTemplate(
2742       isolate, handle(fun->shared().get_api_func_data(), isolate),
2743       instance_template);
2744 }
2745 
SetupConstructor(Isolate * isolate,Handle<JSFunction> constructor,InstanceType instance_type,int instance_size,const char * name=nullptr)2746 Handle<JSObject> SetupConstructor(Isolate* isolate,
2747                                   Handle<JSFunction> constructor,
2748                                   InstanceType instance_type, int instance_size,
2749                                   const char* name = nullptr) {
2750   SetDummyInstanceTemplate(isolate, constructor);
2751   JSFunction::EnsureHasInitialMap(constructor);
2752   Handle<JSObject> proto(JSObject::cast(constructor->instance_prototype()),
2753                          isolate);
2754   Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
2755   JSFunction::SetInitialMap(isolate, constructor, map, proto);
2756   constexpr PropertyAttributes ro_attributes =
2757       static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
2758   if (name) {
2759     JSObject::AddProperty(isolate, proto,
2760                           isolate->factory()->to_string_tag_symbol(),
2761                           v8_str(isolate, name), ro_attributes);
2762   }
2763   return proto;
2764 }
2765 
2766 // static
Install(Isolate * isolate,bool exposed_on_global_object)2767 void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
2768   Handle<JSGlobalObject> global = isolate->global_object();
2769   Handle<Context> context(global->native_context(), isolate);
2770   // Install the JS API once only.
2771   Object prev = context->get(Context::WASM_MODULE_CONSTRUCTOR_INDEX);
2772   if (!prev.IsUndefined(isolate)) {
2773     DCHECK(prev.IsJSFunction());
2774     return;
2775   }
2776 
2777   Factory* factory = isolate->factory();
2778 
2779   // Setup WebAssembly
2780   Handle<String> name = v8_str(isolate, "WebAssembly");
2781   // Not supposed to be called, hence using the kIllegal builtin as code.
2782   Handle<SharedFunctionInfo> info =
2783       factory->NewSharedFunctionInfoForBuiltin(name, Builtin::kIllegal);
2784   info->set_language_mode(LanguageMode::kStrict);
2785 
2786   Handle<JSFunction> cons =
2787       Factory::JSFunctionBuilder{isolate, info, context}.Build();
2788   JSFunction::SetPrototype(cons, isolate->initial_object_prototype());
2789   Handle<JSObject> webassembly =
2790       factory->NewJSObject(cons, AllocationType::kOld);
2791 
2792   PropertyAttributes ro_attributes =
2793       static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
2794   JSObject::AddProperty(isolate, webassembly, factory->to_string_tag_symbol(),
2795                         name, ro_attributes);
2796   InstallFunc(isolate, webassembly, "compile", WebAssemblyCompile, 1);
2797   InstallFunc(isolate, webassembly, "validate", WebAssemblyValidate, 1);
2798   InstallFunc(isolate, webassembly, "instantiate", WebAssemblyInstantiate, 1);
2799 
2800   if (FLAG_wasm_test_streaming) {
2801     isolate->set_wasm_streaming_callback(WasmStreamingCallbackForTesting);
2802   }
2803 
2804   if (isolate->wasm_streaming_callback() != nullptr) {
2805     InstallFunc(isolate, webassembly, "compileStreaming",
2806                 WebAssemblyCompileStreaming, 1);
2807     InstallFunc(isolate, webassembly, "instantiateStreaming",
2808                 WebAssemblyInstantiateStreaming, 1);
2809   }
2810 
2811   // Expose the API on the global object if configured to do so.
2812   if (exposed_on_global_object) {
2813     JSObject::AddProperty(isolate, global, name, webassembly, DONT_ENUM);
2814   }
2815 
2816   // Setup Module
2817   Handle<JSFunction> module_constructor =
2818       InstallConstructorFunc(isolate, webassembly, "Module", WebAssemblyModule);
2819   SetupConstructor(isolate, module_constructor, i::WASM_MODULE_OBJECT_TYPE,
2820                    WasmModuleObject::kHeaderSize, "WebAssembly.Module");
2821   context->set_wasm_module_constructor(*module_constructor);
2822   InstallFunc(isolate, module_constructor, "imports", WebAssemblyModuleImports,
2823               1, false, NONE, SideEffectType::kHasNoSideEffect);
2824   InstallFunc(isolate, module_constructor, "exports", WebAssemblyModuleExports,
2825               1, false, NONE, SideEffectType::kHasNoSideEffect);
2826   InstallFunc(isolate, module_constructor, "customSections",
2827               WebAssemblyModuleCustomSections, 2, false, NONE,
2828               SideEffectType::kHasNoSideEffect);
2829 
2830   // Setup Instance
2831   Handle<JSFunction> instance_constructor = InstallConstructorFunc(
2832       isolate, webassembly, "Instance", WebAssemblyInstance);
2833   Handle<JSObject> instance_proto = SetupConstructor(
2834       isolate, instance_constructor, i::WASM_INSTANCE_OBJECT_TYPE,
2835       WasmInstanceObject::kHeaderSize, "WebAssembly.Instance");
2836   context->set_wasm_instance_constructor(*instance_constructor);
2837   InstallGetter(isolate, instance_proto, "exports",
2838                 WebAssemblyInstanceGetExports);
2839 
2840   // The context is not set up completely yet. That's why we cannot use
2841   // {WasmFeatures::FromIsolate} and have to use {WasmFeatures::FromFlags}
2842   // instead.
2843   auto enabled_features = i::wasm::WasmFeatures::FromFlags();
2844 
2845   // Setup Table
2846   Handle<JSFunction> table_constructor =
2847       InstallConstructorFunc(isolate, webassembly, "Table", WebAssemblyTable);
2848   Handle<JSObject> table_proto =
2849       SetupConstructor(isolate, table_constructor, i::WASM_TABLE_OBJECT_TYPE,
2850                        WasmTableObject::kHeaderSize, "WebAssembly.Table");
2851   context->set_wasm_table_constructor(*table_constructor);
2852   InstallGetter(isolate, table_proto, "length", WebAssemblyTableGetLength);
2853   InstallFunc(isolate, table_proto, "grow", WebAssemblyTableGrow, 1);
2854   InstallFunc(isolate, table_proto, "get", WebAssemblyTableGet, 1, false, NONE,
2855               SideEffectType::kHasNoSideEffect);
2856   InstallFunc(isolate, table_proto, "set", WebAssemblyTableSet, 2);
2857   if (enabled_features.has_type_reflection()) {
2858     InstallFunc(isolate, table_proto, "type", WebAssemblyTableType, 0, false,
2859                 NONE, SideEffectType::kHasNoSideEffect);
2860   }
2861 
2862   // Setup Memory
2863   Handle<JSFunction> memory_constructor =
2864       InstallConstructorFunc(isolate, webassembly, "Memory", WebAssemblyMemory);
2865   Handle<JSObject> memory_proto =
2866       SetupConstructor(isolate, memory_constructor, i::WASM_MEMORY_OBJECT_TYPE,
2867                        WasmMemoryObject::kHeaderSize, "WebAssembly.Memory");
2868   context->set_wasm_memory_constructor(*memory_constructor);
2869   InstallFunc(isolate, memory_proto, "grow", WebAssemblyMemoryGrow, 1);
2870   InstallGetter(isolate, memory_proto, "buffer", WebAssemblyMemoryGetBuffer);
2871   if (enabled_features.has_type_reflection()) {
2872     InstallFunc(isolate, memory_proto, "type", WebAssemblyMemoryType, 0, false,
2873                 NONE, SideEffectType::kHasNoSideEffect);
2874   }
2875 
2876   // Setup Global
2877   Handle<JSFunction> global_constructor =
2878       InstallConstructorFunc(isolate, webassembly, "Global", WebAssemblyGlobal);
2879   Handle<JSObject> global_proto =
2880       SetupConstructor(isolate, global_constructor, i::WASM_GLOBAL_OBJECT_TYPE,
2881                        WasmGlobalObject::kHeaderSize, "WebAssembly.Global");
2882   context->set_wasm_global_constructor(*global_constructor);
2883   InstallFunc(isolate, global_proto, "valueOf", WebAssemblyGlobalValueOf, 0,
2884               false, NONE, SideEffectType::kHasNoSideEffect);
2885   InstallGetterSetter(isolate, global_proto, "value", WebAssemblyGlobalGetValue,
2886                       WebAssemblyGlobalSetValue);
2887   if (enabled_features.has_type_reflection()) {
2888     InstallFunc(isolate, global_proto, "type", WebAssemblyGlobalType, 0, false,
2889                 NONE, SideEffectType::kHasNoSideEffect);
2890   }
2891 
2892   // Setup Exception
2893   if (enabled_features.has_eh()) {
2894     Handle<JSFunction> tag_constructor =
2895         InstallConstructorFunc(isolate, webassembly, "Tag", WebAssemblyTag);
2896     Handle<JSObject> tag_proto =
2897         SetupConstructor(isolate, tag_constructor, i::WASM_TAG_OBJECT_TYPE,
2898                          WasmTagObject::kHeaderSize, "WebAssembly.Tag");
2899     context->set_wasm_tag_constructor(*tag_constructor);
2900 
2901     if (enabled_features.has_type_reflection()) {
2902       InstallFunc(isolate, tag_proto, "type", WebAssemblyTagType, 0);
2903     }
2904     // Set up runtime exception constructor.
2905     Handle<JSFunction> exception_constructor = InstallConstructorFunc(
2906         isolate, webassembly, "Exception", WebAssemblyException);
2907     SetDummyInstanceTemplate(isolate, exception_constructor);
2908     Handle<Map> exception_map(isolate->native_context()
2909                                   ->wasm_exception_error_function()
2910                                   .initial_map(),
2911                               isolate);
2912     Handle<JSObject> exception_proto(
2913         JSObject::cast(isolate->native_context()
2914                            ->wasm_exception_error_function()
2915                            .instance_prototype()),
2916         isolate);
2917     InstallFunc(isolate, exception_proto, "getArg", WebAssemblyExceptionGetArg,
2918                 2);
2919     InstallFunc(isolate, exception_proto, "is", WebAssemblyExceptionIs, 1);
2920     context->set_wasm_exception_constructor(*exception_constructor);
2921     JSFunction::SetInitialMap(isolate, exception_constructor, exception_map,
2922                               exception_proto);
2923   }
2924 
2925   // Setup Suspender.
2926   if (enabled_features.has_stack_switching()) {
2927     Handle<JSFunction> suspender_constructor = InstallConstructorFunc(
2928         isolate, webassembly, "Suspender", WebAssemblySuspender);
2929     context->set_wasm_suspender_constructor(*suspender_constructor);
2930     Handle<JSObject> suspender_proto = SetupConstructor(
2931         isolate, suspender_constructor, i::WASM_SUSPENDER_OBJECT_TYPE,
2932         WasmSuspenderObject::kHeaderSize, "WebAssembly.Suspender");
2933     InstallFunc(isolate, suspender_proto, "returnPromiseOnSuspend",
2934                 WebAssemblySuspenderReturnPromiseOnSuspend, 1);
2935     InstallFunc(isolate, suspender_proto, "suspendOnReturnedPromise",
2936                 WebAssemblySuspenderSuspendOnReturnedPromise, 1);
2937   }
2938 
2939   // Setup Function
2940   if (enabled_features.has_type_reflection()) {
2941     Handle<JSFunction> function_constructor = InstallConstructorFunc(
2942         isolate, webassembly, "Function", WebAssemblyFunction);
2943     SetDummyInstanceTemplate(isolate, function_constructor);
2944     JSFunction::EnsureHasInitialMap(function_constructor);
2945     Handle<JSObject> function_proto(
2946         JSObject::cast(function_constructor->instance_prototype()), isolate);
2947     Handle<Map> function_map = isolate->factory()->CreateSloppyFunctionMap(
2948         FUNCTION_WITHOUT_PROTOTYPE, MaybeHandle<JSFunction>());
2949     CHECK(JSObject::SetPrototype(
2950               isolate, function_proto,
2951               handle(context->function_function().prototype(), isolate), false,
2952               kDontThrow)
2953               .FromJust());
2954     JSFunction::SetInitialMap(isolate, function_constructor, function_map,
2955                               function_proto);
2956     InstallFunc(isolate, function_constructor, "type", WebAssemblyFunctionType,
2957                 1);
2958     // Make all exported functions an instance of {WebAssembly.Function}.
2959     context->set_wasm_exported_function_map(*function_map);
2960   } else {
2961     // Make all exported functions an instance of {Function}.
2962     Handle<Map> function_map = isolate->sloppy_function_without_prototype_map();
2963     context->set_wasm_exported_function_map(*function_map);
2964   }
2965 
2966   // Setup errors
2967   Handle<JSFunction> compile_error(
2968       isolate->native_context()->wasm_compile_error_function(), isolate);
2969   JSObject::AddProperty(isolate, webassembly,
2970                         isolate->factory()->CompileError_string(),
2971                         compile_error, DONT_ENUM);
2972   Handle<JSFunction> link_error(
2973       isolate->native_context()->wasm_link_error_function(), isolate);
2974   JSObject::AddProperty(isolate, webassembly,
2975                         isolate->factory()->LinkError_string(), link_error,
2976                         DONT_ENUM);
2977   Handle<JSFunction> runtime_error(
2978       isolate->native_context()->wasm_runtime_error_function(), isolate);
2979   JSObject::AddProperty(isolate, webassembly,
2980                         isolate->factory()->RuntimeError_string(),
2981                         runtime_error, DONT_ENUM);
2982 }
2983 
2984 // static
InstallConditionalFeatures(Isolate * isolate,Handle<Context> context)2985 void WasmJs::InstallConditionalFeatures(Isolate* isolate,
2986                                         Handle<Context> context) {
2987   // Exception handling may have been enabled by an origin trial. If so, make
2988   // sure that the {WebAssembly.Tag} constructor is set up.
2989   auto enabled_features = i::wasm::WasmFeatures::FromContext(isolate, context);
2990   if (enabled_features.has_eh()) {
2991     Handle<JSGlobalObject> global = handle(context->global_object(), isolate);
2992     MaybeHandle<Object> maybe_webassembly =
2993         JSObject::GetProperty(isolate, global, "WebAssembly");
2994     Handle<Object> webassembly_obj;
2995     if (!maybe_webassembly.ToHandle(&webassembly_obj) ||
2996         !webassembly_obj->IsJSObject()) {
2997       // There is no {WebAssembly} object, or it's not what we expect.
2998       // Just return without adding the {Tag} constructor.
2999       return;
3000     }
3001     Handle<JSObject> webassembly = Handle<JSObject>::cast(webassembly_obj);
3002     // Setup Tag.
3003     Handle<String> tag_name = v8_str(isolate, "Tag");
3004     // The {WebAssembly} object may already have been modified. The following
3005     // code is designed to:
3006     //  - check for existing {Tag} properties on the object itself, and avoid
3007     //    overwriting them or adding duplicate properties
3008     //  - disregard any setters or read-only properties on the prototype chain
3009     //  - only make objects accessible to user code after all internal setup
3010     //    has been completed.
3011     if (JSObject::HasOwnProperty(isolate, webassembly, tag_name)
3012             .FromMaybe(true)) {
3013       // Existing property, or exception.
3014       return;
3015     }
3016 
3017     bool has_prototype = true;
3018     Handle<JSFunction> tag_constructor =
3019         CreateFunc(isolate, tag_name, WebAssemblyTag, has_prototype,
3020                    SideEffectType::kHasNoSideEffect);
3021     tag_constructor->shared().set_length(1);
3022     context->set_wasm_tag_constructor(*tag_constructor);
3023     Handle<JSObject> tag_proto =
3024         SetupConstructor(isolate, tag_constructor, i::WASM_TAG_OBJECT_TYPE,
3025                          WasmTagObject::kHeaderSize, "WebAssembly.Tag");
3026     if (enabled_features.has_type_reflection()) {
3027       InstallFunc(isolate, tag_proto, "type", WebAssemblyTagType, 0);
3028     }
3029     LookupIterator it(isolate, webassembly, tag_name, LookupIterator::OWN);
3030     Maybe<bool> result = JSObject::DefineOwnPropertyIgnoreAttributes(
3031         &it, tag_constructor, DONT_ENUM, Just(kDontThrow));
3032     // This could still fail if the object was non-extensible, but now we
3033     // return anyway so there's no need to even check.
3034     USE(result);
3035   }
3036 }
3037 #undef ASSIGN
3038 #undef EXTRACT_THIS
3039 
3040 }  // namespace internal
3041 }  // namespace v8
3042