diff --git a/src/wasm/wasm-js.cc b/src/wasm/wasm-js.cc index 9199c2f358..717601c8b5 100644 --- a/src/wasm/wasm-js.cc +++ b/src/wasm/wasm-js.cc @@ -2032,7 +2032,8 @@ Handle InstallConstructorFunc(Isolate* isolate, Handle object, const char* str, FunctionCallback func) { - return InstallFunc(isolate, object, str, func, 1, true, DONT_ENUM); + return InstallFunc(isolate, object, str, func, 1, true, DONT_ENUM, + SideEffectType::kHasNoSideEffect); } Handle GetterName(Isolate* isolate, Handle name) { @@ -2062,7 +2063,8 @@ void InstallGetterSetter(Isolate* isolate, Handle object, FunctionCallback setter) { Handle name = v8_str(isolate, str); Handle getter_func = - CreateFunc(isolate, GetterName(isolate, name), getter, false); + CreateFunc(isolate, GetterName(isolate, name), getter, false, + SideEffectType::kHasNoSideEffect); Handle setter_func = CreateFunc(isolate, SetterName(isolate, name), setter, false); setter_func->shared().set_length(1); @@ -2146,11 +2148,12 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) { JSFunction::SetInitialMap(isolate, module_constructor, module_map, module_proto); InstallFunc(isolate, module_constructor, "imports", WebAssemblyModuleImports, - 1); + 1, false, NONE, SideEffectType::kHasNoSideEffect); InstallFunc(isolate, module_constructor, "exports", WebAssemblyModuleExports, - 1); + 1, false, NONE, SideEffectType::kHasNoSideEffect); InstallFunc(isolate, module_constructor, "customSections", - WebAssemblyModuleCustomSections, 2); + WebAssemblyModuleCustomSections, 2, false, NONE, + SideEffectType::kHasNoSideEffect); JSObject::AddProperty(isolate, module_proto, factory->to_string_tag_symbol(), v8_str(isolate, "WebAssembly.Module"), ro_attributes); @@ -2190,7 +2193,8 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) { JSFunction::SetInitialMap(isolate, table_constructor, table_map, table_proto); InstallGetter(isolate, table_proto, "length", WebAssemblyTableGetLength); InstallFunc(isolate, table_proto, "grow", WebAssemblyTableGrow, 1); - InstallFunc(isolate, table_proto, "get", WebAssemblyTableGet, 1); + InstallFunc(isolate, table_proto, "get", WebAssemblyTableGet, 1, false, NONE, + SideEffectType::kHasNoSideEffect); InstallFunc(isolate, table_proto, "set", WebAssemblyTableSet, 2); if (enabled_features.has_type_reflection()) { InstallFunc(isolate, table_constructor, "type", WebAssemblyTableType, 1); @@ -2230,7 +2234,8 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) { i::WASM_GLOBAL_OBJECT_TYPE, WasmGlobalObject::kHeaderSize); JSFunction::SetInitialMap(isolate, global_constructor, global_map, global_proto); - InstallFunc(isolate, global_proto, "valueOf", WebAssemblyGlobalValueOf, 0); + InstallFunc(isolate, global_proto, "valueOf", WebAssemblyGlobalValueOf, 0, + false, NONE, SideEffectType::kHasNoSideEffect); InstallGetterSetter(isolate, global_proto, "value", WebAssemblyGlobalGetValue, WebAssemblyGlobalSetValue); if (enabled_features.has_type_reflection()) { diff --git a/test/inspector/debugger/wasm-side-effect-free-debug-evaluate-expected.txt b/test/inspector/debugger/wasm-side-effect-free-debug-evaluate-expected.txt new file mode 100644 index 0000000000..e538b7584b --- /dev/null +++ b/test/inspector/debugger/wasm-side-effect-free-debug-evaluate-expected.txt @@ -0,0 +1,33 @@ +Test side-effect-free evaluation of WebAssembly APIs + +Running test: testWebAssemblyGlobal +someGlobalGlobal.value: ok +someGlobalGlobal.valueOf(): ok +new WebAssembly.Global({value: "f32", mutable: true}, 3.14): ok +new WebAssembly.Global({value: "f32", mutable: false}, 3.14): ok +new WebAssembly.Global({value: "f32", mutable: true}, 3.14).value: ok +new WebAssembly.Global({value: "f32", mutable: true}, 3.14).valueOf(): ok + +Running test: testWebAssemblyInstance +someGlobalInstance.exports: ok +new WebAssembly.Instance(someGlobalModule): ok +new WebAssembly.Instance(someGlobalModule).exports: ok + +Running test: testWebAssemblyMemory +someGlobalMemory.buffer: ok +new WebAssembly.Memory({initial: 1}): ok +new WebAssembly.Memory({initial: 1}).buffer: ok + +Running test: testWebAssemblyModule +WebAssembly.Module.customSections(someGlobalModule, ".debug_info"): ok +WebAssembly.Module.exports(someGlobalModule): ok +WebAssembly.Module.imports(someGlobalModule): ok +new WebAssembly.Module(EMPTY_WASM_MODULE_BYTES): ok +WebAssembly.Module.customSections(new WebAssembly.Module(EMPTY_WASM_MODULE_BYTES), ".debug_info"): ok +WebAssembly.Module.exports(new WebAssembly.Module(EMPTY_WASM_MODULE_BYTES)): ok +WebAssembly.Module.imports(new WebAssembly.Module(EMPTY_WASM_MODULE_BYTES)): ok + +Running test: testWebAssemblyTable +someGlobalTable.get(0): ok +new WebAssembly.Table({element: "anyfunc", initial: 1}): ok +new WebAssembly.Table({element: "anyfunc", initial: 1}).get(0): ok diff --git a/test/inspector/debugger/wasm-side-effect-free-debug-evaluate.js b/test/inspector/debugger/wasm-side-effect-free-debug-evaluate.js new file mode 100644 index 0000000000..37aca4701c --- /dev/null +++ b/test/inspector/debugger/wasm-side-effect-free-debug-evaluate.js @@ -0,0 +1,72 @@ +// Copyright 2021 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. + +utils.load('test/inspector/wasm-inspector-test.js'); + +let {session, contextGroup, Protocol} = + InspectorTest.start('Test side-effect-free evaluation of WebAssembly APIs'); + +contextGroup.addScript(` +var EMPTY_WASM_MODULE_BYTES = new Uint8Array([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]); +var someGlobalGlobal = new WebAssembly.Global({value: "i64"}, 42n); +var someGlobalMemory = new WebAssembly.Memory({initial: 1}); +var someGlobalModule = new WebAssembly.Module(EMPTY_WASM_MODULE_BYTES); +var someGlobalInstance = new WebAssembly.Instance(someGlobalModule); +var someGlobalTable = new WebAssembly.Table({element: 'anyfunc', initial: 1}); +someGlobalTable.set(0, x => x); +`, 0, 0, 'foo.js'); + +async function check(expression) { + const {result:{exceptionDetails}} = await Protocol.Runtime.evaluate({expression, throwOnSideEffect: true}); + InspectorTest.log(`${expression}: ${exceptionDetails ? 'throws' : 'ok'}`); +} + +InspectorTest.runAsyncTestSuite([ + async function testWebAssemblyGlobal() { + await Protocol.Runtime.enable(); + await check('someGlobalGlobal.value'); + await check('someGlobalGlobal.valueOf()'); + await check('new WebAssembly.Global({value: "f32", mutable: true}, 3.14)'); + await check('new WebAssembly.Global({value: "f32", mutable: false}, 3.14)'); + await check('new WebAssembly.Global({value: "f32", mutable: true}, 3.14).value'); + await check('new WebAssembly.Global({value: "f32", mutable: true}, 3.14).valueOf()'); + await Protocol.Runtime.disable(); + }, + + async function testWebAssemblyInstance() { + await Protocol.Runtime.enable(); + await check('someGlobalInstance.exports'); + await check('new WebAssembly.Instance(someGlobalModule)'); + await check('new WebAssembly.Instance(someGlobalModule).exports'); + await Protocol.Runtime.disable(); + }, + + async function testWebAssemblyMemory() { + await Protocol.Runtime.enable(); + await check('someGlobalMemory.buffer'); + await check('new WebAssembly.Memory({initial: 1})'); + await check('new WebAssembly.Memory({initial: 1}).buffer'); + await Protocol.Runtime.disable(); + }, + + async function testWebAssemblyModule() { + await Protocol.Runtime.enable(); + await check('WebAssembly.Module.customSections(someGlobalModule, ".debug_info")'); + await check('WebAssembly.Module.exports(someGlobalModule)'); + await check('WebAssembly.Module.imports(someGlobalModule)'); + await check('new WebAssembly.Module(EMPTY_WASM_MODULE_BYTES)'); + await check('WebAssembly.Module.customSections(new WebAssembly.Module(EMPTY_WASM_MODULE_BYTES), ".debug_info")'); + await check('WebAssembly.Module.exports(new WebAssembly.Module(EMPTY_WASM_MODULE_BYTES))'); + await check('WebAssembly.Module.imports(new WebAssembly.Module(EMPTY_WASM_MODULE_BYTES))'); + await Protocol.Runtime.disable(); + }, + + async function testWebAssemblyTable() { + await Protocol.Runtime.enable(); + await check('someGlobalTable.get(0)'); + await check('new WebAssembly.Table({element: "anyfunc", initial: 1})'); + await check('new WebAssembly.Table({element: "anyfunc", initial: 1}).get(0)'); + await Protocol.Runtime.disable(); + } +]);