wasm-js.cc 39.8 KB
Newer Older
1 2 3 4 5
// 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.

#include "src/api-natives.h"
6
#include "src/api.h"
7 8
#include "src/assert-scope.h"
#include "src/ast/ast.h"
9
#include "src/execution.h"
10 11 12
#include "src/factory.h"
#include "src/handles.h"
#include "src/isolate.h"
13
#include "src/objects-inl.h"
14
#include "src/objects.h"
15
#include "src/parsing/parse-info.h"
16 17 18

#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-js.h"
19
#include "src/wasm/wasm-limits.h"
20
#include "src/wasm/wasm-module.h"
21
#include "src/wasm/wasm-objects.h"
22 23 24 25 26 27 28 29 30
#include "src/wasm/wasm-result.h"

typedef uint8_t byte;

using v8::internal::wasm::ErrorThrower;

namespace v8 {

namespace {
31

32 33 34 35 36 37 38 39 40
#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()); \
    }                                                \
41 42
  } while (false)

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
// Like an ErrorThrower, but turns all pending exceptions into scheduled
// exceptions when going out of scope. Use this in API methods.
// Note that pending exceptions are not necessarily created by the ErrorThrower,
// but e.g. by the wasm start function. There might also be a scheduled
// exception, created by another API call (e.g. v8::Object::Get). But there
// should never be both pending and scheduled exceptions.
class ScheduledErrorThrower : public ErrorThrower {
 public:
  ScheduledErrorThrower(v8::Isolate* isolate, const char* context)
      : ScheduledErrorThrower(reinterpret_cast<i::Isolate*>(isolate), context) {
  }
  ScheduledErrorThrower(i::Isolate* isolate, const char* context)
      : ErrorThrower(isolate, context) {}
  ~ScheduledErrorThrower() {
    // There should never be both a pending and a scheduled exception.
    DCHECK(!isolate()->has_scheduled_exception() ||
           !isolate()->has_pending_exception());
    // Don't throw another error if there is already a scheduled error.
    if (isolate()->has_scheduled_exception()) {
      Reset();
    } else if (isolate()->has_pending_exception()) {
      Reset();
      isolate()->OptionalRescheduleException(false);
    } else if (error()) {
      isolate()->ScheduleThrow(*Reify());
    }
  }
};

72 73 74 75 76 77 78
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));
}

79 80 81 82 83 84 85
i::MaybeHandle<i::WasmModuleObject> GetFirstArgumentAsModule(
    const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
  if (args.Length() < 1) {
    thrower->TypeError("Argument 0 must be a WebAssembly.Module");
    return {};
  }

86 87 88
  i::Handle<i::Object> arg0 = Utils::OpenHandle(*args[0]);
  if (!arg0->IsWasmModuleObject()) {
    thrower->TypeError("Argument 0 must be a WebAssembly.Module");
89 90 91 92 93 94 95 96 97 98 99 100 101 102
    return {};
  }

  Local<Object> module_obj = Local<Object>::Cast(args[0]);
  return i::Handle<i::WasmModuleObject>::cast(
      v8::Utils::OpenHandle(*module_obj));
}

i::wasm::ModuleWireBytes GetFirstArgumentAsBytes(
    const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
  if (args.Length() < 1) {
    thrower->TypeError("Argument 0 must be a buffer source");
    return i::wasm::ModuleWireBytes(nullptr, nullptr);
  }
103

104
  const byte* start = nullptr;
105
  size_t length = 0;
106
  v8::Local<v8::Value> source = args[0];
rossberg's avatar
rossberg committed
107
  if (source->IsArrayBuffer()) {
108
    // A raw array buffer was passed.
rossberg's avatar
rossberg committed
109
    Local<ArrayBuffer> buffer = Local<ArrayBuffer>::Cast(source);
110 111 112
    ArrayBuffer::Contents contents = buffer->GetContents();

    start = reinterpret_cast<const byte*>(contents.Data());
113
    length = contents.ByteLength();
rossberg's avatar
rossberg committed
114
  } else if (source->IsTypedArray()) {
115
    // A TypedArray was passed.
rossberg's avatar
rossberg committed
116
    Local<TypedArray> array = Local<TypedArray>::Cast(source);
117 118 119 120 121 122
    Local<ArrayBuffer> buffer = array->Buffer();

    ArrayBuffer::Contents contents = buffer->GetContents();

    start =
        reinterpret_cast<const byte*>(contents.Data()) + array->ByteOffset();
123
    length = array->ByteLength();
124
  } else {
125
    thrower->TypeError("Argument 0 must be a buffer source");
126
  }
127 128
  DCHECK_IMPLIES(length, start != nullptr);
  if (length == 0) {
129 130
    thrower->CompileError("BufferSource argument is empty");
  }
131 132 133 134 135 136
  if (length > i::wasm::kV8MaxWasmModuleSize) {
    thrower->RangeError("buffer source exceeds maximum size of %zu (is %zu)",
                        i::wasm::kV8MaxWasmModuleSize, length);
  }
  if (thrower->error()) return i::wasm::ModuleWireBytes(nullptr, nullptr);
  return i::wasm::ModuleWireBytes(start, start + length);
137 138
}

139
i::MaybeHandle<i::JSReceiver> GetValueAsImports(Local<Value> arg,
140 141
                                                ErrorThrower* thrower) {
  if (arg->IsUndefined()) return {};
142

143
  if (!arg->IsObject()) {
144 145 146
    thrower->TypeError("Argument 1 must be an object");
    return {};
  }
147
  Local<Object> obj = Local<Object>::Cast(arg);
148
  return i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
149 150
}

151 152 153 154 155
void WebAssemblyCompileStreaming(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
156 157
  DCHECK_NOT_NULL(i_isolate->wasm_compile_streaming_callback());
  i_isolate->wasm_compile_streaming_callback()(args);
158 159
}

160
// WebAssembly.compile(bytes) -> Promise
rossberg's avatar
rossberg committed
161 162
void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
163
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
164
  MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
165

rossberg's avatar
rossberg committed
166
  HandleScope scope(isolate);
167
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.compile()");
rossberg's avatar
rossberg committed
168

169
  Local<Context> context = isolate->GetCurrentContext();
170
  ASSIGN(Promise::Resolver, resolver, Promise::Resolver::New(context));
171 172 173
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(resolver->GetPromise());

174
  auto bytes = GetFirstArgumentAsBytes(args, &thrower);
175
  if (thrower.error()) {
176
    auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
177 178
    CHECK_IMPLIES(!maybe.FromMaybe(false),
                  i_isolate->has_scheduled_exception());
179
    return;
180
  }
181 182
  i::Handle<i::JSPromise> promise = Utils::OpenHandle(*resolver->GetPromise());
  i::wasm::AsyncCompile(i_isolate, promise, bytes);
rossberg's avatar
rossberg committed
183 184
}

185
// WebAssembly.validate(bytes) -> bool
186 187
void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
188
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
189
  HandleScope scope(isolate);
190
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.validate()");
191

192
  auto bytes = GetFirstArgumentAsBytes(args, &thrower);
193 194

  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
195
  if (!thrower.error() &&
196
      i::wasm::SyncValidate(reinterpret_cast<i::Isolate*>(isolate), bytes)) {
197 198
    return_value.Set(v8::True(isolate));
  } else {
199
    if (thrower.wasm_error()) thrower.Reset();  // Clear error.
200 201 202 203
    return_value.Set(v8::False(isolate));
  }
}

204
// new WebAssembly.Module(bytes) -> WebAssembly.Module
rossberg's avatar
rossberg committed
205 206
void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
207
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
208 209
  if (i_isolate->wasm_module_callback()(args)) return;

rossberg's avatar
rossberg committed
210
  HandleScope scope(isolate);
211
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module()");
rossberg's avatar
rossberg committed
212

213
  auto bytes = GetFirstArgumentAsBytes(args, &thrower);
214

215 216 217
  if (thrower.error()) {
    return;
  }
218 219
  i::MaybeHandle<i::Object> module_obj =
      i::wasm::SyncCompile(i_isolate, &thrower, bytes);
rossberg's avatar
rossberg committed
220 221 222 223 224 225
  if (module_obj.is_null()) return;

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

226
// WebAssembly.Module.imports(module) -> Array<Import>
227 228 229 230
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);
231
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module.imports()");
232

233
  auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
234 235 236
  if (thrower.error()) return;
  auto imports = i::wasm::GetImports(i_isolate, maybe_module.ToHandleChecked());
  args.GetReturnValue().Set(Utils::ToLocal(imports));
237 238
}

239
// WebAssembly.Module.exports(module) -> Array<Export>
240 241 242 243
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);
244
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module.exports()");
245

246
  auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
247 248 249
  if (thrower.error()) return;
  auto exports = i::wasm::GetExports(i_isolate, maybe_module.ToHandleChecked());
  args.GetReturnValue().Set(Utils::ToLocal(exports));
250
}
251

252
// WebAssembly.Module.customSections(module, name) -> Array<Section>
253 254 255 256 257
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);
258 259
  ScheduledErrorThrower thrower(i_isolate,
                                "WebAssembly.Module.customSections()");
260

261
  auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
262
  if (thrower.error()) return;
263 264 265

  if (args.Length() < 2) {
    thrower.TypeError("Argument 1 must be a string");
266 267 268
    return;
  }

269 270 271 272 273
  i::Handle<i::Object> name = Utils::OpenHandle(*args[1]);
  if (!name->IsString()) {
    thrower.TypeError("Argument 1 must be a string");
    return;
  }
274

275 276 277 278 279
  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));
280 281
}

282 283 284 285 286
MaybeLocal<Value> WebAssemblyInstantiateImpl(Isolate* isolate,
                                             Local<Value> module,
                                             Local<Value> ffi) {
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);

287 288 289 290 291 292 293 294 295 296 297 298 299
  i::MaybeHandle<i::Object> instance_object;
  {
    ScheduledErrorThrower thrower(i_isolate, "WebAssembly Instantiation");
    i::MaybeHandle<i::JSReceiver> maybe_imports =
        GetValueAsImports(ffi, &thrower);
    if (thrower.error()) return {};

    i::Handle<i::WasmModuleObject> module_obj =
        i::Handle<i::WasmModuleObject>::cast(
            Utils::OpenHandle(Object::Cast(*module)));
    instance_object =
        i::wasm::SyncInstantiate(i_isolate, &thrower, module_obj, maybe_imports,
                                 i::MaybeHandle<i::JSArrayBuffer>());
300
  }
301 302 303

  DCHECK_EQ(instance_object.is_null(), i_isolate->has_scheduled_exception());
  if (instance_object.is_null()) return {};
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
  return Utils::ToLocal(instance_object.ToHandleChecked());
}

// Entered as internal implementation detail of sync and async instantiate.
// args[0] *must* be a WebAssembly.Module.
void WebAssemblyInstantiateImplCallback(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  DCHECK_GE(args.Length(), 1);
  v8::Isolate* isolate = args.GetIsolate();
  MicrotasksScope does_not_run_microtasks(isolate,
                                          MicrotasksScope::kDoNotRunMicrotasks);

  HandleScope scope(args.GetIsolate());
  Local<Value> module = args[0];
  Local<Value> ffi = args.Data();
  Local<Value> instance;
  if (WebAssemblyInstantiateImpl(isolate, module, ffi).ToLocal(&instance)) {
    args.GetReturnValue().Set(instance);
  }
}

void WebAssemblyInstantiateToPairCallback(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  DCHECK_GE(args.Length(), 1);
  Isolate* isolate = args.GetIsolate();
  MicrotasksScope does_not_run_microtasks(isolate,
                                          MicrotasksScope::kDoNotRunMicrotasks);

  HandleScope scope(args.GetIsolate());

  Local<Context> context = isolate->GetCurrentContext();
  Local<Value> module = args[0];

  const uint8_t* instance_str = reinterpret_cast<const uint8_t*>("instance");
  const uint8_t* module_str = reinterpret_cast<const uint8_t*>("module");
  Local<Value> instance;
  if (!WebAssemblyInstantiateImpl(isolate, module, args.Data())
341
           .ToLocal(&instance)) {
342
    return;
343
  }
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358

  Local<Object> ret = Object::New(isolate);
  Local<String> instance_name =
      String::NewFromOneByte(isolate, instance_str,
                             NewStringType::kInternalized)
          .ToLocalChecked();
  Local<String> module_name =
      String::NewFromOneByte(isolate, module_str, NewStringType::kInternalized)
          .ToLocalChecked();

  CHECK(ret->CreateDataProperty(context, instance_name, instance).IsJust());
  CHECK(ret->CreateDataProperty(context, module_name, module).IsJust());
  args.GetReturnValue().Set(ret);
}

359
// new WebAssembly.Instance(module, imports) -> WebAssembly.Instance
360
void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
361 362 363 364
  Isolate* isolate = args.GetIsolate();
  MicrotasksScope does_not_run_microtasks(isolate,
                                          MicrotasksScope::kDoNotRunMicrotasks);

rossberg's avatar
rossberg committed
365
  HandleScope scope(args.GetIsolate());
366
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
367 368
  if (i_isolate->wasm_instance_callback()(args)) return;

369
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Instance()");
370

371
  GetFirstArgumentAsModule(args, &thrower);
372
  if (thrower.error()) return;
373

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

378 379 380 381
  Local<Value> instance;
  if (WebAssemblyInstantiateImpl(isolate, args[0], data).ToLocal(&instance)) {
    args.GetReturnValue().Set(instance);
  }
382 383
}

384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
void WebAssemblyInstantiateStreaming(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  // we use i_isolate in DCHECKS in the ASSIGN statements.
  USE(i_isolate);
  MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
  HandleScope scope(isolate);

  Local<Context> context = isolate->GetCurrentContext();
  ASSIGN(Promise::Resolver, resolver, Promise::Resolver::New(context));
  Local<Value> first_arg_value = args[0];

  ASSIGN(Function, compileStreaming,
         Function::New(context, WebAssemblyCompileStreaming));
  ASSIGN(Value, compile_retval,
         compileStreaming->Call(context, args.Holder(), 1, &first_arg_value));
  Local<Promise> module_promise = Local<Promise>::Cast(compile_retval);

  DCHECK(!module_promise.IsEmpty());
  Local<Value> data = args[1];
  ASSIGN(Function, instantiate_impl,
         Function::New(context, WebAssemblyInstantiateToPairCallback, data));
  ASSIGN(Promise, result, module_promise->Then(context, instantiate_impl));
  args.GetReturnValue().Set(result);
}

411 412 413
// WebAssembly.instantiate(module, imports) -> WebAssembly.Instance
// WebAssembly.instantiate(bytes, imports) ->
//     {module: WebAssembly.Module, instance: WebAssembly.Instance}
414 415 416
void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
417
  MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
418

419
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.instantiate()");
420 421 422

  HandleScope scope(isolate);

423
  Local<Context> context = isolate->GetCurrentContext();
424

425 426 427
  ASSIGN(Promise::Resolver, resolver, Promise::Resolver::New(context));
  Local<Promise> module_promise = resolver->GetPromise();
  args.GetReturnValue().Set(module_promise);
428

429
  if (args.Length() < 1) {
430 431 432
    thrower.TypeError(
        "Argument 0 must be provided and must be either a buffer source or a "
        "WebAssembly.Module object");
433
    auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
434 435
    CHECK_IMPLIES(!maybe.FromMaybe(false),
                  i_isolate->has_scheduled_exception());
436
    return;
437
  }
438

439 440
  Local<Value> first_arg_value = args[0];
  i::Handle<i::Object> first_arg = Utils::OpenHandle(*first_arg_value);
441 442 443
  if (!first_arg->IsJSObject()) {
    thrower.TypeError(
        "Argument 0 must be a buffer source or a WebAssembly.Module object");
444
    auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
445 446
    CHECK_IMPLIES(!maybe.FromMaybe(false),
                  i_isolate->has_scheduled_exception());
447 448
    return;
  }
449

450
  FunctionCallback instantiator = nullptr;
451
  if (first_arg->IsWasmModuleObject()) {
452 453 454
    module_promise = resolver->GetPromise();
    if (!resolver->Resolve(context, first_arg_value).IsJust()) return;
    instantiator = WebAssemblyInstantiateImplCallback;
455
  } else {
456 457 458 459 460
    ASSIGN(Function, async_compile, Function::New(context, WebAssemblyCompile));
    ASSIGN(Value, async_compile_retval,
           async_compile->Call(context, args.Holder(), 1, &first_arg_value));
    module_promise = Local<Promise>::Cast(async_compile_retval);
    instantiator = WebAssemblyInstantiateToPairCallback;
461
  }
462 463 464 465 466 467 468 469 470
  DCHECK(!module_promise.IsEmpty());
  DCHECK_NOT_NULL(instantiator);
  // If args.Length < 2, this will be undefined - see FunctionCallbackInfo.
  // We'll check for that in WebAssemblyInstantiateImpl.
  Local<Value> data = args[1];
  ASSIGN(Function, instantiate_impl,
         Function::New(context, instantiator, data));
  ASSIGN(Promise, result, module_promise->Then(context, instantiate_impl));
  args.GetReturnValue().Set(result);
471
}
472 473 474

bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
                        Local<Context> context, Local<v8::Object> object,
475
                        Local<String> property, int64_t* result,
476
                        int64_t lower_bound, uint64_t upper_bound) {
477 478
  v8::MaybeLocal<v8::Value> maybe = object->Get(context, property);
  v8::Local<v8::Value> value;
479
  if (maybe.ToLocal(&value)) {
480 481
    int64_t number;
    if (!value->IntegerValue(context).To(&number)) return false;
482
    if (number < lower_bound) {
483
      thrower->RangeError("Property value %" PRId64
484
                          " is below the lower bound %" PRIx64,
485 486 487
                          number, lower_bound);
      return false;
    }
488
    if (number > static_cast<int64_t>(upper_bound)) {
489
      thrower->RangeError("Property value %" PRId64
490
                          " is above the upper bound %" PRIu64,
491 492 493
                          number, upper_bound);
      return false;
    }
494
    *result = static_cast<int>(number);
495 496 497 498 499
    return true;
  }
  return false;
}

500
// new WebAssembly.Table(args) -> WebAssembly.Table
501 502
void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
503
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
504
  HandleScope scope(isolate);
505
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module()");
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
  if (args.Length() < 1 || !args[0]->IsObject()) {
    thrower.TypeError("Argument 0 must be a table descriptor");
    return;
  }
  Local<Context> context = isolate->GetCurrentContext();
  Local<v8::Object> descriptor = args[0]->ToObject(context).ToLocalChecked();
  // 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;
    bool equal;
    if (!string->Equals(context, v8_str(isolate, "anyfunc")).To(&equal)) return;
    if (!equal) {
      thrower.TypeError("Descriptor property 'element' must be 'anyfunc'");
      return;
    }
  }
  // The descriptor's 'initial'.
528
  int64_t initial = 0;
529 530
  if (!GetIntegerProperty(isolate, &thrower, context, descriptor,
                          v8_str(isolate, "initial"), &initial, 0,
531
                          i::FLAG_wasm_max_table_size)) {
532 533 534
    return;
  }
  // The descriptor's 'maximum'.
535
  int64_t maximum = -1;
536 537 538
  Local<String> maximum_key = v8_str(isolate, "maximum");
  Maybe<bool> has_maximum = descriptor->Has(context, maximum_key);

539
  if (!has_maximum.IsNothing() && has_maximum.FromJust()) {
540
    if (!GetIntegerProperty(isolate, &thrower, context, descriptor, maximum_key,
541 542
                            &maximum, initial,
                            i::wasm::kSpecMaxWasmTableSize)) {
543 544 545 546
      return;
    }
  }

547
  i::Handle<i::FixedArray> fixed_array;
548 549
  i::Handle<i::JSObject> table_obj = i::WasmTableObject::New(
      i_isolate, static_cast<uint32_t>(initial), maximum, &fixed_array);
550 551 552
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(Utils::ToLocal(table_obj));
}
553

554 555
void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
556
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
557
  HandleScope scope(isolate);
558
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory()");
559
  if (args.Length() < 1 || !args[0]->IsObject()) {
560
    thrower.TypeError("Argument 0 must be a memory descriptor");
561 562 563 564 565
    return;
  }
  Local<Context> context = isolate->GetCurrentContext();
  Local<v8::Object> descriptor = args[0]->ToObject(context).ToLocalChecked();
  // The descriptor's 'initial'.
566
  int64_t initial = 0;
567
  if (!GetIntegerProperty(isolate, &thrower, context, descriptor,
568
                          v8_str(isolate, "initial"), &initial, 0,
569
                          i::FLAG_wasm_max_mem_pages)) {
570 571
    return;
  }
572
  // The descriptor's 'maximum'.
573
  int64_t maximum = -1;
574 575 576
  Local<String> maximum_key = v8_str(isolate, "maximum");
  Maybe<bool> has_maximum = descriptor->Has(context, maximum_key);

577
  if (!has_maximum.IsNothing() && has_maximum.FromJust()) {
578
    if (!GetIntegerProperty(isolate, &thrower, context, descriptor, maximum_key,
579 580
                            &maximum, initial,
                            i::wasm::kSpecMaxWasmMemoryPages)) {
581 582 583
      return;
    }
  }
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603

  bool is_shared_memory = false;
  if (i::FLAG_experimental_wasm_threads) {
    // Shared property of descriptor
    Local<String> shared_key = v8_str(isolate, "shared");
    Maybe<bool> has_shared = descriptor->Has(context, shared_key);
    if (!has_shared.IsNothing() && has_shared.FromJust()) {
      v8::MaybeLocal<v8::Value> maybe = descriptor->Get(context, shared_key);
      v8::Local<v8::Value> value;
      if (maybe.ToLocal(&value)) {
        if (!value->BooleanValue(context).To(&is_shared_memory)) return;
      }
    }
    // Throw TypeError if shared is true, and the descriptor has no "maximum"
    if (is_shared_memory && maximum == -1) {
      thrower.TypeError(
          "If shared is true, maximum property should be defined.");
    }
  }

604 605
  size_t size = static_cast<size_t>(i::wasm::WasmModule::kPageSize) *
                static_cast<size_t>(initial);
606 607 608
  i::Handle<i::JSArrayBuffer> buffer = i::wasm::NewArrayBuffer(
      i_isolate, size, i::FLAG_wasm_guard_pages,
      is_shared_memory ? i::SharedFlag::kShared : i::SharedFlag::kNotShared);
609 610 611 612
  if (buffer.is_null()) {
    thrower.RangeError("could not allocate memory");
    return;
  }
613 614 615 616 617 618 619 620
  if (buffer->is_shared()) {
    Maybe<bool> result =
        buffer->SetIntegrityLevel(buffer, i::FROZEN, i::Object::DONT_THROW);
    if (!result.FromJust()) {
      thrower.TypeError(
          "Status of setting SetIntegrityLevel of buffer is false.");
    }
  }
621 622
  i::Handle<i::JSObject> memory_obj = i::WasmMemoryObject::New(
      i_isolate, buffer, static_cast<int32_t>(maximum));
623
  args.GetReturnValue().Set(Utils::ToLocal(memory_obj));
624
}
625

626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
#define NAME_OF_WasmMemoryObject "WebAssembly.Memory"
#define NAME_OF_WasmModuleObject "WebAssembly.Module"
#define NAME_OF_WasmInstanceObject "WebAssembly.Instance"
#define NAME_OF_WasmTableObject "WebAssembly.Table"

#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()) {                                 \
      thrower.TypeError("Receiver is not a " NAME_OF_##WasmType);    \
      return;                                                        \
    }                                                                \
    var = i::Handle<i::WasmType>::cast(this_arg);                    \
  }

642 643
void WebAssemblyTableGetLength(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
644
  v8::Isolate* isolate = args.GetIsolate();
645 646
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
647
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.length()");
648
  EXTRACT_THIS(receiver, WasmTableObject);
649 650
  args.GetReturnValue().Set(
      v8::Number::New(isolate, receiver->current_length()));
651
}
652

653
// WebAssembly.Table.grow(num) -> num
654
void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
655
  v8::Isolate* isolate = args.GetIsolate();
656 657
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
658
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.grow()");
659
  Local<Context> context = isolate->GetCurrentContext();
660
  EXTRACT_THIS(receiver, WasmTableObject);
661

662
  i::Handle<i::FixedArray> old_array(receiver->functions(), i_isolate);
663 664 665 666 667 668 669
  int old_size = old_array->length();
  int64_t new_size64 = 0;
  if (args.Length() > 0 && !args[0]->IntegerValue(context).To(&new_size64)) {
    return;
  }
  new_size64 += old_size;

670 671
  int64_t max_size64 = receiver->maximum_length()->Number();
  if (max_size64 < 0 || max_size64 > i::FLAG_wasm_max_table_size) {
672
    max_size64 = i::FLAG_wasm_max_table_size;
673 674 675
  }

  if (new_size64 < old_size || new_size64 > max_size64) {
676 677
    thrower.RangeError(new_size64 < old_size ? "trying to shrink table"
                                             : "maximum table size exceeded");
678 679
    return;
  }
680

681
  int new_size = static_cast<int>(new_size64);
682
  receiver->grow(i_isolate, static_cast<uint32_t>(new_size - old_size));
683 684 685 686 687 688 689

  if (new_size != old_size) {
    i::Handle<i::FixedArray> new_array =
        i_isolate->factory()->NewFixedArray(new_size);
    for (int i = 0; i < old_size; ++i) new_array->set(i, old_array->get(i));
    i::Object* null = i_isolate->heap()->null_value();
    for (int i = old_size; i < new_size; ++i) new_array->set(i, null);
690
    receiver->set_functions(*new_array);
691 692
  }

693 694 695
  // TODO(gdeepti): use weak links for instances
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(old_size);
696
}
697

698
// WebAssembly.Table.get(num) -> JSFunction
699
void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) {
700
  v8::Isolate* isolate = args.GetIsolate();
701
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
702
  HandleScope scope(isolate);
703
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.get()");
704
  Local<Context> context = isolate->GetCurrentContext();
705
  EXTRACT_THIS(receiver, WasmTableObject);
706
  i::Handle<i::FixedArray> array(receiver->functions(), i_isolate);
707 708 709
  int i = 0;
  if (args.Length() > 0 && !args[0]->Int32Value(context).To(&i)) return;
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
710
  if (i < 0 || i >= array->length()) {
711
    thrower.RangeError("index out of bounds");
712
    return;
713
  }
714

715
  i::Handle<i::Object> value(array->get(i), i_isolate);
716
  return_value.Set(Utils::ToLocal(value));
717
}
718

719
// WebAssembly.Table.set(num, JSFunction)
720
void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
721
  v8::Isolate* isolate = args.GetIsolate();
722
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
723
  HandleScope scope(isolate);
724
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.set()");
725
  Local<Context> context = isolate->GetCurrentContext();
726 727
  EXTRACT_THIS(receiver, WasmTableObject);

728
  if (args.Length() < 2) {
729
    thrower.TypeError("Argument 1 must be null or a function");
730 731
    return;
  }
732 733 734 735 736 737

  // Parameter 0.
  int32_t index;
  if (!args[0]->Int32Value(context).To(&index)) return;

  // Parameter 1.
738 739 740 741 742
  i::Handle<i::Object> value = Utils::OpenHandle(*args[1]);
  if (!value->IsNull(i_isolate) &&
      (!value->IsJSFunction() ||
       i::Handle<i::JSFunction>::cast(value)->code()->kind() !=
           i::Code::JS_TO_WASM_FUNCTION)) {
743
    thrower.TypeError("Argument 1 must be null or a WebAssembly function");
744 745
    return;
  }
746

747 748 749 750
  i::wasm::TableSet(&thrower, i_isolate, receiver, index,
                    value->IsNull(i_isolate)
                        ? i::Handle<i::JSFunction>::null()
                        : i::Handle<i::JSFunction>::cast(value));
751
}
752

753
// WebAssembly.Memory.grow(num) -> num
754
void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
755
  v8::Isolate* isolate = args.GetIsolate();
756
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
757
  HandleScope scope(isolate);
758
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory.grow()");
759
  Local<Context> context = isolate->GetCurrentContext();
760 761
  EXTRACT_THIS(receiver, WasmMemoryObject);

762 763
  int64_t delta_size = 0;
  if (args.Length() < 1 || !args[0]->IntegerValue(context).To(&delta_size)) {
764
    thrower.TypeError("Argument 0 required, must be numeric value of pages");
765 766
    return;
  }
767 768
  int64_t max_size64 = receiver->maximum_pages();
  if (max_size64 < 0 ||
769 770
      max_size64 > static_cast<int64_t>(i::FLAG_wasm_max_mem_pages)) {
    max_size64 = i::FLAG_wasm_max_mem_pages;
771
  }
772
  i::Handle<i::JSArrayBuffer> old_buffer(receiver->array_buffer());
773 774 775 776
  uint32_t old_size =
      old_buffer->byte_length()->Number() / i::wasm::kSpecMaxWasmMemoryPages;
  int64_t new_size64 = old_size + delta_size;
  if (delta_size < 0 || max_size64 < new_size64 || new_size64 < old_size) {
777 778
    thrower.RangeError(new_size64 < old_size ? "trying to shrink memory"
                                             : "maximum memory size exceeded");
779 780
    return;
  }
781 782
  int32_t ret = i::WasmMemoryObject::Grow(i_isolate, receiver,
                                          static_cast<uint32_t>(delta_size));
783
  if (ret == -1) {
784
    thrower.RangeError("Unable to grow instance memory.");
785 786
    return;
  }
787
  bool free_memory = (delta_size != 0);
788 789 790
  if (!old_buffer->is_shared()) {
    i::wasm::DetachWebAssemblyMemoryBuffer(i_isolate, old_buffer, free_memory);
  }
791 792
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(ret);
793
}
794

795
// WebAssembly.Memory.buffer -> ArrayBuffer
796 797 798
void WebAssemblyMemoryGetBuffer(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
799
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
800
  HandleScope scope(isolate);
801
  ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Memory.buffer");
802 803
  EXTRACT_THIS(receiver, WasmMemoryObject);

804 805 806 807 808 809 810 811 812 813 814 815 816 817
  i::Handle<i::Object> buffer_obj(receiver->array_buffer(), i_isolate);
  DCHECK(buffer_obj->IsJSArrayBuffer());
  i::Handle<i::JSArrayBuffer> buffer(i::JSArrayBuffer::cast(*buffer_obj));
  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 =
        buffer->SetIntegrityLevel(buffer, i::FROZEN, i::Object::DONT_THROW);
    if (!result.FromJust()) {
      thrower.TypeError(
          "Status of setting SetIntegrityLevel of buffer is false.");
    }
  }
818 819 820
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(Utils::ToLocal(buffer));
}
821 822 823 824 825 826 827
}  // namespace

// TODO(titzer): we use the API to create the function template because the
// internal guts are too ugly to replicate here.
static i::Handle<i::FunctionTemplateInfo> NewTemplate(i::Isolate* i_isolate,
                                                      FunctionCallback func) {
  Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
828 829 830
  Local<FunctionTemplate> templ = FunctionTemplate::New(isolate, func);
  templ->ReadOnlyPrototype();
  return v8::Utils::OpenHandle(*templ);
831 832 833 834
}

namespace internal {

835
Handle<JSFunction> InstallFunc(Isolate* isolate, Handle<JSObject> object,
836 837
                               const char* str, FunctionCallback func,
                               int length = 0) {
838 839 840
  Handle<String> name = v8_str(isolate, str);
  Handle<FunctionTemplateInfo> temp = NewTemplate(isolate, func);
  Handle<JSFunction> function =
841 842
      ApiNatives::InstantiateFunction(temp, name).ToHandleChecked();
  DCHECK(function->shared()->has_shared_name());
843
  function->shared()->set_length(length);
844
  PropertyAttributes attributes = static_cast<PropertyAttributes>(DONT_ENUM);
845
  JSObject::AddProperty(object, name, function, attributes);
rossberg's avatar
rossberg committed
846
  return function;
847 848
}

849 850 851 852
Handle<JSFunction> InstallGetter(Isolate* isolate, Handle<JSObject> object,
                                 const char* str, FunctionCallback func) {
  Handle<String> name = v8_str(isolate, str);
  Handle<FunctionTemplateInfo> temp = NewTemplate(isolate, func);
853
  // TODO(ishell): shouldn't we set "get "+name as getter's name?
854 855
  Handle<JSFunction> function =
      ApiNatives::InstantiateFunction(temp).ToHandleChecked();
856
  DCHECK(function->shared()->has_shared_name());
857
  v8::PropertyAttribute attributes =
858
      static_cast<v8::PropertyAttribute>(v8::DontEnum);
859 860 861 862 863 864
  Utils::ToLocal(object)->SetAccessorProperty(Utils::ToLocal(name),
                                              Utils::ToLocal(function),
                                              Local<Function>(), attributes);
  return function;
}

865 866 867
void WasmJs::Install(Isolate* isolate) {
  Handle<JSGlobalObject> global = isolate->global_object();
  Handle<Context> context(global->native_context(), isolate);
868 869 870 871 872 873
  // Install the JS API once only.
  Object* prev = context->get(Context::WASM_MODULE_CONSTRUCTOR_INDEX);
  if (!prev->IsUndefined(isolate)) {
    DCHECK(prev->IsJSFunction());
    return;
  }
874

875 876
  Factory* factory = isolate->factory();

877
  // Setup WebAssembly
878
  Handle<String> name = v8_str(isolate, "WebAssembly");
879 880
  Handle<JSFunction> cons = factory->NewFunction(isolate->strict_function_map(),
                                                 name, MaybeHandle<Code>());
881
  JSFunction::SetPrototype(cons, isolate->initial_object_prototype());
882
  cons->shared()->set_instance_class_name(*name);
883
  Handle<JSObject> webassembly = factory->NewJSObject(cons, TENURED);
884
  PropertyAttributes attributes = static_cast<PropertyAttributes>(DONT_ENUM);
885
  JSObject::AddProperty(global, name, webassembly, attributes);
886 887 888 889
  PropertyAttributes ro_attributes =
      static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
  JSObject::AddProperty(webassembly, factory->to_string_tag_symbol(),
                        v8_str(isolate, "WebAssembly"), ro_attributes);
890 891
  InstallFunc(isolate, webassembly, "compile", WebAssemblyCompile, 1);
  InstallFunc(isolate, webassembly, "validate", WebAssemblyValidate, 1);
892
  InstallFunc(isolate, webassembly, "instantiate", WebAssemblyInstantiate, 1);
893 894 895 896 897 898 899

  if (isolate->wasm_compile_streaming_callback() != nullptr) {
    InstallFunc(isolate, webassembly, "compileStreaming",
                WebAssemblyCompileStreaming, 1);
    InstallFunc(isolate, webassembly, "instantiateStreaming",
                WebAssemblyInstantiateStreaming, 1);
  }
900

901 902
  // Setup Module
  Handle<JSFunction> module_constructor =
903
      InstallFunc(isolate, webassembly, "Module", WebAssemblyModule, 1);
904 905 906
  context->set_wasm_module_constructor(*module_constructor);
  Handle<JSObject> module_proto =
      factory->NewJSObject(module_constructor, TENURED);
907
  i::Handle<i::Map> module_map = isolate->factory()->NewMap(
908 909
      i::WASM_MODULE_TYPE, i::JSObject::kHeaderSize +
                               WasmModuleObject::kFieldCount * i::kPointerSize);
910
  JSFunction::SetInitialMap(module_constructor, module_map, module_proto);
911 912
  InstallFunc(isolate, module_constructor, "imports", WebAssemblyModuleImports,
              1);
913 914
  InstallFunc(isolate, module_constructor, "exports", WebAssemblyModuleExports,
              1);
915 916
  InstallFunc(isolate, module_constructor, "customSections",
              WebAssemblyModuleCustomSections, 2);
917 918 919 920
  JSObject::AddProperty(module_proto, isolate->factory()->constructor_string(),
                        module_constructor, DONT_ENUM);
  JSObject::AddProperty(module_proto, factory->to_string_tag_symbol(),
                        v8_str(isolate, "WebAssembly.Module"), ro_attributes);
921 922 923

  // Setup Instance
  Handle<JSFunction> instance_constructor =
924
      InstallFunc(isolate, webassembly, "Instance", WebAssemblyInstance, 1);
925
  context->set_wasm_instance_constructor(*instance_constructor);
926 927 928
  Handle<JSObject> instance_proto =
      factory->NewJSObject(instance_constructor, TENURED);
  i::Handle<i::Map> instance_map = isolate->factory()->NewMap(
929
      i::WASM_INSTANCE_TYPE, WasmInstanceObject::kSize);
930 931 932 933
  JSFunction::SetInitialMap(instance_constructor, instance_map, instance_proto);
  JSObject::AddProperty(instance_proto,
                        isolate->factory()->constructor_string(),
                        instance_constructor, DONT_ENUM);
934 935
  JSObject::AddProperty(instance_proto, factory->to_string_tag_symbol(),
                        v8_str(isolate, "WebAssembly.Instance"), ro_attributes);
936 937 938

  // Setup Table
  Handle<JSFunction> table_constructor =
939
      InstallFunc(isolate, webassembly, "Table", WebAssemblyTable, 1);
940 941 942
  context->set_wasm_table_constructor(*table_constructor);
  Handle<JSObject> table_proto =
      factory->NewJSObject(table_constructor, TENURED);
943 944
  i::Handle<i::Map> table_map =
      isolate->factory()->NewMap(i::WASM_TABLE_TYPE, WasmTableObject::kSize);
945
  JSFunction::SetInitialMap(table_constructor, table_map, table_proto);
946 947 948
  JSObject::AddProperty(table_proto, isolate->factory()->constructor_string(),
                        table_constructor, DONT_ENUM);
  InstallGetter(isolate, table_proto, "length", WebAssemblyTableGetLength);
949 950 951
  InstallFunc(isolate, table_proto, "grow", WebAssemblyTableGrow, 1);
  InstallFunc(isolate, table_proto, "get", WebAssemblyTableGet, 1);
  InstallFunc(isolate, table_proto, "set", WebAssemblyTableSet, 2);
952 953
  JSObject::AddProperty(table_proto, factory->to_string_tag_symbol(),
                        v8_str(isolate, "WebAssembly.Table"), ro_attributes);
954 955 956

  // Setup Memory
  Handle<JSFunction> memory_constructor =
957
      InstallFunc(isolate, webassembly, "Memory", WebAssemblyMemory, 1);
958 959 960
  context->set_wasm_memory_constructor(*memory_constructor);
  Handle<JSObject> memory_proto =
      factory->NewJSObject(memory_constructor, TENURED);
961 962
  i::Handle<i::Map> memory_map =
      isolate->factory()->NewMap(i::WASM_MEMORY_TYPE, WasmMemoryObject::kSize);
963
  JSFunction::SetInitialMap(memory_constructor, memory_map, memory_proto);
964 965
  JSObject::AddProperty(memory_proto, isolate->factory()->constructor_string(),
                        memory_constructor, DONT_ENUM);
966
  InstallFunc(isolate, memory_proto, "grow", WebAssemblyMemoryGrow, 1);
967
  InstallGetter(isolate, memory_proto, "buffer", WebAssemblyMemoryGetBuffer);
968 969
  JSObject::AddProperty(memory_proto, factory->to_string_tag_symbol(),
                        v8_str(isolate, "WebAssembly.Memory"), ro_attributes);
970 971

  // Setup errors
972
  attributes = static_cast<PropertyAttributes>(DONT_ENUM);
973 974
  Handle<JSFunction> compile_error(
      isolate->native_context()->wasm_compile_error_function());
975
  JSObject::AddProperty(webassembly, isolate->factory()->CompileError_string(),
976
                        compile_error, attributes);
977 978 979 980
  Handle<JSFunction> link_error(
      isolate->native_context()->wasm_link_error_function());
  JSObject::AddProperty(webassembly, isolate->factory()->LinkError_string(),
                        link_error, attributes);
981 982
  Handle<JSFunction> runtime_error(
      isolate->native_context()->wasm_runtime_error_function());
983
  JSObject::AddProperty(webassembly, isolate->factory()->RuntimeError_string(),
984
                        runtime_error, attributes);
985
}
986 987
}  // namespace internal
}  // namespace v8