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)) return; \ | |
39 } while (false) | |
40 | |
41 #define DO_BOOL(expr) \ | |
42 do { \ | |
43 bool ok; \ | |
44 if (!expr.To(&ok) || !ok) return; \ | |
45 } while (false) | |
46 | |
47 // TODO(wasm): move brand check to the respective types, and don't throw | 35 // TODO(wasm): move brand check to the respective types, and don't throw |
48 // in it, rather, use a provided ErrorThrower, or let caller handle it. | 36 // in it, rather, use a provided ErrorThrower, or let caller handle it. |
49 static bool HasBrand(i::Handle<i::Object> value, i::Handle<i::Symbol> sym) { | 37 static bool HasBrand(i::Handle<i::Object> value, i::Handle<i::Symbol> sym) { |
50 if (!value->IsJSObject()) return false; | 38 if (!value->IsJSObject()) return false; |
51 i::Handle<i::JSObject> object = i::Handle<i::JSObject>::cast(value); | 39 i::Handle<i::JSObject> object = i::Handle<i::JSObject>::cast(value); |
52 Maybe<bool> has_brand = i::JSObject::HasOwnProperty(object, sym); | 40 Maybe<bool> has_brand = i::JSObject::HasOwnProperty(object, sym); |
53 return has_brand.FromMaybe(false); | 41 return has_brand.FromMaybe(false); |
54 } | 42 } |
55 | 43 |
56 static bool BrandCheck(i::Handle<i::Object> value, i::Handle<i::Symbol> sym, | 44 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... |
122 } | 110 } |
123 if (length > i::wasm::kV8MaxWasmModuleSize) { | 111 if (length > i::wasm::kV8MaxWasmModuleSize) { |
124 thrower->RangeError("buffer source exceeds maximum size of %zu (is %zu)", | 112 thrower->RangeError("buffer source exceeds maximum size of %zu (is %zu)", |
125 i::wasm::kV8MaxWasmModuleSize, length); | 113 i::wasm::kV8MaxWasmModuleSize, length); |
126 } | 114 } |
127 if (thrower->error()) return i::wasm::ModuleWireBytes(nullptr, nullptr); | 115 if (thrower->error()) return i::wasm::ModuleWireBytes(nullptr, nullptr); |
128 // TODO(titzer): use the handle as well? | 116 // TODO(titzer): use the handle as well? |
129 return i::wasm::ModuleWireBytes(start, start + length); | 117 return i::wasm::ModuleWireBytes(start, start + length); |
130 } | 118 } |
131 | 119 |
132 i::MaybeHandle<i::JSReceiver> GetValueAsImports(const Local<Value>& arg, | 120 i::MaybeHandle<i::JSReceiver> GetSecondArgumentAsImports( |
133 ErrorThrower* thrower) { | 121 const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) { |
134 if (arg->IsUndefined()) return {}; | 122 if (args.Length() < 2) return {}; |
| 123 if (args[1]->IsUndefined()) return {}; |
135 | 124 |
136 if (!arg->IsObject()) { | 125 if (!args[1]->IsObject()) { |
137 thrower->TypeError("Argument 1 must be an object"); | 126 thrower->TypeError("Argument 1 must be an object"); |
138 return {}; | 127 return {}; |
139 } | 128 } |
140 Local<Object> obj = Local<Object>::Cast(arg); | 129 Local<Object> obj = Local<Object>::Cast(args[1]); |
141 return i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj)); | 130 return i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj)); |
142 } | 131 } |
143 | 132 |
144 // WebAssembly.compile(bytes) -> Promise | 133 // WebAssembly.compile(bytes) -> Promise |
145 void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) { | 134 void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) { |
146 v8::Isolate* isolate = args.GetIsolate(); | 135 v8::Isolate* isolate = args.GetIsolate(); |
147 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); | 136 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
148 if (i_isolate->wasm_compile_callback()(args)) return; | 137 if (i_isolate->wasm_compile_callback()(args)) return; |
149 | 138 |
150 HandleScope scope(isolate); | 139 HandleScope scope(isolate); |
151 ErrorThrower thrower(i_isolate, "WebAssembly.compile()"); | 140 ErrorThrower thrower(i_isolate, "WebAssembly.compile()"); |
152 | 141 |
153 Local<Context> context = isolate->GetCurrentContext(); | 142 Local<Context> context = isolate->GetCurrentContext(); |
154 ASSIGN(Promise::Resolver, resolver, Promise::Resolver::New(context)); | 143 v8::Local<v8::Promise::Resolver> resolver; |
| 144 if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) return; |
155 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); | 145 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); |
156 return_value.Set(resolver->GetPromise()); | 146 return_value.Set(resolver->GetPromise()); |
157 | 147 |
158 auto bytes = GetFirstArgumentAsBytes(args, &thrower); | 148 auto bytes = GetFirstArgumentAsBytes(args, &thrower); |
159 if (thrower.error()) { | 149 if (thrower.error()) { |
160 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); | 150 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); |
161 CHECK_IMPLIES(!maybe.FromMaybe(false), | 151 CHECK_IMPLIES(!maybe.FromMaybe(false), |
162 i_isolate->has_scheduled_exception()); | 152 i_isolate->has_scheduled_exception()); |
163 return; | 153 return; |
164 } | 154 } |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 return; | 246 return; |
257 } | 247 } |
258 | 248 |
259 auto custom_sections = | 249 auto custom_sections = |
260 i::wasm::GetCustomSections(i_isolate, maybe_module.ToHandleChecked(), | 250 i::wasm::GetCustomSections(i_isolate, maybe_module.ToHandleChecked(), |
261 i::Handle<i::String>::cast(name), &thrower); | 251 i::Handle<i::String>::cast(name), &thrower); |
262 if (thrower.error()) return; | 252 if (thrower.error()) return; |
263 args.GetReturnValue().Set(Utils::ToLocal(custom_sections)); | 253 args.GetReturnValue().Set(Utils::ToLocal(custom_sections)); |
264 } | 254 } |
265 | 255 |
266 // Entered as internal implementation detail of sync and async instantiate. | |
267 // args[0] *must* be a WebAssembly.Module. | |
268 void WebAssemblyInstantiateImpl( | |
269 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
270 DCHECK_GE(args.Length(), 1); | |
271 Local<Value> module = args[0]; | |
272 Local<Value> ffi = args.Data(); | |
273 | |
274 HandleScope scope(args.GetIsolate()); | |
275 v8::Isolate* isolate = args.GetIsolate(); | |
276 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); | |
277 ErrorThrower thrower(i_isolate, "WebAssembly Instantiation"); | |
278 i::MaybeHandle<i::JSReceiver> maybe_imports = | |
279 GetValueAsImports(ffi, &thrower); | |
280 if (thrower.error()) return; | |
281 | |
282 i::Handle<i::WasmModuleObject> module_obj = | |
283 i::Handle<i::WasmModuleObject>::cast( | |
284 Utils::OpenHandle(Object::Cast(*module))); | |
285 i::MaybeHandle<i::Object> instance_object = | |
286 i::wasm::SyncInstantiate(i_isolate, &thrower, module_obj, maybe_imports, | |
287 i::MaybeHandle<i::JSArrayBuffer>()); | |
288 | |
289 if (instance_object.is_null()) { | |
290 // TODO(wasm): this *should* mean there's an error to throw, but | |
291 // we exit sometimes the instantiation pipeline without throwing. | |
292 // v8:6232. | |
293 return; | |
294 } | |
295 args.GetReturnValue().Set(Utils::ToLocal(instance_object.ToHandleChecked())); | |
296 } | |
297 | |
298 void WebAssemblyInstantiateToPair( | |
299 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
300 DCHECK_GE(args.Length(), 1); | |
301 Local<Value> module = args[0]; | |
302 Isolate* isolate = args.GetIsolate(); | |
303 Local<Context> context = isolate->GetCurrentContext(); | |
304 | |
305 const uint8_t* instance_str = reinterpret_cast<const uint8_t*>("instance"); | |
306 const uint8_t* module_str = reinterpret_cast<const uint8_t*>("module"); | |
307 ASSIGN(Function, vanilla_instantiate, | |
308 Function::New(context, WebAssemblyInstantiateImpl, args.Data())); | |
309 | |
310 ASSIGN(Value, instance, | |
311 vanilla_instantiate->Call(context, args.Holder(), 1, &module)); | |
312 Local<Object> ret = Object::New(isolate); | |
313 ASSIGN(String, instance_name, | |
314 String::NewFromOneByte(isolate, instance_str, | |
315 NewStringType::kInternalized)); | |
316 ASSIGN(String, module_name, | |
317 String::NewFromOneByte(isolate, module_str, | |
318 NewStringType::kInternalized)); | |
319 | |
320 DO_BOOL(ret->CreateDataProperty(context, instance_name, instance)); | |
321 DO_BOOL(ret->CreateDataProperty(context, module_name, module)); | |
322 args.GetReturnValue().Set(ret); | |
323 } | |
324 | |
325 // new WebAssembly.Instance(module, imports) -> WebAssembly.Instance | 256 // new WebAssembly.Instance(module, imports) -> WebAssembly.Instance |
326 void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) { | 257 void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) { |
327 HandleScope scope(args.GetIsolate()); | 258 HandleScope scope(args.GetIsolate()); |
328 Isolate* isolate = args.GetIsolate(); | 259 v8::Isolate* isolate = args.GetIsolate(); |
329 Local<Context> context = isolate->GetCurrentContext(); | |
330 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); | 260 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
331 if (i_isolate->wasm_instance_callback()(args)) return; | 261 if (i_isolate->wasm_instance_callback()(args)) return; |
332 | 262 |
333 ErrorThrower thrower(i_isolate, "WebAssembly.Instance()"); | 263 ErrorThrower thrower(i_isolate, "WebAssembly.Instance()"); |
334 | 264 |
335 auto maybe_module = GetFirstArgumentAsModule(args, &thrower); | 265 auto maybe_module = GetFirstArgumentAsModule(args, &thrower); |
336 if (thrower.error()) return; | 266 if (thrower.error()) return; |
337 | 267 |
338 // If args.Length < 2, this will be undefined - see FunctionCallbackInfo. | 268 auto maybe_imports = GetSecondArgumentAsImports(args, &thrower); |
339 // We'll check for that in WebAssemblyInstantiateImpl. | 269 if (thrower.error()) return; |
340 Local<Value> data = args[1]; | |
341 | 270 |
342 ASSIGN(Function, impl, | 271 i::MaybeHandle<i::Object> instance_object = i::wasm::SyncInstantiate( |
343 Function::New(context, WebAssemblyInstantiateImpl, data)); | 272 i_isolate, &thrower, maybe_module.ToHandleChecked(), maybe_imports, |
344 Local<Value> first_param = args[0]; | 273 i::MaybeHandle<i::JSArrayBuffer>()); |
345 ASSIGN(Value, ret, impl->Call(context, args.Holder(), 1, &first_param)); | 274 if (instance_object.is_null()) return; |
346 args.GetReturnValue().Set(ret); | 275 args.GetReturnValue().Set(Utils::ToLocal(instance_object.ToHandleChecked())); |
347 } | 276 } |
348 | 277 |
349 // WebAssembly.instantiate(module, imports) -> WebAssembly.Instance | 278 // WebAssembly.instantiate(module, imports) -> WebAssembly.Instance |
350 // WebAssembly.instantiate(bytes, imports) -> | 279 // WebAssembly.instantiate(bytes, imports) -> |
351 // {module: WebAssembly.Module, instance: WebAssembly.Instance} | 280 // {module: WebAssembly.Module, instance: WebAssembly.Instance} |
352 void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) { | 281 void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) { |
353 v8::Isolate* isolate = args.GetIsolate(); | 282 v8::Isolate* isolate = args.GetIsolate(); |
354 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); | 283 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
355 if (i_isolate->wasm_instantiate_callback()(args)) return; | 284 if (i_isolate->wasm_instantiate_callback()(args)) return; |
356 | 285 |
357 ErrorThrower thrower(i_isolate, "WebAssembly.instantiate()"); | 286 ErrorThrower thrower(i_isolate, "WebAssembly.instantiate()"); |
358 | 287 |
359 HandleScope scope(isolate); | 288 HandleScope scope(isolate); |
360 | 289 |
361 Local<Context> context = isolate->GetCurrentContext(); | 290 Local<Context> context = isolate->GetCurrentContext(); |
362 i::Handle<i::Context> i_context = Utils::OpenHandle(*context); | 291 i::Handle<i::Context> i_context = Utils::OpenHandle(*context); |
363 | 292 |
364 ASSIGN(Promise::Resolver, resolver, Promise::Resolver::New(context)); | 293 v8::Local<v8::Promise::Resolver> resolver; |
365 Local<Promise> module_promise = resolver->GetPromise(); | 294 if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) return; |
366 args.GetReturnValue().Set(module_promise); | 295 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); |
| 296 return_value.Set(resolver->GetPromise()); |
367 | 297 |
368 if (args.Length() < 1) { | 298 if (args.Length() < 1) { |
369 thrower.TypeError( | 299 thrower.TypeError( |
370 "Argument 0 must be provided and must be either a buffer source or a " | 300 "Argument 0 must be provided and must be either a buffer source or a " |
371 "WebAssembly.Module object"); | 301 "WebAssembly.Module object"); |
372 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); | 302 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); |
373 CHECK_IMPLIES(!maybe.FromMaybe(false), | 303 CHECK_IMPLIES(!maybe.FromMaybe(false), |
374 i_isolate->has_scheduled_exception()); | 304 i_isolate->has_scheduled_exception()); |
375 return; | 305 return; |
376 } | 306 } |
377 | 307 |
378 Local<Value> first_arg_value = args[0]; | 308 i::Handle<i::Object> first_arg = Utils::OpenHandle(*args[0]); |
379 i::Handle<i::Object> first_arg = Utils::OpenHandle(*first_arg_value); | |
380 if (!first_arg->IsJSObject()) { | 309 if (!first_arg->IsJSObject()) { |
381 thrower.TypeError( | 310 thrower.TypeError( |
382 "Argument 0 must be a buffer source or a WebAssembly.Module object"); | 311 "Argument 0 must be a buffer source or a WebAssembly.Module object"); |
383 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); | 312 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); |
384 CHECK_IMPLIES(!maybe.FromMaybe(false), | 313 CHECK_IMPLIES(!maybe.FromMaybe(false), |
385 i_isolate->has_scheduled_exception()); | 314 i_isolate->has_scheduled_exception()); |
386 return; | 315 return; |
387 } | 316 } |
388 | 317 |
389 FunctionCallback instantiator = nullptr; | 318 auto maybe_imports = GetSecondArgumentAsImports(args, &thrower); |
| 319 if (thrower.error()) { |
| 320 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); |
| 321 CHECK_IMPLIES(!maybe.FromMaybe(false), |
| 322 i_isolate->has_scheduled_exception()); |
| 323 return; |
| 324 } |
| 325 i::Handle<i::JSPromise> promise = Utils::OpenHandle(*resolver->GetPromise()); |
390 if (HasBrand(first_arg, i::Handle<i::Symbol>(i_context->wasm_module_sym()))) { | 326 if (HasBrand(first_arg, i::Handle<i::Symbol>(i_context->wasm_module_sym()))) { |
391 module_promise = resolver->GetPromise(); | 327 // WebAssembly.instantiate(module, imports) -> WebAssembly.Instance |
392 DO_BOOL(resolver->Resolve(context, first_arg_value)); | 328 auto module_object = GetFirstArgumentAsModule(args, &thrower); |
393 instantiator = WebAssemblyInstantiateImpl; | 329 i::wasm::AsyncInstantiate(i_isolate, promise, |
| 330 module_object.ToHandleChecked(), maybe_imports); |
394 } else { | 331 } else { |
395 ASSIGN(Function, async_compile, Function::New(context, WebAssemblyCompile)); | 332 // WebAssembly.instantiate(bytes, imports) -> {module, instance} |
396 ASSIGN(Value, async_compile_retval, | 333 auto bytes = GetFirstArgumentAsBytes(args, &thrower); |
397 async_compile->Call(context, args.Holder(), 1, &first_arg_value)); | 334 if (thrower.error()) { |
398 module_promise = Local<Promise>::Cast(async_compile_retval); | 335 auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); |
399 instantiator = WebAssemblyInstantiateToPair; | 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); |
400 } | 342 } |
401 DCHECK(!module_promise.IsEmpty()); | |
402 DCHECK_NOT_NULL(instantiator); | |
403 // If args.Length < 2, this will be undefined - see FunctionCallbackInfo. | |
404 // We'll check for that in WebAssemblyInstantiateImpl. | |
405 Local<Value> data = args[1]; | |
406 ASSIGN(Function, instantiate_impl, | |
407 Function::New(context, instantiator, data)); | |
408 ASSIGN(Promise, result, module_promise->Then(context, instantiate_impl)); | |
409 args.GetReturnValue().Set(result); | |
410 } | 343 } |
411 | 344 |
412 bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower, | 345 bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower, |
413 Local<Context> context, Local<v8::Object> object, | 346 Local<Context> context, Local<v8::Object> object, |
414 Local<String> property, int* result, | 347 Local<String> property, int* result, |
415 int64_t lower_bound, uint64_t upper_bound) { | 348 int64_t lower_bound, uint64_t upper_bound) { |
416 v8::MaybeLocal<v8::Value> maybe = object->Get(context, property); | 349 v8::MaybeLocal<v8::Value> maybe = object->Get(context, property); |
417 v8::Local<v8::Value> value; | 350 v8::Local<v8::Value> value; |
418 if (maybe.ToLocal(&value)) { | 351 if (maybe.ToLocal(&value)) { |
419 int64_t number; | 352 int64_t number; |
(...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
951 i::Handle<i::Symbol> symbol(isolate->context()->wasm_memory_sym(), isolate); | 884 i::Handle<i::Symbol> symbol(isolate->context()->wasm_memory_sym(), isolate); |
952 return HasBrand(value, symbol); | 885 return HasBrand(value, symbol); |
953 } | 886 } |
954 | 887 |
955 bool WasmJs::IsWasmTableObject(Isolate* isolate, Handle<Object> value) { | 888 bool WasmJs::IsWasmTableObject(Isolate* isolate, Handle<Object> value) { |
956 i::Handle<i::Symbol> symbol(isolate->context()->wasm_table_sym(), isolate); | 889 i::Handle<i::Symbol> symbol(isolate->context()->wasm_table_sym(), isolate); |
957 return HasBrand(value, symbol); | 890 return HasBrand(value, symbol); |
958 } | 891 } |
959 } // namespace internal | 892 } // namespace internal |
960 } // namespace v8 | 893 } // namespace v8 |
OLD | NEW |