Merge inbound to m-c.

This commit is contained in:
Ryan VanderMeulen 2014-02-10 15:42:58 -05:00
commit d2ef169276
77 changed files with 1682 additions and 874 deletions

View File

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

View File

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

View File

@ -322,6 +322,7 @@ public:
void SetDisplayState(HTMLDivElement* aDisplayState)
{
mDisplayState = aDisplayState;
mReset = false;
}
bool HasBeenReset()

View File

@ -5,5 +5,6 @@ support-files =
basic.vtt
seek.webm
[test_texttrackcue_chrome.html]
[test_texttrack_chrome.html]
[test_texttracklist_chrome.html]

View File

@ -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"] },

View File

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

View File

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

View File

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

View File

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

View File

@ -42,3 +42,7 @@ elif toolkit == 'windows':
]
FORCE_SHARED_LIB = True
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
RCFILE = 'nptest.rc'
RESFILE = 'nptest.res'

View File

@ -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;
}
};

View File

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

View File

@ -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) \

View File

@ -15,3 +15,5 @@ SOURCES += [
XPI_NAME = 'winembed'
DEFINES['XPCOM_GLUE'] = True
RESFILE = 'winEmbed.res'

View File

@ -14,7 +14,6 @@ endif
# Target: 'libEGL'
# Links with: 'libGLESv2'
DEFFILE = $(srcdir)/libEGL.def
RCFILE = $(srcdir)/libEGL.rc
include $(topsrcdir)/config/rules.mk

View File

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

View File

@ -11,7 +11,6 @@ OS_CPPFLAGS += -EHsc
endif
DEFFILE = $(srcdir)/libGLESv2.def
RCFILE = $(srcdir)/libGLESv2.rc
# End build_angle.gypi transcription.

View File

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

View File

@ -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));
}
};

View File

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

View File

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

View File

@ -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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();

View File

@ -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: ");

View File

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

View File

@ -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 &reg) {
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 &reg)
: mode_(DOUBLE_REG)
{
fpu_ = reg.code();
}
Slot(SlotMode mode, const FloatRegister &reg)
: 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 */

View File

@ -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 &reg);
void addSlot(JSValueType type, const Register &reg);
void addSlot(JSValueType type, int32_t stackIndex);
void addUndefinedSlot();
void addNullSlot();
void addInt32Slot(int32_t value);
void addFloat32Slot(const FloatRegister &reg);
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 */

View File

@ -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 &reg)
{
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 &reg)
{
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 &reg)
{
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);
}
}

463
js/src/jit/Snapshots.h Normal file
View File

@ -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 &reg) {
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 &reg)
: 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 &reg) {
return RValueAllocation(DOUBLE_REG, reg);
}
// FLOAT32_REG or FLOAT32_STACK
static RValueAllocation Float32(const FloatRegister &reg) {
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 &reg) {
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 */

View File

@ -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;
}

View File

@ -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);

View File

@ -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();
}

View File

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

View File

@ -41,6 +41,7 @@ UNIFIED_SOURCES += [
'testIntern.cpp',
'testIntString.cpp',
'testIntTypesABI.cpp',
'testJitRValueAlloc.cpp',
'testJSEvaluateScript.cpp',
'testLookup.cpp',
'testLooselyEqual.cpp',

View File

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

View File

@ -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;
}

View File

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

View File

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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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);

View File

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

View File

@ -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;
}

View File

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

View File

@ -0,0 +1,17 @@
<html>
<math>
<mrow>
<mn>1</mn>
<mo>&#x200B;<!-- INVISIBLE COMMA --></mo>
<mn>2</mn>
<mo>&#x2061;<!-- FUNCTION APPLICATION --></mo>
<mn>3</mn>
<mo>&#x2062;<!-- INVISIBLE TIMES --></mo>
<mn>4</mn>
<mo>&#x2063;<!-- INVISIBLE SEPARATOR --></mo>
<mn>5</mn>
<mo>&#x2064;<!-- INVISIBLE PLUS --></mo>
<mn>6</mn>
</mrow>
</math>
</html>

View File

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

View File

@ -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();
}
}
}

View File

@ -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");
}

View File

@ -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;
}

View File

@ -236,6 +236,8 @@ class TreeMetadataEmitter(LoggingMixin):
'MSVC_ENABLE_PGO',
'NO_DIST_INSTALL',
'OS_LIBS',
'RCFILE',
'RESFILE',
'SDK_LIBRARY',
]
for v in varlist:

View File

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

View File

@ -35,3 +35,6 @@ MSVC_ENABLE_PGO = True
NO_VISIBILITY_FLAGS = True
DELAYLOAD_DLLS = ['foo.dll', 'bar.dll']
RCFILE = 'foo.rc'
RESFILE = 'bar.res'

View File

@ -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():

View File

@ -41,3 +41,6 @@ IS_COMPONENT = True
NO_VISIBILITY_FLAGS = True
DELAYLOAD_DLLS = ['foo.dll', 'bar.dll']
RCFILE = 'foo.rc'
RESFILE = 'bar.res'

View File

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

View File

@ -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));
}

View File

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

View File

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

View File

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

View File

@ -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 = {}

View File

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

View File

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

View File

@ -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");
}

View File

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

View File

@ -36,3 +36,5 @@ LOCAL_INCLUDES += [
DEFINES['USE_OS2_TOOLKIT_HEADERS'] = True
DEFINES['MOZ_APP_DISPLAYNAME'] = '"%s"' % CONFIG['MOZ_APP_DISPLAYNAME']
RESFILE = 'widget.res'

View File

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

View File

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

View File

@ -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);

View File

@ -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',

View File

@ -59,7 +59,6 @@ endif
endif
ifeq ($(OS_ARCH),OS2)
RESFILE=splashos2.res
RCFLAGS += -DMOZ_XULRUNNER
ifdef DEBUG
RCFLAGS += -DDEBUG