CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / js / src / methodjit / Compiler.h
blob8ac24d764ce0721c193c4ee6900384f1c380d9a6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=4 sw=4 et tw=99:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18 * May 28, 2008.
20 * The Initial Developer of the Original Code is
21 * Brendan Eich <brendan@mozilla.org>
23 * Contributor(s):
24 * David Anderson <danderson@mozilla.com>
25 * David Mandelin <dmandelin@mozilla.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
40 #if !defined jsjaeger_compiler_h__ && defined JS_METHODJIT
41 #define jsjaeger_compiler_h__
43 #include "jsanalyze.h"
44 #include "jscntxt.h"
45 #include "jstl.h"
46 #include "MethodJIT.h"
47 #include "CodeGenIncludes.h"
48 #include "BaseCompiler.h"
49 #include "StubCompiler.h"
50 #include "MonoIC.h"
51 #include "PolyIC.h"
53 namespace js {
54 namespace mjit {
56 class Compiler : public BaseCompiler
58 friend class StubCompiler;
60 struct BranchPatch {
61 BranchPatch(const Jump &j, jsbytecode *pc)
62 : jump(j), pc(pc)
63 { }
65 Jump jump;
66 jsbytecode *pc;
69 #if defined JS_MONOIC
70 struct GlobalNameICInfo {
71 Label fastPathStart;
72 Call slowPathCall;
73 DataLabel32 shape;
74 DataLabelPtr addrLabel;
75 bool usePropertyCache;
77 void copyTo(ic::GlobalNameIC &to, JSC::LinkBuffer &full, JSC::LinkBuffer &stub) {
78 to.fastPathStart = full.locationOf(fastPathStart);
80 int offset = full.locationOf(shape) - to.fastPathStart;
81 to.shapeOffset = offset;
82 JS_ASSERT(to.shapeOffset == offset);
84 to.slowPathCall = stub.locationOf(slowPathCall);
85 to.usePropertyCache = usePropertyCache;
89 struct GetGlobalNameICInfo : public GlobalNameICInfo {
90 Label load;
93 struct SetGlobalNameICInfo : public GlobalNameICInfo {
94 Label slowPathStart;
95 Label fastPathRejoin;
96 DataLabel32 store;
97 Jump shapeGuardJump;
98 ValueRemat vr;
99 RegisterID objReg;
100 RegisterID shapeReg;
101 bool objConst;
104 struct EqualityGenInfo {
105 DataLabelPtr addrLabel;
106 Label stubEntry;
107 Call stubCall;
108 BoolStub stub;
109 MaybeJump jumpToStub;
110 Label fallThrough;
111 jsbytecode *jumpTarget;
112 ValueRemat lvr, rvr;
113 Assembler::Condition cond;
114 JSC::MacroAssembler::RegisterID tempReg;
117 struct TraceGenInfo {
118 bool initialized;
119 Label stubEntry;
120 DataLabelPtr addrLabel;
121 jsbytecode *jumpTarget;
122 Jump traceHint;
123 MaybeJump slowTraceHint;
125 TraceGenInfo() : initialized(false) {}
128 /* InlineFrameAssembler wants to see this. */
129 public:
130 struct CallGenInfo {
131 CallGenInfo(jsbytecode *pc) : pc(pc) {}
134 * These members map to members in CallICInfo. See that structure for
135 * more comments.
137 jsbytecode *pc;
138 DataLabelPtr funGuard;
139 Jump funJump;
140 Jump hotJump;
141 Call oolCall;
142 Label joinPoint;
143 Label slowJoinPoint;
144 Label slowPathStart;
145 Label hotPathLabel;
146 DataLabelPtr addrLabel1;
147 DataLabelPtr addrLabel2;
148 Jump oolJump;
149 Label icCall;
150 RegisterID funObjReg;
151 RegisterID funPtrReg;
152 FrameSize frameSize;
155 private:
156 #endif
159 * Writes of call return addresses which needs to be delayed until the final
160 * absolute address of the join point is known.
162 struct CallPatchInfo {
163 CallPatchInfo() : hasFastNcode(false), hasSlowNcode(false) {}
164 Label joinPoint;
165 DataLabelPtr fastNcodePatch;
166 DataLabelPtr slowNcodePatch;
167 bool hasFastNcode;
168 bool hasSlowNcode;
171 struct BaseICInfo {
172 BaseICInfo(JSOp op) : op(op)
174 Label fastPathStart;
175 Label fastPathRejoin;
176 Label slowPathStart;
177 Call slowPathCall;
178 DataLabelPtr paramAddr;
179 JSOp op;
181 void copyTo(ic::BaseIC &to, JSC::LinkBuffer &full, JSC::LinkBuffer &stub) {
182 to.fastPathStart = full.locationOf(fastPathStart);
183 to.fastPathRejoin = full.locationOf(fastPathRejoin);
184 to.slowPathStart = stub.locationOf(slowPathStart);
185 to.slowPathCall = stub.locationOf(slowPathCall);
186 to.op = op;
187 JS_ASSERT(to.op == op);
191 struct GetElementICInfo : public BaseICInfo {
192 GetElementICInfo(JSOp op) : BaseICInfo(op)
194 RegisterID typeReg;
195 RegisterID objReg;
196 ValueRemat id;
197 MaybeJump typeGuard;
198 Jump claspGuard;
201 struct SetElementICInfo : public BaseICInfo {
202 SetElementICInfo(JSOp op) : BaseICInfo(op)
204 RegisterID objReg;
205 StateRemat objRemat;
206 ValueRemat vr;
207 Jump capacityGuard;
208 Jump claspGuard;
209 Jump holeGuard;
210 Int32Key key;
211 uint32 volatileMask;
214 struct PICGenInfo : public BaseICInfo {
215 PICGenInfo(ic::PICInfo::Kind kind, JSOp op, bool usePropCache)
216 : BaseICInfo(op), kind(kind), usePropCache(usePropCache)
218 ic::PICInfo::Kind kind;
219 Label typeCheck;
220 RegisterID shapeReg;
221 RegisterID objReg;
222 RegisterID typeReg;
223 bool usePropCache;
224 Label shapeGuard;
225 jsbytecode *pc;
226 JSAtom *atom;
227 bool hasTypeCheck;
228 ValueRemat vr;
229 #ifdef JS_HAS_IC_LABELS
230 union {
231 ic::GetPropLabels getPropLabels_;
232 ic::SetPropLabels setPropLabels_;
233 ic::BindNameLabels bindNameLabels_;
234 ic::ScopeNameLabels scopeNameLabels_;
237 ic::GetPropLabels &getPropLabels() {
238 JS_ASSERT(kind == ic::PICInfo::GET || kind == ic::PICInfo::CALL);
239 return getPropLabels_;
241 ic::SetPropLabels &setPropLabels() {
242 JS_ASSERT(kind == ic::PICInfo::SET || kind == ic::PICInfo::SETMETHOD);
243 return setPropLabels_;
245 ic::BindNameLabels &bindNameLabels() {
246 JS_ASSERT(kind == ic::PICInfo::BIND);
247 return bindNameLabels_;
249 ic::ScopeNameLabels &scopeNameLabels() {
250 JS_ASSERT(kind == ic::PICInfo::NAME || kind == ic::PICInfo::XNAME);
251 return scopeNameLabels_;
253 #else
254 ic::GetPropLabels &getPropLabels() {
255 JS_ASSERT(kind == ic::PICInfo::GET || kind == ic::PICInfo::CALL);
256 return ic::PICInfo::getPropLabels_;
258 ic::SetPropLabels &setPropLabels() {
259 JS_ASSERT(kind == ic::PICInfo::SET || kind == ic::PICInfo::SETMETHOD);
260 return ic::PICInfo::setPropLabels_;
262 ic::BindNameLabels &bindNameLabels() {
263 JS_ASSERT(kind == ic::PICInfo::BIND);
264 return ic::PICInfo::bindNameLabels_;
266 ic::ScopeNameLabels &scopeNameLabels() {
267 JS_ASSERT(kind == ic::PICInfo::NAME || kind == ic::PICInfo::XNAME);
268 return ic::PICInfo::scopeNameLabels_;
270 #endif
272 void copySimpleMembersTo(ic::PICInfo &ic) {
273 ic.kind = kind;
274 ic.shapeReg = shapeReg;
275 ic.objReg = objReg;
276 ic.atom = atom;
277 ic.usePropCache = usePropCache;
278 if (ic.isSet()) {
279 ic.u.vr = vr;
280 } else if (ic.isGet()) {
281 ic.u.get.typeReg = typeReg;
282 ic.u.get.hasTypeCheck = hasTypeCheck;
284 #ifdef JS_HAS_IC_LABELS
285 if (ic.isGet())
286 ic.setLabels(getPropLabels());
287 else if (ic.isSet())
288 ic.setLabels(setPropLabels());
289 else if (ic.isBind())
290 ic.setLabels(bindNameLabels());
291 else if (ic.isScopeName())
292 ic.setLabels(scopeNameLabels());
293 #endif
298 struct Defs {
299 Defs(uint32 ndefs)
300 : ndefs(ndefs)
302 uint32 ndefs;
305 struct InternalCallSite {
306 uint32 returnOffset;
307 jsbytecode *pc;
308 uint32 id;
309 bool call;
310 bool ool;
312 InternalCallSite(uint32 returnOffset, jsbytecode *pc, uint32 id,
313 bool call, bool ool)
314 : returnOffset(returnOffset), pc(pc), id(id), call(call), ool(ool)
318 struct DoublePatch {
319 double d;
320 DataLabelPtr label;
321 bool ool;
324 struct JumpTable {
325 DataLabelPtr label;
326 size_t offsetIndex;
329 JSStackFrame *fp;
330 JSScript *script;
331 JSObject *scopeChain;
332 JSObject *globalObj;
333 JSFunction *fun;
334 bool isConstructing;
335 analyze::Script *analysis;
336 Label *jumpMap;
337 bool *savedTraps;
338 jsbytecode *PC;
339 Assembler masm;
340 FrameState frame;
341 js::Vector<BranchPatch, 64, CompilerAllocPolicy> branchPatches;
342 #if defined JS_MONOIC
343 js::Vector<GetGlobalNameICInfo, 16, CompilerAllocPolicy> getGlobalNames;
344 js::Vector<SetGlobalNameICInfo, 16, CompilerAllocPolicy> setGlobalNames;
345 js::Vector<CallGenInfo, 64, CompilerAllocPolicy> callICs;
346 js::Vector<EqualityGenInfo, 64, CompilerAllocPolicy> equalityICs;
347 js::Vector<TraceGenInfo, 64, CompilerAllocPolicy> traceICs;
348 #endif
349 #if defined JS_POLYIC
350 js::Vector<PICGenInfo, 16, CompilerAllocPolicy> pics;
351 js::Vector<GetElementICInfo, 16, CompilerAllocPolicy> getElemICs;
352 js::Vector<SetElementICInfo, 16, CompilerAllocPolicy> setElemICs;
353 #endif
354 js::Vector<CallPatchInfo, 64, CompilerAllocPolicy> callPatches;
355 js::Vector<InternalCallSite, 64, CompilerAllocPolicy> callSites;
356 js::Vector<DoublePatch, 16, CompilerAllocPolicy> doubleList;
357 js::Vector<JumpTable, 16> jumpTables;
358 js::Vector<uint32, 16> jumpTableOffsets;
359 StubCompiler stubcc;
360 Label invokeLabel;
361 Label arityLabel;
362 bool debugMode_;
363 bool addTraceHints;
364 bool oomInVector; // True if we have OOM'd appending to a vector.
365 enum { NoApplyTricks, LazyArgsObj } applyTricks;
367 Compiler *thisFromCtor() { return this; }
369 friend class CompilerAllocPolicy;
370 public:
371 // Special atom index used to indicate that the atom is 'length'. This
372 // follows interpreter usage in JSOP_LENGTH.
373 enum { LengthAtomIndex = uint32(-2) };
375 Compiler(JSContext *cx, JSStackFrame *fp);
376 ~Compiler();
378 CompileStatus compile();
380 jsbytecode *getPC() { return PC; }
381 Label getLabel() { return masm.label(); }
382 bool knownJump(jsbytecode *pc);
383 Label labelOf(jsbytecode *target);
384 void *findCallSite(const CallSite &callSite);
385 void addCallSite(const InternalCallSite &callSite);
386 void addReturnSite(Label joinPoint, uint32 id);
387 bool loadOldTraps(const Vector<CallSite> &site);
389 bool debugMode() { return debugMode_; }
391 private:
392 CompileStatus performCompilation(JITScript **jitp);
393 CompileStatus generatePrologue();
394 CompileStatus generateMethod();
395 CompileStatus generateEpilogue();
396 CompileStatus finishThisUp(JITScript **jitp);
398 /* Non-emitting helpers. */
399 uint32 fullAtomIndex(jsbytecode *pc);
400 bool jumpInScript(Jump j, jsbytecode *pc);
401 bool compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs);
402 bool canUseApplyTricks();
404 /* Emitting helpers. */
405 void restoreFrameRegs(Assembler &masm);
406 bool emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused);
407 bool iter(uintN flags);
408 void iterNext();
409 bool iterMore();
410 void iterEnd();
411 MaybeJump loadDouble(FrameEntry *fe, FPRegisterID fpReg);
412 #ifdef JS_POLYIC
413 void passICAddress(BaseICInfo *ic);
414 #endif
415 #ifdef JS_MONOIC
416 void passMICAddress(GlobalNameICInfo &mic);
417 #endif
418 bool constructThis();
420 /* Opcode handlers. */
421 bool jumpAndTrace(Jump j, jsbytecode *target, Jump *slow = NULL);
422 void jsop_bindname(JSAtom *atom, bool usePropCache);
423 void jsop_setglobal(uint32 index);
424 void jsop_getglobal(uint32 index);
425 void jsop_getprop_slow(JSAtom *atom, bool usePropCache = true);
426 void jsop_getarg(uint32 slot);
427 void jsop_setarg(uint32 slot, bool popped);
428 void jsop_this();
429 void emitReturn(FrameEntry *fe);
430 void emitFinalReturn(Assembler &masm);
431 void loadReturnValue(Assembler *masm, FrameEntry *fe);
432 void emitReturnValue(Assembler *masm, FrameEntry *fe);
433 void dispatchCall(VoidPtrStubUInt32 stub, uint32 argc);
434 void interruptCheckHelper();
435 void emitUncachedCall(uint32 argc, bool callingNew);
436 void checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedArgc,
437 FrameEntry *origCallee, FrameEntry *origThis,
438 MaybeRegisterID origCalleeType, RegisterID origCalleeData,
439 MaybeRegisterID origThisType, RegisterID origThisData,
440 Jump *uncachedCallSlowRejoin, CallPatchInfo *uncachedCallPatch);
441 void inlineCallHelper(uint32 argc, bool callingNew);
442 void fixPrimitiveReturn(Assembler *masm, FrameEntry *fe);
443 void jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index);
444 bool jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index);
445 bool jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index);
446 void jsop_eleminc(JSOp op, VoidStub);
447 void jsop_getgname(uint32 index);
448 void jsop_getgname_slow(uint32 index);
449 void jsop_setgname(JSAtom *atom, bool usePropertyCache);
450 void jsop_setgname_slow(JSAtom *atom, bool usePropertyCache);
451 void jsop_bindgname();
452 void jsop_setelem_slow();
453 void jsop_getelem_slow();
454 void jsop_callelem_slow();
455 void jsop_unbrand();
456 bool jsop_getprop(JSAtom *atom, bool typeCheck = true, bool usePropCache = true);
457 bool jsop_length();
458 bool jsop_setprop(JSAtom *atom, bool usePropCache = true);
459 void jsop_setprop_slow(JSAtom *atom, bool usePropCache = true);
460 bool jsop_callprop_slow(JSAtom *atom);
461 bool jsop_callprop(JSAtom *atom);
462 bool jsop_callprop_obj(JSAtom *atom);
463 bool jsop_callprop_str(JSAtom *atom);
464 bool jsop_callprop_generic(JSAtom *atom);
465 bool jsop_instanceof();
466 void jsop_name(JSAtom *atom);
467 bool jsop_xname(JSAtom *atom);
468 void enterBlock(JSObject *obj);
469 void leaveBlock();
470 void emitEval(uint32 argc);
471 void jsop_arguments();
472 bool jsop_tableswitch(jsbytecode *pc);
473 void jsop_forprop(JSAtom *atom);
474 void jsop_forname(JSAtom *atom);
475 void jsop_forgname(JSAtom *atom);
477 /* Fast arithmetic. */
478 void jsop_binary(JSOp op, VoidStub stub);
479 void jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub);
480 void jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub);
481 void jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub);
482 void slowLoadConstantDouble(Assembler &masm, FrameEntry *fe,
483 FPRegisterID fpreg);
484 void maybeJumpIfNotInt32(Assembler &masm, MaybeJump &mj, FrameEntry *fe,
485 MaybeRegisterID &mreg);
486 void maybeJumpIfNotDouble(Assembler &masm, MaybeJump &mj, FrameEntry *fe,
487 MaybeRegisterID &mreg);
488 bool jsop_relational(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
489 bool jsop_relational_self(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
490 bool jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
491 bool jsop_relational_double(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
493 void emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
494 MaybeJump &lhsNotDouble, MaybeJump &rhsNotNumber,
495 MaybeJump &lhsUnknownDone);
496 void emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
497 MaybeJump &rhsNotNumber2);
498 bool tryBinaryConstantFold(JSContext *cx, FrameState &frame, JSOp op,
499 FrameEntry *lhs, FrameEntry *rhs);
501 /* Fast opcodes. */
502 void jsop_bitop(JSOp op);
503 void jsop_rsh();
504 RegisterID rightRegForShift(FrameEntry *rhs);
505 void jsop_rsh_int_int(FrameEntry *lhs, FrameEntry *rhs);
506 void jsop_rsh_const_int(FrameEntry *lhs, FrameEntry *rhs);
507 void jsop_rsh_int_const(FrameEntry *lhs, FrameEntry *rhs);
508 void jsop_rsh_int_unknown(FrameEntry *lhs, FrameEntry *rhs);
509 void jsop_rsh_const_const(FrameEntry *lhs, FrameEntry *rhs);
510 void jsop_rsh_const_unknown(FrameEntry *lhs, FrameEntry *rhs);
511 void jsop_rsh_unknown_const(FrameEntry *lhs, FrameEntry *rhs);
512 void jsop_rsh_unknown_any(FrameEntry *lhs, FrameEntry *rhs);
513 void jsop_mod();
514 void jsop_neg();
515 void jsop_bitnot();
516 void jsop_not();
517 void jsop_typeof();
518 bool booleanJumpScript(JSOp op, jsbytecode *target);
519 bool jsop_ifneq(JSOp op, jsbytecode *target);
520 bool jsop_andor(JSOp op, jsbytecode *target);
521 void jsop_arginc(JSOp op, uint32 slot, bool popped);
522 void jsop_localinc(JSOp op, uint32 slot, bool popped);
523 void jsop_newinit();
524 void jsop_initmethod();
525 void jsop_initprop();
526 void jsop_initelem();
527 bool jsop_setelem(bool popGuaranteed);
528 bool jsop_getelem(bool isCall);
529 bool isCacheableBaseAndIndex(FrameEntry *obj, FrameEntry *id);
530 void jsop_stricteq(JSOp op);
531 bool jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
532 bool jsop_equality_int_string(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
533 void jsop_pos();
536 void prepareStubCall(Uses uses);
537 Call emitStubCall(void *ptr);
540 // Given a stub call, emits the call into the inline assembly path. If
541 // debug mode is on, adds the appropriate instrumentation for recompilation.
542 #define INLINE_STUBCALL(stub) \
543 do { \
544 Call cl = emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub))); \
545 if (debugMode()) { \
546 InternalCallSite site(masm.callReturnOffset(cl), PC, __LINE__, \
547 true, false); \
548 addCallSite(site); \
550 } while (0) \
552 // Given a stub call, emits the call into the out-of-line assembly path. If
553 // debug mode is on, adds the appropriate instrumentation for recompilation.
554 // Unlike the INLINE_STUBCALL variant, this returns the Call offset.
555 #define OOL_STUBCALL(stub) \
556 stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), __LINE__) \
558 // Same as OOL_STUBCALL, but specifies a slot depth.
559 #define OOL_STUBCALL_LOCAL_SLOTS(stub, slots) \
560 stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), (slots), __LINE__) \
562 } /* namespace js */
563 } /* namespace mjit */
565 #endif