Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: src/wasm/wasm-js.cc

Issue 2806073002: [wasm] instantiate expressed in terms of compile (Closed)
Patch Set: feedback Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/runtime/runtime-test.cc ('k') | src/wasm/wasm-module.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/api-natives.h" 5 #include "src/api-natives.h"
6 #include "src/api.h" 6 #include "src/api.h"
7 #include "src/asmjs/asm-js.h" 7 #include "src/asmjs/asm-js.h"
8 #include "src/asmjs/asm-typer.h" 8 #include "src/asmjs/asm-typer.h"
9 #include "src/asmjs/asm-wasm-builder.h" 9 #include "src/asmjs/asm-wasm-builder.h"
10 #include "src/assert-scope.h" 10 #include "src/assert-scope.h"
(...skipping 14 matching lines...) Expand all
25 #include "src/wasm/wasm-result.h" 25 #include "src/wasm/wasm-result.h"
26 26
27 typedef uint8_t byte; 27 typedef uint8_t byte;
28 28
29 using v8::internal::wasm::ErrorThrower; 29 using v8::internal::wasm::ErrorThrower;
30 30
31 namespace v8 { 31 namespace v8 {
32 32
33 namespace { 33 namespace {
34 34
35 #define ASSIGN(type, var, expr) \
36 Local<type> var; \
37 do { \
38 if (!expr.ToLocal(&var)) { \
39 DCHECK(i_isolate->has_pending_exception()); \
adamk 2017/04/18 17:17:22 You still need to return here, otherwise we'll cra
40 } \
41 } while (false)
42
35 // TODO(wasm): move brand check to the respective types, and don't throw 43 // TODO(wasm): move brand check to the respective types, and don't throw
36 // in it, rather, use a provided ErrorThrower, or let caller handle it. 44 // in it, rather, use a provided ErrorThrower, or let caller handle it.
37 static bool HasBrand(i::Handle<i::Object> value, i::Handle<i::Symbol> sym) { 45 static bool HasBrand(i::Handle<i::Object> value, i::Handle<i::Symbol> sym) {
38 if (!value->IsJSObject()) return false; 46 if (!value->IsJSObject()) return false;
39 i::Handle<i::JSObject> object = i::Handle<i::JSObject>::cast(value); 47 i::Handle<i::JSObject> object = i::Handle<i::JSObject>::cast(value);
40 Maybe<bool> has_brand = i::JSObject::HasOwnProperty(object, sym); 48 Maybe<bool> has_brand = i::JSObject::HasOwnProperty(object, sym);
41 return has_brand.FromMaybe(false); 49 return has_brand.FromMaybe(false);
42 } 50 }
43 51
44 static bool BrandCheck(i::Handle<i::Object> value, i::Handle<i::Symbol> sym, 52 static bool BrandCheck(i::Handle<i::Object> value, i::Handle<i::Symbol> sym,
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 } 118 }
111 if (length > i::wasm::kV8MaxWasmModuleSize) { 119 if (length > i::wasm::kV8MaxWasmModuleSize) {
112 thrower->RangeError("buffer source exceeds maximum size of %zu (is %zu)", 120 thrower->RangeError("buffer source exceeds maximum size of %zu (is %zu)",
113 i::wasm::kV8MaxWasmModuleSize, length); 121 i::wasm::kV8MaxWasmModuleSize, length);
114 } 122 }
115 if (thrower->error()) return i::wasm::ModuleWireBytes(nullptr, nullptr); 123 if (thrower->error()) return i::wasm::ModuleWireBytes(nullptr, nullptr);
116 // TODO(titzer): use the handle as well? 124 // TODO(titzer): use the handle as well?
117 return i::wasm::ModuleWireBytes(start, start + length); 125 return i::wasm::ModuleWireBytes(start, start + length);
118 } 126 }
119 127
120 i::MaybeHandle<i::JSReceiver> GetSecondArgumentAsImports( 128 i::MaybeHandle<i::JSReceiver> GetValueAsImports(const Local<Value>& arg,
adamk 2017/04/18 17:17:22 Style nit: we pass Locals and Handles by value (th
121 const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) { 129 ErrorThrower* thrower) {
122 if (args.Length() < 2) return {}; 130 if (arg->IsUndefined()) return {};
123 if (args[1]->IsUndefined()) return {};
124 131
125 if (!args[1]->IsObject()) { 132 if (!arg->IsObject()) {
126 thrower->TypeError("Argument 1 must be an object"); 133 thrower->TypeError("Argument 1 must be an object");
127 return {}; 134 return {};
128 } 135 }
129 Local<Object> obj = Local<Object>::Cast(args[1]); 136 Local<Object> obj = Local<Object>::Cast(arg);
130 return i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj)); 137 return i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
131 } 138 }
132 139
133 // WebAssembly.compile(bytes) -> Promise 140 // WebAssembly.compile(bytes) -> Promise
134 void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) { 141 void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
135 v8::Isolate* isolate = args.GetIsolate(); 142 v8::Isolate* isolate = args.GetIsolate();
136 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 143 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
144 MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
137 if (i_isolate->wasm_compile_callback()(args)) return; 145 if (i_isolate->wasm_compile_callback()(args)) return;
138 146
139 HandleScope scope(isolate); 147 HandleScope scope(isolate);
140 ErrorThrower thrower(i_isolate, "WebAssembly.compile()"); 148 ErrorThrower thrower(i_isolate, "WebAssembly.compile()");
141 149
142 Local<Context> context = isolate->GetCurrentContext(); 150 Local<Context> context = isolate->GetCurrentContext();
143 v8::Local<v8::Promise::Resolver> resolver; 151 ASSIGN(Promise::Resolver, resolver, Promise::Resolver::New(context));
144 if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) return;
145 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); 152 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
146 return_value.Set(resolver->GetPromise()); 153 return_value.Set(resolver->GetPromise());
147 154
148 auto bytes = GetFirstArgumentAsBytes(args, &thrower); 155 auto bytes = GetFirstArgumentAsBytes(args, &thrower);
149 if (thrower.error()) { 156 if (thrower.error()) {
150 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); 157 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
151 CHECK_IMPLIES(!maybe.FromMaybe(false), 158 CHECK_IMPLIES(!maybe.FromMaybe(false),
152 i_isolate->has_scheduled_exception()); 159 i_isolate->has_scheduled_exception());
153 return; 160 return;
154 } 161 }
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 return; 253 return;
247 } 254 }
248 255
249 auto custom_sections = 256 auto custom_sections =
250 i::wasm::GetCustomSections(i_isolate, maybe_module.ToHandleChecked(), 257 i::wasm::GetCustomSections(i_isolate, maybe_module.ToHandleChecked(),
251 i::Handle<i::String>::cast(name), &thrower); 258 i::Handle<i::String>::cast(name), &thrower);
252 if (thrower.error()) return; 259 if (thrower.error()) return;
253 args.GetReturnValue().Set(Utils::ToLocal(custom_sections)); 260 args.GetReturnValue().Set(Utils::ToLocal(custom_sections));
254 } 261 }
255 262
263 MaybeLocal<Value> WebAssemblyInstantiateImpl(Isolate* isolate,
264 Local<Value> module,
265 Local<Value> ffi) {
266 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
267
268 ErrorThrower thrower(i_isolate, "WebAssembly Instantiation");
269 i::MaybeHandle<i::JSReceiver> maybe_imports =
270 GetValueAsImports(ffi, &thrower);
271 if (thrower.error()) return {};
272
273 i::Handle<i::WasmModuleObject> module_obj =
274 i::Handle<i::WasmModuleObject>::cast(
275 Utils::OpenHandle(Object::Cast(*module)));
276 i::MaybeHandle<i::Object> instance_object =
277 i::wasm::SyncInstantiate(i_isolate, &thrower, module_obj, maybe_imports,
278 i::MaybeHandle<i::JSArrayBuffer>());
279
280 if (instance_object.is_null()) {
281 // TODO(wasm): this *should* mean there's an error to throw, but
282 // we exit sometimes the instantiation pipeline without throwing.
283 // v8:6232.
284 return {};
285 }
286 return Utils::ToLocal(instance_object.ToHandleChecked());
287 }
288
289 // Entered as internal implementation detail of sync and async instantiate.
290 // args[0] *must* be a WebAssembly.Module.
291 void WebAssemblyInstantiateImplCallback(
292 const v8::FunctionCallbackInfo<v8::Value>& args) {
293 DCHECK_GE(args.Length(), 1);
294 v8::Isolate* isolate = args.GetIsolate();
295 MicrotasksScope does_not_run_microtasks(isolate,
296 MicrotasksScope::kDoNotRunMicrotasks);
297
298 HandleScope scope(args.GetIsolate());
299 Local<Value> module = args[0];
300 Local<Value> ffi = args.Data();
301 Local<Value> instance;
302 if (WebAssemblyInstantiateImpl(isolate, module, ffi).ToLocal(&instance)) {
303 args.GetReturnValue().Set(instance);
304 }
305 }
306
307 void WebAssemblyInstantiateToPairCallback(
308 const v8::FunctionCallbackInfo<v8::Value>& args) {
309 DCHECK_GE(args.Length(), 1);
310 Isolate* isolate = args.GetIsolate();
311 MicrotasksScope does_not_run_microtasks(isolate,
312 MicrotasksScope::kDoNotRunMicrotasks);
313
314 HandleScope scope(args.GetIsolate());
315
316 Local<Context> context = isolate->GetCurrentContext();
317 Local<Value> module = args[0];
318
319 const uint8_t* instance_str = reinterpret_cast<const uint8_t*>("instance");
320 const uint8_t* module_str = reinterpret_cast<const uint8_t*>("module");
321 Local<Value> instance;
322 if (!WebAssemblyInstantiateImpl(isolate, module, args.Data())
323 .ToLocal(&instance))
adamk 2017/04/18 17:17:22 Style nit: please add { } around if-statement body
324 return;
325
326 Local<Object> ret = Object::New(isolate);
327 Local<String> instance_name =
328 String::NewFromOneByte(isolate, instance_str,
329 NewStringType::kInternalized)
330 .ToLocalChecked();
331 Local<String> module_name =
332 String::NewFromOneByte(isolate, module_str, NewStringType::kInternalized)
333 .ToLocalChecked();
334
335 CHECK(ret->CreateDataProperty(context, instance_name, instance).IsJust());
336 CHECK(ret->CreateDataProperty(context, module_name, module).IsJust());
337 args.GetReturnValue().Set(ret);
338 }
339
256 // new WebAssembly.Instance(module, imports) -> WebAssembly.Instance 340 // new WebAssembly.Instance(module, imports) -> WebAssembly.Instance
257 void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) { 341 void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
342 Isolate* isolate = args.GetIsolate();
343 MicrotasksScope does_not_run_microtasks(isolate,
344 MicrotasksScope::kDoNotRunMicrotasks);
345
258 HandleScope scope(args.GetIsolate()); 346 HandleScope scope(args.GetIsolate());
259 v8::Isolate* isolate = args.GetIsolate();
260 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 347 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
261 if (i_isolate->wasm_instance_callback()(args)) return; 348 if (i_isolate->wasm_instance_callback()(args)) return;
262 349
263 ErrorThrower thrower(i_isolate, "WebAssembly.Instance()"); 350 ErrorThrower thrower(i_isolate, "WebAssembly.Instance()");
264 351
265 auto maybe_module = GetFirstArgumentAsModule(args, &thrower); 352 auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
266 if (thrower.error()) return; 353 if (thrower.error()) return;
267 354
268 auto maybe_imports = GetSecondArgumentAsImports(args, &thrower); 355 // If args.Length < 2, this will be undefined - see FunctionCallbackInfo.
269 if (thrower.error()) return; 356 // We'll check for that in WebAssemblyInstantiateImpl.
357 Local<Value> data = args[1];
270 358
271 i::MaybeHandle<i::Object> instance_object = i::wasm::SyncInstantiate( 359 Local<Value> instance;
272 i_isolate, &thrower, maybe_module.ToHandleChecked(), maybe_imports, 360 if (WebAssemblyInstantiateImpl(isolate, args[0], data).ToLocal(&instance)) {
273 i::MaybeHandle<i::JSArrayBuffer>()); 361 args.GetReturnValue().Set(instance);
274 if (instance_object.is_null()) return; 362 }
275 args.GetReturnValue().Set(Utils::ToLocal(instance_object.ToHandleChecked()));
276 } 363 }
277 364
278 // WebAssembly.instantiate(module, imports) -> WebAssembly.Instance 365 // WebAssembly.instantiate(module, imports) -> WebAssembly.Instance
279 // WebAssembly.instantiate(bytes, imports) -> 366 // WebAssembly.instantiate(bytes, imports) ->
280 // {module: WebAssembly.Module, instance: WebAssembly.Instance} 367 // {module: WebAssembly.Module, instance: WebAssembly.Instance}
281 void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) { 368 void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
282 v8::Isolate* isolate = args.GetIsolate(); 369 v8::Isolate* isolate = args.GetIsolate();
283 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 370 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
371 MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
284 if (i_isolate->wasm_instantiate_callback()(args)) return; 372 if (i_isolate->wasm_instantiate_callback()(args)) return;
285 373
286 ErrorThrower thrower(i_isolate, "WebAssembly.instantiate()"); 374 ErrorThrower thrower(i_isolate, "WebAssembly.instantiate()");
287 375
288 HandleScope scope(isolate); 376 HandleScope scope(isolate);
289 377
290 Local<Context> context = isolate->GetCurrentContext(); 378 Local<Context> context = isolate->GetCurrentContext();
291 i::Handle<i::Context> i_context = Utils::OpenHandle(*context); 379 i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
292 380
293 v8::Local<v8::Promise::Resolver> resolver; 381 ASSIGN(Promise::Resolver, resolver, Promise::Resolver::New(context));
294 if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) return; 382 Local<Promise> module_promise = resolver->GetPromise();
295 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); 383 args.GetReturnValue().Set(module_promise);
296 return_value.Set(resolver->GetPromise());
297 384
298 if (args.Length() < 1) { 385 if (args.Length() < 1) {
299 thrower.TypeError( 386 thrower.TypeError(
300 "Argument 0 must be provided and must be either a buffer source or a " 387 "Argument 0 must be provided and must be either a buffer source or a "
301 "WebAssembly.Module object"); 388 "WebAssembly.Module object");
302 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); 389 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
303 CHECK_IMPLIES(!maybe.FromMaybe(false), 390 CHECK_IMPLIES(!maybe.FromMaybe(false),
304 i_isolate->has_scheduled_exception()); 391 i_isolate->has_scheduled_exception());
305 return; 392 return;
306 } 393 }
307 394
308 i::Handle<i::Object> first_arg = Utils::OpenHandle(*args[0]); 395 Local<Value> first_arg_value = args[0];
396 i::Handle<i::Object> first_arg = Utils::OpenHandle(*first_arg_value);
309 if (!first_arg->IsJSObject()) { 397 if (!first_arg->IsJSObject()) {
310 thrower.TypeError( 398 thrower.TypeError(
311 "Argument 0 must be a buffer source or a WebAssembly.Module object"); 399 "Argument 0 must be a buffer source or a WebAssembly.Module object");
312 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); 400 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
313 CHECK_IMPLIES(!maybe.FromMaybe(false), 401 CHECK_IMPLIES(!maybe.FromMaybe(false),
314 i_isolate->has_scheduled_exception()); 402 i_isolate->has_scheduled_exception());
315 return; 403 return;
316 } 404 }
317 405
318 auto maybe_imports = GetSecondArgumentAsImports(args, &thrower); 406 FunctionCallback instantiator = nullptr;
319 if (thrower.error()) { 407 if (HasBrand(first_arg, i::Handle<i::Symbol>(i_context->wasm_module_sym()))) {
320 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); 408 module_promise = resolver->GetPromise();
321 CHECK_IMPLIES(!maybe.FromMaybe(false), 409 if (!resolver->Resolve(context, first_arg_value).IsJust()) return;
322 i_isolate->has_scheduled_exception()); 410 instantiator = WebAssemblyInstantiateImplCallback;
323 return; 411 } else {
412 ASSIGN(Function, async_compile, Function::New(context, WebAssemblyCompile));
413 ASSIGN(Value, async_compile_retval,
414 async_compile->Call(context, args.Holder(), 1, &first_arg_value));
415 module_promise = Local<Promise>::Cast(async_compile_retval);
416 instantiator = WebAssemblyInstantiateToPairCallback;
324 } 417 }
325 i::Handle<i::JSPromise> promise = Utils::OpenHandle(*resolver->GetPromise()); 418 DCHECK(!module_promise.IsEmpty());
326 if (HasBrand(first_arg, i::Handle<i::Symbol>(i_context->wasm_module_sym()))) { 419 DCHECK_NOT_NULL(instantiator);
327 // WebAssembly.instantiate(module, imports) -> WebAssembly.Instance 420 // If args.Length < 2, this will be undefined - see FunctionCallbackInfo.
328 auto module_object = GetFirstArgumentAsModule(args, &thrower); 421 // We'll check for that in WebAssemblyInstantiateImpl.
329 i::wasm::AsyncInstantiate(i_isolate, promise, 422 Local<Value> data = args[1];
330 module_object.ToHandleChecked(), maybe_imports); 423 ASSIGN(Function, instantiate_impl,
331 } else { 424 Function::New(context, instantiator, data));
332 // WebAssembly.instantiate(bytes, imports) -> {module, instance} 425 ASSIGN(Promise, result, module_promise->Then(context, instantiate_impl));
333 auto bytes = GetFirstArgumentAsBytes(args, &thrower); 426 args.GetReturnValue().Set(result);
334 if (thrower.error()) {
335 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
336 CHECK_IMPLIES(!maybe.FromMaybe(false),
337 i_isolate->has_scheduled_exception());
338 return;
339 }
340 i::wasm::AsyncCompileAndInstantiate(i_isolate, promise, bytes,
341 maybe_imports);
342 }
343 } 427 }
344 428
345 bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower, 429 bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
346 Local<Context> context, Local<v8::Object> object, 430 Local<Context> context, Local<v8::Object> object,
347 Local<String> property, int* result, 431 Local<String> property, int* result,
348 int64_t lower_bound, uint64_t upper_bound) { 432 int64_t lower_bound, uint64_t upper_bound) {
349 v8::MaybeLocal<v8::Value> maybe = object->Get(context, property); 433 v8::MaybeLocal<v8::Value> maybe = object->Get(context, property);
350 v8::Local<v8::Value> value; 434 v8::Local<v8::Value> value;
351 if (maybe.ToLocal(&value)) { 435 if (maybe.ToLocal(&value)) {
352 int64_t number; 436 int64_t number;
(...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after
884 i::Handle<i::Symbol> symbol(isolate->context()->wasm_memory_sym(), isolate); 968 i::Handle<i::Symbol> symbol(isolate->context()->wasm_memory_sym(), isolate);
885 return HasBrand(value, symbol); 969 return HasBrand(value, symbol);
886 } 970 }
887 971
888 bool WasmJs::IsWasmTableObject(Isolate* isolate, Handle<Object> value) { 972 bool WasmJs::IsWasmTableObject(Isolate* isolate, Handle<Object> value) {
889 i::Handle<i::Symbol> symbol(isolate->context()->wasm_table_sym(), isolate); 973 i::Handle<i::Symbol> symbol(isolate->context()->wasm_table_sym(), isolate);
890 return HasBrand(value, symbol); 974 return HasBrand(value, symbol);
891 } 975 }
892 } // namespace internal 976 } // namespace internal
893 } // namespace v8 977 } // namespace v8
OLDNEW
« no previous file with comments | « src/runtime/runtime-test.cc ('k') | src/wasm/wasm-module.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698