Bug 1334504 - Baldr: remove baseline's explicit TLS-saving (r=yury)

MozReview-Commit-ID: 3MyiHUo0da2

--HG--
extra : rebase_source : c81c5636f58abed9a2763319a72c3080e695bdc6
This commit is contained in:
Luke Wagner 2017-03-22 17:15:18 -05:00
Родитель d4d809f4c4
Коммит 2710499799
13 изменённых файлов: 261 добавлений и 323 удалений

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

@ -2980,9 +2980,9 @@ MacroAssembler::loadWasmActivationFromSymbolicAddress(Register dest)
}
void
MacroAssembler::loadWasmTlsRegFromFrame()
MacroAssembler::loadWasmTlsRegFromFrame(Register dest)
{
loadPtr(Address(getStackPointer(), framePushed() + offsetof(wasm::Frame, tls)), WasmTlsReg);
loadPtr(Address(getStackPointer(), framePushed() + offsetof(wasm::Frame, tls)), dest);
}
void

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

@ -1520,7 +1520,7 @@ class MacroAssembler : public MacroAssemblerSpecific
void loadWasmActivationFromTls(Register dest);
void loadWasmActivationFromSymbolicAddress(Register dest);
void loadWasmTlsRegFromFrame();
void loadWasmTlsRegFromFrame(Register dest = WasmTlsReg);
template<typename T>
void loadTypedOrValue(const T& src, TypedOrValueRegister dest) {

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

@ -381,7 +381,6 @@ UNIFIED_SOURCES += [
'wasm/WasmCode.cpp',
'wasm/WasmCompartment.cpp',
'wasm/WasmCompile.cpp',
'wasm/WasmDebugFrame.cpp',
'wasm/WasmFrameIterator.cpp',
'wasm/WasmGenerator.cpp',
'wasm/WasmInstance.cpp',

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

@ -2549,7 +2549,7 @@ Debugger::updateExecutionObservabilityOfFrames(JSContext* cx, const ExecutionObs
oldestEnabledFrame.setIsDebuggee();
}
if (iter.abstractFramePtr().isWasmDebugFrame())
iter.abstractFramePtr().asWasmDebugFrame()->observeFrame(cx);
iter.abstractFramePtr().asWasmDebugFrame()->observe(cx);
} else {
#ifdef DEBUG
// Debugger.Frame lifetimes are managed by the debug epilogue,

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

@ -19,7 +19,6 @@
#include "js/Debug.h"
#include "vm/EnvironmentObject.h"
#include "vm/GeneratorObject.h"
#include "wasm/WasmDebugFrame.h"
#include "wasm/WasmInstance.h"
#include "jsobjinlines.h"
@ -455,7 +454,7 @@ AbstractFramePtr::environmentChain() const
if (isBaselineFrame())
return asBaselineFrame()->environmentChain();
if (isWasmDebugFrame())
return asWasmDebugFrame()->environmentChain();
return &global()->lexicalEnvironment();
return asRematerializedFrame()->environmentChain();
}

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

@ -17,7 +17,6 @@
#include "js/GCAPI.h"
#include "vm/Debugger.h"
#include "vm/Opcodes.h"
#include "wasm/WasmDebugFrame.h"
#include "jit/JitFrameIterator-inl.h"
#include "vm/EnvironmentObject-inl.h"

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

@ -25,6 +25,7 @@
#include "vm/ArgumentsObject.h"
#include "vm/SavedFrame.h"
#include "wasm/WasmFrameIterator.h"
#include "wasm/WasmTypes.h"
struct JSCompartment;
@ -166,6 +167,7 @@ class AbstractFramePtr
MOZ_IMPLICIT AbstractFramePtr(wasm::DebugFrame* fp)
: ptr_(fp ? uintptr_t(fp) | Tag_WasmDebugFrame : 0)
{
static_assert(wasm::DebugFrame::Alignment >= TagMask, "aligned");
MOZ_ASSERT_IF(fp, asWasmDebugFrame() == fp);
}

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

@ -97,7 +97,6 @@
#endif
#include "wasm/WasmBinaryIterator.h"
#include "wasm/WasmDebugFrame.h"
#include "wasm/WasmGenerator.h"
#include "wasm/WasmSignalHandlers.h"
#include "wasm/WasmValidate.h"
@ -199,31 +198,19 @@ static constexpr int32_t TlsSlotSize = sizeof(void*);
static constexpr int32_t TlsSlotOffset = TlsSlotSize;
BaseLocalIter::BaseLocalIter(const ValTypeVector& locals,
size_t argsLength,
bool debugEnabled)
size_t argsLength,
bool debugEnabled)
: locals_(locals),
argsLength_(argsLength),
argsRange_(locals.begin(), argsLength),
argsIter_(argsRange_),
index_(0),
localSize_(0),
localSize_(debugEnabled ? DebugFrame::offsetOfFrame() : 0),
reservedSize_(localSize_),
done_(false)
{
MOZ_ASSERT(argsLength <= locals.length());
// Reserve a stack slot for the TLS pointer outside the locals range so it
// isn't zero-filled like the normal locals.
DebugOnly<int32_t> tlsSlotOffset = pushLocal(TlsSlotSize);
MOZ_ASSERT(tlsSlotOffset == TlsSlotOffset);
if (debugEnabled) {
// If debug information is generated, constructing DebugFrame record:
// reserving some data before TLS pointer. The TLS pointer allocated
// above and regular wasm::Frame data starts after locals.
localSize_ += DebugFrame::offsetOfTlsData();
MOZ_ASSERT(DebugFrame::offsetOfFrame() == localSize_);
}
reservedSize_ = localSize_;
settle();
}
@ -628,10 +615,6 @@ class BaseCompiler
Vector<Local, 8, SystemAllocPolicy> localInfo_;
Vector<OutOfLineCode*, 8, SystemAllocPolicy> outOfLine_;
// Index into localInfo_ of the special local used for saving the TLS
// pointer. This follows the function's real arguments and locals.
uint32_t tlsSlot_;
// On specific platforms we sometimes need to use specific registers.
#ifdef JS_CODEGEN_X64
@ -2229,9 +2212,6 @@ class BaseCompiler
maxFramePushed_ = localSize_;
// The TLS pointer is always passed as a hidden argument in WasmTlsReg.
// Save it into its assigned local slot.
storeToFramePtr(WasmTlsReg, localInfo_[tlsSlot_].offs());
if (debugEnabled_) {
// Initialize funcIndex and flag fields of DebugFrame.
size_t debugFrame = masm.framePushed() - DebugFrame::offsetOfFrame();
@ -2390,8 +2370,9 @@ class BaseCompiler
restoreResult();
}
// Restore the TLS register in case it was overwritten by the function.
loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
// The epilogue assumes WasmTlsReg is valid so reload it in case it was
// clobbered by the body.
masm.loadWasmTlsRegFromFrame();
GenerateFunctionEpilogue(masm, localSize_, &offsets_);
@ -2481,7 +2462,7 @@ class BaseCompiler
// On x86 there are no pinned registers, so don't waste time
// reloading the Tls.
#ifndef JS_CODEGEN_X86
loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadWasmTlsRegFromFrame();
masm.loadWasmPinnedRegsFromTls();
#endif
}
@ -2678,7 +2659,7 @@ class BaseCompiler
const FunctionCall& call)
{
// Builtin method calls assume the TLS register has been set.
loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadWasmTlsRegFromFrame();
CallSiteDesc desc(call.lineOrBytecode, CallSiteDesc::Symbolic);
masm.wasmCallBuiltinInstanceMethod(instanceArg, builtin);
@ -3317,56 +3298,56 @@ class BaseCompiler
void loadGlobalVarI32(unsigned globalDataOffset, RegI32 r)
{
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadWasmTlsRegFromFrame(tmp);
masm.load32(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
}
void loadGlobalVarI64(unsigned globalDataOffset, RegI64 r)
{
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadWasmTlsRegFromFrame(tmp);
masm.load64(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
}
void loadGlobalVarF32(unsigned globalDataOffset, RegF32 r)
{
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadWasmTlsRegFromFrame(tmp);
masm.loadFloat32(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
}
void loadGlobalVarF64(unsigned globalDataOffset, RegF64 r)
{
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadWasmTlsRegFromFrame(tmp);
masm.loadDouble(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
}
void storeGlobalVarI32(unsigned globalDataOffset, RegI32 r)
{
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadWasmTlsRegFromFrame(tmp);
masm.store32(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
}
void storeGlobalVarI64(unsigned globalDataOffset, RegI64 r)
{
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadWasmTlsRegFromFrame(tmp);
masm.store64(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
}
void storeGlobalVarF32(unsigned globalDataOffset, RegF32 r)
{
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadWasmTlsRegFromFrame(tmp);
masm.storeFloat32(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
}
void storeGlobalVarF64(unsigned globalDataOffset, RegF64 r)
{
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadWasmTlsRegFromFrame(tmp);
masm.storeDouble(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
}
@ -5804,11 +5785,8 @@ BaseCompiler::emitCallArgs(const ValTypeVector& argTypes, FunctionCall& baseline
for (size_t i = 0; i < numArgs; ++i)
passArg(baselineCall, argTypes[i], peek(numArgs - 1 - i));
// Pass the TLS pointer as a hidden argument in WasmTlsReg. Load
// it directly out if its stack slot so we don't interfere with
// the stk_.
if (baselineCall.loadTlsBefore)
loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadWasmTlsRegFromFrame();
return true;
}
@ -6450,7 +6428,7 @@ BaseCompiler::maybeLoadTlsForAccess(bool omitBoundsCheck)
RegI32 tls = invalidI32();
if (needTlsForAccess(omitBoundsCheck)) {
tls = needI32();
loadFromFramePtr(tls, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadWasmTlsRegFromFrame(tls);
}
return tls;
}
@ -7473,7 +7451,6 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env,
#ifdef DEBUG
scratchRegisterTaken_(false),
#endif
tlsSlot_(0),
#ifdef JS_CODEGEN_X64
specific_rax(RegI64(Register64(rax))),
specific_rcx(RegI64(Register64(rcx))),
@ -7533,15 +7510,9 @@ BaseCompiler::init()
const ValTypeVector& args = func_.sig().args();
// localInfo_ contains an entry for every local in locals_, followed by
// entries for special locals. Currently the only special local is the TLS
// pointer.
tlsSlot_ = locals_.length();
if (!localInfo_.resize(locals_.length() + 1))
if (!localInfo_.resize(locals_.length()))
return false;
localInfo_[tlsSlot_].init(MIRType::Pointer, TlsSlotOffset);
BaseLocalIter i(locals_, args.length(), debugEnabled_);
varLow_ = i.reservedSize();
for (; !i.done() && i.index() < args.length(); i++) {

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

@ -1,136 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* Copyright 2016 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "wasm/WasmDebugFrame.h"
#include "vm/EnvironmentObject.h"
#include "wasm/WasmBaselineCompile.h"
#include "wasm/WasmInstance.h"
#include "jsobjinlines.h"
using namespace js;
using namespace js::wasm;
Instance*
DebugFrame::instance() const
{
return tlsData_->instance;
}
GlobalObject*
DebugFrame::global() const
{
return &instance()->object()->global();
}
JSObject*
DebugFrame::environmentChain() const
{
return &global()->lexicalEnvironment();
}
void
DebugFrame::observeFrame(JSContext* cx)
{
if (observing_)
return;
instance()->code().adjustEnterAndLeaveFrameTrapsState(cx, /* enabled = */ true);
observing_ = true;
}
void
DebugFrame::leaveFrame(JSContext* cx)
{
if (!observing_)
return;
instance()->code().adjustEnterAndLeaveFrameTrapsState(cx, /* enabled = */ 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
DebugFrame::getLocal(uint32_t localIndex, MutableHandleValue vp)
{
ValTypeVector locals;
size_t argsLength;
if (!instance()->code().debugGetLocalTypes(funcIndex(), &locals, &argsLength))
return false;
BaseLocalIter iter(locals, argsLength, /* debugEnabled = */ true);
while (!iter.done() && iter.index() < localIndex)
iter++;
MOZ_ALWAYS_TRUE(!iter.done());
uint8_t* frame = static_cast<uint8_t*>((void*)this) + offsetOfFrame();
void* dataPtr = frame - iter.frameOffset();
switch (iter.mirType()) {
case jit::MIRType::Int32:
vp.set(Int32Value(*static_cast<int32_t*>(dataPtr)));
break;
case jit::MIRType::Int64:
// Just display as a Number; it's ok if we lose some precision
vp.set(NumberValue((double)*static_cast<int64_t*>(dataPtr)));
break;
case jit::MIRType::Float32:
vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<float*>(dataPtr))));
break;
case jit::MIRType::Double:
vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<double*>(dataPtr))));
break;
default:
MOZ_CRASH("local type");
}
return true;
}

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

@ -1,126 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* Copyright 2016 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef wasmdebugframe_js_h
#define wasmdebugframe_js_h
#include "gc/Barrier.h"
#include "js/RootingAPI.h"
#include "js/TracingAPI.h"
#include "wasm/WasmTypes.h"
namespace js {
class WasmFunctionCallObject;
namespace wasm {
class DebugFrame
{
union
{
int32_t resultI32_;
int64_t resultI64_;
float resultF32_;
double resultF64_;
};
js::Value cachedReturnJSValue_;
// The fields below are initialized by the baseline compiler.
uint32_t funcIndex_;
union
{
struct
{
bool observing_ : 1;
bool isDebuggee_ : 1;
bool prevUpToDate_ : 1;
bool hasCachedSavedFrame_ : 1;
bool hasCachedReturnJSValue_ : 1;
};
void* reserved1_;
};
TlsData* tlsData_;
Frame frame_;
explicit DebugFrame() {}
void StaticAsserts() {
// VS2017 doesn't consider offsetOfResults() etc. to be constexpr, so we have to use
// offsetof directly. These asserts can't be at class-level because the type is incomplete.
static_assert(offsetof(DebugFrame, resultI32_) == 0, "results shall be at offset 0");
static_assert(offsetof(DebugFrame, tlsData_) + sizeof(TlsData*) ==
offsetof(DebugFrame, frame_),
"TLS pointer must be a field just before the wasm frame");
static_assert(sizeof(DebugFrame) % 8 == 0,
"DebugFrame is 8-bytes aligned for AbstractFramePtr");
}
public:
inline uint32_t funcIndex() const { return funcIndex_; }
inline TlsData* tlsData() const { return tlsData_; }
inline Frame& frame() { return frame_; }
Instance* instance() const;
GlobalObject* global() const;
JSObject* environmentChain() const;
void observeFrame(JSContext* cx);
void leaveFrame(JSContext* cx);
void trace(JSTracer* trc);
// These are opaque boolean flags used by the debugger and
// saved-frame-chains code.
inline bool isDebuggee() const { return isDebuggee_; }
inline void setIsDebuggee() { isDebuggee_ = true; }
inline void unsetIsDebuggee() { isDebuggee_ = false; }
inline bool prevUpToDate() const { return prevUpToDate_; }
inline void setPrevUpToDate() { prevUpToDate_ = true; }
inline void unsetPrevUpToDate() { prevUpToDate_ = false; }
inline bool hasCachedSavedFrame() const { return hasCachedSavedFrame_; }
inline void setHasCachedSavedFrame() { hasCachedSavedFrame_ = true; }
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_); }
static constexpr size_t offsetOfFlagsWord() { return offsetof(DebugFrame, reserved1_); }
static constexpr size_t offsetOfFuncIndex() { return offsetof(DebugFrame, funcIndex_); }
static constexpr size_t offsetOfTlsData() { return offsetof(DebugFrame, tlsData_); }
static constexpr size_t offsetOfFrame() { return offsetof(DebugFrame, frame_); }
};
} // namespace wasm
} // namespace js
#endif // wasmdebugframe_js_h

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

@ -18,7 +18,6 @@
#include "wasm/WasmFrameIterator.h"
#include "wasm/WasmDebugFrame.h"
#include "wasm/WasmInstance.h"
#include "jit/MacroAssembler-inl.h"

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

@ -28,6 +28,7 @@
#include "jit/MacroAssembler.h"
#include "js/Conversions.h"
#include "vm/Interpreter.h"
#include "wasm/WasmBaselineCompile.h"
#include "wasm/WasmInstance.h"
#include "wasm/WasmSerialize.h"
#include "wasm/WasmSignalHandlers.h"
@ -115,7 +116,7 @@ WasmHandleDebugTrap()
return true;
DebugFrame* frame = iter.debugFrame();
frame->setIsDebuggee();
frame->observeFrame(cx);
frame->observe(cx);
// TODO call onEnterFrame
JSTrapStatus status = Debugger::onEnterFrame(cx, frame);
if (status == JSTRAP_RETURN) {
@ -131,7 +132,7 @@ WasmHandleDebugTrap()
DebugFrame* frame = iter.debugFrame();
frame->updateReturnJSValue();
bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, true);
frame->leaveFrame(cx);
frame->leave(cx);
return ok;
}
@ -196,7 +197,7 @@ WasmHandleThrow()
// TODO properly handle success and resume wasm execution.
JS_ReportErrorASCII(cx, "Unexpected success from onLeaveFrame");
}
frame->leaveFrame(cx);
frame->leave(cx);
}
}
@ -998,3 +999,122 @@ wasm::ComputeMappedSize(uint32_t maxSize)
}
#endif // WASM_HUGE_MEMORY
void
DebugFrame::alignmentStaticAsserts()
{
// VS2017 doesn't consider offsetOfFrame() to be a constexpr, so we have
// to use offsetof directly. These asserts can't be at class-level
// because the type is incomplete.
static_assert(WasmStackAlignment >= Alignment,
"Aligned by ABI before pushing DebugFrame");
static_assert((offsetof(DebugFrame, frame_) + sizeof(Frame)) % Alignment == 0,
"Aligned after pushing DebugFrame");
}
GlobalObject*
DebugFrame::global() const
{
return &instance()->object()->global();
}
JSObject*
DebugFrame::environmentChain() const
{
return &global()->lexicalEnvironment();
}
bool
DebugFrame::getLocal(uint32_t localIndex, MutableHandleValue vp)
{
ValTypeVector locals;
size_t argsLength;
if (!instance()->code().debugGetLocalTypes(funcIndex(), &locals, &argsLength))
return false;
BaseLocalIter iter(locals, argsLength, /* debugEnabled = */ true);
while (!iter.done() && iter.index() < localIndex)
iter++;
MOZ_ALWAYS_TRUE(!iter.done());
uint8_t* frame = static_cast<uint8_t*>((void*)this) + offsetOfFrame();
void* dataPtr = frame - iter.frameOffset();
switch (iter.mirType()) {
case jit::MIRType::Int32:
vp.set(Int32Value(*static_cast<int32_t*>(dataPtr)));
break;
case jit::MIRType::Int64:
// Just display as a Number; it's ok if we lose some precision
vp.set(NumberValue((double)*static_cast<int64_t*>(dataPtr)));
break;
case jit::MIRType::Float32:
vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<float*>(dataPtr))));
break;
case jit::MIRType::Double:
vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<double*>(dataPtr))));
break;
default:
MOZ_CRASH("local type");
}
return true;
}
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");
}
}
HandleValue
DebugFrame::returnValue() const
{
MOZ_ASSERT(hasCachedReturnJSValue_);
return HandleValue::fromMarkedLocation(&cachedReturnJSValue_);
}
void
DebugFrame::clearReturnJSValue()
{
hasCachedReturnJSValue_ = true;
cachedReturnJSValue_.setUndefined();
}
void
DebugFrame::observe(JSContext* cx)
{
if (!observing_) {
instance()->code().adjustEnterAndLeaveFrameTrapsState(cx, /* enabled = */ true);
observing_ = true;
}
}
void
DebugFrame::leave(JSContext* cx)
{
if (observing_) {
instance()->code().adjustEnterAndLeaveFrameTrapsState(cx, /* enabled = */ false);
observing_ = false;
}
}

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

@ -41,6 +41,7 @@
namespace js {
class PropertyName;
class WasmFunctionCallObject;
namespace jit {
struct BaselineScript;
enum class RoundingMode;
@ -1465,6 +1466,116 @@ struct Frame
// The return address pushed by the call (in the case of ARM/MIPS the return
// address is pushed by the first instruction of the prologue).
void* returnAddress;
// Helper functions:
Instance* instance() const { return tls->instance; }
};
// A DebugFrame is a Frame with additional fields that are added after the
// normal function prologue by the baseline compiler. If a Module is compiled
// with debugging enabled, then all its code creates DebugFrames on the stack
// instead of just Frames. These extra fields are used by the Debugger API.
class DebugFrame
{
// The results field left uninitialized and only used during the baseline
// compiler's return sequence to allow the debugger to inspect and modify
// the return value of a frame being debugged.
union
{
int32_t resultI32_;
int64_t resultI64_;
float resultF32_;
double resultF64_;
};
// The returnValue() method returns a HandleValue pointing to this field.
js::Value cachedReturnJSValue_;
// The function index of this frame. Technically, this could be derived
// given a PC into this frame (which could lookup the CodeRange which has
// the function index), but this isn't always readily available.
uint32_t funcIndex_;
// Flags whose meaning are described below.
union
{
struct
{
bool observing_ : 1;
bool isDebuggee_ : 1;
bool prevUpToDate_ : 1;
bool hasCachedSavedFrame_ : 1;
bool hasCachedReturnJSValue_ : 1;
};
void* flagsWord_;
};
// Padding so that DebugFrame has Alignment.
#if JS_BITS_PER_WORD == 32
void* padding_;
#endif
// The Frame goes at the end since the stack grows down.
Frame frame_;
public:
Frame& frame() { return frame_; }
uint32_t funcIndex() const { return funcIndex_; }
Instance* instance() const { return frame_.instance(); }
GlobalObject* global() const;
JSObject* environmentChain() const;
bool getLocal(uint32_t localIndex, MutableHandleValue vp);
// The return value must be written from the unboxed representation in the
// results union into cachedReturnJSValue_ by updateReturnJSValue() before
// returnValue() can return a Handle to it.
void updateReturnJSValue();
HandleValue returnValue() const;
void clearReturnJSValue();
// Once the debugger observes a frame, it must be notified via
// onLeaveFrame() before the frame is popped. Calling observe() ensures the
// leave frame traps are enabled. Both methods are idempotent so the caller
// doesn't have to worry about calling them more than once.
void observe(JSContext* cx);
void leave(JSContext* cx);
// The 'isDebugge' bit is initialized to false and set by the WebAssembly
// runtime right before a frame is exposed to the debugger, as required by
// the Debugger API. The bit is then used for Debugger-internal purposes
// afterwards.
bool isDebuggee() const { return isDebuggee_; }
void setIsDebuggee() { isDebuggee_ = true; }
void unsetIsDebuggee() { isDebuggee_ = false; }
// These are opaque boolean flags used by the debugger to implement
// AbstractFramePtr. They are initialized to false and not otherwise read or
// written by wasm code or runtime.
bool prevUpToDate() const { return prevUpToDate_; }
void setPrevUpToDate() { prevUpToDate_ = true; }
void unsetPrevUpToDate() { prevUpToDate_ = false; }
bool hasCachedSavedFrame() const { return hasCachedSavedFrame_; }
void setHasCachedSavedFrame() { hasCachedSavedFrame_ = true; }
// DebugFrame is accessed directly by JIT code.
static constexpr size_t offsetOfResults() { return offsetof(DebugFrame, resultI32_); }
static constexpr size_t offsetOfFlagsWord() { return offsetof(DebugFrame, flagsWord_); }
static constexpr size_t offsetOfFuncIndex() { return offsetof(DebugFrame, funcIndex_); }
static constexpr size_t offsetOfFrame() { return offsetof(DebugFrame, frame_); }
// DebugFrames are aligned to 8-byte aligned, allowing them to be placed in
// an AbstractFramePtr.
static const unsigned Alignment = 8;
static void alignmentStaticAsserts();
};
} // namespace wasm