wasm-js.cc 40.9 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
// TODO(wasm): move brand check to the respective types, and don't throw
// in it, rather, use a provided ErrorThrower, or let caller handle it.
static bool HasBrand(i::Handle<i::Object> value, i::Handle<i::Symbol> sym) {
  if (!value->IsJSObject()) return false;
  i::Handle<i::JSObject> object = i::Handle<i::JSObject>::cast(value);
  Maybe<bool> has_brand = i::JSObject::HasOwnProperty(object, sym);
  return has_brand.FromMaybe(false);
}

static bool BrandCheck(i::Handle<i::Object> value, i::Handle<i::Symbol> sym,
                       ErrorThrower* thrower, const char* msg) {
  return HasBrand(value, sym) ? true : (thrower->TypeError("%s", msg), false);
}

57 58 59 60 61 62 63
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));
}

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
i::MaybeHandle<i::WasmModuleObject> GetFirstArgumentAsModule(
    const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
  v8::Isolate* isolate = args.GetIsolate();
  if (args.Length() < 1) {
    thrower->TypeError("Argument 0 must be a WebAssembly.Module");
    return {};
  }

  Local<Context> context = isolate->GetCurrentContext();
  i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
  if (!BrandCheck(Utils::OpenHandle(*args[0]),
                  i::handle(i_context->wasm_module_sym()), thrower,
                  "Argument 0 must be a WebAssembly.Module")) {
    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);
  }
91

92
  const byte* start = nullptr;
93
  size_t length = 0;
94
  v8::Local<v8::Value> source = args[0];
rossberg's avatar
rossberg committed
95
  if (source->IsArrayBuffer()) {
96
    // A raw array buffer was passed.
rossberg's avatar
rossberg committed
97
    Local<ArrayBuffer> buffer = Local<ArrayBuffer>::Cast(source);
98 99 100
    ArrayBuffer::Contents contents = buffer->GetContents();

    start = reinterpret_cast<const byte*>(contents.Data());
101
    length = contents.ByteLength();
rossberg's avatar
rossberg committed
102
  } else if (source->IsTypedArray()) {
103
    // A TypedArray was passed.
rossberg's avatar
rossberg committed
104
    Local<TypedArray> array = Local<TypedArray>::Cast(source);
105 106 107 108 109 110
    Local<ArrayBuffer> buffer = array->Buffer();

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

    start =
        reinterpret_cast<const byte*>(contents.Data()) + array->ByteOffset();
111
    length = array->ByteLength();
112
  } else {
113
    thrower->TypeError("Argument 0 must be a buffer source");
114
  }
115 116
  DCHECK_IMPLIES(length, start != nullptr);
  if (length == 0) {
117 118
    thrower->CompileError("BufferSource argument is empty");
  }
119 120 121 122 123
  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);
124
  // TODO(titzer): use the handle as well?
125
  return i::wasm::ModuleWireBytes(start, start + length);
126 127
}

128
i::MaybeHandle<i::JSReceiver> GetValueAsImports(Local<Value> arg,
129 130
                                                ErrorThrower* thrower) {
  if (arg->IsUndefined()) return {};
131

132
  if (!arg->IsObject()) {
133 134 135
    thrower->TypeError("Argument 1 must be an object");
    return {};
  }
136
  Local<Object> obj = Local<Object>::Cast(arg);
137
  return i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
138 139
}

140 141 142 143 144
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);
145 146
  DCHECK_NOT_NULL(i_isolate->wasm_compile_streaming_callback());
  i_isolate->wasm_compile_streaming_callback()(args);
147 148
}

149
// WebAssembly.compile(bytes) -> Promise
rossberg's avatar
rossberg committed
150 151
void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
152
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
153
  MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
154

rossberg's avatar
rossberg committed
155
  HandleScope scope(isolate);
156
  ErrorThrower thrower(i_isolate, "WebAssembly.compile()");
rossberg's avatar
rossberg committed
157

158
  Local<Context> context = isolate->GetCurrentContext();
159
  ASSIGN(Promise::Resolver, resolver, Promise::Resolver::New(context));
160 161 162
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(resolver->GetPromise());

163
  auto bytes = GetFirstArgumentAsBytes(args, &thrower);
164
  if (thrower.error()) {
165
    auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
166 167
    CHECK_IMPLIES(!maybe.FromMaybe(false),
                  i_isolate->has_scheduled_exception());
168
    return;
169
  }
170 171
  i::Handle<i::JSPromise> promise = Utils::OpenHandle(*resolver->GetPromise());
  i::wasm::AsyncCompile(i_isolate, promise, bytes);
rossberg's avatar
rossberg committed
172 173
}

174
// WebAssembly.validate(bytes) -> bool
175 176
void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
177
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
178
  HandleScope scope(isolate);
179
  ErrorThrower thrower(i_isolate, "WebAssembly.validate()");
180

181
  auto bytes = GetFirstArgumentAsBytes(args, &thrower);
182 183

  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
184
  if (!thrower.error() &&
185
      i::wasm::SyncValidate(reinterpret_cast<i::Isolate*>(isolate), bytes)) {
186 187
    return_value.Set(v8::True(isolate));
  } else {
188
    if (thrower.wasm_error()) thrower.Reset();  // Clear error.
189 190 191 192
    return_value.Set(v8::False(isolate));
  }
}

193
// new WebAssembly.Module(bytes) -> WebAssembly.Module
rossberg's avatar
rossberg committed
194 195
void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
196
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
197 198
  if (i_isolate->wasm_module_callback()(args)) return;

rossberg's avatar
rossberg committed
199
  HandleScope scope(isolate);
200
  ErrorThrower thrower(i_isolate, "WebAssembly.Module()");
rossberg's avatar
rossberg committed
201

202
  auto bytes = GetFirstArgumentAsBytes(args, &thrower);
203

204 205 206
  if (thrower.error()) {
    return;
  }
207 208
  i::MaybeHandle<i::Object> module_obj =
      i::wasm::SyncCompile(i_isolate, &thrower, bytes);
rossberg's avatar
rossberg committed
209 210 211 212 213 214
  if (module_obj.is_null()) return;

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

215
// WebAssembly.Module.imports(module) -> Array<Import>
216 217 218 219 220
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);
  ErrorThrower thrower(i_isolate, "WebAssembly.Module.imports()");
221

222
  auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
223 224 225
  if (thrower.error()) return;
  auto imports = i::wasm::GetImports(i_isolate, maybe_module.ToHandleChecked());
  args.GetReturnValue().Set(Utils::ToLocal(imports));
226 227
}

228
// WebAssembly.Module.exports(module) -> Array<Export>
229 230 231 232 233 234
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);
  ErrorThrower thrower(i_isolate, "WebAssembly.Module.exports()");

235
  auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
236 237 238
  if (thrower.error()) return;
  auto exports = i::wasm::GetExports(i_isolate, maybe_module.ToHandleChecked());
  args.GetReturnValue().Set(Utils::ToLocal(exports));
239
}
240

241
// WebAssembly.Module.customSections(module, name) -> Array<Section>
242 243 244 245 246 247 248
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);
  ErrorThrower thrower(i_isolate, "WebAssembly.Module.customSections()");

249
  auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
250
  if (thrower.error()) return;
251 252 253

  if (args.Length() < 2) {
    thrower.TypeError("Argument 1 must be a string");
254 255 256
    return;
  }

257 258 259 260 261
  i::Handle<i::Object> name = Utils::OpenHandle(*args[1]);
  if (!name->IsString()) {
    thrower.TypeError("Argument 1 must be a string");
    return;
  }
262

263 264 265 266 267
  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));
268 269
}

270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 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
MaybeLocal<Value> WebAssemblyInstantiateImpl(Isolate* isolate,
                                             Local<Value> module,
                                             Local<Value> ffi) {
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);

  ErrorThrower 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)));
  i::MaybeHandle<i::Object> instance_object =
      i::wasm::SyncInstantiate(i_isolate, &thrower, module_obj, maybe_imports,
                               i::MaybeHandle<i::JSArrayBuffer>());

  if (instance_object.is_null()) {
    // TODO(wasm): this *should* mean there's an error to throw, but
    // we exit sometimes the instantiation pipeline without throwing.
    // v8:6232.
    return {};
  }
  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())
330
           .ToLocal(&instance)) {
331
    return;
332
  }
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347

  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);
}

348
// new WebAssembly.Instance(module, imports) -> WebAssembly.Instance
349
void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
350 351 352 353
  Isolate* isolate = args.GetIsolate();
  MicrotasksScope does_not_run_microtasks(isolate,
                                          MicrotasksScope::kDoNotRunMicrotasks);

rossberg's avatar
rossberg committed
354
  HandleScope scope(args.GetIsolate());
355
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
356 357
  if (i_isolate->wasm_instance_callback()(args)) return;

358
  ErrorThrower thrower(i_isolate, "WebAssembly.Instance()");
359

360
  GetFirstArgumentAsModule(args, &thrower);
361
  if (thrower.error()) return;
362

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

367 368 369 370
  Local<Value> instance;
  if (WebAssemblyInstantiateImpl(isolate, args[0], data).ToLocal(&instance)) {
    args.GetReturnValue().Set(instance);
  }
371 372
}

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
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);
}

400 401 402
// WebAssembly.instantiate(module, imports) -> WebAssembly.Instance
// WebAssembly.instantiate(bytes, imports) ->
//     {module: WebAssembly.Module, instance: WebAssembly.Instance}
403 404 405
void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
406
  MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
407

408
  ErrorThrower thrower(i_isolate, "WebAssembly.instantiate()");
409 410 411

  HandleScope scope(isolate);

412
  Local<Context> context = isolate->GetCurrentContext();
413 414
  i::Handle<i::Context> i_context = Utils::OpenHandle(*context);

415 416 417
  ASSIGN(Promise::Resolver, resolver, Promise::Resolver::New(context));
  Local<Promise> module_promise = resolver->GetPromise();
  args.GetReturnValue().Set(module_promise);
418

419
  if (args.Length() < 1) {
420 421 422
    thrower.TypeError(
        "Argument 0 must be provided and must be either a buffer source or a "
        "WebAssembly.Module object");
423
    auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
424 425
    CHECK_IMPLIES(!maybe.FromMaybe(false),
                  i_isolate->has_scheduled_exception());
426
    return;
427
  }
428

429 430
  Local<Value> first_arg_value = args[0];
  i::Handle<i::Object> first_arg = Utils::OpenHandle(*first_arg_value);
431 432 433
  if (!first_arg->IsJSObject()) {
    thrower.TypeError(
        "Argument 0 must be a buffer source or a WebAssembly.Module object");
434
    auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
435 436
    CHECK_IMPLIES(!maybe.FromMaybe(false),
                  i_isolate->has_scheduled_exception());
437 438
    return;
  }
439

440
  FunctionCallback instantiator = nullptr;
441
  if (HasBrand(first_arg, i::Handle<i::Symbol>(i_context->wasm_module_sym()))) {
442 443 444
    module_promise = resolver->GetPromise();
    if (!resolver->Resolve(context, first_arg_value).IsJust()) return;
    instantiator = WebAssemblyInstantiateImplCallback;
445
  } else {
446 447 448 449 450
    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;
451
  }
452 453 454 455 456 457 458 459 460
  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);
461
}
462 463 464

bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
                        Local<Context> context, Local<v8::Object> object,
465 466
                        Local<String> property, int* result,
                        int64_t lower_bound, uint64_t upper_bound) {
467 468
  v8::MaybeLocal<v8::Value> maybe = object->Get(context, property);
  v8::Local<v8::Value> value;
469
  if (maybe.ToLocal(&value)) {
470 471
    int64_t number;
    if (!value->IntegerValue(context).To(&number)) return false;
472
    if (number < lower_bound) {
473
      thrower->RangeError("Property value %" PRId64
474
                          " is below the lower bound %" PRIx64,
475 476 477
                          number, lower_bound);
      return false;
    }
478
    if (number > static_cast<int64_t>(upper_bound)) {
479
      thrower->RangeError("Property value %" PRId64
480
                          " is above the upper bound %" PRIu64,
481 482 483
                          number, upper_bound);
      return false;
    }
484
    *result = static_cast<int>(number);
485 486 487 488 489
    return true;
  }
  return false;
}

490
// new WebAssembly.Table(args) -> WebAssembly.Table
491 492
void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
493
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
494
  HandleScope scope(isolate);
495
  ErrorThrower thrower(i_isolate, "WebAssembly.Module()");
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
  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'.
518
  int initial = 0;
519 520
  if (!GetIntegerProperty(isolate, &thrower, context, descriptor,
                          v8_str(isolate, "initial"), &initial, 0,
521
                          i::FLAG_wasm_max_table_size)) {
522 523 524
    return;
  }
  // The descriptor's 'maximum'.
525
  int maximum = -1;
526 527 528
  Local<String> maximum_key = v8_str(isolate, "maximum");
  Maybe<bool> has_maximum = descriptor->Has(context, maximum_key);

529
  if (!has_maximum.IsNothing() && has_maximum.FromJust()) {
530
    if (!GetIntegerProperty(isolate, &thrower, context, descriptor, maximum_key,
531 532
                            &maximum, initial,
                            i::wasm::kSpecMaxWasmTableSize)) {
533 534 535 536
      return;
    }
  }

537
  i::Handle<i::FixedArray> fixed_array;
538 539
  i::Handle<i::JSObject> table_obj =
      i::WasmTableObject::New(i_isolate, initial, maximum, &fixed_array);
540 541 542
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(Utils::ToLocal(table_obj));
}
543

544 545
void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
546
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
547
  HandleScope scope(isolate);
548
  ErrorThrower thrower(i_isolate, "WebAssembly.Memory()");
549
  if (args.Length() < 1 || !args[0]->IsObject()) {
550
    thrower.TypeError("Argument 0 must be a memory descriptor");
551 552 553 554 555
    return;
  }
  Local<Context> context = isolate->GetCurrentContext();
  Local<v8::Object> descriptor = args[0]->ToObject(context).ToLocalChecked();
  // The descriptor's 'initial'.
556
  int initial = 0;
557
  if (!GetIntegerProperty(isolate, &thrower, context, descriptor,
558
                          v8_str(isolate, "initial"), &initial, 0,
559
                          i::FLAG_wasm_max_mem_pages)) {
560 561
    return;
  }
562
  // The descriptor's 'maximum'.
563
  int maximum = -1;
564 565 566
  Local<String> maximum_key = v8_str(isolate, "maximum");
  Maybe<bool> has_maximum = descriptor->Has(context, maximum_key);

567
  if (!has_maximum.IsNothing() && has_maximum.FromJust()) {
568
    if (!GetIntegerProperty(isolate, &thrower, context, descriptor, maximum_key,
569 570
                            &maximum, initial,
                            i::wasm::kSpecMaxWasmMemoryPages)) {
571 572 573 574 575
      return;
    }
  }
  size_t size = static_cast<size_t>(i::wasm::WasmModule::kPageSize) *
                static_cast<size_t>(initial);
576 577
  i::Handle<i::JSArrayBuffer> buffer =
      i::wasm::NewArrayBuffer(i_isolate, size, i::FLAG_wasm_guard_pages);
578 579 580 581
  if (buffer.is_null()) {
    thrower.RangeError("could not allocate memory");
    return;
  }
582 583
  i::Handle<i::JSObject> memory_obj =
      i::WasmMemoryObject::New(i_isolate, buffer, maximum);
584
  args.GetReturnValue().Set(Utils::ToLocal(memory_obj));
585
}
586

587 588
void WebAssemblyTableGetLength(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
589
  v8::Isolate* isolate = args.GetIsolate();
590 591 592
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
  ErrorThrower thrower(i_isolate, "WebAssembly.Table.length()");
593 594
  Local<Context> context = isolate->GetCurrentContext();
  i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
595 596
  if (!BrandCheck(Utils::OpenHandle(*args.This()),
                  i::Handle<i::Symbol>(i_context->wasm_table_sym()), &thrower,
597 598 599
                  "Receiver is not a WebAssembly.Table")) {
    return;
  }
600 601 602 603
  auto receiver =
      i::Handle<i::WasmTableObject>::cast(Utils::OpenHandle(*args.This()));
  args.GetReturnValue().Set(
      v8::Number::New(isolate, receiver->current_length()));
604
}
605

606
// WebAssembly.Table.grow(num) -> num
607
void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
608
  v8::Isolate* isolate = args.GetIsolate();
609 610 611
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
  HandleScope scope(isolate);
  ErrorThrower thrower(i_isolate, "WebAssembly.Table.grow()");
612 613
  Local<Context> context = isolate->GetCurrentContext();
  i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
614 615
  if (!BrandCheck(Utils::OpenHandle(*args.This()),
                  i::Handle<i::Symbol>(i_context->wasm_table_sym()), &thrower,
616 617 618
                  "Receiver is not a WebAssembly.Table")) {
    return;
  }
619

620 621
  auto receiver =
      i::Handle<i::WasmTableObject>::cast(Utils::OpenHandle(*args.This()));
622
  i::Handle<i::FixedArray> old_array(receiver->functions(), i_isolate);
623 624 625 626 627 628 629
  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;

630 631
  int64_t max_size64 = receiver->maximum_length();
  if (max_size64 < 0 ||
632 633
      max_size64 > static_cast<int64_t>(i::FLAG_wasm_max_table_size)) {
    max_size64 = i::FLAG_wasm_max_table_size;
634 635 636
  }

  if (new_size64 < old_size || new_size64 > max_size64) {
637 638
    thrower.RangeError(new_size64 < old_size ? "trying to shrink table"
                                             : "maximum table size exceeded");
639 640
    return;
  }
641

642
  int new_size = static_cast<int>(new_size64);
643
  receiver->grow(i_isolate, static_cast<uint32_t>(new_size - old_size));
644 645 646 647 648 649 650

  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);
651
    receiver->set_functions(*new_array);
652 653
  }

654 655 656
  // TODO(gdeepti): use weak links for instances
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(old_size);
657
}
658

659
// WebAssembly.Table.get(num) -> JSFunction
660
void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) {
661
  v8::Isolate* isolate = args.GetIsolate();
662
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
663
  HandleScope scope(isolate);
664
  ErrorThrower thrower(i_isolate, "WebAssembly.Table.get()");
665 666
  Local<Context> context = isolate->GetCurrentContext();
  i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
667 668
  if (!BrandCheck(Utils::OpenHandle(*args.This()),
                  i::Handle<i::Symbol>(i_context->wasm_table_sym()), &thrower,
669 670 671 672
                  "Receiver is not a WebAssembly.Table")) {
    return;
  }

673 674
  auto receiver =
      i::Handle<i::WasmTableObject>::cast(Utils::OpenHandle(*args.This()));
675
  i::Handle<i::FixedArray> array(receiver->functions(), i_isolate);
676 677 678
  int i = 0;
  if (args.Length() > 0 && !args[0]->Int32Value(context).To(&i)) return;
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
679
  if (i < 0 || i >= array->length()) {
680
    thrower.RangeError("index out of bounds");
681
    return;
682
  }
683

684
  i::Handle<i::Object> value(array->get(i), i_isolate);
685
  return_value.Set(Utils::ToLocal(value));
686
}
687

688
// WebAssembly.Table.set(num, JSFunction)
689
void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
690
  v8::Isolate* isolate = args.GetIsolate();
691
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
692
  HandleScope scope(isolate);
693
  ErrorThrower thrower(i_isolate, "WebAssembly.Table.set()");
694 695
  Local<Context> context = isolate->GetCurrentContext();
  i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
696 697
  if (!BrandCheck(Utils::OpenHandle(*args.This()),
                  i::Handle<i::Symbol>(i_context->wasm_table_sym()), &thrower,
698 699 700
                  "Receiver is not a WebAssembly.Table")) {
    return;
  }
701
  if (args.Length() < 2) {
702
    thrower.TypeError("Argument 1 must be null or a function");
703 704
    return;
  }
705 706 707 708 709 710 711 712 713 714

  // {This} parameter.
  auto receiver =
      i::Handle<i::WasmTableObject>::cast(Utils::OpenHandle(*args.This()));

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

  // Parameter 1.
715 716 717 718 719
  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)) {
720
    thrower.TypeError("Argument 1 must be null or a WebAssembly function");
721 722
    return;
  }
723

724 725 726 727
  i::wasm::TableSet(&thrower, i_isolate, receiver, index,
                    value->IsNull(i_isolate)
                        ? i::Handle<i::JSFunction>::null()
                        : i::Handle<i::JSFunction>::cast(value));
728
}
729

730
// WebAssembly.Memory.grow(num) -> num
731
void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
732
  v8::Isolate* isolate = args.GetIsolate();
733
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
734
  HandleScope scope(isolate);
735
  ErrorThrower thrower(i_isolate, "WebAssembly.Memory.grow()");
736 737
  Local<Context> context = isolate->GetCurrentContext();
  i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
738 739
  if (!BrandCheck(Utils::OpenHandle(*args.This()),
                  i::Handle<i::Symbol>(i_context->wasm_memory_sym()), &thrower,
740 741 742
                  "Receiver is not a WebAssembly.Memory")) {
    return;
  }
743 744
  int64_t delta_size = 0;
  if (args.Length() < 1 || !args[0]->IntegerValue(context).To(&delta_size)) {
745
    thrower.TypeError("Argument 0 required, must be numeric value of pages");
746 747
    return;
  }
748 749 750 751
  i::Handle<i::WasmMemoryObject> receiver =
      i::Handle<i::WasmMemoryObject>::cast(Utils::OpenHandle(*args.This()));
  int64_t max_size64 = receiver->maximum_pages();
  if (max_size64 < 0 ||
752 753
      max_size64 > static_cast<int64_t>(i::FLAG_wasm_max_mem_pages)) {
    max_size64 = i::FLAG_wasm_max_mem_pages;
754 755 756 757 758 759
  }
  i::Handle<i::JSArrayBuffer> old_buffer(receiver->buffer());
  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) {
760 761
    thrower.RangeError(new_size64 < old_size ? "trying to shrink memory"
                                             : "maximum memory size exceeded");
762 763
    return;
  }
764 765
  int32_t ret = i::WasmMemoryObject::Grow(i_isolate, receiver,
                                          static_cast<uint32_t>(delta_size));
766
  if (ret == -1) {
767
    thrower.RangeError("Unable to grow instance memory.");
768 769
    return;
  }
770 771
  bool free_memory = (delta_size != 0);
  i::wasm::DetachWebAssemblyMemoryBuffer(i_isolate, old_buffer, free_memory);
772 773
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(ret);
774
}
775

776
// WebAssembly.Memory.buffer -> ArrayBuffer
777 778 779
void WebAssemblyMemoryGetBuffer(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
780
  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
781
  HandleScope scope(isolate);
782
  ErrorThrower thrower(i_isolate, "WebAssembly.Memory.buffer");
783 784
  Local<Context> context = isolate->GetCurrentContext();
  i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
785 786
  if (!BrandCheck(Utils::OpenHandle(*args.This()),
                  i::Handle<i::Symbol>(i_context->wasm_memory_sym()), &thrower,
787 788 789
                  "Receiver is not a WebAssembly.Memory")) {
    return;
  }
790 791
  i::Handle<i::WasmMemoryObject> receiver =
      i::Handle<i::WasmMemoryObject>::cast(Utils::OpenHandle(*args.This()));
792
  i::Handle<i::Object> buffer(receiver->buffer(), i_isolate);
793 794 795 796
  DCHECK(buffer->IsJSArrayBuffer());
  v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
  return_value.Set(Utils::ToLocal(buffer));
}
797 798 799 800 801 802 803
}  // 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);
804 805 806
  Local<FunctionTemplate> templ = FunctionTemplate::New(isolate, func);
  templ->ReadOnlyPrototype();
  return v8::Utils::OpenHandle(*templ);
807 808 809 810
}

namespace internal {

811
Handle<JSFunction> InstallFunc(Isolate* isolate, Handle<JSObject> object,
812 813
                               const char* str, FunctionCallback func,
                               int length = 0) {
814 815 816 817
  Handle<String> name = v8_str(isolate, str);
  Handle<FunctionTemplateInfo> temp = NewTemplate(isolate, func);
  Handle<JSFunction> function =
      ApiNatives::InstantiateFunction(temp).ToHandleChecked();
818 819
  JSFunction::SetName(function, name, isolate->factory()->empty_string());
  function->shared()->set_length(length);
820
  PropertyAttributes attributes = static_cast<PropertyAttributes>(DONT_ENUM);
821
  JSObject::AddProperty(object, name, function, attributes);
rossberg's avatar
rossberg committed
822
  return function;
823 824
}

825 826 827 828 829 830 831
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);
  Handle<JSFunction> function =
      ApiNatives::InstantiateFunction(temp).ToHandleChecked();
  v8::PropertyAttribute attributes =
832
      static_cast<v8::PropertyAttribute>(v8::DontEnum);
833 834 835 836 837 838
  Utils::ToLocal(object)->SetAccessorProperty(Utils::ToLocal(name),
                                              Utils::ToLocal(function),
                                              Local<Function>(), attributes);
  return function;
}

839 840 841 842 843 844 845 846 847 848 849 850
void WasmJs::Install(Isolate* isolate) {
  Handle<JSGlobalObject> global = isolate->global_object();
  Handle<Context> context(global->native_context(), isolate);
  // TODO(titzer): once FLAG_expose_wasm is gone, this should become a DCHECK.
  if (context->get(Context::WASM_FUNCTION_MAP_INDEX)->IsMap()) return;

  // Install Maps.

  // TODO(titzer): Also make one for strict mode functions?
  Handle<Map> prev_map = Handle<Map>(context->sloppy_function_map(), isolate);

  InstanceType instance_type = prev_map->instance_type();
851 852
  int embedder_fields = JSObject::GetEmbedderFieldCount(*prev_map);
  CHECK_EQ(0, embedder_fields);
853 854 855 856
  int pre_allocated =
      prev_map->GetInObjectProperties() - prev_map->unused_property_fields();
  int instance_size = 0;
  int in_object_properties = 0;
857 858 859 860
  int wasm_embedder_fields = embedder_fields + 1  // module instance object
                             + 1                  // function arity
                             + 1;                 // function signature
  JSFunction::CalculateInstanceSizeHelper(instance_type, wasm_embedder_fields,
861 862 863 864 865 866 867 868 869 870
                                          0, &instance_size,
                                          &in_object_properties);

  int unused_property_fields = in_object_properties - pre_allocated;
  Handle<Map> map = Map::CopyInitialMap(
      prev_map, instance_size, in_object_properties, unused_property_fields);

  context->set_wasm_function_map(*map);

  // Install symbols.
871

872 873 874 875 876 877 878 879 880 881 882 883 884 885
  Factory* factory = isolate->factory();
  // Create private symbols.
  Handle<Symbol> module_sym = factory->NewPrivateSymbol();
  context->set_wasm_module_sym(*module_sym);

  Handle<Symbol> instance_sym = factory->NewPrivateSymbol();
  context->set_wasm_instance_sym(*instance_sym);

  Handle<Symbol> table_sym = factory->NewPrivateSymbol();
  context->set_wasm_table_sym(*table_sym);

  Handle<Symbol> memory_sym = factory->NewPrivateSymbol();
  context->set_wasm_memory_sym(*memory_sym);

886 887 888
  // Install the JS API.

  // Setup WebAssembly
889 890
  Handle<String> name = v8_str(isolate, "WebAssembly");
  Handle<JSFunction> cons = factory->NewFunction(name);
891
  JSFunction::SetPrototype(cons, isolate->initial_object_prototype());
892
  cons->shared()->set_instance_class_name(*name);
893
  Handle<JSObject> webassembly = factory->NewJSObject(cons, TENURED);
894
  PropertyAttributes attributes = static_cast<PropertyAttributes>(DONT_ENUM);
895
  JSObject::AddProperty(global, name, webassembly, attributes);
896 897 898 899
  PropertyAttributes ro_attributes =
      static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
  JSObject::AddProperty(webassembly, factory->to_string_tag_symbol(),
                        v8_str(isolate, "WebAssembly"), ro_attributes);
900 901
  InstallFunc(isolate, webassembly, "compile", WebAssemblyCompile, 1);
  InstallFunc(isolate, webassembly, "validate", WebAssemblyValidate, 1);
902
  InstallFunc(isolate, webassembly, "instantiate", WebAssemblyInstantiate, 1);
903 904 905 906 907 908 909

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

911 912
  // Setup Module
  Handle<JSFunction> module_constructor =
913
      InstallFunc(isolate, webassembly, "Module", WebAssemblyModule, 1);
914 915 916
  context->set_wasm_module_constructor(*module_constructor);
  Handle<JSObject> module_proto =
      factory->NewJSObject(module_constructor, TENURED);
917
  i::Handle<i::Map> module_map = isolate->factory()->NewMap(
918
      i::JS_API_OBJECT_TYPE, i::JSObject::kHeaderSize +
919
                             WasmModuleObject::kFieldCount * i::kPointerSize);
920
  JSFunction::SetInitialMap(module_constructor, module_map, module_proto);
921 922
  InstallFunc(isolate, module_constructor, "imports", WebAssemblyModuleImports,
              1);
923 924
  InstallFunc(isolate, module_constructor, "exports", WebAssemblyModuleExports,
              1);
925 926
  InstallFunc(isolate, module_constructor, "customSections",
              WebAssemblyModuleCustomSections, 2);
927 928 929 930
  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);
931 932 933

  // Setup Instance
  Handle<JSFunction> instance_constructor =
934
      InstallFunc(isolate, webassembly, "Instance", WebAssemblyInstance, 1);
935
  context->set_wasm_instance_constructor(*instance_constructor);
936 937 938
  Handle<JSObject> instance_proto =
      factory->NewJSObject(instance_constructor, TENURED);
  i::Handle<i::Map> instance_map = isolate->factory()->NewMap(
939
      i::JS_API_OBJECT_TYPE, i::JSObject::kHeaderSize +
940 941 942 943 944
                             WasmInstanceObject::kFieldCount * i::kPointerSize);
  JSFunction::SetInitialMap(instance_constructor, instance_map, instance_proto);
  JSObject::AddProperty(instance_proto,
                        isolate->factory()->constructor_string(),
                        instance_constructor, DONT_ENUM);
945 946
  JSObject::AddProperty(instance_proto, factory->to_string_tag_symbol(),
                        v8_str(isolate, "WebAssembly.Instance"), ro_attributes);
947 948 949

  // Setup Table
  Handle<JSFunction> table_constructor =
950
      InstallFunc(isolate, webassembly, "Table", WebAssemblyTable, 1);
951 952 953
  context->set_wasm_table_constructor(*table_constructor);
  Handle<JSObject> table_proto =
      factory->NewJSObject(table_constructor, TENURED);
954
  i::Handle<i::Map> table_map = isolate->factory()->NewMap(
955
      i::JS_API_OBJECT_TYPE, i::JSObject::kHeaderSize +
956
                             WasmTableObject::kFieldCount * i::kPointerSize);
957
  JSFunction::SetInitialMap(table_constructor, table_map, table_proto);
958 959 960
  JSObject::AddProperty(table_proto, isolate->factory()->constructor_string(),
                        table_constructor, DONT_ENUM);
  InstallGetter(isolate, table_proto, "length", WebAssemblyTableGetLength);
961 962 963
  InstallFunc(isolate, table_proto, "grow", WebAssemblyTableGrow, 1);
  InstallFunc(isolate, table_proto, "get", WebAssemblyTableGet, 1);
  InstallFunc(isolate, table_proto, "set", WebAssemblyTableSet, 2);
964 965
  JSObject::AddProperty(table_proto, factory->to_string_tag_symbol(),
                        v8_str(isolate, "WebAssembly.Table"), ro_attributes);
966 967 968

  // Setup Memory
  Handle<JSFunction> memory_constructor =
969
      InstallFunc(isolate, webassembly, "Memory", WebAssemblyMemory, 1);
970 971 972
  context->set_wasm_memory_constructor(*memory_constructor);
  Handle<JSObject> memory_proto =
      factory->NewJSObject(memory_constructor, TENURED);
973
  i::Handle<i::Map> memory_map = isolate->factory()->NewMap(
974
      i::JS_API_OBJECT_TYPE, i::JSObject::kHeaderSize +
975
                             WasmMemoryObject::kFieldCount * i::kPointerSize);
976
  JSFunction::SetInitialMap(memory_constructor, memory_map, memory_proto);
977 978
  JSObject::AddProperty(memory_proto, isolate->factory()->constructor_string(),
                        memory_constructor, DONT_ENUM);
979
  InstallFunc(isolate, memory_proto, "grow", WebAssemblyMemoryGrow, 1);
980
  InstallGetter(isolate, memory_proto, "buffer", WebAssemblyMemoryGetBuffer);
981 982
  JSObject::AddProperty(memory_proto, factory->to_string_tag_symbol(),
                        v8_str(isolate, "WebAssembly.Memory"), ro_attributes);
983 984

  // Setup errors
985
  attributes = static_cast<PropertyAttributes>(DONT_ENUM);
986 987
  Handle<JSFunction> compile_error(
      isolate->native_context()->wasm_compile_error_function());
988
  JSObject::AddProperty(webassembly, isolate->factory()->CompileError_string(),
989
                        compile_error, attributes);
990 991 992 993
  Handle<JSFunction> link_error(
      isolate->native_context()->wasm_link_error_function());
  JSObject::AddProperty(webassembly, isolate->factory()->LinkError_string(),
                        link_error, attributes);
994 995
  Handle<JSFunction> runtime_error(
      isolate->native_context()->wasm_runtime_error_function());
996
  JSObject::AddProperty(webassembly, isolate->factory()->RuntimeError_string(),
997
                        runtime_error, attributes);
998 999
}

1000 1001 1002 1003 1004 1005 1006 1007 1008
bool WasmJs::IsWasmMemoryObject(Isolate* isolate, Handle<Object> value) {
  i::Handle<i::Symbol> symbol(isolate->context()->wasm_memory_sym(), isolate);
  return HasBrand(value, symbol);
}

bool WasmJs::IsWasmTableObject(Isolate* isolate, Handle<Object> value) {
  i::Handle<i::Symbol> symbol(isolate->context()->wasm_table_sym(), isolate);
  return HasBrand(value, symbol);
}
1009 1010
}  // namespace internal
}  // namespace v8