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:
Yury Delendik 2017-03-02 13:25:17 -06:00
Родитель 603ff013e0
Коммит b12f5d0357
9 изменённых файлов: 129 добавлений и 4 удалений

Просмотреть файл

@ -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.