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
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
21 * Brendan Eich <brendan@mozilla.org>
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"
46 #include "MethodJIT.h"
47 #include "CodeGenIncludes.h"
48 #include "BaseCompiler.h"
49 #include "StubCompiler.h"
56 class Compiler
: public BaseCompiler
58 friend class StubCompiler
;
61 BranchPatch(const Jump
&j
, jsbytecode
*pc
)
70 struct GlobalNameICInfo
{
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
{
93 struct SetGlobalNameICInfo
: public GlobalNameICInfo
{
104 struct EqualityGenInfo
{
105 DataLabelPtr addrLabel
;
109 MaybeJump jumpToStub
;
111 jsbytecode
*jumpTarget
;
113 Assembler::Condition cond
;
114 JSC::MacroAssembler::RegisterID tempReg
;
117 struct TraceGenInfo
{
120 DataLabelPtr addrLabel
;
121 jsbytecode
*jumpTarget
;
123 MaybeJump slowTraceHint
;
125 TraceGenInfo() : initialized(false) {}
128 /* InlineFrameAssembler wants to see this. */
131 CallGenInfo(jsbytecode
*pc
) : pc(pc
) {}
134 * These members map to members in CallICInfo. See that structure for
138 DataLabelPtr funGuard
;
146 DataLabelPtr addrLabel1
;
147 DataLabelPtr addrLabel2
;
150 RegisterID funObjReg
;
151 RegisterID funPtrReg
;
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) {}
165 DataLabelPtr fastNcodePatch
;
166 DataLabelPtr slowNcodePatch
;
172 BaseICInfo(JSOp op
) : op(op
)
175 Label fastPathRejoin
;
178 DataLabelPtr paramAddr
;
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
);
187 JS_ASSERT(to
.op
== op
);
191 struct GetElementICInfo
: public BaseICInfo
{
192 GetElementICInfo(JSOp op
) : BaseICInfo(op
)
201 struct SetElementICInfo
: public BaseICInfo
{
202 SetElementICInfo(JSOp op
) : BaseICInfo(op
)
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
;
229 #ifdef JS_HAS_IC_LABELS
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_
;
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_
;
272 void copySimpleMembersTo(ic::PICInfo
&ic
) {
274 ic
.shapeReg
= shapeReg
;
277 ic
.usePropCache
= usePropCache
;
280 } else if (ic
.isGet()) {
281 ic
.u
.get
.typeReg
= typeReg
;
282 ic
.u
.get
.hasTypeCheck
= hasTypeCheck
;
284 #ifdef JS_HAS_IC_LABELS
286 ic
.setLabels(getPropLabels());
288 ic
.setLabels(setPropLabels());
289 else if (ic
.isBind())
290 ic
.setLabels(bindNameLabels());
291 else if (ic
.isScopeName())
292 ic
.setLabels(scopeNameLabels());
305 struct InternalCallSite
{
312 InternalCallSite(uint32 returnOffset
, jsbytecode
*pc
, uint32 id
,
314 : returnOffset(returnOffset
), pc(pc
), id(id
), call(call
), ool(ool
)
331 JSObject
*scopeChain
;
335 analyze::Script
*analysis
;
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
;
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
;
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
;
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
;
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
);
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_
; }
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
);
411 MaybeJump
loadDouble(FrameEntry
*fe
, FPRegisterID fpReg
);
413 void passICAddress(BaseICInfo
*ic
);
416 void passMICAddress(GlobalNameICInfo
&mic
);
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
);
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();
456 bool jsop_getprop(JSAtom
*atom
, bool typeCheck
= true, bool usePropCache
= true);
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
);
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
,
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
®s
,
494 MaybeJump
&lhsNotDouble
, MaybeJump
&rhsNotNumber
,
495 MaybeJump
&lhsUnknownDone
);
496 void emitRightDoublePath(FrameEntry
*lhs
, FrameEntry
*rhs
, FrameState::BinaryAlloc
®s
,
497 MaybeJump
&rhsNotNumber2
);
498 bool tryBinaryConstantFold(JSContext
*cx
, FrameState
&frame
, JSOp op
,
499 FrameEntry
*lhs
, FrameEntry
*rhs
);
502 void jsop_bitop(JSOp op
);
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
);
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
);
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
);
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) \
544 Call cl = emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub))); \
546 InternalCallSite site(masm.callReturnOffset(cl), PC, __LINE__, \
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__) \
563 } /* namespace mjit */