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