Commit 6a6f5de1 authored by Matthias Liedtke's avatar Matthias Liedtke Committed by V8 LUCI CQ

[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: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82691}
parent c08f7bf4
......@@ -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;
......
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.
// 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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment