Commit 987a7f4a authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[inspector] Send type as description for WasmValueObject.

Also block sending "type" as part of the ObjectPreview, but only send
the "value" property. The front-end will be updated to display
WasmValueObject's similar to what we do for wrapper objects (i.e.
StringWrapper and the like). The matching front-end change is still
pending.

Also refactor the WasmValueObject to have dedicated constructors for
the individual types (i32, i64, f32, f64, externref and v128). This
way we can just reuse the existing logic in descriptionForObject()
and we also don't need to store the "type" on the object itself (not
really performance sensitive, but fewer moving parts / things that
can go wrong).

This also addresses the crash in https://crbug.com/1166077#c16 since
the WasmValueObject instances now have a proper JSFunction in their
maps' constructor_or_backpointer slot and are thus able to locate
their creation context. Note that this doesn't generally address
https://crbug.com/1166077 itself, but only the WasmValueObject case.

Screenshot: https://imgur.com/kbd3bix.png
Bug: chromium:1170282, chromium:1071432
Bug: chromium:1159402, chromium:1166077
Change-Id: Iae649cad155efd774cfb1f4eea8cf406e413c03a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2692574Reviewed-by: 's avatarPhilip Pfaffe <pfaffe@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72736}
parent ed02eca6
...@@ -1119,22 +1119,6 @@ bool WasmValueObject::IsWasmValueObject(Local<Value> that) { ...@@ -1119,22 +1119,6 @@ bool WasmValueObject::IsWasmValueObject(Local<Value> that) {
return obj->IsWasmValueObject(); return obj->IsWasmValueObject();
} }
Local<String> WasmValueObject::type() const {
i::Handle<i::WasmValueObject> object =
i::Handle<i::WasmValueObject>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = object->GetIsolate();
i::Handle<i::String> type(object->type(), isolate);
return Utils::ToLocal(type);
}
Local<Value> WasmValueObject::value() const {
i::Handle<i::WasmValueObject> object =
i::Handle<i::WasmValueObject>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = object->GetIsolate();
i::Handle<i::Object> value(object->value(), isolate);
return Utils::ToLocal(value);
}
MaybeLocal<Message> GetMessageFromPromise(Local<Promise> p) { MaybeLocal<Message> GetMessageFromPromise(Local<Promise> p) {
i::Handle<i::JSPromise> promise = Utils::OpenHandle(*p); i::Handle<i::JSPromise> promise = Utils::OpenHandle(*p);
i::Isolate* isolate = promise->GetIsolate(); i::Isolate* isolate = promise->GetIsolate();
......
...@@ -622,9 +622,6 @@ class V8_EXPORT_PRIVATE WasmValueObject : public v8::Object { ...@@ -622,9 +622,6 @@ class V8_EXPORT_PRIVATE WasmValueObject : public v8::Object {
static bool IsWasmValueObject(v8::Local<v8::Value> obj); static bool IsWasmValueObject(v8::Local<v8::Value> obj);
V8_INLINE static WasmValueObject* Cast(v8::Value* obj); V8_INLINE static WasmValueObject* Cast(v8::Value* obj);
v8::Local<v8::String> type() const;
v8::Local<v8::Value> value() const;
private: private:
static void CheckCast(v8::Value* obj); static void CheckCast(v8::Value* obj);
}; };
......
...@@ -20,7 +20,6 @@ OBJECT_CONSTRUCTORS_IMPL(WasmValueObject, JSObject) ...@@ -20,7 +20,6 @@ OBJECT_CONSTRUCTORS_IMPL(WasmValueObject, JSObject)
CAST_ACCESSOR(WasmValueObject) CAST_ACCESSOR(WasmValueObject)
ACCESSORS(WasmValueObject, type, String, kTypeOffset)
ACCESSORS(WasmValueObject, value, Object, kValueOffset) ACCESSORS(WasmValueObject, value, Object, kValueOffset)
} // namespace internal } // namespace internal
......
...@@ -82,8 +82,10 @@ enum DebugProxyId { ...@@ -82,8 +82,10 @@ enum DebugProxyId {
kNumInstanceProxies = kLastInstanceProxyId + 1 kNumInstanceProxies = kLastInstanceProxyId + 1
}; };
constexpr int kWasmValueMapIndex = kNumProxies; constexpr int kFirstWasmValueMapIndex = kNumProxies;
constexpr int kNumDebugMaps = kWasmValueMapIndex + 1; constexpr int kLastWasmValueMapIndex =
kFirstWasmValueMapIndex + WasmValueObject::kNumTypes - 1;
constexpr int kNumDebugMaps = kLastWasmValueMapIndex + 1;
Handle<FixedArray> GetOrCreateDebugMaps(Isolate* isolate) { Handle<FixedArray> GetOrCreateDebugMaps(Isolate* isolate) {
Handle<FixedArray> maps = isolate->wasm_debug_maps(); Handle<FixedArray> maps = isolate->wasm_debug_maps();
...@@ -751,23 +753,53 @@ Handle<String> WasmSimd128ToString(Isolate* isolate, wasm::Simd128 s128) { ...@@ -751,23 +753,53 @@ Handle<String> WasmSimd128ToString(Isolate* isolate, wasm::Simd128 s128) {
return isolate->factory()->NewStringFromAsciiChecked(buffer.data()); return isolate->factory()->NewStringFromAsciiChecked(buffer.data());
} }
Handle<String> Type2String(Isolate* isolate, WasmValueObject::Type type) {
switch (type) {
case WasmValueObject::kExternRef:
return isolate->factory()->InternalizeString(
StaticCharVector("externref"));
case WasmValueObject::kF32:
return isolate->factory()->InternalizeString(StaticCharVector("f32"));
case WasmValueObject::kF64:
return isolate->factory()->InternalizeString(StaticCharVector("f64"));
case WasmValueObject::kI32:
return isolate->factory()->InternalizeString(StaticCharVector("i32"));
case WasmValueObject::kI64:
return isolate->factory()->InternalizeString(StaticCharVector("i64"));
case WasmValueObject::kV128:
return isolate->factory()->InternalizeString(StaticCharVector("v128"));
case WasmValueObject::kNumTypes:
break;
}
UNREACHABLE();
}
} // namespace } // namespace
// static // static
Handle<WasmValueObject> WasmValueObject::New(Isolate* isolate, Handle<WasmValueObject> WasmValueObject::New(Isolate* isolate, Type type,
Handle<String> type,
Handle<Object> value) { Handle<Object> value) {
int map_index = kFirstWasmValueMapIndex + type;
DCHECK_LE(kFirstWasmValueMapIndex, map_index);
DCHECK_LE(map_index, kLastWasmValueMapIndex);
auto maps = GetOrCreateDebugMaps(isolate); auto maps = GetOrCreateDebugMaps(isolate);
if (maps->is_the_hole(isolate, kWasmValueMapIndex)) { if (maps->is_the_hole(isolate, map_index)) {
auto type_name = Type2String(isolate, type);
auto shared = isolate->factory()->NewSharedFunctionInfoForBuiltin(
type_name, Builtins::kIllegal);
shared->set_language_mode(LanguageMode::kStrict);
auto constructor =
Factory::JSFunctionBuilder{isolate, shared, isolate->native_context()}
.set_map(isolate->strict_function_map())
.Build();
Handle<Map> map = isolate->factory()->NewMap( Handle<Map> map = isolate->factory()->NewMap(
WASM_VALUE_OBJECT_TYPE, WasmValueObject::kSize, WASM_VALUE_OBJECT_TYPE, WasmValueObject::kSize,
TERMINAL_FAST_ELEMENTS_KIND, 2); TERMINAL_FAST_ELEMENTS_KIND, 1);
Map::EnsureDescriptorSlack(isolate, map, 2); Map::EnsureDescriptorSlack(isolate, map, 2);
{ // type { // type
Descriptor d = Descriptor::DataField( Descriptor d = Descriptor::DataConstant(
isolate,
isolate->factory()->InternalizeString(StaticCharVector("type")), isolate->factory()->InternalizeString(StaticCharVector("type")),
WasmValueObject::kTypeIndex, FROZEN, Representation::Tagged()); type_name, FROZEN);
map->AppendDescriptor(isolate, &d); map->AppendDescriptor(isolate, &d);
} }
{ // value { // value
...@@ -777,14 +809,13 @@ Handle<WasmValueObject> WasmValueObject::New(Isolate* isolate, ...@@ -777,14 +809,13 @@ Handle<WasmValueObject> WasmValueObject::New(Isolate* isolate,
WasmValueObject::kValueIndex, FROZEN, Representation::Tagged()); WasmValueObject::kValueIndex, FROZEN, Representation::Tagged());
map->AppendDescriptor(isolate, &d); map->AppendDescriptor(isolate, &d);
} }
map->set_constructor_or_back_pointer(*constructor);
map->set_is_extensible(false); map->set_is_extensible(false);
maps->set(kWasmValueMapIndex, *map); maps->set(map_index, *map);
} }
Handle<Map> value_map = Handle<Map> value_map(Map::cast(maps->get(map_index)), isolate);
handle(Map::cast(maps->get(kWasmValueMapIndex)), isolate);
Handle<WasmValueObject> object = Handle<WasmValueObject>::cast( Handle<WasmValueObject> object = Handle<WasmValueObject>::cast(
isolate->factory()->NewJSObjectFromMap(value_map)); isolate->factory()->NewJSObjectFromMap(value_map));
object->set_type(*type);
object->set_value(*value); object->set_value(*value);
return object; return object;
} }
...@@ -792,44 +823,22 @@ Handle<WasmValueObject> WasmValueObject::New(Isolate* isolate, ...@@ -792,44 +823,22 @@ Handle<WasmValueObject> WasmValueObject::New(Isolate* isolate,
// static // static
Handle<WasmValueObject> WasmValueObject::New(Isolate* isolate, Handle<WasmValueObject> WasmValueObject::New(Isolate* isolate,
const wasm::WasmValue& value) { const wasm::WasmValue& value) {
Handle<String> t;
Handle<Object> v;
switch (value.type().kind()) { switch (value.type().kind()) {
case wasm::ValueType::kI32: { case wasm::ValueType::kF32:
t = isolate->factory()->InternalizeString(StaticCharVector("i32")); return New(isolate, kF32, isolate->factory()->NewNumber(value.to_f32()));
v = isolate->factory()->NewNumberFromInt(value.to_i32_unchecked()); case wasm::ValueType::kF64:
break; return New(isolate, kF64, isolate->factory()->NewNumber(value.to_f64()));
} case wasm::ValueType::kI32:
case wasm::ValueType::kI64: { return New(isolate, kI32, isolate->factory()->NewNumber(value.to_i32()));
t = isolate->factory()->InternalizeString(StaticCharVector("i64")); case wasm::ValueType::kI64:
v = BigInt::FromInt64(isolate, value.to_i64_unchecked()); return New(isolate, kI64, BigInt::FromInt64(isolate, value.to_i64()));
break; case wasm::ValueType::kRef:
} return New(isolate, kExternRef, value.to_externref());
case wasm::ValueType::kF32: { case wasm::ValueType::kS128:
t = isolate->factory()->InternalizeString(StaticCharVector("f32")); return New(isolate, kV128, WasmSimd128ToString(isolate, value.to_s128()));
v = isolate->factory()->NewNumber(value.to_f32_unchecked());
break;
}
case wasm::ValueType::kF64: {
t = isolate->factory()->InternalizeString(StaticCharVector("f64"));
v = isolate->factory()->NewNumber(value.to_f64_unchecked());
break;
}
case wasm::ValueType::kS128: {
t = isolate->factory()->InternalizeString(StaticCharVector("v128"));
v = WasmSimd128ToString(isolate, value.to_s128_unchecked());
break;
}
case wasm::ValueType::kRef: {
t = isolate->factory()->InternalizeString(StaticCharVector("externref"));
v = value.to_externref();
break;
}
default: default:
UNREACHABLE(); UNREACHABLE();
} }
return New(isolate, t, v);
} }
Handle<JSObject> GetWasmDebugProxy(WasmFrame* frame) { Handle<JSObject> GetWasmDebugProxy(WasmFrame* frame) {
......
...@@ -32,7 +32,6 @@ class WasmValueObject : public JSObject { ...@@ -32,7 +32,6 @@ class WasmValueObject : public JSObject {
public: public:
DECL_CAST(WasmValueObject) DECL_CAST(WasmValueObject)
DECL_ACCESSORS(type, String)
DECL_ACCESSORS(value, Object) DECL_ACCESSORS(value, Object)
// Dispatched behavior. // Dispatched behavior.
...@@ -41,17 +40,17 @@ class WasmValueObject : public JSObject { ...@@ -41,17 +40,17 @@ class WasmValueObject : public JSObject {
// Layout description. // Layout description.
#define WASM_VALUE_FIELDS(V) \ #define WASM_VALUE_FIELDS(V) \
V(kTypeOffset, kTaggedSize) \
V(kValueOffset, kTaggedSize) \ V(kValueOffset, kTaggedSize) \
V(kSize, 0) V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, WASM_VALUE_FIELDS) DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, WASM_VALUE_FIELDS)
#undef WASM_VALUE_FIELDS #undef WASM_VALUE_FIELDS
// Indices of in-object properties. // Indices of in-object properties.
static constexpr int kTypeIndex = 0; static constexpr int kValueIndex = 0;
static constexpr int kValueIndex = 1;
static Handle<WasmValueObject> New(Isolate* isolate, Handle<String> type, enum Type { kExternRef, kF32, kF64, kI32, kI64, kV128, kNumTypes };
static Handle<WasmValueObject> New(Isolate* isolate, Type type,
Handle<Object> value); Handle<Object> value);
static Handle<WasmValueObject> New(Isolate* isolate, static Handle<WasmValueObject> New(Isolate* isolate,
const wasm::WasmValue& value); const wasm::WasmValue& value);
......
...@@ -1548,7 +1548,6 @@ void WasmInstanceObject::WasmInstanceObjectVerify(Isolate* isolate) { ...@@ -1548,7 +1548,6 @@ void WasmInstanceObject::WasmInstanceObjectVerify(Isolate* isolate) {
void WasmValueObject::WasmValueObjectVerify(Isolate* isolate) { void WasmValueObject::WasmValueObjectVerify(Isolate* isolate) {
JSObjectVerify(isolate); JSObjectVerify(isolate);
CHECK(IsWasmValueObject()); CHECK(IsWasmValueObject());
CHECK(type().IsString());
} }
void WasmExportedFunctionData::WasmExportedFunctionDataVerify( void WasmExportedFunctionData::WasmExportedFunctionDataVerify(
......
...@@ -1902,7 +1902,6 @@ void WasmTableObject::WasmTableObjectPrint(std::ostream& os) { // NOLINT ...@@ -1902,7 +1902,6 @@ void WasmTableObject::WasmTableObjectPrint(std::ostream& os) { // NOLINT
void WasmValueObject::WasmValueObjectPrint(std::ostream& os) { // NOLINT void WasmValueObject::WasmValueObjectPrint(std::ostream& os) { // NOLINT
PrintHeader(os, "WasmValueObject"); PrintHeader(os, "WasmValueObject");
os << "\n - type: " << Brief(type());
os << "\n - value: " << Brief(value()); os << "\n - value: " << Brief(value());
os << "\n"; os << "\n";
} }
......
...@@ -305,22 +305,6 @@ String16 descriptionForCollection(v8::Isolate* isolate, ...@@ -305,22 +305,6 @@ String16 descriptionForCollection(v8::Isolate* isolate,
return String16::concat(className, '(', String16::fromInteger(length), ')'); return String16::concat(className, '(', String16::fromInteger(length), ')');
} }
String16 descriptionForWasmValueObject(
v8::Local<v8::Context> context,
v8::Local<v8::debug::WasmValueObject> object) {
v8::Isolate* isolate = context->GetIsolate();
auto type = toProtocolString(isolate, object->type());
auto value = object->value();
if (type == "i32" || type == "f32" || type == "f64") {
return String16::fromDouble(v8::Local<v8::Number>::Cast(value)->Value());
} else if (type == "i64") {
return descriptionForBigInt(context, v8::Local<v8::BigInt>::Cast(value));
} else if (type == "v128") {
return toProtocolString(isolate, v8::Local<v8::String>::Cast(value));
}
return type;
}
String16 descriptionForEntry(v8::Local<v8::Context> context, String16 descriptionForEntry(v8::Local<v8::Context> context,
v8::Local<v8::Object> object) { v8::Local<v8::Object> object) {
v8::Isolate* isolate = context->GetIsolate(); v8::Isolate* isolate = context->GetIsolate();
...@@ -809,6 +793,8 @@ bool getPropertiesForPreview(v8::Local<v8::Context> context, ...@@ -809,6 +793,8 @@ bool getPropertiesForPreview(v8::Local<v8::Context> context,
if (object->IsArray() || isArrayLike(context, object, &length) || if (object->IsArray() || isArrayLike(context, object, &length) ||
object->IsStringObject()) { object->IsStringObject()) {
blocklist.push_back("length"); blocklist.push_back("length");
} else if (v8::debug::WasmValueObject::IsWasmValueObject(object)) {
blocklist.push_back("type");
} else { } else {
auto clientSubtype = clientFor(context)->valueSubtype(object); auto clientSubtype = clientFor(context)->valueSubtype(object);
if (clientSubtype && toString16(clientSubtype->string()) == "array") { if (clientSubtype && toString16(clientSubtype->string()) == "array") {
...@@ -1708,11 +1694,11 @@ std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context, ...@@ -1708,11 +1694,11 @@ std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context,
isolate, memory, memory->Buffer()->ByteLength() / kWasmPageSize)); isolate, memory, memory->Buffer()->ByteLength() / kWasmPageSize));
} }
if (v8::debug::WasmValueObject::IsWasmValueObject(value)) { if (v8::debug::WasmValueObject::IsWasmValueObject(value)) {
v8::Local<v8::debug::WasmValueObject> v = v8::Local<v8::debug::WasmValueObject> object =
value.As<v8::debug::WasmValueObject>(); value.As<v8::debug::WasmValueObject>();
return std::make_unique<ObjectMirror>( return std::make_unique<ObjectMirror>(
value, RemoteObject::SubtypeEnum::Wasmvalue, value, RemoteObject::SubtypeEnum::Wasmvalue,
descriptionForWasmValueObject(context, v)); descriptionForObject(isolate, object));
} }
V8InternalValueType internalType = V8InternalValueType internalType =
v8InternalValueTypeFrom(context, value.As<v8::Object>()); v8InternalValueTypeFrom(context, value.As<v8::Object>());
......
...@@ -18,33 +18,33 @@ Debugger paused in main. ...@@ -18,33 +18,33 @@ Debugger paused in main.
> globals = Globals > globals = Globals
> typeof globals = "object" > typeof globals = "object"
> Object.keys(globals) = Array(2) > Object.keys(globals) = Array(2)
> globals[0] = 0 > globals[0] = i32 {0}
> globals[1] = 1 > globals[1] = i32 {1}
> globals[2] = 2n > globals[2] = i64 {2n}
> globals[3] = 3n > globals[3] = i64 {3n}
> globals["$global0"] = 0 > globals["$global0"] = i32 {0}
> $global0 = 0 > $global0 = i32 {0}
> globals["$global3"] = 2n > globals["$global3"] = i64 {2n}
> $global3 = 2n > $global3 = i64 {2n}
Stepping twice in main. Stepping twice in main.
Debugger paused in main. Debugger paused in main.
> globals[0] = 0 > globals[0] = i32 {0}
> globals[1] = 1 > globals[1] = i32 {1}
> globals[2] = 2n > globals[2] = i64 {2n}
> globals[3] = 42n > globals[3] = i64 {42n}
> globals["$global0"] = 0 > globals["$global0"] = i32 {0}
> $global0 = 0 > $global0 = i32 {0}
> globals["$global3"] = 2n > globals["$global3"] = i64 {2n}
> $global3 = 2n > $global3 = i64 {2n}
Changing global from JavaScript. Changing global from JavaScript.
> globals[0] = 0 > globals[0] = i32 {0}
> globals[1] = 21 > globals[1] = i32 {21}
> globals[2] = 2n > globals[2] = i64 {2n}
> globals[3] = 42n > globals[3] = i64 {42n}
> globals["$global0"] = 0 > globals["$global0"] = i32 {0}
> $global0 = 0 > $global0 = i32 {0}
> globals["$global3"] = 2n > globals["$global3"] = i64 {2n}
> $global3 = 2n > $global3 = i64 {2n}
Running test: testFunctions Running test: testFunctions
Compile module. Compile module.
...@@ -77,22 +77,22 @@ Debugger paused in main. ...@@ -77,22 +77,22 @@ Debugger paused in main.
> locals = Locals > locals = Locals
> typeof locals = "object" > typeof locals = "object"
> Object.keys(locals) = Array(2) > Object.keys(locals) = Array(2)
> locals[0] = 3 > locals[0] = i32 {3}
> locals[1] = 6 > locals[1] = i32 {6}
> locals[2] = 0 > locals[2] = i32 {0}
> locals["$x"] = 3 > locals["$x"] = i32 {3}
> $x = 3 > $x = i32 {3}
> locals["$var2"] = 0 > locals["$var2"] = i32 {0}
> $var2 = 0 > $var2 = i32 {0}
Stepping twice in main. Stepping twice in main.
Debugger paused in main. Debugger paused in main.
> locals[0] = 3 > locals[0] = i32 {3}
> locals[1] = 6 > locals[1] = i32 {6}
> locals[2] = 42 > locals[2] = i32 {42}
> locals["$x"] = 3 > locals["$x"] = i32 {3}
> $x = 3 > $x = i32 {3}
> locals["$var2"] = 42 > locals["$var2"] = i32 {42}
> $var2 = 42 > $var2 = i32 {42}
Running test: testMemories Running test: testMemories
Compile module. Compile module.
...@@ -133,5 +133,5 @@ Stepping twice in main. ...@@ -133,5 +133,5 @@ Stepping twice in main.
Debugger paused in main. Debugger paused in main.
> stack = Stack > stack = Stack
> Object.keys(stack) = Array(2) > Object.keys(stack) = Array(2)
> stack[0] = 5 > stack[0] = i32 {5}
> stack[1] = 42 > stack[1] = i32 {42}
...@@ -31,13 +31,17 @@ async function instantiateModule({objectId}, importObject) { ...@@ -31,13 +31,17 @@ async function instantiateModule({objectId}, importObject) {
} }
async function dumpOnCallFrame(callFrameId, expression) { async function dumpOnCallFrame(callFrameId, expression) {
const {result: {result}} = await Protocol.Debugger.evaluateOnCallFrame({ const {result: {result: object}} = await Protocol.Debugger.evaluateOnCallFrame({
callFrameId, expression callFrameId, expression
}); });
if ('description' in result) { if (object.type === 'object' && object.subtype === 'wasmvalue') {
InspectorTest.log(`> ${expression} = ${result.description}`); const {result: {result: properties}} = await Protocol.Runtime.getProperties({objectId: object.objectId, ownProperties: true})
const valueProperty = properties.find(p => p.name === 'value');
InspectorTest.log(`> ${expression} = ${object.description} {${valueProperty.value.description}}`);
} else if ('description' in object) {
InspectorTest.log(`> ${expression} = ${object.description}`);
} else { } else {
InspectorTest.log(`> ${expression} = ${JSON.stringify(result.value)}`); InspectorTest.log(`> ${expression} = ${JSON.stringify(object.value)}`);
} }
} }
......
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