зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1343581 - Expose wasm function return value to Debugger.Frame. r=luke
MozReview-Commit-ID: 4XPGHhrZTvM --HG-- extra : rebase_source : 093cb711c63c61f9a1e451eaf3ef3f021846b162
This commit is contained in:
Родитель
603ff013e0
Коммит
b12f5d0357
|
@ -0,0 +1,62 @@
|
||||||
|
// |jit-test| test-also-wasm-baseline
|
||||||
|
// Tests that wasm frame opPop event can access function resumption value.
|
||||||
|
|
||||||
|
load(libdir + "wasm.js");
|
||||||
|
load(libdir + 'eqArrayHelper.js');
|
||||||
|
|
||||||
|
function monitorFrameOnPopReturns(wast, expected) {
|
||||||
|
var values = [];
|
||||||
|
wasmRunWithDebugger(
|
||||||
|
wast,
|
||||||
|
undefined,
|
||||||
|
function ({dbg}) {
|
||||||
|
dbg.onEnterFrame = function (frame) {
|
||||||
|
if (frame.type != 'wasmcall') return;
|
||||||
|
frame.onPop = function (value) {
|
||||||
|
values.push(value.return);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
},
|
||||||
|
function ({error}) {
|
||||||
|
assertEq(error, undefined);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assertEqArray(values, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
monitorFrameOnPopReturns(
|
||||||
|
`(module (func (export "test")))`,
|
||||||
|
[undefined]);
|
||||||
|
monitorFrameOnPopReturns(
|
||||||
|
`(module (func (export "test") (result i32) (i32.const 42)))`,
|
||||||
|
[42]);
|
||||||
|
monitorFrameOnPopReturns(
|
||||||
|
`(module (func (export "test") (result f32) (f32.const 0.5)))`,
|
||||||
|
[0.5]);
|
||||||
|
monitorFrameOnPopReturns(
|
||||||
|
`(module (func (export "test") (result f64) (f64.const -42.75)))`,
|
||||||
|
[-42.75]);
|
||||||
|
monitorFrameOnPopReturns(
|
||||||
|
`(module (func (result i64) (i64.const 2)) (func (export "test") (call 0) (drop)))`,
|
||||||
|
[2, undefined]);
|
||||||
|
|
||||||
|
// Checking if throwing frame has right resumption value.
|
||||||
|
var throwCount = 0;
|
||||||
|
wasmRunWithDebugger(
|
||||||
|
'(module (func (unreachable)) (func (export "test") (result i32) (call 0) (i32.const 1)))',
|
||||||
|
undefined,
|
||||||
|
function ({dbg, g}) {
|
||||||
|
dbg.onEnterFrame = function (frame) {
|
||||||
|
if (frame.type != 'wasmcall') return;
|
||||||
|
frame.onPop = function (value) {
|
||||||
|
if ('throw' in value)
|
||||||
|
throwCount++;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
},
|
||||||
|
function ({error}) {
|
||||||
|
assertEq(error != undefined, true);
|
||||||
|
assertEq(throwCount, 2);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -423,7 +423,7 @@ AbstractFramePtr::returnValue() const
|
||||||
if (isInterpreterFrame())
|
if (isInterpreterFrame())
|
||||||
return asInterpreterFrame()->returnValue();
|
return asInterpreterFrame()->returnValue();
|
||||||
if (isWasmDebugFrame())
|
if (isWasmDebugFrame())
|
||||||
return UndefinedHandleValue;
|
return asWasmDebugFrame()->returnValue();
|
||||||
return asBaselineFrame()->returnValue();
|
return asBaselineFrame()->returnValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -471,7 +471,8 @@ uint8_t*
|
||||||
Metadata::serialize(uint8_t* cursor) const
|
Metadata::serialize(uint8_t* cursor) const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!debugEnabled && debugTrapFarJumpOffsets.empty() &&
|
MOZ_ASSERT(!debugEnabled && debugTrapFarJumpOffsets.empty() &&
|
||||||
debugFuncArgTypes.empty() && debugFuncToCodeRange.empty());
|
debugFuncArgTypes.empty() && debugFuncReturnTypes.empty() &&
|
||||||
|
debugFuncToCodeRange.empty());
|
||||||
cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
|
cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
|
||||||
cursor = SerializeVector(cursor, funcImports);
|
cursor = SerializeVector(cursor, funcImports);
|
||||||
cursor = SerializeVector(cursor, funcExports);
|
cursor = SerializeVector(cursor, funcExports);
|
||||||
|
@ -512,6 +513,7 @@ Metadata::deserialize(const uint8_t* cursor)
|
||||||
debugTrapFarJumpOffsets.clear();
|
debugTrapFarJumpOffsets.clear();
|
||||||
debugFuncToCodeRange.clear();
|
debugFuncToCodeRange.clear();
|
||||||
debugFuncArgTypes.clear();
|
debugFuncArgTypes.clear();
|
||||||
|
debugFuncReturnTypes.clear();
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1193,6 +1195,13 @@ Code::debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t* args
|
||||||
return DecodeLocalEntries(d, metadata_->kind, locals);
|
return DecodeLocalEntries(d, metadata_->kind, locals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExprType
|
||||||
|
Code::debugGetResultType(uint32_t funcIndex)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(metadata_->debugEnabled);
|
||||||
|
return metadata_->debugFuncReturnTypes[funcIndex];
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Code::addSizeOfMisc(MallocSizeOf mallocSizeOf,
|
Code::addSizeOfMisc(MallocSizeOf mallocSizeOf,
|
||||||
Metadata::SeenSet* seenMetadata,
|
Metadata::SeenSet* seenMetadata,
|
||||||
|
|
|
@ -428,6 +428,7 @@ struct CustomSection
|
||||||
|
|
||||||
typedef Vector<CustomSection, 0, SystemAllocPolicy> CustomSectionVector;
|
typedef Vector<CustomSection, 0, SystemAllocPolicy> CustomSectionVector;
|
||||||
typedef Vector<ValTypeVector, 0, SystemAllocPolicy> FuncArgTypesVector;
|
typedef Vector<ValTypeVector, 0, SystemAllocPolicy> FuncArgTypesVector;
|
||||||
|
typedef Vector<ExprType, 0, SystemAllocPolicy> FuncReturnTypesVector;
|
||||||
|
|
||||||
// Metadata holds all the data that is needed to describe compiled wasm code
|
// Metadata holds all the data that is needed to describe compiled wasm code
|
||||||
// at runtime (as opposed to data that is only used to statically link or
|
// at runtime (as opposed to data that is only used to statically link or
|
||||||
|
@ -479,6 +480,7 @@ struct Metadata : ShareableBase<Metadata>, MetadataCacheablePod
|
||||||
Uint32Vector debugTrapFarJumpOffsets;
|
Uint32Vector debugTrapFarJumpOffsets;
|
||||||
Uint32Vector debugFuncToCodeRange;
|
Uint32Vector debugFuncToCodeRange;
|
||||||
FuncArgTypesVector debugFuncArgTypes;
|
FuncArgTypesVector debugFuncArgTypes;
|
||||||
|
FuncReturnTypesVector debugFuncReturnTypes;
|
||||||
|
|
||||||
bool usesMemory() const { return UsesMemory(memoryUsage); }
|
bool usesMemory() const { return UsesMemory(memoryUsage); }
|
||||||
bool hasSharedMemory() const { return memoryUsage == MemoryUsage::Shared; }
|
bool hasSharedMemory() const { return memoryUsage == MemoryUsage::Shared; }
|
||||||
|
@ -671,6 +673,7 @@ class Code
|
||||||
// Stack inspection helpers.
|
// Stack inspection helpers.
|
||||||
|
|
||||||
bool debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t* argsLength);
|
bool debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t* argsLength);
|
||||||
|
ExprType debugGetResultType(uint32_t funcIndex);
|
||||||
|
|
||||||
// about:memory reporting:
|
// about:memory reporting:
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,40 @@ DebugFrame::leaveFrame(JSContext* cx)
|
||||||
observing_ = false;
|
observing_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DebugFrame::clearReturnJSValue()
|
||||||
|
{
|
||||||
|
hasCachedReturnJSValue_ = true;
|
||||||
|
cachedReturnJSValue_.setUndefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DebugFrame::updateReturnJSValue()
|
||||||
|
{
|
||||||
|
hasCachedReturnJSValue_ = true;
|
||||||
|
ExprType returnType = instance()->code().debugGetResultType(funcIndex());
|
||||||
|
switch (returnType) {
|
||||||
|
case ExprType::Void:
|
||||||
|
cachedReturnJSValue_.setUndefined();
|
||||||
|
break;
|
||||||
|
case ExprType::I32:
|
||||||
|
cachedReturnJSValue_.setInt32(resultI32_);
|
||||||
|
break;
|
||||||
|
case ExprType::I64:
|
||||||
|
// Just display as a Number; it's ok if we lose some precision
|
||||||
|
cachedReturnJSValue_.setDouble((double)resultI64_);
|
||||||
|
break;
|
||||||
|
case ExprType::F32:
|
||||||
|
cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF32_));
|
||||||
|
break;
|
||||||
|
case ExprType::F64:
|
||||||
|
cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF64_));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MOZ_CRASH("result type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DebugFrame::getLocal(uint32_t localIndex, MutableHandleValue vp)
|
DebugFrame::getLocal(uint32_t localIndex, MutableHandleValue vp)
|
||||||
{
|
{
|
||||||
|
@ -89,10 +123,10 @@ DebugFrame::getLocal(uint32_t localIndex, MutableHandleValue vp)
|
||||||
vp.set(NumberValue((double)*static_cast<int64_t*>(dataPtr)));
|
vp.set(NumberValue((double)*static_cast<int64_t*>(dataPtr)));
|
||||||
break;
|
break;
|
||||||
case jit::MIRType::Float32:
|
case jit::MIRType::Float32:
|
||||||
vp.set(NumberValue(*static_cast<float*>(dataPtr)));
|
vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<float*>(dataPtr))));
|
||||||
break;
|
break;
|
||||||
case jit::MIRType::Double:
|
case jit::MIRType::Double:
|
||||||
vp.set(NumberValue(*static_cast<double*>(dataPtr)));
|
vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<double*>(dataPtr))));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
MOZ_CRASH("local type");
|
MOZ_CRASH("local type");
|
||||||
|
|
|
@ -40,6 +40,8 @@ class DebugFrame
|
||||||
double resultF64_;
|
double resultF64_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
js::Value cachedReturnJSValue_;
|
||||||
|
|
||||||
// The fields below are initialized by the baseline compiler.
|
// The fields below are initialized by the baseline compiler.
|
||||||
uint32_t funcIndex_;
|
uint32_t funcIndex_;
|
||||||
uint32_t reserved0_;
|
uint32_t reserved0_;
|
||||||
|
@ -52,6 +54,7 @@ class DebugFrame
|
||||||
bool isDebuggee_ : 1;
|
bool isDebuggee_ : 1;
|
||||||
bool prevUpToDate_ : 1;
|
bool prevUpToDate_ : 1;
|
||||||
bool hasCachedSavedFrame_ : 1;
|
bool hasCachedSavedFrame_ : 1;
|
||||||
|
bool hasCachedReturnJSValue_ : 1;
|
||||||
};
|
};
|
||||||
void* reserved1_;
|
void* reserved1_;
|
||||||
};
|
};
|
||||||
|
@ -91,6 +94,13 @@ class DebugFrame
|
||||||
|
|
||||||
inline void* resultsPtr() { return &resultI32_; }
|
inline void* resultsPtr() { return &resultI32_; }
|
||||||
|
|
||||||
|
inline HandleValue returnValue() const {
|
||||||
|
MOZ_ASSERT(hasCachedReturnJSValue_);
|
||||||
|
return HandleValue::fromMarkedLocation(&cachedReturnJSValue_);
|
||||||
|
}
|
||||||
|
void updateReturnJSValue();
|
||||||
|
void clearReturnJSValue();
|
||||||
|
|
||||||
bool getLocal(uint32_t localIndex, MutableHandleValue vp);
|
bool getLocal(uint32_t localIndex, MutableHandleValue vp);
|
||||||
|
|
||||||
static constexpr size_t offsetOfResults() { return offsetof(DebugFrame, resultI32_); }
|
static constexpr size_t offsetOfResults() { return offsetof(DebugFrame, resultI32_); }
|
||||||
|
|
|
@ -204,9 +204,12 @@ ModuleGenerator::initWasm(const CompileArgs& args)
|
||||||
if (metadata_->debugEnabled) {
|
if (metadata_->debugEnabled) {
|
||||||
if (!debugFuncArgTypes_.resize(env_->funcSigs.length()))
|
if (!debugFuncArgTypes_.resize(env_->funcSigs.length()))
|
||||||
return false;
|
return false;
|
||||||
|
if (!debugFuncReturnTypes_.resize(env_->funcSigs.length()))
|
||||||
|
return false;
|
||||||
for (size_t i = 0; i < debugFuncArgTypes_.length(); i++) {
|
for (size_t i = 0; i < debugFuncArgTypes_.length(); i++) {
|
||||||
if (!debugFuncArgTypes_[i].appendAll(env_->funcSigs[i]->args()))
|
if (!debugFuncArgTypes_[i].appendAll(env_->funcSigs[i]->args()))
|
||||||
return false;
|
return false;
|
||||||
|
debugFuncReturnTypes_[i] = env_->funcSigs[i]->ret();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1160,6 +1163,7 @@ ModuleGenerator::finish(const ShareableBytes& bytecode)
|
||||||
|
|
||||||
// Additional debug information to copy.
|
// Additional debug information to copy.
|
||||||
metadata_->debugFuncArgTypes = Move(debugFuncArgTypes_);
|
metadata_->debugFuncArgTypes = Move(debugFuncArgTypes_);
|
||||||
|
metadata_->debugFuncReturnTypes = Move(debugFuncReturnTypes_);
|
||||||
if (metadata_->debugEnabled)
|
if (metadata_->debugEnabled)
|
||||||
metadata_->debugFuncToCodeRange = Move(funcToCodeRange_);
|
metadata_->debugFuncToCodeRange = Move(funcToCodeRange_);
|
||||||
|
|
||||||
|
|
|
@ -237,6 +237,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||||
uint32_t startOfUnpatchedCallsites_;
|
uint32_t startOfUnpatchedCallsites_;
|
||||||
Uint32Vector debugTrapFarJumps_;
|
Uint32Vector debugTrapFarJumps_;
|
||||||
FuncArgTypesVector debugFuncArgTypes_;
|
FuncArgTypesVector debugFuncArgTypes_;
|
||||||
|
FuncReturnTypesVector debugFuncReturnTypes_;
|
||||||
|
|
||||||
// Parallel compilation
|
// Parallel compilation
|
||||||
bool parallel_;
|
bool parallel_;
|
||||||
|
|
|
@ -129,6 +129,7 @@ WasmHandleDebugTrap()
|
||||||
}
|
}
|
||||||
if (site->kind() == CallSite::LeaveFrame) {
|
if (site->kind() == CallSite::LeaveFrame) {
|
||||||
DebugFrame* frame = iter.debugFrame();
|
DebugFrame* frame = iter.debugFrame();
|
||||||
|
frame->updateReturnJSValue();
|
||||||
bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, true);
|
bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, true);
|
||||||
frame->leaveFrame(cx);
|
frame->leaveFrame(cx);
|
||||||
return ok;
|
return ok;
|
||||||
|
@ -174,6 +175,7 @@ WasmHandleThrow()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
DebugFrame* frame = iter.debugFrame();
|
DebugFrame* frame = iter.debugFrame();
|
||||||
|
frame->clearReturnJSValue();
|
||||||
|
|
||||||
// Assume JSTRAP_ERROR status if no exception is pending --
|
// Assume JSTRAP_ERROR status if no exception is pending --
|
||||||
// no onExceptionUnwind handlers must be fired.
|
// no onExceptionUnwind handlers must be fired.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче