зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c.
This commit is contained in:
Коммит
d2ef169276
|
@ -82,7 +82,6 @@ endif
|
|||
endif
|
||||
|
||||
ifeq ($(OS_ARCH),OS2)
|
||||
RESFILE=splashos2.res
|
||||
RCFLAGS += -DMOZ_PHOENIX
|
||||
RCFLAGS += -DFIREFOX_ICO='"$(DIST)/branding/firefox-os2.ico"' -DDOCUMENT_ICO='"$(DIST)/branding/document-os2.ico"'
|
||||
endif
|
||||
|
|
|
@ -148,7 +148,7 @@ TextTrack::RemoveRegion(const TextTrackRegion& aRegion, ErrorResult& aRv)
|
|||
void
|
||||
TextTrack::UpdateActiveCueList()
|
||||
{
|
||||
if (mMode == TextTrackMode::Disabled || !mTextTrackList) {
|
||||
if (!mTextTrackList) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -188,15 +188,20 @@ TextTrack::UpdateActiveCueList()
|
|||
|
||||
TextTrackCueList*
|
||||
TextTrack::GetActiveCues() {
|
||||
UpdateActiveCueList();
|
||||
return mActiveCueList;
|
||||
if (mMode != TextTrackMode::Disabled) {
|
||||
UpdateActiveCueList();
|
||||
return mActiveCueList;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
TextTrack::GetActiveCueArray(nsTArray<nsRefPtr<TextTrackCue> >& aCues)
|
||||
{
|
||||
UpdateActiveCueList();
|
||||
mActiveCueList->GetArray(aCues);
|
||||
if (mMode != TextTrackMode::Disabled) {
|
||||
UpdateActiveCueList();
|
||||
mActiveCueList->GetArray(aCues);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t
|
||||
|
|
|
@ -322,6 +322,7 @@ public:
|
|||
void SetDisplayState(HTMLDivElement* aDisplayState)
|
||||
{
|
||||
mDisplayState = aDisplayState;
|
||||
mReset = false;
|
||||
}
|
||||
|
||||
bool HasBeenReset()
|
||||
|
|
|
@ -5,5 +5,6 @@ support-files =
|
|||
basic.vtt
|
||||
seek.webm
|
||||
|
||||
[test_texttrackcue_chrome.html]
|
||||
[test_texttrack_chrome.html]
|
||||
[test_texttracklist_chrome.html]
|
||||
|
|
|
@ -173,6 +173,15 @@ SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true]]},
|
|||
|
||||
is(cueList.length, 6, "Cue list length should be 6.");
|
||||
|
||||
video.currentTime = 2;
|
||||
isnot(trackElement.track.activeCues, null);
|
||||
|
||||
trackElement.track.mode = "disabled";
|
||||
is(trackElement.track.activeCues, null);
|
||||
|
||||
trackElement.track.mode = "showing";
|
||||
video.currentTime = 0;
|
||||
|
||||
// Test TextTrack::ActiveCues.
|
||||
var cueInfo = [
|
||||
{ startTime: 0.51, endTime: 0.71, ids: ["Cue 01"] },
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=967157
|
||||
-->
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>Test for Bug 967157 - Setting TextTrackCue::DisplayState should set TextTrackCue::HasBeenReset to false</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true]]},
|
||||
function() {
|
||||
var cue = new VTTCue(0, 1, "Some text.");
|
||||
is(cue.hasBeenReset, false, "Cue's hasBeenReset flag should be false.");
|
||||
is(cue.displayState, null, "Cue's displayState should be null.");
|
||||
|
||||
cue.startTime = 0.5;
|
||||
is(cue.hasBeenReset, true, "Cue's hasBeenReset flag should now be true.");
|
||||
|
||||
cue.displayState = document.createElement("div");
|
||||
is(cue.hasBeenReset, false, "Cue's hasBeenReset flag should now be false.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
);
|
||||
</script>
|
|
@ -7,8 +7,6 @@ LIB_IS_C_ONLY = 1
|
|||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
DEFFILE = $(CURDIR)/sqlite-processed.def
|
||||
RCFILE = sqlite.rc
|
||||
RESFILE = sqlite.res
|
||||
|
||||
GARBAGE += \
|
||||
sqlite-version.h \
|
||||
|
|
|
@ -66,3 +66,7 @@ if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_MEMORY']:
|
|||
# disable PGO for Sun Studio
|
||||
if CONFIG['SOLARIS_SUNPRO_CC']:
|
||||
NO_PGO = True
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
RCFILE = 'sqlite.rc'
|
||||
RESFILE = 'sqlite.res'
|
||||
|
|
|
@ -20,8 +20,6 @@ EXTRA_DSO_LDOPTS = \
|
|||
endif
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
|
||||
RCFILE = nptest.rc
|
||||
RESFILE = nptest.res
|
||||
DEFFILE = $(win_srcdir)/nptest.def
|
||||
OS_LIBS += $(call EXPAND_LIBNAME,msimg32)
|
||||
|
||||
|
|
|
@ -42,3 +42,7 @@ elif toolkit == 'windows':
|
|||
]
|
||||
|
||||
FORCE_SHARED_LIB = True
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
RCFILE = 'nptest.rc'
|
||||
RESFILE = 'nptest.res'
|
||||
|
|
|
@ -167,7 +167,9 @@ private:
|
|||
static bool
|
||||
Slice(JSContext* aCx, unsigned aArgc, jsval* aVp)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(aCx, JS_THIS_OBJECT(aCx, aVp));
|
||||
JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, args.thisv().toObjectOrNull());
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
@ -179,7 +181,7 @@ private:
|
|||
|
||||
double start = 0, end = 0;
|
||||
JS::Rooted<JSString*> jsContentType(aCx, JS_GetEmptyString(JS_GetRuntime(aCx)));
|
||||
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "/IIS", &start,
|
||||
if (!JS_ConvertArguments(aCx, args, "/IIS", &start,
|
||||
&end, jsContentType.address())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -203,7 +205,7 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(rtnObj));
|
||||
args.rval().setObject(*rtnObj);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -453,7 +453,7 @@ static HWND CreateControl(LPCTSTR aType,
|
|||
HWND hWnd = ::CreateWindow (aType, str.get(),
|
||||
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | aStyle,
|
||||
aRect.x, aRect.y, aRect.width, aRect.height,
|
||||
(HWND)aHdlg, (HMENU)aId,
|
||||
(HWND)aHdlg, (HMENU)(intptr_t)aId,
|
||||
aHInst, nullptr);
|
||||
if (hWnd == nullptr) return nullptr;
|
||||
|
||||
|
|
|
@ -27,8 +27,6 @@
|
|||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
RESFILE = winEmbed.res
|
||||
|
||||
LIBS = \
|
||||
$(DEPTH)/profile/dirserviceprovider/standalone/$(LIB_PREFIX)profdirserviceprovidersa_s.$(LIB_SUFFIX) \
|
||||
$(XPCOM_STANDALONE_GLUE_LDOPTS) \
|
||||
|
|
|
@ -15,3 +15,5 @@ SOURCES += [
|
|||
XPI_NAME = 'winembed'
|
||||
|
||||
DEFINES['XPCOM_GLUE'] = True
|
||||
|
||||
RESFILE = 'winEmbed.res'
|
||||
|
|
|
@ -14,7 +14,6 @@ endif
|
|||
# Target: 'libEGL'
|
||||
# Links with: 'libGLESv2'
|
||||
DEFFILE = $(srcdir)/libEGL.def
|
||||
RCFILE = $(srcdir)/libEGL.rc
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
@ -42,3 +42,5 @@ if not CONFIG['MOZ_DEBUG']:
|
|||
DEFINES['_SECURE_SCL'] = 0
|
||||
|
||||
DEFINES['ANGLE_COMPILE_OPTIMIZATION_LEVEL'] = 'D3DCOMPILE_OPTIMIZATION_LEVEL1'
|
||||
|
||||
RCFILE = SRCDIR + '/libEGL.rc'
|
||||
|
|
|
@ -11,7 +11,6 @@ OS_CPPFLAGS += -EHsc
|
|||
endif
|
||||
|
||||
DEFFILE = $(srcdir)/libGLESv2.def
|
||||
RCFILE = $(srcdir)/libGLESv2.rc
|
||||
|
||||
# End build_angle.gypi transcription.
|
||||
|
||||
|
|
|
@ -193,3 +193,5 @@ if not CONFIG['MOZ_DEBUG']:
|
|||
DEFINES['_SECURE_SCL'] = 0
|
||||
|
||||
DEFINES['ANGLE_COMPILE_OPTIMIZATION_LEVEL'] = 'D3DCOMPILE_OPTIMIZATION_LEVEL1'
|
||||
|
||||
RCFILE = SRCDIR + '/libGLESv2.rc'
|
||||
|
|
|
@ -619,9 +619,10 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
|||
WriteParam(aMsg, aParam.mPresShellId);
|
||||
WriteParam(aMsg, aParam.mIsRoot);
|
||||
WriteParam(aMsg, aParam.mHasScrollgrab);
|
||||
WriteParam(aMsg, aParam.mUpdateScrollOffset);
|
||||
WriteParam(aMsg, aParam.mDisableScrollingX);
|
||||
WriteParam(aMsg, aParam.mDisableScrollingY);
|
||||
WriteParam(aMsg, aParam.mUpdateScrollOffset);
|
||||
WriteParam(aMsg, aParam.mScrollGeneration);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
|
@ -641,9 +642,10 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
|||
ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mIsRoot) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHasScrollgrab) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mUpdateScrollOffset) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mDisableScrollingX) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mDisableScrollingY));
|
||||
ReadParam(aMsg, aIter, &aResult->mDisableScrollingY) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mUpdateScrollOffset) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScrollGeneration));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -150,7 +150,21 @@ TextureClientD3D11::TextureClientD3D11(gfx::SurfaceFormat aFormat, TextureFlags
|
|||
{}
|
||||
|
||||
TextureClientD3D11::~TextureClientD3D11()
|
||||
{}
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// An Azure DrawTarget needs to be locked when it gets nullptr'ed as this is
|
||||
// when it calls EndDraw. This EndDraw should not execute anything so it
|
||||
// shouldn't -really- need the lock but the debug layer chokes on this.
|
||||
if (mDrawTarget) {
|
||||
MOZ_ASSERT(!mIsLocked);
|
||||
MOZ_ASSERT(mTexture);
|
||||
MOZ_ASSERT(mDrawTarget->refCount() == 1);
|
||||
LockD3DTexture(mTexture.get());
|
||||
mDrawTarget = nullptr;
|
||||
UnlockD3DTexture(mTexture.get());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
TextureClientD3D11::Lock(OpenMode aMode)
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
#define APZC_LOG_FM(fm, prefix, ...) \
|
||||
APZC_LOG(prefix ":" \
|
||||
" i=(%ld %lld) cb=(%d %d %d %d) dp=(%.3f %.3f %.3f %.3f) v=(%.3f %.3f %.3f %.3f) " \
|
||||
"s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) %d\n", \
|
||||
"s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) u=(%d %llu)\n", \
|
||||
__VA_ARGS__, \
|
||||
fm.mPresShellId, fm.mScrollId, \
|
||||
fm.mCompositionBounds.x, fm.mCompositionBounds.y, fm.mCompositionBounds.width, fm.mCompositionBounds.height, \
|
||||
|
@ -75,7 +75,7 @@
|
|||
fm.mScrollOffset.x, fm.mScrollOffset.y, \
|
||||
fm.mScrollableRect.x, fm.mScrollableRect.y, fm.mScrollableRect.width, fm.mScrollableRect.height, \
|
||||
fm.mDevPixelsPerCSSPixel.scale, fm.mResolution.scale, fm.mCumulativeResolution.scale, fm.mZoom.scale, \
|
||||
fm.GetScrollOffsetUpdated()); \
|
||||
fm.GetScrollOffsetUpdated(), fm.GetScrollGeneration()); \
|
||||
|
||||
// Static helper functions
|
||||
namespace {
|
||||
|
|
|
@ -1575,7 +1575,7 @@ void
|
|||
DirectWriteFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
|
||||
{
|
||||
// lookup the family
|
||||
nsAutoTArray<char16_t, 32> famName;
|
||||
nsAutoTArray<wchar_t, 32> famName;
|
||||
|
||||
uint32_t len = aFamilyName.Length();
|
||||
famName.SetLength(len + 1);
|
||||
|
|
|
@ -222,11 +222,6 @@ else
|
|||
NSPR_STATIC_PATH = $(DIST)/lib
|
||||
endif
|
||||
|
||||
ifdef MOZ_ETW
|
||||
# This will get the ETW provider resources into the library mozjs.dll
|
||||
RESFILE = ETWProvider.res
|
||||
endif
|
||||
|
||||
# HP-UX does not require the extra linking of "-lm"
|
||||
ifeq (,$(filter HP-UX WINNT OS2,$(OS_ARCH)))
|
||||
EXTRA_LIBS += -lm
|
||||
|
|
|
@ -107,7 +107,7 @@ Library::Create(JSContext* cx, jsval path_, JSCTypesCallbacks* callbacks)
|
|||
#ifdef XP_WIN
|
||||
// On Windows, converting to native charset may corrupt path string.
|
||||
// So, we have to use Unicode path directly.
|
||||
const char16_t* pathChars = JS_GetFlatStringChars(pathStr);
|
||||
char16ptr_t pathChars = JS_GetFlatStringChars(pathStr);
|
||||
if (!pathChars)
|
||||
return nullptr;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "jit/Ion.h"
|
||||
#include "jit/IonSpewer.h"
|
||||
#include "jit/JitCompartment.h"
|
||||
#include "jit/SnapshotReader.h"
|
||||
#include "jit/Snapshots.h"
|
||||
|
||||
#include "jit/IonFrameIterator-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
|
|
@ -91,9 +91,6 @@ namespace jit {
|
|||
|
||||
static const BailoutId INVALID_BAILOUT_ID = BailoutId(-1);
|
||||
|
||||
static const uint32_t BAILOUT_KIND_BITS = 3;
|
||||
static const uint32_t BAILOUT_RESUME_BITS = 1;
|
||||
|
||||
// Keep this arbitrarily small for now, for testing.
|
||||
static const uint32_t BAILOUT_TABLE_SIZE = 16;
|
||||
|
||||
|
|
|
@ -475,7 +475,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
if (excInfo)
|
||||
exprStackSlots = excInfo->numExprSlots;
|
||||
else
|
||||
exprStackSlots = iter.slots() - (script->nfixed() + CountArgSlots(script, fun));
|
||||
exprStackSlots = iter.allocations() - (script->nfixed() + CountArgSlots(script, fun));
|
||||
|
||||
builder.resetFramePushed();
|
||||
|
||||
|
@ -623,9 +623,9 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
size_t thisvOffset = builder.framePushed() + IonJSFrameLayout::offsetOfThis();
|
||||
*builder.valuePointerAtStackOffset(thisvOffset) = thisv;
|
||||
|
||||
JS_ASSERT(iter.slots() >= CountArgSlots(script, fun));
|
||||
JS_ASSERT(iter.allocations() >= CountArgSlots(script, fun));
|
||||
IonSpew(IonSpew_BaselineBailouts, " frame slots %u, nargs %u, nfixed %u",
|
||||
iter.slots(), fun->nargs(), script->nfixed());
|
||||
iter.allocations(), fun->nargs(), script->nfixed());
|
||||
|
||||
if (!callerPC) {
|
||||
// This is the first frame. Store the formals in a Vector until we
|
||||
|
|
|
@ -28,14 +28,6 @@ class AsmJSModule;
|
|||
|
||||
namespace jit {
|
||||
|
||||
// The maximum size of any buffer associated with an assembler or code object.
|
||||
// This is chosen to not overflow a signed integer, leaving room for an extra
|
||||
// bit on offsets.
|
||||
static const uint32_t MAX_BUFFER_SIZE = (1 << 30) - 1;
|
||||
|
||||
// Maximum number of scripted arg slots.
|
||||
static const uint32_t SNAPSHOT_MAX_NARGS = 127;
|
||||
|
||||
class MacroAssembler;
|
||||
class CodeOffsetLabel;
|
||||
class PatchableBackedge;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "jstypes.h"
|
||||
|
||||
#include "jit/IonCode.h"
|
||||
#include "jit/SnapshotReader.h"
|
||||
#include "jit/Snapshots.h"
|
||||
|
||||
namespace js {
|
||||
class ActivationIterator;
|
||||
|
@ -237,12 +237,17 @@ class SnapshotIterator : public SnapshotReader
|
|||
IonScript *ionScript_;
|
||||
|
||||
private:
|
||||
bool hasLocation(const SnapshotReader::Location &loc);
|
||||
uintptr_t fromLocation(const SnapshotReader::Location &loc);
|
||||
// Read a spilled register from the machine state.
|
||||
bool hasRegister(const Location &loc);
|
||||
uintptr_t fromRegister(const Location &loc);
|
||||
|
||||
Value slotValue(const Slot &slot);
|
||||
bool slotReadable(const Slot &slot);
|
||||
void warnUnreadableSlot();
|
||||
// Read an uintptr_t from the stack.
|
||||
bool hasStack(const Location &loc);
|
||||
uintptr_t fromStack(const Location &loc);
|
||||
|
||||
Value allocationValue(const RValueAllocation &a);
|
||||
bool allocationReadable(const RValueAllocation &a);
|
||||
void warnUnreadableAllocation();
|
||||
|
||||
public:
|
||||
SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset,
|
||||
|
@ -251,15 +256,19 @@ class SnapshotIterator : public SnapshotReader
|
|||
SnapshotIterator(const IonBailoutIterator &iter);
|
||||
SnapshotIterator();
|
||||
|
||||
Value skip() {
|
||||
readAllocation();
|
||||
return UndefinedValue();
|
||||
}
|
||||
Value read() {
|
||||
return slotValue(readSlot());
|
||||
return allocationValue(readAllocation());
|
||||
}
|
||||
Value maybeRead(bool silentFailure = false) {
|
||||
Slot s = readSlot();
|
||||
if (slotReadable(s))
|
||||
return slotValue(s);
|
||||
RValueAllocation a = readAllocation();
|
||||
if (allocationReadable(a))
|
||||
return allocationValue(a);
|
||||
if (!silentFailure)
|
||||
warnUnreadableSlot();
|
||||
warnUnreadableAllocation();
|
||||
return UndefinedValue();
|
||||
}
|
||||
|
||||
|
@ -303,15 +312,15 @@ class SnapshotIterator : public SnapshotReader
|
|||
}
|
||||
}
|
||||
|
||||
Value maybeReadSlotByIndex(size_t index) {
|
||||
Value maybeReadAllocByIndex(size_t index) {
|
||||
while (index--) {
|
||||
JS_ASSERT(moreSlots());
|
||||
JS_ASSERT(moreAllocations());
|
||||
skip();
|
||||
}
|
||||
|
||||
Value s = maybeRead(true);
|
||||
|
||||
while (moreSlots())
|
||||
while (moreAllocations())
|
||||
skip();
|
||||
|
||||
return s;
|
||||
|
@ -422,8 +431,8 @@ class InlineFrameIteratorMaybeGC
|
|||
|
||||
// Skip over all slots untill we get to the last slots (= arguments slots of callee)
|
||||
// the +3 is for [this], [returnvalue], [scopechain], and maybe +1 for [argsObj]
|
||||
JS_ASSERT(parent_s.slots() >= nactual + 3 + argsObjAdj);
|
||||
unsigned skip = parent_s.slots() - nactual - 3 - argsObjAdj;
|
||||
JS_ASSERT(parent_s.allocations() >= nactual + 3 + argsObjAdj);
|
||||
unsigned skip = parent_s.allocations() - nactual - 3 - argsObjAdj;
|
||||
for (unsigned j = 0; j < skip; j++)
|
||||
parent_s.skip();
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "jit/ParallelFunctions.h"
|
||||
#include "jit/PcScriptCache.h"
|
||||
#include "jit/Safepoints.h"
|
||||
#include "jit/SnapshotReader.h"
|
||||
#include "jit/Snapshots.h"
|
||||
#include "jit/VMFunctions.h"
|
||||
#include "vm/ForkJoin.h"
|
||||
#include "vm/Interpreter.h"
|
||||
|
@ -1319,19 +1319,30 @@ SnapshotIterator::SnapshotIterator()
|
|||
}
|
||||
|
||||
bool
|
||||
SnapshotIterator::hasLocation(const SnapshotReader::Location &loc)
|
||||
SnapshotIterator::hasRegister(const Location &loc)
|
||||
{
|
||||
return loc.isStackSlot() || machine_.has(loc.reg());
|
||||
return machine_.has(loc.reg());
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
SnapshotIterator::fromLocation(const SnapshotReader::Location &loc)
|
||||
SnapshotIterator::fromRegister(const Location &loc)
|
||||
{
|
||||
if (loc.isStackSlot())
|
||||
return ReadFrameSlot(fp_, loc.stackSlot());
|
||||
return machine_.read(loc.reg());
|
||||
}
|
||||
|
||||
bool
|
||||
SnapshotIterator::hasStack(const Location &loc)
|
||||
{
|
||||
JS_ASSERT(loc.isStackOffset());
|
||||
return true;
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
SnapshotIterator::fromStack(const Location &loc)
|
||||
{
|
||||
return ReadFrameSlot(fp_, loc.stackOffset());
|
||||
}
|
||||
|
||||
static Value
|
||||
FromObjectPayload(uintptr_t payload)
|
||||
{
|
||||
|
@ -1362,20 +1373,29 @@ FromTypedPayload(JSValueType type, uintptr_t payload)
|
|||
}
|
||||
|
||||
bool
|
||||
SnapshotIterator::slotReadable(const Slot &slot)
|
||||
SnapshotIterator::allocationReadable(const RValueAllocation &alloc)
|
||||
{
|
||||
switch (slot.mode()) {
|
||||
case SnapshotReader::DOUBLE_REG:
|
||||
return machine_.has(slot.floatReg());
|
||||
switch (alloc.mode()) {
|
||||
case RValueAllocation::DOUBLE_REG:
|
||||
return machine_.has(alloc.floatReg());
|
||||
|
||||
case SnapshotReader::TYPED_REG:
|
||||
return machine_.has(slot.reg());
|
||||
case RValueAllocation::TYPED_REG:
|
||||
return machine_.has(alloc.reg());
|
||||
|
||||
case SnapshotReader::UNTYPED:
|
||||
#if defined(JS_NUNBOX32)
|
||||
return hasLocation(slot.type()) && hasLocation(slot.payload());
|
||||
case RValueAllocation::UNTYPED_REG_REG:
|
||||
return hasRegister(alloc.type()) && hasRegister(alloc.payload());
|
||||
case RValueAllocation::UNTYPED_REG_STACK:
|
||||
return hasRegister(alloc.type()) && hasStack(alloc.payload());
|
||||
case RValueAllocation::UNTYPED_STACK_REG:
|
||||
return hasStack(alloc.type()) && hasRegister(alloc.payload());
|
||||
case RValueAllocation::UNTYPED_STACK_STACK:
|
||||
return hasStack(alloc.type()) && hasStack(alloc.payload());
|
||||
#elif defined(JS_PUNBOX64)
|
||||
return hasLocation(slot.value());
|
||||
case RValueAllocation::UNTYPED_REG:
|
||||
return hasRegister(alloc.value());
|
||||
case RValueAllocation::UNTYPED_STACK:
|
||||
return hasStack(alloc.value());
|
||||
#endif
|
||||
|
||||
default:
|
||||
|
@ -1384,71 +1404,107 @@ SnapshotIterator::slotReadable(const Slot &slot)
|
|||
}
|
||||
|
||||
Value
|
||||
SnapshotIterator::slotValue(const Slot &slot)
|
||||
SnapshotIterator::allocationValue(const RValueAllocation &alloc)
|
||||
{
|
||||
switch (slot.mode()) {
|
||||
case SnapshotReader::DOUBLE_REG:
|
||||
return DoubleValue(machine_.read(slot.floatReg()));
|
||||
switch (alloc.mode()) {
|
||||
case RValueAllocation::DOUBLE_REG:
|
||||
return DoubleValue(machine_.read(alloc.floatReg()));
|
||||
|
||||
case SnapshotReader::FLOAT32_REG:
|
||||
case RValueAllocation::FLOAT32_REG:
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
float f;
|
||||
} pun;
|
||||
pun.d = machine_.read(slot.floatReg());
|
||||
pun.d = machine_.read(alloc.floatReg());
|
||||
// The register contains the encoding of a float32. We just read
|
||||
// the bits without making any conversion.
|
||||
return Float32Value(pun.f);
|
||||
}
|
||||
|
||||
case SnapshotReader::FLOAT32_STACK:
|
||||
return Float32Value(ReadFrameFloat32Slot(fp_, slot.stackSlot()));
|
||||
case RValueAllocation::FLOAT32_STACK:
|
||||
return Float32Value(ReadFrameFloat32Slot(fp_, alloc.stackOffset()));
|
||||
|
||||
case SnapshotReader::TYPED_REG:
|
||||
return FromTypedPayload(slot.knownType(), machine_.read(slot.reg()));
|
||||
case RValueAllocation::TYPED_REG:
|
||||
return FromTypedPayload(alloc.knownType(), machine_.read(alloc.reg()));
|
||||
|
||||
case SnapshotReader::TYPED_STACK:
|
||||
case RValueAllocation::TYPED_STACK:
|
||||
{
|
||||
switch (slot.knownType()) {
|
||||
switch (alloc.knownType()) {
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
return DoubleValue(ReadFrameDoubleSlot(fp_, slot.stackSlot()));
|
||||
return DoubleValue(ReadFrameDoubleSlot(fp_, alloc.stackOffset()));
|
||||
case JSVAL_TYPE_INT32:
|
||||
return Int32Value(ReadFrameInt32Slot(fp_, slot.stackSlot()));
|
||||
return Int32Value(ReadFrameInt32Slot(fp_, alloc.stackOffset()));
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
return BooleanValue(ReadFrameBooleanSlot(fp_, slot.stackSlot()));
|
||||
return BooleanValue(ReadFrameBooleanSlot(fp_, alloc.stackOffset()));
|
||||
case JSVAL_TYPE_STRING:
|
||||
return FromStringPayload(ReadFrameSlot(fp_, slot.stackSlot()));
|
||||
return FromStringPayload(ReadFrameSlot(fp_, alloc.stackOffset()));
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
return FromObjectPayload(ReadFrameSlot(fp_, slot.stackSlot()));
|
||||
return FromObjectPayload(ReadFrameSlot(fp_, alloc.stackOffset()));
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Unexpected type");
|
||||
}
|
||||
}
|
||||
|
||||
case SnapshotReader::UNTYPED:
|
||||
{
|
||||
jsval_layout layout;
|
||||
#if defined(JS_NUNBOX32)
|
||||
layout.s.tag = (JSValueTag)fromLocation(slot.type());
|
||||
layout.s.payload.word = fromLocation(slot.payload());
|
||||
#elif defined(JS_PUNBOX64)
|
||||
layout.asBits = fromLocation(slot.value());
|
||||
#endif
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
case RValueAllocation::UNTYPED_REG_REG:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.s.tag = (JSValueTag) fromRegister(alloc.type());
|
||||
layout.s.payload.word = fromRegister(alloc.payload());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
|
||||
case SnapshotReader::JS_UNDEFINED:
|
||||
case RValueAllocation::UNTYPED_REG_STACK:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.s.tag = (JSValueTag) fromRegister(alloc.type());
|
||||
layout.s.payload.word = fromStack(alloc.payload());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
|
||||
case RValueAllocation::UNTYPED_STACK_REG:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.s.tag = (JSValueTag) fromStack(alloc.type());
|
||||
layout.s.payload.word = fromRegister(alloc.payload());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
|
||||
case RValueAllocation::UNTYPED_STACK_STACK:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.s.tag = (JSValueTag) fromStack(alloc.type());
|
||||
layout.s.payload.word = fromStack(alloc.payload());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
#elif defined(JS_PUNBOX64)
|
||||
case RValueAllocation::UNTYPED_REG:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.asBits = fromRegister(alloc.value());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
|
||||
case RValueAllocation::UNTYPED_STACK:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.asBits = fromStack(alloc.value());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
#endif
|
||||
|
||||
case RValueAllocation::JS_UNDEFINED:
|
||||
return UndefinedValue();
|
||||
|
||||
case SnapshotReader::JS_NULL:
|
||||
case RValueAllocation::JS_NULL:
|
||||
return NullValue();
|
||||
|
||||
case SnapshotReader::JS_INT32:
|
||||
return Int32Value(slot.int32Value());
|
||||
case RValueAllocation::JS_INT32:
|
||||
return Int32Value(alloc.int32Value());
|
||||
|
||||
case SnapshotReader::CONSTANT:
|
||||
return ionScript_->getConstant(slot.constantIndex());
|
||||
case RValueAllocation::CONSTANT:
|
||||
return ionScript_->getConstant(alloc.constantIndex());
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("huh?");
|
||||
|
@ -1539,14 +1595,14 @@ InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
|
|||
JS_ASSERT(numActualArgs_ != 0xbadbad);
|
||||
|
||||
// Skip over non-argument slots, as well as |this|.
|
||||
unsigned skipCount = (si_.slots() - 1) - numActualArgs_ - 1;
|
||||
unsigned skipCount = (si_.allocations() - 1) - numActualArgs_ - 1;
|
||||
for (unsigned j = 0; j < skipCount; j++)
|
||||
si_.skip();
|
||||
|
||||
Value funval = si_.read();
|
||||
|
||||
// Skip extra slots.
|
||||
while (si_.moreSlots())
|
||||
// Skip extra value allocations.
|
||||
while (si_.moreAllocations())
|
||||
si_.skip();
|
||||
|
||||
si_.nextFrame();
|
||||
|
@ -1665,9 +1721,9 @@ IonFrameIterator::numActualArgs() const
|
|||
}
|
||||
|
||||
void
|
||||
SnapshotIterator::warnUnreadableSlot()
|
||||
SnapshotIterator::warnUnreadableAllocation()
|
||||
{
|
||||
fprintf(stderr, "Warning! Tried to access unreadable IonMonkey slot (possible f.arguments).\n");
|
||||
fprintf(stderr, "Warning! Tried to access unreadable value allocation (possible f.arguments).\n");
|
||||
}
|
||||
|
||||
struct DumpOp {
|
||||
|
@ -1761,8 +1817,8 @@ InlineFrameIteratorMaybeGC<allowGC>::dump() const
|
|||
}
|
||||
|
||||
SnapshotIterator si = snapshotIterator();
|
||||
fprintf(stderr, " slots: %u\n", si.slots() - 1);
|
||||
for (unsigned i = 0; i < si.slots() - 1; i++) {
|
||||
fprintf(stderr, " slots: %u\n", si.allocations() - 1);
|
||||
for (unsigned i = 0; i < si.allocations() - 1; i++) {
|
||||
if (isFunction) {
|
||||
if (i == 0)
|
||||
fprintf(stderr, " scope chain: ");
|
||||
|
|
|
@ -17,6 +17,14 @@ namespace jit {
|
|||
typedef uint32_t SnapshotOffset;
|
||||
typedef uint32_t BailoutId;
|
||||
|
||||
// The maximum size of any buffer associated with an assembler or code object.
|
||||
// This is chosen to not overflow a signed integer, leaving room for an extra
|
||||
// bit on offsets.
|
||||
static const uint32_t MAX_BUFFER_SIZE = (1 << 30) - 1;
|
||||
|
||||
// Maximum number of scripted arg slots.
|
||||
static const uint32_t SNAPSHOT_MAX_NARGS = 127;
|
||||
|
||||
static const SnapshotOffset INVALID_SNAPSHOT_OFFSET = uint32_t(-1);
|
||||
|
||||
// Different kinds of bailouts. When extending this enum, make sure to check
|
||||
|
@ -41,6 +49,9 @@ enum BailoutKind
|
|||
Bailout_BaselineInfo
|
||||
};
|
||||
|
||||
static const uint32_t BAILOUT_KIND_BITS = 3;
|
||||
static const uint32_t BAILOUT_RESUME_BITS = 1;
|
||||
|
||||
#ifdef DEBUG
|
||||
inline const char *
|
||||
BailoutKindString(BailoutKind kind)
|
||||
|
|
|
@ -1,250 +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:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jit_SnapshotReader_h
|
||||
#define jit_SnapshotReader_h
|
||||
|
||||
#include "jit/CompactBuffer.h"
|
||||
#include "jit/IonCode.h"
|
||||
#include "jit/IonTypes.h"
|
||||
#include "jit/Registers.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
class LInstruction;
|
||||
#endif
|
||||
|
||||
// A snapshot reader reads the entries out of the compressed snapshot buffer in
|
||||
// a script. These entries describe the stack state of an Ion frame at a given
|
||||
// position in JIT code.
|
||||
class SnapshotReader
|
||||
{
|
||||
CompactBufferReader reader_;
|
||||
|
||||
uint32_t pcOffset_; // Offset from script->code.
|
||||
uint32_t slotCount_; // Number of slots.
|
||||
uint32_t frameCount_;
|
||||
BailoutKind bailoutKind_;
|
||||
uint32_t framesRead_; // Number of frame headers that have been read.
|
||||
uint32_t slotsRead_; // Number of slots that have been read.
|
||||
bool resumeAfter_;
|
||||
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
private:
|
||||
uint32_t pcOpcode_;
|
||||
uint32_t mirOpcode_;
|
||||
uint32_t mirId_;
|
||||
uint32_t lirOpcode_;
|
||||
uint32_t lirId_;
|
||||
public:
|
||||
void spewBailingFrom() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
void readSnapshotHeader();
|
||||
void readFrameHeader();
|
||||
|
||||
public:
|
||||
enum SlotMode
|
||||
{
|
||||
CONSTANT, // An index into the constant pool.
|
||||
DOUBLE_REG, // Type is double, payload is in a register.
|
||||
FLOAT32_REG, // Type is float32, payload is in a register.
|
||||
FLOAT32_STACK, // Type is float32, payload is on the stack.
|
||||
TYPED_REG, // Type is constant, payload is in a register.
|
||||
TYPED_STACK, // Type is constant, payload is on the stack.
|
||||
UNTYPED, // Type is not known.
|
||||
JS_UNDEFINED, // UndefinedValue()
|
||||
JS_NULL, // NullValue()
|
||||
JS_INT32 // Int32Value(n)
|
||||
};
|
||||
|
||||
class Location
|
||||
{
|
||||
friend class SnapshotReader;
|
||||
|
||||
// An offset that is illegal for a local variable's stack allocation.
|
||||
static const int32_t InvalidStackSlot = -1;
|
||||
|
||||
Register::Code reg_;
|
||||
int32_t stackSlot_;
|
||||
|
||||
static Location From(const Register ®) {
|
||||
Location loc;
|
||||
loc.reg_ = reg.code();
|
||||
loc.stackSlot_ = InvalidStackSlot;
|
||||
return loc;
|
||||
}
|
||||
static Location From(int32_t stackSlot) {
|
||||
JS_ASSERT(stackSlot != InvalidStackSlot);
|
||||
Location loc;
|
||||
loc.reg_ = Register::Code(0); // Quell compiler warnings.
|
||||
loc.stackSlot_ = stackSlot;
|
||||
return loc;
|
||||
}
|
||||
|
||||
public:
|
||||
Register reg() const {
|
||||
JS_ASSERT(!isStackSlot());
|
||||
return Register::FromCode(reg_);
|
||||
}
|
||||
int32_t stackSlot() const {
|
||||
JS_ASSERT(isStackSlot());
|
||||
return stackSlot_;
|
||||
}
|
||||
bool isStackSlot() const {
|
||||
return stackSlot_ != InvalidStackSlot;
|
||||
}
|
||||
};
|
||||
|
||||
class Slot
|
||||
{
|
||||
friend class SnapshotReader;
|
||||
|
||||
SlotMode mode_;
|
||||
|
||||
union {
|
||||
FloatRegister::Code fpu_;
|
||||
struct {
|
||||
JSValueType type;
|
||||
Location payload;
|
||||
} known_type_;
|
||||
#if defined(JS_NUNBOX32)
|
||||
struct {
|
||||
Location type;
|
||||
Location payload;
|
||||
} unknown_type_;
|
||||
#elif defined(JS_PUNBOX64)
|
||||
struct {
|
||||
Location value;
|
||||
} unknown_type_;
|
||||
#endif
|
||||
int32_t value_;
|
||||
};
|
||||
|
||||
Slot(SlotMode mode, JSValueType type, const Location &loc)
|
||||
: mode_(mode)
|
||||
{
|
||||
known_type_.type = type;
|
||||
known_type_.payload = loc;
|
||||
}
|
||||
Slot(const FloatRegister ®)
|
||||
: mode_(DOUBLE_REG)
|
||||
{
|
||||
fpu_ = reg.code();
|
||||
}
|
||||
Slot(SlotMode mode, const FloatRegister ®)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == FLOAT32_REG);
|
||||
fpu_ = reg.code();
|
||||
}
|
||||
Slot(SlotMode mode, const Location &loc)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == FLOAT32_STACK);
|
||||
known_type_.payload = loc;
|
||||
}
|
||||
Slot(SlotMode mode)
|
||||
: mode_(mode)
|
||||
{ }
|
||||
Slot(SlotMode mode, uint32_t index)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == CONSTANT || mode == JS_INT32);
|
||||
value_ = index;
|
||||
}
|
||||
|
||||
public:
|
||||
SlotMode mode() const {
|
||||
return mode_;
|
||||
}
|
||||
uint32_t constantIndex() const {
|
||||
JS_ASSERT(mode() == CONSTANT);
|
||||
return value_;
|
||||
}
|
||||
int32_t int32Value() const {
|
||||
JS_ASSERT(mode() == JS_INT32);
|
||||
return value_;
|
||||
}
|
||||
JSValueType knownType() const {
|
||||
JS_ASSERT(mode() == TYPED_REG || mode() == TYPED_STACK);
|
||||
return known_type_.type;
|
||||
}
|
||||
Register reg() const {
|
||||
JS_ASSERT(mode() == TYPED_REG && knownType() != JSVAL_TYPE_DOUBLE);
|
||||
return known_type_.payload.reg();
|
||||
}
|
||||
FloatRegister floatReg() const {
|
||||
JS_ASSERT(mode() == DOUBLE_REG || mode() == FLOAT32_REG);
|
||||
return FloatRegister::FromCode(fpu_);
|
||||
}
|
||||
int32_t stackSlot() const {
|
||||
JS_ASSERT(mode() == TYPED_STACK || mode() == FLOAT32_STACK);
|
||||
return known_type_.payload.stackSlot();
|
||||
}
|
||||
#if defined(JS_NUNBOX32)
|
||||
Location payload() const {
|
||||
JS_ASSERT(mode() == UNTYPED);
|
||||
return unknown_type_.payload;
|
||||
}
|
||||
Location type() const {
|
||||
JS_ASSERT(mode() == UNTYPED);
|
||||
return unknown_type_.type;
|
||||
}
|
||||
#elif defined(JS_PUNBOX64)
|
||||
Location value() const {
|
||||
JS_ASSERT(mode() == UNTYPED);
|
||||
return unknown_type_.value;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
public:
|
||||
SnapshotReader(const uint8_t *buffer, const uint8_t *end);
|
||||
|
||||
uint32_t pcOffset() const {
|
||||
return pcOffset_;
|
||||
}
|
||||
uint32_t slots() const {
|
||||
return slotCount_;
|
||||
}
|
||||
BailoutKind bailoutKind() const {
|
||||
return bailoutKind_;
|
||||
}
|
||||
bool resumeAfter() const {
|
||||
if (moreFrames())
|
||||
return false;
|
||||
return resumeAfter_;
|
||||
}
|
||||
bool moreFrames() const {
|
||||
return framesRead_ < frameCount_;
|
||||
}
|
||||
void nextFrame() {
|
||||
readFrameHeader();
|
||||
}
|
||||
Slot readSlot();
|
||||
|
||||
Value skip() {
|
||||
readSlot();
|
||||
return UndefinedValue();
|
||||
}
|
||||
|
||||
bool moreSlots() const {
|
||||
return slotsRead_ < slotCount_;
|
||||
}
|
||||
uint32_t frameCount() const {
|
||||
return frameCount_;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* jit_SnapshotReader_h */
|
|
@ -1,78 +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:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jit_SnapshotWriter_h
|
||||
#define jit_SnapshotWriter_h
|
||||
|
||||
#include "jit/Bailouts.h"
|
||||
#include "jit/CompactBuffer.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "jit/IonCode.h"
|
||||
#include "jit/Registers.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
// Collects snapshots in a contiguous buffer, which is copied into IonScript
|
||||
// memory after code generation.
|
||||
class SnapshotWriter
|
||||
{
|
||||
CompactBufferWriter writer_;
|
||||
|
||||
// These are only used to assert sanity.
|
||||
uint32_t nslots_;
|
||||
uint32_t slotsWritten_;
|
||||
uint32_t nframes_;
|
||||
uint32_t framesWritten_;
|
||||
SnapshotOffset lastStart_;
|
||||
|
||||
void writeSlotHeader(JSValueType type, uint32_t regCode);
|
||||
|
||||
public:
|
||||
SnapshotOffset startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter);
|
||||
void startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack);
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
void trackFrame(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
|
||||
uint32_t lirOpcode, uint32_t lirId);
|
||||
#endif
|
||||
void endFrame();
|
||||
|
||||
void addSlot(const FloatRegister ®);
|
||||
void addSlot(JSValueType type, const Register ®);
|
||||
void addSlot(JSValueType type, int32_t stackIndex);
|
||||
void addUndefinedSlot();
|
||||
void addNullSlot();
|
||||
void addInt32Slot(int32_t value);
|
||||
void addFloat32Slot(const FloatRegister ®);
|
||||
void addFloat32Slot(int32_t stackIndex);
|
||||
void addConstantPoolSlot(uint32_t index);
|
||||
#if defined(JS_NUNBOX32)
|
||||
void addSlot(const Register &type, const Register &payload);
|
||||
void addSlot(const Register &type, int32_t payloadStackIndex);
|
||||
void addSlot(int32_t typeStackIndex, const Register &payload);
|
||||
void addSlot(int32_t typeStackIndex, int32_t payloadStackIndex);
|
||||
#elif defined(JS_PUNBOX64)
|
||||
void addSlot(const Register &value);
|
||||
void addSlot(int32_t valueStackSlot);
|
||||
#endif
|
||||
void endSnapshot();
|
||||
|
||||
bool oom() const {
|
||||
return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return writer_.length();
|
||||
}
|
||||
const uint8_t *buffer() const {
|
||||
return writer_.buffer();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* jit_SnapshotWriter_h */
|
|
@ -4,15 +4,16 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/Snapshots.h"
|
||||
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "jit/CompileInfo.h"
|
||||
#include "jit/IonSpewer.h"
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
#include "jit/LIR.h"
|
||||
#include "jit/MIR.h"
|
||||
# include "jit/LIR.h"
|
||||
# include "jit/MIR.h"
|
||||
#endif
|
||||
#include "jit/SnapshotReader.h"
|
||||
#include "jit/SnapshotWriter.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
@ -28,15 +29,16 @@ using namespace js::jit;
|
|||
// [ptr] Debug only: JSScript *
|
||||
// [vwu] pc offset
|
||||
// [vwu] # of slots, including nargs
|
||||
// [slot*] N slot entries, where N = nargs + nfixed + stackDepth
|
||||
// [rva*] N recover value allocations entries,
|
||||
// where N = nargs + nfixed + stackDepth
|
||||
//
|
||||
// Encodings:
|
||||
// [ptr] A fixed-size pointer.
|
||||
// [vwu] A variable-width unsigned integer.
|
||||
// [vws] A variable-width signed integer.
|
||||
// [u8] An 8-bit unsigned integer.
|
||||
// [slot*] Information on how to reify a js::Value from an Ion frame. The
|
||||
// first byte is split as thus:
|
||||
// [rva*] list of RValueAllocation which are indicating how to find a js::Value
|
||||
// on a call/bailout. The first byte is split as thus:
|
||||
// Bits 0-2: JSValueType
|
||||
// Bits 3-7: 5-bit register code ("reg").
|
||||
//
|
||||
|
@ -48,8 +50,8 @@ using namespace js::jit;
|
|||
// JSVAL_TYPE_OBJECT:
|
||||
// JSVAL_TYPE_BOOLEAN:
|
||||
// JSVAL_TYPE_STRING:
|
||||
// If "reg" is InvalidReg1, this byte is followed by a [vws]
|
||||
// stack offset. Otherwise, "reg" encodes a GPR register.
|
||||
// If "reg" is ESC_REG_FIELD_INDEX, this byte is followed by a
|
||||
// [vws] stack offset. Otherwise, "reg" encodes a GPR register.
|
||||
//
|
||||
// JSVAL_TYPE_NULL:
|
||||
// Reg value:
|
||||
|
@ -86,17 +88,334 @@ using namespace js::jit;
|
|||
// code=3 reg, reg
|
||||
//
|
||||
// PUNBOX64:
|
||||
// "reg" is InvalidReg1: byte is followed by a [vws] stack
|
||||
// offset containing a Value.
|
||||
// "reg" is ESC_REG_FIELD_INDEX: byte is followed by a [vws]
|
||||
// stack offset containing a Value.
|
||||
//
|
||||
// Otherwise, "reg" is a register containing a Value.
|
||||
//
|
||||
//
|
||||
|
||||
#ifdef JS_NUNBOX32
|
||||
static const uint32_t NUNBOX32_STACK_STACK = 0;
|
||||
static const uint32_t NUNBOX32_STACK_REG = 1;
|
||||
static const uint32_t NUNBOX32_REG_STACK = 2;
|
||||
static const uint32_t NUNBOX32_REG_REG = 3;
|
||||
#endif
|
||||
|
||||
static const uint32_t MAX_TYPE_FIELD_VALUE = 7;
|
||||
|
||||
static const uint32_t MAX_REG_FIELD_VALUE = 31;
|
||||
static const uint32_t ESC_REG_FIELD_INDEX = 31;
|
||||
static const uint32_t ESC_REG_FIELD_CONST = 30;
|
||||
static const uint32_t ESC_REG_FIELD_FLOAT32_STACK = 29;
|
||||
static const uint32_t ESC_REG_FIELD_FLOAT32_REG = 28;
|
||||
static const uint32_t MIN_REG_FIELD_ESC = 28;
|
||||
|
||||
RValueAllocation
|
||||
RValueAllocation::read(CompactBufferReader &reader)
|
||||
{
|
||||
uint8_t b = reader.readByte();
|
||||
|
||||
JSValueType type = JSValueType(b & 0x7);
|
||||
uint32_t code = b >> 3;
|
||||
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
if (code < MIN_REG_FIELD_ESC)
|
||||
return Double(FloatRegister::FromCode(code));
|
||||
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
|
||||
return Typed(type, reader.readSigned());
|
||||
|
||||
case JSVAL_TYPE_INT32:
|
||||
case JSVAL_TYPE_STRING:
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
if (code < MIN_REG_FIELD_ESC)
|
||||
return Typed(type, Register::FromCode(code));
|
||||
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
|
||||
return Typed(type, reader.readSigned());
|
||||
|
||||
case JSVAL_TYPE_NULL:
|
||||
if (code == ESC_REG_FIELD_CONST)
|
||||
return Null();
|
||||
if (code == ESC_REG_FIELD_INDEX)
|
||||
return Int32(reader.readSigned());
|
||||
if (code == ESC_REG_FIELD_FLOAT32_REG)
|
||||
return Float32(FloatRegister::FromCode(reader.readUnsigned()));
|
||||
if (code == ESC_REG_FIELD_FLOAT32_STACK)
|
||||
return Float32(reader.readSigned());
|
||||
return Int32(code);
|
||||
|
||||
case JSVAL_TYPE_UNDEFINED:
|
||||
if (code == ESC_REG_FIELD_CONST)
|
||||
return Undefined();
|
||||
if (code == ESC_REG_FIELD_INDEX)
|
||||
return ConstantPool(reader.readUnsigned());
|
||||
return ConstantPool(code);
|
||||
|
||||
case JSVAL_TYPE_MAGIC:
|
||||
{
|
||||
if (code == ESC_REG_FIELD_CONST) {
|
||||
uint8_t reg2 = reader.readUnsigned();
|
||||
if (reg2 != ESC_REG_FIELD_INDEX)
|
||||
return Typed(type, Register::FromCode(reg2));
|
||||
return Typed(type, reader.readSigned());
|
||||
}
|
||||
|
||||
#ifdef JS_NUNBOX32
|
||||
int32_t type, payload;
|
||||
switch (code) {
|
||||
case NUNBOX32_STACK_STACK:
|
||||
type = reader.readSigned();
|
||||
payload = reader.readSigned();
|
||||
return Untyped(type, payload);
|
||||
case NUNBOX32_STACK_REG:
|
||||
type = reader.readSigned();
|
||||
payload = reader.readByte();
|
||||
return Untyped(type, Register::FromCode(payload));
|
||||
case NUNBOX32_REG_STACK:
|
||||
type = reader.readByte();
|
||||
payload = reader.readSigned();
|
||||
return Untyped(Register::FromCode(type), payload);
|
||||
case NUNBOX32_REG_REG:
|
||||
type = reader.readByte();
|
||||
payload = reader.readByte();
|
||||
return Untyped(Register::FromCode(type),
|
||||
Register::FromCode(payload));
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("bad code");
|
||||
break;
|
||||
}
|
||||
#elif JS_PUNBOX64
|
||||
if (code < MIN_REG_FIELD_ESC)
|
||||
return Untyped(Register::FromCode(code));
|
||||
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
|
||||
return Untyped(reader.readSigned());
|
||||
#endif
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("bad type");
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("huh?");
|
||||
}
|
||||
|
||||
void
|
||||
RValueAllocation::writeHeader(CompactBufferWriter &writer,
|
||||
JSValueType type,
|
||||
uint32_t regCode) const
|
||||
{
|
||||
JS_ASSERT(uint32_t(type) <= MAX_TYPE_FIELD_VALUE);
|
||||
JS_ASSERT(uint32_t(regCode) <= MAX_REG_FIELD_VALUE);
|
||||
JS_STATIC_ASSERT(Registers::Total < MIN_REG_FIELD_ESC);
|
||||
|
||||
uint8_t byte = uint32_t(type) | (regCode << 3);
|
||||
writer.writeByte(byte);
|
||||
}
|
||||
|
||||
void
|
||||
RValueAllocation::write(CompactBufferWriter &writer) const
|
||||
{
|
||||
switch (mode()) {
|
||||
case CONSTANT: {
|
||||
if (constantIndex() < MIN_REG_FIELD_ESC) {
|
||||
writeHeader(writer, JSVAL_TYPE_UNDEFINED, constantIndex());
|
||||
} else {
|
||||
writeHeader(writer, JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_INDEX);
|
||||
writer.writeUnsigned(constantIndex());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DOUBLE_REG: {
|
||||
writeHeader(writer, JSVAL_TYPE_DOUBLE, floatReg().code());
|
||||
break;
|
||||
}
|
||||
|
||||
case FLOAT32_REG: {
|
||||
writeHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_REG);
|
||||
writer.writeUnsigned(floatReg().code());
|
||||
break;
|
||||
}
|
||||
|
||||
case FLOAT32_STACK: {
|
||||
writeHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_STACK);
|
||||
writer.writeSigned(stackOffset());
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPED_REG: {
|
||||
writeHeader(writer, knownType(), reg().code());
|
||||
break;
|
||||
}
|
||||
case TYPED_STACK: {
|
||||
writeHeader(writer, knownType(), ESC_REG_FIELD_INDEX);
|
||||
writer.writeSigned(stackOffset());
|
||||
break;
|
||||
}
|
||||
#if defined(JS_NUNBOX32)
|
||||
case UNTYPED_REG_REG: {
|
||||
writeHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_REG_REG);
|
||||
writer.writeByte(type().reg().code());
|
||||
writer.writeByte(payload().reg().code());
|
||||
break;
|
||||
}
|
||||
case UNTYPED_REG_STACK: {
|
||||
writeHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_REG_STACK);
|
||||
writer.writeByte(type().reg().code());
|
||||
writer.writeSigned(payload().stackOffset());
|
||||
break;
|
||||
}
|
||||
case UNTYPED_STACK_REG: {
|
||||
writeHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_STACK_REG);
|
||||
writer.writeSigned(type().stackOffset());
|
||||
writer.writeByte(payload().reg().code());
|
||||
break;
|
||||
}
|
||||
case UNTYPED_STACK_STACK: {
|
||||
writeHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_STACK_STACK);
|
||||
writer.writeSigned(type().stackOffset());
|
||||
writer.writeSigned(payload().stackOffset());
|
||||
break;
|
||||
}
|
||||
#elif defined(JS_PUNBOX64)
|
||||
case UNTYPED_REG: {
|
||||
writeHeader(writer, JSVAL_TYPE_MAGIC, value().reg().code());
|
||||
break;
|
||||
}
|
||||
case UNTYPED_STACK: {
|
||||
writeHeader(writer, JSVAL_TYPE_MAGIC, ESC_REG_FIELD_INDEX);
|
||||
writer.writeSigned(value().stackOffset());
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case JS_UNDEFINED: {
|
||||
writeHeader(writer, JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_CONST);
|
||||
break;
|
||||
}
|
||||
case JS_NULL: {
|
||||
writeHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_CONST);
|
||||
break;
|
||||
}
|
||||
case JS_INT32: {
|
||||
if (int32Value() >= 0 && uint32_t(int32Value()) < MIN_REG_FIELD_ESC) {
|
||||
writeHeader(writer, JSVAL_TYPE_NULL, int32Value());
|
||||
} else {
|
||||
writeHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_INDEX);
|
||||
writer.writeSigned(int32Value());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INVALID: {
|
||||
MOZ_ASSUME_UNREACHABLE("not initialized");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Location::dump(FILE *fp) const
|
||||
{
|
||||
if (isStackOffset())
|
||||
fprintf(fp, "stack %d", stackOffset());
|
||||
else
|
||||
fprintf(fp, "reg %s", reg().name());
|
||||
}
|
||||
|
||||
static const char *
|
||||
ValTypeToString(JSValueType type)
|
||||
{
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_INT32:
|
||||
return "int32_t";
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
return "double";
|
||||
case JSVAL_TYPE_STRING:
|
||||
return "string";
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
return "boolean";
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
return "object";
|
||||
case JSVAL_TYPE_MAGIC:
|
||||
return "magic";
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("no payload");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RValueAllocation::dump(FILE *fp) const
|
||||
{
|
||||
switch (mode()) {
|
||||
case CONSTANT:
|
||||
fprintf(fp, "constant (pool index %u)", constantIndex());
|
||||
break;
|
||||
|
||||
case DOUBLE_REG:
|
||||
fprintf(fp, "double (reg %s)", floatReg().name());
|
||||
break;
|
||||
|
||||
case FLOAT32_REG:
|
||||
fprintf(fp, "float32 (reg %s)", floatReg().name());
|
||||
break;
|
||||
|
||||
case FLOAT32_STACK:
|
||||
fprintf(fp, "float32 (");
|
||||
known_type_.payload.dump(fp);
|
||||
fprintf(fp, ")");
|
||||
break;
|
||||
|
||||
case TYPED_REG:
|
||||
case TYPED_STACK:
|
||||
fprintf(fp, "%s (", ValTypeToString(knownType()));
|
||||
known_type_.payload.dump(fp);
|
||||
fprintf(fp, ")");
|
||||
break;
|
||||
|
||||
#if defined(JS_NUNBOX32)
|
||||
case UNTYPED_REG_REG:
|
||||
case UNTYPED_REG_STACK:
|
||||
case UNTYPED_STACK_REG:
|
||||
case UNTYPED_STACK_STACK:
|
||||
fprintf(fp, "value (type = ");
|
||||
type().dump(fp);
|
||||
fprintf(fp, ", payload = ");
|
||||
payload().dump(fp);
|
||||
fprintf(fp, ")");
|
||||
break;
|
||||
#elif defined(JS_PUNBOX64)
|
||||
case UNTYPED_REG:
|
||||
case UNTYPED_STACK:
|
||||
fprintf(fp, "value (");
|
||||
value().dump(fp);
|
||||
fprintf(fp, ")");
|
||||
break;
|
||||
#endif
|
||||
|
||||
case JS_UNDEFINED:
|
||||
fprintf(fp, "undefined");
|
||||
break;
|
||||
|
||||
case JS_NULL:
|
||||
fprintf(fp, "null");
|
||||
break;
|
||||
|
||||
case JS_INT32:
|
||||
fprintf(fp, "int32_t %d", int32Value());
|
||||
break;
|
||||
|
||||
case INVALID:
|
||||
fprintf(fp, "invalid");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SnapshotReader::SnapshotReader(const uint8_t *buffer, const uint8_t *end)
|
||||
: reader_(buffer, end),
|
||||
slotCount_(0),
|
||||
allocCount_(0),
|
||||
frameCount_(0),
|
||||
slotsRead_(0)
|
||||
allocRead_(0)
|
||||
{
|
||||
if (!buffer)
|
||||
return;
|
||||
|
@ -129,12 +448,10 @@ void
|
|||
SnapshotReader::readFrameHeader()
|
||||
{
|
||||
JS_ASSERT(moreFrames());
|
||||
JS_ASSERT(slotsRead_ == slotCount_);
|
||||
JS_ASSERT(allocRead_ == allocCount_);
|
||||
|
||||
pcOffset_ = reader_.readUnsigned();
|
||||
slotCount_ = reader_.readUnsigned();
|
||||
IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, slotCount_);
|
||||
|
||||
allocCount_ = reader_.readUnsigned();
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
pcOpcode_ = reader_.readUnsigned();
|
||||
mirOpcode_ = reader_.readUnsigned();
|
||||
|
@ -142,9 +459,10 @@ SnapshotReader::readFrameHeader()
|
|||
lirOpcode_ = reader_.readUnsigned();
|
||||
lirId_ = reader_.readUnsigned();
|
||||
#endif
|
||||
IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, allocCount_);
|
||||
|
||||
framesRead_++;
|
||||
slotsRead_ = 0;
|
||||
allocRead_ = 0;
|
||||
}
|
||||
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
|
@ -163,116 +481,13 @@ SnapshotReader::spewBailingFrom() const
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef JS_NUNBOX32
|
||||
static const uint32_t NUNBOX32_STACK_STACK = 0;
|
||||
static const uint32_t NUNBOX32_STACK_REG = 1;
|
||||
static const uint32_t NUNBOX32_REG_STACK = 2;
|
||||
static const uint32_t NUNBOX32_REG_REG = 3;
|
||||
#endif
|
||||
|
||||
static const uint32_t MAX_TYPE_FIELD_VALUE = 7;
|
||||
|
||||
static const uint32_t MAX_REG_FIELD_VALUE = 31;
|
||||
static const uint32_t ESC_REG_FIELD_INDEX = 31;
|
||||
static const uint32_t ESC_REG_FIELD_CONST = 30;
|
||||
static const uint32_t ESC_REG_FIELD_FLOAT32_STACK = 29;
|
||||
static const uint32_t ESC_REG_FIELD_FLOAT32_REG = 28;
|
||||
static const uint32_t MIN_REG_FIELD_ESC = 28;
|
||||
|
||||
SnapshotReader::Slot
|
||||
SnapshotReader::readSlot()
|
||||
RValueAllocation
|
||||
SnapshotReader::readAllocation()
|
||||
{
|
||||
JS_ASSERT(slotsRead_ < slotCount_);
|
||||
IonSpew(IonSpew_Snapshots, "Reading slot %u", slotsRead_);
|
||||
slotsRead_++;
|
||||
|
||||
uint8_t b = reader_.readByte();
|
||||
|
||||
JSValueType type = JSValueType(b & 0x7);
|
||||
uint32_t code = b >> 3;
|
||||
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
if (code < MIN_REG_FIELD_ESC)
|
||||
return Slot(FloatRegister::FromCode(code));
|
||||
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
|
||||
return Slot(TYPED_STACK, type, Location::From(reader_.readSigned()));
|
||||
|
||||
case JSVAL_TYPE_INT32:
|
||||
case JSVAL_TYPE_STRING:
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
if (code < MIN_REG_FIELD_ESC)
|
||||
return Slot(TYPED_REG, type, Location::From(Register::FromCode(code)));
|
||||
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
|
||||
return Slot(TYPED_STACK, type, Location::From(reader_.readSigned()));
|
||||
|
||||
case JSVAL_TYPE_NULL:
|
||||
if (code == ESC_REG_FIELD_CONST)
|
||||
return Slot(JS_NULL);
|
||||
if (code == ESC_REG_FIELD_INDEX)
|
||||
return Slot(JS_INT32, reader_.readSigned());
|
||||
if (code == ESC_REG_FIELD_FLOAT32_REG)
|
||||
return Slot(FLOAT32_REG, FloatRegister::FromCode(reader_.readUnsigned()));
|
||||
if (code == ESC_REG_FIELD_FLOAT32_STACK)
|
||||
return Slot(FLOAT32_STACK, Location::From(reader_.readSigned()));
|
||||
return Slot(JS_INT32, code);
|
||||
|
||||
case JSVAL_TYPE_UNDEFINED:
|
||||
if (code == ESC_REG_FIELD_CONST)
|
||||
return Slot(JS_UNDEFINED);
|
||||
if (code == ESC_REG_FIELD_INDEX)
|
||||
return Slot(CONSTANT, reader_.readUnsigned());
|
||||
return Slot(CONSTANT, code);
|
||||
|
||||
default:
|
||||
{
|
||||
JS_ASSERT(type == JSVAL_TYPE_MAGIC);
|
||||
|
||||
if (code == ESC_REG_FIELD_CONST) {
|
||||
uint8_t reg2 = reader_.readUnsigned();
|
||||
Location loc;
|
||||
if (reg2 != ESC_REG_FIELD_INDEX)
|
||||
loc = Location::From(Register::FromCode(reg2));
|
||||
else
|
||||
loc = Location::From(reader_.readSigned());
|
||||
return Slot(TYPED_REG, type, loc);
|
||||
}
|
||||
|
||||
Slot slot(UNTYPED);
|
||||
#ifdef JS_NUNBOX32
|
||||
switch (code) {
|
||||
case NUNBOX32_STACK_STACK:
|
||||
slot.unknown_type_.type = Location::From(reader_.readSigned());
|
||||
slot.unknown_type_.payload = Location::From(reader_.readSigned());
|
||||
return slot;
|
||||
case NUNBOX32_STACK_REG:
|
||||
slot.unknown_type_.type = Location::From(reader_.readSigned());
|
||||
slot.unknown_type_.payload = Location::From(Register::FromCode(reader_.readByte()));
|
||||
return slot;
|
||||
case NUNBOX32_REG_STACK:
|
||||
slot.unknown_type_.type = Location::From(Register::FromCode(reader_.readByte()));
|
||||
slot.unknown_type_.payload = Location::From(reader_.readSigned());
|
||||
return slot;
|
||||
default:
|
||||
JS_ASSERT(code == NUNBOX32_REG_REG);
|
||||
slot.unknown_type_.type = Location::From(Register::FromCode(reader_.readByte()));
|
||||
slot.unknown_type_.payload = Location::From(Register::FromCode(reader_.readByte()));
|
||||
return slot;
|
||||
}
|
||||
#elif JS_PUNBOX64
|
||||
if (code < MIN_REG_FIELD_ESC) {
|
||||
slot.unknown_type_.value = Location::From(Register::FromCode(code));
|
||||
} else {
|
||||
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
|
||||
slot.unknown_type_.value = Location::From(reader_.readSigned());
|
||||
}
|
||||
return slot;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("huh?");
|
||||
JS_ASSERT(allocRead_ < allocCount_);
|
||||
IonSpew(IonSpew_Snapshots, "Reading slot %u", allocRead_);
|
||||
allocRead_++;
|
||||
return RValueAllocation::read(reader_);
|
||||
}
|
||||
|
||||
SnapshotOffset
|
||||
|
@ -309,16 +524,16 @@ SnapshotWriter::startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, ui
|
|||
uint32_t implicit = StartArgSlot(script);
|
||||
uint32_t formalArgs = CountArgSlots(script, fun);
|
||||
|
||||
nslots_ = formalArgs + script->nfixed() + exprStack;
|
||||
slotsWritten_ = 0;
|
||||
nallocs_ = formalArgs + script->nfixed() + exprStack;
|
||||
allocWritten_ = 0;
|
||||
|
||||
IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u",
|
||||
implicit, formalArgs - implicit, script->nfixed(), exprStack);
|
||||
|
||||
uint32_t pcoff = script->pcToOffset(pc);
|
||||
IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nslots_);
|
||||
IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs_);
|
||||
writer_.writeUnsigned(pcoff);
|
||||
writer_.writeUnsigned(nslots_);
|
||||
writer_.writeUnsigned(nallocs_);
|
||||
}
|
||||
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
|
@ -334,159 +549,30 @@ SnapshotWriter::trackFrame(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId
|
|||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
SnapshotWriter::add(const RValueAllocation &alloc)
|
||||
{
|
||||
if (IonSpewEnabled(IonSpew_Snapshots)) {
|
||||
IonSpewHeader(IonSpew_Snapshots);
|
||||
fprintf(IonSpewFile, " slot %u: ", allocWritten_);
|
||||
alloc.dump(IonSpewFile);
|
||||
fprintf(IonSpewFile, "\n");
|
||||
}
|
||||
|
||||
allocWritten_++;
|
||||
JS_ASSERT(allocWritten_ <= nallocs_);
|
||||
alloc.write(writer_);
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::endFrame()
|
||||
{
|
||||
// Check that the last write succeeded.
|
||||
JS_ASSERT(nslots_ == slotsWritten_);
|
||||
nslots_ = slotsWritten_ = 0;
|
||||
JS_ASSERT(nallocs_ == allocWritten_);
|
||||
nallocs_ = allocWritten_ = 0;
|
||||
framesWritten_++;
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::writeSlotHeader(JSValueType type, uint32_t regCode)
|
||||
{
|
||||
JS_ASSERT(uint32_t(type) <= MAX_TYPE_FIELD_VALUE);
|
||||
JS_ASSERT(uint32_t(regCode) <= MAX_REG_FIELD_VALUE);
|
||||
JS_STATIC_ASSERT(Registers::Total < MIN_REG_FIELD_ESC);
|
||||
|
||||
uint8_t byte = uint32_t(type) | (regCode << 3);
|
||||
writer_.writeByte(byte);
|
||||
|
||||
slotsWritten_++;
|
||||
JS_ASSERT(slotsWritten_ <= nslots_);
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::addSlot(const FloatRegister ®)
|
||||
{
|
||||
JS_ASSERT(uint32_t(reg.code()) < MIN_REG_FIELD_ESC);
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: double (reg %s)", slotsWritten_, reg.name());
|
||||
|
||||
writeSlotHeader(JSVAL_TYPE_DOUBLE, reg.code());
|
||||
}
|
||||
|
||||
static const char *
|
||||
ValTypeToString(JSValueType type)
|
||||
{
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_INT32:
|
||||
return "int32_t";
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
return "double";
|
||||
case JSVAL_TYPE_STRING:
|
||||
return "string";
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
return "boolean";
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
return "object";
|
||||
case JSVAL_TYPE_MAGIC:
|
||||
return "magic";
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("no payload");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::addSlot(JSValueType type, const Register ®)
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: %s (%s)",
|
||||
slotsWritten_, ValTypeToString(type), reg.name());
|
||||
|
||||
JS_ASSERT(type != JSVAL_TYPE_DOUBLE);
|
||||
writeSlotHeader(type, reg.code());
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::addSlot(JSValueType type, int32_t stackIndex)
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: %s (stack %d)",
|
||||
slotsWritten_, ValTypeToString(type), stackIndex);
|
||||
|
||||
writeSlotHeader(type, ESC_REG_FIELD_INDEX);
|
||||
writer_.writeSigned(stackIndex);
|
||||
}
|
||||
|
||||
#if defined(JS_NUNBOX32)
|
||||
void
|
||||
SnapshotWriter::addSlot(const Register &type, const Register &payload)
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: value (t=%s, d=%s)",
|
||||
slotsWritten_, type.name(), payload.name());
|
||||
|
||||
writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_REG_REG);
|
||||
writer_.writeByte(type.code());
|
||||
writer_.writeByte(payload.code());
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::addSlot(const Register &type, int32_t payloadStackIndex)
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: value (t=%s, d=%d)",
|
||||
slotsWritten_, type.name(), payloadStackIndex);
|
||||
|
||||
writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_REG_STACK);
|
||||
writer_.writeByte(type.code());
|
||||
writer_.writeSigned(payloadStackIndex);
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::addSlot(int32_t typeStackIndex, const Register &payload)
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: value (t=%d, d=%s)",
|
||||
slotsWritten_, typeStackIndex, payload.name());
|
||||
|
||||
writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_STACK_REG);
|
||||
writer_.writeSigned(typeStackIndex);
|
||||
writer_.writeByte(payload.code());
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::addSlot(int32_t typeStackIndex, int32_t payloadStackIndex)
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: value (t=%d, d=%d)",
|
||||
slotsWritten_, typeStackIndex, payloadStackIndex);
|
||||
|
||||
writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_STACK_STACK);
|
||||
writer_.writeSigned(typeStackIndex);
|
||||
writer_.writeSigned(payloadStackIndex);
|
||||
}
|
||||
|
||||
#elif defined(JS_PUNBOX64)
|
||||
void
|
||||
SnapshotWriter::addSlot(const Register &value)
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: value (reg %s)", slotsWritten_, value.name());
|
||||
|
||||
writeSlotHeader(JSVAL_TYPE_MAGIC, value.code());
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::addSlot(int32_t valueStackSlot)
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: value (stack %d)", slotsWritten_, valueStackSlot);
|
||||
|
||||
writeSlotHeader(JSVAL_TYPE_MAGIC, ESC_REG_FIELD_INDEX);
|
||||
writer_.writeSigned(valueStackSlot);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
SnapshotWriter::addUndefinedSlot()
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: undefined", slotsWritten_);
|
||||
|
||||
writeSlotHeader(JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_CONST);
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::addNullSlot()
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: null", slotsWritten_);
|
||||
|
||||
writeSlotHeader(JSVAL_TYPE_NULL, ESC_REG_FIELD_CONST);
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::endSnapshot()
|
||||
{
|
||||
|
@ -500,47 +586,3 @@ SnapshotWriter::endSnapshot()
|
|||
IonSpew(IonSpew_Snapshots, "ending snapshot total size: %u bytes (start %u)",
|
||||
uint32_t(writer_.length() - lastStart_), lastStart_);
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::addInt32Slot(int32_t value)
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: int32_t %d", slotsWritten_, value);
|
||||
|
||||
if (value >= 0 && uint32_t(value) < MIN_REG_FIELD_ESC) {
|
||||
writeSlotHeader(JSVAL_TYPE_NULL, value);
|
||||
} else {
|
||||
writeSlotHeader(JSVAL_TYPE_NULL, ESC_REG_FIELD_INDEX);
|
||||
writer_.writeSigned(value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::addFloat32Slot(const FloatRegister ®)
|
||||
{
|
||||
JS_ASSERT(uint32_t(reg.code()) < MIN_REG_FIELD_ESC);
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: float32 (reg %s)", slotsWritten_, reg.name());
|
||||
writeSlotHeader(JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_REG);
|
||||
writer_.writeUnsigned(reg.code());
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::addFloat32Slot(int32_t stackIndex)
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: float32 (stack %d)", slotsWritten_, stackIndex);
|
||||
writeSlotHeader(JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_STACK);
|
||||
writer_.writeSigned(stackIndex);
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::addConstantPoolSlot(uint32_t index)
|
||||
{
|
||||
IonSpew(IonSpew_Snapshots, " slot %u: constant pool index %u", slotsWritten_, index);
|
||||
|
||||
if (index < MIN_REG_FIELD_ESC) {
|
||||
writeSlotHeader(JSVAL_TYPE_UNDEFINED, index);
|
||||
} else {
|
||||
writeSlotHeader(JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_INDEX);
|
||||
writer_.writeUnsigned(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,463 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jit_Snapshot_h
|
||||
#define jit_Snapshot_h
|
||||
|
||||
#include "jsbytecode.h"
|
||||
|
||||
#include "jit/CompactBuffer.h"
|
||||
#include "jit/IonTypes.h"
|
||||
#include "jit/Registers.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
class RValueAllocation;
|
||||
|
||||
class Location
|
||||
{
|
||||
friend class RValueAllocation;
|
||||
|
||||
// An offset that is illegal for a local variable's stack allocation.
|
||||
static const int32_t InvalidStackOffset = -1;
|
||||
|
||||
Register::Code reg_;
|
||||
int32_t stackOffset_;
|
||||
|
||||
static Location From(const Register ®) {
|
||||
Location loc;
|
||||
loc.reg_ = reg.code();
|
||||
loc.stackOffset_ = InvalidStackOffset;
|
||||
return loc;
|
||||
}
|
||||
static Location From(int32_t stackOffset) {
|
||||
JS_ASSERT(stackOffset != InvalidStackOffset);
|
||||
Location loc;
|
||||
loc.reg_ = Register::Code(0); // Quell compiler warnings.
|
||||
loc.stackOffset_ = stackOffset;
|
||||
return loc;
|
||||
}
|
||||
|
||||
public:
|
||||
Register reg() const {
|
||||
JS_ASSERT(!isStackOffset());
|
||||
return Register::FromCode(reg_);
|
||||
}
|
||||
int32_t stackOffset() const {
|
||||
JS_ASSERT(isStackOffset());
|
||||
return stackOffset_;
|
||||
}
|
||||
bool isStackOffset() const {
|
||||
return stackOffset_ != InvalidStackOffset;
|
||||
}
|
||||
|
||||
void dump(FILE *fp) const;
|
||||
|
||||
public:
|
||||
bool operator==(const Location &l) const {
|
||||
return reg_ == l.reg_ && stackOffset_ == l.stackOffset_;
|
||||
}
|
||||
};
|
||||
|
||||
// A Recover Value Allocation mirror what is known at compiled time as being the
|
||||
// MIRType and the LAllocation. This is read out of the snapshot to recover the
|
||||
// value which would be there if this frame was an interpreter frame instead of
|
||||
// an Ion frame.
|
||||
//
|
||||
// It is used with the SnapshotIterator to recover a Value from the stack,
|
||||
// spilled registers or the list of constant of the compiled script.
|
||||
class RValueAllocation
|
||||
{
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
CONSTANT, // An index into the constant pool.
|
||||
DOUBLE_REG, // Type is double, payload is in a register.
|
||||
FLOAT32_REG, // Type is float32, payload is in a register.
|
||||
FLOAT32_STACK, // Type is float32, payload is on the stack.
|
||||
TYPED_REG, // Type is constant, payload is in a register.
|
||||
TYPED_STACK, // Type is constant, payload is on the stack.
|
||||
#if defined(JS_NUNBOX32)
|
||||
UNTYPED_REG_REG, // Type is not known, type & payload are is in
|
||||
// registers.
|
||||
UNTYPED_REG_STACK, // Type is not known, type is in a register and the
|
||||
// payload is on the stack.
|
||||
UNTYPED_STACK_REG, // Type is not known, type is on the stack and the
|
||||
// payload is in a register.
|
||||
UNTYPED_STACK_STACK, // Type is not known, type & payload are on the
|
||||
// stack.
|
||||
#elif defined(JS_PUNBOX64)
|
||||
UNTYPED_REG, // Type is not known, value is in a register.
|
||||
UNTYPED_STACK, // Type is not known, value is on the stack.
|
||||
#endif
|
||||
JS_UNDEFINED, // UndefinedValue()
|
||||
JS_NULL, // NullValue()
|
||||
JS_INT32, // Int32Value(n)
|
||||
INVALID,
|
||||
|
||||
// Assert that the mode is UNTYPED by checking the range.
|
||||
#if defined(JS_NUNBOX32)
|
||||
UNTYPED_MIN = UNTYPED_REG_REG,
|
||||
UNTYPED_MAX = UNTYPED_STACK_STACK
|
||||
#elif defined(JS_PUNBOX64)
|
||||
UNTYPED_MIN = UNTYPED_REG,
|
||||
UNTYPED_MAX = UNTYPED_STACK
|
||||
#endif
|
||||
};
|
||||
|
||||
private:
|
||||
Mode mode_;
|
||||
|
||||
union {
|
||||
// DOUBLE_REG or FLOAT32_REG
|
||||
FloatRegister::Code fpu_;
|
||||
|
||||
// TYPED_REG or TYPED_STACK or FLOAT32_STACK
|
||||
struct {
|
||||
JSValueType type;
|
||||
Location payload;
|
||||
} known_type_;
|
||||
|
||||
// UNTYPED
|
||||
#if defined(JS_NUNBOX32)
|
||||
struct {
|
||||
Location type;
|
||||
Location payload;
|
||||
} unknown_type_;
|
||||
#elif defined(JS_PUNBOX64)
|
||||
struct {
|
||||
Location value;
|
||||
} unknown_type_;
|
||||
#endif
|
||||
|
||||
// CONSTANT's index or JS_INT32
|
||||
int32_t value_;
|
||||
};
|
||||
|
||||
RValueAllocation(Mode mode, JSValueType type, const Location &loc)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == TYPED_REG || mode == TYPED_STACK);
|
||||
known_type_.type = type;
|
||||
known_type_.payload = loc;
|
||||
}
|
||||
RValueAllocation(Mode mode, const FloatRegister ®)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == FLOAT32_REG || mode == DOUBLE_REG);
|
||||
fpu_ = reg.code();
|
||||
}
|
||||
RValueAllocation(Mode mode, const Location &loc)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == FLOAT32_STACK);
|
||||
known_type_.payload = loc;
|
||||
}
|
||||
RValueAllocation(Mode mode, int32_t index)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == CONSTANT || mode == JS_INT32);
|
||||
value_ = index;
|
||||
}
|
||||
RValueAllocation(Mode mode)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == JS_UNDEFINED || mode == JS_NULL ||
|
||||
(UNTYPED_MIN <= mode && mode <= UNTYPED_MAX));
|
||||
}
|
||||
|
||||
public:
|
||||
RValueAllocation()
|
||||
: mode_(INVALID)
|
||||
{ }
|
||||
|
||||
// DOUBLE_REG
|
||||
static RValueAllocation Double(const FloatRegister ®) {
|
||||
return RValueAllocation(DOUBLE_REG, reg);
|
||||
}
|
||||
|
||||
// FLOAT32_REG or FLOAT32_STACK
|
||||
static RValueAllocation Float32(const FloatRegister ®) {
|
||||
return RValueAllocation(FLOAT32_REG, reg);
|
||||
}
|
||||
static RValueAllocation Float32(int32_t stackIndex) {
|
||||
return RValueAllocation(FLOAT32_STACK, Location::From(stackIndex));
|
||||
}
|
||||
|
||||
// TYPED_REG or TYPED_STACK
|
||||
static RValueAllocation Typed(JSValueType type, const Register ®) {
|
||||
JS_ASSERT(type != JSVAL_TYPE_DOUBLE &&
|
||||
type != JSVAL_TYPE_MAGIC &&
|
||||
type != JSVAL_TYPE_NULL &&
|
||||
type != JSVAL_TYPE_UNDEFINED);
|
||||
return RValueAllocation(TYPED_REG, type, Location::From(reg));
|
||||
}
|
||||
static RValueAllocation Typed(JSValueType type, int32_t stackIndex) {
|
||||
JS_ASSERT(type != JSVAL_TYPE_MAGIC &&
|
||||
type != JSVAL_TYPE_NULL &&
|
||||
type != JSVAL_TYPE_UNDEFINED);
|
||||
return RValueAllocation(TYPED_STACK, type, Location::From(stackIndex));
|
||||
}
|
||||
|
||||
// UNTYPED
|
||||
#if defined(JS_NUNBOX32)
|
||||
static RValueAllocation Untyped(const Register &type, const Register &payload) {
|
||||
RValueAllocation slot(UNTYPED_REG_REG);
|
||||
slot.unknown_type_.type = Location::From(type);
|
||||
slot.unknown_type_.payload = Location::From(payload);
|
||||
return slot;
|
||||
}
|
||||
|
||||
static RValueAllocation Untyped(const Register &type, int32_t payloadStackIndex) {
|
||||
RValueAllocation slot(UNTYPED_REG_STACK);
|
||||
slot.unknown_type_.type = Location::From(type);
|
||||
slot.unknown_type_.payload = Location::From(payloadStackIndex);
|
||||
return slot;
|
||||
}
|
||||
|
||||
static RValueAllocation Untyped(int32_t typeStackIndex, const Register &payload) {
|
||||
RValueAllocation slot(UNTYPED_STACK_REG);
|
||||
slot.unknown_type_.type = Location::From(typeStackIndex);
|
||||
slot.unknown_type_.payload = Location::From(payload);
|
||||
return slot;
|
||||
}
|
||||
|
||||
static RValueAllocation Untyped(int32_t typeStackIndex, int32_t payloadStackIndex) {
|
||||
RValueAllocation slot(UNTYPED_STACK_STACK);
|
||||
slot.unknown_type_.type = Location::From(typeStackIndex);
|
||||
slot.unknown_type_.payload = Location::From(payloadStackIndex);
|
||||
return slot;
|
||||
}
|
||||
|
||||
#elif defined(JS_PUNBOX64)
|
||||
static RValueAllocation Untyped(const Register &value) {
|
||||
RValueAllocation slot(UNTYPED_REG);
|
||||
slot.unknown_type_.value = Location::From(value);
|
||||
return slot;
|
||||
}
|
||||
|
||||
static RValueAllocation Untyped(int32_t stackOffset) {
|
||||
RValueAllocation slot(UNTYPED_STACK);
|
||||
slot.unknown_type_.value = Location::From(stackOffset);
|
||||
return slot;
|
||||
}
|
||||
#endif
|
||||
|
||||
// common constants.
|
||||
static RValueAllocation Undefined() {
|
||||
return RValueAllocation(JS_UNDEFINED);
|
||||
}
|
||||
static RValueAllocation Null() {
|
||||
return RValueAllocation(JS_NULL);
|
||||
}
|
||||
|
||||
// JS_INT32
|
||||
static RValueAllocation Int32(int32_t value) {
|
||||
return RValueAllocation(JS_INT32, value);
|
||||
}
|
||||
|
||||
// CONSTANT's index
|
||||
static RValueAllocation ConstantPool(uint32_t index) {
|
||||
return RValueAllocation(CONSTANT, int32_t(index));
|
||||
}
|
||||
|
||||
void writeHeader(CompactBufferWriter &writer, JSValueType type, uint32_t regCode) const;
|
||||
public:
|
||||
static RValueAllocation read(CompactBufferReader &reader);
|
||||
void write(CompactBufferWriter &writer) const;
|
||||
|
||||
public:
|
||||
Mode mode() const {
|
||||
return mode_;
|
||||
}
|
||||
uint32_t constantIndex() const {
|
||||
JS_ASSERT(mode() == CONSTANT);
|
||||
return value_;
|
||||
}
|
||||
int32_t int32Value() const {
|
||||
JS_ASSERT(mode() == JS_INT32);
|
||||
return value_;
|
||||
}
|
||||
JSValueType knownType() const {
|
||||
JS_ASSERT(mode() == TYPED_REG || mode() == TYPED_STACK);
|
||||
return known_type_.type;
|
||||
}
|
||||
Register reg() const {
|
||||
JS_ASSERT(mode() == TYPED_REG && knownType() != JSVAL_TYPE_DOUBLE);
|
||||
return known_type_.payload.reg();
|
||||
}
|
||||
FloatRegister floatReg() const {
|
||||
JS_ASSERT(mode() == DOUBLE_REG || mode() == FLOAT32_REG);
|
||||
return FloatRegister::FromCode(fpu_);
|
||||
}
|
||||
int32_t stackOffset() const {
|
||||
JS_ASSERT(mode() == TYPED_STACK || mode() == FLOAT32_STACK);
|
||||
return known_type_.payload.stackOffset();
|
||||
}
|
||||
#if defined(JS_NUNBOX32)
|
||||
Location payload() const {
|
||||
JS_ASSERT((UNTYPED_MIN <= mode() && mode() <= UNTYPED_MAX));
|
||||
return unknown_type_.payload;
|
||||
}
|
||||
Location type() const {
|
||||
JS_ASSERT((UNTYPED_MIN <= mode() && mode() <= UNTYPED_MAX));
|
||||
return unknown_type_.type;
|
||||
}
|
||||
#elif defined(JS_PUNBOX64)
|
||||
Location value() const {
|
||||
JS_ASSERT((UNTYPED_MIN <= mode() && mode() <= UNTYPED_MAX));
|
||||
return unknown_type_.value;
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
const char *modeToString() const;
|
||||
void dump(FILE *fp) const;
|
||||
void dump() const;
|
||||
|
||||
public:
|
||||
bool operator==(const RValueAllocation &s) const {
|
||||
if (mode_ != s.mode_)
|
||||
return false;
|
||||
|
||||
switch (mode_) {
|
||||
case DOUBLE_REG:
|
||||
case FLOAT32_REG:
|
||||
return fpu_ == s.fpu_;
|
||||
case TYPED_REG:
|
||||
case TYPED_STACK:
|
||||
case FLOAT32_STACK:
|
||||
return known_type_.type == s.known_type_.type &&
|
||||
known_type_.payload == s.known_type_.payload;
|
||||
#if defined(JS_NUNBOX32)
|
||||
case UNTYPED_REG_REG:
|
||||
case UNTYPED_REG_STACK:
|
||||
case UNTYPED_STACK_REG:
|
||||
case UNTYPED_STACK_STACK:
|
||||
return unknown_type_.type == s.unknown_type_.type &&
|
||||
unknown_type_.payload == s.unknown_type_.payload;
|
||||
#else
|
||||
case UNTYPED_REG:
|
||||
case UNTYPED_STACK:
|
||||
return unknown_type_.value == s.unknown_type_.value;
|
||||
#endif
|
||||
case CONSTANT:
|
||||
case JS_INT32:
|
||||
return value_ == s.value_;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Collects snapshots in a contiguous buffer, which is copied into IonScript
|
||||
// memory after code generation.
|
||||
class SnapshotWriter
|
||||
{
|
||||
CompactBufferWriter writer_;
|
||||
|
||||
// These are only used to assert sanity.
|
||||
uint32_t nallocs_;
|
||||
uint32_t allocWritten_;
|
||||
uint32_t nframes_;
|
||||
uint32_t framesWritten_;
|
||||
SnapshotOffset lastStart_;
|
||||
|
||||
public:
|
||||
SnapshotOffset startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter);
|
||||
void startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack);
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
void trackFrame(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
|
||||
uint32_t lirOpcode, uint32_t lirId);
|
||||
#endif
|
||||
void endFrame();
|
||||
|
||||
void add(const RValueAllocation &slot);
|
||||
|
||||
void endSnapshot();
|
||||
|
||||
bool oom() const {
|
||||
return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return writer_.length();
|
||||
}
|
||||
const uint8_t *buffer() const {
|
||||
return writer_.buffer();
|
||||
}
|
||||
};
|
||||
|
||||
// A snapshot reader reads the entries out of the compressed snapshot buffer in
|
||||
// a script. These entries describe the equivalent interpreter frames at a given
|
||||
// position in JIT code. Each entry is an Ion's value allocations, used to
|
||||
// recover the corresponding Value from an Ion frame.
|
||||
class SnapshotReader
|
||||
{
|
||||
CompactBufferReader reader_;
|
||||
|
||||
uint32_t pcOffset_; // Offset from script->code.
|
||||
uint32_t allocCount_; // Number of slots.
|
||||
uint32_t frameCount_;
|
||||
BailoutKind bailoutKind_;
|
||||
uint32_t framesRead_; // Number of frame headers that have been read.
|
||||
uint32_t allocRead_; // Number of slots that have been read.
|
||||
bool resumeAfter_;
|
||||
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
private:
|
||||
uint32_t pcOpcode_;
|
||||
uint32_t mirOpcode_;
|
||||
uint32_t mirId_;
|
||||
uint32_t lirOpcode_;
|
||||
uint32_t lirId_;
|
||||
|
||||
public:
|
||||
void spewBailingFrom() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void readSnapshotHeader();
|
||||
void readFrameHeader();
|
||||
|
||||
public:
|
||||
SnapshotReader(const uint8_t *buffer, const uint8_t *end);
|
||||
|
||||
uint32_t pcOffset() const {
|
||||
return pcOffset_;
|
||||
}
|
||||
uint32_t allocations() const {
|
||||
return allocCount_;
|
||||
}
|
||||
BailoutKind bailoutKind() const {
|
||||
return bailoutKind_;
|
||||
}
|
||||
bool resumeAfter() const {
|
||||
if (moreFrames())
|
||||
return false;
|
||||
return resumeAfter_;
|
||||
}
|
||||
bool moreFrames() const {
|
||||
return framesRead_ < frameCount_;
|
||||
}
|
||||
void nextFrame() {
|
||||
readFrameHeader();
|
||||
}
|
||||
RValueAllocation readAllocation();
|
||||
|
||||
bool moreAllocations() const {
|
||||
return allocRead_ < allocCount_;
|
||||
}
|
||||
uint32_t frameCount() const {
|
||||
return frameCount_;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* jit_Snapshot_h */
|
|
@ -2043,6 +2043,35 @@ typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
|
|||
typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
|
||||
typedef int32_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
|
||||
|
||||
|
||||
// Fill the volatile registers with scratch values.
|
||||
//
|
||||
// Some of the ABI calls assume that the float registers are not scratched, even
|
||||
// though the ABI defines them as volatile - a performance optimization. These are
|
||||
// all calls passing operands in integer registers, so for now the simulator does not
|
||||
// scratch any float registers for these calls. Should try to narrow it further in
|
||||
// future.
|
||||
//
|
||||
void
|
||||
Simulator::scratchVolatileRegisters(bool scratchFloat)
|
||||
{
|
||||
int32_t scratch_value = 0xa5a5a5a5 ^ uint32_t(icount_);
|
||||
set_register(r0, scratch_value);
|
||||
set_register(r1, scratch_value);
|
||||
set_register(r2, scratch_value);
|
||||
set_register(r3, scratch_value);
|
||||
set_register(r12, scratch_value); // Intra-Procedure-call scratch register
|
||||
set_register(r14, scratch_value); // Link register
|
||||
|
||||
if (scratchFloat) {
|
||||
uint64_t scratch_value_d = 0x5a5a5a5a5a5a5a5aLU ^ uint64_t(icount_) ^ (uint64_t(icount_) << 30);
|
||||
for (uint32_t i = d0; i < d8; i++)
|
||||
set_d_register(i, &scratch_value_d);
|
||||
for (uint32_t i = d16; i < FloatRegisters::Total; i++)
|
||||
set_d_register(i, &scratch_value_d);
|
||||
}
|
||||
}
|
||||
|
||||
// Software interrupt instructions are used by the simulator to call into C++.
|
||||
void
|
||||
Simulator::softwareInterrupt(SimInstruction *instr)
|
||||
|
@ -2072,42 +2101,53 @@ Simulator::softwareInterrupt(SimInstruction *instr)
|
|||
case Args_General0: {
|
||||
Prototype_General0 target = reinterpret_cast<Prototype_General0>(external);
|
||||
int64_t result = target();
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResult(result);
|
||||
break;
|
||||
}
|
||||
case Args_General1: {
|
||||
Prototype_General1 target = reinterpret_cast<Prototype_General1>(external);
|
||||
int64_t result = target(arg0);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResult(result);
|
||||
break;
|
||||
}
|
||||
case Args_General2: {
|
||||
Prototype_General2 target = reinterpret_cast<Prototype_General2>(external);
|
||||
int64_t result = target(arg0, arg1);
|
||||
// The ARM backend makes calls to __aeabi_idivmod and __aeabi_uidivmod assuming
|
||||
// that the float registers are non-volatile as a performance optimization, so the
|
||||
// float registers must not be scratch when calling these.
|
||||
bool scratchFloat = target != __aeabi_idivmod && target != __aeabi_uidivmod;
|
||||
scratchVolatileRegisters(/* scratchFloat = */ scratchFloat);
|
||||
setCallResult(result);
|
||||
break;
|
||||
}
|
||||
case Args_General3: {
|
||||
Prototype_General3 target = reinterpret_cast<Prototype_General3>(external);
|
||||
int64_t result = target(arg0, arg1, arg2);
|
||||
scratchVolatileRegisters(/* scratchFloat = true*/);
|
||||
setCallResult(result);
|
||||
break;
|
||||
}
|
||||
case Args_General4: {
|
||||
Prototype_General4 target = reinterpret_cast<Prototype_General4>(external);
|
||||
int64_t result = target(arg0, arg1, arg2, arg3);
|
||||
scratchVolatileRegisters(/* scratchFloat = true*/);
|
||||
setCallResult(result);
|
||||
break;
|
||||
}
|
||||
case Args_General5: {
|
||||
Prototype_General5 target = reinterpret_cast<Prototype_General5>(external);
|
||||
int64_t result = target(arg0, arg1, arg2, arg3, arg4);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResult(result);
|
||||
break;
|
||||
}
|
||||
case Args_General6: {
|
||||
Prototype_General6 target = reinterpret_cast<Prototype_General6>(external);
|
||||
int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResult(result);
|
||||
break;
|
||||
}
|
||||
|
@ -2115,6 +2155,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
|
|||
Prototype_General7 target = reinterpret_cast<Prototype_General7>(external);
|
||||
int32_t arg6 = stack_pointer[2];
|
||||
int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResult(result);
|
||||
break;
|
||||
}
|
||||
|
@ -2123,12 +2164,14 @@ Simulator::softwareInterrupt(SimInstruction *instr)
|
|||
int32_t arg6 = stack_pointer[2];
|
||||
int32_t arg7 = stack_pointer[3];
|
||||
int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResult(result);
|
||||
break;
|
||||
}
|
||||
case Args_Double_None: {
|
||||
Prototype_Double_None target = reinterpret_cast<Prototype_Double_None>(external);
|
||||
double dresult = target();
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResultDouble(dresult);
|
||||
break;
|
||||
}
|
||||
|
@ -2138,6 +2181,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
|
|||
getFpArgs(&dval0, &dval1, &ival);
|
||||
Prototype_Int_Double target = reinterpret_cast<Prototype_Int_Double>(external);
|
||||
int32_t res = target(dval0);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
set_register(r0, res);
|
||||
break;
|
||||
}
|
||||
|
@ -2147,6 +2191,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
|
|||
getFpArgs(&dval0, &dval1, &ival);
|
||||
Prototype_Double_Double target = reinterpret_cast<Prototype_Double_Double>(external);
|
||||
double dresult = target(dval0);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResultDouble(dresult);
|
||||
break;
|
||||
}
|
||||
|
@ -2154,12 +2199,14 @@ Simulator::softwareInterrupt(SimInstruction *instr)
|
|||
float fval0 = mozilla::BitwiseCast<float>(arg0);
|
||||
Prototype_Float32_Float32 target = reinterpret_cast<Prototype_Float32_Float32>(external);
|
||||
float fresult = target(fval0);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResultFloat(fresult);
|
||||
break;
|
||||
}
|
||||
case Args_Double_Int: {
|
||||
Prototype_Double_Int target = reinterpret_cast<Prototype_Double_Int>(external);
|
||||
double dresult = target(arg0);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResultDouble(dresult);
|
||||
break;
|
||||
}
|
||||
|
@ -2169,6 +2216,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
|
|||
getFpArgs(&dval0, &dval1, &ival);
|
||||
Prototype_DoubleInt target = reinterpret_cast<Prototype_DoubleInt>(external);
|
||||
double dresult = target(dval0, ival);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResultDouble(dresult);
|
||||
break;
|
||||
}
|
||||
|
@ -2178,6 +2226,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
|
|||
getFpArgs(&dval0, &dval1, &ival);
|
||||
Prototype_Double_DoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDouble>(external);
|
||||
double dresult = target(dval0, dval1);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResultDouble(dresult);
|
||||
break;
|
||||
}
|
||||
|
@ -2187,6 +2236,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
|
|||
double dval0 = get_double_from_register_pair(2);
|
||||
Prototype_Double_IntDouble target = reinterpret_cast<Prototype_Double_IntDouble>(external);
|
||||
double dresult = target(ival, dval0);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
setCallResultDouble(dresult);
|
||||
break;
|
||||
}
|
||||
|
@ -2196,6 +2246,7 @@ Simulator::softwareInterrupt(SimInstruction *instr)
|
|||
double dval0 = get_double_from_register_pair(2);
|
||||
Prototype_Int_IntDouble target = reinterpret_cast<Prototype_Int_IntDouble>(external);
|
||||
int32_t result = target(ival, dval0);
|
||||
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||
set_register(r0, result);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -281,6 +281,7 @@ class Simulator
|
|||
void setCallResultDouble(double result);
|
||||
void setCallResultFloat(float result);
|
||||
void setCallResult(int64_t res);
|
||||
void scratchVolatileRegisters(bool scratchFloat = true);
|
||||
|
||||
template<class ReturnType, int register_size>
|
||||
ReturnType getFromVFPRegister(int reg_index);
|
||||
|
|
|
@ -131,14 +131,14 @@ ToStackIndex(LAllocation *a)
|
|||
}
|
||||
|
||||
bool
|
||||
CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
|
||||
uint32_t *startIndex)
|
||||
CodeGeneratorShared::encodeAllocations(LSnapshot *snapshot, MResumePoint *resumePoint,
|
||||
uint32_t *startIndex)
|
||||
{
|
||||
IonSpew(IonSpew_Codegen, "Encoding %u of resume point %p's operands starting from %u",
|
||||
resumePoint->numOperands(), (void *) resumePoint, *startIndex);
|
||||
for (uint32_t slotno = 0, e = resumePoint->numOperands(); slotno < e; slotno++) {
|
||||
uint32_t i = slotno + *startIndex;
|
||||
MDefinition *mir = resumePoint->getOperand(slotno);
|
||||
for (uint32_t allocno = 0, e = resumePoint->numOperands(); allocno < e; allocno++) {
|
||||
uint32_t i = allocno + *startIndex;
|
||||
MDefinition *mir = resumePoint->getOperand(allocno);
|
||||
|
||||
if (mir->isBox())
|
||||
mir = mir->toBox()->getOperand(0);
|
||||
|
@ -147,12 +147,14 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
|
|||
? MIRType_Undefined
|
||||
: mir->type();
|
||||
|
||||
RValueAllocation alloc;
|
||||
|
||||
switch (type) {
|
||||
case MIRType_Undefined:
|
||||
snapshots_.addUndefinedSlot();
|
||||
alloc = RValueAllocation::Undefined();
|
||||
break;
|
||||
case MIRType_Null:
|
||||
snapshots_.addNullSlot();
|
||||
alloc = RValueAllocation::Null();
|
||||
break;
|
||||
case MIRType_Int32:
|
||||
case MIRType_String:
|
||||
|
@ -165,29 +167,29 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
|
|||
JSValueType valueType = ValueTypeFromMIRType(type);
|
||||
if (payload->isMemory()) {
|
||||
if (type == MIRType_Float32)
|
||||
snapshots_.addFloat32Slot(ToStackIndex(payload));
|
||||
alloc = RValueAllocation::Float32(ToStackIndex(payload));
|
||||
else
|
||||
snapshots_.addSlot(valueType, ToStackIndex(payload));
|
||||
alloc = RValueAllocation::Typed(valueType, ToStackIndex(payload));
|
||||
} else if (payload->isGeneralReg()) {
|
||||
snapshots_.addSlot(valueType, ToRegister(payload));
|
||||
alloc = RValueAllocation::Typed(valueType, ToRegister(payload));
|
||||
} else if (payload->isFloatReg()) {
|
||||
FloatRegister reg = ToFloatRegister(payload);
|
||||
if (type == MIRType_Float32)
|
||||
snapshots_.addFloat32Slot(reg);
|
||||
alloc = RValueAllocation::Float32(reg);
|
||||
else
|
||||
snapshots_.addSlot(reg);
|
||||
alloc = RValueAllocation::Double(reg);
|
||||
} else {
|
||||
MConstant *constant = mir->toConstant();
|
||||
const Value &v = constant->value();
|
||||
|
||||
// Don't bother with the constant pool for smallish integers.
|
||||
if (v.isInt32() && v.toInt32() >= -32 && v.toInt32() <= 32) {
|
||||
snapshots_.addInt32Slot(v.toInt32());
|
||||
alloc = RValueAllocation::Int32(v.toInt32());
|
||||
} else {
|
||||
uint32_t index;
|
||||
if (!graph.addConstantToPool(constant->value(), &index))
|
||||
return false;
|
||||
snapshots_.addConstantPoolSlot(index);
|
||||
alloc = RValueAllocation::ConstantPool(index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -197,7 +199,7 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
|
|||
uint32_t index;
|
||||
if (!graph.addConstantToPool(MagicValue(JS_OPTIMIZED_ARGUMENTS), &index))
|
||||
return false;
|
||||
snapshots_.addConstantPoolSlot(index);
|
||||
alloc = RValueAllocation::ConstantPool(index);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -208,24 +210,26 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
|
|||
LAllocation *type = snapshot->typeOfSlot(i);
|
||||
if (type->isRegister()) {
|
||||
if (payload->isRegister())
|
||||
snapshots_.addSlot(ToRegister(type), ToRegister(payload));
|
||||
alloc = RValueAllocation::Untyped(ToRegister(type), ToRegister(payload));
|
||||
else
|
||||
snapshots_.addSlot(ToRegister(type), ToStackIndex(payload));
|
||||
alloc = RValueAllocation::Untyped(ToRegister(type), ToStackIndex(payload));
|
||||
} else {
|
||||
if (payload->isRegister())
|
||||
snapshots_.addSlot(ToStackIndex(type), ToRegister(payload));
|
||||
alloc = RValueAllocation::Untyped(ToStackIndex(type), ToRegister(payload));
|
||||
else
|
||||
snapshots_.addSlot(ToStackIndex(type), ToStackIndex(payload));
|
||||
alloc = RValueAllocation::Untyped(ToStackIndex(type), ToStackIndex(payload));
|
||||
}
|
||||
#elif JS_PUNBOX64
|
||||
if (payload->isRegister())
|
||||
snapshots_.addSlot(ToRegister(payload));
|
||||
alloc = RValueAllocation::Untyped(ToRegister(payload));
|
||||
else
|
||||
snapshots_.addSlot(ToStackIndex(payload));
|
||||
alloc = RValueAllocation::Untyped(ToStackIndex(payload));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snapshots_.add(alloc);
|
||||
}
|
||||
|
||||
*startIndex += resumePoint->numOperands();
|
||||
|
@ -328,7 +332,7 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
|
|||
snapshots_.trackFrame(pcOpcode, mirOpcode, mirId, lirOpcode, lirId);
|
||||
#endif
|
||||
|
||||
if (!encodeSlots(snapshot, mir, &startIndex))
|
||||
if (!encodeAllocations(snapshot, mir, &startIndex))
|
||||
return false;
|
||||
snapshots_.endFrame();
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "jit/MIRGenerator.h"
|
||||
#include "jit/MIRGraph.h"
|
||||
#include "jit/Safepoints.h"
|
||||
#include "jit/SnapshotWriter.h"
|
||||
#include "jit/Snapshots.h"
|
||||
#include "jit/VMFunctions.h"
|
||||
#include "vm/ForkJoin.h"
|
||||
|
||||
|
@ -258,7 +258,7 @@ class CodeGeneratorShared : public LInstructionVisitor
|
|||
// Encodes an LSnapshot into the compressed snapshot buffer, returning
|
||||
// false on failure.
|
||||
bool encode(LSnapshot *snapshot);
|
||||
bool encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint, uint32_t *startIndex);
|
||||
bool encodeAllocations(LSnapshot *snapshot, MResumePoint *resumePoint, uint32_t *startIndex);
|
||||
|
||||
// Attempts to assign a BailoutId to a snapshot, if one isn't already set.
|
||||
// If the bailout table is full, this returns false, which is not a fatal
|
||||
|
|
|
@ -41,6 +41,7 @@ UNIFIED_SOURCES += [
|
|||
'testIntern.cpp',
|
||||
'testIntString.cpp',
|
||||
'testIntTypesABI.cpp',
|
||||
'testJitRValueAlloc.cpp',
|
||||
'testJSEvaluateScript.cpp',
|
||||
'testLookup.cpp',
|
||||
'testLooselyEqual.cpp',
|
||||
|
|
|
@ -0,0 +1,236 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/Snapshots.h"
|
||||
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
// These tests are checking that all slots of the current architecture can all
|
||||
// be encoded and decoded correctly. We iterate on all registers and on many
|
||||
// fake stack locations (Fibonacci).
|
||||
static RValueAllocation
|
||||
Read(const RValueAllocation &slot)
|
||||
{
|
||||
CompactBufferWriter writer;
|
||||
slot.write(writer);
|
||||
|
||||
CompactBufferReader reader(writer);
|
||||
return RValueAllocation::read(reader);
|
||||
}
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_Double)
|
||||
{
|
||||
RValueAllocation s;
|
||||
for (uint32_t i = 0; i < FloatRegisters::Total; i++) {
|
||||
s = RValueAllocation::Double(FloatRegister::FromCode(i));
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_Double)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_FloatReg)
|
||||
{
|
||||
RValueAllocation s;
|
||||
for (uint32_t i = 0; i < FloatRegisters::Total; i++) {
|
||||
s = RValueAllocation::Float32(FloatRegister::FromCode(i));
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_FloatReg)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_FloatStack)
|
||||
{
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
s = RValueAllocation::Float32(i);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_FloatStack)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_TypedReg)
|
||||
{
|
||||
RValueAllocation s;
|
||||
for (uint32_t i = 0; i < Registers::Total; i++) {
|
||||
#define FOR_EACH_JSVAL(_) \
|
||||
/* _(JSVAL_TYPE_DOUBLE) */ \
|
||||
_(JSVAL_TYPE_INT32) \
|
||||
/* _(JSVAL_TYPE_UNDEFINED) */ \
|
||||
_(JSVAL_TYPE_BOOLEAN) \
|
||||
/* _(JSVAL_TYPE_MAGIC) */ \
|
||||
_(JSVAL_TYPE_STRING) \
|
||||
/* _(JSVAL_TYPE_NULL) */ \
|
||||
_(JSVAL_TYPE_OBJECT)
|
||||
|
||||
#define CHECK_WITH_JSVAL(jsval) \
|
||||
s = RValueAllocation::Typed(jsval, Register::FromCode(i)); \
|
||||
CHECK(s == Read(s));
|
||||
|
||||
FOR_EACH_JSVAL(CHECK_WITH_JSVAL)
|
||||
#undef CHECK_WITH_JSVAL
|
||||
#undef FOR_EACH_JSVAL
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_TypedReg)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_TypedStack)
|
||||
{
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
#define FOR_EACH_JSVAL(_) \
|
||||
_(JSVAL_TYPE_DOUBLE) \
|
||||
_(JSVAL_TYPE_INT32) \
|
||||
/* _(JSVAL_TYPE_UNDEFINED) */ \
|
||||
_(JSVAL_TYPE_BOOLEAN) \
|
||||
/* _(JSVAL_TYPE_MAGIC) */ \
|
||||
_(JSVAL_TYPE_STRING) \
|
||||
/* _(JSVAL_TYPE_NULL) */ \
|
||||
_(JSVAL_TYPE_OBJECT)
|
||||
|
||||
#define CHECK_WITH_JSVAL(jsval) \
|
||||
s = RValueAllocation::Typed(jsval, i); \
|
||||
CHECK(s == Read(s));
|
||||
|
||||
FOR_EACH_JSVAL(CHECK_WITH_JSVAL)
|
||||
#undef CHECK_WITH_JSVAL
|
||||
#undef FOR_EACH_JSVAL
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_TypedStack)
|
||||
|
||||
#if defined(JS_NUNBOX32)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_UntypedRegReg)
|
||||
{
|
||||
RValueAllocation s;
|
||||
for (uint32_t i = 0; i < Registers::Total; i++) {
|
||||
for (uint32_t j = 0; j < Registers::Total; j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
s = RValueAllocation::Untyped(Register::FromCode(i), Register::FromCode(j));
|
||||
MOZ_ASSERT(s == Read(s));
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_UntypedRegReg)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_UntypedRegStack)
|
||||
{
|
||||
RValueAllocation s;
|
||||
for (uint32_t i = 0; i < Registers::Total; i++) {
|
||||
int32_t j, last = 0, tmp;
|
||||
for (j = 0; j > 0; tmp = j, j += last, last = tmp) {
|
||||
s = RValueAllocation::Untyped(Register::FromCode(i), j);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_UntypedRegStack)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_UntypedStackReg)
|
||||
{
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
for (uint32_t j = 0; j < Registers::Total; j++) {
|
||||
s = RValueAllocation::Untyped(i, Register::FromCode(j));
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_UntypedStackReg)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_UntypedStackStack)
|
||||
{
|
||||
RValueAllocation s;
|
||||
int32_t i, li = 0, ti;
|
||||
for (i = 0; i > 0; ti = i, i += li, li = ti) {
|
||||
int32_t j, lj = 0, tj;
|
||||
for (j = 0; j > 0; tj = j, j += lj, lj = tj) {
|
||||
s = RValueAllocation::Untyped(i, j);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_UntypedStackStack)
|
||||
|
||||
#else
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_UntypedReg)
|
||||
{
|
||||
RValueAllocation s;
|
||||
for (uint32_t i = 0; i < Registers::Total; i++) {
|
||||
s = RValueAllocation::Untyped(Register::FromCode(i));
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_UntypedReg)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_UntypedStack)
|
||||
{
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
s = RValueAllocation::Untyped(i);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_UntypedStack)
|
||||
|
||||
#endif
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_UndefinedAndNull)
|
||||
{
|
||||
RValueAllocation s;
|
||||
s = RValueAllocation::Undefined();
|
||||
CHECK(s == Read(s));
|
||||
s = RValueAllocation::Null();
|
||||
CHECK(s == Read(s));
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_UndefinedAndNull)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_Int32)
|
||||
{
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
s = RValueAllocation::Int32(i);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_Int32)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_ConstantPool)
|
||||
{
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
s = RValueAllocation::ConstantPool(i);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_ConstantPool)
|
|
@ -191,7 +191,7 @@ AssertHeapIsIdleOrStringIsFlat(JSContext *cx, JSString *str)
|
|||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ConvertArguments(JSContext *cx, unsigned argc, jsval *argv, const char *format, ...)
|
||||
JS_ConvertArguments(JSContext *cx, const CallArgs &args, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
bool ok;
|
||||
|
@ -199,15 +199,15 @@ JS_ConvertArguments(JSContext *cx, unsigned argc, jsval *argv, const char *forma
|
|||
AssertHeapIsIdle(cx);
|
||||
|
||||
va_start(ap, format);
|
||||
ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
|
||||
ok = JS_ConvertArgumentsVA(cx, args, format, ap);
|
||||
va_end(ap);
|
||||
return ok;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv, const char *format, va_list ap)
|
||||
JS_ConvertArgumentsVA(JSContext *cx, const CallArgs &args, const char *format, va_list ap)
|
||||
{
|
||||
jsval *sp;
|
||||
unsigned index = 0;
|
||||
bool required;
|
||||
char c;
|
||||
double d;
|
||||
|
@ -217,8 +217,7 @@ JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv, const char *for
|
|||
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, JSValueArray(argv - 2, argc + 2));
|
||||
sp = argv;
|
||||
assertSameCompartment(cx, args);
|
||||
required = true;
|
||||
while ((c = *format++) != '\0') {
|
||||
if (isspace(c))
|
||||
|
@ -227,24 +226,23 @@ JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv, const char *for
|
|||
required = false;
|
||||
continue;
|
||||
}
|
||||
if (sp == argv + argc) {
|
||||
if (index == args.length()) {
|
||||
if (required) {
|
||||
HandleValue callee = HandleValue::fromMarkedLocation(&argv[-2]);
|
||||
if (JSFunction *fun = ReportIfNotFunction(cx, callee)) {
|
||||
if (JSFunction *fun = ReportIfNotFunction(cx, args.calleev())) {
|
||||
char numBuf[12];
|
||||
JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
|
||||
JS_snprintf(numBuf, sizeof numBuf, "%u", args.length());
|
||||
JSAutoByteString funNameBytes;
|
||||
if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
|
||||
JSMSG_MORE_ARGS_NEEDED,
|
||||
name, numBuf, (argc == 1) ? "" : "s");
|
||||
name, numBuf, (args.length() == 1) ? "" : "s");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
RootedValue arg(cx, *sp);
|
||||
MutableHandleValue arg = args[index++];
|
||||
switch (c) {
|
||||
case 'b':
|
||||
*va_arg(ap, bool *) = ToBoolean(arg);
|
||||
|
@ -273,11 +271,10 @@ JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv, const char *for
|
|||
break;
|
||||
case 'S':
|
||||
case 'W':
|
||||
val = *sp;
|
||||
str = ToString<CanGC>(cx, val);
|
||||
str = ToString<CanGC>(cx, arg);
|
||||
if (!str)
|
||||
return false;
|
||||
*sp = STRING_TO_JSVAL(str);
|
||||
arg.setString(str);
|
||||
if (c == 'W') {
|
||||
JSFlatString *flat = str->ensureFlat(cx);
|
||||
if (!flat)
|
||||
|
@ -288,26 +285,25 @@ JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv, const char *for
|
|||
}
|
||||
break;
|
||||
case 'o':
|
||||
if (sp->isNullOrUndefined()) {
|
||||
if (arg.isNullOrUndefined()) {
|
||||
obj = nullptr;
|
||||
} else {
|
||||
RootedValue v(cx, *sp);
|
||||
obj = ToObject(cx, v);
|
||||
obj = ToObject(cx, arg);
|
||||
if (!obj)
|
||||
return false;
|
||||
}
|
||||
*sp = ObjectOrNullValue(obj);
|
||||
arg.setObjectOrNull(obj);
|
||||
*va_arg(ap, JSObject **) = obj;
|
||||
break;
|
||||
case 'f':
|
||||
obj = ReportIfNotFunction(cx, HandleValue::fromMarkedLocation(sp));
|
||||
obj = ReportIfNotFunction(cx, arg);
|
||||
if (!obj)
|
||||
return false;
|
||||
*sp = OBJECT_TO_JSVAL(obj);
|
||||
arg.setObject(*obj);
|
||||
*va_arg(ap, JSFunction **) = &obj->as<JSFunction>();
|
||||
break;
|
||||
case 'v':
|
||||
*va_arg(ap, jsval *) = *sp;
|
||||
*va_arg(ap, jsval *) = arg;
|
||||
break;
|
||||
case '*':
|
||||
break;
|
||||
|
@ -315,7 +311,6 @@ JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv, const char *for
|
|||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_CHAR, format);
|
||||
return false;
|
||||
}
|
||||
sp++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -996,13 +996,12 @@ JS_GetEmptyString(JSRuntime *rt);
|
|||
* unconverted arguments.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ConvertArguments(JSContext *cx, unsigned argc, jsval *argv, const char *format,
|
||||
...);
|
||||
JS_ConvertArguments(JSContext *cx, const JS::CallArgs &args, const char *format, ...);
|
||||
|
||||
#ifdef va_start
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv,
|
||||
const char *format, va_list ap);
|
||||
JS_ConvertArgumentsVA(JSContext *cx, const JS::CallArgs &args, const char *format,
|
||||
va_list ap);
|
||||
#endif
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
|
|
|
@ -409,6 +409,8 @@ if CONFIG['MOZ_ETW']:
|
|||
GENERATED_FILES = [
|
||||
'ETWProvider.h',
|
||||
]
|
||||
# This will get the ETW provider resources into the library mozjs.dll
|
||||
RESFILE = 'ETWProvider.res'
|
||||
|
||||
if CONFIG['NIGHTLY_BUILD']:
|
||||
DEFINES['ENABLE_PARALLEL_JS'] = True
|
||||
|
|
|
@ -171,8 +171,14 @@ static const JSClass pm_class = {
|
|||
static bool
|
||||
pm_construct(JSContext* cx, unsigned argc, jsval* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
uint32_t mask;
|
||||
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "u", &mask))
|
||||
if (!args.hasDefined(0)) {
|
||||
js_ReportMissingArg(cx, args.calleev(), 0);
|
||||
return false;
|
||||
}
|
||||
if (!JS::ToUint32(cx, args[0], &mask))
|
||||
return false;
|
||||
|
||||
JS::RootedObject obj(cx, JS_NewObjectForConstructor(cx, &pm_class, vp));
|
||||
|
@ -189,7 +195,7 @@ pm_construct(JSContext* cx, unsigned argc, jsval* vp)
|
|||
}
|
||||
|
||||
JS_SetPrivate(obj, p);
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
args.rval().setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1364,7 +1364,7 @@ Quit(JSContext *cx, unsigned argc, jsval *vp)
|
|||
#endif
|
||||
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
JS_ConvertArguments(cx, args.length(), args.array(), "/ i", &gExitCode);
|
||||
JS_ConvertArguments(cx, args, "/ i", &gExitCode);
|
||||
|
||||
gQuitting = true;
|
||||
return false;
|
||||
|
@ -2227,7 +2227,7 @@ DumpObject(JSContext *cx, unsigned argc, jsval *vp)
|
|||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedObject arg0(cx);
|
||||
if (!JS_ConvertArguments(cx, args.length(), args.array(), "o", arg0.address()))
|
||||
if (!JS_ConvertArguments(cx, args, "o", arg0.address()))
|
||||
return false;
|
||||
|
||||
js_DumpObject(arg0);
|
||||
|
@ -2480,9 +2480,11 @@ NewSandbox(JSContext *cx, bool lazy)
|
|||
static bool
|
||||
EvalInContext(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
RootedString str(cx);
|
||||
RootedObject sobj(cx);
|
||||
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S / o", str.address(), sobj.address()))
|
||||
if (!JS_ConvertArguments(cx, args, "S / o", str.address(), sobj.address()))
|
||||
return false;
|
||||
|
||||
size_t srclen;
|
||||
|
@ -2507,7 +2509,7 @@ EvalInContext(JSContext *cx, unsigned argc, jsval *vp)
|
|||
}
|
||||
|
||||
if (srclen == 0) {
|
||||
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(sobj));
|
||||
args.rval().setObject(*sobj);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2515,7 +2517,6 @@ EvalInContext(JSContext *cx, unsigned argc, jsval *vp)
|
|||
unsigned lineno;
|
||||
|
||||
JS_DescribeScriptedCaller(cx, &script, &lineno);
|
||||
RootedValue rval(cx);
|
||||
{
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
unsigned flags;
|
||||
|
@ -2535,15 +2536,14 @@ EvalInContext(JSContext *cx, unsigned argc, jsval *vp)
|
|||
if (!JS_EvaluateUCScript(cx, sobj, src, srclen,
|
||||
script->filename(),
|
||||
lineno,
|
||||
&rval)) {
|
||||
args.rval())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cx->compartment()->wrap(cx, &rval))
|
||||
if (!cx->compartment()->wrap(cx, args.rval()))
|
||||
return false;
|
||||
|
||||
JS_SET_RVAL(cx, vp, rval);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1173,10 +1173,12 @@ ScriptFrameIter::numFrameSlots() const
|
|||
switch (data_.state_) {
|
||||
case DONE:
|
||||
break;
|
||||
case JIT: {
|
||||
case JIT: {
|
||||
#ifdef JS_ION
|
||||
if (data_.ionFrames_.isOptimizedJS())
|
||||
return ionInlineFrames_.snapshotIterator().slots() - ionInlineFrames_.script()->nfixed();
|
||||
if (data_.ionFrames_.isOptimizedJS()) {
|
||||
return ionInlineFrames_.snapshotIterator().allocations() -
|
||||
ionInlineFrames_.script()->nfixed();
|
||||
}
|
||||
jit::BaselineFrame *frame = data_.ionFrames_.baselineFrame();
|
||||
return frame->numValueSlots() - data_.ionFrames_.script()->nfixed();
|
||||
#else
|
||||
|
@ -1201,7 +1203,7 @@ ScriptFrameIter::frameSlotValue(size_t index) const
|
|||
if (data_.ionFrames_.isOptimizedJS()) {
|
||||
jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
|
||||
index += ionInlineFrames_.script()->nfixed();
|
||||
return si.maybeReadSlotByIndex(index);
|
||||
return si.maybeReadAllocByIndex(index);
|
||||
}
|
||||
|
||||
index += data_.ionFrames_.script()->nfixed();
|
||||
|
|
|
@ -379,7 +379,7 @@ static bool
|
|||
Quit(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
gExitCode = 0;
|
||||
JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp),"/ i", &gExitCode);
|
||||
JS_ConvertArguments(cx, JS::CallArgsFromVp(argc, vp),"/ i", &gExitCode);
|
||||
|
||||
gQuitting = true;
|
||||
// exit(0);
|
||||
|
|
|
@ -2792,6 +2792,12 @@ public:
|
|||
|
||||
virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
||||
bool* aSnap) MOZ_OVERRIDE {
|
||||
*aSnap = false;
|
||||
return nsRegion();
|
||||
}
|
||||
|
||||
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion,
|
||||
const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
|
||||
|
|
|
@ -33,6 +33,8 @@ nsMathMLmoFrame::~nsMathMLmoFrame()
|
|||
static const char16_t kInvisibleComma = char16_t(0x200B); // a.k.a. ZERO WIDTH SPACE
|
||||
static const char16_t kApplyFunction = char16_t(0x2061);
|
||||
static const char16_t kInvisibleTimes = char16_t(0x2062);
|
||||
static const char16_t kInvisibleSeparator = char16_t(0x2063);
|
||||
static const char16_t kInvisiblePlus = char16_t(0x2064);
|
||||
|
||||
eMathMLFrameType
|
||||
nsMathMLmoFrame::GetMathMLFrameType()
|
||||
|
@ -123,6 +125,8 @@ nsMathMLmoFrame::ProcessTextData()
|
|||
if ((length == 1) &&
|
||||
(ch == kInvisibleComma ||
|
||||
ch == kApplyFunction ||
|
||||
ch == kInvisibleSeparator ||
|
||||
ch == kInvisiblePlus ||
|
||||
ch == kInvisibleTimes)) {
|
||||
mFlags |= NS_MATHML_OPERATOR_INVISIBLE;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<html>
|
||||
<math>
|
||||
<mrow>
|
||||
<mn>1</mn>
|
||||
<mn>2</mn>
|
||||
<mn>3</mn>
|
||||
<mn>4</mn>
|
||||
<mn>5</mn>
|
||||
<mn>6</mn>
|
||||
</mrow>
|
||||
</math>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
<html>
|
||||
<math>
|
||||
<mrow>
|
||||
<mn>1</mn>
|
||||
<mo>​<!-- INVISIBLE COMMA --></mo>
|
||||
<mn>2</mn>
|
||||
<mo>⁡<!-- FUNCTION APPLICATION --></mo>
|
||||
<mn>3</mn>
|
||||
<mo>⁢<!-- INVISIBLE TIMES --></mo>
|
||||
<mn>4</mn>
|
||||
<mo>⁣<!-- INVISIBLE SEPARATOR --></mo>
|
||||
<mn>5</mn>
|
||||
<mo>⁤<!-- INVISIBLE PLUS --></mo>
|
||||
<mn>6</mn>
|
||||
</mrow>
|
||||
</math>
|
||||
</html>
|
|
@ -141,6 +141,7 @@ skip-if(B2G) == quotes-1.xhtml quotes-1-ref.xhtml
|
|||
skip-if(B2G) == maction-dynamic-1.html maction-dynamic-1-ref.html # bug 773482
|
||||
== maction-dynamic-2.html maction-dynamic-2-ref.html
|
||||
== mo-lspace-rspace.html mo-lspace-rspace-ref.html
|
||||
== mo-invisibleoperators.html mo-invisibleoperators-ref.html
|
||||
skip-if(B2G) == maction-dynamic-3.html maction-dynamic-3-ref.html # bug 773482
|
||||
== whitespace-trim-1.html whitespace-trim-1-ref.html
|
||||
== whitespace-trim-2.html whitespace-trim-2-ref.html
|
||||
|
|
|
@ -322,7 +322,6 @@ void InvalidateImagesCallback(nsIFrame* aFrame,
|
|||
}
|
||||
|
||||
aItem->Invalidate();
|
||||
aFrame->SchedulePaint();
|
||||
|
||||
// Update ancestor rendering observers (-moz-element etc)
|
||||
nsIFrame *f = aFrame;
|
||||
|
@ -350,6 +349,7 @@ ImageLoader::DoRedraw(FrameSet* aFrameSet)
|
|||
frame->InvalidateFrame();
|
||||
} else {
|
||||
FrameLayerBuilder::IterateRetainedDataFor(frame, InvalidateImagesCallback);
|
||||
frame->SchedulePaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,13 +80,13 @@ PaymentUI.prototype = {
|
|||
|
||||
// If there's only one payment provider that will work, just move on without prompting the user.
|
||||
if (aRequests.length == 1) {
|
||||
aSuccessCb.onresult(aRequestId, aRequests[0].wrappedJSObject.type);
|
||||
aSuccessCb.onresult(aRequestId, aRequests[0].type);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, let the user select a payment provider from a list.
|
||||
for (let i = 0; i < aRequests.length; i++) {
|
||||
let request = aRequests[i].wrappedJSObject;
|
||||
let request = aRequests[i];
|
||||
let requestText = request.providerName;
|
||||
if (request.productPrice) {
|
||||
requestText += " (" + request.productPrice[0].amount + " " +
|
||||
|
@ -100,7 +100,7 @@ PaymentUI.prototype = {
|
|||
title: this.bundle.GetStringFromName("payments.providerdialog.title"),
|
||||
}).setSingleChoiceItems(listItems).show(function(data) {
|
||||
if (data.button > -1 && aSuccessCb) {
|
||||
aSuccessCb.onresult(aRequestId, aRequests[data.button].wrappedJSObject.type);
|
||||
aSuccessCb.onresult(aRequestId, aRequests[data.button].type);
|
||||
} else {
|
||||
_error(aRequestId, "USER_CANCELED");
|
||||
}
|
||||
|
|
|
@ -395,13 +395,15 @@ bool PACResolveToString(const nsCString &aHostName,
|
|||
static
|
||||
bool PACDnsResolve(JSContext *cx, unsigned int argc, JS::Value *vp)
|
||||
{
|
||||
JS::CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
NS_WARNING("DNS Resolution From PAC on Main Thread. How did that happen?");
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSString*> arg1(cx);
|
||||
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", arg1.address()))
|
||||
if (!JS_ConvertArguments(cx, args, "S", arg1.address()))
|
||||
return false;
|
||||
|
||||
nsDependentJSString hostName;
|
||||
|
@ -411,10 +413,10 @@ bool PACDnsResolve(JSContext *cx, unsigned int argc, JS::Value *vp)
|
|||
return false;
|
||||
if (PACResolveToString(NS_ConvertUTF16toUTF8(hostName), dottedDecimal, 0)) {
|
||||
JSString *dottedDecimalString = JS_NewStringCopyZ(cx, dottedDecimal.get());
|
||||
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(dottedDecimalString));
|
||||
args.rval().setString(dottedDecimalString);
|
||||
}
|
||||
else {
|
||||
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
||||
args.rval().setNull();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -441,8 +443,10 @@ bool PACMyIpAddress(JSContext *cx, unsigned int argc, JS::Value *vp)
|
|||
static
|
||||
bool PACProxyAlert(JSContext *cx, unsigned int argc, JS::Value *vp)
|
||||
{
|
||||
JS::CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
JS::Rooted<JSString*> arg1(cx);
|
||||
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", arg1.address()))
|
||||
if (!JS_ConvertArguments(cx, args, "S", arg1.address()))
|
||||
return false;
|
||||
|
||||
nsDependentJSString message;
|
||||
|
@ -455,7 +459,7 @@ bool PACProxyAlert(JSContext *cx, unsigned int argc, JS::Value *vp)
|
|||
alertMessage += message;
|
||||
PACLogToConsole(alertMessage);
|
||||
|
||||
JS_SET_RVAL(cx, vp, JSVAL_VOID); /* return undefined */
|
||||
args.rval().setUndefined(); /* return undefined */
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -236,6 +236,8 @@ class TreeMetadataEmitter(LoggingMixin):
|
|||
'MSVC_ENABLE_PGO',
|
||||
'NO_DIST_INSTALL',
|
||||
'OS_LIBS',
|
||||
'RCFILE',
|
||||
'RESFILE',
|
||||
'SDK_LIBRARY',
|
||||
]
|
||||
for v in varlist:
|
||||
|
|
|
@ -322,6 +322,18 @@ VARIABLES = {
|
|||
This variable contains a list of system libaries to link against.
|
||||
""", None),
|
||||
|
||||
'RCFILE': (unicode, unicode,
|
||||
"""The program .rc file.
|
||||
|
||||
This variable can only be used on Windows (and OS/2).
|
||||
""", None),
|
||||
|
||||
'RESFILE': (unicode, unicode,
|
||||
"""The program .res file.
|
||||
|
||||
This variable can only be used on Windows (and OS/2).
|
||||
""", None),
|
||||
|
||||
'SDK_LIBRARY': (StrictOrderingOnAppendList, list,
|
||||
"""Elements of the distributed SDK.
|
||||
|
||||
|
|
|
@ -35,3 +35,6 @@ MSVC_ENABLE_PGO = True
|
|||
NO_VISIBILITY_FLAGS = True
|
||||
|
||||
DELAYLOAD_DLLS = ['foo.dll', 'bar.dll']
|
||||
|
||||
RCFILE = 'foo.rc'
|
||||
RESFILE = 'bar.res'
|
||||
|
|
|
@ -328,6 +328,12 @@ class TestRecursiveMakeBackend(BackendTester):
|
|||
'USE_DELAYIMP': [
|
||||
'USE_DELAYIMP := 1',
|
||||
],
|
||||
'RCFILE': [
|
||||
'RCFILE := foo.rc',
|
||||
],
|
||||
'RESFILE': [
|
||||
'RESFILE := bar.res',
|
||||
],
|
||||
}
|
||||
|
||||
for var, val in expected.items():
|
||||
|
|
|
@ -41,3 +41,6 @@ IS_COMPONENT = True
|
|||
NO_VISIBILITY_FLAGS = True
|
||||
|
||||
DELAYLOAD_DLLS = ['foo.dll', 'bar.dll']
|
||||
|
||||
RCFILE = 'foo.rc'
|
||||
RESFILE = 'bar.res'
|
||||
|
|
|
@ -171,6 +171,8 @@ class TestEmitterBasic(unittest.TestCase):
|
|||
VISIBILITY_FLAGS='',
|
||||
DELAYLOAD_LDFLAGS=['-DELAYLOAD:foo.dll', '-DELAYLOAD:bar.dll'],
|
||||
USE_DELAYIMP=True,
|
||||
RCFILE='foo.rc',
|
||||
RESFILE='bar.res',
|
||||
)
|
||||
|
||||
variables = objs[0].variables
|
||||
|
|
|
@ -185,13 +185,13 @@ SmartCardMonitoringThread::SetTokenName(CK_SLOT_ID slotid,
|
|||
memcpy(entry,&series,sizeof(uint32_t));
|
||||
memcpy(&entry[sizeof(uint32_t)],tokenName,len);
|
||||
|
||||
PL_HashTableAdd(mHash,(void *)slotid, entry); /* adopt */
|
||||
PL_HashTableAdd(mHash,(void *)(uintptr_t)slotid, entry); /* adopt */
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// if tokenName was not provided, remove the old one (implicit delete)
|
||||
PL_HashTableRemove(mHash,(void *)slotid);
|
||||
PL_HashTableRemove(mHash,(void *)(uintptr_t)slotid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ SmartCardMonitoringThread::GetTokenName(CK_SLOT_ID slotid)
|
|||
const char *entry;
|
||||
|
||||
if (mHash) {
|
||||
entry = (const char *)PL_HashTableLookupConst(mHash,(void *)slotid);
|
||||
entry = (const char *)PL_HashTableLookupConst(mHash,(void *)(uintptr_t)slotid);
|
||||
if (entry) {
|
||||
tokenName = &entry[sizeof(uint32_t)];
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ SmartCardMonitoringThread::GetTokenSeries(CK_SLOT_ID slotid)
|
|||
const char *entry;
|
||||
|
||||
if (mHash) {
|
||||
entry = (const char *)PL_HashTableLookupConst(mHash,(void *)slotid);
|
||||
entry = (const char *)PL_HashTableLookupConst(mHash,(void *)(uintptr_t)slotid);
|
||||
if (entry) {
|
||||
memcpy(&series,entry,sizeof(uint32_t));
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import errno
|
||||
import json
|
||||
import socket
|
||||
|
||||
|
@ -52,9 +53,8 @@ class MarionetteClient(object):
|
|||
response += self._recv_n_bytes(int(length) + 1 + len(length) - 10)
|
||||
return json.loads(response)
|
||||
else:
|
||||
raise InvalidResponseException("Could not successfully complete "
|
||||
"transport of message to Gecko, "
|
||||
"socket closed?",
|
||||
raise InvalidResponseException("Could not communicate with Marionette server. "
|
||||
"Is the Gecko process still running?",
|
||||
status=ErrorCodes.INVALID_RESPONSE)
|
||||
|
||||
def connect(self, timeout=360.0):
|
||||
|
@ -90,7 +90,13 @@ class MarionetteClient(object):
|
|||
|
||||
for packet in [data[i:i + self.max_packet_length] for i in
|
||||
range(0, len(data), self.max_packet_length)]:
|
||||
self.sock.send(packet)
|
||||
try:
|
||||
self.sock.send(packet)
|
||||
except IOError as e:
|
||||
if e.errno == errno.EPIPE:
|
||||
raise IOError("%s: Connection to Marionette server is lost. Check gecko.log (desktop firefox) or logcat (b2g) for errors." % str(e))
|
||||
else:
|
||||
raise e
|
||||
|
||||
response = self.receive()
|
||||
return response
|
||||
|
|
|
@ -20,6 +20,7 @@ from manifestparser import TestManifest
|
|||
from mozhttpd import MozHttpd
|
||||
from marionette import Marionette
|
||||
from moztest.results import TestResultCollection, TestResult, relevant_line
|
||||
from mixins.b2g import B2GTestResultMixin, get_b2g_pid, get_dm
|
||||
|
||||
|
||||
class MarionetteTest(TestResult):
|
||||
|
@ -113,7 +114,7 @@ class MarionetteTestResult(unittest._TextTestResult, TestResultCollection):
|
|||
context=context, **kwargs)
|
||||
# call any registered result modifiers
|
||||
for modifier in self.result_modifiers:
|
||||
modifier(t, result_expected, result_actual, output, context)
|
||||
result_expected, result_actual, output, context = modifier(t, result_expected, result_actual, output, context)
|
||||
t.finish(result_actual,
|
||||
time_end=time.time() if test.start_time else 0,
|
||||
reason=relevant_line(output),
|
||||
|
@ -238,6 +239,7 @@ class MarionetteTextTestRunner(unittest.TextTestRunner):
|
|||
|
||||
def __init__(self, **kwargs):
|
||||
self.marionette = kwargs['marionette']
|
||||
self.capabilities = kwargs.pop('capabilities')
|
||||
del kwargs['marionette']
|
||||
unittest.TextTestRunner.__init__(self, **kwargs)
|
||||
|
||||
|
@ -309,6 +311,40 @@ class MarionetteTextTestRunner(unittest.TextTestRunner):
|
|||
return result
|
||||
|
||||
|
||||
class B2GMarionetteTestResult(MarionetteTestResult, B2GTestResultMixin):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# stupid hack because _TextTestRunner doesn't accept **kwargs
|
||||
b2g_pid = kwargs.pop('b2g_pid')
|
||||
MarionetteTestResult.__init__(self, *args, **kwargs)
|
||||
kwargs['b2g_pid'] = b2g_pid
|
||||
B2GTestResultMixin.__init__(self, *args, **kwargs)
|
||||
|
||||
|
||||
class B2GMarionetteTextTestRunner(MarionetteTextTestRunner):
|
||||
|
||||
resultclass = B2GMarionetteTestResult
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
MarionetteTextTestRunner.__init__(self, **kwargs)
|
||||
if self.capabilities['device'] != 'desktop':
|
||||
self.resultclass = B2GMarionetteTestResult
|
||||
self.b2g_pid = None
|
||||
|
||||
def _makeResult(self):
|
||||
return self.resultclass(self.stream,
|
||||
self.descriptions,
|
||||
self.verbosity,
|
||||
marionette=self.marionette,
|
||||
b2g_pid=self.b2g_pid)
|
||||
|
||||
def run(self, test):
|
||||
dm_type = os.environ.get('DM_TRANS', 'adb')
|
||||
if dm_type == 'adb':
|
||||
self.b2g_pid = get_b2g_pid(get_dm(self.marionette))
|
||||
return super(B2GMarionetteTextTestRunner, self).run(test)
|
||||
|
||||
|
||||
class BaseMarionetteOptions(OptionParser):
|
||||
def __init__(self, **kwargs):
|
||||
OptionParser.__init__(self, **kwargs)
|
||||
|
@ -768,6 +804,12 @@ class BaseMarionetteTestRunner(object):
|
|||
self.start_marionette()
|
||||
if self.emulator:
|
||||
self.marionette.emulator.wait_for_homescreen(self.marionette)
|
||||
# Retrieve capabilities for later use
|
||||
if not self._capabilities:
|
||||
self.capabilities
|
||||
|
||||
if self.capabilities['device'] != 'desktop':
|
||||
self.textrunnerclass = B2GMarionetteTextTestRunner
|
||||
|
||||
testargs = {}
|
||||
if self.type is not None:
|
||||
|
@ -858,7 +900,8 @@ class BaseMarionetteTestRunner(object):
|
|||
|
||||
if suite.countTestCases():
|
||||
runner = self.textrunnerclass(verbosity=3,
|
||||
marionette=self.marionette)
|
||||
marionette=self.marionette,
|
||||
capabilities=self.capabilities)
|
||||
results = runner.run(suite)
|
||||
self.results.append(results)
|
||||
|
||||
|
|
|
@ -4,6 +4,34 @@
|
|||
|
||||
import mozdevice
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
def get_dm(marionette=None,**kwargs):
|
||||
if marionette and marionette.emulator:
|
||||
adb_path = marionette.emulator.b2g.adb_path
|
||||
return mozdevice.DeviceManagerADB(adbPath=adb_path,
|
||||
deviceSerial='emulator-%d' % marionette.emulator.port,
|
||||
**kwargs)
|
||||
else:
|
||||
dm_type = os.environ.get('DM_TRANS', 'adb')
|
||||
if dm_type == 'adb':
|
||||
return mozdevice.DeviceManagerADB(**kwargs)
|
||||
elif dm_type == 'sut':
|
||||
host = os.environ.get('TEST_DEVICE')
|
||||
if not host:
|
||||
raise Exception('Must specify host with SUT!')
|
||||
return mozdevice.DeviceManagerSUT(host=host)
|
||||
else:
|
||||
raise Exception('Unknown device manager type: %s' % dm_type)
|
||||
|
||||
|
||||
def get_b2g_pid(dm):
|
||||
b2g_output = dm.shellCheckOutput(['b2g-ps'])
|
||||
pid_re = re.compile(r"""[\s\S]*root[\s]*([\d]+)[\s]*(?:[\w]*[\s]*){6}/system/b2g/b2g""")
|
||||
if '/system/b2g/b2g' in b2g_output:
|
||||
pid = pid_re.match(b2g_output)
|
||||
return pid.group(1)
|
||||
|
||||
|
||||
class B2GTestCaseMixin(object):
|
||||
|
@ -14,18 +42,61 @@ class B2GTestCaseMixin(object):
|
|||
|
||||
def get_device_manager(self, *args, **kwargs):
|
||||
if not self._device_manager:
|
||||
dm_type = os.environ.get('DM_TRANS', 'adb')
|
||||
if dm_type == 'adb':
|
||||
self._device_manager = mozdevice.DeviceManagerADB(**kwargs)
|
||||
elif dm_type == 'sut':
|
||||
host = os.environ.get('TEST_DEVICE')
|
||||
if not host:
|
||||
raise Exception('Must specify host with SUT!')
|
||||
self._device_manager = mozdevice.DeviceManagerSUT(host=host)
|
||||
else:
|
||||
raise Exception('Unknown device manager type: %s' % dm_type)
|
||||
self._device_manager = get_dm(self.marionette, **kwargs)
|
||||
return self._device_manager
|
||||
|
||||
@property
|
||||
def device_manager(self):
|
||||
return self.get_device_manager()
|
||||
|
||||
class B2GTestResultMixin(object):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.result_modifiers.append(self.b2g_output_modifier)
|
||||
self.b2g_pid = kwargs.pop('b2g_pid')
|
||||
|
||||
def b2g_output_modifier(self, test, result_expected, result_actual, output, context):
|
||||
# This function will check if b2g is running and report any recent errors. This is
|
||||
# used in automation since a plain timeout error doesn't tell you
|
||||
# much information about what actually is going on
|
||||
def diagnose_socket(output):
|
||||
dm_type = os.environ.get('DM_TRANS', 'adb')
|
||||
if dm_type == 'adb':
|
||||
device_manager = get_dm(self.marionette)
|
||||
pid = get_b2g_pid(device_manager)
|
||||
if pid:
|
||||
# find recent errors
|
||||
message = ""
|
||||
error_re = re.compile(r"""[\s\S]*(exception|error)[\s\S]*""", flags=re.IGNORECASE)
|
||||
logcat = device_manager.getLogcat()
|
||||
latest = []
|
||||
iters = len(logcat) - 1
|
||||
# reading from the latest line
|
||||
while len(latest) < 5 and iters >= 0:
|
||||
line = logcat[iters]
|
||||
error_log_line = error_re.match(line)
|
||||
if error_log_line is not None:
|
||||
latest.append(line)
|
||||
iters -= 1
|
||||
message += "\nMost recent errors/exceptions are:\n"
|
||||
for line in reversed(latest):
|
||||
message += "%s" % line
|
||||
b2g_status = ""
|
||||
if pid != self.b2g_pid:
|
||||
b2g_status = "The B2G process has restarted after crashing during the tests so "
|
||||
else:
|
||||
b2g_status = "B2G is still running but "
|
||||
output += "%s\n%sMarionette can't respond due to either a Gecko, Gaia or Marionette error. " \
|
||||
"Above, the 5 most recent errors are " \
|
||||
"listed. Check logcat for all errors if these errors are not the cause " \
|
||||
"of the failure." % (message, b2g_status)
|
||||
else:
|
||||
output += "B2G process has died"
|
||||
return output
|
||||
# output is the actual string output from the test, so we have to do string comparison
|
||||
if "Broken pipe" in output:
|
||||
output = diagnose_socket(output)
|
||||
elif "Connection timed out" in output:
|
||||
output = diagnose_socket(output)
|
||||
return result_expected, result_actual, output, context
|
||||
|
||||
|
|
|
@ -193,6 +193,7 @@ class HTMLReportingTestResultMixin(object):
|
|||
test.debug = None
|
||||
if result_actual is not 'PASS':
|
||||
test.debug = self.gather_debug()
|
||||
return result_expected, result_actual, output, context
|
||||
|
||||
def gather_debug(self):
|
||||
debug = {}
|
||||
|
|
|
@ -35,7 +35,6 @@ LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/base
|
|||
endif
|
||||
|
||||
ifeq ($(OS_ARCH),OS2)
|
||||
RESFILE = xulrunos2.res
|
||||
RCFLAGS += -i $(topsrcdir)/widget/os2
|
||||
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/widget/os2
|
||||
|
|
|
@ -44,6 +44,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'os2', 'mac', 'cocoa',
|
|||
'gtk2', 'gtk3', 'qt', 'android'):
|
||||
DEFINES['ICON_DECODER'] = True
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/config',
|
||||
# need widget/windows for resource.h (included from widget.rc)
|
||||
'/widget/windows',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']:
|
||||
LOCAL_INCLUDES += [
|
||||
'/xpcom/base',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
MSVC_ENABLE_PGO = True
|
||||
|
|
|
@ -52,7 +52,7 @@ PaymentUI.prototype = {
|
|||
// If there's only one payment provider that will work, just move on
|
||||
// without prompting the user.
|
||||
if (aRequests.length == 1) {
|
||||
aSuccessCb.onresult(aRequestId, aRequests[0].wrappedJSObject.type);
|
||||
aSuccessCb.onresult(aRequestId, aRequests[0].type);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ PaymentUI.prototype = {
|
|||
|
||||
// Otherwise, let the user select a payment provider from a list.
|
||||
for (let i = 0; i < aRequests.length; i++) {
|
||||
let request = aRequests[i].wrappedJSObject;
|
||||
let request = aRequests[i];
|
||||
let requestText = request.providerName;
|
||||
if (request.productPrice && Array.isArray(request.productPrice)) {
|
||||
// We should guess the user currency and use that instead.
|
||||
|
@ -80,7 +80,7 @@ PaymentUI.prototype = {
|
|||
items.length, items, selected);
|
||||
if (result) {
|
||||
aSuccessCb.onresult(aRequestId,
|
||||
aRequests[selected.value].wrappedJSObject.type);
|
||||
aRequests[selected.value].type);
|
||||
} else {
|
||||
aErrorCb.onresult(aRequestId, "USER_CANCELLED");
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
RESFILE = widget.res
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
|
||||
|
|
|
@ -36,3 +36,5 @@ LOCAL_INCLUDES += [
|
|||
DEFINES['USE_OS2_TOOLKIT_HEADERS'] = True
|
||||
|
||||
DEFINES['MOZ_APP_DISPLAYNAME'] = '"%s"' % CONFIG['MOZ_APP_DISPLAYNAME']
|
||||
|
||||
RESFILE = 'widget.res'
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
RESFILE = widget.res
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
|
||||
|
|
|
@ -112,3 +112,5 @@ DEFINES['MOZ_UNICODE'] = True
|
|||
for var in ('MOZ_ENABLE_D3D9_LAYER', 'MOZ_ENABLE_D3D10_LAYER'):
|
||||
if CONFIG[var]:
|
||||
DEFINES[var] = True
|
||||
|
||||
RESFILE = 'widget.res'
|
||||
|
|
|
@ -80,7 +80,7 @@ nsWindowsRegKey::Open(uint32_t rootKey, const nsAString &path, uint32_t mode)
|
|||
{
|
||||
Close();
|
||||
|
||||
LONG rv = RegOpenKeyExW((HKEY) rootKey, PromiseFlatString(path).get(), 0,
|
||||
LONG rv = RegOpenKeyExW((HKEY)(intptr_t) rootKey, PromiseFlatString(path).get(), 0,
|
||||
(REGSAM) mode, &mKey);
|
||||
|
||||
return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
@ -92,7 +92,7 @@ nsWindowsRegKey::Create(uint32_t rootKey, const nsAString &path, uint32_t mode)
|
|||
Close();
|
||||
|
||||
DWORD disposition;
|
||||
LONG rv = RegCreateKeyExW((HKEY) rootKey, PromiseFlatString(path).get(), 0,
|
||||
LONG rv = RegCreateKeyExW((HKEY)(intptr_t) rootKey, PromiseFlatString(path).get(), 0,
|
||||
nullptr, REG_OPTION_NON_VOLATILE, (REGSAM) mode, nullptr,
|
||||
&mKey, &disposition);
|
||||
|
||||
|
|
|
@ -256,7 +256,7 @@ if CONFIG['OS_ARCH'] == 'OpenBSD' and CONFIG['OS_TEST'] == 'sparc':
|
|||
'xptcstubs_sparc_openbsd.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'OpenBSD' and CONFIG['OS_TEST'] == 'sparc64':
|
||||
if CONFIG['OS_ARCH'] in ('OpenBSD', 'FreeBSD') and CONFIG['OS_TEST'] == 'sparc64':
|
||||
SOURCES += [
|
||||
'xptcinvoke_asm_sparc64_openbsd.s',
|
||||
'xptcinvoke_sparc64_openbsd.cpp',
|
||||
|
|
|
@ -59,7 +59,6 @@ endif
|
|||
endif
|
||||
|
||||
ifeq ($(OS_ARCH),OS2)
|
||||
RESFILE=splashos2.res
|
||||
RCFLAGS += -DMOZ_XULRUNNER
|
||||
ifdef DEBUG
|
||||
RCFLAGS += -DDEBUG
|
||||
|
|
Загрузка…
Ссылка в новой задаче