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 // This file declares the data structures for building a MIRGraph from a 11 // JSScript. 12 13 #include "mozilla/LinkedList.h" 14 15 #include "jit/BaselineInspector.h" 16 #include "jit/BytecodeAnalysis.h" 17 #include "jit/IonAnalysis.h" 18 #include "jit/IonOptimizationLevels.h" 19 #include "jit/MIR.h" 20 #include "jit/MIRGenerator.h" 21 #include "jit/MIRGraph.h" 22 #include "jit/OptimizationTracking.h" 23 24 namespace js { 25 namespace jit { 26 27 class CodeGenerator; 28 class CallInfo; 29 class BaselineFrameInspector; 30 31 enum class InlinableNative : uint16_t; 32 33 // Records information about a baseline frame for compilation that is stable 34 // when later used off thread. 35 BaselineFrameInspector* 36 NewBaselineFrameInspector(TempAllocator* temp, BaselineFrame* frame, CompileInfo* info); 37 38 class IonBuilder 39 : public MIRGenerator, 40 public mozilla::LinkedListElement<IonBuilder> 41 { 42 enum ControlStatus { 43 ControlStatus_Error, 44 ControlStatus_Abort, 45 ControlStatus_Ended, // There is no continuation/join point. 46 ControlStatus_Joined, // Created a join node. 47 ControlStatus_Jumped, // Parsing another branch at the same level. 48 ControlStatus_None // No control flow. 49 }; 50 51 struct DeferredEdge : public TempObject 52 { 53 MBasicBlock* block; 54 DeferredEdge* next; 55 DeferredEdgeDeferredEdge56 DeferredEdge(MBasicBlock* block, DeferredEdge* next) 57 : block(block), next(next) 58 { } 59 }; 60 61 struct ControlFlowInfo { 62 // Entry in the cfgStack. 63 uint32_t cfgEntry; 64 65 // Label that continues go to. 66 jsbytecode* continuepc; 67 ControlFlowInfoControlFlowInfo68 ControlFlowInfo(uint32_t cfgEntry, jsbytecode* continuepc) 69 : cfgEntry(cfgEntry), 70 continuepc(continuepc) 71 { } 72 }; 73 74 // To avoid recursion, the bytecode analyzer uses a stack where each entry 75 // is a small state machine. As we encounter branches or jumps in the 76 // bytecode, we push information about the edges on the stack so that the 77 // CFG can be built in a tree-like fashion. 78 struct CFGState { 79 enum State { 80 IF_TRUE, // if() { }, no else. 81 IF_TRUE_EMPTY_ELSE, // if() { }, empty else 82 IF_ELSE_TRUE, // if() { X } else { } 83 IF_ELSE_FALSE, // if() { } else { X } 84 DO_WHILE_LOOP_BODY, // do { x } while () 85 DO_WHILE_LOOP_COND, // do { } while (x) 86 WHILE_LOOP_COND, // while (x) { } 87 WHILE_LOOP_BODY, // while () { x } 88 FOR_LOOP_COND, // for (; x;) { } 89 FOR_LOOP_BODY, // for (; ;) { x } 90 FOR_LOOP_UPDATE, // for (; ; x) { } 91 TABLE_SWITCH, // switch() { x } 92 COND_SWITCH_CASE, // switch() { case X: ... } 93 COND_SWITCH_BODY, // switch() { case ...: X } 94 AND_OR, // && x, || x 95 LABEL, // label: x 96 TRY // try { x } catch(e) { } 97 }; 98 99 State state; // Current state of this control structure. 100 jsbytecode* stopAt; // Bytecode at which to stop the processing loop. 101 102 // For if structures, this contains branch information. 103 union { 104 struct { 105 MBasicBlock* ifFalse; 106 jsbytecode* falseEnd; 107 MBasicBlock* ifTrue; // Set when the end of the true path is reached. 108 MTest* test; 109 } branch; 110 struct { 111 // Common entry point. 112 MBasicBlock* entry; 113 114 // Whether OSR is being performed for this loop. 115 bool osr; 116 117 // Position of where the loop body starts and ends. 118 jsbytecode* bodyStart; 119 jsbytecode* bodyEnd; 120 121 // pc immediately after the loop exits. 122 jsbytecode* exitpc; 123 124 // pc for 'continue' jumps. 125 jsbytecode* continuepc; 126 127 // Common exit point. Created lazily, so it may be nullptr. 128 MBasicBlock* successor; 129 130 // Deferred break and continue targets. 131 DeferredEdge* breaks; 132 DeferredEdge* continues; 133 134 // Initial state, in case loop processing is restarted. 135 State initialState; 136 jsbytecode* initialPc; 137 jsbytecode* initialStopAt; 138 jsbytecode* loopHead; 139 140 // For-loops only. 141 jsbytecode* condpc; 142 jsbytecode* updatepc; 143 jsbytecode* updateEnd; 144 } loop; 145 struct { 146 // pc immediately after the switch. 147 jsbytecode* exitpc; 148 149 // Deferred break and continue targets. 150 DeferredEdge* breaks; 151 152 // MIR instruction 153 MTableSwitch* ins; 154 155 // The number of current successor that get mapped into a block. 156 uint32_t currentBlock; 157 158 } tableswitch; 159 struct { 160 // Vector of body blocks to process after the cases. 161 FixedList<MBasicBlock*>* bodies; 162 163 // When processing case statements, this counter points at the 164 // last uninitialized body. When processing bodies, this 165 // counter targets the next body to process. 166 uint32_t currentIdx; 167 168 // Remember the block index of the default case. 169 jsbytecode* defaultTarget; 170 uint32_t defaultIdx; 171 172 // Block immediately after the switch. 173 jsbytecode* exitpc; 174 DeferredEdge* breaks; 175 } condswitch; 176 struct { 177 DeferredEdge* breaks; 178 } label; 179 struct { 180 MBasicBlock* successor; 181 } try_; 182 }; 183 isLoopCFGState184 inline bool isLoop() const { 185 switch (state) { 186 case DO_WHILE_LOOP_COND: 187 case DO_WHILE_LOOP_BODY: 188 case WHILE_LOOP_COND: 189 case WHILE_LOOP_BODY: 190 case FOR_LOOP_COND: 191 case FOR_LOOP_BODY: 192 case FOR_LOOP_UPDATE: 193 return true; 194 default: 195 return false; 196 } 197 } 198 199 static CFGState If(jsbytecode* join, MTest* test); 200 static CFGState IfElse(jsbytecode* trueEnd, jsbytecode* falseEnd, MTest* test); 201 static CFGState AndOr(jsbytecode* join, MBasicBlock* lhs); 202 static CFGState TableSwitch(jsbytecode* exitpc, MTableSwitch* ins); 203 static CFGState CondSwitch(IonBuilder* builder, jsbytecode* exitpc, jsbytecode* defaultTarget); 204 static CFGState Label(jsbytecode* exitpc); 205 static CFGState Try(jsbytecode* exitpc, MBasicBlock* successor); 206 }; 207 208 static int CmpSuccessors(const void* a, const void* b); 209 210 public: 211 IonBuilder(JSContext* analysisContext, CompileCompartment* comp, 212 const JitCompileOptions& options, TempAllocator* temp, 213 MIRGraph* graph, CompilerConstraintList* constraints, 214 BaselineInspector* inspector, CompileInfo* info, 215 const OptimizationInfo* optimizationInfo, BaselineFrameInspector* baselineFrame, 216 size_t inliningDepth = 0, uint32_t loopDepth = 0); 217 218 // Callers of build() and buildInline() should always check whether the 219 // call overrecursed, if false is returned. Overrecursion is not 220 // signaled as OOM and will not in general be caught by OOM paths. 221 bool build(); 222 bool buildInline(IonBuilder* callerBuilder, MResumePoint* callerResumePoint, 223 CallInfo& callInfo); 224 225 private: 226 bool traverseBytecode(); 227 ControlStatus snoopControlFlow(JSOp op); 228 bool processIterators(); 229 bool inspectOpcode(JSOp op); 230 uint32_t readIndex(jsbytecode* pc); 231 JSAtom* readAtom(jsbytecode* pc); 232 bool abort(const char* message, ...); 233 void trackActionableAbort(const char* message); 234 void spew(const char* message); 235 236 JSFunction* getSingleCallTarget(TemporaryTypeSet* calleeTypes); 237 bool getPolyCallTargets(TemporaryTypeSet* calleeTypes, bool constructing, 238 ObjectVector& targets, uint32_t maxTargets); 239 240 void popCfgStack(); 241 DeferredEdge* filterDeadDeferredEdges(DeferredEdge* edge); 242 bool processDeferredContinues(CFGState& state); 243 ControlStatus processControlEnd(); 244 ControlStatus processCfgStack(); 245 ControlStatus processCfgEntry(CFGState& state); 246 ControlStatus processIfEnd(CFGState& state); 247 ControlStatus processIfElseTrueEnd(CFGState& state); 248 ControlStatus processIfElseFalseEnd(CFGState& state); 249 ControlStatus processDoWhileBodyEnd(CFGState& state); 250 ControlStatus processDoWhileCondEnd(CFGState& state); 251 ControlStatus processWhileCondEnd(CFGState& state); 252 ControlStatus processWhileBodyEnd(CFGState& state); 253 ControlStatus processForCondEnd(CFGState& state); 254 ControlStatus processForBodyEnd(CFGState& state); 255 ControlStatus processForUpdateEnd(CFGState& state); 256 ControlStatus processNextTableSwitchCase(CFGState& state); 257 ControlStatus processCondSwitchCase(CFGState& state); 258 ControlStatus processCondSwitchBody(CFGState& state); 259 ControlStatus processSwitchBreak(JSOp op); 260 ControlStatus processSwitchEnd(DeferredEdge* breaks, jsbytecode* exitpc); 261 ControlStatus processAndOrEnd(CFGState& state); 262 ControlStatus processLabelEnd(CFGState& state); 263 ControlStatus processTryEnd(CFGState& state); 264 ControlStatus processReturn(JSOp op); 265 ControlStatus processThrow(); 266 ControlStatus processContinue(JSOp op); 267 ControlStatus processBreak(JSOp op, jssrcnote* sn); 268 ControlStatus maybeLoop(JSOp op, jssrcnote* sn); 269 bool pushLoop(CFGState::State state, jsbytecode* stopAt, MBasicBlock* entry, bool osr, 270 jsbytecode* loopHead, jsbytecode* initialPc, 271 jsbytecode* bodyStart, jsbytecode* bodyEnd, 272 jsbytecode* exitpc, jsbytecode* continuepc); 273 bool analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecode* end); 274 275 MBasicBlock* addBlock(MBasicBlock* block, uint32_t loopDepth); 276 MBasicBlock* newBlock(MBasicBlock* predecessor, jsbytecode* pc); 277 MBasicBlock* newBlock(MBasicBlock* predecessor, jsbytecode* pc, uint32_t loopDepth); 278 MBasicBlock* newBlock(MBasicBlock* predecessor, jsbytecode* pc, MResumePoint* priorResumePoint); 279 MBasicBlock* newBlockPopN(MBasicBlock* predecessor, jsbytecode* pc, uint32_t popped); 280 MBasicBlock* newBlockAfter(MBasicBlock* at, MBasicBlock* predecessor, jsbytecode* pc); 281 MBasicBlock* newOsrPreheader(MBasicBlock* header, jsbytecode* loopEntry, 282 jsbytecode* beforeLoopEntry); 283 MBasicBlock* newPendingLoopHeader(MBasicBlock* predecessor, jsbytecode* pc, bool osr, bool canOsr, 284 unsigned stackPhiCount); newBlock(jsbytecode * pc)285 MBasicBlock* newBlock(jsbytecode* pc) { 286 return newBlock(nullptr, pc); 287 } newBlockAfter(MBasicBlock * at,jsbytecode * pc)288 MBasicBlock* newBlockAfter(MBasicBlock* at, jsbytecode* pc) { 289 return newBlockAfter(at, nullptr, pc); 290 } 291 292 // We want to make sure that our MTest instructions all check whether the 293 // thing being tested might emulate undefined. So we funnel their creation 294 // through this method, to make sure that happens. We don't want to just do 295 // the check in MTest::New, because that can run on background compilation 296 // threads, and we're not sure it's safe to touch that part of the typeset 297 // from a background thread. 298 MTest* newTest(MDefinition* ins, MBasicBlock* ifTrue, MBasicBlock* ifFalse); 299 300 // Given a list of pending breaks, creates a new block and inserts a Goto 301 // linking each break to the new block. 302 MBasicBlock* createBreakCatchBlock(DeferredEdge* edge, jsbytecode* pc); 303 304 // Finishes loops that do not actually loop, containing only breaks and 305 // returns or a do while loop with a condition that is constant false. 306 ControlStatus processBrokenLoop(CFGState& state); 307 308 // Computes loop phis, places them in all successors of a loop, then 309 // handles any pending breaks. 310 ControlStatus finishLoop(CFGState& state, MBasicBlock* successor); 311 312 // Incorporates a type/typeSet into an OSR value for a loop, after the loop 313 // body has been processed. 314 bool addOsrValueTypeBarrier(uint32_t slot, MInstruction** def, 315 MIRType type, TemporaryTypeSet* typeSet); 316 bool maybeAddOsrTypeBarriers(); 317 318 // Restarts processing of a loop if the type information at its header was 319 // incomplete. 320 ControlStatus restartLoop(CFGState state); 321 322 void assertValidLoopHeadOp(jsbytecode* pc); 323 324 ControlStatus forLoop(JSOp op, jssrcnote* sn); 325 ControlStatus whileOrForInLoop(jssrcnote* sn); 326 ControlStatus doWhileLoop(JSOp op, jssrcnote* sn); 327 ControlStatus tableSwitch(JSOp op, jssrcnote* sn); 328 ControlStatus condSwitch(JSOp op, jssrcnote* sn); 329 330 // Please see the Big Honkin' Comment about how resume points work in 331 // IonBuilder.cpp, near the definition for this function. 332 bool resume(MInstruction* ins, jsbytecode* pc, MResumePoint::Mode mode); 333 bool resumeAt(MInstruction* ins, jsbytecode* pc); 334 bool resumeAfter(MInstruction* ins); 335 bool maybeInsertResume(); 336 337 void insertRecompileCheck(); 338 339 void initParameters(); 340 void initLocals(); 341 void rewriteParameter(uint32_t slotIdx, MDefinition* param, int32_t argIndex); 342 void rewriteParameters(); 343 bool initScopeChain(MDefinition* callee = nullptr); 344 bool initArgumentsObject(); 345 bool pushConstant(const Value& v); 346 347 MConstant* constant(const Value& v); 348 MConstant* constantInt(int32_t i); 349 MInstruction* initializedLength(MDefinition* obj, MDefinition* elements, 350 JSValueType unboxedType); 351 MInstruction* setInitializedLength(MDefinition* obj, JSValueType unboxedType, size_t count); 352 353 // Improve the type information at tests 354 bool improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test); 355 bool improveTypesAtCompare(MCompare* ins, bool trueBranch, MTest* test); 356 bool improveTypesAtNullOrUndefinedCompare(MCompare* ins, bool trueBranch, MTest* test); 357 bool improveTypesAtTypeOfCompare(MCompare* ins, bool trueBranch, MTest* test); 358 359 // Used to detect triangular structure at test. 360 bool detectAndOrStructure(MPhi* ins, bool* branchIsTrue); 361 bool replaceTypeSet(MDefinition* subject, TemporaryTypeSet* type, MTest* test); 362 363 // Add a guard which ensure that the set of type which goes through this 364 // generated code correspond to the observed types for the bytecode. 365 MDefinition* addTypeBarrier(MDefinition* def, TemporaryTypeSet* observed, 366 BarrierKind kind, MTypeBarrier** pbarrier = nullptr); 367 bool pushTypeBarrier(MDefinition* def, TemporaryTypeSet* observed, BarrierKind kind); 368 369 // As pushTypeBarrier, but will compute the needBarrier boolean itself based 370 // on observed and the JSFunction that we're planning to call. The 371 // JSFunction must be a DOM method or getter. 372 bool pushDOMTypeBarrier(MInstruction* ins, TemporaryTypeSet* observed, JSFunction* func); 373 374 // If definiteType is not known or def already has the right type, just 375 // returns def. Otherwise, returns an MInstruction that has that definite 376 // type, infallibly unboxing ins as needed. The new instruction will be 377 // added to |current| in this case. 378 MDefinition* ensureDefiniteType(MDefinition* def, MIRType definiteType); 379 380 // Creates a MDefinition based on the given def improved with type as TypeSet. 381 MDefinition* ensureDefiniteTypeSet(MDefinition* def, TemporaryTypeSet* types); 382 383 void maybeMarkEmpty(MDefinition* ins); 384 385 JSObject* getSingletonPrototype(JSFunction* target); 386 387 MDefinition* createThisScripted(MDefinition* callee, MDefinition* newTarget); 388 MDefinition* createThisScriptedSingleton(JSFunction* target, MDefinition* callee); 389 MDefinition* createThisScriptedBaseline(MDefinition* callee); 390 MDefinition* createThis(JSFunction* target, MDefinition* callee, MDefinition* newTarget); 391 MInstruction* createDeclEnvObject(MDefinition* callee, MDefinition* scopeObj); 392 MInstruction* createCallObject(MDefinition* callee, MDefinition* scopeObj); 393 394 MDefinition* walkScopeChain(unsigned hops); 395 396 MInstruction* addConvertElementsToDoubles(MDefinition* elements); 397 MDefinition* addMaybeCopyElementsForWrite(MDefinition* object, bool checkNative); 398 MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length); 399 MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind); 400 MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind); 401 MInstruction* addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind); 402 MInstruction* addSharedTypedArrayGuard(MDefinition* obj); 403 404 MInstruction* 405 addGuardReceiverPolymorphic(MDefinition* obj, const BaselineInspector::ReceiverVector& receivers); 406 407 MDefinition* convertShiftToMaskForStaticTypedArray(MDefinition* id, 408 Scalar::Type viewType); 409 410 bool invalidatedIdempotentCache(); 411 412 bool hasStaticScopeObject(ScopeCoordinate sc, JSObject** pcall); 413 bool loadSlot(MDefinition* obj, size_t slot, size_t nfixed, MIRType rvalType, 414 BarrierKind barrier, TemporaryTypeSet* types); 415 bool loadSlot(MDefinition* obj, Shape* shape, MIRType rvalType, 416 BarrierKind barrier, TemporaryTypeSet* types); 417 bool storeSlot(MDefinition* obj, size_t slot, size_t nfixed, 418 MDefinition* value, bool needsBarrier, 419 MIRType slotType = MIRType_None); 420 bool storeSlot(MDefinition* obj, Shape* shape, MDefinition* value, bool needsBarrier, 421 MIRType slotType = MIRType_None); 422 bool shouldAbortOnPreliminaryGroups(MDefinition *obj); 423 424 MDefinition* tryInnerizeWindow(MDefinition* obj); 425 MDefinition* maybeUnboxForPropertyAccess(MDefinition* def); 426 427 // jsop_getprop() helpers. 428 bool checkIsDefinitelyOptimizedArguments(MDefinition* obj, bool* isOptimizedArgs); 429 bool getPropTryInferredConstant(bool* emitted, MDefinition* obj, PropertyName* name, 430 TemporaryTypeSet* types); 431 bool getPropTryArgumentsLength(bool* emitted, MDefinition* obj); 432 bool getPropTryArgumentsCallee(bool* emitted, MDefinition* obj, PropertyName* name); 433 bool getPropTryConstant(bool* emitted, MDefinition* obj, jsid id, TemporaryTypeSet* types); 434 bool getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name, 435 BarrierKind barrier, TemporaryTypeSet* types); 436 bool getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyName* name, 437 BarrierKind barrier, TemporaryTypeSet* types); 438 bool getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name, 439 BarrierKind barrier, TemporaryTypeSet* types); 440 bool getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName* name, 441 TemporaryTypeSet* types); 442 bool getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name, 443 BarrierKind barrier, TemporaryTypeSet* types); 444 bool getPropTrySimdGetter(bool* emitted, MDefinition* obj, PropertyName* name); 445 bool getPropTryTypedObject(bool* emitted, MDefinition* obj, PropertyName* name); 446 bool getPropTryScalarPropOfTypedObject(bool* emitted, MDefinition* typedObj, 447 int32_t fieldOffset, 448 TypedObjectPrediction fieldTypeReprs); 449 bool getPropTryReferencePropOfTypedObject(bool* emitted, MDefinition* typedObj, 450 int32_t fieldOffset, 451 TypedObjectPrediction fieldPrediction, 452 PropertyName* name); 453 bool getPropTryComplexPropOfTypedObject(bool* emitted, MDefinition* typedObj, 454 int32_t fieldOffset, 455 TypedObjectPrediction fieldTypeReprs, 456 size_t fieldIndex); 457 bool getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* name, 458 TemporaryTypeSet* types); 459 bool getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name, 460 BarrierKind barrier, TemporaryTypeSet* types); 461 bool getPropTrySharedStub(bool* emitted, MDefinition* obj); 462 463 // jsop_setprop() helpers. 464 bool setPropTryCommonSetter(bool* emitted, MDefinition* obj, 465 PropertyName* name, MDefinition* value); 466 bool setPropTryCommonDOMSetter(bool* emitted, MDefinition* obj, 467 MDefinition* value, JSFunction* setter, 468 TemporaryTypeSet* objTypes); 469 bool setPropTryDefiniteSlot(bool* emitted, MDefinition* obj, 470 PropertyName* name, MDefinition* value, 471 bool barrier, TemporaryTypeSet* objTypes); 472 bool setPropTryUnboxed(bool* emitted, MDefinition* obj, 473 PropertyName* name, MDefinition* value, 474 bool barrier, TemporaryTypeSet* objTypes); 475 bool setPropTryInlineAccess(bool* emitted, MDefinition* obj, 476 PropertyName* name, MDefinition* value, 477 bool barrier, TemporaryTypeSet* objTypes); 478 bool setPropTryTypedObject(bool* emitted, MDefinition* obj, 479 PropertyName* name, MDefinition* value); 480 bool setPropTryReferencePropOfTypedObject(bool* emitted, 481 MDefinition* obj, 482 int32_t fieldOffset, 483 MDefinition* value, 484 TypedObjectPrediction fieldPrediction, 485 PropertyName* name); 486 bool setPropTryScalarPropOfTypedObject(bool* emitted, 487 MDefinition* obj, 488 int32_t fieldOffset, 489 MDefinition* value, 490 TypedObjectPrediction fieldTypeReprs); 491 bool setPropTryCache(bool* emitted, MDefinition* obj, 492 PropertyName* name, MDefinition* value, 493 bool barrier, TemporaryTypeSet* objTypes); 494 495 // jsop_binary_arith helpers. 496 MBinaryArithInstruction* binaryArithInstruction(JSOp op, MDefinition* left, MDefinition* right); 497 bool binaryArithTryConcat(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); 498 bool binaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); 499 bool binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* left, 500 MDefinition* right); 501 bool arithTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); 502 503 // jsop_bitnot helpers. 504 bool bitnotTrySpecialized(bool* emitted, MDefinition* input); 505 506 // jsop_compare helpes. 507 bool compareTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); 508 bool compareTryBitwise(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); 509 bool compareTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* left, 510 MDefinition* right); 511 bool compareTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); 512 513 // binary data lookup helpers. 514 TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj); 515 TypedObjectPrediction typedObjectPrediction(TemporaryTypeSet* types); 516 bool typedObjectHasField(MDefinition* typedObj, 517 PropertyName* name, 518 size_t* fieldOffset, 519 TypedObjectPrediction* fieldTypeReprs, 520 size_t* fieldIndex); 521 MDefinition* loadTypedObjectType(MDefinition* value); 522 void loadTypedObjectData(MDefinition* typedObj, 523 MDefinition** owner, 524 LinearSum* ownerOffset); 525 void loadTypedObjectElements(MDefinition* typedObj, 526 const LinearSum& byteOffset, 527 int32_t scale, 528 MDefinition** ownerElements, 529 MDefinition** ownerScaledOffset, 530 int32_t* ownerByteAdjustment); 531 MDefinition* typeObjectForElementFromArrayStructType(MDefinition* typedObj); 532 MDefinition* typeObjectForFieldFromStructType(MDefinition* type, 533 size_t fieldIndex); 534 bool storeReferenceTypedObjectValue(MDefinition* typedObj, 535 const LinearSum& byteOffset, 536 ReferenceTypeDescr::Type type, 537 MDefinition* value, 538 PropertyName* name); 539 bool storeScalarTypedObjectValue(MDefinition* typedObj, 540 const LinearSum& byteOffset, 541 ScalarTypeDescr::Type type, 542 MDefinition* value); 543 bool checkTypedObjectIndexInBounds(int32_t elemSize, 544 MDefinition* obj, 545 MDefinition* index, 546 TypedObjectPrediction objTypeDescrs, 547 LinearSum* indexAsByteOffset); 548 bool pushDerivedTypedObject(bool* emitted, 549 MDefinition* obj, 550 const LinearSum& byteOffset, 551 TypedObjectPrediction derivedTypeDescrs, 552 MDefinition* derivedTypeObj); 553 bool pushScalarLoadFromTypedObject(MDefinition* obj, 554 const LinearSum& byteoffset, 555 ScalarTypeDescr::Type type); 556 bool pushReferenceLoadFromTypedObject(MDefinition* typedObj, 557 const LinearSum& byteOffset, 558 ReferenceTypeDescr::Type type, 559 PropertyName* name); 560 MDefinition* neuterCheck(MDefinition* obj); 561 JSObject* getStaticTypedArrayObject(MDefinition* obj, MDefinition* index); 562 563 // jsop_setelem() helpers. 564 bool setElemTryTypedArray(bool* emitted, MDefinition* object, 565 MDefinition* index, MDefinition* value); 566 bool setElemTryTypedObject(bool* emitted, MDefinition* obj, 567 MDefinition* index, MDefinition* value); 568 bool setElemTryTypedStatic(bool* emitted, MDefinition* object, 569 MDefinition* index, MDefinition* value); 570 bool setElemTryDense(bool* emitted, MDefinition* object, 571 MDefinition* index, MDefinition* value, bool writeHole); 572 bool setElemTryArguments(bool* emitted, MDefinition* object, 573 MDefinition* index, MDefinition* value); 574 bool setElemTryCache(bool* emitted, MDefinition* object, 575 MDefinition* index, MDefinition* value); 576 bool setElemTryReferenceElemOfTypedObject(bool* emitted, 577 MDefinition* obj, 578 MDefinition* index, 579 TypedObjectPrediction objPrediction, 580 MDefinition* value, 581 TypedObjectPrediction elemPrediction); 582 bool setElemTryScalarElemOfTypedObject(bool* emitted, 583 MDefinition* obj, 584 MDefinition* index, 585 TypedObjectPrediction objTypeReprs, 586 MDefinition* value, 587 TypedObjectPrediction elemTypeReprs, 588 int32_t elemSize); 589 bool initializeArrayElement(MDefinition* obj, size_t index, MDefinition* value, 590 JSValueType unboxedType, 591 bool addResumePointAndIncrementInitializedLength); 592 593 // jsop_getelem() helpers. 594 bool getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index); 595 bool getElemTryGetProp(bool* emitted, MDefinition* obj, MDefinition* index); 596 bool getElemTryTypedStatic(bool* emitted, MDefinition* obj, MDefinition* index); 597 bool getElemTryTypedArray(bool* emitted, MDefinition* obj, MDefinition* index); 598 bool getElemTryTypedObject(bool* emitted, MDefinition* obj, MDefinition* index); 599 bool getElemTryString(bool* emitted, MDefinition* obj, MDefinition* index); 600 bool getElemTryArguments(bool* emitted, MDefinition* obj, MDefinition* index); 601 bool getElemTryArgumentsInlined(bool* emitted, MDefinition* obj, MDefinition* index); 602 bool getElemTryCache(bool* emitted, MDefinition* obj, MDefinition* index); 603 bool getElemTryScalarElemOfTypedObject(bool* emitted, 604 MDefinition* obj, 605 MDefinition* index, 606 TypedObjectPrediction objTypeReprs, 607 TypedObjectPrediction elemTypeReprs, 608 int32_t elemSize); 609 bool getElemTryReferenceElemOfTypedObject(bool* emitted, 610 MDefinition* obj, 611 MDefinition* index, 612 TypedObjectPrediction objPrediction, 613 TypedObjectPrediction elemPrediction); 614 bool getElemTryComplexElemOfTypedObject(bool* emitted, 615 MDefinition* obj, 616 MDefinition* index, 617 TypedObjectPrediction objTypeReprs, 618 TypedObjectPrediction elemTypeReprs, 619 int32_t elemSize); 620 TemporaryTypeSet* computeHeapType(const TemporaryTypeSet* objTypes, const jsid id); 621 622 enum BoundsChecking { DoBoundsCheck, SkipBoundsCheck }; 623 624 // Add instructions to compute a typed array's length and data. Also 625 // optionally convert |*index| into a bounds-checked definition, if 626 // requested. 627 // 628 // If you only need the array's length, use addTypedArrayLength below. 629 void addTypedArrayLengthAndData(MDefinition* obj, 630 BoundsChecking checking, 631 MDefinition** index, 632 MInstruction** length, MInstruction** elements); 633 634 // Add an instruction to compute a typed array's length to the current 635 // block. If you also need the typed array's data, use the above method 636 // instead. addTypedArrayLength(MDefinition * obj)637 MInstruction* addTypedArrayLength(MDefinition* obj) { 638 MInstruction* length; 639 addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr); 640 return length; 641 } 642 643 bool improveThisTypesForCall(); 644 645 MDefinition* getCallee(); 646 MDefinition* getAliasedVar(ScopeCoordinate sc); 647 MDefinition* addLexicalCheck(MDefinition* input); 648 649 bool tryFoldInstanceOf(MDefinition* lhs, JSObject* protoObject); 650 bool hasOnProtoChain(TypeSet::ObjectKey* key, JSObject* protoObject, bool* hasOnProto); 651 652 bool jsop_add(MDefinition* left, MDefinition* right); 653 bool jsop_bitnot(); 654 bool jsop_bitop(JSOp op); 655 bool jsop_binary_arith(JSOp op); 656 bool jsop_binary_arith(JSOp op, MDefinition* left, MDefinition* right); 657 bool jsop_pow(); 658 bool jsop_pos(); 659 bool jsop_neg(); 660 bool jsop_tostring(); 661 bool jsop_setarg(uint32_t arg); 662 bool jsop_defvar(uint32_t index); 663 bool jsop_deflexical(uint32_t index); 664 bool jsop_deffun(uint32_t index); 665 bool jsop_notearg(); 666 bool jsop_throwsetconst(); 667 bool jsop_checklexical(); 668 bool jsop_checkaliasedlet(ScopeCoordinate sc); 669 bool jsop_funcall(uint32_t argc); 670 bool jsop_funapply(uint32_t argc); 671 bool jsop_funapplyarguments(uint32_t argc); 672 bool jsop_funapplyarray(uint32_t argc); 673 bool jsop_call(uint32_t argc, bool constructing); 674 bool jsop_eval(uint32_t argc); 675 bool jsop_ifeq(JSOp op); 676 bool jsop_try(); 677 bool jsop_label(); 678 bool jsop_condswitch(); 679 bool jsop_andor(JSOp op); 680 bool jsop_dup2(); 681 bool jsop_loophead(jsbytecode* pc); 682 bool jsop_compare(JSOp op); 683 bool jsop_compare(JSOp op, MDefinition* left, MDefinition* right); 684 bool getStaticName(JSObject* staticObject, PropertyName* name, bool* psucceeded, 685 MDefinition* lexicalCheck = nullptr); 686 bool setStaticName(JSObject* staticObject, PropertyName* name); 687 bool jsop_getgname(PropertyName* name); 688 bool jsop_getname(PropertyName* name); 689 bool jsop_intrinsic(PropertyName* name); 690 bool jsop_getimport(PropertyName* name); 691 bool jsop_bindname(PropertyName* name); 692 bool jsop_getelem(); 693 bool jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType unboxedType); 694 bool jsop_getelem_typed(MDefinition* obj, MDefinition* index, ScalarTypeDescr::Type arrayType); 695 bool jsop_setelem(); 696 bool jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion, 697 MDefinition* object, MDefinition* index, MDefinition* value, 698 JSValueType unboxedType, bool writeHole); 699 bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType, 700 MDefinition* object, MDefinition* index, MDefinition* value); 701 bool jsop_length(); 702 bool jsop_length_fastPath(); 703 bool jsop_arguments(); 704 bool jsop_arguments_getelem(); 705 bool jsop_runonce(); 706 bool jsop_rest(); 707 bool jsop_not(); 708 bool jsop_getprop(PropertyName* name); 709 bool jsop_setprop(PropertyName* name); 710 bool jsop_delprop(PropertyName* name); 711 bool jsop_delelem(); 712 bool jsop_newarray(uint32_t length); 713 bool jsop_newarray_copyonwrite(); 714 bool jsop_newobject(); 715 bool jsop_initelem(); 716 bool jsop_initelem_array(); 717 bool jsop_initelem_getter_setter(); 718 bool jsop_mutateproto(); 719 bool jsop_initprop(PropertyName* name); 720 bool jsop_initprop_getter_setter(PropertyName* name); 721 bool jsop_regexp(RegExpObject* reobj); 722 bool jsop_object(JSObject* obj); 723 bool jsop_lambda(JSFunction* fun); 724 bool jsop_lambda_arrow(JSFunction* fun); 725 bool jsop_functionthis(); 726 bool jsop_globalthis(); 727 bool jsop_typeof(); 728 bool jsop_toid(); 729 bool jsop_iter(uint8_t flags); 730 bool jsop_itermore(); 731 bool jsop_isnoiter(); 732 bool jsop_iterend(); 733 bool jsop_in(); 734 bool jsop_in_dense(MDefinition* obj, MDefinition* id, JSValueType unboxedType); 735 bool jsop_instanceof(); 736 bool jsop_getaliasedvar(ScopeCoordinate sc); 737 bool jsop_setaliasedvar(ScopeCoordinate sc); 738 bool jsop_debugger(); 739 bool jsop_newtarget(); 740 bool jsop_checkobjcoercible(); 741 742 /* Inlining. */ 743 744 enum InliningStatus 745 { 746 InliningStatus_Error, 747 InliningStatus_NotInlined, 748 InliningStatus_WarmUpCountTooLow, 749 InliningStatus_Inlined 750 }; 751 752 enum InliningDecision 753 { 754 InliningDecision_Error, 755 InliningDecision_Inline, 756 InliningDecision_DontInline, 757 InliningDecision_WarmUpCountTooLow 758 }; 759 760 static InliningDecision DontInline(JSScript* targetScript, const char* reason); 761 762 // Helper function for canInlineTarget 763 bool hasCommonInliningPath(const JSScript* scriptToInline); 764 765 // Oracles. 766 InliningDecision canInlineTarget(JSFunction* target, CallInfo& callInfo); 767 InliningDecision makeInliningDecision(JSObject* target, CallInfo& callInfo); 768 bool selectInliningTargets(const ObjectVector& targets, CallInfo& callInfo, 769 BoolVector& choiceSet, uint32_t* numInlineable); 770 771 // Native inlining helpers. 772 // The typeset for the return value of our function. These are 773 // the types it's been observed returning in the past. 774 TemporaryTypeSet* getInlineReturnTypeSet(); 775 // The known MIR type of getInlineReturnTypeSet. 776 MIRType getInlineReturnType(); 777 778 // Array natives. 779 InliningStatus inlineArray(CallInfo& callInfo); 780 InliningStatus inlineArrayIsArray(CallInfo& callInfo); 781 InliningStatus inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode); 782 InliningStatus inlineArrayPush(CallInfo& callInfo); 783 InliningStatus inlineArrayConcat(CallInfo& callInfo); 784 InliningStatus inlineArraySlice(CallInfo& callInfo); 785 InliningStatus inlineArrayJoin(CallInfo& callInfo); 786 InliningStatus inlineArraySplice(CallInfo& callInfo); 787 788 // Math natives. 789 InliningStatus inlineMathAbs(CallInfo& callInfo); 790 InliningStatus inlineMathFloor(CallInfo& callInfo); 791 InliningStatus inlineMathCeil(CallInfo& callInfo); 792 InliningStatus inlineMathClz32(CallInfo& callInfo); 793 InliningStatus inlineMathRound(CallInfo& callInfo); 794 InliningStatus inlineMathSqrt(CallInfo& callInfo); 795 InliningStatus inlineMathAtan2(CallInfo& callInfo); 796 InliningStatus inlineMathHypot(CallInfo& callInfo); 797 InliningStatus inlineMathMinMax(CallInfo& callInfo, bool max); 798 InliningStatus inlineMathPow(CallInfo& callInfo); 799 InliningStatus inlineMathPowHelper(MDefinition* lhs, MDefinition* rhs, MIRType outputType); 800 InliningStatus inlineMathRandom(CallInfo& callInfo); 801 InliningStatus inlineMathImul(CallInfo& callInfo); 802 InliningStatus inlineMathFRound(CallInfo& callInfo); 803 InliningStatus inlineMathFunction(CallInfo& callInfo, MMathFunction::Function function); 804 805 // String natives. 806 InliningStatus inlineStringObject(CallInfo& callInfo); 807 InliningStatus inlineConstantStringSplit(CallInfo& callInfo); 808 InliningStatus inlineStringSplit(CallInfo& callInfo); 809 InliningStatus inlineStrCharCodeAt(CallInfo& callInfo); 810 InliningStatus inlineConstantCharCodeAt(CallInfo& callInfo); 811 InliningStatus inlineStrFromCharCode(CallInfo& callInfo); 812 InliningStatus inlineStrCharAt(CallInfo& callInfo); 813 InliningStatus inlineStrReplace(CallInfo& callInfo); 814 815 // RegExp natives. 816 InliningStatus inlineRegExpExec(CallInfo& callInfo); 817 InliningStatus inlineRegExpTest(CallInfo& callInfo); 818 819 // Object natives and intrinsics. 820 InliningStatus inlineObjectCreate(CallInfo& callInfo); 821 InliningStatus inlineDefineDataProperty(CallInfo& callInfo); 822 823 // Atomics natives. 824 InliningStatus inlineAtomicsCompareExchange(CallInfo& callInfo); 825 InliningStatus inlineAtomicsExchange(CallInfo& callInfo); 826 InliningStatus inlineAtomicsLoad(CallInfo& callInfo); 827 InliningStatus inlineAtomicsStore(CallInfo& callInfo); 828 InliningStatus inlineAtomicsFence(CallInfo& callInfo); 829 InliningStatus inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target); 830 InliningStatus inlineAtomicsIsLockFree(CallInfo& callInfo); 831 832 // Slot intrinsics. 833 InliningStatus inlineUnsafeSetReservedSlot(CallInfo& callInfo); 834 InliningStatus inlineUnsafeGetReservedSlot(CallInfo& callInfo, 835 MIRType knownValueType); 836 837 // TypedArray intrinsics. 838 enum WrappingBehavior { AllowWrappedTypedArrays, RejectWrappedTypedArrays }; 839 InliningStatus inlineIsTypedArrayHelper(CallInfo& callInfo, WrappingBehavior wrappingBehavior); 840 InliningStatus inlineIsTypedArray(CallInfo& callInfo); 841 InliningStatus inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo); 842 InliningStatus inlineTypedArrayLength(CallInfo& callInfo); 843 InliningStatus inlineSetDisjointTypedElements(CallInfo& callInfo); 844 845 // TypedObject intrinsics and natives. 846 InliningStatus inlineObjectIsTypeDescr(CallInfo& callInfo); 847 InliningStatus inlineSetTypedObjectOffset(CallInfo& callInfo); 848 InliningStatus inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* target); 849 850 // SIMD intrinsics and natives. 851 InliningStatus inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* target); 852 853 // helpers 854 static MIRType SimdTypeDescrToMIRType(SimdTypeDescr::Type type); 855 bool checkInlineSimd(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type, 856 unsigned numArgs, InlineTypedObject** templateObj); 857 IonBuilder::InliningStatus boxSimd(CallInfo& callInfo, MInstruction* ins, 858 InlineTypedObject* templateObj); 859 860 InliningStatus inlineSimdInt32x4(CallInfo& callInfo, JSNative native); 861 InliningStatus inlineSimdFloat32x4(CallInfo& callInfo, JSNative native); 862 863 template <typename T> 864 InliningStatus inlineBinarySimd(CallInfo& callInfo, JSNative native, 865 typename T::Operation op, SimdTypeDescr::Type type); 866 InliningStatus inlineCompSimd(CallInfo& callInfo, JSNative native, 867 MSimdBinaryComp::Operation op, SimdTypeDescr::Type compType); 868 InliningStatus inlineUnarySimd(CallInfo& callInfo, JSNative native, 869 MSimdUnaryArith::Operation op, SimdTypeDescr::Type type); 870 InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native, 871 SimdTypeDescr::Type type); 872 InliningStatus inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, 873 SimdTypeDescr::Type type); 874 InliningStatus inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type); 875 InliningStatus inlineSimdShuffle(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type, 876 unsigned numVectors, unsigned numLanes); 877 InliningStatus inlineSimdCheck(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type); 878 InliningStatus inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast, 879 SimdTypeDescr::Type from, SimdTypeDescr::Type to); 880 InliningStatus inlineSimdSelect(CallInfo& callInfo, JSNative native, bool isElementWise, 881 SimdTypeDescr::Type type); 882 883 bool prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, MInstruction** elements, 884 MDefinition** index, Scalar::Type* arrayType); 885 InliningStatus inlineSimdLoad(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type, 886 unsigned numElems); 887 InliningStatus inlineSimdStore(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type, 888 unsigned numElems); 889 890 // Utility intrinsics. 891 InliningStatus inlineIsCallable(CallInfo& callInfo); 892 InliningStatus inlineIsObject(CallInfo& callInfo); 893 InliningStatus inlineToObject(CallInfo& callInfo); 894 InliningStatus inlineToInteger(CallInfo& callInfo); 895 InliningStatus inlineToString(CallInfo& callInfo); 896 InliningStatus inlineDump(CallInfo& callInfo); 897 InliningStatus inlineHasClass(CallInfo& callInfo, const Class* clasp, 898 const Class* clasp2 = nullptr, 899 const Class* clasp3 = nullptr, 900 const Class* clasp4 = nullptr); 901 InliningStatus inlineIsConstructing(CallInfo& callInfo); 902 InliningStatus inlineSubstringKernel(CallInfo& callInfo); 903 904 // Testing functions. 905 InliningStatus inlineBailout(CallInfo& callInfo); 906 InliningStatus inlineAssertFloat32(CallInfo& callInfo); 907 InliningStatus inlineAssertRecoveredOnBailout(CallInfo& callInfo); 908 909 // Bind function. 910 InliningStatus inlineBoundFunction(CallInfo& callInfo, JSFunction* target); 911 912 // Main inlining functions 913 InliningStatus inlineNativeCall(CallInfo& callInfo, JSFunction* target); 914 InliningStatus inlineNativeGetter(CallInfo& callInfo, JSFunction* target); 915 InliningStatus inlineNonFunctionCall(CallInfo& callInfo, JSObject* target); 916 bool inlineScriptedCall(CallInfo& callInfo, JSFunction* target); 917 InliningStatus inlineSingleCall(CallInfo& callInfo, JSObject* target); 918 919 // Call functions 920 InliningStatus inlineCallsite(const ObjectVector& targets, CallInfo& callInfo); 921 bool inlineCalls(CallInfo& callInfo, const ObjectVector& targets, BoolVector& choiceSet, 922 MGetPropertyCache* maybeCache); 923 924 // Inlining helpers. 925 bool inlineGenericFallback(JSFunction* target, CallInfo& callInfo, MBasicBlock* dispatchBlock); 926 bool inlineObjectGroupFallback(CallInfo& callInfo, MBasicBlock* dispatchBlock, 927 MObjectGroupDispatch* dispatch, MGetPropertyCache* cache, 928 MBasicBlock** fallbackTarget); 929 930 enum AtomicCheckResult { 931 DontCheckAtomicResult, 932 DoCheckAtomicResult 933 }; 934 935 bool atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayElementType, 936 bool* requiresDynamicCheck, 937 AtomicCheckResult checkResult=DoCheckAtomicResult); 938 void atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index); 939 940 bool testNeedsArgumentCheck(JSFunction* target, CallInfo& callInfo); 941 942 MCall* makeCallHelper(JSFunction* target, CallInfo& callInfo); 943 bool makeCall(JSFunction* target, CallInfo& callInfo); 944 945 MDefinition* patchInlinedReturn(CallInfo& callInfo, MBasicBlock* exit, MBasicBlock* bottom); 946 MDefinition* patchInlinedReturns(CallInfo& callInfo, MIRGraphReturns& returns, 947 MBasicBlock* bottom); 948 MDefinition* specializeInlinedReturn(MDefinition* rdef, MBasicBlock* exit); 949 950 bool objectsHaveCommonPrototype(TemporaryTypeSet* types, PropertyName* name, 951 bool isGetter, JSObject* foundProto, bool* guardGlobal); 952 void freezePropertiesForCommonPrototype(TemporaryTypeSet* types, PropertyName* name, 953 JSObject* foundProto, bool allowEmptyTypesForGlobal = false); 954 /* 955 * Callers must pass a non-null globalGuard if they pass a non-null globalShape. 956 */ 957 bool testCommonGetterSetter(TemporaryTypeSet* types, PropertyName* name, 958 bool isGetter, JSObject* foundProto, Shape* lastProperty, 959 JSFunction* getterOrSetter, 960 MDefinition** guard, Shape* globalShape = nullptr, 961 MDefinition** globalGuard = nullptr); 962 bool testShouldDOMCall(TypeSet* inTypes, 963 JSFunction* func, JSJitInfo::OpType opType); 964 965 MDefinition* 966 addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape, 967 const BaselineInspector::ReceiverVector& receivers, 968 const BaselineInspector::ObjectGroupVector& convertUnboxedGroups, 969 bool isOwnProperty); 970 971 bool annotateGetPropertyCache(MDefinition* obj, PropertyName* name, 972 MGetPropertyCache* getPropCache, TemporaryTypeSet* objTypes, 973 TemporaryTypeSet* pushedTypes); 974 975 MGetPropertyCache* getInlineableGetPropertyCache(CallInfo& callInfo); 976 977 JSObject* testGlobalLexicalBinding(PropertyName* name); 978 979 JSObject* testSingletonProperty(JSObject* obj, jsid id); 980 JSObject* testSingletonPropertyTypes(MDefinition* obj, jsid id); 981 982 uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed); 983 MDefinition* convertUnboxedObjects(MDefinition* obj); 984 MDefinition* convertUnboxedObjects(MDefinition* obj, 985 const BaselineInspector::ObjectGroupVector& list); 986 uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name, 987 JSValueType* punboxedType); 988 MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType, 989 BarrierKind barrier, TemporaryTypeSet* types); 990 MInstruction* loadUnboxedValue(MDefinition* elements, size_t elementsOffset, 991 MDefinition* scaledOffset, JSValueType unboxedType, 992 BarrierKind barrier, TemporaryTypeSet* types); 993 MInstruction* storeUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType, 994 MDefinition* value); 995 MInstruction* storeUnboxedValue(MDefinition* obj, 996 MDefinition* elements, int32_t elementsOffset, 997 MDefinition* scaledOffset, JSValueType unboxedType, 998 MDefinition* value, bool preBarrier = true); 999 bool checkPreliminaryGroups(MDefinition *obj); 1000 bool freezePropTypeSets(TemporaryTypeSet* types, 1001 JSObject* foundProto, PropertyName* name); 1002 bool canInlinePropertyOpShapes(const BaselineInspector::ReceiverVector& receivers); 1003 1004 TemporaryTypeSet* bytecodeTypes(jsbytecode* pc); 1005 1006 // Use one of the below methods for updating the current block, rather than 1007 // updating |current| directly. setCurrent() should only be used in cases 1008 // where the block cannot have phis whose type needs to be computed. 1009 setCurrentAndSpecializePhis(MBasicBlock * block)1010 bool setCurrentAndSpecializePhis(MBasicBlock* block) { 1011 if (block) { 1012 if (!block->specializePhis()) 1013 return false; 1014 } 1015 setCurrent(block); 1016 return true; 1017 } 1018 setCurrent(MBasicBlock * block)1019 void setCurrent(MBasicBlock* block) { 1020 current = block; 1021 } 1022 1023 // A builder is inextricably tied to a particular script. 1024 JSScript* script_; 1025 1026 // script->hasIonScript() at the start of the compilation. Used to avoid 1027 // calling hasIonScript() from background compilation threads. 1028 bool scriptHasIonScript_; 1029 1030 // If off thread compilation is successful, the final code generator is 1031 // attached here. Code has been generated, but not linked (there is not yet 1032 // an IonScript). This is heap allocated, and must be explicitly destroyed, 1033 // performed by FinishOffThreadBuilder(). 1034 CodeGenerator* backgroundCodegen_; 1035 1036 // Some aborts are actionable (e.g., using an unsupported bytecode). When 1037 // optimization tracking is enabled, the location and message of the abort 1038 // are recorded here so they may be propagated to the script's 1039 // corresponding JitcodeGlobalEntry::BaselineEntry. 1040 JSScript* actionableAbortScript_; 1041 jsbytecode* actionableAbortPc_; 1042 const char* actionableAbortMessage_; 1043 1044 MRootList* rootList_; 1045 1046 public: setRootList(MRootList & rootList)1047 void setRootList(MRootList& rootList) { 1048 MOZ_ASSERT(!rootList_); 1049 rootList_ = &rootList; 1050 } 1051 void clearForBackEnd(); 1052 JSObject* checkNurseryObject(JSObject* obj); 1053 script()1054 JSScript* script() const { return script_; } scriptHasIonScript()1055 bool scriptHasIonScript() const { return scriptHasIonScript_; } 1056 backgroundCodegen()1057 CodeGenerator* backgroundCodegen() const { return backgroundCodegen_; } setBackgroundCodegen(CodeGenerator * codegen)1058 void setBackgroundCodegen(CodeGenerator* codegen) { backgroundCodegen_ = codegen; } 1059 constraints()1060 CompilerConstraintList* constraints() { 1061 return constraints_; 1062 } 1063 isInlineBuilder()1064 bool isInlineBuilder() const { 1065 return callerBuilder_ != nullptr; 1066 } 1067 names()1068 const JSAtomState& names() { return compartment->runtime()->names(); } 1069 hadActionableAbort()1070 bool hadActionableAbort() const { 1071 MOZ_ASSERT(!actionableAbortScript_ || 1072 (actionableAbortPc_ && actionableAbortMessage_)); 1073 return actionableAbortScript_ != nullptr; 1074 } 1075 actionableAbortLocationAndMessage(JSScript ** abortScript,jsbytecode ** abortPc,const char ** abortMessage)1076 void actionableAbortLocationAndMessage(JSScript** abortScript, jsbytecode** abortPc, 1077 const char** abortMessage) 1078 { 1079 MOZ_ASSERT(hadActionableAbort()); 1080 *abortScript = actionableAbortScript_; 1081 *abortPc = actionableAbortPc_; 1082 *abortMessage = actionableAbortMessage_; 1083 } 1084 1085 void trace(JSTracer* trc); 1086 1087 private: 1088 bool init(); 1089 1090 JSContext* analysisContext; 1091 BaselineFrameInspector* baselineFrame_; 1092 1093 // Constraints for recording dependencies on type information. 1094 CompilerConstraintList* constraints_; 1095 1096 // Basic analysis information about the script. 1097 BytecodeAnalysis analysis_; analysis()1098 BytecodeAnalysis& analysis() { 1099 return analysis_; 1100 } 1101 1102 TemporaryTypeSet* thisTypes; 1103 TemporaryTypeSet* argTypes; 1104 TemporaryTypeSet* typeArray; 1105 uint32_t typeArrayHint; 1106 uint32_t* bytecodeTypeMap; 1107 1108 GSNCache gsn; 1109 ScopeCoordinateNameCache scopeCoordinateNameCache; 1110 1111 jsbytecode* pc; 1112 MBasicBlock* current; 1113 uint32_t loopDepth_; 1114 1115 Vector<BytecodeSite*, 0, JitAllocPolicy> trackedOptimizationSites_; 1116 bytecodeSite(jsbytecode * pc)1117 BytecodeSite* bytecodeSite(jsbytecode* pc) { 1118 MOZ_ASSERT(info().inlineScriptTree()->script()->containsPC(pc)); 1119 // See comment in maybeTrackedOptimizationSite. 1120 if (isOptimizationTrackingEnabled()) { 1121 if (BytecodeSite* site = maybeTrackedOptimizationSite(pc)) 1122 return site; 1123 } 1124 return new(alloc()) BytecodeSite(info().inlineScriptTree(), pc); 1125 } 1126 1127 BytecodeSite* maybeTrackedOptimizationSite(jsbytecode* pc); 1128 1129 MDefinition* lexicalCheck_; 1130 setLexicalCheck(MDefinition * lexical)1131 void setLexicalCheck(MDefinition* lexical) { 1132 MOZ_ASSERT(!lexicalCheck_); 1133 lexicalCheck_ = lexical; 1134 } takeLexicalCheck()1135 MDefinition* takeLexicalCheck() { 1136 MDefinition* lexical = lexicalCheck_; 1137 lexicalCheck_ = nullptr; 1138 return lexical; 1139 } 1140 1141 /* Information used for inline-call builders. */ 1142 MResumePoint* callerResumePoint_; callerPC()1143 jsbytecode* callerPC() { 1144 return callerResumePoint_ ? callerResumePoint_->pc() : nullptr; 1145 } 1146 IonBuilder* callerBuilder_; 1147 1148 IonBuilder* outermostBuilder(); 1149 oom()1150 bool oom() { 1151 abortReason_ = AbortReason_Alloc; 1152 return false; 1153 } 1154 1155 struct LoopHeader { 1156 jsbytecode* pc; 1157 MBasicBlock* header; 1158 LoopHeaderLoopHeader1159 LoopHeader(jsbytecode* pc, MBasicBlock* header) 1160 : pc(pc), header(header) 1161 {} 1162 }; 1163 1164 Vector<CFGState, 8, JitAllocPolicy> cfgStack_; 1165 Vector<ControlFlowInfo, 4, JitAllocPolicy> loops_; 1166 Vector<ControlFlowInfo, 0, JitAllocPolicy> switches_; 1167 Vector<ControlFlowInfo, 2, JitAllocPolicy> labels_; 1168 Vector<MInstruction*, 2, JitAllocPolicy> iterators_; 1169 Vector<LoopHeader, 0, JitAllocPolicy> loopHeaders_; 1170 BaselineInspector* inspector; 1171 1172 size_t inliningDepth_; 1173 1174 // Total bytecode length of all inlined scripts. Only tracked for the 1175 // outermost builder. 1176 size_t inlinedBytecodeLength_; 1177 1178 // Cutoff to disable compilation if excessive time is spent reanalyzing 1179 // loop bodies to compute a fixpoint of the types for loop variables. 1180 static const size_t MAX_LOOP_RESTARTS = 40; 1181 size_t numLoopRestarts_; 1182 1183 // True if script->failedBoundsCheck is set for the current script or 1184 // an outer script. 1185 bool failedBoundsCheck_; 1186 1187 // True if script->failedShapeGuard is set for the current script or 1188 // an outer script. 1189 bool failedShapeGuard_; 1190 1191 // True if script->failedLexicalCheck_ is set for the current script or 1192 // an outer script. 1193 bool failedLexicalCheck_; 1194 1195 // Has an iterator other than 'for in'. 1196 bool nonStringIteration_; 1197 1198 // If this script can use a lazy arguments object, it will be pre-created 1199 // here. 1200 MInstruction* lazyArguments_; 1201 1202 // If this is an inline builder, the call info for the builder. 1203 const CallInfo* inlineCallInfo_; 1204 1205 // When compiling a call with multiple targets, we are first creating a 1206 // MGetPropertyCache. This MGetPropertyCache is following the bytecode, and 1207 // is used to recover the JSFunction. In some cases, the Type of the object 1208 // which own the property is enough for dispatching to the right function. 1209 // In such cases we do not have read the property, except when the type 1210 // object is unknown. 1211 // 1212 // As an optimization, we can dispatch a call based on the object group, 1213 // without doing the MGetPropertyCache. This is what is achieved by 1214 // |IonBuilder::inlineCalls|. As we might not know all the functions, we 1215 // are adding a fallback path, where this MGetPropertyCache would be moved 1216 // into. 1217 // 1218 // In order to build the fallback path, we have to capture a resume point 1219 // ahead, for the potential fallback path. This resume point is captured 1220 // while building MGetPropertyCache. It is capturing the state of Baseline 1221 // before the execution of the MGetPropertyCache, such as we can safely do 1222 // it in the fallback path. 1223 // 1224 // This field is used to discard the resume point if it is not used for 1225 // building a fallback path. 1226 1227 // Discard the prior resume point while setting a new MGetPropertyCache. 1228 void replaceMaybeFallbackFunctionGetter(MGetPropertyCache* cache); 1229 1230 // Discard the MGetPropertyCache if it is handled by WrapMGetPropertyCache. keepFallbackFunctionGetter(MGetPropertyCache * cache)1231 void keepFallbackFunctionGetter(MGetPropertyCache* cache) { 1232 if (cache == maybeFallbackFunctionGetter_) 1233 maybeFallbackFunctionGetter_ = nullptr; 1234 } 1235 1236 MGetPropertyCache* maybeFallbackFunctionGetter_; 1237 1238 // Used in tracking outcomes of optimization strategies for devtools. 1239 void startTrackingOptimizations(); 1240 1241 // The track* methods below are called often. Do not combine them with the 1242 // unchecked variants, despite the unchecked variants having no other 1243 // callers. trackTypeInfo(JS::TrackedTypeSite site,MIRType mirType,TemporaryTypeSet * typeSet)1244 void trackTypeInfo(JS::TrackedTypeSite site, MIRType mirType, 1245 TemporaryTypeSet* typeSet) 1246 { 1247 if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) 1248 trackTypeInfoUnchecked(site, mirType, typeSet); 1249 } trackTypeInfo(JS::TrackedTypeSite site,JSObject * obj)1250 void trackTypeInfo(JS::TrackedTypeSite site, JSObject* obj) { 1251 if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) 1252 trackTypeInfoUnchecked(site, obj); 1253 } trackTypeInfo(CallInfo & callInfo)1254 void trackTypeInfo(CallInfo& callInfo) { 1255 if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) 1256 trackTypeInfoUnchecked(callInfo); 1257 } trackOptimizationAttempt(JS::TrackedStrategy strategy)1258 void trackOptimizationAttempt(JS::TrackedStrategy strategy) { 1259 if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) 1260 trackOptimizationAttemptUnchecked(strategy); 1261 } amendOptimizationAttempt(uint32_t index)1262 void amendOptimizationAttempt(uint32_t index) { 1263 if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) 1264 amendOptimizationAttemptUnchecked(index); 1265 } trackOptimizationOutcome(JS::TrackedOutcome outcome)1266 void trackOptimizationOutcome(JS::TrackedOutcome outcome) { 1267 if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) 1268 trackOptimizationOutcomeUnchecked(outcome); 1269 } trackOptimizationSuccess()1270 void trackOptimizationSuccess() { 1271 if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) 1272 trackOptimizationSuccessUnchecked(); 1273 } 1274 void trackInlineSuccess(InliningStatus status = InliningStatus_Inlined) { 1275 if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) 1276 trackInlineSuccessUnchecked(status); 1277 } 1278 forceInlineCaches()1279 bool forceInlineCaches() { 1280 return MOZ_UNLIKELY(JitOptions.forceInlineCaches); 1281 } 1282 1283 // Out-of-line variants that don't check if optimization tracking is 1284 // enabled. 1285 void trackTypeInfoUnchecked(JS::TrackedTypeSite site, MIRType mirType, 1286 TemporaryTypeSet* typeSet); 1287 void trackTypeInfoUnchecked(JS::TrackedTypeSite site, JSObject* obj); 1288 void trackTypeInfoUnchecked(CallInfo& callInfo); 1289 void trackOptimizationAttemptUnchecked(JS::TrackedStrategy strategy); 1290 void amendOptimizationAttemptUnchecked(uint32_t index); 1291 void trackOptimizationOutcomeUnchecked(JS::TrackedOutcome outcome); 1292 void trackOptimizationSuccessUnchecked(); 1293 void trackInlineSuccessUnchecked(InliningStatus status); 1294 }; 1295 1296 class CallInfo 1297 { 1298 MDefinition* fun_; 1299 MDefinition* thisArg_; 1300 MDefinition* newTargetArg_; 1301 MDefinitionVector args_; 1302 1303 bool constructing_; 1304 bool setter_; 1305 1306 public: CallInfo(TempAllocator & alloc,bool constructing)1307 CallInfo(TempAllocator& alloc, bool constructing) 1308 : fun_(nullptr), 1309 thisArg_(nullptr), 1310 newTargetArg_(nullptr), 1311 args_(alloc), 1312 constructing_(constructing), 1313 setter_(false) 1314 { } 1315 init(CallInfo & callInfo)1316 bool init(CallInfo& callInfo) { 1317 MOZ_ASSERT(constructing_ == callInfo.constructing()); 1318 1319 fun_ = callInfo.fun(); 1320 thisArg_ = callInfo.thisArg(); 1321 1322 if (constructing()) 1323 newTargetArg_ = callInfo.getNewTarget(); 1324 1325 if (!args_.appendAll(callInfo.argv())) 1326 return false; 1327 1328 return true; 1329 } 1330 init(MBasicBlock * current,uint32_t argc)1331 bool init(MBasicBlock* current, uint32_t argc) { 1332 MOZ_ASSERT(args_.empty()); 1333 1334 // Get the arguments in the right order 1335 if (!args_.reserve(argc)) 1336 return false; 1337 1338 if (constructing()) 1339 setNewTarget(current->pop()); 1340 1341 for (int32_t i = argc; i > 0; i--) 1342 args_.infallibleAppend(current->peek(-i)); 1343 current->popn(argc); 1344 1345 // Get |this| and |fun| 1346 setThis(current->pop()); 1347 setFun(current->pop()); 1348 1349 return true; 1350 } 1351 popFormals(MBasicBlock * current)1352 void popFormals(MBasicBlock* current) { 1353 current->popn(numFormals()); 1354 } 1355 pushFormals(MBasicBlock * current)1356 void pushFormals(MBasicBlock* current) { 1357 current->push(fun()); 1358 current->push(thisArg()); 1359 1360 for (uint32_t i = 0; i < argc(); i++) 1361 current->push(getArg(i)); 1362 1363 if (constructing()) 1364 current->push(getNewTarget()); 1365 } 1366 argc()1367 uint32_t argc() const { 1368 return args_.length(); 1369 } numFormals()1370 uint32_t numFormals() const { 1371 return argc() + 2 + constructing(); 1372 } 1373 setArgs(const MDefinitionVector & args)1374 bool setArgs(const MDefinitionVector& args) { 1375 MOZ_ASSERT(args_.empty()); 1376 return args_.appendAll(args); 1377 } 1378 argv()1379 MDefinitionVector& argv() { 1380 return args_; 1381 } 1382 argv()1383 const MDefinitionVector& argv() const { 1384 return args_; 1385 } 1386 getArg(uint32_t i)1387 MDefinition* getArg(uint32_t i) const { 1388 MOZ_ASSERT(i < argc()); 1389 return args_[i]; 1390 } 1391 getArgWithDefault(uint32_t i,MDefinition * defaultValue)1392 MDefinition* getArgWithDefault(uint32_t i, MDefinition* defaultValue) const { 1393 if (i < argc()) 1394 return args_[i]; 1395 1396 return defaultValue; 1397 } 1398 setArg(uint32_t i,MDefinition * def)1399 void setArg(uint32_t i, MDefinition* def) { 1400 MOZ_ASSERT(i < argc()); 1401 args_[i] = def; 1402 } 1403 thisArg()1404 MDefinition* thisArg() const { 1405 MOZ_ASSERT(thisArg_); 1406 return thisArg_; 1407 } 1408 setThis(MDefinition * thisArg)1409 void setThis(MDefinition* thisArg) { 1410 thisArg_ = thisArg; 1411 } 1412 constructing()1413 bool constructing() const { 1414 return constructing_; 1415 } 1416 setNewTarget(MDefinition * newTarget)1417 void setNewTarget(MDefinition* newTarget) { 1418 MOZ_ASSERT(constructing()); 1419 newTargetArg_ = newTarget; 1420 } getNewTarget()1421 MDefinition* getNewTarget() const { 1422 MOZ_ASSERT(newTargetArg_); 1423 return newTargetArg_; 1424 } 1425 isSetter()1426 bool isSetter() const { 1427 return setter_; 1428 } markAsSetter()1429 void markAsSetter() { 1430 setter_ = true; 1431 } 1432 fun()1433 MDefinition* fun() const { 1434 MOZ_ASSERT(fun_); 1435 return fun_; 1436 } 1437 setFun(MDefinition * fun)1438 void setFun(MDefinition* fun) { 1439 fun_ = fun; 1440 } 1441 setImplicitlyUsedUnchecked()1442 void setImplicitlyUsedUnchecked() { 1443 fun_->setImplicitlyUsedUnchecked(); 1444 thisArg_->setImplicitlyUsedUnchecked(); 1445 if (newTargetArg_) 1446 newTargetArg_->setImplicitlyUsedUnchecked(); 1447 for (uint32_t i = 0; i < argc(); i++) 1448 getArg(i)->setImplicitlyUsedUnchecked(); 1449 } 1450 }; 1451 1452 bool NeedsPostBarrier(MDefinition* value); 1453 1454 } // namespace jit 1455 } // namespace js 1456 1457 #endif /* jit_IonBuilder_h */ 1458