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