[wasm] Fix inspection of imported wasm tables created in JS
Fixed: chromium:1365101 Change-Id: Ie6f5fa08416348e827de9a389af5d63eba118ceb Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3909810 Reviewed-by: Philip Pfaffe <pfaffe@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Matthias Liedtke <mliedtke@chromium.org> Cr-Commit-Position: refs/heads/main@{#83385}
This commit is contained in:
parent
98c6c367b5
commit
3665fbaaf5
@ -729,6 +729,18 @@ Handle<String> GetRefTypeName(Isolate* isolate, wasm::ValueType type,
|
||||
return ToInternalString(name, isolate);
|
||||
}
|
||||
|
||||
// Returns the type name for the given value. Uses the module object for
|
||||
// providing user-defined type names if available, otherwise falls back
|
||||
// to numbers for indexed types.
|
||||
Handle<String> GetRefTypeName(Isolate* isolate, wasm::ValueType type,
|
||||
Handle<WasmModuleObject> module_object) {
|
||||
if (!module_object.is_null()) {
|
||||
return GetRefTypeName(isolate, type, module_object->native_module());
|
||||
}
|
||||
std::string name = type.name();
|
||||
return isolate->factory()->InternalizeString({name.data(), name.length()});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
@ -905,38 +917,49 @@ Handle<WasmValueObject> WasmValueObject::New(
|
||||
}
|
||||
case wasm::kRefNull:
|
||||
case wasm::kRef: {
|
||||
t = GetRefTypeName(isolate, value.type(), module_object->native_module());
|
||||
Handle<Object> ref = value.to_ref();
|
||||
if (ref->IsWasmStruct()) {
|
||||
WasmTypeInfo type_info = ref->GetHeapObject().map().wasm_type_info();
|
||||
wasm::ValueType type = wasm::ValueType::FromIndex(
|
||||
wasm::ValueKind::kRef, type_info.type_index());
|
||||
t = GetRefTypeName(
|
||||
isolate, type,
|
||||
type_info.instance().module_object().native_module());
|
||||
v = StructProxy::Create(isolate, Handle<WasmStruct>::cast(ref),
|
||||
module_object);
|
||||
Handle<WasmModuleObject> module(type_info.instance().module_object(),
|
||||
isolate);
|
||||
t = GetRefTypeName(isolate, type, module->native_module());
|
||||
v = StructProxy::Create(isolate, Handle<WasmStruct>::cast(ref), module);
|
||||
} else if (ref->IsWasmArray()) {
|
||||
WasmTypeInfo type_info = ref->GetHeapObject().map().wasm_type_info();
|
||||
wasm::ValueType type = wasm::ValueType::FromIndex(
|
||||
wasm::ValueKind::kRef, type_info.type_index());
|
||||
t = GetRefTypeName(
|
||||
isolate, type,
|
||||
type_info.instance().module_object().native_module());
|
||||
v = ArrayProxy::Create(isolate, Handle<WasmArray>::cast(ref),
|
||||
module_object);
|
||||
Handle<WasmModuleObject> module(type_info.instance().module_object(),
|
||||
isolate);
|
||||
t = GetRefTypeName(isolate, type, module->native_module());
|
||||
v = ArrayProxy::Create(isolate, Handle<WasmArray>::cast(ref), module);
|
||||
} else if (ref->IsWasmInternalFunction()) {
|
||||
v = handle(Handle<WasmInternalFunction>::cast(ref)->external(),
|
||||
isolate);
|
||||
auto internal_fct = Handle<WasmInternalFunction>::cast(ref);
|
||||
v = handle(internal_fct->external(), isolate);
|
||||
// If the module is not provided by the caller, retrieve it from the
|
||||
// instance object. If the function was created in JavaScript using
|
||||
// `new WebAssembly.Function(...)`, a module for name resolution is not
|
||||
// available.
|
||||
if (module_object.is_null() &&
|
||||
internal_fct->ref().IsWasmInstanceObject()) {
|
||||
module_object = handle(
|
||||
WasmInstanceObject::cast(internal_fct->ref()).module_object(),
|
||||
isolate);
|
||||
}
|
||||
t = GetRefTypeName(isolate, value.type(), module_object);
|
||||
} else if (ref->IsJSFunction() || ref->IsSmi() || ref->IsNull() ||
|
||||
ref->IsString() ||
|
||||
value.type().is_reference_to(wasm::HeapType::kExtern)) {
|
||||
value.type().is_reference_to(wasm::HeapType::kExtern) ||
|
||||
value.type().is_reference_to(wasm::HeapType::kAny)) {
|
||||
t = GetRefTypeName(isolate, value.type(), module_object);
|
||||
v = ref;
|
||||
} else {
|
||||
// Fail gracefully.
|
||||
base::EmbeddedVector<char, 64> error;
|
||||
int len = SNPrintF(error, "unimplemented object type: %d",
|
||||
HeapObject::cast(*ref).map().instance_type());
|
||||
t = GetRefTypeName(isolate, value.type(), module_object);
|
||||
v = isolate->factory()->InternalizeString(error.SubVector(0, len));
|
||||
}
|
||||
break;
|
||||
@ -1037,8 +1060,11 @@ Handle<ArrayList> AddWasmTableObjectInternalProperties(
|
||||
for (int i = 0; i < length; ++i) {
|
||||
Handle<Object> entry = WasmTableObject::Get(isolate, table, i);
|
||||
wasm::WasmValue wasm_value(entry, table->type());
|
||||
Handle<WasmModuleObject> module(
|
||||
WasmInstanceObject::cast(table->instance()).module_object(), isolate);
|
||||
Handle<WasmModuleObject> module;
|
||||
if (table->instance().IsWasmInstanceObject()) {
|
||||
module = Handle<WasmModuleObject>(
|
||||
WasmInstanceObject::cast(table->instance()).module_object(), isolate);
|
||||
}
|
||||
Handle<Object> debug_value =
|
||||
WasmValueObject::New(isolate, wasm_value, module);
|
||||
entries->set(i, *debug_value);
|
||||
|
@ -4,18 +4,18 @@ Running test: test
|
||||
Calling instantiate function.
|
||||
Waiting for wasm script to be parsed.
|
||||
Got wasm script!
|
||||
Setting breakpoint
|
||||
Module instantiated.
|
||||
Tables populated.
|
||||
Setting breakpoint
|
||||
{
|
||||
columnNumber : 138
|
||||
columnNumber : 246
|
||||
lineNumber : 0
|
||||
scriptId : <scriptId>
|
||||
}
|
||||
Table populated.
|
||||
Paused:
|
||||
Script wasm://wasm/0e116a66 byte offset 138: Wasm opcode 0x01 (kExprNop)
|
||||
Script wasm://wasm/739f5f0a byte offset 246: Wasm opcode 0x01 (kExprNop)
|
||||
Scope:
|
||||
at $main (0:138):
|
||||
at $main (0:246):
|
||||
- scope (wasm-expression-stack):
|
||||
stack:
|
||||
- scope (local):
|
||||
@ -24,11 +24,15 @@ at $main (0:138):
|
||||
$anyref_local_i31: null (anyref)
|
||||
$anyref_local_null: null (anyref)
|
||||
- scope (module):
|
||||
instance: exports: "exported_ref_table" (Table), "fill_ref_table" (Function), "main" (Function)
|
||||
instance: exports: "exported_ref_table" (Table), "exported_func_table" (Table), "fill_tables" (Function), "main" (Function)
|
||||
module: Module
|
||||
functions: "$fill_ref_table": (Function), "$main": (Function)
|
||||
functions: "$my_func": (Function), "$fill_tables": (Function), "$main": (Function)
|
||||
globals: "$global0": function $my_func() { [native code] } (funcref)
|
||||
tables:
|
||||
$import.any_table: 0: Array(2) (anyref), 1: Struct ((ref $type0)), 2: undefined (anyref)
|
||||
$import.func_table: 0: function () { [native code] } (funcref), 1: function $my_func() { [native code] } (funcref), 2: undefined (funcref)
|
||||
$exported_ref_table: 0: Struct ((ref $type0)), 1: Array ((ref $type1)), 2: undefined (anyref), 3: undefined (anyref)
|
||||
$exported_func_table: 0: function external_fct() { [native code] } (funcref), 1: function $my_func() { [native code] } (funcref), 2: undefined (funcref)
|
||||
at (anonymous) (0:17):
|
||||
- scope (global):
|
||||
-- skipped globals
|
||||
|
@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --experimental-wasm-gc
|
||||
// Flags: --experimental-wasm-gc --experimental-wasm-typed-funcref
|
||||
// Flags: --experimental-wasm-type-reflection
|
||||
|
||||
utils.load('test/inspector/wasm-inspector-test.js');
|
||||
|
||||
@ -17,8 +18,9 @@ let breakpointLocation = -1;
|
||||
|
||||
InspectorTest.runAsyncTestSuite([
|
||||
async function test() {
|
||||
instantiateWasm();
|
||||
let wasm_promise = instantiateWasm();
|
||||
let scriptIds = await waitForWasmScripts();
|
||||
await wasm_promise; // Make sure the instantiation is finished.
|
||||
|
||||
// Set a breakpoint.
|
||||
InspectorTest.log('Setting breakpoint');
|
||||
@ -66,10 +68,20 @@ async function instantiateWasm() {
|
||||
var builder = new WasmModuleBuilder();
|
||||
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
|
||||
let array_type = builder.addArray(kWasmI32);
|
||||
let imported_ref_table =
|
||||
builder.addImportedTable('import', 'any_table', 3, 3, kWasmAnyRef);
|
||||
let imported_func_table =
|
||||
builder.addImportedTable('import', 'func_table', 3, 3, kWasmFuncRef);
|
||||
let ref_table = builder.addTable(kWasmAnyRef, 4)
|
||||
.exportAs('exported_ref_table');
|
||||
let func_table = builder.addTable(kWasmFuncRef, 3)
|
||||
.exportAs('exported_func_table');
|
||||
|
||||
builder.addFunction('fill_ref_table', kSig_v_v)
|
||||
let func = builder.addFunction('my_func', kSig_v_v).addBody([kExprNop]);
|
||||
// Make the function "declared".
|
||||
builder.addGlobal(kWasmFuncRef, false, [kExprRefFunc, func.index]);
|
||||
|
||||
builder.addFunction('fill_tables', kSig_v_v)
|
||||
.addBody([
|
||||
...wasmI32Const(0), ...wasmI32Const(123),
|
||||
kGCPrefix, kExprStructNew, struct_type, kExprTableSet, ref_table.index,
|
||||
@ -83,6 +95,21 @@ async function instantiateWasm() {
|
||||
// apart.
|
||||
// ...wasmI32Const(2), ...wasmI32Const(30),
|
||||
// kGCPrefix, kExprI31New, kExprTableSet, ref_table.index,
|
||||
|
||||
// Fill imported any table.
|
||||
...wasmI32Const(1),
|
||||
...wasmI32Const(123), kGCPrefix, kExprStructNew, struct_type,
|
||||
kExprTableSet, imported_ref_table,
|
||||
|
||||
// Fill imported func table.
|
||||
...wasmI32Const(1),
|
||||
kExprRefFunc, func.index,
|
||||
kExprTableSet, imported_func_table,
|
||||
|
||||
// Fill func table.
|
||||
...wasmI32Const(1),
|
||||
kExprRefFunc, func.index,
|
||||
kExprTableSet, func_table.index,
|
||||
]).exportFunc();
|
||||
|
||||
let body = [
|
||||
@ -114,11 +141,32 @@ async function instantiateWasm() {
|
||||
breakpointLocation = main.body_offset + body.length - 1;
|
||||
|
||||
InspectorTest.log('Calling instantiate function.');
|
||||
await WasmInspectorTest.instantiate(module_bytes);
|
||||
let imports = `{'import' : {
|
||||
'any_table': (() => {
|
||||
let js_table =
|
||||
new WebAssembly.Table({element: 'anyref', initial: 3, maximum: 3});
|
||||
js_table.set(0, ['JavaScript', 'value']);
|
||||
return js_table;
|
||||
})(),
|
||||
'func_table': (() => {
|
||||
let func_table =
|
||||
new WebAssembly.Table({element: 'anyfunc', initial: 3, maximum: 3});
|
||||
func_table.set(0, new WebAssembly.Function(
|
||||
{parameters:['i32', 'i32'], results: ['i32']},
|
||||
function /*anonymous*/ (a, b) { return a * b; }));
|
||||
return func_table;
|
||||
})(),
|
||||
}}`;
|
||||
await WasmInspectorTest.instantiate(module_bytes, 'instance', imports);
|
||||
InspectorTest.log('Module instantiated.');
|
||||
await WasmInspectorTest.evalWithUrl(
|
||||
'instance.exports.fill_ref_table()', 'fill_ref_table');
|
||||
InspectorTest.log('Table populated.');
|
||||
'instance.exports.fill_tables();', 'fill_tables');
|
||||
await WasmInspectorTest.evalWithUrl(
|
||||
`instance.exports.exported_func_table.set(0, new WebAssembly.Function(
|
||||
{parameters:['i32', 'i32'], results: ['i32']},
|
||||
function external_fct(a, b) { return a * b; }))`,
|
||||
'add_func_to_table');
|
||||
InspectorTest.log('Tables populated.');
|
||||
}
|
||||
|
||||
async function waitForWasmScripts() {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "include/v8-object.h"
|
||||
#include "include/v8-template.h"
|
||||
#include "src/api/api.h"
|
||||
#include "src/objects/js-array-inl.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
#include "test/unittests/test-utils.h"
|
||||
@ -56,6 +57,27 @@ TEST_F(RuntimeTest, DoesNotReturnPrototypeWhenInacessible) {
|
||||
EXPECT_EQ(0u, result->Length());
|
||||
}
|
||||
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
TEST_F(RuntimeTest, WasmTableWithoutInstance) {
|
||||
uint32_t initial = 1u;
|
||||
bool has_maximum = false;
|
||||
uint32_t maximum = std::numeric_limits<uint32_t>::max();
|
||||
Handle<FixedArray> elements;
|
||||
Handle<WasmTableObject> table = WasmTableObject::New(
|
||||
i_isolate(), Handle<WasmInstanceObject>(), wasm::kWasmAnyRef, initial,
|
||||
has_maximum, maximum, &elements, i_isolate()->factory()->null_value());
|
||||
MaybeHandle<JSArray> result =
|
||||
Runtime::GetInternalProperties(i_isolate(), table);
|
||||
ASSERT_FALSE(result.is_null());
|
||||
// ["[[Prototype]]", <map>, "[[Entries]]", <entries>]
|
||||
ASSERT_EQ(4, result.ToHandleChecked()->elements().length());
|
||||
Handle<Object> entries =
|
||||
FixedArrayBase::GetElement(i_isolate(), result.ToHandleChecked(), 3)
|
||||
.ToHandleChecked();
|
||||
EXPECT_EQ(1, JSArray::cast(*entries).elements().length());
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user