wasm-js.cc 89.8 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#include "src/wasm/wasm-js.h"

7 8
#include <cinttypes>
#include <cstring>
9

10 11
#include "src/api/api-inl.h"
#include "src/api/api-natives.h"
12
#include "src/ast/ast.h"
13
#include "src/base/logging.h"
14
#include "src/base/overflowing-math.h"
15
#include "src/base/platform/wrappers.h"
16
#include "src/common/assert-scope.h"
17
#include "src/execution/execution.h"
18
#include "src/execution/frames-inl.h"
19
#include "src/execution/isolate.h"
20
#include "src/handles/handles.h"
21
#include "src/heap/factory.h"
22
#include "src/init/v8.h"
23
#include "src/objects/js-promise-inl.h"
24
#include "src/objects/objects-inl.h"
25
#include "src/objects/templates.h"
26
#include "src/parsing/parse-info.h"
27
#include "src/tasks/task-utils.h"
28
#include "src/trap-handler/trap-handler.h"
29
#include "src/wasm/function-compiler.h"
30
#include "src/wasm/streaming-decoder.h"
31
#include "src/wasm/value-type.h"
32
#include "src/wasm/wasm-debug.h"
33
#include "src/wasm/wasm-engine.h"
34
#include "src/wasm/wasm-limits.h"
35
#include "src/wasm/wasm-objects-inl.h"
36
#include "src/wasm/wasm-serialization.h"
37
#include "src/wasm/wasm-value.h"
38 39

using v8::internal::wasm::ErrorThrower;
40
using v8::internal::wasm::ScheduledErrorThrower;
41 42 43

namespace v8 {

44 45
class WasmStreaming::WasmStreamingImpl {
 public:
46
  WasmStreamingImpl(
47
      Isolate* isolate, const char* api_method_name,
48 49 50
      std::shared_ptr<internal::wasm::CompilationResultResolver> resolver)
      : isolate_(isolate), resolver_(std::move(resolver)) {
    i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate_);
51
    auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
52 53
    streaming_decoder_ = i_isolate->wasm_engine()->StartStreamingCompilation(
        i_isolate, enabled_features, handle(i_isolate->context(), i_isolate),
54
        api_method_name, resolver_);
55 56 57
  }

  void OnBytesReceived(const uint8_t* bytes, size_t size) {
58
    streaming_decoder_->OnBytesReceived(i::VectorOf(bytes, size));
59 60
  }
  void Finish() { streaming_decoder_->Finish(); }
61

62 63 64 65 66 67 68 69 70 71 72 73
  void Abort(MaybeLocal<Value> exception) {
    i::HandleScope scope(reinterpret_cast<i::Isolate*>(isolate_));
    streaming_decoder_->Abort();

    // If no exception value is provided, we do not reject the promise. This can
    // happen when streaming compilation gets aborted when no script execution
    // is allowed anymore, e.g. when a browser tab gets refreshed.
    if (exception.IsEmpty()) return;

    resolver_->OnCompilationFailed(
        Utils::OpenHandle(*exception.ToLocalChecked()));
  }
74

75
  bool SetCompiledModuleBytes(const uint8_t* bytes, size_t size) {
76
    if (!i::wasm::IsSupportedVersion({bytes, size})) return false;
77 78 79
    return streaming_decoder_->SetCompiledModuleBytes({bytes, size});
  }

80 81
  void SetClient(std::shared_ptr<Client> client) {
    streaming_decoder_->SetModuleCompiledCallback(
82 83 84 85 86 87
        [client, streaming_decoder = streaming_decoder_](
            const std::shared_ptr<i::wasm::NativeModule>& native_module) {
          i::Vector<const char> url = streaming_decoder->url();
          auto compiled_wasm_module =
              CompiledWasmModule(native_module, url.begin(), url.size());
          client->OnModuleCompiled(compiled_wasm_module);
88 89 90
        });
  }

91 92 93 94
  void SetUrl(internal::Vector<const char> url) {
    streaming_decoder_->SetUrl(url);
  }

95
 private:
96
  Isolate* const isolate_;
97 98
  std::shared_ptr<internal::wasm::StreamingDecoder> streaming_decoder_;
  std::shared_ptr<internal::wasm::CompilationResultResolver> resolver_;
99 100 101
};

WasmStreaming::WasmStreaming(std::unique_ptr<WasmStreamingImpl> impl)
102 103 104
    : impl_(std::move(impl)) {
  TRACE_EVENT0("v8.wasm", "wasm.InitializeStreaming");
}
105 106 107 108 109 110

// The destructor is defined here because we have a unique_ptr with forward
// declaration.
WasmStreaming::~WasmStreaming() = default;

void WasmStreaming::OnBytesReceived(const uint8_t* bytes, size_t size) {
111
  TRACE_EVENT1("v8.wasm", "wasm.OnBytesReceived", "bytes", size);
112 113 114
  impl_->OnBytesReceived(bytes, size);
}

115 116 117 118
void WasmStreaming::Finish() {
  TRACE_EVENT0("v8.wasm", "wasm.FinishStreaming");
  impl_->Finish();
}
119 120

void WasmStreaming::Abort(MaybeLocal<Value> exception) {
121
  TRACE_EVENT0("v8.wasm", "wasm.AbortStreaming");
122 123 124
  impl_->Abort(exception);
}

125
bool WasmStreaming::SetCompiledModuleBytes(const uint8_t* bytes, size_t size) {
126
  TRACE_EVENT0("v8.wasm", "wasm.SetCompiledModuleBytes");
127 128 129
  return impl_->SetCompiledModuleBytes(bytes, size);
}

130
void WasmStreaming::SetClient(std::shared_ptr<Client> client) {
131
  TRACE_EVENT0("v8.wasm", "wasm.WasmStreaming.SetClient");
132 133 134
  impl_->SetClient(client);
}

135
void WasmStreaming::SetUrl(const char* url, size_t length) {
136
  TRACE_EVENT0("v8.wasm", "wasm.SetUrl");
137 138 139
  impl_->SetUrl(internal::VectorOf(url, length));
}

140 141 142
// static
std::shared_ptr<WasmStreaming> WasmStreaming::Unpack(Isolate* isolate,
                                                     Local<Value> value) {
143
  TRACE_EVENT0("v8.wasm", "wasm.WasmStreaming.Unpack");
144 145 146 147 148 149
  i::HandleScope scope(reinterpret_cast<i::Isolate*>(isolate));
  auto managed =
      i::Handle<i::Managed<WasmStreaming>>::cast(Utils::OpenHandle(*value));
  return managed->get();
}

150
namespace {
151

152 153 154 155 156 157 158 159 160
#define ASSIGN(type, var, expr)                      \
  Local<type> var;                                   \
  do {                                               \
    if (!expr.ToLocal(&var)) {                       \
      DCHECK(i_isolate->has_scheduled_exception());  \
      return;                                        \
    } else {                                         \
      DCHECK(!i_isolate->has_scheduled_exception()); \
    }                                                \
161 162
  } while (false)

163 164 165 166 167 168 169
i::Handle<i::String> v8_str(i::Isolate* isolate, const char* str) {
  return isolate->factory()->NewStringFromAsciiChecked(str);
}
Local<String> v8_str(Isolate* isolate, const char* str) {
  return Utils::ToLocal(v8_str(reinterpret_cast<i::Isolate*>(isolate), str));
}

170 171 172 173 174 175 176 177 178 179 180 181
#define GET_FIRST_ARGUMENT_AS(Type)                                  \
  i::MaybeHandle<i::Wasm##Type##Object> GetFirstArgumentAs##Type(    \
      const v8::FunctionCallbackInfo<v8::Value>& args,               \
      ErrorThrower* thrower) {                                       \
    i::Handle<i::Object> arg0 = Utils::OpenHandle(*args[0]);         \
    if (!arg0->IsWasm##Type##Object()) {                             \
      thrower->TypeError("Argument 0 must be a WebAssembly." #Type); \
      return {};                                                     \
    }                                                                \
    Local<Object> obj = Local<Object>::Cast(args[0]);                \
    return i::Handle<i::Wasm##Type##Object>::cast(                   \
        v8::Utils::OpenHandle(*obj));                                \
182 183
  }

184 185
GET_FIRST_ARGUMENT_AS(Module)
GET_FIRST_ARGUMENT_AS(Memory)
186
GET_FIRST_ARGUMENT_AS(Table)
187
GET_FIRST_ARGUMENT_AS(Global)
188 189

#undef GET_FIRST_ARGUMENT_AS
190 191

i::wasm::ModuleWireBytes GetFirstArgumentAsBytes(
192 193
    const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower,
    bool* is_shared) {
194
  const uint8_t* start = nullptr;
195
  size_t length = 0;
196
  v8::Local<v8::Value> source = args[0];
rossberg's avatar
rossberg committed
197
  if (source->IsArrayBuffer()) {
198
    // A raw array buffer was passed.
rossberg's avatar
rossberg committed
199
    Local<ArrayBuffer> buffer = Local<ArrayBuffer>::Cast(source);
200
    auto backing_store = buffer->GetBackingStore();
201

202 203
    start = reinterpret_cast<const uint8_t*>(backing_store->Data());
    length = backing_store->ByteLength();
204
    *is_shared = buffer->IsSharedArrayBuffer();
rossberg's avatar
rossberg committed
205
  } else if (source->IsTypedArray()) {
206
    // A TypedArray was passed.
rossberg's avatar
rossberg committed
207
    Local<TypedArray> array = Local<TypedArray>::Cast(source);
208 209
    Local<ArrayBuffer> buffer = array->Buffer();

210
    auto backing_store = buffer->GetBackingStore();
211

212 213
    start = reinterpret_cast<const uint8_t*>(backing_store->Data()) +
            array->ByteOffset();
214
    length = array->ByteLength();
215
    *is_shared = buffer->IsSharedArrayBuffer();
216
  } else {
217
    thrower->TypeError("Argument 0 must be a buffer source");
218
  }
219 220
  DCHECK_IMPLIES(length, start != nullptr);
  if (length == 0) {
221 222
    thrower->CompileError("BufferSource argument is empty");
  }
223 224
  size_t max_length = i::wasm::max_module_size();
  if (length > max_length) {
225
    thrower->RangeError("buffer source exceeds maximum size of %zu (is %zu)",
226
                        max_length, length);
227 228 229
  }
  if (thrower->error()) return i::wasm::ModuleWireBytes(nullptr, nullptr);
  return i::wasm::ModuleWireBytes(start, start + length);
230 231
}

232
i::MaybeHandle<i::JSReceiver> GetValueAsImports(Local<Value> arg,
233 234
                                                ErrorThrower* thrower) {
  if (arg->IsUndefined()) return {};
235

236
  if (!arg->IsObject()) {
237 238 239
    thrower->TypeError("Argument 1 must be an object");
    return {};
  }
240
  Local<Object> obj = Local<Object>::Cast(arg);
241
  return i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
242 243
}

244 245 246 247 248 249
namespace {
// This class resolves the result of WebAssembly.compile. It just places the
// compilation result in the supplied {promise}.
class AsyncCompilationResolver : public i::wasm::CompilationResultResolver {
 public:
  AsyncCompilationResolver(i::Isolate* isolate, i::Handle<i::JSPromise> promise)
250 251 252 253
      : promise_(isolate->global_handles()->Create(*promise)) {
    i::GlobalHandles::AnnotateStrongRetainer(promise_.location(),
                                             kGlobalPromiseHandle);
  }
254

255
  ~AsyncCompilationResolver() override {
256
    i::GlobalHandles::Destroy(promise_.location());
257 258 259
  }

  void OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result) override {
260 261
    if (finished_) return;
    finished_ = true;
262 263 264 265 266 267 268
    i::MaybeHandle<i::Object> promise_result =
        i::JSPromise::Resolve(promise_, result);
    CHECK_EQ(promise_result.is_null(),
             promise_->GetIsolate()->has_pending_exception());
  }

  void OnCompilationFailed(i::Handle<i::Object> error_reason) override {
269 270
    if (finished_) return;
    finished_ = true;
271 272 273 274 275 276 277
    i::MaybeHandle<i::Object> promise_result =
        i::JSPromise::Reject(promise_, error_reason);
    CHECK_EQ(promise_result.is_null(),
             promise_->GetIsolate()->has_pending_exception());
  }

 private:
278 279
  static constexpr char kGlobalPromiseHandle[] =
      "AsyncCompilationResolver::promise_";
280
  bool finished_ = false;
281 282 283
  i::Handle<i::JSPromise> promise_;
};

284 285
constexpr char AsyncCompilationResolver::kGlobalPromiseHandle[];

286 287 288 289 290 291 292
// This class resolves the result of WebAssembly.instantiate(module, imports).
// It just places the instantiation result in the supplied {promise}.
class InstantiateModuleResultResolver
    : public i::wasm::InstantiationResultResolver {
 public:
  InstantiateModuleResultResolver(i::Isolate* isolate,
                                  i::Handle<i::JSPromise> promise)
293 294 295 296
      : promise_(isolate->global_handles()->Create(*promise)) {
    i::GlobalHandles::AnnotateStrongRetainer(promise_.location(),
                                             kGlobalPromiseHandle);
  }
297

298
  ~InstantiateModuleResultResolver() override {
299
    i::GlobalHandles::Destroy(promise_.location());
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
  }

  void OnInstantiationSucceeded(
      i::Handle<i::WasmInstanceObject> instance) override {
    i::MaybeHandle<i::Object> promise_result =
        i::JSPromise::Resolve(promise_, instance);
    CHECK_EQ(promise_result.is_null(),
             promise_->GetIsolate()->has_pending_exception());
  }

  void OnInstantiationFailed(i::Handle<i::Object> error_reason) override {
    i::MaybeHandle<i::Object> promise_result =
        i::JSPromise::Reject(promise_, error_reason);
    CHECK_EQ(promise_result.is_null(),
             promise_->GetIsolate()->has_pending_exception());
  }

 private:
318 319
  static constexpr char kGlobalPromiseHandle[] =
      "InstantiateModuleResultResolver::promise_";
320 321 322
  i::Handle<i::JSPromise> promise_;
};

323 324
constexpr char InstantiateModuleResultResolver::kGlobalPromiseHandle[];

325 326 327 328 329 330 331 332 333 334 335
// This class resolves the result of WebAssembly.instantiate(bytes, imports).
// For that it creates a new {JSObject} which contains both the provided
// {WasmModuleObject} and the resulting {WebAssemblyInstanceObject} itself.
class InstantiateBytesResultResolver
    : public i::wasm::InstantiationResultResolver {
 public:
  InstantiateBytesResultResolver(i::Isolate* isolate,
                                 i::Handle<i::JSPromise> promise,
                                 i::Handle<i::WasmModuleObject> module)
      : isolate_(isolate),
        promise_(isolate_->global_handles()->Create(*promise)),
336 337 338 339 340 341
        module_(isolate_->global_handles()->Create(*module)) {
    i::GlobalHandles::AnnotateStrongRetainer(promise_.location(),
                                             kGlobalPromiseHandle);
    i::GlobalHandles::AnnotateStrongRetainer(module_.location(),
                                             kGlobalModuleHandle);
  }
342

343
  ~InstantiateBytesResultResolver() override {
344 345
    i::GlobalHandles::Destroy(promise_.location());
    i::GlobalHandles::Destroy(module_.location());
346 347 348 349 350 351 352 353 354 355
  }

  void OnInstantiationSucceeded(
      i::Handle<i::WasmInstanceObject> instance) override {
    // The result is a JSObject with 2 fields which contain the
    // WasmInstanceObject and the WasmModuleObject.
    i::Handle<i::JSObject> result =
        isolate_->factory()->NewJSObject(isolate_->object_function());

    i::Handle<i::String> instance_name =
356
        isolate_->factory()->NewStringFromStaticChars("instance");
357 358

    i::Handle<i::String> module_name =
359
        isolate_->factory()->NewStringFromStaticChars("module");
360

361 362 363
    i::JSObject::AddProperty(isolate_, result, instance_name, instance,
                             i::NONE);
    i::JSObject::AddProperty(isolate_, result, module_name, module_, i::NONE);
364 365 366 367 368 369 370 371 372 373 374 375 376

    i::MaybeHandle<i::Object> promise_result =
        i::JSPromise::Resolve(promise_, result);
    CHECK_EQ(promise_result.is_null(), isolate_->has_pending_exception());
  }

  void OnInstantiationFailed(i::Handle<i::Object> error_reason) override {
    i::MaybeHandle<i::Object> promise_result =
        i::JSPromise::Reject(promise_, error_reason);
    CHECK_EQ(promise_result.is_null(), isolate_->has_pending_exception());
  }

 private:
377 378 379 380
  static constexpr char kGlobalPromiseHandle[] =
      "InstantiateBytesResultResolver::promise_";
  static constexpr char kGlobalModuleHandle[] =
      "InstantiateBytesResultResolver::module_";
381 382 383 384 385
  i::Isolate* isolate_;
  i::Handle<i::JSPromise> promise_;
  i::Handle<i::WasmModuleObject> module_;
};

386 387 388
constexpr char InstantiateBytesResultResolver::kGlobalPromiseHandle[];
constexpr char InstantiateBytesResultResolver::kGlobalModuleHandle[];

389 390 391 392 393 394 395 396 397 398 399 400 401 402
// This class is the {CompilationResultResolver} for
// WebAssembly.instantiate(bytes, imports). When compilation finishes,
// {AsyncInstantiate} is started on the compilation result.
class AsyncInstantiateCompileResultResolver
    : public i::wasm::CompilationResultResolver {
 public:
  AsyncInstantiateCompileResultResolver(
      i::Isolate* isolate, i::Handle<i::JSPromise> promise,
      i::MaybeHandle<i::JSReceiver> maybe_imports)
      : isolate_(isolate),
        promise_(isolate_->global_handles()->Create(*promise)),
        maybe_imports_(maybe_imports.is_null()
                           ? maybe_imports
                           : isolate_->global_handles()->Create(
403 404 405 406 407 408 409 410
                                 *maybe_imports.ToHandleChecked())) {
    i::GlobalHandles::AnnotateStrongRetainer(promise_.location(),
                                             kGlobalPromiseHandle);
    if (!maybe_imports_.is_null()) {
      i::GlobalHandles::AnnotateStrongRetainer(
          maybe_imports_.ToHandleChecked().location(), kGlobalImportsHandle);
    }
  }
411

412
  ~AsyncInstantiateCompileResultResolver() override {
413
    i::GlobalHandles::Destroy(promise_.location());
414
    if (!maybe_imports_.is_null()) {
415
      i::GlobalHandles::Destroy(maybe_imports_.ToHandleChecked().location());
416 417 418 419
    }
  }

  void OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result) override {
420 421
    if (finished_) return;
    finished_ = true;
422 423
    isolate_->wasm_engine()->AsyncInstantiate(
        isolate_,
424 425
        std::make_unique<InstantiateBytesResultResolver>(isolate_, promise_,
                                                         result),
426 427 428 429
        result, maybe_imports_);
  }

  void OnCompilationFailed(i::Handle<i::Object> error_reason) override {
430 431
    if (finished_) return;
    finished_ = true;
432 433 434 435 436 437
    i::MaybeHandle<i::Object> promise_result =
        i::JSPromise::Reject(promise_, error_reason);
    CHECK_EQ(promise_result.is_null(), isolate_->has_pending_exception());
  }

 private:
438 439 440 441
  static constexpr char kGlobalPromiseHandle[] =
      "AsyncInstantiateCompileResultResolver::promise_";
  static constexpr char kGlobalImportsHandle[] =
      "AsyncInstantiateCompileResultResolver::module_";
442
  bool finished_ = false;
443 444 445 446 447
  i::Isolate* isolate_;
  i::Handle<i::JSPromise> promise_;
  i::MaybeHandle<i::JSReceiver> maybe_imports_;
};

448 449
constexpr char AsyncInstantiateCompileResultResolver::kGlobalPromiseHandle[];
constexpr char AsyncInstantiateCompileResultResolver::kGlobalImportsHandle[];
450 451 452 453 454 455

std::string ToString(const char* name) { return std::string(name); }

std::string ToString(const i::Handle<i::String> name) {
  return std::string("Property '") + name->ToCString().get() + "'";
}
456

457 458 459
// Web IDL: '[EnforceRange] unsigned long'
// Previously called ToNonWrappingUint32 in the draft WebAssembly JS spec.
// https://heycam.github.io/webidl/#EnforceRange
460 461 462
template <typename T>
bool EnforceUint32(T argument_name, Local<v8::Value> v, Local<Context> context,
                   ErrorThrower* thrower, uint32_t* res) {
463 464 465
  double double_number;

  if (!v->NumberValue(context).To(&double_number)) {
466 467
    thrower->TypeError("%s must be convertible to a number",
                       ToString(argument_name).c_str());
468 469 470
    return false;
  }
  if (!std::isfinite(double_number)) {
471 472
    thrower->TypeError("%s must be convertible to a valid number",
                       ToString(argument_name).c_str());
473 474 475
    return false;
  }
  if (double_number < 0) {
476 477
    thrower->TypeError("%s must be non-negative",
                       ToString(argument_name).c_str());
478 479 480
    return false;
  }
  if (double_number > std::numeric_limits<uint32_t>::max()) {
481 482
    thrower->TypeError("%s must be in the unsigned long range",
                       ToString(argument_name).c_str());
483 484 485 486 487 488
    return false;
  }

  *res = static_cast<uint32_t>(double_number);
  return true;
}
489
}  // namespace
490

491
// WebAssembly.compile(bytes) -> Promise
rossberg's avatar
rossberg committed
492
void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
493
  constexpr const char* kAPIMethodName = "WebAssembly.compile()";
rossberg's avatar
rossberg committed
494
  v8::Isolate* isolate = args.GetIsolate();
495
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
496

rossberg's avatar
rossberg committed
497
  HandleScope scope(isolate);
498
  ScheduledErrorThrower thrower(i_isolate, kAPIMethodName);
rossberg's avatar
rossberg committed
499

500 501 502 503
  if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
    thrower.CompileError("Wasm code generation disallowed by embedder");
  }

504
  Local<Context> context = isolate->GetCurrentContext();
505 506
  ASSIGN(Promise::Resolver, promise_resolver, Promise::Resolver::New(context));
  Local<Promise> promise = promise_resolver->GetPromise();
507
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
508 509
  return_value.Set(promise);

510
  std::shared_ptr<i::wasm::CompilationResultResolver> resolver(
511
      new AsyncCompilationResolver(i_isolate, Utils::OpenHandle(*promise)));
512

513 514
  bool is_shared = false;
  auto bytes = GetFirstArgumentAsBytes(args, &thrower, &is_shared);
515
  if (thrower.error()) {
516
    resolver->OnCompilationFailed(thrower.Reify());
517
    return;
518
  }
519
  // Asynchronous compilation handles copying wire bytes if necessary.
520
  auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
521
  i_isolate->wasm_engine()->AsyncCompile(i_isolate, enabled_features,
522 523
                                         std::move(resolver), bytes, is_shared,
                                         kAPIMethodName);
rossberg's avatar
rossberg committed
524 525
}

526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
void WasmStreamingCallbackForTesting(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);

  HandleScope scope(isolate);
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.compile()");

  std::shared_ptr<v8::WasmStreaming> streaming =
      v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());

  bool is_shared = false;
  i::wasm::ModuleWireBytes bytes =
      GetFirstArgumentAsBytes(args, &thrower, &is_shared);
  if (thrower.error()) {
    streaming->Abort(Utils::ToLocal(thrower.Reify()));
    return;
  }
  streaming->OnBytesReceived(bytes.start(), bytes.length());
  streaming->Finish();
  CHECK(!thrower.error());
}

void WasmStreamingPromiseFailedCallback(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  std::shared_ptr<v8::WasmStreaming> streaming =
      v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
  streaming->Abort(args[0]);
}

556 557
// WebAssembly.compileStreaming(Response | Promise<Response>)
//   -> Promise<WebAssembly.Module>
558 559 560 561 562
void WebAssemblyCompileStreaming(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
563 564
  const char* const kAPIMethodName = "WebAssembly.compileStreaming()";
  ScheduledErrorThrower thrower(i_isolate, kAPIMethodName);
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
  Local<Context> context = isolate->GetCurrentContext();

  // Create and assign the return value of this function.
  ASSIGN(Promise::Resolver, result_resolver, Promise::Resolver::New(context));
  Local<Promise> promise = result_resolver->GetPromise();
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(promise);

  // Prepare the CompilationResultResolver for the compilation.
  auto resolver = std::make_shared<AsyncCompilationResolver>(
      i_isolate, Utils::OpenHandle(*promise));

  if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
    thrower.CompileError("Wasm code generation disallowed by embedder");
    resolver->OnCompilationFailed(thrower.Reify());
    return;
  }

  // Allocate the streaming decoder in a Managed so we can pass it to the
  // embedder.
  i::Handle<i::Managed<WasmStreaming>> data =
      i::Managed<WasmStreaming>::Allocate(
          i_isolate, 0,
588
          std::make_unique<WasmStreaming::WasmStreamingImpl>(
589
              isolate, kAPIMethodName, resolver));
590 591 592 593 594 595

  DCHECK_NOT_NULL(i_isolate->wasm_streaming_callback());
  ASSIGN(
      v8::Function, compile_callback,
      v8::Function::New(context, i_isolate->wasm_streaming_callback(),
                        Utils::ToLocal(i::Handle<i::Object>::cast(data)), 1));
596 597 598 599
  ASSIGN(
      v8::Function, reject_callback,
      v8::Function::New(context, WasmStreamingPromiseFailedCallback,
                        Utils::ToLocal(i::Handle<i::Object>::cast(data)), 1));
600 601 602 603 604 605 606 607 608 609 610 611 612

  // The parameter may be of type {Response} or of type {Promise<Response>}.
  // Treat either case of parameter as Promise.resolve(parameter)
  // as per https://www.w3.org/2001/tag/doc/promises-guide#resolve-arguments

  // Ending with:
  //    return Promise.resolve(parameter).then(compile_callback);
  ASSIGN(Promise::Resolver, input_resolver, Promise::Resolver::New(context));
  if (!input_resolver->Resolve(context, args[0]).IsJust()) return;

  // We do not have any use of the result here. The {compile_callback} will
  // start streaming compilation, which will eventually resolve the promise we
  // set as result value.
613 614
  USE(input_resolver->GetPromise()->Then(context, compile_callback,
                                         reject_callback));
615 616
}

617
// WebAssembly.validate(bytes) -> bool
618 619
void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
620
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
621
  HandleScope scope(isolate);
622
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.validate()");
623

624 625
  bool is_shared = false;
  auto bytes = GetFirstArgumentAsBytes(args, &thrower, &is_shared);
626 627

  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
628 629

  if (thrower.error()) {
630
    if (thrower.wasm_error()) thrower.Reset();  // Clear error.
631
    return_value.Set(v8::False(isolate));
632 633 634
    return;
  }

635
  auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
636 637 638 639
  bool validated = false;
  if (is_shared) {
    // Make a copy of the wire bytes to avoid concurrent modification.
    std::unique_ptr<uint8_t[]> copy(new uint8_t[bytes.length()]);
640
    base::Memcpy(copy.get(), bytes.start(), bytes.length());
641 642
    i::wasm::ModuleWireBytes bytes_copy(copy.get(),
                                        copy.get() + bytes.length());
643 644
    validated = i_isolate->wasm_engine()->SyncValidate(
        i_isolate, enabled_features, bytes_copy);
645 646
  } else {
    // The wire bytes are not shared, OK to use them directly.
647 648
    validated = i_isolate->wasm_engine()->SyncValidate(i_isolate,
                                                       enabled_features, bytes);
649
  }
650 651

  return_value.Set(Boolean::New(isolate, validated));
652 653
}

654
// new WebAssembly.Module(bytes) -> WebAssembly.Module
rossberg's avatar
rossberg committed
655 656
void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
657
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
658 659
  if (i_isolate->wasm_module_callback()(args)) return;

rossberg's avatar
rossberg committed
660
  HandleScope scope(isolate);
661
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module()");
rossberg's avatar
rossberg committed
662

663 664 665 666
  if (!args.IsConstructCall()) {
    thrower.TypeError("WebAssembly.Module must be invoked with 'new'");
    return;
  }
667 668 669 670 671
  if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
    thrower.CompileError("Wasm code generation disallowed by embedder");
    return;
  }

672 673
  bool is_shared = false;
  auto bytes = GetFirstArgumentAsBytes(args, &thrower, &is_shared);
674

675 676 677
  if (thrower.error()) {
    return;
  }
678
  auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
679 680 681 682
  i::MaybeHandle<i::Object> module_obj;
  if (is_shared) {
    // Make a copy of the wire bytes to avoid concurrent modification.
    std::unique_ptr<uint8_t[]> copy(new uint8_t[bytes.length()]);
683
    base::Memcpy(copy.get(), bytes.start(), bytes.length());
684 685
    i::wasm::ModuleWireBytes bytes_copy(copy.get(),
                                        copy.get() + bytes.length());
686 687
    module_obj = i_isolate->wasm_engine()->SyncCompile(
        i_isolate, enabled_features, &thrower, bytes_copy);
688 689
  } else {
    // The wire bytes are not shared, OK to use them directly.
690 691
    module_obj = i_isolate->wasm_engine()->SyncCompile(
        i_isolate, enabled_features, &thrower, bytes);
692 693
  }

rossberg's avatar
rossberg committed
694 695 696 697 698 699
  if (module_obj.is_null()) return;

  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(Utils::ToLocal(module_obj.ToHandleChecked()));
}

700
// WebAssembly.Module.imports(module) -> Array<Import>
701 702 703 704
void WebAssemblyModuleImports(const v8::FunctionCallbackInfo<v8::Value>& args) {
  HandleScope scope(args.GetIsolate());
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
705
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module.imports()");
706

707
  auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
708 709 710
  if (thrower.error()) return;
  auto imports = i::wasm::GetImports(i_isolate, maybe_module.ToHandleChecked());
  args.GetReturnValue().Set(Utils::ToLocal(imports));
711 712
}

713
// WebAssembly.Module.exports(module) -> Array<Export>
714 715 716 717
void WebAssemblyModuleExports(const v8::FunctionCallbackInfo<v8::Value>& args) {
  HandleScope scope(args.GetIsolate());
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
718
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module.exports()");
719

720
  auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
721 722 723
  if (thrower.error()) return;
  auto exports = i::wasm::GetExports(i_isolate, maybe_module.ToHandleChecked());
  args.GetReturnValue().Set(Utils::ToLocal(exports));
724
}
725

726
// WebAssembly.Module.customSections(module, name) -> Array<Section>
727 728 729 730 731
void WebAssemblyModuleCustomSections(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  HandleScope scope(args.GetIsolate());
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
732 733
  ScheduledErrorThrower thrower(i_isolate,
                                "WebAssembly.Module.customSections()");
734

735
  auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
736
  if (thrower.error()) return;
737

738 739 740 741 742
  if (args[1]->IsUndefined()) {
    thrower.TypeError("Argument 1 is required");
    return;
  }

743 744 745 746
  i::MaybeHandle<i::Object> maybe_name =
      i::Object::ToString(i_isolate, Utils::OpenHandle(*args[1]));
  i::Handle<i::Object> name;
  if (!maybe_name.ToHandle(&name)) return;
747 748 749 750 751
  auto custom_sections =
      i::wasm::GetCustomSections(i_isolate, maybe_module.ToHandleChecked(),
                                 i::Handle<i::String>::cast(name), &thrower);
  if (thrower.error()) return;
  args.GetReturnValue().Set(Utils::ToLocal(custom_sections));
752 753
}

754 755 756 757 758
MaybeLocal<Value> WebAssemblyInstantiateImpl(Isolate* isolate,
                                             Local<Value> module,
                                             Local<Value> ffi) {
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);

759 760
  i::MaybeHandle<i::Object> instance_object;
  {
761
    ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Instance()");
762 763 764 765 766 767 768 769 770

    // TODO(ahaas): These checks on the module should not be necessary here They
    // are just a workaround for https://crbug.com/837417.
    i::Handle<i::Object> module_obj = Utils::OpenHandle(*module);
    if (!module_obj->IsWasmModuleObject()) {
      thrower.TypeError("Argument 0 must be a WebAssembly.Module object");
      return {};
    }

771 772 773 774
    i::MaybeHandle<i::JSReceiver> maybe_imports =
        GetValueAsImports(ffi, &thrower);
    if (thrower.error()) return {};

775
    instance_object = i_isolate->wasm_engine()->SyncInstantiate(
776 777
        i_isolate, &thrower, i::Handle<i::WasmModuleObject>::cast(module_obj),
        maybe_imports, i::MaybeHandle<i::JSArrayBuffer>());
778
  }
779 780 781

  DCHECK_EQ(instance_object.is_null(), i_isolate->has_scheduled_exception());
  if (instance_object.is_null()) return {};
782 783 784
  return Utils::ToLocal(instance_object.ToHandleChecked());
}

785
// new WebAssembly.Instance(module, imports) -> WebAssembly.Instance
786
void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
787
  Isolate* isolate = args.GetIsolate();
788 789 790
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  i_isolate->CountUsage(
      v8::Isolate::UseCounterFeature::kWebAssemblyInstantiation);
791

rossberg's avatar
rossberg committed
792
  HandleScope scope(args.GetIsolate());
793 794
  if (i_isolate->wasm_instance_callback()(args)) return;

795
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Instance()");
796 797 798 799
  if (!args.IsConstructCall()) {
    thrower.TypeError("WebAssembly.Instance must be invoked with 'new'");
    return;
  }
800

801
  GetFirstArgumentAsModule(args, &thrower);
802
  if (thrower.error()) return;
803

804 805 806
  // If args.Length < 2, this will be undefined - see FunctionCallbackInfo.
  // We'll check for that in WebAssemblyInstantiateImpl.
  Local<Value> data = args[1];
807

808 809 810 811
  Local<Value> instance;
  if (WebAssemblyInstantiateImpl(isolate, args[0], data).ToLocal(&instance)) {
    args.GetReturnValue().Set(instance);
  }
812 813
}

814 815 816
// WebAssembly.instantiateStreaming(Response | Promise<Response> [, imports])
//   -> Promise<ResultObject>
// (where ResultObject has a "module" and an "instance" field)
817 818 819 820
void WebAssemblyInstantiateStreaming(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
821 822
  i_isolate->CountUsage(
      v8::Isolate::UseCounterFeature::kWebAssemblyInstantiation);
823

824
  HandleScope scope(isolate);
825
  Local<Context> context = isolate->GetCurrentContext();
826 827
  const char* const kAPIMethodName = "WebAssembly.instantiateStreaming()";
  ScheduledErrorThrower thrower(i_isolate, kAPIMethodName);
828

829 830 831 832 833
  // Create and assign the return value of this function.
  ASSIGN(Promise::Resolver, result_resolver, Promise::Resolver::New(context));
  Local<Promise> promise = result_resolver->GetPromise();
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(promise);
834

835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
  // Create an InstantiateResultResolver in case there is an issue with the
  // passed parameters.
  std::unique_ptr<i::wasm::InstantiationResultResolver> resolver(
      new InstantiateModuleResultResolver(i_isolate,
                                          Utils::OpenHandle(*promise)));

  if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
    thrower.CompileError("Wasm code generation disallowed by embedder");
    resolver->OnInstantiationFailed(thrower.Reify());
    return;
  }

  // If args.Length < 2, this will be undefined - see FunctionCallbackInfo.
  Local<Value> ffi = args[1];
  i::MaybeHandle<i::JSReceiver> maybe_imports =
      GetValueAsImports(ffi, &thrower);

  if (thrower.error()) {
    resolver->OnInstantiationFailed(thrower.Reify());
    return;
  }

  // We start compilation now, we have no use for the
  // {InstantiationResultResolver}.
  resolver.reset();

  std::shared_ptr<i::wasm::CompilationResultResolver> compilation_resolver(
      new AsyncInstantiateCompileResultResolver(
          i_isolate, Utils::OpenHandle(*promise), maybe_imports));

  // Allocate the streaming decoder in a Managed so we can pass it to the
  // embedder.
  i::Handle<i::Managed<WasmStreaming>> data =
      i::Managed<WasmStreaming>::Allocate(
          i_isolate, 0,
870
          std::make_unique<WasmStreaming::WasmStreamingImpl>(
871
              isolate, kAPIMethodName, compilation_resolver));
872 873 874 875 876 877

  DCHECK_NOT_NULL(i_isolate->wasm_streaming_callback());
  ASSIGN(
      v8::Function, compile_callback,
      v8::Function::New(context, i_isolate->wasm_streaming_callback(),
                        Utils::ToLocal(i::Handle<i::Object>::cast(data)), 1));
878 879 880 881
  ASSIGN(
      v8::Function, reject_callback,
      v8::Function::New(context, WasmStreamingPromiseFailedCallback,
                        Utils::ToLocal(i::Handle<i::Object>::cast(data)), 1));
882 883 884 885 886 887 888 889 890 891 892 893 894

  // The parameter may be of type {Response} or of type {Promise<Response>}.
  // Treat either case of parameter as Promise.resolve(parameter)
  // as per https://www.w3.org/2001/tag/doc/promises-guide#resolve-arguments

  // Ending with:
  //    return Promise.resolve(parameter).then(compile_callback);
  ASSIGN(Promise::Resolver, input_resolver, Promise::Resolver::New(context));
  if (!input_resolver->Resolve(context, args[0]).IsJust()) return;

  // We do not have any use of the result here. The {compile_callback} will
  // start streaming compilation, which will eventually resolve the promise we
  // set as result value.
895 896
  USE(input_resolver->GetPromise()->Then(context, compile_callback,
                                         reject_callback));
897 898
}

899 900 901
// WebAssembly.instantiate(module, imports) -> WebAssembly.Instance
// WebAssembly.instantiate(bytes, imports) ->
//     {module: WebAssembly.Module, instance: WebAssembly.Instance}
902
void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
903
  constexpr const char* kAPIMethodName = "WebAssembly.instantiate()";
904 905
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
906 907
  i_isolate->CountUsage(
      v8::Isolate::UseCounterFeature::kWebAssemblyInstantiation);
908

909
  ScheduledErrorThrower thrower(i_isolate, kAPIMethodName);
910 911 912

  HandleScope scope(isolate);

913
  Local<Context> context = isolate->GetCurrentContext();
914

915 916
  ASSIGN(Promise::Resolver, promise_resolver, Promise::Resolver::New(context));
  Local<Promise> promise = promise_resolver->GetPromise();
917
  args.GetReturnValue().Set(promise);
918

919 920 921 922
  std::unique_ptr<i::wasm::InstantiationResultResolver> resolver(
      new InstantiateModuleResultResolver(i_isolate,
                                          Utils::OpenHandle(*promise)));

923 924
  Local<Value> first_arg_value = args[0];
  i::Handle<i::Object> first_arg = Utils::OpenHandle(*first_arg_value);
925 926 927
  if (!first_arg->IsJSObject()) {
    thrower.TypeError(
        "Argument 0 must be a buffer source or a WebAssembly.Module object");
928 929 930 931 932 933 934 935 936 937 938
    resolver->OnInstantiationFailed(thrower.Reify());
    return;
  }

  // If args.Length < 2, this will be undefined - see FunctionCallbackInfo.
  Local<Value> ffi = args[1];
  i::MaybeHandle<i::JSReceiver> maybe_imports =
      GetValueAsImports(ffi, &thrower);

  if (thrower.error()) {
    resolver->OnInstantiationFailed(thrower.Reify());
939 940
    return;
  }
941

942
  if (first_arg->IsWasmModuleObject()) {
943 944 945
    i::Handle<i::WasmModuleObject> module_obj =
        i::Handle<i::WasmModuleObject>::cast(first_arg);

946 947 948 949
    i_isolate->wasm_engine()->AsyncInstantiate(i_isolate, std::move(resolver),
                                               module_obj, maybe_imports);
    return;
  }
950

951 952 953 954
  bool is_shared = false;
  auto bytes = GetFirstArgumentAsBytes(args, &thrower, &is_shared);
  if (thrower.error()) {
    resolver->OnInstantiationFailed(thrower.Reify());
955
    return;
956
  }
957

958 959 960 961
  // We start compilation now, we have no use for the
  // {InstantiationResultResolver}.
  resolver.reset();

962
  std::shared_ptr<i::wasm::CompilationResultResolver> compilation_resolver(
963 964 965 966 967 968 969 970
      new AsyncInstantiateCompileResultResolver(
          i_isolate, Utils::OpenHandle(*promise), maybe_imports));

  // The first parameter is a buffer source, we have to check if we are allowed
  // to compile it.
  if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
    thrower.CompileError("Wasm code generation disallowed by embedder");
    compilation_resolver->OnCompilationFailed(thrower.Reify());
971
    return;
972 973 974
  }

  // Asynchronous compilation handles copying wire bytes if necessary.
975
  auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
976 977
  i_isolate->wasm_engine()->AsyncCompile(i_isolate, enabled_features,
                                         std::move(compilation_resolver), bytes,
978
                                         is_shared, kAPIMethodName);
979
}
980 981

bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
982 983
                        Local<Context> context, v8::Local<v8::Value> value,
                        i::Handle<i::String> property_name, int64_t* result,
984
                        int64_t lower_bound, uint64_t upper_bound) {
985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
  uint32_t number;
  if (!EnforceUint32(property_name, value, context, thrower, &number)) {
    return false;
  }
  if (number < lower_bound) {
    thrower->RangeError("Property '%s': value %" PRIu32
                        " is below the lower bound %" PRIx64,
                        property_name->ToCString().get(), number, lower_bound);
    return false;
  }
  if (number > upper_bound) {
    thrower->RangeError("Property '%s': value %" PRIu32
                        " is above the upper bound %" PRIu64,
                        property_name->ToCString().get(), number, upper_bound);
    return false;
  }

  *result = static_cast<int64_t>(number);
  return true;
}

bool GetOptionalIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
                                Local<Context> context,
                                Local<v8::Object> object,
1009 1010 1011
                                Local<String> property, bool* has_property,
                                int64_t* result, int64_t lower_bound,
                                uint64_t upper_bound) {
1012 1013 1014 1015 1016 1017 1018 1019
  v8::Local<v8::Value> value;
  if (!object->Get(context, property).ToLocal(&value)) {
    return false;
  }

  // Web IDL: dictionary presence
  // https://heycam.github.io/webidl/#dfn-present
  if (value->IsUndefined()) {
1020
    if (has_property != nullptr) *has_property = false;
1021 1022
    return true;
  }
1023

1024
  if (has_property != nullptr) *has_property = true;
1025 1026 1027 1028
  i::Handle<i::String> property_name = v8::Utils::OpenHandle(*property);

  return GetIntegerProperty(isolate, thrower, context, value, property_name,
                            result, lower_bound, upper_bound);
1029 1030
}

1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
// Fetch 'initial' or 'minimum' property from object. If both are provided,
// 'initial' is used.
// TODO(aseemgarg): change behavior when the following bug is resolved:
// https://github.com/WebAssembly/js-types/issues/6
bool GetInitialOrMinimumProperty(v8::Isolate* isolate, ErrorThrower* thrower,
                                 Local<Context> context,
                                 Local<v8::Object> object, int64_t* result,
                                 int64_t lower_bound, uint64_t upper_bound) {
  bool has_initial = false;
  if (!GetOptionalIntegerProperty(isolate, thrower, context, object,
                                  v8_str(isolate, "initial"), &has_initial,
                                  result, lower_bound, upper_bound)) {
    return false;
  }
1045 1046
  auto enabled_features = i::wasm::WasmFeatures::FromFlags();
  if (!has_initial && enabled_features.has_type_reflection()) {
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
    if (!GetOptionalIntegerProperty(isolate, thrower, context, object,
                                    v8_str(isolate, "minimum"), &has_initial,
                                    result, lower_bound, upper_bound)) {
      return false;
    }
  }
  if (!has_initial) {
    // TODO(aseemgarg): update error message when the spec issue is resolved.
    thrower->TypeError("Property 'initial' is required");
    return false;
  }
  return true;
}

1061
// new WebAssembly.Table(args) -> WebAssembly.Table
1062 1063
void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
1064
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1065
  HandleScope scope(isolate);
1066
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table()");
1067 1068 1069 1070
  if (!args.IsConstructCall()) {
    thrower.TypeError("WebAssembly.Table must be invoked with 'new'");
    return;
  }
1071
  if (!args[0]->IsObject()) {
1072 1073 1074 1075
    thrower.TypeError("Argument 0 must be a table descriptor");
    return;
  }
  Local<Context> context = isolate->GetCurrentContext();
1076
  Local<v8::Object> descriptor = Local<Object>::Cast(args[0]);
1077
  i::wasm::ValueType type;
1078 1079 1080 1081 1082 1083 1084 1085
  // The descriptor's 'element'.
  {
    v8::MaybeLocal<v8::Value> maybe =
        descriptor->Get(context, v8_str(isolate, "element"));
    v8::Local<v8::Value> value;
    if (!maybe.ToLocal(&value)) return;
    v8::Local<v8::String> string;
    if (!value->ToString(context).ToLocal(&string)) return;
1086
    auto enabled_features = i::wasm::WasmFeatures::FromFlags();
1087
    // The JS api uses 'anyfunc' instead of 'funcref'.
1088
    if (string->StringEquals(v8_str(isolate, "anyfunc"))) {
1089
      type = i::wasm::kWasmFuncRef;
1090 1091 1092
    } else if (enabled_features.has_reftypes() &&
               string->StringEquals(v8_str(isolate, "externref"))) {
      type = i::wasm::kWasmExternRef;
1093
    } else {
1094 1095
      thrower.TypeError(
          "Descriptor property 'element' must be a WebAssembly reference type");
1096 1097 1098
      return;
    }
  }
1099

1100
  int64_t initial = 0;
1101 1102 1103
  if (!GetInitialOrMinimumProperty(isolate, &thrower, context, descriptor,
                                   &initial, 0,
                                   i::wasm::max_table_init_entries())) {
1104 1105 1106
    return;
  }
  // The descriptor's 'maximum'.
1107
  int64_t maximum = -1;
1108
  bool has_maximum = true;
1109 1110 1111 1112
  if (!GetOptionalIntegerProperty(isolate, &thrower, context, descriptor,
                                  v8_str(isolate, "maximum"), &has_maximum,
                                  &maximum, initial,
                                  std::numeric_limits<uint32_t>::max())) {
1113
    return;
1114 1115
  }

1116
  i::Handle<i::FixedArray> fixed_array;
1117 1118 1119 1120
  i::Handle<i::JSObject> table_obj =
      i::WasmTableObject::New(i_isolate, i::Handle<i::WasmInstanceObject>(),
                              type, static_cast<uint32_t>(initial), has_maximum,
                              static_cast<uint32_t>(maximum), &fixed_array);
1121 1122 1123
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(Utils::ToLocal(table_obj));
}
1124

1125 1126
void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
1127
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1128
  HandleScope scope(isolate);
1129
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory()");
1130 1131 1132 1133
  if (!args.IsConstructCall()) {
    thrower.TypeError("WebAssembly.Memory must be invoked with 'new'");
    return;
  }
1134
  if (!args[0]->IsObject()) {
1135
    thrower.TypeError("Argument 0 must be a memory descriptor");
1136 1137 1138
    return;
  }
  Local<Context> context = isolate->GetCurrentContext();
1139
  Local<v8::Object> descriptor = Local<Object>::Cast(args[0]);
1140

1141
  int64_t initial = 0;
1142
  if (!GetInitialOrMinimumProperty(isolate, &thrower, context, descriptor,
1143
                                   &initial, 0, i::wasm::max_mem_pages())) {
1144 1145
    return;
  }
1146
  // The descriptor's 'maximum'.
1147
  int64_t maximum = i::WasmMemoryObject::kNoMaximum;
1148
  if (!GetOptionalIntegerProperty(isolate, &thrower, context, descriptor,
1149
                                  v8_str(isolate, "maximum"), nullptr, &maximum,
1150
                                  initial, i::wasm::max_mem_pages())) {
1151
    return;
1152
  }
1153

1154
  auto shared = i::SharedFlag::kNotShared;
1155 1156
  auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
  if (enabled_features.has_threads()) {
1157 1158
    // Shared property of descriptor
    Local<String> shared_key = v8_str(isolate, "shared");
1159 1160 1161 1162
    v8::MaybeLocal<v8::Value> maybe_value =
        descriptor->Get(context, shared_key);
    v8::Local<v8::Value> value;
    if (maybe_value.ToLocal(&value)) {
1163 1164
      shared = value->BooleanValue(isolate) ? i::SharedFlag::kShared
                                            : i::SharedFlag::kNotShared;
1165 1166 1167
    } else {
      DCHECK(i_isolate->has_scheduled_exception());
      return;
1168
    }
1169

1170
    // Throw TypeError if shared is true, and the descriptor has no "maximum"
1171
    if (shared == i::SharedFlag::kShared && maximum == -1) {
1172 1173
      thrower.TypeError(
          "If shared is true, maximum property should be defined.");
1174
      return;
1175 1176 1177
    }
  }

1178
  i::Handle<i::JSObject> memory_obj;
1179 1180
  if (!i::WasmMemoryObject::New(i_isolate, static_cast<int>(initial),
                                static_cast<int>(maximum), shared)
1181
           .ToHandle(&memory_obj)) {
1182 1183 1184
    thrower.RangeError("could not allocate memory");
    return;
  }
1185
  if (shared == i::SharedFlag::kShared) {
1186 1187 1188
    i::Handle<i::JSArrayBuffer> buffer(
        i::Handle<i::WasmMemoryObject>::cast(memory_obj)->array_buffer(),
        i_isolate);
1189
    Maybe<bool> result =
1190
        buffer->SetIntegrityLevel(buffer, i::FROZEN, i::kDontThrow);
1191 1192 1193
    if (!result.FromJust()) {
      thrower.TypeError(
          "Status of setting SetIntegrityLevel of buffer is false.");
1194
      return;
1195 1196
    }
  }
1197
  args.GetReturnValue().Set(Utils::ToLocal(memory_obj));
1198
}
1199

1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
// Determines the type encoded in a value type property (e.g. type reflection).
// Returns false if there was an exception, true upon success. On success the
// outgoing {type} is set accordingly, or set to {wasm::kWasmStmt} in case the
// type could not be properly recognized.
bool GetValueType(Isolate* isolate, MaybeLocal<Value> maybe,
                  Local<Context> context, i::wasm::ValueType* type,
                  i::wasm::WasmFeatures enabled_features) {
  v8::Local<v8::Value> value;
  if (!maybe.ToLocal(&value)) return false;
  v8::Local<v8::String> string;
  if (!value->ToString(context).ToLocal(&string)) return false;
  if (string->StringEquals(v8_str(isolate, "i32"))) {
    *type = i::wasm::kWasmI32;
  } else if (string->StringEquals(v8_str(isolate, "f32"))) {
    *type = i::wasm::kWasmF32;
  } else if (string->StringEquals(v8_str(isolate, "i64"))) {
    *type = i::wasm::kWasmI64;
  } else if (string->StringEquals(v8_str(isolate, "f64"))) {
    *type = i::wasm::kWasmF64;
1219 1220 1221 1222
  } else if (enabled_features.has_reftypes() &&
             string->StringEquals(v8_str(isolate, "externref"))) {
    *type = i::wasm::kWasmExternRef;
  } else if (enabled_features.has_reftypes() &&
1223
             string->StringEquals(v8_str(isolate, "anyfunc"))) {
1224
    // The JS api spec uses 'anyfunc' instead of 'funcref'.
1225
    *type = i::wasm::kWasmFuncRef;
1226 1227 1228
  } else if (enabled_features.has_gc() &&
             string->StringEquals(v8_str(isolate, "eqref"))) {
    *type = i::wasm::kWasmEqRef;
1229 1230 1231 1232 1233 1234 1235 1236
  } else {
    // Unrecognized type.
    *type = i::wasm::kWasmStmt;
  }
  return true;
}

// WebAssembly.Global
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Global()");
  if (!args.IsConstructCall()) {
    thrower.TypeError("WebAssembly.Global must be invoked with 'new'");
    return;
  }
  if (!args[0]->IsObject()) {
    thrower.TypeError("Argument 0 must be a global descriptor");
    return;
  }
  Local<Context> context = isolate->GetCurrentContext();
  Local<v8::Object> descriptor = Local<Object>::Cast(args[0]);
1252
  auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
1253 1254 1255 1256 1257 1258 1259 1260

  // The descriptor's 'mutable'.
  bool is_mutable = false;
  {
    Local<String> mutable_key = v8_str(isolate, "mutable");
    v8::MaybeLocal<v8::Value> maybe = descriptor->Get(context, mutable_key);
    v8::Local<v8::Value> value;
    if (maybe.ToLocal(&value)) {
1261
      is_mutable = value->BooleanValue(isolate);
1262 1263 1264
    } else {
      DCHECK(i_isolate->has_scheduled_exception());
      return;
1265 1266 1267
    }
  }

1268 1269 1270
  // The descriptor's type, called 'value'. It is called 'value' because this
  // descriptor is planned to be re-used as the global's type for reflection,
  // so calling it 'type' is redundant.
1271 1272 1273
  i::wasm::ValueType type;
  {
    v8::MaybeLocal<v8::Value> maybe =
1274
        descriptor->Get(context, v8_str(isolate, "value"));
1275 1276
    if (!GetValueType(isolate, maybe, context, &type, enabled_features)) return;
    if (type == i::wasm::kWasmStmt) {
1277
      thrower.TypeError(
1278
          "Descriptor property 'value' must be a WebAssembly type");
1279 1280 1281 1282
      return;
    }
  }

1283 1284
  const uint32_t offset = 0;
  i::MaybeHandle<i::WasmGlobalObject> maybe_global_obj =
1285 1286
      i::WasmGlobalObject::New(i_isolate, i::Handle<i::WasmInstanceObject>(),
                               i::MaybeHandle<i::JSArrayBuffer>(),
1287 1288
                               i::MaybeHandle<i::FixedArray>(), type, offset,
                               is_mutable);
1289 1290 1291 1292 1293 1294 1295

  i::Handle<i::WasmGlobalObject> global_obj;
  if (!maybe_global_obj.ToHandle(&global_obj)) {
    thrower.RangeError("could not allocate memory");
    return;
  }

1296 1297
  // Convert value to a WebAssembly value, the default value is 0.
  Local<v8::Value> value = Local<Value>::Cast(args[1]);
1298
  switch (type.kind()) {
1299
    case i::wasm::kI32: {
1300 1301
      int32_t i32_value = 0;
      if (!value->IsUndefined()) {
1302 1303 1304 1305
        v8::Local<v8::Int32> int32_value;
        if (!value->ToInt32(context).ToLocal(&int32_value)) return;
        if (!int32_value->Int32Value(context).To(&i32_value)) return;
      }
1306 1307 1308
      global_obj->SetI32(i32_value);
      break;
    }
1309
    case i::wasm::kI64: {
1310 1311 1312 1313 1314 1315 1316 1317 1318
      int64_t i64_value = 0;
      if (!value->IsUndefined()) {
        v8::Local<v8::BigInt> bigint_value;
        if (!value->ToBigInt(context).ToLocal(&bigint_value)) return;
        i64_value = bigint_value->Int64Value();
      }
      global_obj->SetI64(i64_value);
      break;
    }
1319
    case i::wasm::kF32: {
1320 1321
      float f32_value = 0;
      if (!value->IsUndefined()) {
1322 1323 1324 1325
        double f64_value = 0;
        v8::Local<v8::Number> number_value;
        if (!value->ToNumber(context).ToLocal(&number_value)) return;
        if (!number_value->NumberValue(context).To(&f64_value)) return;
1326
        f32_value = i::DoubleToFloat32(f64_value);
1327
      }
1328 1329 1330
      global_obj->SetF32(f32_value);
      break;
    }
1331
    case i::wasm::kF64: {
1332 1333
      double f64_value = 0;
      if (!value->IsUndefined()) {
1334 1335 1336 1337
        v8::Local<v8::Number> number_value;
        if (!value->ToNumber(context).ToLocal(&number_value)) return;
        if (!number_value->NumberValue(context).To(&f64_value)) return;
      }
1338 1339
      global_obj->SetF64(f64_value);
      break;
1340
    }
1341 1342
    case i::wasm::kRef:
    case i::wasm::kOptRef: {
1343
      switch (type.heap_representation()) {
1344
        case i::wasm::HeapType::kExtern:
1345
        case i::wasm::HeapType::kAny: {
1346 1347 1348 1349 1350 1351 1352 1353 1354
          if (args.Length() < 2) {
            // When no initial value is provided, we have to use the WebAssembly
            // default value 'null', and not the JS default value 'undefined'.
            global_obj->SetExternRef(i_isolate->factory()->null_value());
            break;
          }
          global_obj->SetExternRef(Utils::OpenHandle(*value));
          break;
        }
1355
        case i::wasm::HeapType::kFunc: {
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370
          if (args.Length() < 2) {
            // When no initial value is provided, we have to use the WebAssembly
            // default value 'null', and not the JS default value 'undefined'.
            global_obj->SetFuncRef(i_isolate,
                                   i_isolate->factory()->null_value());
            break;
          }

          if (!global_obj->SetFuncRef(i_isolate, Utils::OpenHandle(*value))) {
            thrower.TypeError(
                "The value of funcref globals must be null or an "
                "exported function");
          }
          break;
        }
1371 1372
        case internal::wasm::HeapType::kBottom:
          UNREACHABLE();
1373
        case i::wasm::HeapType::kEq:
1374 1375
        case internal::wasm::HeapType::kI31:
        case internal::wasm::HeapType::kData:
1376 1377 1378
        default:
          // TODO(7748): Implement these.
          UNIMPLEMENTED();
1379
          break;
1380 1381 1382
      }
      break;
    }
1383 1384
    case i::wasm::kRtt:
    case i::wasm::kRttWithDepth:
1385
      // TODO(7748): Implement.
1386
      UNIMPLEMENTED();
1387 1388 1389 1390 1391
    case i::wasm::kI8:
    case i::wasm::kI16:
    case i::wasm::kStmt:
    case i::wasm::kS128:
    case i::wasm::kBottom:
1392
      UNREACHABLE();
1393 1394 1395 1396
  }

  i::Handle<i::JSObject> global_js_object(global_obj);
  args.GetReturnValue().Set(Utils::ToLocal(global_js_object));
1397 1398
}

1399 1400 1401 1402 1403
// WebAssembly.Exception
void WebAssemblyException(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
1404
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Exception()");
1405 1406 1407
  thrower.TypeError("WebAssembly.Exception cannot be called");
}

1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422
namespace {

uint32_t GetIterableLength(i::Isolate* isolate, Local<Context> context,
                           Local<Object> iterable) {
  Local<String> length = Utils::ToLocal(isolate->factory()->length_string());
  MaybeLocal<Value> property = iterable->Get(context, length);
  if (property.IsEmpty()) return i::kMaxUInt32;
  MaybeLocal<Uint32> number = property.ToLocalChecked()->ToArrayIndex(context);
  if (number.IsEmpty()) return i::kMaxUInt32;
  DCHECK_NE(i::kMaxUInt32, number.ToLocalChecked()->Value());
  return number.ToLocalChecked()->Value();
}

}  // namespace

1423 1424 1425 1426 1427 1428 1429 1430 1431 1432
// WebAssembly.Function
void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Function()");
  if (!args.IsConstructCall()) {
    thrower.TypeError("WebAssembly.Function must be invoked with 'new'");
    return;
  }
1433 1434 1435 1436 1437 1438
  if (!args[0]->IsObject()) {
    thrower.TypeError("Argument 0 must be a function type");
    return;
  }
  Local<Object> function_type = Local<Object>::Cast(args[0]);
  Local<Context> context = isolate->GetCurrentContext();
1439
  auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
1440 1441 1442 1443 1444 1445 1446

  // Load the 'parameters' property of the function type.
  Local<String> parameters_key = v8_str(isolate, "parameters");
  v8::MaybeLocal<v8::Value> parameters_maybe =
      function_type->Get(context, parameters_key);
  v8::Local<v8::Value> parameters_value;
  if (!parameters_maybe.ToLocal(&parameters_value)) return;
1447
  if (!parameters_value->IsObject()) {
1448 1449 1450
    thrower.TypeError("Argument 0 must be a function type with 'parameters'");
    return;
  }
1451 1452 1453 1454 1455 1456
  Local<Object> parameters = parameters_value.As<Object>();
  uint32_t parameters_len = GetIterableLength(i_isolate, context, parameters);
  if (parameters_len == i::kMaxUInt32) {
    thrower.TypeError("Argument 0 contains parameters without 'length'");
    return;
  }
1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467
  if (parameters_len > i::wasm::kV8MaxWasmFunctionParams) {
    thrower.TypeError("Argument 0 contains too many parameters");
    return;
  }

  // Load the 'results' property of the function type.
  Local<String> results_key = v8_str(isolate, "results");
  v8::MaybeLocal<v8::Value> results_maybe =
      function_type->Get(context, results_key);
  v8::Local<v8::Value> results_value;
  if (!results_maybe.ToLocal(&results_value)) return;
1468
  if (!results_value->IsObject()) {
1469 1470 1471
    thrower.TypeError("Argument 0 must be a function type with 'results'");
    return;
  }
1472 1473 1474 1475 1476 1477
  Local<Object> results = results_value.As<Object>();
  uint32_t results_len = GetIterableLength(i_isolate, context, results);
  if (results_len == i::kMaxUInt32) {
    thrower.TypeError("Argument 0 contains results without 'length'");
    return;
  }
1478
  if (results_len > (enabled_features.has_mv()
1479 1480 1481 1482 1483 1484 1485 1486
                         ? i::wasm::kV8MaxWasmFunctionMultiReturns
                         : i::wasm::kV8MaxWasmFunctionReturns)) {
    thrower.TypeError("Argument 0 contains too many results");
    return;
  }

  // Decode the function type and construct a signature.
  i::Zone zone(i_isolate->allocator(), ZONE_NAME);
1487
  i::wasm::FunctionSig::Builder builder(&zone, results_len, parameters_len);
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
  for (uint32_t i = 0; i < parameters_len; ++i) {
    i::wasm::ValueType type;
    MaybeLocal<Value> maybe = parameters->Get(context, i);
    if (!GetValueType(isolate, maybe, context, &type, enabled_features)) return;
    if (type == i::wasm::kWasmStmt) {
      thrower.TypeError(
          "Argument 0 parameter type at index #%u must be a value type", i);
      return;
    }
    builder.AddParam(type);
  }
  for (uint32_t i = 0; i < results_len; ++i) {
    i::wasm::ValueType type;
    MaybeLocal<Value> maybe = results->Get(context, i);
    if (!GetValueType(isolate, maybe, context, &type, enabled_features)) return;
    if (type == i::wasm::kWasmStmt) {
      thrower.TypeError(
          "Argument 0 result type at index #%u must be a value type", i);
      return;
    }
    builder.AddReturn(type);
  }

  if (!args[1]->IsFunction()) {
    thrower.TypeError("Argument 1 must be a function");
    return;
  }
1515
  const i::wasm::FunctionSig* sig = builder.Build();
1516

1517 1518
  i::Handle<i::JSReceiver> callable =
      Utils::OpenHandle(*args[1].As<Function>());
1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542
  if (i::WasmExportedFunction::IsWasmExportedFunction(*callable)) {
    if (*i::Handle<i::WasmExportedFunction>::cast(callable)->sig() == *sig) {
      args.GetReturnValue().Set(Utils::ToLocal(callable));
      return;
    }

    thrower.TypeError(
        "The signature of Argument 1 (a WebAssembly function) does "
        "not match the signature specified in Argument 0");
    return;
  }

  if (i::WasmJSFunction::IsWasmJSFunction(*callable)) {
    if (i::Handle<i::WasmJSFunction>::cast(callable)->MatchesSignature(sig)) {
      args.GetReturnValue().Set(Utils::ToLocal(callable));
      return;
    }

    thrower.TypeError(
        "The signature of Argument 1 (a WebAssembly function) does "
        "not match the signature specified in Argument 0");
    return;
  }

1543 1544 1545
  i::Handle<i::JSFunction> result =
      i::WasmJSFunction::New(i_isolate, sig, callable);
  args.GetReturnValue().Set(Utils::ToLocal(result));
1546 1547
}

1548 1549 1550 1551 1552 1553 1554
// WebAssembly.Function.type(WebAssembly.Function) -> FunctionType
void WebAssemblyFunctionType(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  HandleScope scope(isolate);
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Function.type()");

1555
  const i::wasm::FunctionSig* sig;
1556
  i::Zone zone(i_isolate->allocator(), ZONE_NAME);
1557 1558 1559 1560
  i::Handle<i::Object> arg0 = Utils::OpenHandle(*args[0]);
  if (i::WasmExportedFunction::IsWasmExportedFunction(*arg0)) {
    sig = i::Handle<i::WasmExportedFunction>::cast(arg0)->sig();
  } else if (i::WasmJSFunction::IsWasmJSFunction(*arg0)) {
1561
    sig = i::Handle<i::WasmJSFunction>::cast(arg0)->GetSignature(&zone);
1562 1563 1564 1565 1566
  } else {
    thrower.TypeError("Argument 0 must be a WebAssembly.Function");
    return;
  }

1567 1568
  auto type = i::wasm::GetTypeForFunction(i_isolate, sig);
  args.GetReturnValue().Set(Utils::ToLocal(type));
1569 1570
}

1571
constexpr const char* kName_WasmGlobalObject = "WebAssembly.Global";
1572 1573 1574
constexpr const char* kName_WasmMemoryObject = "WebAssembly.Memory";
constexpr const char* kName_WasmInstanceObject = "WebAssembly.Instance";
constexpr const char* kName_WasmTableObject = "WebAssembly.Table";
1575 1576 1577 1578 1579 1580

#define EXTRACT_THIS(var, WasmType)                                  \
  i::Handle<i::WasmType> var;                                        \
  {                                                                  \
    i::Handle<i::Object> this_arg = Utils::OpenHandle(*args.This()); \
    if (!this_arg->Is##WasmType()) {                                 \
1581
      thrower.TypeError("Receiver is not a %s", kName_##WasmType);   \
1582 1583 1584 1585 1586
      return;                                                        \
    }                                                                \
    var = i::Handle<i::WasmType>::cast(this_arg);                    \
  }

1587
void WebAssemblyInstanceGetExports(
1588
    const v8::FunctionCallbackInfo<v8::Value>& args) {
1589 1590 1591
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
1592
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Instance.exports()");
1593
  EXTRACT_THIS(receiver, WasmInstanceObject);
1594
  i::Handle<i::JSObject> exports_object(receiver->exports_object(), i_isolate);
1595 1596 1597
  args.GetReturnValue().Set(Utils::ToLocal(exports_object));
}

1598 1599
void WebAssemblyTableGetLength(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
1600
  v8::Isolate* isolate = args.GetIsolate();
1601 1602
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
1603
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.length()");
1604
  EXTRACT_THIS(receiver, WasmTableObject);
1605 1606
  args.GetReturnValue().Set(
      v8::Number::New(isolate, receiver->current_length()));
1607
}
1608

1609
// WebAssembly.Table.grow(num, init_value = null) -> num
1610
void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
1611
  v8::Isolate* isolate = args.GetIsolate();
1612 1613
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
1614
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.grow()");
1615
  Local<Context> context = isolate->GetCurrentContext();
1616
  EXTRACT_THIS(receiver, WasmTableObject);
1617

1618 1619 1620 1621 1622
  uint32_t grow_by;
  if (!EnforceUint32("Argument 0", args[0], context, &thrower, &grow_by)) {
    return;
  }

1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636
  i::Handle<i::Object> init_value = i_isolate->factory()->null_value();
  auto enabled_features = i::wasm::WasmFeatures::FromIsolate(i_isolate);
  if (enabled_features.has_typed_funcref()) {
    if (args.Length() >= 2 && !args[1]->IsUndefined()) {
      init_value = Utils::OpenHandle(*args[1]);
    }
    if (!i::WasmTableObject::IsValidElement(i_isolate, receiver, init_value)) {
      thrower.TypeError("Argument 1 must be a valid type for the table");
      return;
    }
  }

  int old_size =
      i::WasmTableObject::Grow(i_isolate, receiver, grow_by, init_value);
1637

1638 1639
  if (old_size < 0) {
    thrower.RangeError("failed to grow table by %u", grow_by);
1640 1641
    return;
  }
1642 1643
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(old_size);
1644
}
1645

1646
// WebAssembly.Table.get(num) -> JSFunction
1647
void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) {
1648
  v8::Isolate* isolate = args.GetIsolate();
1649
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1650
  HandleScope scope(isolate);
1651
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.get()");
1652
  Local<Context> context = isolate->GetCurrentContext();
1653
  EXTRACT_THIS(receiver, WasmTableObject);
1654 1655 1656 1657 1658

  uint32_t index;
  if (!EnforceUint32("Argument 0", args[0], context, &thrower, &index)) {
    return;
  }
1659 1660
  if (!i::WasmTableObject::IsInBounds(i_isolate, receiver, index)) {
    thrower.RangeError("invalid index %u into function table", index);
1661
    return;
1662
  }
1663

1664 1665 1666
  i::Handle<i::Object> result =
      i::WasmTableObject::Get(i_isolate, receiver, index);

1667
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
1668
  return_value.Set(Utils::ToLocal(result));
1669
}
1670

1671
// WebAssembly.Table.set(num, JSFunction)
1672
void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
1673
  v8::Isolate* isolate = args.GetIsolate();
1674
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1675
  HandleScope scope(isolate);
1676
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.set()");
1677
  Local<Context> context = isolate->GetCurrentContext();
1678
  EXTRACT_THIS(table_object, WasmTableObject);
1679

1680
  // Parameter 0.
1681 1682 1683 1684
  uint32_t index;
  if (!EnforceUint32("Argument 0", args[0], context, &thrower, &index)) {
    return;
  }
1685 1686
  if (!i::WasmTableObject::IsInBounds(i_isolate, table_object, index)) {
    thrower.RangeError("invalid index %u into function table", index);
1687 1688
    return;
  }
1689

1690 1691
  i::Handle<i::Object> element = Utils::OpenHandle(*args[1]);
  if (!i::WasmTableObject::IsValidElement(i_isolate, table_object, element)) {
1692 1693 1694
    thrower.TypeError(
        "Argument 1 must be null or a WebAssembly function of type compatible "
        "to 'this'");
1695 1696
    return;
  }
1697
  i::WasmTableObject::Set(i_isolate, table_object, index, element);
1698
}
1699

1700
// WebAssembly.Table.type(WebAssembly.Table) -> TableType
1701
void WebAssemblyTableType(const v8::FunctionCallbackInfo<v8::Value>& args) {
1702 1703 1704 1705 1706 1707 1708 1709
  v8::Isolate* isolate = args.GetIsolate();
  HandleScope scope(isolate);
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.type()");

  auto maybe_table = GetFirstArgumentAsTable(args, &thrower);
  if (thrower.error()) return;
  i::Handle<i::WasmTableObject> table = maybe_table.ToHandleChecked();
1710
  base::Optional<uint32_t> max_size;
1711
  if (!table->maximum_length().IsUndefined()) {
1712 1713 1714
    uint64_t max_size64 = table->maximum_length().Number();
    DCHECK_LE(max_size64, std::numeric_limits<uint32_t>::max());
    max_size.emplace(static_cast<uint32_t>(max_size64));
1715
  }
1716 1717 1718
  auto type = i::wasm::GetTypeForTable(i_isolate, table->type(),
                                       table->current_length(), max_size);
  args.GetReturnValue().Set(Utils::ToLocal(type));
1719 1720
}

1721
// WebAssembly.Memory.grow(num) -> num
1722
void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
1723
  v8::Isolate* isolate = args.GetIsolate();
1724
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1725
  HandleScope scope(isolate);
1726
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory.grow()");
1727
  Local<Context> context = isolate->GetCurrentContext();
1728 1729
  EXTRACT_THIS(receiver, WasmMemoryObject);

1730 1731 1732 1733
  uint32_t delta_size;
  if (!EnforceUint32("Argument 0", args[0], context, &thrower, &delta_size)) {
    return;
  }
1734

1735
  uint64_t max_size64 = receiver->maximum_pages();
1736 1737
  if (max_size64 > uint64_t{i::wasm::max_mem_pages()}) {
    max_size64 = i::wasm::max_mem_pages();
1738
  }
1739
  i::Handle<i::JSArrayBuffer> old_buffer(receiver->array_buffer(), i_isolate);
1740 1741 1742 1743 1744 1745 1746 1747

  DCHECK_LE(max_size64, std::numeric_limits<uint32_t>::max());

  uint64_t old_size64 = old_buffer->byte_length() / i::wasm::kWasmPageSize;
  uint64_t new_size64 = old_size64 + static_cast<uint64_t>(delta_size);

  if (new_size64 > max_size64) {
    thrower.RangeError("Maximum memory size exceeded");
1748 1749
    return;
  }
1750 1751

  int32_t ret = i::WasmMemoryObject::Grow(i_isolate, receiver, delta_size);
1752
  if (ret == -1) {
1753
    thrower.RangeError("Unable to grow instance memory.");
1754 1755 1756 1757
    return;
  }
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(ret);
1758
}
1759

1760
// WebAssembly.Memory.buffer -> ArrayBuffer
1761 1762 1763
void WebAssemblyMemoryGetBuffer(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
1764
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1765
  HandleScope scope(isolate);
1766
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory.buffer");
1767 1768
  EXTRACT_THIS(receiver, WasmMemoryObject);

1769 1770
  i::Handle<i::Object> buffer_obj(receiver->array_buffer(), i_isolate);
  DCHECK(buffer_obj->IsJSArrayBuffer());
1771 1772
  i::Handle<i::JSArrayBuffer> buffer(i::JSArrayBuffer::cast(*buffer_obj),
                                     i_isolate);
1773 1774 1775 1776 1777
  if (buffer->is_shared()) {
    // TODO(gdeepti): More needed here for when cached buffer, and current
    // buffer are out of sync, handle that here when bounds checks, and Grow
    // are handled correctly.
    Maybe<bool> result =
1778
        buffer->SetIntegrityLevel(buffer, i::FROZEN, i::kDontThrow);
1779 1780 1781 1782 1783
    if (!result.FromJust()) {
      thrower.TypeError(
          "Status of setting SetIntegrityLevel of buffer is false.");
    }
  }
1784 1785 1786
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(Utils::ToLocal(buffer));
}
1787

1788
// WebAssembly.Memory.type(WebAssembly.Memory) -> MemoryType
1789
void WebAssemblyMemoryType(const v8::FunctionCallbackInfo<v8::Value>& args) {
1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800
  v8::Isolate* isolate = args.GetIsolate();
  HandleScope scope(isolate);
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory.type()");

  auto maybe_memory = GetFirstArgumentAsMemory(args, &thrower);
  if (thrower.error()) return;
  i::Handle<i::WasmMemoryObject> memory = maybe_memory.ToHandleChecked();
  i::Handle<i::JSArrayBuffer> buffer(memory->array_buffer(), i_isolate);
  size_t curr_size = buffer->byte_length() / i::wasm::kWasmPageSize;
  DCHECK_LE(curr_size, std::numeric_limits<uint32_t>::max());
1801 1802
  uint32_t min_size = static_cast<uint32_t>(curr_size);
  base::Optional<uint32_t> max_size;
1803
  if (memory->has_maximum_pages()) {
1804 1805 1806
    uint64_t max_size64 = memory->maximum_pages();
    DCHECK_LE(max_size64, std::numeric_limits<uint32_t>::max());
    max_size.emplace(static_cast<uint32_t>(max_size64));
1807
  }
1808 1809
  auto type = i::wasm::GetTypeForMemory(i_isolate, min_size, max_size);
  args.GetReturnValue().Set(Utils::ToLocal(type));
1810 1811
}

1812 1813 1814 1815 1816 1817 1818 1819 1820 1821
void WebAssemblyGlobalGetValueCommon(
    const v8::FunctionCallbackInfo<v8::Value>& args, const char* name) {
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
  ScheduledErrorThrower thrower(i_isolate, name);
  EXTRACT_THIS(receiver, WasmGlobalObject);

  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();

1822
  switch (receiver->type().kind()) {
1823
    case i::wasm::kI32:
1824 1825
      return_value.Set(receiver->GetI32());
      break;
1826
    case i::wasm::kI64: {
1827 1828
      Local<BigInt> value = BigInt::New(isolate, receiver->GetI64());
      return_value.Set(value);
1829
      break;
1830
    }
1831
    case i::wasm::kF32:
1832 1833
      return_value.Set(receiver->GetF32());
      break;
1834
    case i::wasm::kF64:
1835 1836
      return_value.Set(receiver->GetF64());
      break;
1837
    case i::wasm::kS128:
1838 1839
      thrower.TypeError("Can't get the value of s128 WebAssembly.Global");
      break;
1840 1841
    case i::wasm::kRef:
    case i::wasm::kOptRef:
1842
      switch (receiver->type().heap_representation()) {
1843 1844
        case i::wasm::HeapType::kExtern:
        case i::wasm::HeapType::kFunc:
1845
        case i::wasm::HeapType::kAny:
1846 1847
          return_value.Set(Utils::ToLocal(receiver->GetRef()));
          break;
1848 1849 1850 1851
        case internal::wasm::HeapType::kBottom:
          UNREACHABLE();
        case internal::wasm::HeapType::kI31:
        case internal::wasm::HeapType::kData:
1852
        case i::wasm::HeapType::kEq:
1853 1854 1855 1856 1857 1858
        default:
          // TODO(7748): Implement these.
          UNIMPLEMENTED();
          break;
      }
      break;
1859 1860
    case i::wasm::kRtt:
    case i::wasm::kRttWithDepth:
1861 1862
      UNIMPLEMENTED();  // TODO(7748): Implement.
      break;
1863 1864 1865 1866
    case i::wasm::kI8:
    case i::wasm::kI16:
    case i::wasm::kBottom:
    case i::wasm::kStmt:
1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891
      UNREACHABLE();
  }
}

// WebAssembly.Global.valueOf() -> num
void WebAssemblyGlobalValueOf(const v8::FunctionCallbackInfo<v8::Value>& args) {
  return WebAssemblyGlobalGetValueCommon(args, "WebAssembly.Global.valueOf()");
}

// get WebAssembly.Global.value -> num
void WebAssemblyGlobalGetValue(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  return WebAssemblyGlobalGetValueCommon(args, "get WebAssembly.Global.value");
}

// set WebAssembly.Global.value(num)
void WebAssemblyGlobalSetValue(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
  Local<Context> context = isolate->GetCurrentContext();
  ScheduledErrorThrower thrower(i_isolate, "set WebAssembly.Global.value");
  EXTRACT_THIS(receiver, WasmGlobalObject);

1892 1893 1894 1895
  if (!receiver->is_mutable()) {
    thrower.TypeError("Can't set the value of an immutable global.");
    return;
  }
1896
  if (args[0]->IsUndefined()) {
1897
    thrower.TypeError("Argument 0 is required");
1898 1899
    return;
  }
1900

1901
  switch (receiver->type().kind()) {
1902
    case i::wasm::kI32: {
1903 1904 1905 1906 1907
      int32_t i32_value = 0;
      if (!args[0]->Int32Value(context).To(&i32_value)) return;
      receiver->SetI32(i32_value);
      break;
    }
1908
    case i::wasm::kI64: {
1909 1910 1911
      v8::Local<v8::BigInt> bigint_value;
      if (!args[0]->ToBigInt(context).ToLocal(&bigint_value)) return;
      receiver->SetI64(bigint_value->Int64Value());
1912
      break;
1913
    }
1914
    case i::wasm::kF32: {
1915 1916
      double f64_value = 0;
      if (!args[0]->NumberValue(context).To(&f64_value)) return;
1917
      receiver->SetF32(i::DoubleToFloat32(f64_value));
1918 1919
      break;
    }
1920
    case i::wasm::kF64: {
1921 1922 1923 1924 1925
      double f64_value = 0;
      if (!args[0]->NumberValue(context).To(&f64_value)) return;
      receiver->SetF64(f64_value);
      break;
    }
1926
    case i::wasm::kS128:
1927 1928
      thrower.TypeError("Can't set the value of s128 WebAssembly.Global");
      break;
1929 1930
    case i::wasm::kRef:
    case i::wasm::kOptRef:
1931
      switch (receiver->type().heap_representation()) {
1932
        case i::wasm::HeapType::kExtern:
1933
        case i::wasm::HeapType::kAny:
1934 1935
          receiver->SetExternRef(Utils::OpenHandle(*args[0]));
          break;
1936
        case i::wasm::HeapType::kFunc: {
1937 1938 1939 1940 1941 1942 1943
          if (!receiver->SetFuncRef(i_isolate, Utils::OpenHandle(*args[0]))) {
            thrower.TypeError(
                "value of an funcref reference must be either null or an "
                "exported function");
          }
          break;
        }
1944 1945 1946 1947
        case internal::wasm::HeapType::kBottom:
          UNREACHABLE();
        case internal::wasm::HeapType::kI31:
        case internal::wasm::HeapType::kData:
1948
        case i::wasm::HeapType::kEq:
1949 1950 1951 1952 1953 1954
        default:
          // TODO(7748): Implement these.
          UNIMPLEMENTED();
          break;
      }
      break;
1955 1956
    case i::wasm::kRtt:
    case i::wasm::kRttWithDepth:
1957
      // TODO(7748): Implement.
1958
      UNIMPLEMENTED();
1959
      break;
1960 1961 1962 1963
    case i::wasm::kI8:
    case i::wasm::kI16:
    case i::wasm::kBottom:
    case i::wasm::kStmt:
1964 1965 1966 1967
      UNREACHABLE();
  }
}

1968
// WebAssembly.Global.type(WebAssembly.Global) -> GlobalType
1969
void WebAssemblyGlobalType(const v8::FunctionCallbackInfo<v8::Value>& args) {
1970 1971 1972 1973 1974 1975 1976 1977
  v8::Isolate* isolate = args.GetIsolate();
  HandleScope scope(isolate);
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Global.type()");

  auto maybe_global = GetFirstArgumentAsGlobal(args, &thrower);
  if (thrower.error()) return;
  i::Handle<i::WasmGlobalObject> global = maybe_global.ToHandleChecked();
1978 1979 1980
  auto type = i::wasm::GetTypeForGlobal(i_isolate, global->is_mutable(),
                                        global->type());
  args.GetReturnValue().Set(Utils::ToLocal(type));
1981 1982
}

1983 1984 1985 1986
}  // namespace

// TODO(titzer): we use the API to create the function template because the
// internal guts are too ugly to replicate here.
1987
static i::Handle<i::FunctionTemplateInfo> NewFunctionTemplate(
1988 1989
    i::Isolate* i_isolate, FunctionCallback func, bool has_prototype,
    SideEffectType side_effect_type = SideEffectType::kHasSideEffect) {
1990
  Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
1991 1992
  ConstructorBehavior behavior =
      has_prototype ? ConstructorBehavior::kAllow : ConstructorBehavior::kThrow;
1993
  Local<FunctionTemplate> templ = FunctionTemplate::New(
1994 1995
      isolate, func, {}, {}, 0, behavior, side_effect_type);
  if (has_prototype) templ->ReadOnlyPrototype();
1996
  return v8::Utils::OpenHandle(*templ);
1997 1998
}

1999 2000 2001 2002 2003 2004 2005
static i::Handle<i::ObjectTemplateInfo> NewObjectTemplate(
    i::Isolate* i_isolate) {
  Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
  return v8::Utils::OpenHandle(*templ);
}

2006 2007
namespace internal {

2008 2009 2010 2011
Handle<JSFunction> CreateFunc(
    Isolate* isolate, Handle<String> name, FunctionCallback func,
    bool has_prototype,
    SideEffectType side_effect_type = SideEffectType::kHasSideEffect) {
2012
  Handle<FunctionTemplateInfo> temp =
2013
      NewFunctionTemplate(isolate, func, has_prototype, side_effect_type);
2014
  Handle<JSFunction> function =
2015
      ApiNatives::InstantiateFunction(temp, name).ToHandleChecked();
2016
  DCHECK(function->shared().HasSharedName());
2017 2018 2019
  return function;
}

2020 2021 2022 2023 2024
Handle<JSFunction> InstallFunc(
    Isolate* isolate, Handle<JSObject> object, const char* str,
    FunctionCallback func, int length, bool has_prototype = false,
    PropertyAttributes attributes = NONE,
    SideEffectType side_effect_type = SideEffectType::kHasSideEffect) {
2025
  Handle<String> name = v8_str(isolate, str);
2026 2027
  Handle<JSFunction> function =
      CreateFunc(isolate, name, func, has_prototype, side_effect_type);
2028
  function->shared().set_length(length);
2029
  JSObject::AddProperty(isolate, object, name, function, attributes);
rossberg's avatar
rossberg committed
2030
  return function;
2031 2032
}

2033
Handle<JSFunction> InstallConstructorFunc(Isolate* isolate,
2034 2035 2036
                                          Handle<JSObject> object,
                                          const char* str,
                                          FunctionCallback func) {
2037
  return InstallFunc(isolate, object, str, func, 1, true, DONT_ENUM);
2038 2039
}

2040
Handle<String> GetterName(Isolate* isolate, Handle<String> name) {
2041
  return Name::ToFunctionName(isolate, name, isolate->factory()->get_string())
2042 2043 2044
      .ToHandleChecked();
}

2045 2046
void InstallGetter(Isolate* isolate, Handle<JSObject> object, const char* str,
                   FunctionCallback func) {
2047 2048
  Handle<String> name = v8_str(isolate, str);
  Handle<JSFunction> function =
2049 2050
      CreateFunc(isolate, GetterName(isolate, name), func, false,
                 SideEffectType::kHasNoSideEffect);
2051

2052 2053
  Utils::ToLocal(object)->SetAccessorProperty(Utils::ToLocal(name),
                                              Utils::ToLocal(function),
2054
                                              Local<Function>(), v8::None);
2055 2056
}

2057
Handle<String> SetterName(Isolate* isolate, Handle<String> name) {
2058
  return Name::ToFunctionName(isolate, name, isolate->factory()->set_string())
2059 2060 2061 2062 2063 2064 2065 2066
      .ToHandleChecked();
}

void InstallGetterSetter(Isolate* isolate, Handle<JSObject> object,
                         const char* str, FunctionCallback getter,
                         FunctionCallback setter) {
  Handle<String> name = v8_str(isolate, str);
  Handle<JSFunction> getter_func =
2067
      CreateFunc(isolate, GetterName(isolate, name), getter, false);
2068
  Handle<JSFunction> setter_func =
2069
      CreateFunc(isolate, SetterName(isolate, name), setter, false);
2070
  setter_func->shared().set_length(1);
2071 2072 2073

  Utils::ToLocal(object)->SetAccessorProperty(
      Utils::ToLocal(name), Utils::ToLocal(getter_func),
2074
      Utils::ToLocal(setter_func), v8::None);
2075 2076
}

2077 2078 2079 2080 2081 2082
// Assigns a dummy instance template to the given constructor function. Used to
// make sure the implicit receivers for the constructors in this file have an
// instance type different from the internal one, they allocate the resulting
// object explicitly and ignore implicit receiver.
void SetDummyInstanceTemplate(Isolate* isolate, Handle<JSFunction> fun) {
  Handle<ObjectTemplateInfo> instance_template = NewObjectTemplate(isolate);
2083
  FunctionTemplateInfo::SetInstanceTemplate(
2084
      isolate, handle(fun->shared().get_api_func_data(), isolate),
2085
      instance_template);
2086 2087
}

2088
// static
2089
void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
2090 2091
  Handle<JSGlobalObject> global = isolate->global_object();
  Handle<Context> context(global->native_context(), isolate);
2092
  // Install the JS API once only.
2093
  Object prev = context->get(Context::WASM_MODULE_CONSTRUCTOR_INDEX);
2094 2095
  if (!prev.IsUndefined(isolate)) {
    DCHECK(prev.IsJSFunction());
2096 2097
    return;
  }
2098

2099 2100
  Factory* factory = isolate->factory();

2101
  // Setup WebAssembly
2102
  Handle<String> name = v8_str(isolate, "WebAssembly");
2103 2104 2105 2106 2107
  // Not supposed to be called, hence using the kIllegal builtin as code.
  Handle<SharedFunctionInfo> info =
      factory->NewSharedFunctionInfoForBuiltin(name, Builtins::kIllegal);
  info->set_language_mode(LanguageMode::kStrict);

2108 2109
  Handle<JSFunction> cons =
      Factory::JSFunctionBuilder{isolate, info, context}.Build();
2110
  JSFunction::SetPrototype(cons, isolate->initial_object_prototype());
2111 2112
  Handle<JSObject> webassembly =
      factory->NewJSObject(cons, AllocationType::kOld);
2113

2114 2115
  PropertyAttributes ro_attributes =
      static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
2116 2117
  JSObject::AddProperty(isolate, webassembly, factory->to_string_tag_symbol(),
                        name, ro_attributes);
2118 2119
  InstallFunc(isolate, webassembly, "compile", WebAssemblyCompile, 1);
  InstallFunc(isolate, webassembly, "validate", WebAssemblyValidate, 1);
2120
  InstallFunc(isolate, webassembly, "instantiate", WebAssemblyInstantiate, 1);
2121

2122
  if (FLAG_wasm_test_streaming) {
2123
    isolate->set_wasm_streaming_callback(WasmStreamingCallbackForTesting);
2124 2125
  }

2126
  if (isolate->wasm_streaming_callback() != nullptr) {
2127 2128 2129 2130 2131
    InstallFunc(isolate, webassembly, "compileStreaming",
                WebAssemblyCompileStreaming, 1);
    InstallFunc(isolate, webassembly, "instantiateStreaming",
                WebAssemblyInstantiateStreaming, 1);
  }
2132

2133 2134
  // Expose the API on the global object if configured to do so.
  if (exposed_on_global_object) {
2135
    JSObject::AddProperty(isolate, global, name, webassembly, DONT_ENUM);
2136 2137
  }

2138 2139
  // Setup Module
  Handle<JSFunction> module_constructor =
2140
      InstallConstructorFunc(isolate, webassembly, "Module", WebAssemblyModule);
2141
  context->set_wasm_module_constructor(*module_constructor);
2142
  SetDummyInstanceTemplate(isolate, module_constructor);
2143 2144
  JSFunction::EnsureHasInitialMap(module_constructor);
  Handle<JSObject> module_proto(
2145
      JSObject::cast(module_constructor->instance_prototype()), isolate);
2146
  Handle<Map> module_map = isolate->factory()->NewMap(
2147
      i::WASM_MODULE_OBJECT_TYPE, WasmModuleObject::kHeaderSize);
2148
  JSFunction::SetInitialMap(module_constructor, module_map, module_proto);
2149 2150
  InstallFunc(isolate, module_constructor, "imports", WebAssemblyModuleImports,
              1);
2151 2152
  InstallFunc(isolate, module_constructor, "exports", WebAssemblyModuleExports,
              1);
2153 2154
  InstallFunc(isolate, module_constructor, "customSections",
              WebAssemblyModuleCustomSections, 2);
2155
  JSObject::AddProperty(isolate, module_proto, factory->to_string_tag_symbol(),
2156
                        v8_str(isolate, "WebAssembly.Module"), ro_attributes);
2157 2158

  // Setup Instance
2159 2160
  Handle<JSFunction> instance_constructor = InstallConstructorFunc(
      isolate, webassembly, "Instance", WebAssemblyInstance);
2161
  context->set_wasm_instance_constructor(*instance_constructor);
2162
  SetDummyInstanceTemplate(isolate, instance_constructor);
2163 2164
  JSFunction::EnsureHasInitialMap(instance_constructor);
  Handle<JSObject> instance_proto(
2165
      JSObject::cast(instance_constructor->instance_prototype()), isolate);
2166
  Handle<Map> instance_map = isolate->factory()->NewMap(
2167
      i::WASM_INSTANCE_OBJECT_TYPE, WasmInstanceObject::kHeaderSize);
2168
  JSFunction::SetInitialMap(instance_constructor, instance_map, instance_proto);
2169 2170
  InstallGetter(isolate, instance_proto, "exports",
                WebAssemblyInstanceGetExports);
2171 2172
  JSObject::AddProperty(isolate, instance_proto,
                        factory->to_string_tag_symbol(),
2173
                        v8_str(isolate, "WebAssembly.Instance"), ro_attributes);
2174

2175
  // The context is not set up completely yet. That's why we cannot use
2176 2177 2178
  // {WasmFeatures::FromIsolate} and have to use {WasmFeatures::FromFlags}
  // instead.
  auto enabled_features = i::wasm::WasmFeatures::FromFlags();
2179

2180 2181
  // Setup Table
  Handle<JSFunction> table_constructor =
2182
      InstallConstructorFunc(isolate, webassembly, "Table", WebAssemblyTable);
2183
  context->set_wasm_table_constructor(*table_constructor);
2184
  SetDummyInstanceTemplate(isolate, table_constructor);
2185 2186
  JSFunction::EnsureHasInitialMap(table_constructor);
  Handle<JSObject> table_proto(
2187
      JSObject::cast(table_constructor->instance_prototype()), isolate);
2188 2189
  Handle<Map> table_map = isolate->factory()->NewMap(
      i::WASM_TABLE_OBJECT_TYPE, WasmTableObject::kHeaderSize);
2190
  JSFunction::SetInitialMap(table_constructor, table_map, table_proto);
2191
  InstallGetter(isolate, table_proto, "length", WebAssemblyTableGetLength);
2192 2193 2194
  InstallFunc(isolate, table_proto, "grow", WebAssemblyTableGrow, 1);
  InstallFunc(isolate, table_proto, "get", WebAssemblyTableGet, 1);
  InstallFunc(isolate, table_proto, "set", WebAssemblyTableSet, 2);
2195
  if (enabled_features.has_type_reflection()) {
2196
    InstallFunc(isolate, table_constructor, "type", WebAssemblyTableType, 1);
2197
  }
2198
  JSObject::AddProperty(isolate, table_proto, factory->to_string_tag_symbol(),
2199
                        v8_str(isolate, "WebAssembly.Table"), ro_attributes);
2200 2201 2202

  // Setup Memory
  Handle<JSFunction> memory_constructor =
2203
      InstallConstructorFunc(isolate, webassembly, "Memory", WebAssemblyMemory);
2204
  context->set_wasm_memory_constructor(*memory_constructor);
2205
  SetDummyInstanceTemplate(isolate, memory_constructor);
2206 2207
  JSFunction::EnsureHasInitialMap(memory_constructor);
  Handle<JSObject> memory_proto(
2208
      JSObject::cast(memory_constructor->instance_prototype()), isolate);
2209
  Handle<Map> memory_map = isolate->factory()->NewMap(
2210
      i::WASM_MEMORY_OBJECT_TYPE, WasmMemoryObject::kHeaderSize);
2211
  JSFunction::SetInitialMap(memory_constructor, memory_map, memory_proto);
2212
  InstallFunc(isolate, memory_proto, "grow", WebAssemblyMemoryGrow, 1);
2213
  InstallGetter(isolate, memory_proto, "buffer", WebAssemblyMemoryGetBuffer);
2214
  if (enabled_features.has_type_reflection()) {
2215
    InstallFunc(isolate, memory_constructor, "type", WebAssemblyMemoryType, 1);
2216
  }
2217
  JSObject::AddProperty(isolate, memory_proto, factory->to_string_tag_symbol(),
2218
                        v8_str(isolate, "WebAssembly.Memory"), ro_attributes);
2219

2220
  // Setup Global
2221 2222 2223 2224 2225 2226 2227
  Handle<JSFunction> global_constructor =
      InstallConstructorFunc(isolate, webassembly, "Global", WebAssemblyGlobal);
  context->set_wasm_global_constructor(*global_constructor);
  SetDummyInstanceTemplate(isolate, global_constructor);
  JSFunction::EnsureHasInitialMap(global_constructor);
  Handle<JSObject> global_proto(
      JSObject::cast(global_constructor->instance_prototype()), isolate);
2228
  Handle<Map> global_map = isolate->factory()->NewMap(
2229
      i::WASM_GLOBAL_OBJECT_TYPE, WasmGlobalObject::kHeaderSize);
2230 2231 2232 2233
  JSFunction::SetInitialMap(global_constructor, global_map, global_proto);
  InstallFunc(isolate, global_proto, "valueOf", WebAssemblyGlobalValueOf, 0);
  InstallGetterSetter(isolate, global_proto, "value", WebAssemblyGlobalGetValue,
                      WebAssemblyGlobalSetValue);
2234
  if (enabled_features.has_type_reflection()) {
2235
    InstallFunc(isolate, global_constructor, "type", WebAssemblyGlobalType, 1);
2236
  }
2237 2238
  JSObject::AddProperty(isolate, global_proto, factory->to_string_tag_symbol(),
                        v8_str(isolate, "WebAssembly.Global"), ro_attributes);
2239

2240
  // Setup Exception
2241 2242 2243 2244 2245
  Handle<String> exception_name = v8_str(isolate, "Exception");
  Handle<JSFunction> exception_constructor =
      CreateFunc(isolate, exception_name, WebAssemblyException, true,
                 SideEffectType::kHasSideEffect);
  exception_constructor->shared().set_length(1);
2246
  if (enabled_features.has_eh()) {
2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260
    JSObject::AddProperty(isolate, webassembly, exception_name,
                          exception_constructor, DONT_ENUM);
  }
  // Install the constructor on the context unconditionally so that it is also
  // available when the feature is enabled via the origin trial.
  context->set_wasm_exception_constructor(*exception_constructor);
  SetDummyInstanceTemplate(isolate, exception_constructor);
  JSFunction::EnsureHasInitialMap(exception_constructor);
  Handle<JSObject> exception_proto(
      JSObject::cast(exception_constructor->instance_prototype()), isolate);
  Handle<Map> exception_map = isolate->factory()->NewMap(
      i::WASM_EXCEPTION_OBJECT_TYPE, WasmExceptionObject::kHeaderSize);
  JSFunction::SetInitialMap(exception_constructor, exception_map,
                            exception_proto);
2261

2262
  // Setup Function
2263
  if (enabled_features.has_type_reflection()) {
2264 2265 2266 2267 2268 2269 2270 2271 2272 2273
    Handle<JSFunction> function_constructor = InstallConstructorFunc(
        isolate, webassembly, "Function", WebAssemblyFunction);
    SetDummyInstanceTemplate(isolate, function_constructor);
    JSFunction::EnsureHasInitialMap(function_constructor);
    Handle<JSObject> function_proto(
        JSObject::cast(function_constructor->instance_prototype()), isolate);
    Handle<Map> function_map = isolate->factory()->CreateSloppyFunctionMap(
        FUNCTION_WITHOUT_PROTOTYPE, MaybeHandle<JSFunction>());
    CHECK(JSObject::SetPrototype(
              function_proto,
2274
              handle(context->function_function().prototype(), isolate), false,
2275 2276 2277 2278
              kDontThrow)
              .FromJust());
    JSFunction::SetInitialMap(function_constructor, function_map,
                              function_proto);
2279 2280
    InstallFunc(isolate, function_constructor, "type", WebAssemblyFunctionType,
                1);
2281 2282 2283 2284 2285 2286 2287 2288
    // Make all exported functions an instance of {WebAssembly.Function}.
    context->set_wasm_exported_function_map(*function_map);
  } else {
    // Make all exported functions an instance of {Function}.
    Handle<Map> function_map = isolate->sloppy_function_without_prototype_map();
    context->set_wasm_exported_function_map(*function_map);
  }

2289 2290
  // Setup errors
  Handle<JSFunction> compile_error(
2291
      isolate->native_context()->wasm_compile_error_function(), isolate);
2292 2293
  JSObject::AddProperty(isolate, webassembly,
                        isolate->factory()->CompileError_string(),
2294
                        compile_error, DONT_ENUM);
2295
  Handle<JSFunction> link_error(
2296
      isolate->native_context()->wasm_link_error_function(), isolate);
2297 2298
  JSObject::AddProperty(isolate, webassembly,
                        isolate->factory()->LinkError_string(), link_error,
2299
                        DONT_ENUM);
2300
  Handle<JSFunction> runtime_error(
2301
      isolate->native_context()->wasm_runtime_error_function(), isolate);
2302 2303
  JSObject::AddProperty(isolate, webassembly,
                        isolate->factory()->RuntimeError_string(),
2304
                        runtime_error, DONT_ENUM);
2305
}
2306 2307 2308 2309

#undef ASSIGN
#undef EXTRACT_THIS

2310 2311
}  // namespace internal
}  // namespace v8