summaryrefslogtreecommitdiff
path: root/js/src/methodjit/Compiler.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/methodjit/Compiler.h')
-rw-r--r--js/src/methodjit/Compiler.h567
1 files changed, 567 insertions, 0 deletions
diff --git a/js/src/methodjit/Compiler.h b/js/src/methodjit/Compiler.h
new file mode 100644
index 0000000..95d8074
--- /dev/null
+++ b/js/src/methodjit/Compiler.h
@@ -0,0 +1,567 @@
+/* -*- 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 ***** */
+#if !defined jsjaeger_compiler_h__ && defined JS_METHODJIT
+#define jsjaeger_compiler_h__
+
+#include "jsanalyze.h"
+#include "jscntxt.h"
+#include "jstl.h"
+#include "MethodJIT.h"
+#include "CodeGenIncludes.h"
+#include "BaseCompiler.h"
+#include "StubCompiler.h"
+#include "MonoIC.h"
+#include "PolyIC.h"
+
+namespace js {
+namespace mjit {
+
+class Compiler : public BaseCompiler
+{
+ friend class StubCompiler;
+
+ struct BranchPatch {
+ BranchPatch(const Jump &j, jsbytecode *pc)
+ : jump(j), pc(pc)
+ { }
+
+ Jump jump;
+ jsbytecode *pc;
+ };
+
+#if defined JS_MONOIC
+ struct GlobalNameICInfo {
+ Label fastPathStart;
+ Call slowPathCall;
+ DataLabel32 shape;
+ DataLabelPtr addrLabel;
+ bool usePropertyCache;
+
+ void copyTo(ic::GlobalNameIC &to, JSC::LinkBuffer &full, JSC::LinkBuffer &stub) {
+ to.fastPathStart = full.locationOf(fastPathStart);
+
+ int offset = full.locationOf(shape) - to.fastPathStart;
+ to.shapeOffset = offset;
+ JS_ASSERT(to.shapeOffset == offset);
+
+ to.slowPathCall = stub.locationOf(slowPathCall);
+ to.usePropertyCache = usePropertyCache;
+ }
+ };
+
+ struct GetGlobalNameICInfo : public GlobalNameICInfo {
+ Label load;
+ };
+
+ struct SetGlobalNameICInfo : public GlobalNameICInfo {
+ Label slowPathStart;
+ Label fastPathRejoin;
+ DataLabel32 store;
+ Jump shapeGuardJump;
+ ValueRemat vr;
+ RegisterID objReg;
+ RegisterID shapeReg;
+ bool objConst;
+ };
+
+ struct EqualityGenInfo {
+ DataLabelPtr addrLabel;
+ Label stubEntry;
+ Call stubCall;
+ BoolStub stub;
+ MaybeJump jumpToStub;
+ Label fallThrough;
+ jsbytecode *jumpTarget;
+ ValueRemat lvr, rvr;
+ Assembler::Condition cond;
+ JSC::MacroAssembler::RegisterID tempReg;
+ };
+
+ struct TraceGenInfo {
+ bool initialized;
+ Label stubEntry;
+ DataLabelPtr addrLabel;
+ jsbytecode *jumpTarget;
+ Jump traceHint;
+ MaybeJump slowTraceHint;
+
+ TraceGenInfo() : initialized(false) {}
+ };
+
+ /* InlineFrameAssembler wants to see this. */
+ public:
+ struct CallGenInfo {
+ CallGenInfo(jsbytecode *pc) : pc(pc) {}
+
+ /*
+ * These members map to members in CallICInfo. See that structure for
+ * more comments.
+ */
+ jsbytecode *pc;
+ DataLabelPtr funGuard;
+ Jump funJump;
+ Jump hotJump;
+ Call oolCall;
+ Label joinPoint;
+ Label slowJoinPoint;
+ Label slowPathStart;
+ Label hotPathLabel;
+ DataLabelPtr addrLabel1;
+ DataLabelPtr addrLabel2;
+ Jump oolJump;
+ Label icCall;
+ RegisterID funObjReg;
+ RegisterID funPtrReg;
+ FrameSize frameSize;
+ };
+
+ private:
+#endif
+
+ /*
+ * Writes of call return addresses which needs to be delayed until the final
+ * absolute address of the join point is known.
+ */
+ struct CallPatchInfo {
+ CallPatchInfo() : hasFastNcode(false), hasSlowNcode(false) {}
+ Label joinPoint;
+ DataLabelPtr fastNcodePatch;
+ DataLabelPtr slowNcodePatch;
+ bool hasFastNcode;
+ bool hasSlowNcode;
+ };
+
+ struct BaseICInfo {
+ BaseICInfo(JSOp op) : op(op)
+ { }
+ Label fastPathStart;
+ Label fastPathRejoin;
+ Label slowPathStart;
+ Call slowPathCall;
+ DataLabelPtr paramAddr;
+ JSOp op;
+
+ void copyTo(ic::BaseIC &to, JSC::LinkBuffer &full, JSC::LinkBuffer &stub) {
+ to.fastPathStart = full.locationOf(fastPathStart);
+ to.fastPathRejoin = full.locationOf(fastPathRejoin);
+ to.slowPathStart = stub.locationOf(slowPathStart);
+ to.slowPathCall = stub.locationOf(slowPathCall);
+ to.op = op;
+ JS_ASSERT(to.op == op);
+ }
+ };
+
+ struct GetElementICInfo : public BaseICInfo {
+ GetElementICInfo(JSOp op) : BaseICInfo(op)
+ { }
+ RegisterID typeReg;
+ RegisterID objReg;
+ ValueRemat id;
+ MaybeJump typeGuard;
+ Jump claspGuard;
+ };
+
+ struct SetElementICInfo : public BaseICInfo {
+ SetElementICInfo(JSOp op) : BaseICInfo(op)
+ { }
+ RegisterID objReg;
+ StateRemat objRemat;
+ ValueRemat vr;
+ Jump capacityGuard;
+ Jump claspGuard;
+ Jump holeGuard;
+ Int32Key key;
+ uint32 volatileMask;
+ };
+
+ struct PICGenInfo : public BaseICInfo {
+ PICGenInfo(ic::PICInfo::Kind kind, JSOp op, bool usePropCache)
+ : BaseICInfo(op), kind(kind), usePropCache(usePropCache)
+ { }
+ ic::PICInfo::Kind kind;
+ Label typeCheck;
+ RegisterID shapeReg;
+ RegisterID objReg;
+ RegisterID typeReg;
+ bool usePropCache;
+ Label shapeGuard;
+ jsbytecode *pc;
+ JSAtom *atom;
+ bool hasTypeCheck;
+ ValueRemat vr;
+#ifdef JS_HAS_IC_LABELS
+ union {
+ ic::GetPropLabels getPropLabels_;
+ ic::SetPropLabels setPropLabels_;
+ ic::BindNameLabels bindNameLabels_;
+ ic::ScopeNameLabels scopeNameLabels_;
+ };
+
+ ic::GetPropLabels &getPropLabels() {
+ JS_ASSERT(kind == ic::PICInfo::GET || kind == ic::PICInfo::CALL);
+ return getPropLabels_;
+ }
+ ic::SetPropLabels &setPropLabels() {
+ JS_ASSERT(kind == ic::PICInfo::SET || kind == ic::PICInfo::SETMETHOD);
+ return setPropLabels_;
+ }
+ ic::BindNameLabels &bindNameLabels() {
+ JS_ASSERT(kind == ic::PICInfo::BIND);
+ return bindNameLabels_;
+ }
+ ic::ScopeNameLabels &scopeNameLabels() {
+ JS_ASSERT(kind == ic::PICInfo::NAME || kind == ic::PICInfo::XNAME);
+ return scopeNameLabels_;
+ }
+#else
+ ic::GetPropLabels &getPropLabels() {
+ JS_ASSERT(kind == ic::PICInfo::GET || kind == ic::PICInfo::CALL);
+ return ic::PICInfo::getPropLabels_;
+ }
+ ic::SetPropLabels &setPropLabels() {
+ JS_ASSERT(kind == ic::PICInfo::SET || kind == ic::PICInfo::SETMETHOD);
+ return ic::PICInfo::setPropLabels_;
+ }
+ ic::BindNameLabels &bindNameLabels() {
+ JS_ASSERT(kind == ic::PICInfo::BIND);
+ return ic::PICInfo::bindNameLabels_;
+ }
+ ic::ScopeNameLabels &scopeNameLabels() {
+ JS_ASSERT(kind == ic::PICInfo::NAME || kind == ic::PICInfo::XNAME);
+ return ic::PICInfo::scopeNameLabels_;
+ }
+#endif
+
+ void copySimpleMembersTo(ic::PICInfo &ic) {
+ ic.kind = kind;
+ ic.shapeReg = shapeReg;
+ ic.objReg = objReg;
+ ic.atom = atom;
+ ic.usePropCache = usePropCache;
+ if (ic.isSet()) {
+ ic.u.vr = vr;
+ } else if (ic.isGet()) {
+ ic.u.get.typeReg = typeReg;
+ ic.u.get.hasTypeCheck = hasTypeCheck;
+ }
+#ifdef JS_HAS_IC_LABELS
+ if (ic.isGet())
+ ic.setLabels(getPropLabels());
+ else if (ic.isSet())
+ ic.setLabels(setPropLabels());
+ else if (ic.isBind())
+ ic.setLabels(bindNameLabels());
+ else if (ic.isScopeName())
+ ic.setLabels(scopeNameLabels());
+#endif
+ }
+
+ };
+
+ struct Defs {
+ Defs(uint32 ndefs)
+ : ndefs(ndefs)
+ { }
+ uint32 ndefs;
+ };
+
+ struct InternalCallSite {
+ uint32 returnOffset;
+ jsbytecode *pc;
+ uint32 id;
+ bool call;
+ bool ool;
+
+ InternalCallSite(uint32 returnOffset, jsbytecode *pc, uint32 id,
+ bool call, bool ool)
+ : returnOffset(returnOffset), pc(pc), id(id), call(call), ool(ool)
+ { }
+ };
+
+ struct DoublePatch {
+ double d;
+ DataLabelPtr label;
+ bool ool;
+ };
+
+ struct JumpTable {
+ DataLabelPtr label;
+ size_t offsetIndex;
+ };
+
+ JSStackFrame *fp;
+ JSScript *script;
+ JSObject *scopeChain;
+ JSObject *globalObj;
+ JSFunction *fun;
+ bool isConstructing;
+ analyze::Script *analysis;
+ Label *jumpMap;
+ bool *savedTraps;
+ jsbytecode *PC;
+ Assembler masm;
+ FrameState frame;
+ js::Vector<BranchPatch, 64, CompilerAllocPolicy> branchPatches;
+#if defined JS_MONOIC
+ js::Vector<GetGlobalNameICInfo, 16, CompilerAllocPolicy> getGlobalNames;
+ js::Vector<SetGlobalNameICInfo, 16, CompilerAllocPolicy> setGlobalNames;
+ js::Vector<CallGenInfo, 64, CompilerAllocPolicy> callICs;
+ js::Vector<EqualityGenInfo, 64, CompilerAllocPolicy> equalityICs;
+ js::Vector<TraceGenInfo, 64, CompilerAllocPolicy> traceICs;
+#endif
+#if defined JS_POLYIC
+ js::Vector<PICGenInfo, 16, CompilerAllocPolicy> pics;
+ js::Vector<GetElementICInfo, 16, CompilerAllocPolicy> getElemICs;
+ js::Vector<SetElementICInfo, 16, CompilerAllocPolicy> setElemICs;
+#endif
+ js::Vector<CallPatchInfo, 64, CompilerAllocPolicy> callPatches;
+ js::Vector<InternalCallSite, 64, CompilerAllocPolicy> callSites;
+ js::Vector<DoublePatch, 16, CompilerAllocPolicy> doubleList;
+ js::Vector<JumpTable, 16> jumpTables;
+ js::Vector<uint32, 16> jumpTableOffsets;
+ StubCompiler stubcc;
+ Label invokeLabel;
+ Label arityLabel;
+ bool debugMode_;
+ bool addTraceHints;
+ bool oomInVector; // True if we have OOM'd appending to a vector.
+ enum { NoApplyTricks, LazyArgsObj } applyTricks;
+
+ Compiler *thisFromCtor() { return this; }
+
+ friend class CompilerAllocPolicy;
+ public:
+ // Special atom index used to indicate that the atom is 'length'. This
+ // follows interpreter usage in JSOP_LENGTH.
+ enum { LengthAtomIndex = uint32(-2) };
+
+ Compiler(JSContext *cx, JSStackFrame *fp);
+ ~Compiler();
+
+ CompileStatus compile();
+
+ jsbytecode *getPC() { return PC; }
+ Label getLabel() { return masm.label(); }
+ bool knownJump(jsbytecode *pc);
+ Label labelOf(jsbytecode *target);
+ void *findCallSite(const CallSite &callSite);
+ void addCallSite(const InternalCallSite &callSite);
+ void addReturnSite(Label joinPoint, uint32 id);
+ bool loadOldTraps(const Vector<CallSite> &site);
+
+ bool debugMode() { return debugMode_; }
+
+ private:
+ CompileStatus performCompilation(JITScript **jitp);
+ CompileStatus generatePrologue();
+ CompileStatus generateMethod();
+ CompileStatus generateEpilogue();
+ CompileStatus finishThisUp(JITScript **jitp);
+
+ /* Non-emitting helpers. */
+ uint32 fullAtomIndex(jsbytecode *pc);
+ bool jumpInScript(Jump j, jsbytecode *pc);
+ bool compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs);
+ bool canUseApplyTricks();
+
+ /* Emitting helpers. */
+ void restoreFrameRegs(Assembler &masm);
+ bool emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused);
+ bool iter(uintN flags);
+ void iterNext();
+ bool iterMore();
+ void iterEnd();
+ MaybeJump loadDouble(FrameEntry *fe, FPRegisterID fpReg);
+#ifdef JS_POLYIC
+ void passICAddress(BaseICInfo *ic);
+#endif
+#ifdef JS_MONOIC
+ void passMICAddress(GlobalNameICInfo &mic);
+#endif
+ bool constructThis();
+
+ /* Opcode handlers. */
+ bool jumpAndTrace(Jump j, jsbytecode *target, Jump *slow = NULL);
+ void jsop_bindname(JSAtom *atom, bool usePropCache);
+ void jsop_setglobal(uint32 index);
+ void jsop_getglobal(uint32 index);
+ void jsop_getprop_slow(JSAtom *atom, bool usePropCache = true);
+ void jsop_getarg(uint32 slot);
+ void jsop_setarg(uint32 slot, bool popped);
+ void jsop_this();
+ void emitReturn(FrameEntry *fe);
+ void emitFinalReturn(Assembler &masm);
+ void loadReturnValue(Assembler *masm, FrameEntry *fe);
+ void emitReturnValue(Assembler *masm, FrameEntry *fe);
+ void dispatchCall(VoidPtrStubUInt32 stub, uint32 argc);
+ void interruptCheckHelper();
+ void emitUncachedCall(uint32 argc, bool callingNew);
+ void checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedArgc,
+ FrameEntry *origCallee, FrameEntry *origThis,
+ MaybeRegisterID origCalleeType, RegisterID origCalleeData,
+ MaybeRegisterID origThisType, RegisterID origThisData,
+ Jump *uncachedCallSlowRejoin, CallPatchInfo *uncachedCallPatch);
+ void inlineCallHelper(uint32 argc, bool callingNew);
+ void fixPrimitiveReturn(Assembler *masm, FrameEntry *fe);
+ void jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index);
+ bool jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index);
+ bool jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index);
+ void jsop_eleminc(JSOp op, VoidStub);
+ void jsop_getgname(uint32 index);
+ void jsop_getgname_slow(uint32 index);
+ void jsop_callgname_epilogue();
+ void jsop_setgname(JSAtom *atom, bool usePropertyCache);
+ void jsop_setgname_slow(JSAtom *atom, bool usePropertyCache);
+ void jsop_bindgname();
+ void jsop_setelem_slow();
+ void jsop_getelem_slow();
+ void jsop_callelem_slow();
+ void jsop_unbrand();
+ bool jsop_getprop(JSAtom *atom, bool typeCheck = true, bool usePropCache = true);
+ bool jsop_length();
+ bool jsop_setprop(JSAtom *atom, bool usePropCache = true);
+ void jsop_setprop_slow(JSAtom *atom, bool usePropCache = true);
+ bool jsop_callprop_slow(JSAtom *atom);
+ bool jsop_callprop(JSAtom *atom);
+ bool jsop_callprop_obj(JSAtom *atom);
+ bool jsop_callprop_str(JSAtom *atom);
+ bool jsop_callprop_generic(JSAtom *atom);
+ bool jsop_instanceof();
+ void jsop_name(JSAtom *atom);
+ bool jsop_xname(JSAtom *atom);
+ void enterBlock(JSObject *obj);
+ void leaveBlock();
+ void emitEval(uint32 argc);
+ void jsop_arguments();
+ bool jsop_tableswitch(jsbytecode *pc);
+ void jsop_forprop(JSAtom *atom);
+ void jsop_forname(JSAtom *atom);
+ void jsop_forgname(JSAtom *atom);
+
+ /* Fast arithmetic. */
+ void jsop_binary(JSOp op, VoidStub stub);
+ void jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub);
+ void jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub);
+ void jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub);
+ void slowLoadConstantDouble(Assembler &masm, FrameEntry *fe,
+ FPRegisterID fpreg);
+ void maybeJumpIfNotInt32(Assembler &masm, MaybeJump &mj, FrameEntry *fe,
+ MaybeRegisterID &mreg);
+ void maybeJumpIfNotDouble(Assembler &masm, MaybeJump &mj, FrameEntry *fe,
+ MaybeRegisterID &mreg);
+ bool jsop_relational(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
+ bool jsop_relational_self(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
+ bool jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
+ bool jsop_relational_double(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
+
+ void emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
+ MaybeJump &lhsNotDouble, MaybeJump &rhsNotNumber,
+ MaybeJump &lhsUnknownDone);
+ void emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
+ MaybeJump &rhsNotNumber2);
+ bool tryBinaryConstantFold(JSContext *cx, FrameState &frame, JSOp op,
+ FrameEntry *lhs, FrameEntry *rhs);
+
+ /* Fast opcodes. */
+ void jsop_bitop(JSOp op);
+ void jsop_rsh();
+ RegisterID rightRegForShift(FrameEntry *rhs);
+ void jsop_rsh_int_int(FrameEntry *lhs, FrameEntry *rhs);
+ void jsop_rsh_const_int(FrameEntry *lhs, FrameEntry *rhs);
+ void jsop_rsh_int_const(FrameEntry *lhs, FrameEntry *rhs);
+ void jsop_rsh_int_unknown(FrameEntry *lhs, FrameEntry *rhs);
+ void jsop_rsh_const_const(FrameEntry *lhs, FrameEntry *rhs);
+ void jsop_rsh_const_unknown(FrameEntry *lhs, FrameEntry *rhs);
+ void jsop_rsh_unknown_const(FrameEntry *lhs, FrameEntry *rhs);
+ void jsop_rsh_unknown_any(FrameEntry *lhs, FrameEntry *rhs);
+ void jsop_mod();
+ void jsop_neg();
+ void jsop_bitnot();
+ void jsop_not();
+ void jsop_typeof();
+ bool booleanJumpScript(JSOp op, jsbytecode *target);
+ bool jsop_ifneq(JSOp op, jsbytecode *target);
+ bool jsop_andor(JSOp op, jsbytecode *target);
+ void jsop_arginc(JSOp op, uint32 slot, bool popped);
+ void jsop_localinc(JSOp op, uint32 slot, bool popped);
+ void jsop_newinit();
+ void jsop_initmethod();
+ void jsop_initprop();
+ void jsop_initelem();
+ bool jsop_setelem(bool popGuaranteed);
+ bool jsop_getelem(bool isCall);
+ bool isCacheableBaseAndIndex(FrameEntry *obj, FrameEntry *id);
+ void jsop_stricteq(JSOp op);
+ bool jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
+ bool jsop_equality_int_string(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
+ void jsop_pos();
+
+
+ void prepareStubCall(Uses uses);
+ Call emitStubCall(void *ptr);
+};
+
+// Given a stub call, emits the call into the inline assembly path. If
+// debug mode is on, adds the appropriate instrumentation for recompilation.
+#define INLINE_STUBCALL(stub) \
+ do { \
+ Call cl = emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub))); \
+ if (debugMode()) { \
+ InternalCallSite site(masm.callReturnOffset(cl), PC, __LINE__, \
+ true, false); \
+ addCallSite(site); \
+ } \
+ } while (0) \
+
+// Given a stub call, emits the call into the out-of-line assembly path. If
+// debug mode is on, adds the appropriate instrumentation for recompilation.
+// Unlike the INLINE_STUBCALL variant, this returns the Call offset.
+#define OOL_STUBCALL(stub) \
+ stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), __LINE__) \
+
+// Same as OOL_STUBCALL, but specifies a slot depth.
+#define OOL_STUBCALL_LOCAL_SLOTS(stub, slots) \
+ stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), (slots), __LINE__) \
+
+} /* namespace js */
+} /* namespace mjit */
+
+#endif
+