Refactor and improve GETELEM IC (bug 602641, r=dmandelin).
[mozilla-central.git] / js / src / methodjit / Compiler.h
blob3bf27b46e14860ff3da38c73f61aee0a13fef342
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
59 struct BranchPatch {
60 BranchPatch(const Jump &j, jsbytecode *pc)
61 : jump(j), pc(pc)
62 { }
64 Jump jump;
65 jsbytecode *pc;
68 #if defined JS_MONOIC
69 struct MICGenInfo {
70 MICGenInfo(ic::MICInfo::Kind kind) : kind(kind)
71 { }
72 Label entry;
73 Label stubEntry;
74 DataLabel32 shape;
75 DataLabelPtr addrLabel;
76 #if defined JS_PUNBOX64
77 uint32 patchValueOffset;
78 #endif
79 Label load;
80 Call call;
81 ic::MICInfo::Kind kind;
82 jsbytecode *jumpTarget;
83 Jump traceHint;
84 MaybeJump slowTraceHint;
85 union {
86 struct {
87 bool typeConst;
88 bool dataConst;
89 } name;
90 struct {
91 uint32 pcOffs;
92 } tracer;
93 } u;
96 struct EqualityGenInfo {
97 DataLabelPtr addrLabel;
98 Label stubEntry;
99 Call stubCall;
100 BoolStub stub;
101 MaybeJump jumpToStub;
102 Label fallThrough;
103 jsbytecode *jumpTarget;
104 ValueRemat lvr, rvr;
105 Assembler::Condition cond;
106 JSC::MacroAssembler::RegisterID tempReg;
109 struct TraceGenInfo {
110 bool initialized;
111 Label stubEntry;
112 DataLabelPtr addrLabel;
113 jsbytecode *jumpTarget;
114 Jump traceHint;
115 MaybeJump slowTraceHint;
117 TraceGenInfo() : initialized(false) {}
120 /* InlineFrameAssembler wants to see this. */
121 public:
122 struct CallGenInfo {
123 CallGenInfo(uint32 argc)
124 : argc(argc)
128 * These members map to members in CallICInfo. See that structure for
129 * more comments.
131 jsbytecode *pc;
132 uint32 argc;
133 DataLabelPtr funGuard;
134 Jump funJump;
135 Jump hotJump;
136 Call oolCall;
137 Label joinPoint;
138 Label slowJoinPoint;
139 Label slowPathStart;
140 Label hotPathLabel;
141 DataLabelPtr addrLabel1;
142 DataLabelPtr addrLabel2;
143 Jump oolJump;
144 RegisterID funObjReg;
145 RegisterID funPtrReg;
146 uint32 frameDepth;
149 private:
150 #endif
153 * Writes of call return addresses which needs to be delayed until the final
154 * absolute address of the join point is known.
156 struct CallPatchInfo {
157 Label joinPoint;
158 DataLabelPtr fastNcodePatch;
159 DataLabelPtr slowNcodePatch;
160 bool hasSlowNcode;
163 struct BaseICInfo {
164 BaseICInfo(JSOp op) : op(op)
166 Label fastPathStart;
167 Label fastPathRejoin;
168 Label slowPathStart;
169 Call slowPathCall;
170 DataLabelPtr paramAddr;
171 JSOp op;
173 void copyTo(ic::BaseIC &to, JSC::LinkBuffer &full, JSC::LinkBuffer &stub) {
174 to.fastPathStart = full.locationOf(fastPathStart);
175 to.fastPathRejoin = full.locationOf(fastPathRejoin);
176 to.slowPathStart = stub.locationOf(slowPathStart);
177 to.slowPathCall = stub.locationOf(slowPathCall);
178 to.op = op;
179 JS_ASSERT(to.op == op);
183 struct GetElementICInfo : public BaseICInfo {
184 GetElementICInfo(JSOp op) : BaseICInfo(op)
186 RegisterID typeReg;
187 RegisterID objReg;
188 ValueRemat id;
189 MaybeJump typeGuard;
190 Jump claspGuard;
193 struct PICGenInfo : public BaseICInfo {
194 PICGenInfo(ic::PICInfo::Kind kind, JSOp op, bool usePropCache)
195 : BaseICInfo(op), kind(kind), usePropCache(usePropCache)
197 ic::PICInfo::Kind kind;
198 Label typeCheck;
199 RegisterID shapeReg;
200 RegisterID objReg;
201 RegisterID idReg;
202 RegisterID typeReg;
203 bool usePropCache;
204 Label shapeGuard;
205 jsbytecode *pc;
206 JSAtom *atom;
207 bool hasTypeCheck;
208 ValueRemat vr;
209 # if defined JS_CPU_X64
210 ic::PICLabels labels;
211 # endif
213 void copySimpleMembersTo(ic::PICInfo &ic) const {
214 ic.kind = kind;
215 ic.shapeReg = shapeReg;
216 ic.objReg = objReg;
217 ic.atom = atom;
218 ic.usePropCache = usePropCache;
219 if (ic.isSet()) {
220 ic.u.vr = vr;
221 } else if (ic.isGet()) {
222 ic.u.get.typeReg = typeReg;
223 ic.u.get.hasTypeCheck = hasTypeCheck;
229 struct Defs {
230 Defs(uint32 ndefs)
231 : ndefs(ndefs)
233 uint32 ndefs;
236 struct InternalCallSite {
237 bool stub;
238 Label location;
239 jsbytecode *pc;
240 uint32 id;
243 struct DoublePatch {
244 double d;
245 DataLabelPtr label;
246 bool ool;
249 JSStackFrame *fp;
250 JSScript *script;
251 JSObject *scopeChain;
252 JSObject *globalObj;
253 JSFunction *fun;
254 bool isConstructing;
255 analyze::Script *analysis;
256 Label *jumpMap;
257 jsbytecode *PC;
258 Assembler masm;
259 FrameState frame;
260 js::Vector<BranchPatch, 64> branchPatches;
261 #if defined JS_MONOIC
262 js::Vector<MICGenInfo, 64> mics;
263 js::Vector<CallGenInfo, 64> callICs;
264 js::Vector<EqualityGenInfo, 64> equalityICs;
265 js::Vector<TraceGenInfo, 64> traceICs;
266 #endif
267 #if defined JS_POLYIC
268 js::Vector<PICGenInfo, 16> pics;
269 js::Vector<GetElementICInfo> getElemICs;
270 #endif
271 js::Vector<CallPatchInfo, 64> callPatches;
272 js::Vector<InternalCallSite, 64> callSites;
273 js::Vector<DoublePatch, 16> doubleList;
274 StubCompiler stubcc;
275 Label invokeLabel;
276 Label arityLabel;
277 bool debugMode;
278 bool addTraceHints;
280 public:
281 // Special atom index used to indicate that the atom is 'length'. This
282 // follows interpreter usage in JSOP_LENGTH.
283 enum { LengthAtomIndex = uint32(-2) };
285 Compiler(JSContext *cx, JSStackFrame *fp);
286 ~Compiler();
288 CompileStatus compile();
290 jsbytecode *getPC() { return PC; }
291 Label getLabel() { return masm.label(); }
292 bool knownJump(jsbytecode *pc);
293 Label labelOf(jsbytecode *target);
294 void *findCallSite(const CallSite &callSite);
296 private:
297 CompileStatus performCompilation(JITScript **jitp);
298 CompileStatus generatePrologue();
299 CompileStatus generateMethod();
300 CompileStatus generateEpilogue();
301 CompileStatus finishThisUp(JITScript **jitp);
303 /* Non-emitting helpers. */
304 uint32 fullAtomIndex(jsbytecode *pc);
305 void jumpInScript(Jump j, jsbytecode *pc);
306 bool compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs);
307 void addCallSite(uint32 id, bool stub);
309 /* Emitting helpers. */
310 void restoreFrameRegs(Assembler &masm);
311 void emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused);
312 void iter(uintN flags);
313 void iterNext();
314 void iterMore();
315 void iterEnd();
316 MaybeJump loadDouble(FrameEntry *fe, FPRegisterID fpReg);
317 #ifdef JS_POLYIC
318 void passICAddress(BaseICInfo *ic);
319 #endif
320 #ifdef JS_MONOIC
321 void passMICAddress(MICGenInfo &mic);
322 #endif
323 bool constructThis();
325 /* Opcode handlers. */
326 void jumpAndTrace(Jump j, jsbytecode *target, Jump *slow = NULL);
327 void jsop_bindname(uint32 index, bool usePropCache);
328 void jsop_setglobal(uint32 index);
329 void jsop_getglobal(uint32 index);
330 void jsop_getprop_slow(JSAtom *atom, bool usePropCache = true);
331 void jsop_getarg(uint32 slot);
332 void jsop_setarg(uint32 slot, bool popped);
333 void jsop_this();
334 void emitReturn(FrameEntry *fe);
335 void emitFinalReturn(Assembler &masm);
336 void loadReturnValue(Assembler *masm, FrameEntry *fe);
337 void emitReturnValue(Assembler *masm, FrameEntry *fe);
338 void dispatchCall(VoidPtrStubUInt32 stub, uint32 argc);
339 void interruptCheckHelper();
340 void emitUncachedCall(uint32 argc, bool callingNew);
341 void inlineCallHelper(uint32 argc, bool callingNew);
342 void fixPrimitiveReturn(Assembler *masm, FrameEntry *fe);
343 void jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index);
344 bool jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index);
345 bool jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index);
346 void jsop_eleminc(JSOp op, VoidStub);
347 void jsop_getgname(uint32 index);
348 void jsop_getgname_slow(uint32 index);
349 void jsop_setgname(uint32 index);
350 void jsop_setgname_slow(uint32 index);
351 void jsop_bindgname();
352 void jsop_setelem_slow();
353 void jsop_getelem_slow();
354 void jsop_unbrand();
355 bool jsop_getprop(JSAtom *atom, bool typeCheck = true, bool usePropCache = true);
356 bool jsop_length();
357 bool jsop_setprop(JSAtom *atom, bool usePropCache = true);
358 void jsop_setprop_slow(JSAtom *atom, bool usePropCache = true);
359 bool jsop_callprop_slow(JSAtom *atom);
360 bool jsop_callprop(JSAtom *atom);
361 bool jsop_callprop_obj(JSAtom *atom);
362 bool jsop_callprop_str(JSAtom *atom);
363 bool jsop_callprop_generic(JSAtom *atom);
364 bool jsop_instanceof();
365 void jsop_name(JSAtom *atom);
366 bool jsop_xname(JSAtom *atom);
367 void enterBlock(JSObject *obj);
368 void leaveBlock();
369 void jsop_eval();
371 /* Fast arithmetic. */
372 void jsop_binary(JSOp op, VoidStub stub);
373 void jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub);
374 void jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub);
375 void jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub);
376 void slowLoadConstantDouble(Assembler &masm, FrameEntry *fe,
377 FPRegisterID fpreg);
378 void maybeJumpIfNotInt32(Assembler &masm, MaybeJump &mj, FrameEntry *fe,
379 MaybeRegisterID &mreg);
380 void maybeJumpIfNotDouble(Assembler &masm, MaybeJump &mj, FrameEntry *fe,
381 MaybeRegisterID &mreg);
382 void jsop_relational(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
383 void jsop_relational_self(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
384 void jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
385 void jsop_relational_double(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
387 void emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
388 MaybeJump &lhsNotDouble, MaybeJump &rhsNotNumber,
389 MaybeJump &lhsUnknownDone);
390 void emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
391 MaybeJump &rhsNotNumber2);
392 bool tryBinaryConstantFold(JSContext *cx, FrameState &frame, JSOp op,
393 FrameEntry *lhs, FrameEntry *rhs);
395 /* Fast opcodes. */
396 void jsop_bitop(JSOp op);
397 void jsop_rsh();
398 RegisterID rightRegForShift(FrameEntry *rhs);
399 void jsop_rsh_int_int(FrameEntry *lhs, FrameEntry *rhs);
400 void jsop_rsh_const_int(FrameEntry *lhs, FrameEntry *rhs);
401 void jsop_rsh_int_const(FrameEntry *lhs, FrameEntry *rhs);
402 void jsop_rsh_int_unknown(FrameEntry *lhs, FrameEntry *rhs);
403 void jsop_rsh_const_const(FrameEntry *lhs, FrameEntry *rhs);
404 void jsop_rsh_const_unknown(FrameEntry *lhs, FrameEntry *rhs);
405 void jsop_rsh_unknown_const(FrameEntry *lhs, FrameEntry *rhs);
406 void jsop_rsh_unknown_any(FrameEntry *lhs, FrameEntry *rhs);
407 void jsop_globalinc(JSOp op, uint32 index);
408 void jsop_mod();
409 void jsop_neg();
410 void jsop_bitnot();
411 void jsop_not();
412 void jsop_typeof();
413 void booleanJumpScript(JSOp op, jsbytecode *target);
414 void jsop_ifneq(JSOp op, jsbytecode *target);
415 void jsop_andor(JSOp op, jsbytecode *target);
416 void jsop_arginc(JSOp op, uint32 slot, bool popped);
417 void jsop_localinc(JSOp op, uint32 slot, bool popped);
418 void jsop_setelem();
419 bool jsop_getelem();
420 void jsop_stricteq(JSOp op);
421 void jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
422 void jsop_equality_int_string(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
423 void jsop_pos();
425 #define STUB_CALL_TYPE(type) \
426 Call stubCall(type stub) { \
427 return stubCall(JS_FUNC_TO_DATA_PTR(void *, stub)); \
430 STUB_CALL_TYPE(JSObjStub);
431 STUB_CALL_TYPE(VoidStubUInt32);
432 STUB_CALL_TYPE(VoidStub);
433 STUB_CALL_TYPE(VoidPtrStubUInt32);
434 STUB_CALL_TYPE(VoidPtrStub);
435 STUB_CALL_TYPE(BoolStub);
436 STUB_CALL_TYPE(JSObjStubUInt32);
437 STUB_CALL_TYPE(JSObjStubFun);
438 STUB_CALL_TYPE(JSObjStubJSObj);
439 STUB_CALL_TYPE(VoidStubAtom);
440 STUB_CALL_TYPE(JSStrStub);
441 STUB_CALL_TYPE(JSStrStubUInt32);
442 STUB_CALL_TYPE(VoidStubJSObj);
443 STUB_CALL_TYPE(VoidPtrStubPC);
444 STUB_CALL_TYPE(VoidVpStub);
445 STUB_CALL_TYPE(VoidStubPC);
446 STUB_CALL_TYPE(BoolStubUInt32);
447 STUB_CALL_TYPE(VoidStubFun);
449 #undef STUB_CALL_TYPE
450 void prepareStubCall(Uses uses);
451 Call stubCall(void *ptr);
454 } /* namespace js */
455 } /* namespace mjit */
457 #endif