зеркало из 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())
|
||||
return asInterpreterFrame()->returnValue();
|
||||
if (isWasmDebugFrame())
|
||||
return UndefinedHandleValue;
|
||||
return asWasmDebugFrame()->returnValue();
|
||||
return asBaselineFrame()->returnValue();
|
||||
}
|
||||
|
||||
|
|
|
@ -471,7 +471,8 @@ uint8_t*
|
|||
Metadata::serialize(uint8_t* cursor) const
|
||||
{
|
||||
MOZ_ASSERT(!debugEnabled && debugTrapFarJumpOffsets.empty() &&
|
||||
debugFuncArgTypes.empty() && debugFuncToCodeRange.empty());
|
||||
debugFuncArgTypes.empty() && debugFuncReturnTypes.empty() &&
|
||||
debugFuncToCodeRange.empty());
|
||||
cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
|
||||
cursor = SerializeVector(cursor, funcImports);
|
||||
cursor = SerializeVector(cursor, funcExports);
|
||||
|
@ -512,6 +513,7 @@ Metadata::deserialize(const uint8_t* cursor)
|
|||
debugTrapFarJumpOffsets.clear();
|
||||
debugFuncToCodeRange.clear();
|
||||
debugFuncArgTypes.clear();
|
||||
debugFuncReturnTypes.clear();
|
||||
return cursor;
|
||||
}
|
||||
|
||||
|
@ -1193,6 +1195,13 @@ Code::debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t* args
|
|||
return DecodeLocalEntries(d, metadata_->kind, locals);
|
||||
}
|
||||
|
||||
ExprType
|
||||
Code::debugGetResultType(uint32_t funcIndex)
|
||||
{
|
||||
MOZ_ASSERT(metadata_->debugEnabled);
|
||||
return metadata_->debugFuncReturnTypes[funcIndex];
|
||||
}
|
||||
|
||||
void
|
||||
Code::addSizeOfMisc(MallocSizeOf mallocSizeOf,
|
||||
Metadata::SeenSet* seenMetadata,
|
||||
|
|
|
@ -428,6 +428,7 @@ struct CustomSection
|
|||
|
||||
typedef Vector<CustomSection, 0, SystemAllocPolicy> CustomSectionVector;
|
||||
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
|
||||
// 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 debugFuncToCodeRange;
|
||||
FuncArgTypesVector debugFuncArgTypes;
|
||||
FuncReturnTypesVector debugFuncReturnTypes;
|
||||
|
||||
bool usesMemory() const { return UsesMemory(memoryUsage); }
|
||||
bool hasSharedMemory() const { return memoryUsage == MemoryUsage::Shared; }
|
||||
|
@ -671,6 +673,7 @@ class Code
|
|||
// Stack inspection helpers.
|
||||
|
||||
bool debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t* argsLength);
|
||||
ExprType debugGetResultType(uint32_t funcIndex);
|
||||
|
||||
// about:memory reporting:
|
||||
|
||||
|
|
|
@ -65,6 +65,40 @@ DebugFrame::leaveFrame(JSContext* cx)
|
|||
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
|
||||
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)));
|
||||
break;
|
||||
case jit::MIRType::Float32:
|
||||
vp.set(NumberValue(*static_cast<float*>(dataPtr)));
|
||||
vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<float*>(dataPtr))));
|
||||
break;
|
||||
case jit::MIRType::Double:
|
||||
vp.set(NumberValue(*static_cast<double*>(dataPtr)));
|
||||
vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<double*>(dataPtr))));
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("local type");
|
||||
|
|
|
@ -40,6 +40,8 @@ class DebugFrame
|
|||
double resultF64_;
|
||||
};
|
||||
|
||||
js::Value cachedReturnJSValue_;
|
||||
|
||||
// The fields below are initialized by the baseline compiler.
|
||||
uint32_t funcIndex_;
|
||||
uint32_t reserved0_;
|
||||
|
@ -52,6 +54,7 @@ class DebugFrame
|
|||
bool isDebuggee_ : 1;
|
||||
bool prevUpToDate_ : 1;
|
||||
bool hasCachedSavedFrame_ : 1;
|
||||
bool hasCachedReturnJSValue_ : 1;
|
||||
};
|
||||
void* reserved1_;
|
||||
};
|
||||
|
@ -91,6 +94,13 @@ class DebugFrame
|
|||
|
||||
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);
|
||||
|
||||
static constexpr size_t offsetOfResults() { return offsetof(DebugFrame, resultI32_); }
|
||||
|
|
|
@ -204,9 +204,12 @@ ModuleGenerator::initWasm(const CompileArgs& args)
|
|||
if (metadata_->debugEnabled) {
|
||||
if (!debugFuncArgTypes_.resize(env_->funcSigs.length()))
|
||||
return false;
|
||||
if (!debugFuncReturnTypes_.resize(env_->funcSigs.length()))
|
||||
return false;
|
||||
for (size_t i = 0; i < debugFuncArgTypes_.length(); i++) {
|
||||
if (!debugFuncArgTypes_[i].appendAll(env_->funcSigs[i]->args()))
|
||||
return false;
|
||||
debugFuncReturnTypes_[i] = env_->funcSigs[i]->ret();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1160,6 +1163,7 @@ ModuleGenerator::finish(const ShareableBytes& bytecode)
|
|||
|
||||
// Additional debug information to copy.
|
||||
metadata_->debugFuncArgTypes = Move(debugFuncArgTypes_);
|
||||
metadata_->debugFuncReturnTypes = Move(debugFuncReturnTypes_);
|
||||
if (metadata_->debugEnabled)
|
||||
metadata_->debugFuncToCodeRange = Move(funcToCodeRange_);
|
||||
|
||||
|
|
|
@ -237,6 +237,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
uint32_t startOfUnpatchedCallsites_;
|
||||
Uint32Vector debugTrapFarJumps_;
|
||||
FuncArgTypesVector debugFuncArgTypes_;
|
||||
FuncReturnTypesVector debugFuncReturnTypes_;
|
||||
|
||||
// Parallel compilation
|
||||
bool parallel_;
|
||||
|
|
|
@ -129,6 +129,7 @@ WasmHandleDebugTrap()
|
|||
}
|
||||
if (site->kind() == CallSite::LeaveFrame) {
|
||||
DebugFrame* frame = iter.debugFrame();
|
||||
frame->updateReturnJSValue();
|
||||
bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, true);
|
||||
frame->leaveFrame(cx);
|
||||
return ok;
|
||||
|
@ -174,6 +175,7 @@ WasmHandleThrow()
|
|||
continue;
|
||||
|
||||
DebugFrame* frame = iter.debugFrame();
|
||||
frame->clearReturnJSValue();
|
||||
|
||||
// Assume JSTRAP_ERROR status if no exception is pending --
|
||||
// no onExceptionUnwind handlers must be fired.
|
||||
|
|
Загрузка…
Ссылка в новой задаче