[wasm-gc][debugger] Fix struct_index retrieval for generic references
The StructProxy::Create() used the static type information to inspect the value. However, for abstract references like anyref, dataref, ... this does not contain the required struct_index. To fix this the WasmTypeInfo stores the type_index for structs and arrays. Bug: v8:7748 Change-Id: I6e1af054711ada5e12c08949c125007e8185e486 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3850296 Commit-Queue: Matthias Liedtke <mliedtke@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/main@{#82691}
This commit is contained in:
parent
c08f7bf491
commit
6a6f5de1a7
@ -778,12 +778,12 @@ struct StructProxy : NamedDebugProxy<StructProxy, kStructProxy, FixedArray> {
|
|||||||
static const int kTypeIndexIndex = 2;
|
static const int kTypeIndexIndex = 2;
|
||||||
static const int kLength = 3;
|
static const int kLength = 3;
|
||||||
|
|
||||||
static Handle<JSObject> Create(Isolate* isolate, const wasm::WasmValue& value,
|
static Handle<JSObject> Create(Isolate* isolate, Handle<WasmStruct> value,
|
||||||
Handle<WasmModuleObject> module) {
|
Handle<WasmModuleObject> module) {
|
||||||
Handle<FixedArray> data = isolate->factory()->NewFixedArray(kLength);
|
Handle<FixedArray> data = isolate->factory()->NewFixedArray(kLength);
|
||||||
data->set(kObjectIndex, *value.to_ref());
|
data->set(kObjectIndex, *value);
|
||||||
data->set(kModuleIndex, *module);
|
data->set(kModuleIndex, *module);
|
||||||
int struct_type_index = value.type().ref_index();
|
int struct_type_index = value->map().wasm_type_info().type_index();
|
||||||
data->set(kTypeIndexIndex, Smi::FromInt(struct_type_index));
|
data->set(kTypeIndexIndex, Smi::FromInt(struct_type_index));
|
||||||
return NamedDebugProxy::Create(isolate, data);
|
return NamedDebugProxy::Create(isolate, data);
|
||||||
}
|
}
|
||||||
@ -820,14 +820,14 @@ struct ArrayProxy : IndexedDebugProxy<ArrayProxy, kArrayProxy, FixedArray> {
|
|||||||
static const int kModuleIndex = 1;
|
static const int kModuleIndex = 1;
|
||||||
static const int kLength = 2;
|
static const int kLength = 2;
|
||||||
|
|
||||||
static Handle<JSObject> Create(Isolate* isolate, const wasm::WasmValue& value,
|
static Handle<JSObject> Create(Isolate* isolate, Handle<WasmArray> value,
|
||||||
Handle<WasmModuleObject> module) {
|
Handle<WasmModuleObject> module) {
|
||||||
Handle<FixedArray> data = isolate->factory()->NewFixedArray(kLength);
|
Handle<FixedArray> data = isolate->factory()->NewFixedArray(kLength);
|
||||||
data->set(kObjectIndex, *value.to_ref());
|
data->set(kObjectIndex, *value);
|
||||||
data->set(kModuleIndex, *module);
|
data->set(kModuleIndex, *module);
|
||||||
Handle<JSObject> proxy = IndexedDebugProxy::Create(
|
Handle<JSObject> proxy = IndexedDebugProxy::Create(
|
||||||
isolate, data, false /* leave map extensible */);
|
isolate, data, false /* leave map extensible */);
|
||||||
uint32_t length = WasmArray::cast(*value.to_ref()).length();
|
uint32_t length = value->length();
|
||||||
Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
|
Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
|
||||||
Object::SetProperty(isolate, proxy, isolate->factory()->length_string(),
|
Object::SetProperty(isolate, proxy, isolate->factory()->length_string(),
|
||||||
length_obj, StoreOrigin::kNamed,
|
length_obj, StoreOrigin::kNamed,
|
||||||
@ -908,9 +908,11 @@ Handle<WasmValueObject> WasmValueObject::New(
|
|||||||
t = GetRefTypeName(isolate, value.type(), module_object->native_module());
|
t = GetRefTypeName(isolate, value.type(), module_object->native_module());
|
||||||
Handle<Object> ref = value.to_ref();
|
Handle<Object> ref = value.to_ref();
|
||||||
if (ref->IsWasmStruct()) {
|
if (ref->IsWasmStruct()) {
|
||||||
v = StructProxy::Create(isolate, value, module_object);
|
v = StructProxy::Create(isolate, Handle<WasmStruct>::cast(ref),
|
||||||
|
module_object);
|
||||||
} else if (ref->IsWasmArray()) {
|
} else if (ref->IsWasmArray()) {
|
||||||
v = ArrayProxy::Create(isolate, value, module_object);
|
v = ArrayProxy::Create(isolate, Handle<WasmArray>::cast(ref),
|
||||||
|
module_object);
|
||||||
} else if (ref->IsWasmInternalFunction()) {
|
} else if (ref->IsWasmInternalFunction()) {
|
||||||
v = handle(Handle<WasmInternalFunction>::cast(ref)->external(),
|
v = handle(Handle<WasmInternalFunction>::cast(ref)->external(),
|
||||||
isolate);
|
isolate);
|
||||||
|
@ -1561,7 +1561,7 @@ Handle<Foreign> Factory::NewForeign(Address addr,
|
|||||||
#if V8_ENABLE_WEBASSEMBLY
|
#if V8_ENABLE_WEBASSEMBLY
|
||||||
Handle<WasmTypeInfo> Factory::NewWasmTypeInfo(
|
Handle<WasmTypeInfo> Factory::NewWasmTypeInfo(
|
||||||
Address type_address, Handle<Map> opt_parent, int instance_size_bytes,
|
Address type_address, Handle<Map> opt_parent, int instance_size_bytes,
|
||||||
Handle<WasmInstanceObject> instance) {
|
Handle<WasmInstanceObject> instance, uint32_t type_index) {
|
||||||
// We pretenure WasmTypeInfo objects for two reasons:
|
// We pretenure WasmTypeInfo objects for two reasons:
|
||||||
// (1) They are referenced by Maps, which are assumed to be long-lived,
|
// (1) They are referenced by Maps, which are assumed to be long-lived,
|
||||||
// so pretenuring the WTI is a bit more efficient.
|
// so pretenuring the WTI is a bit more efficient.
|
||||||
@ -1600,6 +1600,7 @@ Handle<WasmTypeInfo> Factory::NewWasmTypeInfo(
|
|||||||
}
|
}
|
||||||
result.init_native_type(isolate(), type_address);
|
result.init_native_type(isolate(), type_address);
|
||||||
result.set_instance(*instance);
|
result.set_instance(*instance);
|
||||||
|
result.set_type_index(type_index);
|
||||||
return handle(result, isolate());
|
return handle(result, isolate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,7 +623,8 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
|||||||
Handle<WasmTypeInfo> NewWasmTypeInfo(Address type_address,
|
Handle<WasmTypeInfo> NewWasmTypeInfo(Address type_address,
|
||||||
Handle<Map> opt_parent,
|
Handle<Map> opt_parent,
|
||||||
int instance_size_bytes,
|
int instance_size_bytes,
|
||||||
Handle<WasmInstanceObject> instance);
|
Handle<WasmInstanceObject> instance,
|
||||||
|
uint32_t type_index);
|
||||||
Handle<WasmInternalFunction> NewWasmInternalFunction(Address opt_call_target,
|
Handle<WasmInternalFunction> NewWasmInternalFunction(Address opt_call_target,
|
||||||
Handle<HeapObject> ref,
|
Handle<HeapObject> ref,
|
||||||
Handle<Map> rtt);
|
Handle<Map> rtt);
|
||||||
|
@ -118,7 +118,7 @@ Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
|
|||||||
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
|
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
|
||||||
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
|
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
|
||||||
reinterpret_cast<Address>(type), opt_rtt_parent, real_instance_size,
|
reinterpret_cast<Address>(type), opt_rtt_parent, real_instance_size,
|
||||||
instance);
|
instance, struct_index);
|
||||||
Handle<Map> map = isolate->factory()->NewMap(
|
Handle<Map> map = isolate->factory()->NewMap(
|
||||||
instance_type, map_instance_size, elements_kind, inobject_properties);
|
instance_type, map_instance_size, elements_kind, inobject_properties);
|
||||||
map->set_wasm_type_info(*type_info);
|
map->set_wasm_type_info(*type_info);
|
||||||
@ -141,7 +141,7 @@ Handle<Map> CreateArrayMap(Isolate* isolate, const WasmModule* module,
|
|||||||
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
|
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
|
||||||
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
|
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
|
||||||
reinterpret_cast<Address>(type), opt_rtt_parent, cached_instance_size,
|
reinterpret_cast<Address>(type), opt_rtt_parent, cached_instance_size,
|
||||||
instance);
|
instance, array_index);
|
||||||
// TODO(ishell): get canonical descriptor array for WasmArrays from roots.
|
// TODO(ishell): get canonical descriptor array for WasmArrays from roots.
|
||||||
Handle<DescriptorArray> descriptors =
|
Handle<DescriptorArray> descriptors =
|
||||||
CreateArrayDescriptorArray(isolate, type);
|
CreateArrayDescriptorArray(isolate, type);
|
||||||
@ -165,8 +165,9 @@ Handle<Map> CreateFuncRefMap(Isolate* isolate, const WasmModule* module,
|
|||||||
.instance_size();
|
.instance_size();
|
||||||
const InstanceType instance_type = WASM_INTERNAL_FUNCTION_TYPE;
|
const InstanceType instance_type = WASM_INTERNAL_FUNCTION_TYPE;
|
||||||
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
|
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
|
||||||
|
constexpr uint32_t kNoIndex = ~0u;
|
||||||
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
|
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
|
||||||
kNullAddress, opt_rtt_parent, instance_size, instance);
|
kNullAddress, opt_rtt_parent, instance_size, instance, kNoIndex);
|
||||||
Handle<Map> map = isolate->factory()->NewMap(
|
Handle<Map> map = isolate->factory()->NewMap(
|
||||||
instance_type, instance_size, elements_kind, inobject_properties);
|
instance_type, instance_size, elements_kind, inobject_properties);
|
||||||
map->set_wasm_type_info(*type_info);
|
map->set_wasm_type_info(*type_info);
|
||||||
|
@ -189,6 +189,9 @@ extern class WasmTypeInfo extends HeapObject {
|
|||||||
// and introduce a new link from here to just that zone using a Managed<...>.
|
// and introduce a new link from here to just that zone using a Managed<...>.
|
||||||
// Details: https://bit.ly/2UxD4hW
|
// Details: https://bit.ly/2UxD4hW
|
||||||
native_type: ExternalPointer;
|
native_type: ExternalPointer;
|
||||||
|
type_index: uint32;
|
||||||
|
@if(TAGGED_SIZE_8_BYTES) optional_padding: uint32;
|
||||||
|
@ifnot(TAGGED_SIZE_8_BYTES) optional_padding: void;
|
||||||
instance: WasmInstanceObject;
|
instance: WasmInstanceObject;
|
||||||
const supertypes_length: Smi;
|
const supertypes_length: Smi;
|
||||||
supertypes[supertypes_length]: Object;
|
supertypes[supertypes_length]: Object;
|
||||||
|
31
test/inspector/debugger/wasm-gc-anyref-expected.txt
Normal file
31
test/inspector/debugger/wasm-gc-anyref-expected.txt
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
Test inspection of Wasm anyref objects
|
||||||
|
|
||||||
|
Running test: test
|
||||||
|
Calling instantiate function.
|
||||||
|
Waiting for wasm script to be parsed.
|
||||||
|
Got wasm script!
|
||||||
|
Setting breakpoint
|
||||||
|
Module instantiated.
|
||||||
|
{
|
||||||
|
columnNumber : 61
|
||||||
|
lineNumber : 0
|
||||||
|
scriptId : <scriptId>
|
||||||
|
}
|
||||||
|
Paused:
|
||||||
|
Script wasm://wasm/f6eebe1a byte offset 61: Wasm opcode 0x01 (kExprNop)
|
||||||
|
Scope:
|
||||||
|
at $main (0:61):
|
||||||
|
- scope (wasm-expression-stack):
|
||||||
|
stack:
|
||||||
|
- scope (local):
|
||||||
|
$anyref_local: Struct (anyref)
|
||||||
|
$anyref_local2: Array (anyref)
|
||||||
|
- scope (module):
|
||||||
|
instance: exports: "main" (Function)
|
||||||
|
module: Module
|
||||||
|
functions: "$main": (Function)
|
||||||
|
at (anonymous) (0:17):
|
||||||
|
- scope (global):
|
||||||
|
-- skipped globals
|
||||||
|
|
||||||
|
exports.main returned. Test finished.
|
107
test/inspector/debugger/wasm-gc-anyref.js
Normal file
107
test/inspector/debugger/wasm-gc-anyref.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// Copyright 2022 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.
|
||||||
|
|
||||||
|
// Flags: --experimental-wasm-gc
|
||||||
|
|
||||||
|
utils.load('test/inspector/wasm-inspector-test.js');
|
||||||
|
|
||||||
|
let {session, contextGroup, Protocol} = InspectorTest.start(
|
||||||
|
'Test inspection of Wasm anyref objects');
|
||||||
|
session.setupScriptMap();
|
||||||
|
Protocol.Runtime.enable();
|
||||||
|
Protocol.Debugger.enable();
|
||||||
|
Protocol.Debugger.onPaused(printPauseLocationsAndContinue);
|
||||||
|
|
||||||
|
let breakpointLocation = -1;
|
||||||
|
|
||||||
|
InspectorTest.runAsyncTestSuite([
|
||||||
|
async function test() {
|
||||||
|
instantiateWasm();
|
||||||
|
let scriptIds = await waitForWasmScripts();
|
||||||
|
|
||||||
|
// Set a breakpoint.
|
||||||
|
InspectorTest.log('Setting breakpoint');
|
||||||
|
let breakpoint = await Protocol.Debugger.setBreakpoint(
|
||||||
|
{'location': {'scriptId': scriptIds[0],
|
||||||
|
'lineNumber': 0,
|
||||||
|
'columnNumber': breakpointLocation}});
|
||||||
|
printIfFailure(breakpoint);
|
||||||
|
InspectorTest.logMessage(breakpoint.result.actualLocation);
|
||||||
|
|
||||||
|
// Now run the wasm code.
|
||||||
|
await WasmInspectorTest.evalWithUrl('instance.exports.main()', 'runWasm');
|
||||||
|
InspectorTest.log('exports.main returned. Test finished.');
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
async function printPauseLocationsAndContinue(msg) {
|
||||||
|
let loc = msg.params.callFrames[0].location;
|
||||||
|
InspectorTest.log('Paused:');
|
||||||
|
await session.logSourceLocation(loc);
|
||||||
|
InspectorTest.log('Scope:');
|
||||||
|
for (var frame of msg.params.callFrames) {
|
||||||
|
var isWasmFrame = /^wasm/.test(frame.url);
|
||||||
|
var functionName = frame.functionName || '(anonymous)';
|
||||||
|
var lineNumber = frame.location.lineNumber;
|
||||||
|
var columnNumber = frame.location.columnNumber;
|
||||||
|
InspectorTest.log(`at ${functionName} (${lineNumber}:${columnNumber}):`);
|
||||||
|
for (var scope of frame.scopeChain) {
|
||||||
|
InspectorTest.logObject(' - scope (' + scope.type + '):');
|
||||||
|
if (!isWasmFrame && scope.type == 'global') {
|
||||||
|
// Skip global scope for non wasm-functions.
|
||||||
|
InspectorTest.logObject(' -- skipped globals');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var properties = await Protocol.Runtime.getProperties(
|
||||||
|
{'objectId': scope.object.objectId});
|
||||||
|
await WasmInspectorTest.dumpScopeProperties(properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InspectorTest.log();
|
||||||
|
Protocol.Debugger.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function instantiateWasm() {
|
||||||
|
var builder = new WasmModuleBuilder();
|
||||||
|
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
|
||||||
|
let array_type = builder.addArray(kWasmI32);
|
||||||
|
|
||||||
|
let body = [
|
||||||
|
// Set local anyref_local to new struct.
|
||||||
|
...wasmI32Const(12),
|
||||||
|
kGCPrefix, kExprStructNew, struct_type,
|
||||||
|
kExprLocalSet, 0,
|
||||||
|
// Set local anyref_local2 to new array.
|
||||||
|
...wasmI32Const(21),
|
||||||
|
kGCPrefix, kExprArrayNewFixedStatic, array_type, 1,
|
||||||
|
kExprLocalSet, 1,
|
||||||
|
kExprNop,
|
||||||
|
];
|
||||||
|
let main = builder.addFunction('main', kSig_v_v)
|
||||||
|
.addLocals(kWasmAnyRef, 1, ['anyref_local'])
|
||||||
|
.addLocals(kWasmAnyRef, 1, ['anyref_local2'])
|
||||||
|
.addBody(body)
|
||||||
|
.exportFunc();
|
||||||
|
|
||||||
|
var module_bytes = builder.toArray();
|
||||||
|
breakpointLocation = main.body_offset + body.length - 1;
|
||||||
|
|
||||||
|
InspectorTest.log('Calling instantiate function.');
|
||||||
|
await WasmInspectorTest.instantiate(module_bytes);
|
||||||
|
InspectorTest.log('Module instantiated.');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function waitForWasmScripts() {
|
||||||
|
InspectorTest.log('Waiting for wasm script to be parsed.');
|
||||||
|
let wasm_script_ids = [];
|
||||||
|
while (wasm_script_ids.length < 1) {
|
||||||
|
let script_msg = await Protocol.Debugger.onceScriptParsed();
|
||||||
|
let url = script_msg.params.url;
|
||||||
|
if (url.startsWith('wasm://')) {
|
||||||
|
InspectorTest.log('Got wasm script!');
|
||||||
|
wasm_script_ids.push(script_msg.params.scriptId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wasm_script_ids;
|
||||||
|
}
|
@ -479,7 +479,7 @@ InspectorTest.runAsyncTestSuite = async function(testSuite) {
|
|||||||
try {
|
try {
|
||||||
await test();
|
await test();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
utils.print(e.stack);
|
utils.print(e.stack || "Caught error without stack trace!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InspectorTest.completeTest();
|
InspectorTest.completeTest();
|
||||||
|
@ -66,7 +66,7 @@ WasmInspectorTest.getWasmValue = async function(value) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function printIfFailure(message) {
|
function printIfFailure(message) {
|
||||||
if (!message.result) {
|
if (!message.result || message.result.exceptionDetails) {
|
||||||
InspectorTest.logMessage(message);
|
InspectorTest.logMessage(message);
|
||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
|
Loading…
Reference in New Issue
Block a user