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