mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[JAEGER] Re-added Dave Mandelin's polymorphic inline caches for GETPROP (bug 572310).
This commit is contained in:
parent
ff9eadf410
commit
884b494c29
@ -313,6 +313,7 @@ CPPSRCS += Assertions.cpp \
|
||||
FastOps.cpp \
|
||||
StubCompiler.cpp \
|
||||
MonoIC.cpp \
|
||||
PolyIC.cpp \
|
||||
ImmutableSync.cpp \
|
||||
InvokeHelpers.cpp \
|
||||
$(NULL)
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
JITCode& code = codeBlock->getJITCode();
|
||||
m_start = code.start();
|
||||
m_size = code.size();
|
||||
mprot = true;
|
||||
|
||||
if (mprot)
|
||||
ExecutableAllocator::makeWritable(m_start, m_size);
|
||||
|
@ -587,6 +587,9 @@ JSThreadData::purge(JSContext *cx)
|
||||
if (cx->runtime->gcRegenShapes)
|
||||
traceMonitor.needFlush = JS_TRUE;
|
||||
#endif
|
||||
#ifdef JS_METHODJIT
|
||||
jmData.purge(cx);
|
||||
#endif
|
||||
|
||||
/* Destroy eval'ed scripts. */
|
||||
js_DestroyScriptsToGC(cx, this);
|
||||
|
@ -236,6 +236,7 @@ namespace mjit {
|
||||
|
||||
bool addScript(JSScript *script);
|
||||
void removeScript(JSScript *script);
|
||||
void purge(JSContext *cx);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -189,6 +189,10 @@ struct JSScript {
|
||||
(char*)jcode < (char*)ncode + jitLength;
|
||||
}
|
||||
# endif
|
||||
|
||||
inline uint32 numPICs() {
|
||||
return *(uint32*)((uint8 *)pics - sizeof(uint32));
|
||||
}
|
||||
#endif
|
||||
#if 0 /* def JS_TRACER */
|
||||
js::TraceTreeCache *trees; /* trace tree info. */
|
||||
|
@ -117,6 +117,11 @@ class BaseAssembler : public JSC::MacroAssembler
|
||||
load32(ptr, reg);
|
||||
}
|
||||
|
||||
void loadShape(RegisterID obj, RegisterID shape) {
|
||||
loadPtr(Address(obj, offsetof(JSObject, map)), shape);
|
||||
load32(Address(shape, offsetof(JSObjectMap, shape)), shape);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds and returns the address of a known object and slot.
|
||||
*/
|
||||
@ -222,15 +227,15 @@ class BaseAssembler : public JSC::MacroAssembler
|
||||
|
||||
Call call(void *fun) {
|
||||
#if defined(_MSC_VER) && defined(_M_X64)
|
||||
masm.subPtr(JSC::MacroAssembler::Imm32(32),
|
||||
JSC::MacroAssembler::stackPointerRegister);
|
||||
subPtr(JSC::MacroAssembler::Imm32(32),
|
||||
JSC::MacroAssembler::stackPointerRegister);
|
||||
#endif
|
||||
|
||||
Call cl = JSC::MacroAssembler::call();
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_X64)
|
||||
masm.addPtr(JSC::MacroAssembler::Imm32(32),
|
||||
JSC::MacroAssembler::stackPointerRegister);
|
||||
addPtr(JSC::MacroAssembler::Imm32(32),
|
||||
JSC::MacroAssembler::stackPointerRegister);
|
||||
#endif
|
||||
|
||||
callPatches.append(CallPatch(differenceBetween(startLabel, cl), fun));
|
||||
|
@ -76,7 +76,8 @@ static const JSC::MacroAssembler::RegisterID JSReturnReg_Data = JSC::X86Register
|
||||
mjit::Compiler::Compiler(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain)
|
||||
: cx(cx), script(script), scopeChain(scopeChain), globalObj(scopeChain->getGlobal()), fun(fun),
|
||||
analysis(cx, script), jumpMap(NULL), frame(cx, script, masm),
|
||||
branchPatches(ContextAllocPolicy(cx)), mics(ContextAllocPolicy(cx)), stubcc(cx, *this, frame, script)
|
||||
branchPatches(ContextAllocPolicy(cx)), mics(ContextAllocPolicy(cx)),
|
||||
pics(ContextAllocPolicy(cx)), stubcc(cx, *this, frame, script)
|
||||
{
|
||||
}
|
||||
|
||||
@ -238,7 +239,7 @@ mjit::Compiler::finishThisUp()
|
||||
memcpy(result + masm.size(), stubcc.buffer(), stubcc.size());
|
||||
|
||||
/* Build the pc -> ncode mapping. */
|
||||
void **nmap = (void **)cx->calloc(sizeof(void *) * script->length + 1);
|
||||
void **nmap = (void **)cx->calloc(sizeof(void *) * (script->length + 1));
|
||||
if (!nmap) {
|
||||
execPool->release();
|
||||
return Compile_Error;
|
||||
@ -277,6 +278,34 @@ mjit::Compiler::finishThisUp()
|
||||
script->mics[i].dataWrite = mics[i].dataWrite;
|
||||
}
|
||||
|
||||
if (pics.length()) {
|
||||
uint8 *cursor = (uint8 *)cx->calloc(sizeof(ic::PICInfo) * pics.length() + sizeof(uint32));
|
||||
if (!cursor) {
|
||||
execPool->release();
|
||||
return Compile_Error;
|
||||
}
|
||||
*(uint32*)cursor = pics.length();
|
||||
cursor += sizeof(uint32);
|
||||
script->pics = (ic::PICInfo *)cursor;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pics.length(); i++) {
|
||||
script->pics[i].kind = pics[i].kind;
|
||||
script->pics[i].shapeRegHasBaseShape = true;
|
||||
script->pics[i].fastPathStart = fullCode.locationOf(pics[i].hotPathBegin);
|
||||
script->pics[i].storeBack = fullCode.locationOf(pics[i].storeBack);
|
||||
script->pics[i].slowPathStart = stubCode.locationOf(pics[i].slowPathStart);
|
||||
script->pics[i].callReturn = uint8((uint8*)stubCode.locationOf(pics[i].callReturn).executableAddress() -
|
||||
(uint8*)script->pics[i].slowPathStart.executableAddress());
|
||||
script->pics[i].shapeReg = pics[i].shapeReg;
|
||||
script->pics[i].objReg = pics[i].objReg;
|
||||
script->pics[i].objRemat = pics[i].objRemat.offset;
|
||||
script->pics[i].atomIndex = pics[i].atomIndex;
|
||||
script->pics[i].shapeGuard = masm.distanceOf(pics[i].shapeGuard) -
|
||||
masm.distanceOf(pics[i].hotPathBegin);
|
||||
new (&script->pics[i].execPools) ic::PICInfo::ExecPoolVector(SystemAllocPolicy());
|
||||
}
|
||||
|
||||
/* Link fast and slow paths together. */
|
||||
stubcc.fixCrossJumps(result, masm.size(), masm.size() + stubcc.size());
|
||||
|
||||
@ -674,23 +703,23 @@ mjit::Compiler::generateMethod()
|
||||
BEGIN_CASE(JSOP_GETTHISPROP)
|
||||
/* Push thisv onto stack. */
|
||||
jsop_this();
|
||||
jsop_getprop_slow();
|
||||
jsop_getprop(fullAtomIndex(PC));
|
||||
END_CASE(JSOP_GETTHISPROP);
|
||||
|
||||
BEGIN_CASE(JSOP_GETARGPROP)
|
||||
/* Push arg onto stack. */
|
||||
jsop_getarg(GET_SLOTNO(PC));
|
||||
jsop_getprop_slow();
|
||||
jsop_getprop(fullAtomIndex(&PC[ARGNO_LEN]));
|
||||
END_CASE(JSOP_GETARGPROP)
|
||||
|
||||
BEGIN_CASE(JSOP_GETLOCALPROP)
|
||||
frame.pushLocal(GET_SLOTNO(PC));
|
||||
jsop_getprop_slow();
|
||||
jsop_getprop(fullAtomIndex(&PC[SLOTNO_LEN]));
|
||||
END_CASE(JSOP_GETLOCALPROP)
|
||||
|
||||
BEGIN_CASE(JSOP_GETPROP)
|
||||
BEGIN_CASE(JSOP_GETXPROP)
|
||||
jsop_getprop_slow();
|
||||
jsop_getprop(fullAtomIndex(PC));
|
||||
END_CASE(JSOP_GETPROP)
|
||||
|
||||
BEGIN_CASE(JSOP_LENGTH)
|
||||
@ -1792,6 +1821,87 @@ mjit::Compiler::jsop_getprop_slow()
|
||||
frame.pushSynced();
|
||||
}
|
||||
|
||||
#if ENABLE_PIC
|
||||
void
|
||||
mjit::Compiler::jsop_getprop(uint32 atomIndex)
|
||||
{
|
||||
FrameEntry *top = frame.peek(-1);
|
||||
|
||||
/* If the incoming type is not an object, take a slow path. */
|
||||
if (top->isTypeKnown() &&
|
||||
(top->getTypeTag() != JSVAL_MASK32_FUNOBJ &&
|
||||
top->getTypeTag() != JSVAL_MASK32_NONFUNOBJ)) {
|
||||
jsop_getprop_slow();
|
||||
return;
|
||||
}
|
||||
|
||||
PICGenInfo pic(ic::PICInfo::GET);
|
||||
pic.hotPathBegin = masm.label();
|
||||
|
||||
/* Guard that the type is an object. */
|
||||
Jump typeMismatch;
|
||||
bool typeMismatchSet = false;
|
||||
if (!top->isTypeKnown()) {
|
||||
RegisterID reg = frame.tempRegForType(top);
|
||||
RegisterID type = frame.allocReg();
|
||||
masm.move(reg, type);
|
||||
masm.and32(Imm32(JSVAL_MASK32_OBJECT), type);
|
||||
Jump j = masm.branch32(Assembler::BelowOrEqual, type, Imm32(JSVAL_MASK32_CLEAR));
|
||||
stubcc.linkExit(j);
|
||||
stubcc.leave();
|
||||
stubcc.call(stubs::GetProp);
|
||||
typeMismatch = stubcc.masm.jump();
|
||||
frame.freeReg(type);
|
||||
typeMismatchSet = true;
|
||||
}
|
||||
|
||||
RegisterID shapeReg = frame.allocReg();
|
||||
RegisterID objReg = frame.copyDataIntoReg(top);
|
||||
pic.shapeReg = shapeReg;
|
||||
pic.atomIndex = atomIndex;
|
||||
pic.objRemat = frame.dataRematInfo(top);
|
||||
|
||||
/* Guard on shape. */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, map)), shapeReg);
|
||||
masm.load32(Address(shapeReg, offsetof(JSObjectMap, shape)), shapeReg);
|
||||
pic.shapeGuard = masm.label();
|
||||
Jump j = masm.branch32(Assembler::NotEqual, shapeReg,
|
||||
Imm32(int32(JSObjectMap::INVALID_SHAPE)));
|
||||
pic.slowPathStart = stubcc.masm.label();
|
||||
stubcc.linkExit(j);
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
|
||||
pic.callReturn = stubcc.call(ic::GetProp);
|
||||
|
||||
/* Load dslots. */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
|
||||
/* Copy the slot value to the expression stack. */
|
||||
Address slot(objReg, 1 << 24);
|
||||
frame.pop();
|
||||
masm.loadTypeTag(slot, shapeReg);
|
||||
masm.loadData32(slot, objReg);
|
||||
pic.objReg = objReg;
|
||||
frame.pushRegs(shapeReg, objReg);
|
||||
pic.storeBack = masm.label();
|
||||
|
||||
if (typeMismatchSet)
|
||||
typeMismatch.linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
stubcc.rejoin(1);
|
||||
|
||||
pics.append(pic);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getprop(uint32 atomIndex)
|
||||
{
|
||||
jsop_getprop_slow();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getarg(uint32 index)
|
||||
{
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "CodeGenIncludes.h"
|
||||
#include "StubCompiler.h"
|
||||
#include "MonoIC.h"
|
||||
#include "PolyIC.h"
|
||||
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
@ -85,6 +86,21 @@ class Compiler
|
||||
bool dataWrite;
|
||||
};
|
||||
|
||||
struct PICGenInfo {
|
||||
PICGenInfo(ic::PICInfo::Kind kind) : kind(kind)
|
||||
{ }
|
||||
ic::PICInfo::Kind kind;
|
||||
Label hotPathBegin;
|
||||
Label storeBack;
|
||||
Label slowPathStart;
|
||||
RegisterID shapeReg;
|
||||
RegisterID objReg;
|
||||
Label shapeGuard;
|
||||
uint32 atomIndex;
|
||||
StateRemat objRemat;
|
||||
Call callReturn;
|
||||
};
|
||||
|
||||
struct Uses {
|
||||
Uses(uint32 nuses)
|
||||
: nuses(nuses)
|
||||
@ -111,6 +127,7 @@ class Compiler
|
||||
FrameState frame;
|
||||
js::Vector<BranchPatch, 64> branchPatches;
|
||||
js::Vector<MICGenInfo, 64> mics;
|
||||
js::Vector<PICGenInfo, 64> pics;
|
||||
StubCompiler stubcc;
|
||||
Label invokeLabel;
|
||||
|
||||
@ -169,6 +186,7 @@ class Compiler
|
||||
void jsop_setelem_slow();
|
||||
void jsop_getelem_slow();
|
||||
void jsop_unbrand();
|
||||
void jsop_getprop(uint32 atomIndex);
|
||||
|
||||
/* Fast opcodes. */
|
||||
void jsop_bitop(JSOp op);
|
||||
|
@ -596,6 +596,23 @@ FrameState::addEscaping(uint32 local)
|
||||
escaping[local] = 1;
|
||||
}
|
||||
|
||||
inline StateRemat
|
||||
FrameState::dataRematInfo(const FrameEntry *fe) const
|
||||
{
|
||||
if (fe->isCopy())
|
||||
fe = fe->copyOf();
|
||||
StateRemat remat;
|
||||
if (fe->data.inRegister()) {
|
||||
remat.reg = fe->data.reg();
|
||||
remat.inReg = true;
|
||||
} else {
|
||||
JS_ASSERT(fe->data.synced());
|
||||
remat.offset = addressOf(fe).offset;
|
||||
remat.inReg = false;
|
||||
}
|
||||
return remat;
|
||||
}
|
||||
|
||||
} /* namspace mjit */
|
||||
} /* namspace js */
|
||||
|
||||
|
@ -49,6 +49,15 @@
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
|
||||
struct StateRemat {
|
||||
typedef JSC::MacroAssembler::RegisterID RegisterID;
|
||||
union {
|
||||
RegisterID reg : 5;
|
||||
uint32 offset : 31;
|
||||
};
|
||||
bool inReg : 1;
|
||||
};
|
||||
|
||||
/*
|
||||
* The FrameState keeps track of values on the frame during compilation.
|
||||
* The compiler can query FrameState for information about arguments, locals,
|
||||
@ -430,6 +439,8 @@ class FrameState
|
||||
|
||||
Address addressOf(const FrameEntry *fe) const;
|
||||
|
||||
inline StateRemat dataRematInfo(const FrameEntry *fe) const;
|
||||
|
||||
/*
|
||||
* This is similar to freeReg(ownRegForData(fe)) - except no movement takes place.
|
||||
* The fe is simply invalidated as if it were popped. This can be used to free
|
||||
|
@ -41,6 +41,8 @@
|
||||
#include "assembler/jit/ExecutableAllocator.h"
|
||||
#include "jstracer.h"
|
||||
#include "BaseAssembler.h"
|
||||
#include "MonoIC.h"
|
||||
#include "PolyIC.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::mjit;
|
||||
@ -569,6 +571,22 @@ ThreadData::removeScript(JSScript *script)
|
||||
picScripts.remove(p);
|
||||
}
|
||||
|
||||
void
|
||||
ThreadData::purge(JSContext *cx)
|
||||
{
|
||||
if (!cx->runtime->gcRegenShapes)
|
||||
return;
|
||||
|
||||
for (ThreadData::ScriptSet::Enum e(picScripts); !e.empty(); e.popFront()) {
|
||||
JSScript *script = e.front();
|
||||
ic::PurgePICs(cx, script);
|
||||
//PurgeMICs(cs, script);
|
||||
}
|
||||
|
||||
picScripts.clear();
|
||||
}
|
||||
|
||||
|
||||
extern "C" JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code,
|
||||
uintptr_t inlineCallCount);
|
||||
|
||||
@ -629,6 +647,12 @@ mjit::JaegerShot(JSContext *cx)
|
||||
return ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void Destroy(T &t)
|
||||
{
|
||||
t.~T();
|
||||
}
|
||||
|
||||
void
|
||||
mjit::ReleaseScriptCode(JSContext *cx, JSScript *script)
|
||||
{
|
||||
@ -641,13 +665,16 @@ mjit::ReleaseScriptCode(JSContext *cx, JSScript *script)
|
||||
script->jitLength = 0;
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_PIC) && ENABLE_PIC
|
||||
#if ENABLE_PIC
|
||||
if (script->pics) {
|
||||
delete[] script->pics;
|
||||
script->pics = NULL;
|
||||
uint32 npics = script->numPICs();
|
||||
for (uint32 i = 0; i < npics; i++) {
|
||||
script->pics[i].releasePools();
|
||||
Destroy(script->pics[i].execPools);
|
||||
}
|
||||
JS_METHODJIT_DATA(cx).removeScript(script);
|
||||
cx->free((uint8*)script->pics - sizeof(uint32));
|
||||
}
|
||||
script->npics = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -209,6 +209,9 @@ CanMethodJIT(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeCh
|
||||
return Compile_Okay;
|
||||
}
|
||||
|
||||
void
|
||||
PurgeShapeDependencies(JSContext *cx);
|
||||
|
||||
} /* namespace mjit */
|
||||
|
||||
} /* namespace js */
|
||||
@ -221,3 +224,4 @@ extern "C" void JaegerThrowpoline();
|
||||
extern "C" void JaegerFromTracer();
|
||||
|
||||
#endif /* jsjaeger_h__ */
|
||||
|
||||
|
425
js/src/methodjit/PolyIC.cpp
Normal file
425
js/src/methodjit/PolyIC.cpp
Normal file
@ -0,0 +1,425 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* May 28, 2008.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Brendan Eich <brendan@mozilla.org>
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Mandelin <dmandelin@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "PolyIC.h"
|
||||
#include "StubCalls.h"
|
||||
#include "CodeGenIncludes.h"
|
||||
#include "StubCalls-inl.h"
|
||||
#include "assembler/assembler/LinkBuffer.h"
|
||||
#include "jsscope.h"
|
||||
#include "jsnum.h"
|
||||
#include "jsscopeinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::mjit;
|
||||
|
||||
#if ENABLE_PIC
|
||||
|
||||
/* Rough over-estimate of how much memory we need to unprotect. */
|
||||
static const uint32 INLINE_PATH_LENGTH = 64;
|
||||
|
||||
/* Maximum number of stubs for a given callsite. */
|
||||
static const uint32 MAX_STUBS = 16;
|
||||
|
||||
typedef JSC::FunctionPtr FunctionPtr;
|
||||
typedef JSC::RepatchBuffer RepatchBuffer;
|
||||
typedef JSC::CodeBlock CodeBlock;
|
||||
typedef JSC::CodeLocationLabel CodeLocationLabel;
|
||||
typedef JSC::JITCode JITCode;
|
||||
typedef JSC::MacroAssembler::Jump Jump;
|
||||
typedef JSC::MacroAssembler::RegisterID RegisterID;
|
||||
typedef JSC::MacroAssembler::Label Label;
|
||||
typedef JSC::MacroAssembler::Imm32 Imm32;
|
||||
typedef JSC::MacroAssembler::Address Address;
|
||||
typedef JSC::ReturnAddressPtr ReturnAddressPtr;
|
||||
typedef JSC::MacroAssemblerCodePtr MacroAssemblerCodePtr;
|
||||
|
||||
struct AutoPropertyDropper
|
||||
{
|
||||
JSContext *cx;
|
||||
JSObject *holder;
|
||||
JSProperty *prop;
|
||||
|
||||
public:
|
||||
AutoPropertyDropper(JSContext *cx, JSObject *obj, JSProperty *prop)
|
||||
: cx(cx), holder(obj), prop(prop)
|
||||
{
|
||||
JS_ASSERT(prop);
|
||||
}
|
||||
|
||||
~AutoPropertyDropper()
|
||||
{
|
||||
holder->dropProperty(cx, prop);
|
||||
}
|
||||
};
|
||||
|
||||
class PICStubCompiler
|
||||
{
|
||||
const char *type;
|
||||
|
||||
protected:
|
||||
VMFrame &f;
|
||||
JSScript *script;
|
||||
ic::PICInfo &pic;
|
||||
|
||||
public:
|
||||
PICStubCompiler(const char *type, VMFrame &f, JSScript *script, ic::PICInfo &pic)
|
||||
: type(type), f(f), script(script), pic(pic)
|
||||
{ }
|
||||
|
||||
bool disable(const char *reason, VoidStub stub)
|
||||
{
|
||||
return disable(reason, JS_FUNC_TO_DATA_PTR(void *, stub));
|
||||
}
|
||||
|
||||
bool disable(const char *reason, void *stub)
|
||||
{
|
||||
spew("disabled", reason);
|
||||
JITCode jitCode(pic.slowPathStart.executableAddress(), INLINE_PATH_LENGTH);
|
||||
CodeBlock codeBlock(jitCode);
|
||||
RepatchBuffer repatcher(&codeBlock);
|
||||
ReturnAddressPtr retPtr(pic.slowPathStart.callAtOffset(pic.callReturn).executableAddress());
|
||||
MacroAssemblerCodePtr target(stub);
|
||||
repatcher.relinkCallerToTrampoline(retPtr, target);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSC::ExecutablePool *getExecPool(size_t size)
|
||||
{
|
||||
mjit::ThreadData *jd = &JS_METHODJIT_DATA(f.cx);
|
||||
return jd->execPool->poolForSize(size);
|
||||
}
|
||||
|
||||
protected:
|
||||
void spew(const char *event, const char *op)
|
||||
{
|
||||
JaegerSpew(JSpew_PICs, "%s %s: %s (%s: %d)\n",
|
||||
type, event, op, script->filename,
|
||||
js_FramePCToLineNumber(f.cx, f.fp));
|
||||
}
|
||||
};
|
||||
|
||||
class PICRepatchBuffer : public JSC::RepatchBuffer
|
||||
{
|
||||
ic::PICInfo &pic;
|
||||
|
||||
public:
|
||||
PICRepatchBuffer(ic::PICInfo &ic)
|
||||
: JSC::RepatchBuffer(ic.lastPathStart().executableAddress(),
|
||||
INLINE_PATH_LENGTH),
|
||||
pic(ic)
|
||||
{ }
|
||||
|
||||
void relink(int32 offset, JSC::CodeLocationLabel target) {
|
||||
JSC::RepatchBuffer::relink(pic.lastPathStart().jumpAtOffset(offset), target);
|
||||
}
|
||||
};
|
||||
|
||||
class GetPropCompiler : public PICStubCompiler
|
||||
{
|
||||
JSObject *obj;
|
||||
JSAtom *atom;
|
||||
VoidStub stub;
|
||||
|
||||
/* Offsets for patching, computed manually as reverse from the storeBack. */
|
||||
#ifdef JS_CPU_X86
|
||||
static const int32 DSLOTS_LOAD = -15;
|
||||
static const int32 TYPE_LOAD = -6;
|
||||
static const int32 DATA_LOAD = 0;
|
||||
static const int32 INLINE_SHAPE_OFFSET = 6;
|
||||
static const int32 INLINE_SHAPE_JUMP = 12;
|
||||
static const int32 STUB_SHAPE_JUMP = 12;
|
||||
#endif
|
||||
|
||||
public:
|
||||
GetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
|
||||
VoidStub stub)
|
||||
: PICStubCompiler("getprop", f, script, pic), obj(obj), atom(atom), stub(stub)
|
||||
{ }
|
||||
|
||||
static void reset(ic::PICInfo &pic)
|
||||
{
|
||||
RepatchBuffer repatcher(pic.fastPathStart.executableAddress(), INLINE_PATH_LENGTH);
|
||||
repatcher.repatchLEAToLoadPtr(pic.storeBack.instructionAtOffset(DSLOTS_LOAD));
|
||||
repatcher.repatch(pic.fastPathStart.dataLabel32AtOffset(pic.shapeGuard + INLINE_SHAPE_OFFSET),
|
||||
int32(JSScope::INVALID_SHAPE));
|
||||
repatcher.relink(pic.fastPathStart.jumpAtOffset(pic.shapeGuard + INLINE_SHAPE_JUMP),
|
||||
pic.slowPathStart);
|
||||
}
|
||||
|
||||
bool patchInline(JSObject *holder, JSScopeProperty *sprop)
|
||||
{
|
||||
spew("patch", "inline");
|
||||
PICRepatchBuffer repatcher(pic);
|
||||
|
||||
mjit::ThreadData &jm = JS_METHODJIT_DATA(f.cx);
|
||||
if (!jm.addScript(script)) {
|
||||
js_ReportOutOfMemory(f.cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 offset;
|
||||
if (sprop->slot < JS_INITIAL_NSLOTS) {
|
||||
JSC::CodeLocationInstruction istr;
|
||||
istr = pic.storeBack.instructionAtOffset(DSLOTS_LOAD);
|
||||
repatcher.repatchLoadPtrToLEA(istr);
|
||||
|
||||
//
|
||||
// We've patched | mov dslots, [obj + DSLOTS_OFFSET]
|
||||
// To: | lea fslots, [obj + DSLOTS_OFFSET]
|
||||
//
|
||||
// Because the offset is wrong, it's necessary to correct it
|
||||
// below.
|
||||
//
|
||||
int32 diff = int32(offsetof(JSObject, fslots)) -
|
||||
int32(offsetof(JSObject, dslots));
|
||||
JS_ASSERT(diff != 0);
|
||||
offset = (int32(sprop->slot) * sizeof(Value)) + diff;
|
||||
} else {
|
||||
offset = (sprop->slot - JS_INITIAL_NSLOTS) * sizeof(Value);
|
||||
}
|
||||
|
||||
uint32 shapeOffs = pic.shapeGuard + INLINE_SHAPE_OFFSET;
|
||||
repatcher.repatch(pic.fastPathStart.dataLabel32AtOffset(shapeOffs),
|
||||
obj->shape());
|
||||
repatcher.repatch(pic.storeBack.dataLabel32AtOffset(TYPE_LOAD),
|
||||
offset + 4);
|
||||
repatcher.repatch(pic.storeBack.dataLabel32AtOffset(DATA_LOAD),
|
||||
offset);
|
||||
|
||||
pic.inlinePathPatched = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool generateStub(JSObject *holder, JSScopeProperty *sprop)
|
||||
{
|
||||
Vector<Jump, 8> shapeMismatches(f.cx);
|
||||
|
||||
int lastStubSecondShapeGuard = pic.secondShapeGuard;
|
||||
|
||||
Assembler masm;
|
||||
|
||||
if (pic.objNeedsRemat) {
|
||||
if (pic.objRemat >= sizeof(JSStackFrame)) {
|
||||
masm.loadData32(Address(JSFrameReg, pic.objRemat), pic.objReg);
|
||||
} else {
|
||||
masm.move(RegisterID(pic.objRemat), pic.objReg);
|
||||
}
|
||||
pic.objNeedsRemat = false;
|
||||
}
|
||||
if (!pic.shapeRegHasBaseShape) {
|
||||
masm.loadShape(pic.objReg, pic.shapeReg);
|
||||
pic.shapeRegHasBaseShape = true;
|
||||
}
|
||||
|
||||
Label start = masm.label();
|
||||
Jump shapeGuard = masm.branch32_force32(Assembler::NotEqual, pic.shapeReg,
|
||||
Imm32(obj->shape()));
|
||||
if (!shapeMismatches.append(shapeGuard))
|
||||
return false;
|
||||
|
||||
if (obj != holder) {
|
||||
// Emit code that walks the prototype chain.
|
||||
JSObject *tempObj = obj;
|
||||
Address fslot(pic.objReg, offsetof(JSObject, fslots) + JSSLOT_PROTO * sizeof(Value));
|
||||
do {
|
||||
tempObj = tempObj->getProto();
|
||||
JS_ASSERT(tempObj);
|
||||
JS_ASSERT(tempObj->isNative());
|
||||
|
||||
masm.loadData32(fslot, pic.objReg);
|
||||
pic.shapeRegHasBaseShape = false;
|
||||
pic.objNeedsRemat = true;
|
||||
|
||||
Jump j = masm.branchTestPtr(Assembler::Zero, pic.objReg, pic.objReg);
|
||||
if (!shapeMismatches.append(j))
|
||||
return false;
|
||||
} while (tempObj != holder);
|
||||
|
||||
// Load the shape out of the holder and check it.
|
||||
masm.loadShape(pic.objReg, pic.shapeReg);
|
||||
Jump j = masm.branch32_force32(Assembler::NotEqual, pic.shapeReg,
|
||||
Imm32(holder->shape()));
|
||||
if (!shapeMismatches.append(j))
|
||||
return false;
|
||||
pic.secondShapeGuard = masm.distanceOf(masm.label()) - masm.distanceOf(start);
|
||||
} else {
|
||||
pic.secondShapeGuard = 0;
|
||||
}
|
||||
masm.loadSlot(pic.objReg, pic.objReg, sprop->slot, pic.shapeReg, pic.objReg);
|
||||
Jump done = masm.jump();
|
||||
|
||||
JSC::ExecutablePool *ep = getExecPool(masm.size());
|
||||
if (!ep) {
|
||||
js_ReportOutOfMemory(f.cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
// :TODO: this can OOM
|
||||
JSC::LinkBuffer buffer(&masm, ep);
|
||||
|
||||
if (!pic.execPools.append(ep)) {
|
||||
ep->release();
|
||||
js_ReportOutOfMemory(f.cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The guard exit jumps to the original slow case.
|
||||
for (Jump *pj = shapeMismatches.begin(); pj != shapeMismatches.end(); ++pj)
|
||||
buffer.link(*pj, pic.slowPathStart);
|
||||
|
||||
// The final exit jumps to the store-back in the inline stub.
|
||||
buffer.link(done, pic.storeBack);
|
||||
CodeLocationLabel cs = buffer.finalizeCodeAddendum();
|
||||
JaegerSpew(JSpew_PICs, "generated getprop stub at %p\n", cs.executableAddress());
|
||||
|
||||
// Patch either the inline fast path or a generated stub. The stub
|
||||
// omits the prefix of the inline fast path that loads the shape, so
|
||||
// the offsets are different.
|
||||
PICRepatchBuffer repatcher(pic);
|
||||
int shapeGuardJumpOffset;
|
||||
if (pic.stubsGenerated)
|
||||
shapeGuardJumpOffset = STUB_SHAPE_JUMP;
|
||||
else
|
||||
shapeGuardJumpOffset = pic.shapeGuard + INLINE_SHAPE_JUMP;
|
||||
repatcher.relink(shapeGuardJumpOffset, cs);
|
||||
if (lastStubSecondShapeGuard)
|
||||
repatcher.relink(lastStubSecondShapeGuard, cs);
|
||||
|
||||
pic.stubsGenerated++;
|
||||
pic.lastStubStart = buffer.locationOf(start);
|
||||
|
||||
if (pic.stubsGenerated == MAX_STUBS)
|
||||
disable("max stubs reached");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update()
|
||||
{
|
||||
if (!pic.hit) {
|
||||
spew("first hit", "nop");
|
||||
pic.hit = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject *aobj = js_GetProtoIfDenseArray(obj);
|
||||
if (!aobj->isNative())
|
||||
return disable("non-native");
|
||||
|
||||
JSObject *holder;
|
||||
JSProperty *prop;
|
||||
if (!aobj->lookupProperty(f.cx, ATOM_TO_JSID(atom), &holder, &prop))
|
||||
return false;
|
||||
|
||||
if (!prop)
|
||||
return disable("lookup failed");
|
||||
|
||||
AutoPropertyDropper dropper(f.cx, holder, prop);
|
||||
|
||||
JSScopeProperty *sprop = (JSScopeProperty *)prop;
|
||||
if (!sprop->hasDefaultGetterOrIsMethod())
|
||||
return disable("getter");
|
||||
if (!SPROP_HAS_VALID_SLOT(sprop, holder->scope()))
|
||||
return disable("invalid slot");
|
||||
|
||||
if (obj == holder && !pic.inlinePathPatched) {
|
||||
// :FIXME:
|
||||
// Currently, we need this condition in order to patch the inline
|
||||
// stub because that patching goes relative to fastPathStart, and
|
||||
// that only points to the inline stub if no other stubs were
|
||||
// generated. We should either lift that limitation or simplify by
|
||||
// removing the inlinePathPatched flag, which is redundant now.
|
||||
if (pic.stubsGenerated == 0)
|
||||
return patchInline(holder, sprop);
|
||||
} else {
|
||||
JS_ASSERT(pic.stubsGenerated < ic::MAX_PIC_STUBS);
|
||||
return generateStub(holder, sprop);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool disable(const char *reason)
|
||||
{
|
||||
return PICStubCompiler::disable(reason, stub);
|
||||
}
|
||||
};
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::GetProp(VMFrame &f, uint32 index)
|
||||
{
|
||||
JSScript *script = f.fp->script;
|
||||
PICInfo &pic = script->pics[index];
|
||||
|
||||
JSAtom *atom;
|
||||
atom = script->getAtom(pic.atomIndex);
|
||||
|
||||
JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]);
|
||||
if (!obj)
|
||||
THROW();
|
||||
|
||||
if (pic.shouldGenerate()) {
|
||||
GetPropCompiler cc(f, script, obj, pic, atom, stubs::GetProp);
|
||||
if (!cc.update()) {
|
||||
cc.disable("error");
|
||||
THROW();
|
||||
}
|
||||
}
|
||||
|
||||
Value v;
|
||||
if (!obj->getProperty(f.cx, ATOM_TO_JSID(atom), &v))
|
||||
THROW();
|
||||
f.regs.sp[-1] = v;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
ic::PurgePICs(JSContext *cx, JSScript *script)
|
||||
{
|
||||
uint32 npics = script->numPICs();
|
||||
for (uint32 i = 0; i < npics; i++) {
|
||||
ic::PICInfo &pic = script->pics[i];
|
||||
if (pic.kind == ic::PICInfo::GET)
|
||||
GetPropCompiler::reset(pic);
|
||||
pic.reset();
|
||||
}
|
||||
}
|
||||
|
165
js/src/methodjit/PolyIC.h
Normal file
165
js/src/methodjit/PolyIC.h
Normal file
@ -0,0 +1,165 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* May 28, 2008.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Brendan Eich <brendan@mozilla.org>
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Mandelin <dmandelin@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#if !defined jsjaeger_poly_ic_h__ && defined JS_METHODJIT
|
||||
#define jsjaeger_poly_ic_h__
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jstl.h"
|
||||
#include "jsvector.h"
|
||||
#include "assembler/assembler/MacroAssembler.h"
|
||||
#include "assembler/assembler/CodeLocation.h"
|
||||
#include "methodjit/MethodJIT.h"
|
||||
|
||||
#define ENABLE_PIC 1
|
||||
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
namespace ic {
|
||||
|
||||
static const uint32 MAX_PIC_STUBS = 16;
|
||||
|
||||
void PurgePICs(JSContext *cx);
|
||||
|
||||
struct PICInfo {
|
||||
typedef JSC::MacroAssembler::RegisterID RegisterID;
|
||||
|
||||
// Operation this is a PIC for.
|
||||
enum Kind {
|
||||
GET,
|
||||
CALL,
|
||||
SET
|
||||
};
|
||||
|
||||
Kind kind : 2;
|
||||
|
||||
// State flags.
|
||||
bool hit : 1; // this PIC has been executed
|
||||
bool inlinePathPatched : 1; // inline path has been patched
|
||||
|
||||
// True if register R holds the base object shape along exits from the
|
||||
// last stub.
|
||||
bool shapeRegHasBaseShape : 1;
|
||||
RegisterID shapeReg : 5; // also the out type reg
|
||||
RegisterID objReg : 5; // also the out data reg
|
||||
|
||||
// True if the last stub has an extra shape load at its start.
|
||||
bool startsWithShapeLoad : 1;
|
||||
|
||||
// Number of stubs generated.
|
||||
uint32 stubsGenerated : 8;
|
||||
|
||||
// Offset from start of fast path to initial shape guard.
|
||||
int shapeGuard : 8;
|
||||
|
||||
// Offset from start of stub to jump target of second shape guard as Nitro
|
||||
// asm data location. This is 0 if there is only one shape guard in the
|
||||
// last stub.
|
||||
int secondShapeGuard : 8;
|
||||
|
||||
// Index into the script's atom table.
|
||||
uint32 atomIndex;
|
||||
|
||||
// Remat info for the object reg.
|
||||
uint32 objRemat : 20;
|
||||
bool objNeedsRemat : 1;
|
||||
|
||||
// Address of inline fast-path.
|
||||
JSC::CodeLocationLabel fastPathStart;
|
||||
|
||||
// Address of store back at the end of the inline fast-path.
|
||||
JSC::CodeLocationLabel storeBack;
|
||||
|
||||
// Return address of slow path call, as an offset from slowPathStart.
|
||||
uint8 callReturn;
|
||||
|
||||
// Offset from callReturn to the start of the slow case.
|
||||
JSC::CodeLocationLabel slowPathStart;
|
||||
|
||||
// Address of the start of the last generated stub, if any.
|
||||
JSC::CodeLocationLabel lastStubStart;
|
||||
|
||||
typedef Vector<JSC::ExecutablePool *, 0, SystemAllocPolicy> ExecPoolVector;
|
||||
|
||||
// ExecutablePools that PIC stubs were generated into.
|
||||
ExecPoolVector execPools;
|
||||
|
||||
// Return the start address of the last path in this PIC, which is the
|
||||
// inline path if no stubs have been generated yet.
|
||||
JSC::CodeLocationLabel lastPathStart() {
|
||||
return stubsGenerated > 0 ? lastStubStart : fastPathStart;
|
||||
}
|
||||
|
||||
bool shouldGenerate() {
|
||||
return stubsGenerated < MAX_PIC_STUBS || !inlinePathPatched;
|
||||
}
|
||||
|
||||
// Release ExecutablePools referred to by this PIC.
|
||||
void releasePools() {
|
||||
for (JSC::ExecutablePool **pExecPool = execPools.begin();
|
||||
pExecPool != execPools.end();
|
||||
++pExecPool)
|
||||
{
|
||||
(*pExecPool)->release();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the data members to the state of a fresh PIC before any patching
|
||||
// or stub generation was done.
|
||||
void reset() {
|
||||
hit = false;
|
||||
inlinePathPatched = false;
|
||||
objNeedsRemat = false;
|
||||
shapeRegHasBaseShape = true;
|
||||
secondShapeGuard = 0;
|
||||
stubsGenerated = 0;
|
||||
releasePools();
|
||||
execPools.clear();
|
||||
}
|
||||
};
|
||||
|
||||
void PurgePICs(JSContext *cx, JSScript *script);
|
||||
void JS_FASTCALL GetProp(VMFrame &f, uint32 index);
|
||||
|
||||
}
|
||||
} /* namespace mjit */
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsjaeger_poly_ic_h__ */
|
||||
|
74
js/src/methodjit/StubCalls-inl.h
Normal file
74
js/src/methodjit/StubCalls-inl.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* May 28, 2008.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Brendan Eich <brendan@mozilla.org>
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Anderson <danderson@mozilla.com>
|
||||
* David Mandelin <dmandelin@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jslogic_h_inl__
|
||||
#define jslogic_h_inl__
|
||||
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
|
||||
#define THROW() \
|
||||
do { \
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
|
||||
f.setReturnAddress(ReturnAddressPtr(FunctionPtr(ptr))); \
|
||||
return; \
|
||||
} while (0)
|
||||
|
||||
#define THROWV(v) \
|
||||
do { \
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
|
||||
f.setReturnAddress(ReturnAddressPtr(FunctionPtr(ptr))); \
|
||||
return v; \
|
||||
} while (0)
|
||||
|
||||
static inline JSObject *
|
||||
ValueToObject(JSContext *cx, Value *vp)
|
||||
{
|
||||
if (vp->isObject())
|
||||
return &vp->asObject();
|
||||
if (!js_ValueToNonNullObject(cx, *vp, vp))
|
||||
return NULL;
|
||||
return &vp->asObject();
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif /* jslogic_h__ */
|
||||
|
@ -62,6 +62,7 @@
|
||||
#include "jsobjinlines.h"
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsatominlines.h"
|
||||
#include "StubCalls-inl.h"
|
||||
|
||||
#include "jsautooplen.h"
|
||||
|
||||
@ -69,20 +70,6 @@ using namespace js;
|
||||
using namespace js::mjit;
|
||||
using namespace JSC;
|
||||
|
||||
#define THROW() \
|
||||
do { \
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
|
||||
f.setReturnAddress(ReturnAddressPtr(FunctionPtr(ptr))); \
|
||||
return; \
|
||||
} while (0)
|
||||
|
||||
#define THROWV(v) \
|
||||
do { \
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
|
||||
f.setReturnAddress(ReturnAddressPtr(FunctionPtr(ptr))); \
|
||||
return v; \
|
||||
} while (0)
|
||||
|
||||
void JS_FASTCALL
|
||||
mjit::stubs::BindName(VMFrame &f)
|
||||
{
|
||||
@ -142,16 +129,6 @@ mjit::stubs::DebugHook(VMFrame &f)
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
static inline JSObject *
|
||||
ValueToObject(JSContext *cx, Value *vp)
|
||||
{
|
||||
if (vp->isObject())
|
||||
return &vp->asObject();
|
||||
if (!js_ValueToNonNullObject(cx, *vp, vp))
|
||||
return NULL;
|
||||
return &vp->asObject();
|
||||
}
|
||||
|
||||
#define NATIVE_GET(cx,obj,pobj,sprop,getHow,vp,onerr) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (sprop->hasDefaultGetter()) { \
|
||||
|
@ -77,6 +77,22 @@ class Assembler : public BaseAssembler
|
||||
return BaseIndex(address.base, address.index, address.scale, address.offset + TAG_OFFSET);
|
||||
}
|
||||
|
||||
void loadSlot(RegisterID obj, RegisterID clobber, uint32 slot, RegisterID type, RegisterID data) {
|
||||
JS_ASSERT(type != data);
|
||||
Address address(obj, offsetof(JSObject, fslots) + slot * sizeof(Value));
|
||||
if (slot >= JS_INITIAL_NSLOTS) {
|
||||
loadPtr(Address(obj, offsetof(JSObject, dslots)), clobber);
|
||||
address = Address(obj, (slot - JS_INITIAL_NSLOTS) * sizeof(Value));
|
||||
}
|
||||
if (obj == type) {
|
||||
loadData32(address, data);
|
||||
loadTypeTag(address, type);
|
||||
} else {
|
||||
loadTypeTag(address, type);
|
||||
loadData32(address, data);
|
||||
}
|
||||
}
|
||||
|
||||
void loadTypeTag(Address address, RegisterID reg) {
|
||||
load32(Address(address.base, address.offset + TAG_OFFSET), reg);
|
||||
}
|
||||
|
43
js/src/trace-test/tests/jaeger/bug549393-1.js
Normal file
43
js/src/trace-test/tests/jaeger/bug549393-1.js
Normal file
@ -0,0 +1,43 @@
|
||||
// |trace-test| error: TypeError
|
||||
function start() {
|
||||
MAX_TOTAL_TIME = startTime = new Date
|
||||
do {
|
||||
if (rnd(0)) return (a[rnd()])()
|
||||
lastTime = new Date
|
||||
} while ( lastTime - startTime < MAX_TOTAL_TIME )
|
||||
}
|
||||
function MersenneTwister19937() {
|
||||
this.init_genrand = function() {
|
||||
for (mti = 1; mti < 4; mti++) {
|
||||
Array[mti] = 1
|
||||
}
|
||||
};
|
||||
this.genrand_int32 = function() {
|
||||
if (mti > 4) {
|
||||
mti = 0
|
||||
}
|
||||
return Array[mti++];
|
||||
}
|
||||
} (function() {
|
||||
fuzzMT = new MersenneTwister19937;
|
||||
fuzzMT.init_genrand()
|
||||
rnd = function() {
|
||||
return Math.floor(fuzzMT.genrand_int32())
|
||||
}
|
||||
} ())
|
||||
function weighted(wa) {
|
||||
a = []
|
||||
for (i = 0; i < wa.length; ++i) {
|
||||
for (var j = 0; j < 8; ++j) {
|
||||
a.push(wa[i].fun)
|
||||
}
|
||||
}
|
||||
}
|
||||
statementMakers = weighted([{
|
||||
fun: function makeMixedTypeArray() { [[, , , , , , , , , , , , , , , , , , ,
|
||||
, , , , , ""][(a[rnd()])()]]}
|
||||
}])
|
||||
start()
|
||||
|
||||
/* Don't assert. */
|
||||
|
10
js/src/trace-test/tests/jaeger/bug549393-2.js
Normal file
10
js/src/trace-test/tests/jaeger/bug549393-2.js
Normal file
@ -0,0 +1,10 @@
|
||||
(function () {
|
||||
for (var q = 0; q < 6; ++q) {
|
||||
x: (function () {
|
||||
var m = (function () {})()
|
||||
})([0, , 0, 0, 0, , 0, 0, 0, , 0, 0, 0, , 0, 0, 0, 0, 0, 0, Number(1)])
|
||||
}
|
||||
})()
|
||||
|
||||
/* Don't assert. */
|
||||
|
1
js/src/trace-test/tests/jaeger/bug549396.js
Normal file
1
js/src/trace-test/tests/jaeger/bug549396.js
Normal file
@ -0,0 +1 @@
|
||||
x = __defineSetter__("x", function(z) function() { z })
|
10
js/src/trace-test/tests/jaeger/bug549398.js
Normal file
10
js/src/trace-test/tests/jaeger/bug549398.js
Normal file
@ -0,0 +1,10 @@
|
||||
(function () {
|
||||
eval("\
|
||||
for(var z = 0 ; z < 2 ; ++z) {\
|
||||
this\
|
||||
}\
|
||||
", (<x/>))
|
||||
})()
|
||||
|
||||
/* Don't crash. */
|
||||
|
12
js/src/trace-test/tests/jaeger/bug549521.js
Normal file
12
js/src/trace-test/tests/jaeger/bug549521.js
Normal file
@ -0,0 +1,12 @@
|
||||
function f(y) {
|
||||
if (y)
|
||||
return;
|
||||
let(x) {
|
||||
for (;;) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Don't assert. */
|
||||
f(1);
|
||||
|
31
js/src/trace-test/tests/jaeger/bug549602.js
Normal file
31
js/src/trace-test/tests/jaeger/bug549602.js
Normal file
@ -0,0 +1,31 @@
|
||||
version(180)
|
||||
function f1(code) {
|
||||
var c
|
||||
var t = code.replace(/s/, "")
|
||||
var f = new Function(code)
|
||||
var o
|
||||
e = v = f2(f, c)
|
||||
}
|
||||
function f2(f, e) {
|
||||
try {
|
||||
a = f()
|
||||
} catch(r) {
|
||||
var r = g()
|
||||
}
|
||||
}
|
||||
g1 = [{
|
||||
text: "(function sum_slicing(array){return array==0?0:a+sum_slicing(array.slice(1))})",
|
||||
test: function (f) {
|
||||
f([, 2]) == ""
|
||||
}
|
||||
}];
|
||||
(function () {
|
||||
for (var i = 0; i < g1.length; ++i) {
|
||||
var a = g1[i]
|
||||
var text = a.text
|
||||
var f = eval(text.replace(/@/, ""))
|
||||
if (a.test(f)) {}
|
||||
}
|
||||
}())
|
||||
f1("for(let a=0;a<6;a++){print([\"\"].some(function(){false>\"\"}))}")
|
||||
|
3
js/src/trace-test/tests/jaeger/bug549603.js
Normal file
3
js/src/trace-test/tests/jaeger/bug549603.js
Normal file
@ -0,0 +1,3 @@
|
||||
// |trace-test| error: ReferenceError
|
||||
x ? o : [] && x
|
||||
|
14
js/src/trace-test/tests/jaeger/bug550490.js
Normal file
14
js/src/trace-test/tests/jaeger/bug550490.js
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
function a() {
|
||||
function f() {}
|
||||
this.d = function() {
|
||||
f
|
||||
}
|
||||
} (function() {
|
||||
var a2, x
|
||||
a2 = new a;
|
||||
d = (function(){x * 1})();
|
||||
})()
|
||||
|
||||
/* Don't assert. */
|
||||
|
8
js/src/trace-test/tests/jaeger/bug550665.js
Normal file
8
js/src/trace-test/tests/jaeger/bug550665.js
Normal file
@ -0,0 +1,8 @@
|
||||
(function () {
|
||||
var a;
|
||||
eval("for(w in ((function(x,y){b:0})())) ;");
|
||||
})();
|
||||
|
||||
__defineSetter__("l", function() { gc() });
|
||||
this.watch("l", function(x) { yield #1={} });
|
||||
l = true;
|
8
js/src/trace-test/tests/jaeger/bug551603.js
Normal file
8
js/src/trace-test/tests/jaeger/bug551603.js
Normal file
@ -0,0 +1,8 @@
|
||||
(function() {
|
||||
((function f(a) {
|
||||
if (a > 0) {
|
||||
f(a - 1)
|
||||
}
|
||||
})(6))
|
||||
})()
|
||||
|
6
js/src/trace-test/tests/jaeger/bug552644.js
Normal file
6
js/src/trace-test/tests/jaeger/bug552644.js
Normal file
@ -0,0 +1,6 @@
|
||||
(function() {
|
||||
for (e in ((function() {
|
||||
yield
|
||||
})())) return
|
||||
})()
|
||||
/* Don't assert. */
|
13
js/src/trace-test/tests/jaeger/bug553781-2.js
Normal file
13
js/src/trace-test/tests/jaeger/bug553781-2.js
Normal file
@ -0,0 +1,13 @@
|
||||
(function() {
|
||||
do {
|
||||
try {
|
||||
return
|
||||
}
|
||||
catch(x if (c)) {
|
||||
return
|
||||
} (x)
|
||||
} while (x)
|
||||
})()
|
||||
|
||||
/* Don't assert. */
|
||||
|
11
js/src/trace-test/tests/jaeger/bug553781.js
Normal file
11
js/src/trace-test/tests/jaeger/bug553781.js
Normal file
@ -0,0 +1,11 @@
|
||||
(function () {
|
||||
try {
|
||||
return
|
||||
} catch (x if i) {
|
||||
return
|
||||
}
|
||||
for (z in []);
|
||||
})()
|
||||
|
||||
/* Don't assert */
|
||||
|
18
js/src/trace-test/tests/jaeger/bug553784.js
Normal file
18
js/src/trace-test/tests/jaeger/bug553784.js
Normal file
@ -0,0 +1,18 @@
|
||||
// |trace-test| allow-oom
|
||||
(function(){
|
||||
(x)=<x>></x>
|
||||
})()
|
||||
try{
|
||||
(function(){
|
||||
((function a(aaaaaa,bbbbbb){
|
||||
if(aaaaaa.length==bbbbbb){
|
||||
return eval%bbbbbb.valueOf()
|
||||
}
|
||||
cccccc=a(aaaaaa,bbbbbb+1)
|
||||
return cccccc._=x
|
||||
})([,,,,,,,,,,,,,,,,,,0],0))
|
||||
})()
|
||||
}catch(e){}
|
||||
|
||||
/* Don't assert. */
|
||||
|
7
js/src/trace-test/tests/jaeger/bug554580-1.js
Normal file
7
js/src/trace-test/tests/jaeger/bug554580-1.js
Normal file
@ -0,0 +1,7 @@
|
||||
// |trace-test| error: TypeError
|
||||
for (var a = 0; a < 7; ++a) {
|
||||
if (a == 1) {
|
||||
Iterator()
|
||||
}
|
||||
}
|
||||
|
9
js/src/trace-test/tests/jaeger/bug554580-2.js
Normal file
9
js/src/trace-test/tests/jaeger/bug554580-2.js
Normal file
@ -0,0 +1,9 @@
|
||||
// |trace-test| error: RangeError
|
||||
(function() {
|
||||
for each(let a in [function() {}, Infinity]) {
|
||||
new Array(a)
|
||||
}
|
||||
})()
|
||||
|
||||
/* Don't assert/crash. */
|
||||
|
11
js/src/trace-test/tests/jaeger/bug554580-3.js
Normal file
11
js/src/trace-test/tests/jaeger/bug554580-3.js
Normal file
@ -0,0 +1,11 @@
|
||||
// |trace-test| error: SyntaxError
|
||||
Function("\n\
|
||||
for (a = 0; a < 3; a++) {\n\
|
||||
if (a == 0) {} else {\n\
|
||||
__defineSetter__(\"\",1)\n\
|
||||
}\n\
|
||||
}\n\
|
||||
")()
|
||||
|
||||
/* Don't crash/assert. */
|
||||
|
18
js/src/trace-test/tests/jaeger/bug554580-4.js
Normal file
18
js/src/trace-test/tests/jaeger/bug554580-4.js
Normal file
@ -0,0 +1,18 @@
|
||||
(function() {
|
||||
try {
|
||||
(eval("\
|
||||
function() {\
|
||||
for each(let y in [0]) {\
|
||||
for (var a = 0; a < 9; ++a) {\
|
||||
if (a) {\
|
||||
this.__defineGetter__(\"\",this)\
|
||||
}\
|
||||
}\
|
||||
}\
|
||||
}\
|
||||
"))()
|
||||
} catch(e) {}
|
||||
})()
|
||||
|
||||
/* Don't assert. */
|
||||
|
21
js/src/trace-test/tests/jaeger/bug554580-5.js
Normal file
21
js/src/trace-test/tests/jaeger/bug554580-5.js
Normal file
@ -0,0 +1,21 @@
|
||||
// |trace-test| error: TypeError
|
||||
(function() {
|
||||
(function g(m, n) {
|
||||
if (m = n) {
|
||||
return eval("x=this")
|
||||
}
|
||||
g(m, 1)[[]]
|
||||
})()
|
||||
})()
|
||||
Function("\
|
||||
for (let b in [0]) {\
|
||||
for (var k = 0; k < 6; ++k) {\
|
||||
if (k == 1) {\
|
||||
print(x)\
|
||||
}\
|
||||
}\
|
||||
}\
|
||||
")()
|
||||
|
||||
/* Don't crash/assert. */
|
||||
|
15
js/src/trace-test/tests/jaeger/bug554651.js
Normal file
15
js/src/trace-test/tests/jaeger/bug554651.js
Normal file
@ -0,0 +1,15 @@
|
||||
// |trace-test| error: InternalError
|
||||
(function() {
|
||||
try {
|
||||
(Function("__defineGetter__(\"x\",(Function(\"for(z=0;z<6;z++)(x)\")))"))()
|
||||
} catch(e) {}
|
||||
})()
|
||||
((function f(d, aaaaaa) {
|
||||
if (bbbbbb = aaaaaa) {
|
||||
x
|
||||
}
|
||||
f(bbbbbb, aaaaaa + 1)
|
||||
})([], 0))
|
||||
|
||||
/* Don't assert (32-bit mac only, relies on very specific stack usage). */
|
||||
|
8
js/src/trace-test/tests/jaeger/bug554675-1.js
Normal file
8
js/src/trace-test/tests/jaeger/bug554675-1.js
Normal file
@ -0,0 +1,8 @@
|
||||
(function() {
|
||||
for (e in [0, 0]) {
|
||||
if (/x/ < this) {}
|
||||
}
|
||||
})()
|
||||
|
||||
/* Don't assert. */
|
||||
|
11
js/src/trace-test/tests/jaeger/bug554675-2.js
Normal file
11
js/src/trace-test/tests/jaeger/bug554675-2.js
Normal file
@ -0,0 +1,11 @@
|
||||
function a(code) {
|
||||
var f = new Function("for each(let x in[false,'',/x/,'',{}]){if(x<x){(({}))}else if(x){}else{}}");
|
||||
try {
|
||||
f()
|
||||
} catch(e) {}
|
||||
}
|
||||
a()
|
||||
a()
|
||||
|
||||
/* Don't crash (CLI only). */
|
||||
|
11
js/src/trace-test/tests/jaeger/bug554675-3.js
Normal file
11
js/src/trace-test/tests/jaeger/bug554675-3.js
Normal file
@ -0,0 +1,11 @@
|
||||
(function() {
|
||||
try { (function() {
|
||||
for each(let x in [0, /x/, 0, {}]) {
|
||||
if (x < x) {}
|
||||
}
|
||||
})()
|
||||
} catch(e) {}
|
||||
})()
|
||||
|
||||
/* Don't assert. */
|
||||
|
9
js/src/trace-test/tests/jaeger/bug555152.js
Normal file
9
js/src/trace-test/tests/jaeger/bug555152.js
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
(function() {
|
||||
for each(let x in [new Boolean(), new Boolean(), /x/, /x/]) {
|
||||
while (x % x * /x/) {}
|
||||
}
|
||||
})()
|
||||
|
||||
/* Don't crash. */
|
||||
|
12
js/src/trace-test/tests/jaeger/bug555155.js
Normal file
12
js/src/trace-test/tests/jaeger/bug555155.js
Normal file
@ -0,0 +1,12 @@
|
||||
// |trace-test| error: TypeError
|
||||
(function() {
|
||||
throw (function f(a, b) {
|
||||
if (a.h == b) {
|
||||
return eval("((function(){return 1})())!=this")
|
||||
}
|
||||
f(b)
|
||||
})([], 0)
|
||||
})()
|
||||
|
||||
/* Don't assert/crash. */
|
||||
|
4
js/src/trace-test/tests/jaeger/bug555206.js
Normal file
4
js/src/trace-test/tests/jaeger/bug555206.js
Normal file
@ -0,0 +1,4 @@
|
||||
// |trace-test| error: TypeError
|
||||
__defineGetter__("x",/a/)
|
||||
" ".replace(/\s/,"")
|
||||
x.b
|
8
js/src/trace-test/tests/jaeger/bug555543.js
Normal file
8
js/src/trace-test/tests/jaeger/bug555543.js
Normal file
@ -0,0 +1,8 @@
|
||||
(function() {
|
||||
for each(let z in [new String(''), new String('q'), new String('')]) {
|
||||
if (uneval() < z) function(){}
|
||||
}
|
||||
})()
|
||||
|
||||
/* Don't assert/crash. */
|
||||
|
11
js/src/trace-test/tests/jaeger/bug555922.js
Normal file
11
js/src/trace-test/tests/jaeger/bug555922.js
Normal file
@ -0,0 +1,11 @@
|
||||
(function() {
|
||||
let(z) {
|
||||
for each(b in [{}]) { ({
|
||||
get __noSuchMethod__() { return Function }
|
||||
}).w()
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
/* Don't crash/assert. */
|
||||
|
7
js/src/trace-test/tests/jaeger/bug556525.js
Normal file
7
js/src/trace-test/tests/jaeger/bug556525.js
Normal file
@ -0,0 +1,7 @@
|
||||
// |trace-test| error: TypeError
|
||||
|
||||
for each(x in [new Number])
|
||||
x.__proto__ = []
|
||||
++x[x]
|
||||
|
||||
// don't assert
|
7
js/src/trace-test/tests/jaeger/bug557063.js
Normal file
7
js/src/trace-test/tests/jaeger/bug557063.js
Normal file
@ -0,0 +1,7 @@
|
||||
(function() {
|
||||
for (a = 0; a < 2; a++)
|
||||
''.watch("", function() {})
|
||||
})()
|
||||
|
||||
/* Don't crash or assert. */
|
||||
|
5
js/src/trace-test/tests/jaeger/bug557068.js
Normal file
5
js/src/trace-test/tests/jaeger/bug557068.js
Normal file
@ -0,0 +1,5 @@
|
||||
for each(let x in [0, {}, 0, {}]) {
|
||||
x.valueOf
|
||||
}
|
||||
|
||||
// don't crash
|
6
js/src/trace-test/tests/jaeger/bug557070.js
Normal file
6
js/src/trace-test/tests/jaeger/bug557070.js
Normal file
@ -0,0 +1,6 @@
|
||||
// |trace-test| error: InternalError
|
||||
|
||||
for (e in (function x() { [eval()].some(x) } ()));
|
||||
|
||||
/* Don't crash or assert. */
|
||||
|
8
js/src/trace-test/tests/jaeger/bug557075.js
Normal file
8
js/src/trace-test/tests/jaeger/bug557075.js
Normal file
@ -0,0 +1,8 @@
|
||||
// |trace-test| error: TypeError
|
||||
|
||||
for (l in [Math.h.h.h.h.h.I.h.h.h.h.h.h.h.I.h.I]) {
|
||||
t.x
|
||||
}
|
||||
|
||||
/* Don't crash or assert. */
|
||||
|
13
js/src/trace-test/tests/jaeger/bug560221.js
Normal file
13
js/src/trace-test/tests/jaeger/bug560221.js
Normal file
@ -0,0 +1,13 @@
|
||||
try {
|
||||
(function() {
|
||||
(Object.defineProperty(this, "x", ({
|
||||
set: function() {}
|
||||
})))
|
||||
})()
|
||||
} catch(e) {}
|
||||
for (var a = 0; a < 4; a++) {
|
||||
x = 7
|
||||
}
|
||||
|
||||
/* Don't bogus assert. */
|
||||
|
6
js/src/trace-test/tests/jaeger/bug565198.js
Normal file
6
js/src/trace-test/tests/jaeger/bug565198.js
Normal file
@ -0,0 +1,6 @@
|
||||
const X = 12;
|
||||
|
||||
eval("switch (X) { case X: print(); }");
|
||||
|
||||
/* Don't assert. */
|
||||
|
7
js/src/trace-test/tests/jaeger/bug565202.js
Normal file
7
js/src/trace-test/tests/jaeger/bug565202.js
Normal file
@ -0,0 +1,7 @@
|
||||
options("strict", "werror");
|
||||
|
||||
var o = {};
|
||||
|
||||
// Don't throw here.
|
||||
if (o.a)
|
||||
x = true;
|
5
js/src/trace-test/tests/jaeger/globalOptimize-1.js
Normal file
5
js/src/trace-test/tests/jaeger/globalOptimize-1.js
Normal file
@ -0,0 +1,5 @@
|
||||
/* Test that NaN does not trigger js_InitMathClass & constants while parsing. */
|
||||
var NaN
|
||||
|
||||
var x = 2;
|
||||
|
15
js/src/trace-test/tests/jaeger/regalloc-1.js
Normal file
15
js/src/trace-test/tests/jaeger/regalloc-1.js
Normal file
@ -0,0 +1,15 @@
|
||||
// |trace-test| error: TypeError
|
||||
|
||||
x = 2;
|
||||
|
||||
function tryItOut(c) {
|
||||
return eval("(function(){" + c + "})");
|
||||
}
|
||||
|
||||
function doit() {
|
||||
var f = tryItOut("((( \"\" \n for each (eval in [null, this, null, this, (1/0), new String('q'), new String('q'), null, null, null, new String('q'), new String('q'), new String('q'), null]) if (this)).eval(x = x)));");
|
||||
f();
|
||||
}
|
||||
|
||||
doit();
|
||||
|
21
js/src/trace-test/tests/jaeger/testBug550743.js
Normal file
21
js/src/trace-test/tests/jaeger/testBug550743.js
Normal file
@ -0,0 +1,21 @@
|
||||
expected = '';
|
||||
|
||||
function g(code) {
|
||||
f = Function(code);
|
||||
gen = f();
|
||||
gen.next();
|
||||
try { gen.next(); } catch (ex) { expected = ex.toString() }
|
||||
}
|
||||
|
||||
g("\
|
||||
yield this.__defineGetter__('x', function(){ return z }); \
|
||||
let z = new String('hi'); \
|
||||
");
|
||||
|
||||
eval();
|
||||
gc();
|
||||
|
||||
str = x;
|
||||
|
||||
assertEq(expected, "[object StopIteration]");
|
||||
assertEq(str.toString(), "hi");
|
60
js/src/trace-test/tests/pic/bug558099.js
Normal file
60
js/src/trace-test/tests/pic/bug558099.js
Normal file
@ -0,0 +1,60 @@
|
||||
function()[function() function() function() function() function() function() {}]
|
||||
foo = [{
|
||||
text: "(function(){if(d){(1)}})",
|
||||
s: function() {},
|
||||
test: function() {
|
||||
try {
|
||||
f
|
||||
} catch(e) {}
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "(function(){t})",
|
||||
s: function() {},
|
||||
test: function() {}
|
||||
},
|
||||
{
|
||||
text: "(function(){if(0){}})",
|
||||
s: function() {},
|
||||
test: function() {}
|
||||
},
|
||||
{
|
||||
text: "(function(){if(1){}(2)})",
|
||||
s: function() {},
|
||||
test: function() {}
|
||||
},
|
||||
{
|
||||
text: "(function(){g})",
|
||||
b: function() {},
|
||||
test: function() {}
|
||||
},
|
||||
{
|
||||
text: "(function(){})",
|
||||
s: function() {},
|
||||
test: function() {}
|
||||
},
|
||||
{
|
||||
text: "(function(){1})",
|
||||
s: function() {},
|
||||
test: function() {}
|
||||
}]; (function() {
|
||||
for (i = 0; i < foo.length; ++i) {
|
||||
a = foo[i]
|
||||
text = a.text
|
||||
eval(text.replace(/@/, ""));
|
||||
if (a.test()) {}
|
||||
}
|
||||
} ());
|
||||
s = [function() function() function() function() function() function() {}]
|
||||
[function() function() function() function() {}]
|
||||
function() { [function() function() {}] }
|
||||
function() {}
|
||||
(eval("\
|
||||
(function(){\
|
||||
for each(d in[\
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,null,NaN,1,Boolean(false),Boolean(false)\
|
||||
]){\
|
||||
[].filter(new Function,gczeal(2))\
|
||||
}\
|
||||
})\
|
||||
"))()
|
9
js/src/trace-test/tests/pic/bug558616.js
Normal file
9
js/src/trace-test/tests/pic/bug558616.js
Normal file
@ -0,0 +1,9 @@
|
||||
(function() {
|
||||
for each(let d in [{}, {}, 0]) {
|
||||
for each(e in [0, 0, 0, 0, 0, 0, 0, 0, 0]) {
|
||||
d.__defineSetter__("", function() {})
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
// don't assert
|
15
js/src/trace-test/tests/pic/call_self.js
Normal file
15
js/src/trace-test/tests/pic/call_self.js
Normal file
@ -0,0 +1,15 @@
|
||||
var o = {
|
||||
g: function(a) {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
function f() {
|
||||
var z;
|
||||
for (var i = 0; i < 10; ++i) {
|
||||
z = o.g(i);
|
||||
assertEq(z, i);
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
12
js/src/trace-test/tests/pic/densearray.js
Normal file
12
js/src/trace-test/tests/pic/densearray.js
Normal file
@ -0,0 +1,12 @@
|
||||
function f() {
|
||||
var o = [ 1, 2, 3, 4, 5 ];
|
||||
|
||||
for (var i = 6; i < 10; ++i)
|
||||
o.push(i);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
var o = f();
|
||||
|
||||
assertEq(o.join(','), [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ].join(','));
|
4
js/src/trace-test/tests/pic/fuzz1.js
Normal file
4
js/src/trace-test/tests/pic/fuzz1.js
Normal file
@ -0,0 +1,4 @@
|
||||
(function() {
|
||||
for (a = 0; a < 2; a++)
|
||||
''.watch("", function() {})
|
||||
})()
|
3
js/src/trace-test/tests/pic/fuzz2.js
Normal file
3
js/src/trace-test/tests/pic/fuzz2.js
Normal file
@ -0,0 +1,3 @@
|
||||
for each(let x in [0, {}, 0, {}]) {
|
||||
x.valueOf
|
||||
}
|
3
js/src/trace-test/tests/pic/fuzz3.js
Normal file
3
js/src/trace-test/tests/pic/fuzz3.js
Normal file
@ -0,0 +1,3 @@
|
||||
for each(let w in [[], 0, [], 0]) {
|
||||
w.unwatch()
|
||||
}
|
28
js/src/trace-test/tests/pic/grandproto.js
Normal file
28
js/src/trace-test/tests/pic/grandproto.js
Normal file
@ -0,0 +1,28 @@
|
||||
function A()
|
||||
{
|
||||
this.a = 77;
|
||||
this.b = 88;
|
||||
}
|
||||
|
||||
function B()
|
||||
{
|
||||
}
|
||||
|
||||
B.prototype = new A;
|
||||
|
||||
function C()
|
||||
{
|
||||
}
|
||||
|
||||
C.prototype = new B;
|
||||
|
||||
function f() {
|
||||
var o = new C;
|
||||
var z;
|
||||
for (var i = 0; i < 5; ++i) {
|
||||
z = o.a;
|
||||
assertEq(z, 77);
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
16
js/src/trace-test/tests/pic/length_array.js
Normal file
16
js/src/trace-test/tests/pic/length_array.js
Normal file
@ -0,0 +1,16 @@
|
||||
// length, string
|
||||
|
||||
var expected = "3,6,4,3,6,4,3,6,4,3,6,4,";
|
||||
var actual = '';
|
||||
|
||||
function f() {
|
||||
var ss = [ [1, 2, 3], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4] ];
|
||||
|
||||
for (var i = 0; i < 12; ++i) {
|
||||
actual += ss[i%3].length + ',';
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
assertEq(actual, expected);
|
22
js/src/trace-test/tests/pic/length_mix.js
Normal file
22
js/src/trace-test/tests/pic/length_mix.js
Normal file
@ -0,0 +1,22 @@
|
||||
// length, various types
|
||||
|
||||
var expected = "4,5,44,5,44,4,44,4,5,4,5,44,5,44,4,44,4,5,";
|
||||
var actual = '';
|
||||
|
||||
function f() {
|
||||
var a = [ "abcd", [1, 2, 3, 4, 5], { length: 44 } ];
|
||||
|
||||
for (var i = 0; i < 6; ++i) {
|
||||
// Use 3 PICs so we start out with each type in one PIC.
|
||||
var i1 = i % 3;
|
||||
var i2 = (i+1) % 3;
|
||||
var i3 = (i+2) % 3;
|
||||
actual += a[i1].length + ',';
|
||||
actual += a[i2].length + ',';
|
||||
actual += a[i3].length + ',';
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
assertEq(actual, expected);
|
16
js/src/trace-test/tests/pic/length_object.js
Normal file
16
js/src/trace-test/tests/pic/length_object.js
Normal file
@ -0,0 +1,16 @@
|
||||
// length, object
|
||||
|
||||
var expected = "777,777,777,777,777,";
|
||||
var actual = '';
|
||||
|
||||
function f() {
|
||||
var o = { a: 11, length: 777, b: 22 };
|
||||
|
||||
for (var i = 0; i < 5; ++i) {
|
||||
actual += o.length + ',';
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
assertEq(actual, expected);
|
16
js/src/trace-test/tests/pic/length_string.js
Normal file
16
js/src/trace-test/tests/pic/length_string.js
Normal file
@ -0,0 +1,16 @@
|
||||
// length, string
|
||||
|
||||
var expected = "3,6,4,3,6,4,3,6,4,3,6,4,";
|
||||
var actual = '';
|
||||
|
||||
function f() {
|
||||
var ss = [ "abc", "foobar", "quux" ];
|
||||
|
||||
for (var i = 0; i < 12; ++i) {
|
||||
actual += ss[i%3].length + ',';
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
assertEq(actual, expected);
|
24
js/src/trace-test/tests/pic/proto1.js
Normal file
24
js/src/trace-test/tests/pic/proto1.js
Normal file
@ -0,0 +1,24 @@
|
||||
// getprop, proto, 1 shape
|
||||
|
||||
var expected = "11,22,33,11,22,33,11,22,33,11,22,33,11,22,33,";
|
||||
var actual = '';
|
||||
|
||||
var proto = { a: 11, b: 22, c: 33 };
|
||||
|
||||
function B() {
|
||||
}
|
||||
B.prototype = proto;
|
||||
|
||||
function f() {
|
||||
var o = new B();
|
||||
|
||||
for (var i = 0; i < 5; ++i) {
|
||||
actual += o.a + ',';
|
||||
actual += o.b + ',';
|
||||
actual += o.c + ',';
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
assertEq(actual, expected);
|
32
js/src/trace-test/tests/pic/proto3.js
Normal file
32
js/src/trace-test/tests/pic/proto3.js
Normal file
@ -0,0 +1,32 @@
|
||||
// getprop, proto, 3 shapes
|
||||
|
||||
var expected = "22,202,202,22,202,202,22,202,202,";
|
||||
var actual = '';
|
||||
|
||||
var protoB = { a: 11, b: 22, c: 33 };
|
||||
|
||||
function B() {
|
||||
}
|
||||
B.prototype = protoB;
|
||||
|
||||
var protoC = { a: 101, b: 202, c: 303 };
|
||||
|
||||
function C() {
|
||||
}
|
||||
C.prototype = protoC;
|
||||
|
||||
function f() {
|
||||
var o1 = new B();
|
||||
var o2 = new C();
|
||||
var o3 = new C();
|
||||
o3.q = 99;
|
||||
var oa = [ o1, o2, o3 ];
|
||||
|
||||
for (var i = 0; i < 9; ++i) {
|
||||
actual += oa[i%3].b + ',';
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
assertEq(actual, expected);
|
39
js/src/trace-test/tests/pic/proto_self.js
Normal file
39
js/src/trace-test/tests/pic/proto_self.js
Normal file
@ -0,0 +1,39 @@
|
||||
// getprop, proto and self, 3 shapes
|
||||
|
||||
var expected = "22,202,99;202,99,22;99,22,202;22,202,99;202,99,22;99,22,202;22,202,99;202,99,22;99,22,202;";
|
||||
var actual = '';
|
||||
|
||||
var protoB = { a: 11, b: 22, c: 33 };
|
||||
|
||||
function B() {
|
||||
}
|
||||
B.prototype = protoB;
|
||||
|
||||
var protoC = { a: 101, b: 202, c: 303 };
|
||||
|
||||
function C() {
|
||||
}
|
||||
C.prototype = protoC;
|
||||
|
||||
function f() {
|
||||
var o1 = new B();
|
||||
var o2 = new C();
|
||||
var o3 = new C();
|
||||
o3.b = 99;
|
||||
var oa = [ o1, o2, o3 ];
|
||||
|
||||
for (var i = 0; i < 9; ++i) {
|
||||
// Use 3 PICs so we start out with each type in one PIC.
|
||||
var i1 = i % 3;
|
||||
var i2 = (i+1) % 3;
|
||||
var i3 = (i+2) % 3;
|
||||
|
||||
actual += oa[i1].b + ',';
|
||||
actual += oa[i2].b + ',';
|
||||
actual += oa[i3].b + ';';
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
assertEq(actual, expected);
|
18
js/src/trace-test/tests/pic/self1.js
Normal file
18
js/src/trace-test/tests/pic/self1.js
Normal file
@ -0,0 +1,18 @@
|
||||
// getprop, self, 1 shape
|
||||
|
||||
var expected = "11,22,33,11,22,33,11,22,33,11,22,33,11,22,33,";
|
||||
var actual = '';
|
||||
|
||||
function f() {
|
||||
var o = { a: 11, b: 22, c: 33 };
|
||||
|
||||
for (var i = 0; i < 5; ++i) {
|
||||
actual += o.a + ',';
|
||||
actual += o.b + ',';
|
||||
actual += o.c + ',';
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
assertEq(actual, expected);
|
18
js/src/trace-test/tests/pic/self2.js
Normal file
18
js/src/trace-test/tests/pic/self2.js
Normal file
@ -0,0 +1,18 @@
|
||||
// getprop, self, 2 shapes
|
||||
|
||||
var expected = "22,303,22,303,22,303,22,303,";
|
||||
var actual = '';
|
||||
|
||||
function f() {
|
||||
var o1 = { a: 11, b: 22, c: 33 };
|
||||
var o2 = { x: 101, y: 202, b: 303 };
|
||||
var oa = [ o1, o2 ];
|
||||
|
||||
for (var i = 0; i < 8; ++i) {
|
||||
actual += oa[i%2].b + ',';
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
assertEq(actual, expected);
|
19
js/src/trace-test/tests/pic/self3.js
Normal file
19
js/src/trace-test/tests/pic/self3.js
Normal file
@ -0,0 +1,19 @@
|
||||
// getprop, self, 3 shapes
|
||||
|
||||
var expected = "22,303,1001,22,303,1001,22,303,";
|
||||
var actual = '';
|
||||
|
||||
function f() {
|
||||
var o1 = { a: 11, b: 22, c: 33 };
|
||||
var o2 = { x: 101, y: 202, b: 303 };
|
||||
var o3 = { b: 1001, x: 2002, y: 3003 };
|
||||
var oa = [ o1, o2, o3 ];
|
||||
|
||||
for (var i = 0; i < 8; ++i) {
|
||||
actual += oa[i%3].b + ',';
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
assertEq(actual, expected);
|
32
js/src/trace-test/tests/pic/self8.js
Normal file
32
js/src/trace-test/tests/pic/self8.js
Normal file
@ -0,0 +1,32 @@
|
||||
// getprop, self, 8 shapes
|
||||
|
||||
var expected = "0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,";
|
||||
var actual = '';
|
||||
|
||||
function letter(i) {
|
||||
return String.fromCharCode(97 + i);
|
||||
}
|
||||
|
||||
function f() {
|
||||
// Build 8 objects with different shapes and x in different slots.
|
||||
var oa = [];
|
||||
for (var i = 0; i < 8; ++i) {
|
||||
var o = {};
|
||||
for (var j = 0; j < 8; ++j) {
|
||||
if (j != i) {
|
||||
o[letter(j)] = 1000 + i * 10 + j;
|
||||
} else {
|
||||
o.x = i;
|
||||
}
|
||||
}
|
||||
oa[i] = o;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 24; ++i) {
|
||||
actual += oa[i%8].x + ',';
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
assertEq(actual, expected);
|
10
js/src/trace-test/tests/pic/set-assign.js
Normal file
10
js/src/trace-test/tests/pic/set-assign.js
Normal file
@ -0,0 +1,10 @@
|
||||
function f() {
|
||||
var o = { a: 555 };
|
||||
|
||||
for (var j = 0; j < 10; ++j) {
|
||||
var i = o.a = 100 + j;
|
||||
assertEq(i, 100 + j);
|
||||
}
|
||||
}
|
||||
|
||||
f()
|
11
js/src/trace-test/tests/pic/set1.js
Normal file
11
js/src/trace-test/tests/pic/set1.js
Normal file
@ -0,0 +1,11 @@
|
||||
function f() {
|
||||
var o = { a: 5 };
|
||||
|
||||
for (var i = 0; i < 5; ++i) {
|
||||
o.a = i;
|
||||
}
|
||||
|
||||
assertEq(o.a, 4);
|
||||
}
|
||||
|
||||
f();
|
14
js/src/trace-test/tests/pic/set2.js
Normal file
14
js/src/trace-test/tests/pic/set2.js
Normal file
@ -0,0 +1,14 @@
|
||||
function f(k) {
|
||||
var o1 = { a: 5 };
|
||||
var o2 = { b : 7, a : 9 };
|
||||
|
||||
for (var i = 0; i < k; ++i) {
|
||||
var o = i % 2 ? o2 : o1;
|
||||
o.a = i;
|
||||
}
|
||||
|
||||
return o1.a + ',' + o2.a;
|
||||
}
|
||||
|
||||
assertEq(f(5), '4,3')
|
||||
assertEq(f(6), '4,5')
|
33
js/src/trace-test/tests/pic/shape_regen.js
Normal file
33
js/src/trace-test/tests/pic/shape_regen.js
Normal file
@ -0,0 +1,33 @@
|
||||
// Try to test that we handle shape regeneration correctly.
|
||||
// This is a fragile test, but as of this writing, on dmandelin's
|
||||
// windows box, we have the same shape number with different
|
||||
// logical shapes in the two assertEq lines.
|
||||
|
||||
var o;
|
||||
var p;
|
||||
var zz;
|
||||
var o2;
|
||||
|
||||
function f(x) {
|
||||
return x.a;
|
||||
}
|
||||
|
||||
gczeal(1);
|
||||
gc();
|
||||
|
||||
zz = { q: 11 };
|
||||
o = { a: 77, b: 88 };
|
||||
o2 = { c: 11 };
|
||||
p = { b: 99, a: 11 };
|
||||
|
||||
//print('s ' + shapeOf(zz) + ' ' + shapeOf(o) + ' ' + shapeOf(o2) + ' ' + shapeOf(p));
|
||||
|
||||
assertEq(f(o), 77);
|
||||
|
||||
o = undefined;
|
||||
|
||||
gczeal(1);
|
||||
gc();
|
||||
//print('s ' + 'x' + ' ' + shapeOf(p));
|
||||
|
||||
assertEq(f(p), 11);
|
30
js/src/trace-test/tests/pic/thisprop.js
Normal file
30
js/src/trace-test/tests/pic/thisprop.js
Normal file
@ -0,0 +1,30 @@
|
||||
// test getthisprop
|
||||
|
||||
var expected = "22,22,22,;33,33,33,;";
|
||||
var actual = '';
|
||||
|
||||
function f() {
|
||||
for (var i = 0; i < 3; ++i) {
|
||||
actual += this.b + ',';
|
||||
}
|
||||
actual += ';';
|
||||
}
|
||||
|
||||
function A() {
|
||||
this.a = 11;
|
||||
this.b = 22;
|
||||
};
|
||||
|
||||
A.prototype.f = f;
|
||||
|
||||
function B() {
|
||||
this.b = 33;
|
||||
this.c = 44;
|
||||
};
|
||||
|
||||
B.prototype.f = f;
|
||||
|
||||
new A().f();
|
||||
new B().f();
|
||||
|
||||
assertEq(actual, expected);
|
Loading…
Reference in New Issue
Block a user