OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |