[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 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<FixedArray> data = isolate->factory()->NewFixedArray(kLength);
|
||||
data->set(kObjectIndex, *value.to_ref());
|
||||
data->set(kObjectIndex, *value);
|
||||
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));
|
||||
return NamedDebugProxy::Create(isolate, data);
|
||||
}
|
||||
@ -820,14 +820,14 @@ struct ArrayProxy : IndexedDebugProxy<ArrayProxy, kArrayProxy, FixedArray> {
|
||||
static const int kModuleIndex = 1;
|
||||
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<FixedArray> data = isolate->factory()->NewFixedArray(kLength);
|
||||
data->set(kObjectIndex, *value.to_ref());
|
||||
data->set(kObjectIndex, *value);
|
||||
data->set(kModuleIndex, *module);
|
||||
Handle<JSObject> proxy = IndexedDebugProxy::Create(
|
||||
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);
|
||||
Object::SetProperty(isolate, proxy, isolate->factory()->length_string(),
|
||||
length_obj, StoreOrigin::kNamed,
|
||||
@ -908,9 +908,11 @@ Handle<WasmValueObject> WasmValueObject::New(
|
||||
t = GetRefTypeName(isolate, value.type(), module_object->native_module());
|
||||
Handle<Object> ref = value.to_ref();
|
||||
if (ref->IsWasmStruct()) {
|
||||
v = StructProxy::Create(isolate, value, module_object);
|
||||
v = StructProxy::Create(isolate, Handle<WasmStruct>::cast(ref),
|
||||
module_object);
|
||||
} 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()) {
|
||||
v = handle(Handle<WasmInternalFunction>::cast(ref)->external(),
|
||||
isolate);
|
||||
|
@ -1561,7 +1561,7 @@ Handle<Foreign> Factory::NewForeign(Address addr,
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
Handle<WasmTypeInfo> Factory::NewWasmTypeInfo(
|
||||
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:
|
||||
// (1) They are referenced by Maps, which are assumed to be long-lived,
|
||||
// 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.set_instance(*instance);
|
||||
result.set_type_index(type_index);
|
||||
return handle(result, isolate());
|
||||
}
|
||||
|
||||
|
@ -623,7 +623,8 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
Handle<WasmTypeInfo> NewWasmTypeInfo(Address type_address,
|
||||
Handle<Map> opt_parent,
|
||||
int instance_size_bytes,
|
||||
Handle<WasmInstanceObject> instance);
|
||||
Handle<WasmInstanceObject> instance,
|
||||
uint32_t type_index);
|
||||
Handle<WasmInternalFunction> NewWasmInternalFunction(Address opt_call_target,
|
||||
Handle<HeapObject> ref,
|
||||
Handle<Map> rtt);
|
||||
|
@ -118,7 +118,7 @@ Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
|
||||
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
|
||||
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
|
||||
reinterpret_cast<Address>(type), opt_rtt_parent, real_instance_size,
|
||||
instance);
|
||||
instance, struct_index);
|
||||
Handle<Map> map = isolate->factory()->NewMap(
|
||||
instance_type, map_instance_size, elements_kind, inobject_properties);
|
||||
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;
|
||||
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
|
||||
reinterpret_cast<Address>(type), opt_rtt_parent, cached_instance_size,
|
||||
instance);
|
||||
instance, array_index);
|
||||
// TODO(ishell): get canonical descriptor array for WasmArrays from roots.
|
||||
Handle<DescriptorArray> descriptors =
|
||||
CreateArrayDescriptorArray(isolate, type);
|
||||
@ -165,8 +165,9 @@ Handle<Map> CreateFuncRefMap(Isolate* isolate, const WasmModule* module,
|
||||
.instance_size();
|
||||
const InstanceType instance_type = WASM_INTERNAL_FUNCTION_TYPE;
|
||||
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
|
||||
constexpr uint32_t kNoIndex = ~0u;
|
||||
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(
|
||||
instance_type, instance_size, elements_kind, inobject_properties);
|
||||
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<...>.
|
||||
// Details: https://bit.ly/2UxD4hW
|
||||
native_type: ExternalPointer;
|
||||
type_index: uint32;
|
||||
@if(TAGGED_SIZE_8_BYTES) optional_padding: uint32;
|
||||
@ifnot(TAGGED_SIZE_8_BYTES) optional_padding: void;
|
||||
instance: WasmInstanceObject;
|
||||
const supertypes_length: Smi;
|
||||
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 {
|
||||
await test();
|
||||
} catch (e) {
|
||||
utils.print(e.stack);
|
||||
utils.print(e.stack || "Caught error without stack trace!");
|
||||
}
|
||||
}
|
||||
InspectorTest.completeTest();
|
||||
|
@ -66,7 +66,7 @@ WasmInspectorTest.getWasmValue = async function(value) {
|
||||
};
|
||||
|
||||
function printIfFailure(message) {
|
||||
if (!message.result) {
|
||||
if (!message.result || message.result.exceptionDetails) {
|
||||
InspectorTest.logMessage(message);
|
||||
}
|
||||
return message;
|
||||
|
Loading…
Reference in New Issue
Block a user