js/src/jit/IonBuilder.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:27cb4e1c9923
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #ifndef jit_IonBuilder_h
8 #define jit_IonBuilder_h
9
10 #ifdef JS_ION
11
12 // This file declares the data structures for building a MIRGraph from a
13 // JSScript.
14
15 #include "jit/BytecodeAnalysis.h"
16 #include "jit/IonOptimizationLevels.h"
17 #include "jit/MIR.h"
18 #include "jit/MIRGenerator.h"
19 #include "jit/MIRGraph.h"
20 #include "jit/TypeDescrSet.h"
21
22 namespace js {
23 namespace jit {
24
25 class CodeGenerator;
26 class CallInfo;
27 class BaselineInspector;
28 class BaselineFrameInspector;
29
30 // Records information about a baseline frame for compilation that is stable
31 // when later used off thread.
32 BaselineFrameInspector *
33 NewBaselineFrameInspector(TempAllocator *temp, BaselineFrame *frame, CompileInfo *info);
34
35 class IonBuilder : public MIRGenerator
36 {
37 enum ControlStatus {
38 ControlStatus_Error,
39 ControlStatus_Abort,
40 ControlStatus_Ended, // There is no continuation/join point.
41 ControlStatus_Joined, // Created a join node.
42 ControlStatus_Jumped, // Parsing another branch at the same level.
43 ControlStatus_None // No control flow.
44 };
45
46 enum SetElemSafety {
47 // Normal write like a[b] = c.
48 SetElem_Normal,
49
50 // Write due to UnsafePutElements:
51 // - assumed to be in bounds,
52 // - not checked for data races
53 SetElem_Unsafe,
54 };
55
56 struct DeferredEdge : public TempObject
57 {
58 MBasicBlock *block;
59 DeferredEdge *next;
60
61 DeferredEdge(MBasicBlock *block, DeferredEdge *next)
62 : block(block), next(next)
63 { }
64 };
65
66 struct ControlFlowInfo {
67 // Entry in the cfgStack.
68 uint32_t cfgEntry;
69
70 // Label that continues go to.
71 jsbytecode *continuepc;
72
73 ControlFlowInfo(uint32_t cfgEntry, jsbytecode *continuepc)
74 : cfgEntry(cfgEntry),
75 continuepc(continuepc)
76 { }
77 };
78
79 // To avoid recursion, the bytecode analyzer uses a stack where each entry
80 // is a small state machine. As we encounter branches or jumps in the
81 // bytecode, we push information about the edges on the stack so that the
82 // CFG can be built in a tree-like fashion.
83 struct CFGState {
84 enum State {
85 IF_TRUE, // if() { }, no else.
86 IF_TRUE_EMPTY_ELSE, // if() { }, empty else
87 IF_ELSE_TRUE, // if() { X } else { }
88 IF_ELSE_FALSE, // if() { } else { X }
89 DO_WHILE_LOOP_BODY, // do { x } while ()
90 DO_WHILE_LOOP_COND, // do { } while (x)
91 WHILE_LOOP_COND, // while (x) { }
92 WHILE_LOOP_BODY, // while () { x }
93 FOR_LOOP_COND, // for (; x;) { }
94 FOR_LOOP_BODY, // for (; ;) { x }
95 FOR_LOOP_UPDATE, // for (; ; x) { }
96 TABLE_SWITCH, // switch() { x }
97 COND_SWITCH_CASE, // switch() { case X: ... }
98 COND_SWITCH_BODY, // switch() { case ...: X }
99 AND_OR, // && x, || x
100 LABEL, // label: x
101 TRY // try { x } catch(e) { }
102 };
103
104 State state; // Current state of this control structure.
105 jsbytecode *stopAt; // Bytecode at which to stop the processing loop.
106
107 // For if structures, this contains branch information.
108 union {
109 struct {
110 MBasicBlock *ifFalse;
111 jsbytecode *falseEnd;
112 MBasicBlock *ifTrue; // Set when the end of the true path is reached.
113 MTest *test;
114 } branch;
115 struct {
116 // Common entry point.
117 MBasicBlock *entry;
118
119 // Whether OSR is being performed for this loop.
120 bool osr;
121
122 // Position of where the loop body starts and ends.
123 jsbytecode *bodyStart;
124 jsbytecode *bodyEnd;
125
126 // pc immediately after the loop exits.
127 jsbytecode *exitpc;
128
129 // pc for 'continue' jumps.
130 jsbytecode *continuepc;
131
132 // Common exit point. Created lazily, so it may be nullptr.
133 MBasicBlock *successor;
134
135 // Deferred break and continue targets.
136 DeferredEdge *breaks;
137 DeferredEdge *continues;
138
139 // Initial state, in case loop processing is restarted.
140 State initialState;
141 jsbytecode *initialPc;
142 jsbytecode *initialStopAt;
143 jsbytecode *loopHead;
144
145 // For-loops only.
146 jsbytecode *condpc;
147 jsbytecode *updatepc;
148 jsbytecode *updateEnd;
149 } loop;
150 struct {
151 // pc immediately after the switch.
152 jsbytecode *exitpc;
153
154 // Deferred break and continue targets.
155 DeferredEdge *breaks;
156
157 // MIR instruction
158 MTableSwitch *ins;
159
160 // The number of current successor that get mapped into a block.
161 uint32_t currentBlock;
162
163 } tableswitch;
164 struct {
165 // Vector of body blocks to process after the cases.
166 FixedList<MBasicBlock *> *bodies;
167
168 // When processing case statements, this counter points at the
169 // last uninitialized body. When processing bodies, this
170 // counter targets the next body to process.
171 uint32_t currentIdx;
172
173 // Remember the block index of the default case.
174 jsbytecode *defaultTarget;
175 uint32_t defaultIdx;
176
177 // Block immediately after the switch.
178 jsbytecode *exitpc;
179 DeferredEdge *breaks;
180 } condswitch;
181 struct {
182 DeferredEdge *breaks;
183 } label;
184 struct {
185 MBasicBlock *successor;
186 } try_;
187 };
188
189 inline bool isLoop() const {
190 switch (state) {
191 case DO_WHILE_LOOP_COND:
192 case DO_WHILE_LOOP_BODY:
193 case WHILE_LOOP_COND:
194 case WHILE_LOOP_BODY:
195 case FOR_LOOP_COND:
196 case FOR_LOOP_BODY:
197 case FOR_LOOP_UPDATE:
198 return true;
199 default:
200 return false;
201 }
202 }
203
204 static CFGState If(jsbytecode *join, MTest *test);
205 static CFGState IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MTest *test);
206 static CFGState AndOr(jsbytecode *join, MBasicBlock *joinStart);
207 static CFGState TableSwitch(jsbytecode *exitpc, MTableSwitch *ins);
208 static CFGState CondSwitch(IonBuilder *builder, jsbytecode *exitpc, jsbytecode *defaultTarget);
209 static CFGState Label(jsbytecode *exitpc);
210 static CFGState Try(jsbytecode *exitpc, MBasicBlock *successor);
211 };
212
213 static int CmpSuccessors(const void *a, const void *b);
214
215 public:
216 IonBuilder(JSContext *analysisContext, CompileCompartment *comp,
217 const JitCompileOptions &options, TempAllocator *temp,
218 MIRGraph *graph, types::CompilerConstraintList *constraints,
219 BaselineInspector *inspector, CompileInfo *info,
220 const OptimizationInfo *optimizationInfo, BaselineFrameInspector *baselineFrame,
221 size_t inliningDepth = 0, uint32_t loopDepth = 0);
222
223 bool build();
224 bool buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoint,
225 CallInfo &callInfo);
226
227 private:
228 bool traverseBytecode();
229 ControlStatus snoopControlFlow(JSOp op);
230 bool processIterators();
231 bool inspectOpcode(JSOp op);
232 uint32_t readIndex(jsbytecode *pc);
233 JSAtom *readAtom(jsbytecode *pc);
234 bool abort(const char *message, ...);
235 void spew(const char *message);
236
237 JSFunction *getSingleCallTarget(types::TemporaryTypeSet *calleeTypes);
238 bool getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constructing,
239 ObjectVector &targets, uint32_t maxTargets, bool *gotLambda);
240
241 void popCfgStack();
242 DeferredEdge *filterDeadDeferredEdges(DeferredEdge *edge);
243 bool processDeferredContinues(CFGState &state);
244 ControlStatus processControlEnd();
245 ControlStatus processCfgStack();
246 ControlStatus processCfgEntry(CFGState &state);
247 ControlStatus processIfEnd(CFGState &state);
248 ControlStatus processIfElseTrueEnd(CFGState &state);
249 ControlStatus processIfElseFalseEnd(CFGState &state);
250 ControlStatus processDoWhileBodyEnd(CFGState &state);
251 ControlStatus processDoWhileCondEnd(CFGState &state);
252 ControlStatus processWhileCondEnd(CFGState &state);
253 ControlStatus processWhileBodyEnd(CFGState &state);
254 ControlStatus processForCondEnd(CFGState &state);
255 ControlStatus processForBodyEnd(CFGState &state);
256 ControlStatus processForUpdateEnd(CFGState &state);
257 ControlStatus processNextTableSwitchCase(CFGState &state);
258 ControlStatus processCondSwitchCase(CFGState &state);
259 ControlStatus processCondSwitchBody(CFGState &state);
260 ControlStatus processSwitchBreak(JSOp op);
261 ControlStatus processSwitchEnd(DeferredEdge *breaks, jsbytecode *exitpc);
262 ControlStatus processAndOrEnd(CFGState &state);
263 ControlStatus processLabelEnd(CFGState &state);
264 ControlStatus processTryEnd(CFGState &state);
265 ControlStatus processReturn(JSOp op);
266 ControlStatus processThrow();
267 ControlStatus processContinue(JSOp op);
268 ControlStatus processBreak(JSOp op, jssrcnote *sn);
269 ControlStatus maybeLoop(JSOp op, jssrcnote *sn);
270 bool pushLoop(CFGState::State state, jsbytecode *stopAt, MBasicBlock *entry, bool osr,
271 jsbytecode *loopHead, jsbytecode *initialPc,
272 jsbytecode *bodyStart, jsbytecode *bodyEnd, jsbytecode *exitpc,
273 jsbytecode *continuepc = nullptr);
274 bool analyzeNewLoopTypes(MBasicBlock *entry, jsbytecode *start, jsbytecode *end);
275
276 MBasicBlock *addBlock(MBasicBlock *block, uint32_t loopDepth);
277 MBasicBlock *newBlock(MBasicBlock *predecessor, jsbytecode *pc);
278 MBasicBlock *newBlock(MBasicBlock *predecessor, jsbytecode *pc, uint32_t loopDepth);
279 MBasicBlock *newBlock(MBasicBlock *predecessor, jsbytecode *pc, MResumePoint *priorResumePoint);
280 MBasicBlock *newBlockPopN(MBasicBlock *predecessor, jsbytecode *pc, uint32_t popped);
281 MBasicBlock *newBlockAfter(MBasicBlock *at, MBasicBlock *predecessor, jsbytecode *pc);
282 MBasicBlock *newOsrPreheader(MBasicBlock *header, jsbytecode *loopEntry);
283 MBasicBlock *newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool osr, bool canOsr,
284 unsigned stackPhiCount);
285 MBasicBlock *newBlock(jsbytecode *pc) {
286 return newBlock(nullptr, pc);
287 }
288 MBasicBlock *newBlockAfter(MBasicBlock *at, jsbytecode *pc) {
289 return newBlockAfter(at, nullptr, pc);
290 }
291
292 // Given a list of pending breaks, creates a new block and inserts a Goto
293 // linking each break to the new block.
294 MBasicBlock *createBreakCatchBlock(DeferredEdge *edge, jsbytecode *pc);
295
296 // Finishes loops that do not actually loop, containing only breaks and
297 // returns or a do while loop with a condition that is constant false.
298 ControlStatus processBrokenLoop(CFGState &state);
299
300 // Computes loop phis, places them in all successors of a loop, then
301 // handles any pending breaks.
302 ControlStatus finishLoop(CFGState &state, MBasicBlock *successor);
303
304 // Incorporates a type/typeSet into an OSR value for a loop, after the loop
305 // body has been processed.
306 bool addOsrValueTypeBarrier(uint32_t slot, MInstruction **def,
307 MIRType type, types::TemporaryTypeSet *typeSet);
308 bool maybeAddOsrTypeBarriers();
309
310 // Restarts processing of a loop if the type information at its header was
311 // incomplete.
312 ControlStatus restartLoop(CFGState state);
313
314 void assertValidLoopHeadOp(jsbytecode *pc);
315
316 ControlStatus forLoop(JSOp op, jssrcnote *sn);
317 ControlStatus whileOrForInLoop(jssrcnote *sn);
318 ControlStatus doWhileLoop(JSOp op, jssrcnote *sn);
319 ControlStatus tableSwitch(JSOp op, jssrcnote *sn);
320 ControlStatus condSwitch(JSOp op, jssrcnote *sn);
321
322 // Please see the Big Honkin' Comment about how resume points work in
323 // IonBuilder.cpp, near the definition for this function.
324 bool resume(MInstruction *ins, jsbytecode *pc, MResumePoint::Mode mode);
325 bool resumeAt(MInstruction *ins, jsbytecode *pc);
326 bool resumeAfter(MInstruction *ins);
327 bool maybeInsertResume();
328
329 void insertRecompileCheck();
330
331 void initParameters();
332 void rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex);
333 void rewriteParameters();
334 bool initScopeChain(MDefinition *callee = nullptr);
335 bool initArgumentsObject();
336 bool pushConstant(const Value &v);
337
338 MConstant *constant(const Value &v);
339 MConstant *constantInt(int32_t i);
340
341 // Filter the type information at tests
342 bool filterTypesAtTest(MTest *test);
343
344 // Add a guard which ensure that the set of type which goes through this
345 // generated code correspond to the observed types for the bytecode.
346 bool pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, bool needBarrier);
347
348 // As pushTypeBarrier, but will compute the needBarrier boolean itself based
349 // on observed and the JSFunction that we're planning to call. The
350 // JSFunction must be a DOM method or getter.
351 bool pushDOMTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, JSFunction* func);
352
353 // If definiteType is not known or def already has the right type, just
354 // returns def. Otherwise, returns an MInstruction that has that definite
355 // type, infallibly unboxing ins as needed. The new instruction will be
356 // added to |current| in this case.
357 MDefinition *ensureDefiniteType(MDefinition* def, MIRType definiteType);
358
359 // Creates a MDefinition based on the given def improved with type as TypeSet.
360 MDefinition *ensureDefiniteTypeSet(MDefinition* def, types::TemporaryTypeSet *types);
361
362 JSObject *getSingletonPrototype(JSFunction *target);
363
364 MDefinition *createThisScripted(MDefinition *callee);
365 MDefinition *createThisScriptedSingleton(JSFunction *target, MDefinition *callee);
366 MDefinition *createThis(JSFunction *target, MDefinition *callee);
367 MInstruction *createDeclEnvObject(MDefinition *callee, MDefinition *scopeObj);
368 MInstruction *createCallObject(MDefinition *callee, MDefinition *scopeObj);
369
370 MDefinition *walkScopeChain(unsigned hops);
371
372 MInstruction *addConvertElementsToDoubles(MDefinition *elements);
373 MInstruction *addBoundsCheck(MDefinition *index, MDefinition *length);
374 MInstruction *addShapeGuard(MDefinition *obj, Shape *const shape, BailoutKind bailoutKind);
375
376 MDefinition *convertShiftToMaskForStaticTypedArray(MDefinition *id,
377 ArrayBufferView::ViewType viewType);
378
379 bool invalidatedIdempotentCache();
380
381 bool hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall);
382 bool loadSlot(MDefinition *obj, size_t slot, size_t nfixed, MIRType rvalType,
383 bool barrier, types::TemporaryTypeSet *types);
384 bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
385 bool barrier, types::TemporaryTypeSet *types);
386 bool storeSlot(MDefinition *obj, size_t slot, size_t nfixed,
387 MDefinition *value, bool needsBarrier,
388 MIRType slotType = MIRType_None);
389 bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier,
390 MIRType slotType = MIRType_None);
391
392 // jsop_getprop() helpers.
393 bool getPropTryArgumentsLength(bool *emitted);
394 bool getPropTryConstant(bool *emitted, PropertyName *name,
395 types::TemporaryTypeSet *types);
396 bool getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
397 bool barrier, types::TemporaryTypeSet *types);
398 bool getPropTryCommonGetter(bool *emitted, PropertyName *name,
399 types::TemporaryTypeSet *types);
400 bool getPropTryInlineAccess(bool *emitted, PropertyName *name,
401 bool barrier, types::TemporaryTypeSet *types);
402 bool getPropTryTypedObject(bool *emitted, PropertyName *name,
403 types::TemporaryTypeSet *resultTypes);
404 bool getPropTryScalarPropOfTypedObject(bool *emitted,
405 int32_t fieldOffset,
406 TypeDescrSet fieldTypeReprs,
407 types::TemporaryTypeSet *resultTypes);
408 bool getPropTryComplexPropOfTypedObject(bool *emitted,
409 int32_t fieldOffset,
410 TypeDescrSet fieldTypeReprs,
411 size_t fieldIndex,
412 types::TemporaryTypeSet *resultTypes);
413 bool getPropTryCache(bool *emitted, PropertyName *name,
414 bool barrier, types::TemporaryTypeSet *types);
415 bool needsToMonitorMissingProperties(types::TemporaryTypeSet *types);
416
417 // jsop_setprop() helpers.
418 bool setPropTryCommonSetter(bool *emitted, MDefinition *obj,
419 PropertyName *name, MDefinition *value);
420 bool setPropTryCommonDOMSetter(bool *emitted, MDefinition *obj,
421 MDefinition *value, JSFunction *setter,
422 bool isDOM);
423 bool setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
424 PropertyName *name, MDefinition *value,
425 bool barrier, types::TemporaryTypeSet *objTypes);
426 bool setPropTryInlineAccess(bool *emitted, MDefinition *obj,
427 PropertyName *name, MDefinition *value, bool barrier,
428 types::TemporaryTypeSet *objTypes);
429 bool setPropTryTypedObject(bool *emitted, MDefinition *obj,
430 PropertyName *name, MDefinition *value);
431 bool setPropTryScalarPropOfTypedObject(bool *emitted,
432 MDefinition *obj,
433 int32_t fieldOffset,
434 MDefinition *value,
435 TypeDescrSet fieldTypeReprs);
436 bool setPropTryCache(bool *emitted, MDefinition *obj,
437 PropertyName *name, MDefinition *value,
438 bool barrier, types::TemporaryTypeSet *objTypes);
439
440 // binary data lookup helpers.
441 bool lookupTypeDescrSet(MDefinition *typedObj,
442 TypeDescrSet *out);
443 bool typeSetToTypeDescrSet(types::TemporaryTypeSet *types,
444 TypeDescrSet *out);
445 bool lookupTypedObjectField(MDefinition *typedObj,
446 PropertyName *name,
447 int32_t *fieldOffset,
448 TypeDescrSet *fieldTypeReprs,
449 size_t *fieldIndex);
450 MDefinition *loadTypedObjectType(MDefinition *value);
451 void loadTypedObjectData(MDefinition *typedObj,
452 MDefinition *offset,
453 bool canBeNeutered,
454 MDefinition **owner,
455 MDefinition **ownerOffset);
456 void loadTypedObjectElements(MDefinition *typedObj,
457 MDefinition *offset,
458 int32_t unit,
459 bool canBeNeutered,
460 MDefinition **ownerElements,
461 MDefinition **ownerScaledOffset);
462 MDefinition *typeObjectForElementFromArrayStructType(MDefinition *typedObj);
463 MDefinition *typeObjectForFieldFromStructType(MDefinition *type,
464 size_t fieldIndex);
465 bool storeScalarTypedObjectValue(MDefinition *typedObj,
466 MDefinition *offset,
467 ScalarTypeDescr::Type type,
468 bool canBeNeutered,
469 bool racy,
470 MDefinition *value);
471 bool checkTypedObjectIndexInBounds(int32_t elemSize,
472 MDefinition *obj,
473 MDefinition *index,
474 TypeDescrSet objTypeDescrs,
475 MDefinition **indexAsByteOffset,
476 bool *canBeNeutered);
477 bool pushDerivedTypedObject(bool *emitted,
478 MDefinition *obj,
479 MDefinition *offset,
480 TypeDescrSet derivedTypeDescrs,
481 MDefinition *derivedTypeObj,
482 bool canBeNeutered);
483 bool pushScalarLoadFromTypedObject(bool *emitted,
484 MDefinition *obj,
485 MDefinition *offset,
486 ScalarTypeDescr::Type type,
487 bool canBeNeutered);
488 MDefinition *neuterCheck(MDefinition *obj);
489
490 // jsop_setelem() helpers.
491 bool setElemTryTypedArray(bool *emitted, MDefinition *object,
492 MDefinition *index, MDefinition *value);
493 bool setElemTryTypedObject(bool *emitted, MDefinition *obj,
494 MDefinition *index, MDefinition *value);
495 bool setElemTryTypedStatic(bool *emitted, MDefinition *object,
496 MDefinition *index, MDefinition *value);
497 bool setElemTryDense(bool *emitted, MDefinition *object,
498 MDefinition *index, MDefinition *value);
499 bool setElemTryArguments(bool *emitted, MDefinition *object,
500 MDefinition *index, MDefinition *value);
501 bool setElemTryCache(bool *emitted, MDefinition *object,
502 MDefinition *index, MDefinition *value);
503 bool setElemTryScalarElemOfTypedObject(bool *emitted,
504 MDefinition *obj,
505 MDefinition *index,
506 TypeDescrSet objTypeReprs,
507 MDefinition *value,
508 TypeDescrSet elemTypeReprs,
509 int32_t elemSize);
510
511 // jsop_getelem() helpers.
512 bool getElemTryDense(bool *emitted, MDefinition *obj, MDefinition *index);
513 bool getElemTryTypedStatic(bool *emitted, MDefinition *obj, MDefinition *index);
514 bool getElemTryTypedArray(bool *emitted, MDefinition *obj, MDefinition *index);
515 bool getElemTryTypedObject(bool *emitted, MDefinition *obj, MDefinition *index);
516 bool getElemTryString(bool *emitted, MDefinition *obj, MDefinition *index);
517 bool getElemTryArguments(bool *emitted, MDefinition *obj, MDefinition *index);
518 bool getElemTryArgumentsInlined(bool *emitted, MDefinition *obj, MDefinition *index);
519 bool getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index);
520 bool getElemTryScalarElemOfTypedObject(bool *emitted,
521 MDefinition *obj,
522 MDefinition *index,
523 TypeDescrSet objTypeReprs,
524 TypeDescrSet elemTypeReprs,
525 int32_t elemSize);
526 bool getElemTryComplexElemOfTypedObject(bool *emitted,
527 MDefinition *obj,
528 MDefinition *index,
529 TypeDescrSet objTypeReprs,
530 TypeDescrSet elemTypeReprs,
531 int32_t elemSize);
532
533 enum BoundsChecking { DoBoundsCheck, SkipBoundsCheck };
534
535 // Add instructions to compute a typed array's length and data. Also
536 // optionally convert |*index| into a bounds-checked definition, if
537 // requested.
538 //
539 // If you only need the array's length, use addTypedArrayLength below.
540 void addTypedArrayLengthAndData(MDefinition *obj,
541 BoundsChecking checking,
542 MDefinition **index,
543 MInstruction **length, MInstruction **elements);
544
545 // Add an instruction to compute a typed array's length to the current
546 // block. If you also need the typed array's data, use the above method
547 // instead.
548 MInstruction *addTypedArrayLength(MDefinition *obj) {
549 MInstruction *length;
550 addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr);
551 return length;
552 }
553
554
555 MDefinition *getCallee();
556
557 bool jsop_add(MDefinition *left, MDefinition *right);
558 bool jsop_bitnot();
559 bool jsop_bitop(JSOp op);
560 bool jsop_binary(JSOp op);
561 bool jsop_binary(JSOp op, MDefinition *left, MDefinition *right);
562 bool jsop_pos();
563 bool jsop_neg();
564 bool jsop_setarg(uint32_t arg);
565 bool jsop_defvar(uint32_t index);
566 bool jsop_deffun(uint32_t index);
567 bool jsop_notearg();
568 bool jsop_funcall(uint32_t argc);
569 bool jsop_funapply(uint32_t argc);
570 bool jsop_funapplyarguments(uint32_t argc);
571 bool jsop_call(uint32_t argc, bool constructing);
572 bool jsop_eval(uint32_t argc);
573 bool jsop_ifeq(JSOp op);
574 bool jsop_try();
575 bool jsop_label();
576 bool jsop_condswitch();
577 bool jsop_andor(JSOp op);
578 bool jsop_dup2();
579 bool jsop_loophead(jsbytecode *pc);
580 bool jsop_compare(JSOp op);
581 bool getStaticName(JSObject *staticObject, PropertyName *name, bool *psucceeded);
582 bool setStaticName(JSObject *staticObject, PropertyName *name);
583 bool jsop_getgname(PropertyName *name);
584 bool jsop_getname(PropertyName *name);
585 bool jsop_intrinsic(PropertyName *name);
586 bool jsop_bindname(PropertyName *name);
587 bool jsop_getelem();
588 bool jsop_getelem_dense(MDefinition *obj, MDefinition *index);
589 bool jsop_getelem_typed(MDefinition *obj, MDefinition *index, ScalarTypeDescr::Type arrayType);
590 bool jsop_setelem();
591 bool jsop_setelem_dense(types::TemporaryTypeSet::DoubleConversion conversion,
592 SetElemSafety safety,
593 MDefinition *object, MDefinition *index, MDefinition *value);
594 bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
595 SetElemSafety safety,
596 MDefinition *object, MDefinition *index, MDefinition *value);
597 bool jsop_setelem_typed_object(ScalarTypeDescr::Type arrayType,
598 SetElemSafety safety, bool racy,
599 MDefinition *object, MDefinition *index, MDefinition *value);
600 bool jsop_length();
601 bool jsop_length_fastPath();
602 bool jsop_arguments();
603 bool jsop_arguments_length();
604 bool jsop_arguments_getelem();
605 bool jsop_runonce();
606 bool jsop_rest();
607 bool jsop_not();
608 bool jsop_getprop(PropertyName *name);
609 bool jsop_setprop(PropertyName *name);
610 bool jsop_delprop(PropertyName *name);
611 bool jsop_delelem();
612 bool jsop_newarray(uint32_t count);
613 bool jsop_newobject();
614 bool jsop_initelem();
615 bool jsop_initelem_array();
616 bool jsop_initelem_getter_setter();
617 bool jsop_mutateproto();
618 bool jsop_initprop(PropertyName *name);
619 bool jsop_initprop_getter_setter(PropertyName *name);
620 bool jsop_regexp(RegExpObject *reobj);
621 bool jsop_object(JSObject *obj);
622 bool jsop_lambda(JSFunction *fun);
623 bool jsop_lambda_arrow(JSFunction *fun);
624 bool jsop_this();
625 bool jsop_typeof();
626 bool jsop_toid();
627 bool jsop_iter(uint8_t flags);
628 bool jsop_iternext();
629 bool jsop_itermore();
630 bool jsop_iterend();
631 bool jsop_in();
632 bool jsop_in_dense();
633 bool jsop_instanceof();
634 bool jsop_getaliasedvar(ScopeCoordinate sc);
635 bool jsop_setaliasedvar(ScopeCoordinate sc);
636
637 /* Inlining. */
638
639 enum InliningStatus
640 {
641 InliningStatus_Error,
642 InliningStatus_NotInlined,
643 InliningStatus_Inlined
644 };
645
646 enum InliningDecision
647 {
648 InliningDecision_Error,
649 InliningDecision_Inline,
650 InliningDecision_DontInline
651 };
652
653 static InliningDecision DontInline(JSScript *targetScript, const char *reason);
654
655 // Oracles.
656 InliningDecision canInlineTarget(JSFunction *target, CallInfo &callInfo);
657 InliningDecision makeInliningDecision(JSFunction *target, CallInfo &callInfo);
658 bool selectInliningTargets(ObjectVector &targets, CallInfo &callInfo,
659 BoolVector &choiceSet, uint32_t *numInlineable);
660
661 // Native inlining helpers.
662 types::TemporaryTypeSet *getInlineReturnTypeSet();
663 MIRType getInlineReturnType();
664
665 // Array natives.
666 InliningStatus inlineArray(CallInfo &callInfo);
667 InliningStatus inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode);
668 InliningStatus inlineArrayPush(CallInfo &callInfo);
669 InliningStatus inlineArrayConcat(CallInfo &callInfo);
670 InliningStatus inlineArraySplice(CallInfo &callInfo);
671
672 // Math natives.
673 InliningStatus inlineMathAbs(CallInfo &callInfo);
674 InliningStatus inlineMathFloor(CallInfo &callInfo);
675 InliningStatus inlineMathCeil(CallInfo &callInfo);
676 InliningStatus inlineMathRound(CallInfo &callInfo);
677 InliningStatus inlineMathSqrt(CallInfo &callInfo);
678 InliningStatus inlineMathAtan2(CallInfo &callInfo);
679 InliningStatus inlineMathHypot(CallInfo &callInfo);
680 InliningStatus inlineMathMinMax(CallInfo &callInfo, bool max);
681 InliningStatus inlineMathPow(CallInfo &callInfo);
682 InliningStatus inlineMathRandom(CallInfo &callInfo);
683 InliningStatus inlineMathImul(CallInfo &callInfo);
684 InliningStatus inlineMathFRound(CallInfo &callInfo);
685 InliningStatus inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function);
686
687 // String natives.
688 InliningStatus inlineStringObject(CallInfo &callInfo);
689 InliningStatus inlineStringSplit(CallInfo &callInfo);
690 InliningStatus inlineStrCharCodeAt(CallInfo &callInfo);
691 InliningStatus inlineStrFromCharCode(CallInfo &callInfo);
692 InliningStatus inlineStrCharAt(CallInfo &callInfo);
693 InliningStatus inlineStrReplace(CallInfo &callInfo);
694
695 // RegExp natives.
696 InliningStatus inlineRegExpExec(CallInfo &callInfo);
697 InliningStatus inlineRegExpTest(CallInfo &callInfo);
698
699 // Array intrinsics.
700 InliningStatus inlineUnsafePutElements(CallInfo &callInfo);
701 bool inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base);
702 bool inlineUnsafeSetTypedArrayElement(CallInfo &callInfo, uint32_t base,
703 ScalarTypeDescr::Type arrayType);
704 bool inlineUnsafeSetTypedObjectArrayElement(CallInfo &callInfo, uint32_t base,
705 ScalarTypeDescr::Type arrayType);
706 InliningStatus inlineNewDenseArray(CallInfo &callInfo);
707 InliningStatus inlineNewDenseArrayForSequentialExecution(CallInfo &callInfo);
708 InliningStatus inlineNewDenseArrayForParallelExecution(CallInfo &callInfo);
709
710 // Slot intrinsics.
711 InliningStatus inlineUnsafeSetReservedSlot(CallInfo &callInfo);
712 InliningStatus inlineUnsafeGetReservedSlot(CallInfo &callInfo);
713
714 // ForkJoin intrinsics
715 InliningStatus inlineForkJoinGetSlice(CallInfo &callInfo);
716
717 // TypedObject intrinsics.
718 InliningStatus inlineObjectIsTypeDescr(CallInfo &callInfo);
719 InliningStatus inlineSetTypedObjectOffset(CallInfo &callInfo);
720 bool elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
721 ScalarTypeDescr::Type *arrayType);
722
723 // Utility intrinsics.
724 InliningStatus inlineIsCallable(CallInfo &callInfo);
725 InliningStatus inlineHaveSameClass(CallInfo &callInfo);
726 InliningStatus inlineToObject(CallInfo &callInfo);
727 InliningStatus inlineDump(CallInfo &callInfo);
728 InliningStatus inlineHasClass(CallInfo &callInfo, const Class *clasp) {
729 return inlineHasClasses(callInfo, clasp, nullptr);
730 }
731 InliningStatus inlineHasClasses(CallInfo &callInfo, const Class *clasp1, const Class *clasp2);
732
733 // Testing functions.
734 InliningStatus inlineForceSequentialOrInParallelSection(CallInfo &callInfo);
735 InliningStatus inlineBailout(CallInfo &callInfo);
736 InliningStatus inlineAssertFloat32(CallInfo &callInfo);
737
738 // Bind function.
739 InliningStatus inlineBoundFunction(CallInfo &callInfo, JSFunction *target);
740
741 // Main inlining functions
742 InliningStatus inlineNativeCall(CallInfo &callInfo, JSFunction *target);
743 bool inlineScriptedCall(CallInfo &callInfo, JSFunction *target);
744 InliningStatus inlineSingleCall(CallInfo &callInfo, JSFunction *target);
745
746 // Call functions
747 InliningStatus inlineCallsite(ObjectVector &targets, ObjectVector &originals,
748 bool lambda, CallInfo &callInfo);
749 bool inlineCalls(CallInfo &callInfo, ObjectVector &targets, ObjectVector &originals,
750 BoolVector &choiceSet, MGetPropertyCache *maybeCache);
751
752 // Inlining helpers.
753 bool inlineGenericFallback(JSFunction *target, CallInfo &callInfo, MBasicBlock *dispatchBlock,
754 bool clonedAtCallsite);
755 bool inlineTypeObjectFallback(CallInfo &callInfo, MBasicBlock *dispatchBlock,
756 MTypeObjectDispatch *dispatch, MGetPropertyCache *cache,
757 MBasicBlock **fallbackTarget);
758
759 bool testNeedsArgumentCheck(JSFunction *target, CallInfo &callInfo);
760
761 MDefinition *makeCallsiteClone(JSFunction *target, MDefinition *fun);
762 MCall *makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsite);
763 bool makeCall(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsite);
764
765 MDefinition *patchInlinedReturn(CallInfo &callInfo, MBasicBlock *exit, MBasicBlock *bottom);
766 MDefinition *patchInlinedReturns(CallInfo &callInfo, MIRGraphReturns &returns,
767 MBasicBlock *bottom);
768
769 bool objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
770 bool isGetter, JSObject *foundProto);
771 void freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
772 JSObject *foundProto);
773 MDefinition *testCommonGetterSetter(types::TemporaryTypeSet *types, PropertyName *name,
774 bool isGetter, JSObject *foundProto, Shape *lastProperty);
775 bool testShouldDOMCall(types::TypeSet *inTypes,
776 JSFunction *func, JSJitInfo::OpType opType);
777
778 bool annotateGetPropertyCache(MDefinition *obj, MGetPropertyCache *getPropCache,
779 types::TemporaryTypeSet *objTypes,
780 types::TemporaryTypeSet *pushedTypes);
781
782 MGetPropertyCache *getInlineableGetPropertyCache(CallInfo &callInfo);
783
784 JSObject *testSingletonProperty(JSObject *obj, PropertyName *name);
785 bool testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, PropertyName *name,
786 bool *testObject, bool *testString);
787 bool getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name,
788 types::HeapTypeSetKey *property);
789 bool freezePropTypeSets(types::TemporaryTypeSet *types,
790 JSObject *foundProto, PropertyName *name);
791
792 types::TemporaryTypeSet *bytecodeTypes(jsbytecode *pc);
793
794 // Use one of the below methods for updating the current block, rather than
795 // updating |current| directly. setCurrent() should only be used in cases
796 // where the block cannot have phis whose type needs to be computed.
797
798 bool setCurrentAndSpecializePhis(MBasicBlock *block) {
799 if (block) {
800 if (!block->specializePhis())
801 return false;
802 }
803 setCurrent(block);
804 return true;
805 }
806
807 void setCurrent(MBasicBlock *block) {
808 current = block;
809 }
810
811 // A builder is inextricably tied to a particular script.
812 JSScript *script_;
813
814 // If off thread compilation is successful, the final code generator is
815 // attached here. Code has been generated, but not linked (there is not yet
816 // an IonScript). This is heap allocated, and must be explicitly destroyed,
817 // performed by FinishOffThreadBuilder().
818 CodeGenerator *backgroundCodegen_;
819
820 public:
821 void clearForBackEnd();
822
823 JSScript *script() const { return script_; }
824
825 CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; }
826 void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; }
827
828 AbortReason abortReason() { return abortReason_; }
829
830 TypeDescrSetHash *getOrCreateDescrSetHash(); // fallible
831
832 types::CompilerConstraintList *constraints() {
833 return constraints_;
834 }
835
836 bool isInlineBuilder() const {
837 return callerBuilder_ != nullptr;
838 }
839
840 const JSAtomState &names() { return compartment->runtime()->names(); }
841
842 private:
843 bool init();
844
845 JSContext *analysisContext;
846 BaselineFrameInspector *baselineFrame_;
847 AbortReason abortReason_;
848 TypeDescrSetHash *descrSetHash_;
849
850 // Constraints for recording dependencies on type information.
851 types::CompilerConstraintList *constraints_;
852
853 // Basic analysis information about the script.
854 BytecodeAnalysis analysis_;
855 BytecodeAnalysis &analysis() {
856 return analysis_;
857 }
858
859 types::TemporaryTypeSet *thisTypes, *argTypes, *typeArray;
860 uint32_t typeArrayHint;
861 uint32_t *bytecodeTypeMap;
862
863 GSNCache gsn;
864 ScopeCoordinateNameCache scopeCoordinateNameCache;
865
866 jsbytecode *pc;
867 MBasicBlock *current;
868 uint32_t loopDepth_;
869
870 /* Information used for inline-call builders. */
871 MResumePoint *callerResumePoint_;
872 jsbytecode *callerPC() {
873 return callerResumePoint_ ? callerResumePoint_->pc() : nullptr;
874 }
875 IonBuilder *callerBuilder_;
876
877 bool oom() {
878 abortReason_ = AbortReason_Alloc;
879 return false;
880 }
881
882 struct LoopHeader {
883 jsbytecode *pc;
884 MBasicBlock *header;
885
886 LoopHeader(jsbytecode *pc, MBasicBlock *header)
887 : pc(pc), header(header)
888 {}
889 };
890
891 Vector<CFGState, 8, IonAllocPolicy> cfgStack_;
892 Vector<ControlFlowInfo, 4, IonAllocPolicy> loops_;
893 Vector<ControlFlowInfo, 0, IonAllocPolicy> switches_;
894 Vector<ControlFlowInfo, 2, IonAllocPolicy> labels_;
895 Vector<MInstruction *, 2, IonAllocPolicy> iterators_;
896 Vector<LoopHeader, 0, IonAllocPolicy> loopHeaders_;
897 BaselineInspector *inspector;
898
899 size_t inliningDepth_;
900
901 // Cutoff to disable compilation if excessive time is spent reanalyzing
902 // loop bodies to compute a fixpoint of the types for loop variables.
903 static const size_t MAX_LOOP_RESTARTS = 40;
904 size_t numLoopRestarts_;
905
906 // True if script->failedBoundsCheck is set for the current script or
907 // an outer script.
908 bool failedBoundsCheck_;
909
910 // True if script->failedShapeGuard is set for the current script or
911 // an outer script.
912 bool failedShapeGuard_;
913
914 // Has an iterator other than 'for in'.
915 bool nonStringIteration_;
916
917 // If this script can use a lazy arguments object, it will be pre-created
918 // here.
919 MInstruction *lazyArguments_;
920
921 // If this is an inline builder, the call info for the builder.
922 const CallInfo *inlineCallInfo_;
923 };
924
925 class CallInfo
926 {
927 MDefinition *fun_;
928 MDefinition *thisArg_;
929 MDefinitionVector args_;
930
931 bool constructing_;
932 bool setter_;
933
934 public:
935 CallInfo(TempAllocator &alloc, bool constructing)
936 : fun_(nullptr),
937 thisArg_(nullptr),
938 args_(alloc),
939 constructing_(constructing),
940 setter_(false)
941 { }
942
943 bool init(CallInfo &callInfo) {
944 JS_ASSERT(constructing_ == callInfo.constructing());
945
946 fun_ = callInfo.fun();
947 thisArg_ = callInfo.thisArg();
948
949 if (!args_.appendAll(callInfo.argv()))
950 return false;
951
952 return true;
953 }
954
955 bool init(MBasicBlock *current, uint32_t argc) {
956 JS_ASSERT(args_.empty());
957
958 // Get the arguments in the right order
959 if (!args_.reserve(argc))
960 return false;
961 for (int32_t i = argc; i > 0; i--)
962 args_.infallibleAppend(current->peek(-i));
963 current->popn(argc);
964
965 // Get |this| and |fun|
966 setThis(current->pop());
967 setFun(current->pop());
968
969 return true;
970 }
971
972 void popFormals(MBasicBlock *current) {
973 current->popn(numFormals());
974 }
975
976 void pushFormals(MBasicBlock *current) {
977 current->push(fun());
978 current->push(thisArg());
979
980 for (uint32_t i = 0; i < argc(); i++)
981 current->push(getArg(i));
982 }
983
984 uint32_t argc() const {
985 return args_.length();
986 }
987 uint32_t numFormals() const {
988 return argc() + 2;
989 }
990
991 void setArgs(MDefinitionVector *args) {
992 JS_ASSERT(args_.empty());
993 args_.appendAll(*args);
994 }
995
996 MDefinitionVector &argv() {
997 return args_;
998 }
999
1000 const MDefinitionVector &argv() const {
1001 return args_;
1002 }
1003
1004 MDefinition *getArg(uint32_t i) const {
1005 JS_ASSERT(i < argc());
1006 return args_[i];
1007 }
1008
1009 void setArg(uint32_t i, MDefinition *def) {
1010 JS_ASSERT(i < argc());
1011 args_[i] = def;
1012 }
1013
1014 MDefinition *thisArg() const {
1015 JS_ASSERT(thisArg_);
1016 return thisArg_;
1017 }
1018
1019 void setThis(MDefinition *thisArg) {
1020 thisArg_ = thisArg;
1021 }
1022
1023 bool constructing() const {
1024 return constructing_;
1025 }
1026
1027 bool isSetter() const {
1028 return setter_;
1029 }
1030 void markAsSetter() {
1031 setter_ = true;
1032 }
1033
1034 MDefinition *fun() const {
1035 JS_ASSERT(fun_);
1036 return fun_;
1037 }
1038
1039 void setFun(MDefinition *fun) {
1040 fun_ = fun;
1041 }
1042
1043 void setImplicitlyUsedUnchecked() {
1044 fun_->setImplicitlyUsedUnchecked();
1045 thisArg_->setImplicitlyUsedUnchecked();
1046 for (uint32_t i = 0; i < argc(); i++)
1047 getArg(i)->setImplicitlyUsedUnchecked();
1048 }
1049 };
1050
1051 bool TypeSetIncludes(types::TypeSet *types, MIRType input, types::TypeSet *inputTypes);
1052
1053 bool NeedsPostBarrier(CompileInfo &info, MDefinition *value);
1054
1055 } // namespace jit
1056 } // namespace js
1057
1058 #endif // JS_ION
1059
1060 #endif /* jit_IonBuilder_h */

mercurial