1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=4 sw=4 et tw=99:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
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/
11 : *
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.
16 : *
17 : * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18 : * May 28, 2008.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Brendan Eich <brendan@mozilla.org>
22 : *
23 : * Contributor(s):
24 : * David Anderson <danderson@mozilla.com>
25 : * David Mandelin <dmandelin@mozilla.com>
26 : *
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.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 : #if !defined jsjaeger_compiler_h__ && defined JS_METHODJIT
41 : #define jsjaeger_compiler_h__
42 :
43 : #include "jsanalyze.h"
44 : #include "jscntxt.h"
45 : #include "MethodJIT.h"
46 : #include "CodeGenIncludes.h"
47 : #include "BaseCompiler.h"
48 : #include "StubCompiler.h"
49 : #include "MonoIC.h"
50 : #include "PolyIC.h"
51 :
52 : namespace js {
53 : namespace mjit {
54 :
55 : /*
56 : * Patch for storing call site and rejoin site return addresses at, for
57 : * redirecting the return address in InvariantFailure.
58 : */
59 : struct InvariantCodePatch {
60 : bool hasPatch;
61 : JSC::MacroAssembler::DataLabelPtr codePatch;
62 5053912 : InvariantCodePatch() : hasPatch(false) {}
63 : };
64 :
65 : struct JSActiveFrame {
66 : JSActiveFrame *parent;
67 : jsbytecode *parentPC;
68 : JSScript *script;
69 :
70 : /*
71 : * Index into inlineFrames or OUTER_FRAME, matches this frame's index in
72 : * the cross script SSA.
73 : */
74 : uint32_t inlineIndex;
75 :
76 : /* JIT code generation tracking state */
77 : size_t mainCodeStart;
78 : size_t stubCodeStart;
79 : size_t mainCodeEnd;
80 : size_t stubCodeEnd;
81 : size_t inlinePCOffset;
82 :
83 : JSActiveFrame();
84 : };
85 :
86 : class Compiler : public BaseCompiler
87 : {
88 : friend class StubCompiler;
89 :
90 239807 : struct BranchPatch {
91 198463 : BranchPatch(const Jump &j, jsbytecode *pc, uint32_t inlineIndex)
92 198463 : : jump(j), pc(pc), inlineIndex(inlineIndex)
93 198463 : { }
94 :
95 : Jump jump;
96 : jsbytecode *pc;
97 : uint32_t inlineIndex;
98 : };
99 :
100 : #if defined JS_MONOIC
101 408882 : struct GlobalNameICInfo {
102 : Label fastPathStart;
103 : Call slowPathCall;
104 : DataLabelPtr shape;
105 : DataLabelPtr addrLabel;
106 :
107 408880 : void copyTo(ic::GlobalNameIC &to, JSC::LinkBuffer &full, JSC::LinkBuffer &stub) {
108 408880 : to.fastPathStart = full.locationOf(fastPathStart);
109 :
110 408880 : int offset = full.locationOf(shape) - to.fastPathStart;
111 408880 : to.shapeOffset = offset;
112 408880 : JS_ASSERT(to.shapeOffset == offset);
113 :
114 408880 : to.slowPathCall = stub.locationOf(slowPathCall);
115 408880 : }
116 : };
117 :
118 1374318 : struct GetGlobalNameICInfo : public GlobalNameICInfo {
119 : Label load;
120 : };
121 :
122 63572 : struct SetGlobalNameICInfo : public GlobalNameICInfo {
123 : Label slowPathStart;
124 : Label fastPathRejoin;
125 : DataLabel32 store;
126 : Jump shapeGuardJump;
127 : ValueRemat vr;
128 : RegisterID objReg;
129 : RegisterID shapeReg;
130 : bool objConst;
131 : };
132 :
133 25913 : struct EqualityGenInfo {
134 : DataLabelPtr addrLabel;
135 : Label stubEntry;
136 : Call stubCall;
137 : BoolStub stub;
138 : MaybeJump jumpToStub;
139 : Label fallThrough;
140 : jsbytecode *jumpTarget;
141 : bool trampoline;
142 : Label trampolineStart;
143 : ValueRemat lvr, rvr;
144 : Assembler::Condition cond;
145 : JSC::MacroAssembler::RegisterID tempReg;
146 : };
147 :
148 : /* InlineFrameAssembler wants to see this. */
149 : public:
150 356950 : struct CallGenInfo {
151 : /*
152 : * These members map to members in CallICInfo. See that structure for
153 : * more comments.
154 : */
155 : uint32_t callIndex;
156 : DataLabelPtr funGuard;
157 : Jump funJump;
158 : Jump hotJump;
159 : Call oolCall;
160 : Label joinPoint;
161 : Label slowJoinPoint;
162 : Label slowPathStart;
163 : Label hotPathLabel;
164 : DataLabelPtr addrLabel1;
165 : DataLabelPtr addrLabel2;
166 : Jump oolJump;
167 : Label icCall;
168 : RegisterID funObjReg;
169 : FrameSize frameSize;
170 : bool typeMonitored;
171 : };
172 :
173 : private:
174 : #endif
175 :
176 : /*
177 : * Writes of call return addresses which needs to be delayed until the final
178 : * absolute address of the join point is known.
179 : */
180 308568 : struct CallPatchInfo {
181 438549 : CallPatchInfo() : hasFastNcode(false), hasSlowNcode(false), joinSlow(false) {}
182 : Label joinPoint;
183 : DataLabelPtr fastNcodePatch;
184 : DataLabelPtr slowNcodePatch;
185 : bool hasFastNcode;
186 : bool hasSlowNcode;
187 : bool joinSlow;
188 : };
189 :
190 : struct BaseICInfo {
191 850622 : BaseICInfo(JSOp op) : op(op), canCallHook(false), forcedTypeBarrier(false)
192 850622 : { }
193 : Label fastPathStart;
194 : Label fastPathRejoin;
195 : Label slowPathStart;
196 : Call slowPathCall;
197 : DataLabelPtr paramAddr;
198 : JSOp op;
199 : bool canCallHook;
200 : bool forcedTypeBarrier;
201 :
202 850596 : void copyTo(ic::BaseIC &to, JSC::LinkBuffer &full, JSC::LinkBuffer &stub) {
203 850596 : to.fastPathStart = full.locationOf(fastPathStart);
204 850596 : to.fastPathRejoin = full.locationOf(fastPathRejoin);
205 850596 : to.slowPathStart = stub.locationOf(slowPathStart);
206 850596 : to.slowPathCall = stub.locationOf(slowPathCall);
207 850596 : to.canCallHook = canCallHook;
208 850596 : to.forcedTypeBarrier = forcedTypeBarrier;
209 850596 : to.op = op;
210 850596 : JS_ASSERT(to.op == op);
211 850596 : }
212 : };
213 :
214 24345 : struct GetElementICInfo : public BaseICInfo {
215 21695 : GetElementICInfo(JSOp op) : BaseICInfo(op)
216 21695 : { }
217 : RegisterID typeReg;
218 : RegisterID objReg;
219 : ValueRemat id;
220 : MaybeJump typeGuard;
221 : Jump shapeGuard;
222 : };
223 :
224 6244 : struct SetElementICInfo : public BaseICInfo {
225 5692 : SetElementICInfo(JSOp op) : BaseICInfo(op)
226 5692 : { }
227 : RegisterID objReg;
228 : StateRemat objRemat;
229 : ValueRemat vr;
230 : Jump capacityGuard;
231 : Jump shapeGuard;
232 : Jump holeGuard;
233 : Int32Key key;
234 : uint32_t volatileMask;
235 : };
236 :
237 1671743 : struct PICGenInfo : public BaseICInfo {
238 823235 : PICGenInfo(ic::PICInfo::Kind kind, JSOp op)
239 823235 : : BaseICInfo(op), kind(kind), typeMonitored(false)
240 823235 : { }
241 : ic::PICInfo::Kind kind;
242 : Label typeCheck;
243 : RegisterID shapeReg;
244 : RegisterID objReg;
245 : RegisterID typeReg;
246 : Label shapeGuard;
247 : jsbytecode *pc;
248 : PropertyName *name;
249 : bool hasTypeCheck;
250 : bool typeMonitored;
251 : types::TypeSet *rhsTypes;
252 : ValueRemat vr;
253 : union {
254 : ic::GetPropLabels getPropLabels_;
255 : ic::SetPropLabels setPropLabels_;
256 : ic::BindNameLabels bindNameLabels_;
257 : ic::ScopeNameLabels scopeNameLabels_;
258 : };
259 :
260 887238 : ic::GetPropLabels &getPropLabels() {
261 887238 : JS_ASSERT(kind == ic::PICInfo::GET);
262 887238 : return getPropLabels_;
263 : }
264 66156 : ic::SetPropLabels &setPropLabels() {
265 66156 : JS_ASSERT(kind == ic::PICInfo::SET || kind == ic::PICInfo::SETMETHOD);
266 66156 : return setPropLabels_;
267 : }
268 14222 : ic::BindNameLabels &bindNameLabels() {
269 14222 : JS_ASSERT(kind == ic::PICInfo::BIND);
270 14222 : return bindNameLabels_;
271 : }
272 678828 : ic::ScopeNameLabels &scopeNameLabels() {
273 0 : JS_ASSERT(kind == ic::PICInfo::NAME ||
274 678828 : kind == ic::PICInfo::XNAME);
275 678828 : return scopeNameLabels_;
276 : }
277 :
278 823209 : void copySimpleMembersTo(ic::PICInfo &ic) {
279 823209 : ic.kind = kind;
280 823209 : ic.shapeReg = shapeReg;
281 823209 : ic.objReg = objReg;
282 823209 : ic.name = name;
283 823209 : if (ic.isSet()) {
284 33078 : ic.u.vr = vr;
285 790131 : } else if (ic.isGet()) {
286 443609 : ic.u.get.typeReg = typeReg;
287 443609 : ic.u.get.hasTypeCheck = hasTypeCheck;
288 : }
289 823209 : ic.typeMonitored = typeMonitored;
290 823209 : ic.rhsTypes = rhsTypes;
291 823209 : if (ic.isGet())
292 443609 : ic.setLabels(getPropLabels());
293 379600 : else if (ic.isSet())
294 33078 : ic.setLabels(setPropLabels());
295 346522 : else if (ic.isBind())
296 7111 : ic.setLabels(bindNameLabels());
297 339411 : else if (ic.isScopeName())
298 339411 : ic.setLabels(scopeNameLabels());
299 823209 : }
300 :
301 : };
302 :
303 : struct Defs {
304 : Defs(uint32_t ndefs)
305 : : ndefs(ndefs)
306 : { }
307 : uint32_t ndefs;
308 : };
309 :
310 11200524 : struct InternalCallSite {
311 : uint32_t returnOffset;
312 : DataLabelPtr inlinePatch;
313 : uint32_t inlineIndex;
314 : jsbytecode *inlinepc;
315 : RejoinState rejoin;
316 : bool ool;
317 : Label loopJumpLabel;
318 : InvariantCodePatch loopPatch;
319 :
320 5053912 : InternalCallSite(uint32_t returnOffset,
321 : uint32_t inlineIndex, jsbytecode *inlinepc,
322 : RejoinState rejoin, bool ool)
323 : : returnOffset(returnOffset),
324 : inlineIndex(inlineIndex), inlinepc(inlinepc),
325 5053912 : rejoin(rejoin), ool(ool)
326 5053912 : { }
327 : };
328 :
329 0 : struct DoublePatch {
330 : double d;
331 : DataLabelPtr label;
332 : bool ool;
333 : };
334 :
335 548 : struct JumpTable {
336 : DataLabelPtr label;
337 : size_t offsetIndex;
338 : };
339 :
340 2087 : struct JumpTableEdge {
341 : uint32_t source;
342 : uint32_t target;
343 : };
344 :
345 10 : struct ChunkJumpTableEdge {
346 : JumpTableEdge edge;
347 : void **jumpTableEntry;
348 : };
349 :
350 69024 : struct LoopEntry {
351 : uint32_t pcOffset;
352 : Label label;
353 : };
354 :
355 : /*
356 : * Information about the current type of an argument or local in the
357 : * script. The known type tag of these types is cached when possible to
358 : * avoid generating duplicate dependency constraints.
359 : */
360 : class VarType {
361 : JSValueType type;
362 : types::TypeSet *types;
363 :
364 : public:
365 376194 : void setTypes(types::TypeSet *types) {
366 376194 : this->types = types;
367 376194 : this->type = JSVAL_TYPE_MISSING;
368 376194 : }
369 :
370 : types::TypeSet *getTypes() { return types; }
371 :
372 647477 : JSValueType getTypeTag(JSContext *cx) {
373 647477 : if (type == JSVAL_TYPE_MISSING)
374 214072 : type = types ? types->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN;
375 647477 : return type;
376 : }
377 : };
378 :
379 3596 : struct OutgoingChunkEdge {
380 : uint32_t source;
381 : uint32_t target;
382 :
383 : #ifdef JS_CPU_X64
384 : Label sourceTrampoline;
385 : #endif
386 :
387 : Jump fastJump;
388 : MaybeJump slowJump;
389 : };
390 :
391 : struct SlotType
392 : {
393 : uint32_t slot;
394 : VarType vt;
395 : SlotType(uint32_t slot, VarType vt) : slot(slot), vt(vt) {}
396 : };
397 :
398 : JSScript *outerScript;
399 : unsigned chunkIndex;
400 : bool isConstructing;
401 : ChunkDescriptor outerChunk;
402 :
403 : /* SSA information for the outer script and all frames we will be inlining. */
404 : analyze::CrossScriptSSA ssa;
405 :
406 : GlobalObject *globalObj;
407 : const HeapSlot *globalSlots; /* Original slots pointer. */
408 :
409 : Assembler masm;
410 : FrameState frame;
411 :
412 : /*
413 : * State for the current stack frame, and links to its parents going up to
414 : * the outermost script.
415 : */
416 :
417 : public:
418 : struct ActiveFrame : public JSActiveFrame {
419 : Label *jumpMap;
420 :
421 : /* Current types for non-escaping vars in the script. */
422 : VarType *varTypes;
423 :
424 : /* State for managing return from inlined frames. */
425 : bool needReturnValue; /* Return value will be used. */
426 : bool syncReturnValue; /* Return value should be fully synced. */
427 : bool returnValueDouble; /* Return value should be a double. */
428 : bool returnSet; /* Whether returnRegister is valid. */
429 : AnyRegisterID returnRegister; /* Register holding return value. */
430 : const FrameEntry *returnEntry; /* Entry copied by return value. */
431 : Vector<Jump, 4, CompilerAllocPolicy> *returnJumps;
432 :
433 : /*
434 : * Snapshot of the heap state to use after the call, in case
435 : * there are multiple return paths the inlined frame could take.
436 : */
437 : RegisterAllocation *exitState;
438 :
439 : ActiveFrame(JSContext *cx);
440 : ~ActiveFrame();
441 : };
442 :
443 : private:
444 : ActiveFrame *a;
445 : ActiveFrame *outer;
446 :
447 : JSScript *script;
448 : analyze::ScriptAnalysis *analysis;
449 : jsbytecode *PC;
450 :
451 : LoopState *loop;
452 :
453 : /* State spanning all stack frames. */
454 :
455 : js::Vector<ActiveFrame*, 4, CompilerAllocPolicy> inlineFrames;
456 : js::Vector<BranchPatch, 64, CompilerAllocPolicy> branchPatches;
457 : #if defined JS_MONOIC
458 : js::Vector<GetGlobalNameICInfo, 16, CompilerAllocPolicy> getGlobalNames;
459 : js::Vector<SetGlobalNameICInfo, 16, CompilerAllocPolicy> setGlobalNames;
460 : js::Vector<CallGenInfo, 64, CompilerAllocPolicy> callICs;
461 : js::Vector<EqualityGenInfo, 64, CompilerAllocPolicy> equalityICs;
462 : #endif
463 : #if defined JS_POLYIC
464 : js::Vector<PICGenInfo, 16, CompilerAllocPolicy> pics;
465 : js::Vector<GetElementICInfo, 16, CompilerAllocPolicy> getElemICs;
466 : js::Vector<SetElementICInfo, 16, CompilerAllocPolicy> setElemICs;
467 : #endif
468 : js::Vector<CallPatchInfo, 64, CompilerAllocPolicy> callPatches;
469 : js::Vector<InternalCallSite, 64, CompilerAllocPolicy> callSites;
470 : js::Vector<DoublePatch, 16, CompilerAllocPolicy> doubleList;
471 : js::Vector<uint32_t> fixedIntToDoubleEntries;
472 : js::Vector<uint32_t> fixedDoubleToAnyEntries;
473 : js::Vector<JumpTable, 16> jumpTables;
474 : js::Vector<JumpTableEdge, 16> jumpTableEdges;
475 : js::Vector<LoopEntry, 16> loopEntries;
476 : js::Vector<OutgoingChunkEdge, 16> chunkEdges;
477 : StubCompiler stubcc;
478 : Label invokeLabel;
479 : Label arityLabel;
480 : Label argsCheckLabel;
481 : #ifdef JS_MONOIC
482 : Label argsCheckStub;
483 : Label argsCheckFallthrough;
484 : Jump argsCheckJump;
485 : #endif
486 : bool debugMode_;
487 : bool inlining_;
488 : bool hasGlobalReallocation;
489 : bool oomInVector; // True if we have OOM'd appending to a vector.
490 : bool overflowICSpace; // True if we added a constant pool in a reserved space.
491 : uint64_t gcNumber;
492 : enum { NoApplyTricks, LazyArgsObj } applyTricks;
493 : PCLengthEntry *pcLengths;
494 :
495 2681820 : Compiler *thisFromCtor() { return this; }
496 :
497 : friend class CompilerAllocPolicy;
498 : public:
499 : Compiler(JSContext *cx, JSScript *outerScript, unsigned chunkIndex, bool isConstructing);
500 : ~Compiler();
501 :
502 : CompileStatus compile();
503 :
504 3581621 : Label getLabel() { return masm.label(); }
505 : bool knownJump(jsbytecode *pc);
506 : Label labelOf(jsbytecode *target, uint32_t inlineIndex);
507 : void addCallSite(const InternalCallSite &callSite);
508 : void addReturnSite();
509 : void inlineStubCall(void *stub, RejoinState rejoin, Uses uses);
510 :
511 1085104 : bool debugMode() { return debugMode_; }
512 835365 : bool inlining() { return inlining_; }
513 4933 : bool constructing() { return isConstructing; }
514 :
515 4762722 : jsbytecode *outerPC() {
516 4762722 : if (a == outer)
517 4735629 : return PC;
518 27093 : ActiveFrame *scan = a;
519 68096 : while (scan && scan->parent != outer)
520 13910 : scan = static_cast<ActiveFrame *>(scan->parent);
521 27093 : return scan->parentPC;
522 : }
523 :
524 1301921 : JITScript *outerJIT() {
525 1301921 : return outerScript->getJIT(isConstructing);
526 : }
527 :
528 520572 : ChunkDescriptor &outerChunkRef() {
529 520572 : return outerJIT()->chunkDescriptor(chunkIndex);
530 : }
531 :
532 579577 : bool bytecodeInChunk(jsbytecode *pc) {
533 : return (unsigned(pc - outerScript->code) >= outerChunk.begin)
534 579577 : && (unsigned(pc - outerScript->code) < outerChunk.end);
535 : }
536 :
537 3666774 : jsbytecode *inlinePC() { return PC; }
538 3870802 : uint32_t inlineIndex() { return a->inlineIndex; }
539 :
540 31291 : Assembler &getAssembler(bool ool) { return ool ? stubcc.masm : masm; }
541 :
542 8231 : InvariantCodePatch *getInvariantPatch(unsigned index) {
543 8231 : return &callSites[index].loopPatch;
544 : }
545 8588 : jsbytecode *getInvariantPC(unsigned index) {
546 8588 : return callSites[index].inlinepc;
547 : }
548 :
549 16523 : bool activeFrameHasMultipleExits() {
550 16523 : ActiveFrame *na = a;
551 33225 : while (na->parent) {
552 200 : if (na->exitState)
553 21 : return true;
554 179 : na = static_cast<ActiveFrame *>(na->parent);
555 : }
556 16502 : return false;
557 : }
558 :
559 : private:
560 : CompileStatus performCompilation();
561 : CompileStatus generatePrologue();
562 : CompileStatus generateMethod();
563 : CompileStatus generateEpilogue();
564 : CompileStatus finishThisUp();
565 : CompileStatus pushActiveFrame(JSScript *script, uint32_t argc);
566 : void popActiveFrame();
567 : void updatePCCounters(jsbytecode *pc, Label *start, bool *updated);
568 : void updatePCTypes(jsbytecode *pc, FrameEntry *fe);
569 : void updateArithCounters(jsbytecode *pc, FrameEntry *fe,
570 : JSValueType firstUseType, JSValueType secondUseType);
571 : void updateElemCounters(jsbytecode *pc, FrameEntry *obj, FrameEntry *id);
572 : void bumpPropCounter(jsbytecode *pc, int counter);
573 :
574 : /* Analysis helpers. */
575 : CompileStatus prepareInferenceTypes(JSScript *script, ActiveFrame *a);
576 : void ensureDoubleArguments();
577 : void markUndefinedLocal(uint32_t offset, uint32_t i);
578 : void markUndefinedLocals();
579 : void fixDoubleTypes(jsbytecode *target);
580 : void watchGlobalReallocation();
581 : void updateVarType();
582 : void updateJoinVarTypes();
583 : void restoreVarType();
584 : JSValueType knownPushedType(uint32_t pushed);
585 : bool mayPushUndefined(uint32_t pushed);
586 : types::TypeSet *pushedTypeSet(uint32_t which);
587 : bool monitored(jsbytecode *pc);
588 : bool hasTypeBarriers(jsbytecode *pc);
589 : bool testSingletonProperty(JSObject *obj, jsid id);
590 : bool testSingletonPropertyTypes(FrameEntry *top, jsid id, bool *testObject);
591 : CompileStatus addInlineFrame(JSScript *script, uint32_t depth, uint32_t parent, jsbytecode *parentpc);
592 : CompileStatus scanInlineCalls(uint32_t index, uint32_t depth);
593 : CompileStatus checkAnalysis(JSScript *script);
594 :
595 1640188 : struct BarrierState {
596 : MaybeJump jump;
597 : RegisterID typeReg;
598 : RegisterID dataReg;
599 : };
600 :
601 : MaybeJump trySingleTypeTest(types::TypeSet *types, RegisterID typeReg);
602 : Jump addTypeTest(types::TypeSet *types, RegisterID typeReg, RegisterID dataReg);
603 : BarrierState pushAddressMaybeBarrier(Address address, JSValueType type, bool reuseBase,
604 : bool testUndefined = false);
605 : BarrierState testBarrier(RegisterID typeReg, RegisterID dataReg,
606 : bool testUndefined = false, bool testReturn = false,
607 : bool force = false);
608 : void finishBarrier(const BarrierState &barrier, RejoinState rejoin, uint32_t which);
609 :
610 : void testPushedType(RejoinState rejoin, int which, bool ool = true);
611 :
612 : /* Non-emitting helpers. */
613 : void pushSyncedEntry(uint32_t pushed);
614 : bool jumpInScript(Jump j, jsbytecode *pc);
615 : bool compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs);
616 : bool canUseApplyTricks();
617 :
618 : /* Emitting helpers. */
619 : bool constantFoldBranch(jsbytecode *target, bool taken);
620 : bool emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused);
621 : bool iter(unsigned flags);
622 : void iterNext(ptrdiff_t offset);
623 : bool iterMore(jsbytecode *target);
624 : void iterEnd();
625 : MaybeJump loadDouble(FrameEntry *fe, FPRegisterID *fpReg, bool *allocated);
626 : #ifdef JS_POLYIC
627 : void passICAddress(BaseICInfo *ic);
628 : #endif
629 : #ifdef JS_MONOIC
630 : void passMICAddress(GlobalNameICInfo &mic);
631 : #endif
632 : bool constructThis();
633 : void ensureDouble(FrameEntry *fe);
634 :
635 : /*
636 : * Ensure fe is an integer, truncating from double if necessary, or jump to
637 : * the slow path per uses.
638 : */
639 : void ensureInteger(FrameEntry *fe, Uses uses);
640 :
641 : /* Convert fe from a double to integer (per ValueToECMAInt32) in place. */
642 : void truncateDoubleToInt32(FrameEntry *fe, Uses uses);
643 :
644 : /*
645 : * Try to convert a double fe to an integer, with no truncation performed,
646 : * or jump to the slow path per uses.
647 : */
648 : void tryConvertInteger(FrameEntry *fe, Uses uses);
649 :
650 : /* Opcode handlers. */
651 : bool jumpAndRun(Jump j, jsbytecode *target,
652 : Jump *slow = NULL, bool *trampoline = NULL,
653 : bool fallthrough = false);
654 : bool startLoop(jsbytecode *head, Jump entry, jsbytecode *entryTarget);
655 : bool finishLoop(jsbytecode *head);
656 : inline bool shouldStartLoop(jsbytecode *head);
657 : void jsop_bindname(PropertyName *name);
658 : void jsop_setglobal(uint32_t index);
659 : void jsop_getprop_slow(PropertyName *name, bool forPrototype = false);
660 : void jsop_getarg(uint32_t slot);
661 : void jsop_setarg(uint32_t slot, bool popped);
662 : void jsop_this();
663 : void emitReturn(FrameEntry *fe);
664 : void emitFinalReturn(Assembler &masm);
665 : void loadReturnValue(Assembler *masm, FrameEntry *fe);
666 : void emitReturnValue(Assembler *masm, FrameEntry *fe);
667 : void emitInlineReturnValue(FrameEntry *fe);
668 : void dispatchCall(VoidPtrStubUInt32 stub, uint32_t argc);
669 : void interruptCheckHelper();
670 : void recompileCheckHelper();
671 : void emitUncachedCall(uint32_t argc, bool callingNew);
672 : void checkCallApplySpeculation(uint32_t callImmArgc, uint32_t speculatedArgc,
673 : FrameEntry *origCallee, FrameEntry *origThis,
674 : MaybeRegisterID origCalleeType, RegisterID origCalleeData,
675 : MaybeRegisterID origThisType, RegisterID origThisData,
676 : Jump *uncachedCallSlowRejoin, CallPatchInfo *uncachedCallPatch);
677 : bool inlineCallHelper(uint32_t argc, bool callingNew, FrameSize &callFrameSize);
678 : void fixPrimitiveReturn(Assembler *masm, FrameEntry *fe);
679 : void jsop_getgname(uint32_t index);
680 : void jsop_getgname_slow(uint32_t index);
681 : void jsop_setgname(PropertyName *name, bool popGuaranteed);
682 : void jsop_setgname_slow(PropertyName *name);
683 : void jsop_bindgname();
684 : void jsop_setelem_slow();
685 : void jsop_getelem_slow();
686 : bool jsop_getprop(PropertyName *name, JSValueType type,
687 : bool typeCheck = true, bool forPrototype = false);
688 : bool jsop_getprop_dispatch(PropertyName *name);
689 : bool jsop_setprop(PropertyName *name, bool popGuaranteed);
690 : void jsop_setprop_slow(PropertyName *name);
691 : bool jsop_instanceof();
692 : void jsop_name(PropertyName *name, JSValueType type);
693 : bool jsop_xname(PropertyName *name);
694 : void enterBlock(StaticBlockObject *block);
695 : void leaveBlock();
696 : void emitEval(uint32_t argc);
697 : void jsop_arguments(RejoinState rejoin);
698 : bool jsop_tableswitch(jsbytecode *pc);
699 :
700 : /* Fast arithmetic. */
701 : bool jsop_binary_slow(JSOp op, VoidStub stub, JSValueType type, FrameEntry *lhs, FrameEntry *rhs);
702 : bool jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet);
703 : void jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub,
704 : JSValueType type, bool cannotOverflow, bool ignoreOverflow);
705 : void jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub,
706 : JSValueType type);
707 : void jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub,
708 : JSValueType type);
709 : void slowLoadConstantDouble(Assembler &masm, FrameEntry *fe,
710 : FPRegisterID fpreg);
711 : void maybeJumpIfNotInt32(Assembler &masm, MaybeJump &mj, FrameEntry *fe,
712 : MaybeRegisterID &mreg);
713 : void maybeJumpIfNotDouble(Assembler &masm, MaybeJump &mj, FrameEntry *fe,
714 : MaybeRegisterID &mreg);
715 : bool jsop_relational(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
716 : bool jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
717 : bool jsop_relational_double(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
718 : bool jsop_relational_int(JSOp op, jsbytecode *target, JSOp fused);
719 :
720 : void emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc ®s,
721 : MaybeJump &lhsNotDouble, MaybeJump &rhsNotNumber,
722 : MaybeJump &lhsUnknownDone);
723 : void emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc ®s,
724 : MaybeJump &rhsNotNumber2);
725 : bool tryBinaryConstantFold(JSContext *cx, FrameState &frame, JSOp op,
726 : FrameEntry *lhs, FrameEntry *rhs, Value *vp);
727 :
728 : /* Fast opcodes. */
729 : void jsop_bitop(JSOp op);
730 : bool jsop_mod();
731 : void jsop_neg();
732 : void jsop_bitnot();
733 : void jsop_not();
734 : void jsop_typeof();
735 : bool booleanJumpScript(JSOp op, jsbytecode *target);
736 : bool jsop_ifneq(JSOp op, jsbytecode *target);
737 : bool jsop_andor(JSOp op, jsbytecode *target);
738 : bool jsop_arginc(JSOp op, uint32_t slot);
739 : bool jsop_localinc(JSOp op, uint32_t slot);
740 : bool jsop_newinit();
741 : bool jsop_regexp();
742 : void jsop_initmethod();
743 : void jsop_initprop();
744 : void jsop_initelem();
745 : void jsop_setelem_dense();
746 : #ifdef JS_METHODJIT_TYPED_ARRAY
747 : void jsop_setelem_typed(int atype);
748 : void convertForTypedArray(int atype, ValueRemat *vr, bool *allocated);
749 : #endif
750 : bool jsop_setelem(bool popGuaranteed);
751 : bool jsop_getelem();
752 : void jsop_getelem_dense(bool isPacked);
753 : void jsop_getelem_args();
754 : #ifdef JS_METHODJIT_TYPED_ARRAY
755 : bool jsop_getelem_typed(int atype);
756 : #endif
757 : void jsop_toid();
758 : bool isCacheableBaseAndIndex(FrameEntry *obj, FrameEntry *id);
759 : void jsop_stricteq(JSOp op);
760 : bool jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
761 : CompileStatus jsop_equality_obj_obj(JSOp op, jsbytecode *target, JSOp fused);
762 : bool jsop_equality_int_string(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
763 : void jsop_pos();
764 : void jsop_in();
765 :
766 : static inline Assembler::Condition
767 69435 : GetCompareCondition(JSOp op, JSOp fused)
768 : {
769 69435 : bool ifeq = fused == JSOP_IFEQ;
770 69435 : switch (op) {
771 : case JSOP_GT:
772 4925 : return ifeq ? Assembler::LessThanOrEqual : Assembler::GreaterThan;
773 : case JSOP_GE:
774 7031 : return ifeq ? Assembler::LessThan : Assembler::GreaterThanOrEqual;
775 : case JSOP_LT:
776 52707 : return ifeq ? Assembler::GreaterThanOrEqual : Assembler::LessThan;
777 : case JSOP_LE:
778 4361 : return ifeq ? Assembler::GreaterThan : Assembler::LessThanOrEqual;
779 : case JSOP_STRICTEQ:
780 : case JSOP_EQ:
781 286 : return ifeq ? Assembler::NotEqual : Assembler::Equal;
782 : case JSOP_STRICTNE:
783 : case JSOP_NE:
784 125 : return ifeq ? Assembler::Equal : Assembler::NotEqual;
785 : default:
786 0 : JS_NOT_REACHED("unrecognized op");
787 : return Assembler::Equal;
788 : }
789 : }
790 :
791 : static inline Assembler::Condition
792 76256 : GetStubCompareCondition(JSOp fused)
793 : {
794 76256 : return fused == JSOP_IFEQ ? Assembler::Zero : Assembler::NonZero;
795 : }
796 :
797 : /* Fast builtins. */
798 : JSObject *pushedSingleton(unsigned pushed);
799 : CompileStatus callArrayBuiltin(uint32_t argc, bool callingNew);
800 : CompileStatus inlineNativeFunction(uint32_t argc, bool callingNew);
801 : CompileStatus inlineScriptedFunction(uint32_t argc, bool callingNew);
802 : CompileStatus compileMathAbsInt(FrameEntry *arg);
803 : CompileStatus compileMathAbsDouble(FrameEntry *arg);
804 : CompileStatus compileMathSqrt(FrameEntry *arg);
805 : CompileStatus compileMathMinMaxDouble(FrameEntry *arg1, FrameEntry *arg2,
806 : Assembler::DoubleCondition cond);
807 : CompileStatus compileMathMinMaxInt(FrameEntry *arg1, FrameEntry *arg2,
808 : Assembler::Condition cond);
809 : CompileStatus compileMathPowSimple(FrameEntry *arg1, FrameEntry *arg2);
810 : CompileStatus compileArrayPush(FrameEntry *thisv, FrameEntry *arg);
811 : CompileStatus compileArrayConcat(types::TypeSet *thisTypes, types::TypeSet *argTypes,
812 : FrameEntry *thisValue, FrameEntry *argValue);
813 : CompileStatus compileArrayPopShift(FrameEntry *thisv, bool isPacked, bool isArrayPop);
814 : CompileStatus compileArrayWithLength(uint32_t argc);
815 : CompileStatus compileArrayWithArgs(uint32_t argc);
816 :
817 : enum RoundingMode { Floor, Round };
818 : CompileStatus compileRound(FrameEntry *arg, RoundingMode mode);
819 :
820 : enum GetCharMode { GetChar, GetCharCode };
821 : CompileStatus compileGetChar(FrameEntry *thisValue, FrameEntry *arg, GetCharMode mode);
822 :
823 : CompileStatus compileStringFromCode(FrameEntry *arg);
824 : CompileStatus compileParseInt(JSValueType argType, uint32_t argc);
825 :
826 : void prepareStubCall(Uses uses);
827 : Call emitStubCall(void *ptr, DataLabelPtr *pinline);
828 : };
829 :
830 : // Given a stub call, emits the call into the inline assembly path. rejoin
831 : // indicates how to rejoin should this call trigger expansion/discarding.
832 : #define INLINE_STUBCALL(stub, rejoin) \
833 : inlineStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin, Uses(0))
834 : #define INLINE_STUBCALL_USES(stub, rejoin, uses) \
835 : inlineStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin, uses)
836 :
837 : // Given a stub call, emits the call into the out-of-line assembly path.
838 : // Unlike the INLINE_STUBCALL variant, this returns the Call offset.
839 : #define OOL_STUBCALL(stub, rejoin) \
840 : stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin, Uses(0))
841 : #define OOL_STUBCALL_USES(stub, rejoin, uses) \
842 : stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin, uses)
843 :
844 : // Same as OOL_STUBCALL, but specifies a slot depth.
845 : #define OOL_STUBCALL_LOCAL_SLOTS(stub, rejoin, slots) \
846 : stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin, Uses(0), (slots))
847 :
848 : } /* namespace js */
849 : } /* namespace mjit */
850 :
851 : #endif
852 :
|