diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg')
40 files changed, 2175 insertions, 1303 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index a0849acea..94e96853d 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -99,31 +99,31 @@ void AbstractState::initialize(Graph& graph) continue; } - PredictedType prediction = node.variableAccessData()->prediction(); - if (isInt32Prediction(prediction)) - root->valuesAtHead.argument(i).set(PredictInt32); - else if (isArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictArray); - else if (isBooleanPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictBoolean); - else if (isInt8ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictInt8Array); - else if (isInt16ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictInt16Array); - else if (isInt32ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictInt32Array); - else if (isUint8ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictUint8Array); - else if (isUint8ClampedArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictUint8ClampedArray); - else if (isUint16ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictUint16Array); - else if (isUint32ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictUint32Array); - else if (isFloat32ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictFloat32Array); - else if (isFloat64ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictFloat64Array); + SpeculatedType prediction = node.variableAccessData()->prediction(); + if (isInt32Speculation(prediction)) + root->valuesAtHead.argument(i).set(SpecInt32); + else if (isArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecArray); + else if (isBooleanSpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecBoolean); + else if (isInt8ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecInt8Array); + else if (isInt16ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecInt16Array); + else if (isInt32ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecInt32Array); + else if (isUint8ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecUint8Array); + else if (isUint8ClampedArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecUint8ClampedArray); + else if (isUint16ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecUint16Array); + else if (isUint32ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecUint32Array); + else if (isFloat32ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecFloat32Array); + else if (isFloat64ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecFloat64Array); else root->valuesAtHead.argument(i).makeTop(); @@ -219,7 +219,9 @@ bool AbstractState::execute(unsigned indexInBlock) { ASSERT(m_block); ASSERT(m_isValid); - + + m_didClobber = false; + NodeIndex nodeIndex = m_block->at(indexInBlock); Node& node = m_graph[nodeIndex]; @@ -237,24 +239,29 @@ bool AbstractState::execute(unsigned indexInBlock) case GetLocal: { VariableAccessData* variableAccessData = node.variableAccessData(); + if (variableAccessData->prediction() == SpecNone) { + m_isValid = false; + node.setCanExit(true); + break; + } bool canExit = false; - canExit |= variableAccessData->prediction() == PredictNone; - if (variableAccessData->isCaptured()) - forNode(nodeIndex) = m_variables.operand(variableAccessData->local()); - else { - AbstractValue value = m_variables.operand(variableAccessData->local()); + AbstractValue value = m_variables.operand(variableAccessData->local()); + if (!variableAccessData->isCaptured()) { if (value.isClear()) canExit |= true; - if (value.value()) - m_foundConstants = true; - forNode(nodeIndex) = value; } + if (value.value()) + m_foundConstants = true; + forNode(nodeIndex) = value; node.setCanExit(canExit); break; } case GetLocalUnlinked: { - forNode(nodeIndex) = m_variables.operand(node.unlinkedLocal()); + AbstractValue value = m_variables.operand(node.unlinkedLocal()); + if (value.value()) + m_foundConstants = true; + forNode(nodeIndex) = value; node.setCanExit(false); break; } @@ -268,17 +275,17 @@ bool AbstractState::execute(unsigned indexInBlock) if (node.variableAccessData()->shouldUseDoubleFormat()) { speculateNumberUnary(node); - m_variables.operand(node.local()).set(PredictDouble); + m_variables.operand(node.local()).set(SpecDouble); break; } - PredictedType predictedType = node.variableAccessData()->argumentAwarePrediction(); - if (isInt32Prediction(predictedType)) + SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction(); + if (isInt32Speculation(predictedType)) speculateInt32Unary(node); - else if (isArrayPrediction(predictedType)) { - node.setCanExit(!isArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictArray); - } else if (isBooleanPrediction(predictedType)) + else if (isArraySpeculation(predictedType)) { + node.setCanExit(!isArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecArray); + } else if (isBooleanSpeculation(predictedType)) speculateBooleanUnary(node); else node.setCanExit(false); @@ -331,7 +338,7 @@ bool AbstractState::execute(unsigned indexInBlock) break; } speculateInt32Binary(node); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } @@ -345,10 +352,10 @@ bool AbstractState::execute(unsigned indexInBlock) break; } if (!node.canSpeculateInteger()) { - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); node.setCanExit(false); } else { - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); node.setCanExit(true); } break; @@ -367,8 +374,8 @@ bool AbstractState::execute(unsigned indexInBlock) } } node.setCanExit(true); - forNode(node.child1()).filter(PredictNumber); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecNumber); + forNode(nodeIndex).set(SpecInt32); break; } @@ -392,7 +399,7 @@ bool AbstractState::execute(unsigned indexInBlock) else node.setCanExit(false); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } @@ -405,12 +412,12 @@ bool AbstractState::execute(unsigned indexInBlock) break; } speculateNumberUnary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } case CheckNumber: - forNode(node.child1()).filter(PredictNumber); + forNode(node.child1()).filter(SpecNumber); break; case ValueAdd: @@ -426,17 +433,17 @@ bool AbstractState::execute(unsigned indexInBlock) if (m_graph.addShouldSpeculateInteger(node)) { speculateInt32Binary( node, !nodeCanTruncateInteger(node.arithNodeFlags())); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()])) { speculateNumberBinary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } if (node.op() == ValueAdd) { clobberWorld(node.codeOrigin, indexInBlock); - forNode(nodeIndex).set(PredictString | PredictInt32 | PredictNumber); + forNode(nodeIndex).set(SpecString | SpecInt32 | SpecNumber); node.setCanExit(false); break; } @@ -458,11 +465,11 @@ bool AbstractState::execute(unsigned indexInBlock) if (m_graph.addShouldSpeculateInteger(node)) { speculateInt32Binary( node, !nodeCanTruncateInteger(node.arithNodeFlags())); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } speculateNumberBinary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -477,11 +484,11 @@ bool AbstractState::execute(unsigned indexInBlock) if (m_graph.negateShouldSpeculateInteger(node)) { speculateInt32Unary( node, !nodeCanTruncateInteger(node.arithNodeFlags())); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } speculateNumberUnary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -499,11 +506,11 @@ bool AbstractState::execute(unsigned indexInBlock) node, !nodeCanTruncateInteger(node.arithNodeFlags()) || !nodeCanIgnoreNegativeZero(node.arithNodeFlags())); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } speculateNumberBinary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -541,11 +548,11 @@ bool AbstractState::execute(unsigned indexInBlock) m_graph[node.child1()], m_graph[node.child2()]) && node.canSpeculateInteger()) { speculateInt32Binary(node, true); // forcing can-exit, which is a bit on the conservative side. - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } speculateNumberBinary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -560,11 +567,11 @@ bool AbstractState::execute(unsigned indexInBlock) if (m_graph[node.child1()].shouldSpeculateInteger() && node.canSpeculateInteger()) { speculateInt32Unary(node, true); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } speculateNumberUnary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -577,7 +584,7 @@ bool AbstractState::execute(unsigned indexInBlock) break; } speculateNumberUnary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -585,27 +592,28 @@ bool AbstractState::execute(unsigned indexInBlock) JSValue childConst = forNode(node.child1()).value(); if (childConst) { forNode(nodeIndex).set(jsBoolean(!childConst.toBoolean())); + m_foundConstants = true; node.setCanExit(false); break; } Node& child = m_graph[node.child1()]; - if (isBooleanPrediction(child.prediction())) + if (isBooleanSpeculation(child.prediction())) speculateBooleanUnary(node); else if (child.shouldSpeculateFinalObjectOrOther()) { node.setCanExit( - !isFinalObjectOrOtherPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictFinalObject | PredictOther); + !isFinalObjectOrOtherSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecFinalObject | SpecOther); } else if (child.shouldSpeculateArrayOrOther()) { node.setCanExit( - !isArrayOrOtherPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictArray | PredictOther); + !isArrayOrOtherSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecArray | SpecOther); } else if (child.shouldSpeculateInteger()) speculateInt32Unary(node); else if (child.shouldSpeculateNumber()) speculateNumberUnary(node); else node.setCanExit(false); - forNode(nodeIndex).set(PredictBoolean); + forNode(nodeIndex).set(SpecBoolean); break; } @@ -643,7 +651,7 @@ bool AbstractState::execute(unsigned indexInBlock) break; } } - forNode(nodeIndex).set(PredictBoolean); + forNode(nodeIndex).set(SpecBoolean); break; } @@ -682,18 +690,18 @@ bool AbstractState::execute(unsigned indexInBlock) break; } - forNode(nodeIndex).set(PredictBoolean); + forNode(nodeIndex).set(SpecBoolean); Node& left = m_graph[node.child1()]; Node& right = m_graph[node.child2()]; - PredictedType filter; - PredictionChecker checker; + SpeculatedType filter; + SpeculatedTypeChecker checker; if (Node::shouldSpeculateInteger(left, right)) { - filter = PredictInt32; - checker = isInt32Prediction; + filter = SpecInt32; + checker = isInt32Speculation; } else if (Node::shouldSpeculateNumber(left, right)) { - filter = PredictNumber; - checker = isNumberPrediction; + filter = SpecNumber; + checker = isNumberSpeculation; } else if (node.op() == CompareEq) { if ((m_graph.isConstant(node.child1().index()) && m_graph.valueOfJSConstant(node.child1().index()).isNull()) @@ -705,47 +713,47 @@ bool AbstractState::execute(unsigned indexInBlock) } if (Node::shouldSpeculateFinalObject(left, right)) { - filter = PredictFinalObject; - checker = isFinalObjectPrediction; + filter = SpecFinalObject; + checker = isFinalObjectSpeculation; } else if (Node::shouldSpeculateArray(left, right)) { - filter = PredictArray; - checker = isArrayPrediction; + filter = SpecArray; + checker = isArraySpeculation; } else if (left.shouldSpeculateFinalObject() && right.shouldSpeculateFinalObjectOrOther()) { node.setCanExit( - !isFinalObjectPrediction(forNode(node.child1()).m_type) - || !isFinalObjectOrOtherPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictFinalObject); - forNode(node.child2()).filter(PredictFinalObject | PredictOther); + !isFinalObjectSpeculation(forNode(node.child1()).m_type) + || !isFinalObjectOrOtherSpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecFinalObject); + forNode(node.child2()).filter(SpecFinalObject | SpecOther); break; } else if (right.shouldSpeculateFinalObject() && left.shouldSpeculateFinalObjectOrOther()) { node.setCanExit( - !isFinalObjectOrOtherPrediction(forNode(node.child1()).m_type) - || !isFinalObjectPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictFinalObject | PredictOther); - forNode(node.child2()).filter(PredictFinalObject); + !isFinalObjectOrOtherSpeculation(forNode(node.child1()).m_type) + || !isFinalObjectSpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecFinalObject | SpecOther); + forNode(node.child2()).filter(SpecFinalObject); break; } else if (left.shouldSpeculateArray() && right.shouldSpeculateArrayOrOther()) { node.setCanExit( - !isArrayPrediction(forNode(node.child1()).m_type) - || !isArrayOrOtherPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictArray); - forNode(node.child2()).filter(PredictArray | PredictOther); + !isArraySpeculation(forNode(node.child1()).m_type) + || !isArrayOrOtherSpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecArray); + forNode(node.child2()).filter(SpecArray | SpecOther); break; } else if (right.shouldSpeculateArray() && left.shouldSpeculateArrayOrOther()) { node.setCanExit( - !isArrayOrOtherPrediction(forNode(node.child1()).m_type) - || !isArrayPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictArray | PredictOther); - forNode(node.child2()).filter(PredictArray); + !isArrayOrOtherSpeculation(forNode(node.child1()).m_type) + || !isArraySpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecArray | SpecOther); + forNode(node.child2()).filter(SpecArray); break; } else { - filter = PredictTop; - checker = isAnyPrediction; + filter = SpecTop; + checker = isAnySpeculation; clobberWorld(node.codeOrigin, indexInBlock); } } else { - filter = PredictTop; - checker = isAnyPrediction; + filter = SpecTop; + checker = isAnySpeculation; clobberWorld(node.codeOrigin, indexInBlock); } node.setCanExit( @@ -765,7 +773,7 @@ bool AbstractState::execute(unsigned indexInBlock) node.setCanExit(false); break; } - forNode(nodeIndex).set(PredictBoolean); + forNode(nodeIndex).set(SpecBoolean); if (m_graph.isJSConstant(node.child1().index())) { JSValue value = m_graph.valueOfJSConstant(node.child1().index()); if (!value.isNumber() && !value.isString()) { @@ -793,19 +801,19 @@ bool AbstractState::execute(unsigned indexInBlock) if (Node::shouldSpeculateFinalObject( m_graph[node.child1()], m_graph[node.child2()])) { node.setCanExit( - !isFinalObjectPrediction(forNode(node.child1()).m_type) - || !isFinalObjectPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictFinalObject); - forNode(node.child2()).filter(PredictFinalObject); + !isFinalObjectSpeculation(forNode(node.child1()).m_type) + || !isFinalObjectSpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecFinalObject); + forNode(node.child2()).filter(SpecFinalObject); break; } if (Node::shouldSpeculateArray( m_graph[node.child1()], m_graph[node.child2()])) { node.setCanExit( - !isArrayPrediction(forNode(node.child1()).m_type) - || !isArrayPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictArray); - forNode(node.child2()).filter(PredictArray); + !isArraySpeculation(forNode(node.child1()).m_type) + || !isArraySpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecArray); + forNode(node.child2()).filter(SpecArray); break; } node.setCanExit(false); @@ -814,16 +822,16 @@ bool AbstractState::execute(unsigned indexInBlock) case StringCharCodeAt: node.setCanExit(true); - forNode(node.child1()).filter(PredictString); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecString); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; case StringCharAt: node.setCanExit(true); - forNode(node.child1()).filter(PredictString); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictString); + forNode(node.child1()).filter(SpecString); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecString); break; case GetByVal: { @@ -832,84 +840,84 @@ bool AbstractState::execute(unsigned indexInBlock) m_isValid = false; break; } - if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) { + if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) { clobberWorld(node.codeOrigin, indexInBlock); forNode(nodeIndex).makeTop(); break; } if (m_graph[node.child1()].shouldSpeculateArguments()) { - forNode(node.child1()).filter(PredictArguments); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecArguments); + forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).makeTop(); break; } - if (m_graph[node.child1()].prediction() == PredictString) { - forNode(node.child1()).filter(PredictString); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictString); + if (m_graph[node.child1()].prediction() == SpecString) { + forNode(node.child1()).filter(SpecString); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecString); break; } if (m_graph[node.child1()].shouldSpeculateInt8Array()) { - forNode(node.child1()).filter(PredictInt8Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecInt8Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateInt16Array()) { - forNode(node.child1()).filter(PredictInt16Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecInt16Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateInt32Array()) { - forNode(node.child1()).filter(PredictInt32Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecInt32Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateUint8Array()) { - forNode(node.child1()).filter(PredictUint8Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecUint8Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { - forNode(node.child1()).filter(PredictUint8ClampedArray); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecUint8ClampedArray); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateUint16Array()) { - forNode(node.child1()).filter(PredictUint16Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecUint16Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateUint32Array()) { - forNode(node.child1()).filter(PredictUint32Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecUint32Array); + forNode(node.child2()).filter(SpecInt32); if (node.shouldSpeculateInteger()) - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); else - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } if (m_graph[node.child1()].shouldSpeculateFloat32Array()) { - forNode(node.child1()).filter(PredictFloat32Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictDouble); + forNode(node.child1()).filter(SpecFloat32Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecDouble); break; } if (m_graph[node.child1()].shouldSpeculateFloat64Array()) { - forNode(node.child1()).filter(PredictFloat64Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictDouble); + forNode(node.child1()).filter(SpecFloat64Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecDouble); break; } ASSERT(m_graph[node.child1()].shouldSpeculateArray()); - forNode(node.child1()).filter(PredictArray); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecArray); + forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).makeTop(); break; } @@ -921,7 +929,7 @@ bool AbstractState::execute(unsigned indexInBlock) m_isValid = false; break; } - if (!m_graph[node.child2()].shouldSpeculateInteger() || !isActionableMutableArrayPrediction(m_graph[node.child1()].prediction()) + if (!m_graph[node.child2()].shouldSpeculateInteger() || !isActionableMutableArraySpeculation(m_graph[node.child1()].prediction()) #if USE(JSVALUE32_64) || m_graph[node.child1()].shouldSpeculateArguments() #endif @@ -933,110 +941,112 @@ bool AbstractState::execute(unsigned indexInBlock) } if (m_graph[node.child1()].shouldSpeculateArguments()) { - forNode(node.child1()).filter(PredictArguments); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecArguments); + forNode(node.child2()).filter(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateInt8Array()) { - forNode(node.child1()).filter(PredictInt8Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecInt8Array); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateInt16Array()) { - forNode(node.child1()).filter(PredictInt16Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecInt16Array); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateInt32Array()) { - forNode(node.child1()).filter(PredictInt32Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecInt32Array); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateUint8Array()) { - forNode(node.child1()).filter(PredictUint8Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecUint8Array); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { - forNode(node.child1()).filter(PredictUint8ClampedArray); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecUint8ClampedArray); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateUint16Array()) { - forNode(node.child1()).filter(PredictUint16Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecUint16Array); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateUint32Array()) { - forNode(node.child1()).filter(PredictUint32Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecUint32Array); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateFloat32Array()) { - forNode(node.child1()).filter(PredictFloat32Array); - forNode(node.child2()).filter(PredictInt32); - forNode(node.child3()).filter(PredictNumber); + forNode(node.child1()).filter(SpecFloat32Array); + forNode(node.child2()).filter(SpecInt32); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateFloat64Array()) { - forNode(node.child1()).filter(PredictFloat64Array); - forNode(node.child2()).filter(PredictInt32); - forNode(node.child3()).filter(PredictNumber); + forNode(node.child1()).filter(SpecFloat64Array); + forNode(node.child2()).filter(SpecInt32); + forNode(node.child3()).filter(SpecNumber); break; } ASSERT(m_graph[node.child1()].shouldSpeculateArray()); - forNode(node.child1()).filter(PredictArray); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecArray); + forNode(node.child2()).filter(SpecInt32); + if (node.op() == PutByVal) + clobberWorld(node.codeOrigin, indexInBlock); break; } case ArrayPush: node.setCanExit(true); - forNode(node.child1()).filter(PredictArray); - forNode(nodeIndex).set(PredictNumber); + forNode(node.child1()).filter(SpecArray); + forNode(nodeIndex).set(SpecNumber); break; case ArrayPop: node.setCanExit(true); - forNode(node.child1()).filter(PredictArray); + forNode(node.child1()).filter(SpecArray); forNode(nodeIndex).makeTop(); break; case RegExpExec: case RegExpTest: node.setCanExit( - !isCellPrediction(forNode(node.child1()).m_type) - || !isCellPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictCell); - forNode(node.child2()).filter(PredictCell); + !isCellSpeculation(forNode(node.child1()).m_type) + || !isCellSpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecCell); + forNode(node.child2()).filter(SpecCell); forNode(nodeIndex).makeTop(); break; @@ -1067,12 +1077,12 @@ bool AbstractState::execute(unsigned indexInBlock) speculateBooleanUnary(node); else if (child.shouldSpeculateFinalObjectOrOther()) { node.setCanExit( - !isFinalObjectOrOtherPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictFinalObject | PredictOther); + !isFinalObjectOrOtherSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecFinalObject | SpecOther); } else if (child.shouldSpeculateArrayOrOther()) { node.setCanExit( - !isArrayOrOtherPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictArray | PredictOther); + !isArrayOrOtherSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecArray | SpecOther); } else if (child.shouldSpeculateInteger()) speculateInt32Unary(node); else if (child.shouldSpeculateNumber()) @@ -1106,17 +1116,17 @@ bool AbstractState::execute(unsigned indexInBlock) Node& child = m_graph[node.child1()]; if (child.shouldSpeculateInteger()) { speculateInt32Unary(node); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } AbstractValue& source = forNode(node.child1()); AbstractValue& destination = forNode(nodeIndex); - PredictedType type = source.m_type; - if (type & ~(PredictNumber | PredictString | PredictBoolean)) { - type &= (PredictNumber | PredictString | PredictBoolean); - type |= PredictString; + SpeculatedType type = source.m_type; + if (type & ~(SpecNumber | SpecString | SpecBoolean)) { + type &= (SpecNumber | SpecString | SpecBoolean); + type |= SpecString; } destination.set(type); node.setCanExit(false); @@ -1125,7 +1135,7 @@ bool AbstractState::execute(unsigned indexInBlock) case StrCat: node.setCanExit(false); - forNode(nodeIndex).set(PredictString); + forNode(nodeIndex).set(SpecString); break; case NewArray: @@ -1146,7 +1156,7 @@ bool AbstractState::execute(unsigned indexInBlock) AbstractValue& source = forNode(node.child1()); AbstractValue& destination = forNode(nodeIndex); - if (isObjectPrediction(source.m_type)) { + if (isObjectSpeculation(source.m_type)) { // This is the simple case. We already know that the source is an // object, so there's nothing to do. I don't think this case will // be hit, but then again, you never know. @@ -1157,20 +1167,20 @@ bool AbstractState::execute(unsigned indexInBlock) node.setCanExit(true); - if (isOtherPrediction(child.prediction())) { - source.filter(PredictOther); - destination.set(PredictObjectOther); + if (isOtherSpeculation(child.prediction())) { + source.filter(SpecOther); + destination.set(SpecObjectOther); break; } - if (isObjectPrediction(child.prediction())) { - source.filter(PredictObjectMask); + if (isObjectSpeculation(child.prediction())) { + source.filter(SpecObjectMask); destination = source; break; } destination = source; - destination.merge(PredictObjectOther); + destination.merge(SpecObjectOther); break; } @@ -1178,10 +1188,10 @@ bool AbstractState::execute(unsigned indexInBlock) AbstractValue& source = forNode(node.child1()); AbstractValue& destination = forNode(nodeIndex); - node.setCanExit(!isCellPrediction(source.m_type)); + node.setCanExit(!isCellSpeculation(source.m_type)); - source.filter(PredictFunction); - destination.set(PredictFinalObject); + source.filter(SpecFunction); + destination.set(SpecFinalObject); break; } @@ -1210,10 +1220,13 @@ bool AbstractState::execute(unsigned indexInBlock) break; case CheckArgumentsNotCreated: - node.setCanExit( - !isEmptyPrediction( + if (isEmptySpeculation( m_variables.operand( - m_graph.argumentsRegisterFor(node.codeOrigin)).m_type)); + m_graph.argumentsRegisterFor(node.codeOrigin)).m_type)) { + node.setCanExit(false); + m_foundConstants = true; + } else + node.setCanExit(true); break; case GetMyArgumentsLength: @@ -1224,9 +1237,9 @@ bool AbstractState::execute(unsigned indexInBlock) if (node.codeOrigin.inlineCallFrame) forNode(nodeIndex).set(jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1)); else - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); node.setCanExit( - !isEmptyPrediction( + !isEmptySpeculation( m_variables.operand( m_graph.argumentsRegisterFor(node.codeOrigin)).m_type)); break; @@ -1246,7 +1259,7 @@ bool AbstractState::execute(unsigned indexInBlock) // We know that this executable does not escape its arguments, so we can optimize // the arguments a bit. Note that this ends up being further optimized by the // ArgumentsSimplificationPhase. - forNode(node.child1()).filter(PredictInt32); + forNode(node.child1()).filter(SpecInt32); forNode(nodeIndex).makeTop(); break; @@ -1256,7 +1269,7 @@ bool AbstractState::execute(unsigned indexInBlock) // a getter. We don't speculate against this. clobberWorld(node.codeOrigin, indexInBlock); // But we do speculate that the index is an integer. - forNode(node.child1()).filter(PredictInt32); + forNode(node.child1()).filter(SpecInt32); // And the result is unknown. forNode(nodeIndex).makeTop(); break; @@ -1270,12 +1283,12 @@ bool AbstractState::execute(unsigned indexInBlock) case GetCallee: node.setCanExit(false); - forNode(nodeIndex).set(PredictFunction); + forNode(nodeIndex).set(SpecFunction); break; case GetScopeChain: node.setCanExit(false); - forNode(nodeIndex).set(PredictCellOther); + forNode(nodeIndex).set(SpecCellOther); break; case GetScopedVar: @@ -1295,74 +1308,74 @@ bool AbstractState::execute(unsigned indexInBlock) m_isValid = false; break; } - if (isCellPrediction(m_graph[node.child1()].prediction())) - forNode(node.child1()).filter(PredictCell); + if (isCellSpeculation(m_graph[node.child1()].prediction())) + forNode(node.child1()).filter(SpecCell); clobberWorld(node.codeOrigin, indexInBlock); forNode(nodeIndex).makeTop(); break; case GetArrayLength: node.setCanExit(true); - forNode(node.child1()).filter(PredictArray); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecArray); + forNode(nodeIndex).set(SpecInt32); break; case GetArgumentsLength: node.setCanExit(true); - forNode(node.child1()).filter(PredictArguments); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecArguments); + forNode(nodeIndex).set(SpecInt32); break; case GetStringLength: - node.setCanExit(!isStringPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictString); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isStringSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecString); + forNode(nodeIndex).set(SpecInt32); break; case GetInt8ArrayLength: - node.setCanExit(!isInt8ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictInt8Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isInt8ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecInt8Array); + forNode(nodeIndex).set(SpecInt32); break; case GetInt16ArrayLength: - node.setCanExit(!isInt16ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictInt16Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isInt16ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecInt16Array); + forNode(nodeIndex).set(SpecInt32); break; case GetInt32ArrayLength: - node.setCanExit(!isInt32ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictInt32Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isInt32ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecInt32Array); + forNode(nodeIndex).set(SpecInt32); break; case GetUint8ArrayLength: - node.setCanExit(!isUint8ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictUint8Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isUint8ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint8Array); + forNode(nodeIndex).set(SpecInt32); break; case GetUint8ClampedArrayLength: - node.setCanExit(!isUint8ClampedArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictUint8ClampedArray); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isUint8ClampedArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint8ClampedArray); + forNode(nodeIndex).set(SpecInt32); break; case GetUint16ArrayLength: - node.setCanExit(!isUint16ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictUint16Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isUint16ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint16Array); + forNode(nodeIndex).set(SpecInt32); break; case GetUint32ArrayLength: - node.setCanExit(!isUint32ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictUint32Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isUint32ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint32Array); + forNode(nodeIndex).set(SpecInt32); break; case GetFloat32ArrayLength: - node.setCanExit(!isFloat32ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictFloat32Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isFloat32ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecFloat32Array); + forNode(nodeIndex).set(SpecInt32); break; case GetFloat64ArrayLength: - node.setCanExit(!isFloat64ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictFloat64Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isFloat64ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecFloat64Array); + forNode(nodeIndex).set(SpecInt32); break; case CheckStructure: { @@ -1370,11 +1383,20 @@ bool AbstractState::execute(unsigned indexInBlock) AbstractValue& value = forNode(node.child1()); node.setCanExit( !value.m_structure.isSubsetOf(node.structureSet()) - || !isCellPrediction(value.m_type)); + || !isCellSpeculation(value.m_type)); value.filter(node.structureSet()); m_haveStructures = true; break; } + + case StructureTransitionWatchpoint: { + // FIXME: Turn CheckStructure into StructureTransitionWatchpoint when possible! + AbstractValue& value = forNode(node.child1()); + ASSERT(isCellSpeculation(value.m_type)); + value.filter(node.structure()); + node.setCanExit(true); + break; + } case PutStructure: case PhantomPutStructure: @@ -1385,13 +1407,13 @@ bool AbstractState::execute(unsigned indexInBlock) break; case GetPropertyStorage: node.setCanExit(false); - forNode(node.child1()).filter(PredictCell); + forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).clear(); // The result is not a JS value. break; case GetIndexedPropertyStorage: { node.setCanExit(true); // Lies, but this is (almost) always followed by GetByVal, which does exit. So no point in trying to be more precise. - PredictedType basePrediction = m_graph[node.child2()].prediction(); - if (!(basePrediction & PredictInt32) && basePrediction) { + SpeculatedType basePrediction = m_graph[node.child2()].prediction(); + if (!(basePrediction & SpecInt32) && basePrediction) { forNode(nodeIndex).clear(); break; } @@ -1399,82 +1421,82 @@ bool AbstractState::execute(unsigned indexInBlock) ASSERT_NOT_REACHED(); break; } - if (m_graph[node.child1()].prediction() == PredictString) { - forNode(node.child1()).filter(PredictString); + if (m_graph[node.child1()].prediction() == SpecString) { + forNode(node.child1()).filter(SpecString); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateInt8Array()) { - forNode(node.child1()).filter(PredictInt8Array); + forNode(node.child1()).filter(SpecInt8Array); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateInt16Array()) { - forNode(node.child1()).filter(PredictInt16Array); + forNode(node.child1()).filter(SpecInt16Array); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateInt32Array()) { - forNode(node.child1()).filter(PredictInt32Array); + forNode(node.child1()).filter(SpecInt32Array); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateUint8Array()) { - forNode(node.child1()).filter(PredictUint8Array); + forNode(node.child1()).filter(SpecUint8Array); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { - forNode(node.child1()).filter(PredictUint8ClampedArray); + forNode(node.child1()).filter(SpecUint8ClampedArray); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateUint16Array()) { - forNode(node.child1()).filter(PredictUint16Array); - forNode(nodeIndex).set(PredictOther); + forNode(node.child1()).filter(SpecUint16Array); + forNode(nodeIndex).set(SpecOther); break; } if (m_graph[node.child1()].shouldSpeculateUint32Array()) { - forNode(node.child1()).filter(PredictUint32Array); + forNode(node.child1()).filter(SpecUint32Array); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateFloat32Array()) { - forNode(node.child1()).filter(PredictFloat32Array); + forNode(node.child1()).filter(SpecFloat32Array); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateFloat64Array()) { - forNode(node.child1()).filter(PredictFloat64Array); + forNode(node.child1()).filter(SpecFloat64Array); forNode(nodeIndex).clear(); break; } - forNode(node.child1()).filter(PredictArray); + forNode(node.child1()).filter(SpecArray); forNode(nodeIndex).clear(); break; } case GetByOffset: node.setCanExit(false); - forNode(node.child1()).filter(PredictCell); + forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).makeTop(); break; case PutByOffset: node.setCanExit(false); - forNode(node.child1()).filter(PredictCell); + forNode(node.child1()).filter(SpecCell); break; case CheckFunction: node.setCanExit(true); // Lies! We can do better. - forNode(node.child1()).filter(PredictFunction); + forNode(node.child1()).filter(SpecFunction); // FIXME: Should be able to propagate the fact that we know what the function is. break; - + case PutById: case PutByIdDirect: node.setCanExit(true); - forNode(node.child1()).filter(PredictCell); + forNode(node.child1()).filter(SpecCell); clobberWorld(node.codeOrigin, indexInBlock); break; @@ -1482,24 +1504,29 @@ bool AbstractState::execute(unsigned indexInBlock) node.setCanExit(false); forNode(nodeIndex).makeTop(); break; + + case GlobalVarWatchpoint: + node.setCanExit(true); + break; case PutGlobalVar: + case PutGlobalVarCheck: node.setCanExit(false); break; case CheckHasInstance: node.setCanExit(true); - forNode(node.child1()).filter(PredictCell); + forNode(node.child1()).filter(SpecCell); // Sadly, we don't propagate the fact that we've done CheckHasInstance break; case InstanceOf: node.setCanExit(true); // Again, sadly, we don't propagate the fact that we've done InstanceOf - if (!(m_graph[node.child1()].prediction() & ~PredictCell) && !(forNode(node.child1()).m_type & ~PredictCell)) - forNode(node.child1()).filter(PredictCell); - forNode(node.child3()).filter(PredictCell); - forNode(nodeIndex).set(PredictBoolean); + if (!(m_graph[node.child1()].prediction() & ~SpecCell) && !(forNode(node.child1()).m_type & ~SpecCell)) + forNode(node.child1()).filter(SpecCell); + forNode(node.child3()).filter(SpecCell); + forNode(nodeIndex).set(SpecBoolean); break; case Phi: @@ -1572,6 +1599,7 @@ inline void AbstractState::clobberStructures(unsigned indexInBlock) for (size_t i = m_variables.numberOfLocals(); i--;) m_variables.local(i).clobberStructures(); m_haveStructures = false; + m_didClobber = true; } inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, NodeIndex nodeIndex) @@ -1625,7 +1653,7 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract // before and after setting it. if (node.variableAccessData()->shouldUseDoubleFormat()) { // FIXME: This unnecessarily loses precision. - source.set(PredictDouble); + source.set(SpecDouble); } else source = forNode(node.child1()); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.h b/Source/JavaScriptCore/dfg/DFGAbstractState.h index 4b0a248f3..9bb74cd86 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.h +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.h @@ -193,6 +193,9 @@ public: // of Throw. bool execute(unsigned); + // Did the last executed node clobber the world? + bool didClobber() const { return m_didClobber; } + // Is the execution state still valid? This will be false if execute() has // returned false previously. bool isValid() const { return m_isValid; } @@ -223,22 +226,22 @@ private: void speculateInt32Unary(Node& node, bool forceCanExit = false) { AbstractValue& childValue = forNode(node.child1()); - node.setCanExit(forceCanExit || !isInt32Prediction(childValue.m_type)); - childValue.filter(PredictInt32); + node.setCanExit(forceCanExit || !isInt32Speculation(childValue.m_type)); + childValue.filter(SpecInt32); } void speculateNumberUnary(Node& node) { AbstractValue& childValue = forNode(node.child1()); - node.setCanExit(!isNumberPrediction(childValue.m_type)); - childValue.filter(PredictNumber); + node.setCanExit(!isNumberSpeculation(childValue.m_type)); + childValue.filter(SpecNumber); } void speculateBooleanUnary(Node& node) { AbstractValue& childValue = forNode(node.child1()); - node.setCanExit(!isBooleanPrediction(childValue.m_type)); - childValue.filter(PredictBoolean); + node.setCanExit(!isBooleanSpeculation(childValue.m_type)); + childValue.filter(SpecBoolean); } void speculateInt32Binary(Node& node, bool forceCanExit = false) @@ -247,10 +250,10 @@ private: AbstractValue& childValue2 = forNode(node.child2()); node.setCanExit( forceCanExit - || !isInt32Prediction(childValue1.m_type) - || !isInt32Prediction(childValue2.m_type)); - childValue1.filter(PredictInt32); - childValue2.filter(PredictInt32); + || !isInt32Speculation(childValue1.m_type) + || !isInt32Speculation(childValue2.m_type)); + childValue1.filter(SpecInt32); + childValue2.filter(SpecInt32); } void speculateNumberBinary(Node& node) @@ -258,10 +261,10 @@ private: AbstractValue& childValue1 = forNode(node.child1()); AbstractValue& childValue2 = forNode(node.child2()); node.setCanExit( - !isNumberPrediction(childValue1.m_type) - || !isNumberPrediction(childValue2.m_type)); - childValue1.filter(PredictNumber); - childValue2.filter(PredictNumber); + !isNumberSpeculation(childValue1.m_type) + || !isNumberSpeculation(childValue2.m_type)); + childValue1.filter(SpecNumber); + childValue2.filter(SpecNumber); } CodeBlock* m_codeBlock; @@ -274,6 +277,7 @@ private: bool m_foundConstants; bool m_isValid; + bool m_didClobber; BranchDirection m_branchDirection; // This is only set for blocks that end in Branch and that execute to completion (i.e. m_isValid == true). }; diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h index c61a383eb..f81af4ecf 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h +++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h @@ -31,7 +31,7 @@ #if ENABLE(DFG_JIT) #include "JSCell.h" -#include "PredictedType.h" +#include "SpeculatedType.h" #include "StructureSet.h" namespace JSC { namespace DFG { @@ -225,9 +225,9 @@ public: m_structure = 0; } - void filter(PredictedType other) + void filter(SpeculatedType other) { - if (!(other & PredictCell)) { + if (!(other & SpecCell)) { clear(); return; } @@ -235,7 +235,7 @@ public: if (isClearOrTop()) return; - if (!(predictionFromStructure(m_structure) & other)) + if (!(speculationFromStructure(m_structure) & other)) m_structure = 0; } @@ -273,13 +273,13 @@ public: return at(0); } - PredictedType predictionFromStructures() const + SpeculatedType speculationFromStructures() const { if (isTop()) - return PredictCell; + return SpecCell; if (isClear()) - return PredictNone; - return predictionFromStructure(m_structure); + return SpecNone; + return speculationFromStructure(m_structure); } bool operator==(const StructureAbstractValue& other) const @@ -309,13 +309,13 @@ private: struct AbstractValue { AbstractValue() - : m_type(PredictNone) + : m_type(SpecNone) { } void clear() { - m_type = PredictNone; + m_type = SpecNone; m_structure.clear(); m_value = JSValue(); checkConsistency(); @@ -323,7 +323,7 @@ struct AbstractValue { bool isClear() const { - bool result = m_type == PredictNone && m_structure.isClear(); + bool result = m_type == SpecNone && m_structure.isClear(); if (result) ASSERT(!m_value); return result; @@ -331,7 +331,7 @@ struct AbstractValue { void makeTop() { - m_type = PredictTop; + m_type = SpecTop; m_structure.makeTop(); m_value = JSValue(); checkConsistency(); @@ -339,7 +339,7 @@ struct AbstractValue { void clobberStructures() { - if (m_type & PredictCell) + if (m_type & SpecCell) m_structure.makeTop(); else ASSERT(m_structure.isClear()); @@ -353,7 +353,7 @@ struct AbstractValue { bool isTop() const { - return m_type == PredictTop && m_structure.isTop(); + return m_type == SpecTop && m_structure.isTop(); } bool valueIsTop() const @@ -386,7 +386,7 @@ struct AbstractValue { } else m_structure.clear(); - m_type = predictionFromValue(value); + m_type = speculationFromValue(value); m_value = value; checkConsistency(); @@ -397,15 +397,15 @@ struct AbstractValue { m_structure.clear(); m_structure.add(structure); - m_type = predictionFromStructure(structure); + m_type = speculationFromStructure(structure); m_value = JSValue(); checkConsistency(); } - void set(PredictedType type) + void set(SpeculatedType type) { - if (type & PredictCell) + if (type & SpecCell) m_structure.makeTop(); else m_structure.clear(); @@ -435,7 +435,7 @@ struct AbstractValue { *this = other; result = !other.isClear(); } else { - result |= mergePrediction(m_type, other.m_type); + result |= mergeSpeculation(m_type, other.m_type); result |= m_structure.addAll(other.m_structure); if (m_value != other.m_value) { result |= !!m_value; @@ -447,11 +447,11 @@ struct AbstractValue { return result; } - void merge(PredictedType type) + void merge(SpeculatedType type) { - mergePrediction(m_type, type); + mergeSpeculation(m_type, type); - if (type & PredictCell) + if (type & SpecCell) m_structure.makeTop(); m_value = JSValue(); @@ -460,13 +460,13 @@ struct AbstractValue { void filter(const StructureSet& other) { - m_type &= other.predictionFromStructures(); + m_type &= other.speculationFromStructures(); m_structure.filter(other); // It's possible that prior to the above two statements we had (Foo, TOP), where - // Foo is a PredictedType that is disjoint with the passed StructureSet. In that + // Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that // case, we will now have (None, [someStructure]). In general, we need to make - // sure that new information gleaned from the PredictedType needs to be fed back + // sure that new information gleaned from the SpeculatedType needs to be fed back // into the information gleaned from the StructureSet. m_structure.filter(m_type); @@ -476,9 +476,9 @@ struct AbstractValue { checkConsistency(); } - void filter(PredictedType type) + void filter(SpeculatedType type) { - if (type == PredictTop) + if (type == SpecTop) return; m_type &= type; @@ -499,11 +499,11 @@ struct AbstractValue { if (isTop()) return true; - if (mergePredictions(m_type, predictionFromValue(value)) != m_type) + if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type) return false; if (value.isEmpty()) { - ASSERT(m_type & PredictEmpty); + ASSERT(m_type & SpecEmpty); return true; } @@ -511,7 +511,7 @@ struct AbstractValue { return true; if (!!value && value.isCell()) { - ASSERT(m_type & PredictCell); + ASSERT(m_type & SpecCell); return m_structure.contains(value.asCell()->structure()); } @@ -526,11 +526,11 @@ struct AbstractValue { if (!!m_value) return m_value == value; - if (mergePredictions(m_type, predictionFromValue(value)) != m_type) + if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type) return false; if (value.isEmpty()) { - ASSERT(m_type & PredictEmpty); + ASSERT(m_type & SpecEmpty); return true; } @@ -538,7 +538,7 @@ struct AbstractValue { return true; if (!!value && value.isCell()) { - ASSERT(m_type & PredictCell); + ASSERT(m_type & SpecCell); return m_structure.contains(value.asCell()->structure()); } @@ -547,14 +547,14 @@ struct AbstractValue { void checkConsistency() const { - if (!(m_type & PredictCell)) + if (!(m_type & SpecCell)) ASSERT(m_structure.isClear()); if (isClear()) ASSERT(!m_value); if (!!m_value) - ASSERT(mergePredictions(m_type, predictionFromValue(m_value)) == m_type); + ASSERT(mergeSpeculations(m_type, speculationFromValue(m_value)) == m_type); // Note that it's possible for a prediction like (Final, []). This really means that // the value is bottom and that any code that uses the value is unreachable. But @@ -564,7 +564,7 @@ struct AbstractValue { void dump(FILE* out) const { - fprintf(out, "(%s, ", predictionToString(m_type)); + fprintf(out, "(%s, ", speculationToString(m_type)); m_structure.dump(out); if (!!m_value) fprintf(out, ", %s", m_value.description()); @@ -572,7 +572,7 @@ struct AbstractValue { } StructureAbstractValue m_structure; - PredictedType m_type; + SpeculatedType m_type; JSValue m_value; }; diff --git a/Source/JavaScriptCore/dfg/DFGArgumentPosition.h b/Source/JavaScriptCore/dfg/DFGArgumentPosition.h index ed447ff91..05d1cb048 100644 --- a/Source/JavaScriptCore/dfg/DFGArgumentPosition.h +++ b/Source/JavaScriptCore/dfg/DFGArgumentPosition.h @@ -28,14 +28,14 @@ #include "DFGDoubleFormatState.h" #include "DFGVariableAccessData.h" -#include "PredictedType.h" +#include "SpeculatedType.h" namespace JSC { namespace DFG { class ArgumentPosition { public: ArgumentPosition() - : m_prediction(PredictNone) + : m_prediction(SpecNone) , m_doubleFormatState(EmptyDoubleFormatState) { } @@ -49,7 +49,7 @@ public: { bool changed = false; for (unsigned i = 0; i < m_variables.size(); ++i) { - changed |= mergePrediction(m_prediction, m_variables[i]->argumentAwarePrediction()); + changed |= mergeSpeculation(m_prediction, m_variables[i]->argumentAwarePrediction()); changed |= mergeDoubleFormatState(m_doubleFormatState, m_variables[i]->doubleFormatState()); } if (!changed) @@ -62,8 +62,15 @@ public: return changed; } + SpeculatedType prediction() const { return m_prediction; } + DoubleFormatState doubleFormatState() const { return m_doubleFormatState; } + bool shouldUseDoubleFormat() const + { + return doubleFormatState() == UsingDoubleFormat; + } + private: - PredictedType m_prediction; + SpeculatedType m_prediction; DoubleFormatState m_doubleFormatState; Vector<VariableAccessData*, 2> m_variables; diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp index 48163a91b..28e686aef 100644 --- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp @@ -170,9 +170,17 @@ public: break; } + case TearOffArguments: { + // Ignore arguments tear off, because it's only relevant if we actually + // need to create the arguments. + break; + } + case SetLocal: { Node& source = m_graph[node.child1()]; VariableAccessData* variableAccessData = node.variableAccessData(); + int argumentsRegister = + m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin); if (source.op() != CreateArguments) { // Make sure that the source of the SetLocal knows that if it's // a variable that we think is aliased to the arguments, then it @@ -180,8 +188,28 @@ public: // aliasing. But not yet. observeBadArgumentsUse(node.child1()); - if (variableAccessData->isCaptured()) + if (variableAccessData->isCaptured()) { + // If this is an assignment to the arguments register, then + // pretend as if the arguments were created. We don't want to + // optimize code that explicitly assigns to the arguments, + // because that seems too ugly. + + // But, before getting rid of CreateArguments, we will have + // an assignment to the arguments registers with JSValue(). + // That's because CSE will refuse to get rid of the + // init_lazy_reg since it treats CreateArguments as reading + // local variables. That could be fixed, but it's easier to + // work around this here. + if (source.op() == JSConstant + && !source.valueOfJSConstant(codeBlock())) + break; + + if (argumentsRegister != InvalidVirtualRegister + && (variableAccessData->local() == argumentsRegister + || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) + m_createsArguments.add(node.codeOrigin.inlineCallFrame); break; + } // Make sure that if it's a variable that we think is aliased to // the arguments, that we know that it might actually not be. @@ -191,11 +219,9 @@ public: data.mergeCallContext(node.codeOrigin.inlineCallFrame); break; } - int argumentsRegister = - m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin); - if (variableAccessData->local() == argumentsRegister - || variableAccessData->local() == - unmodifiedArgumentsRegister(argumentsRegister)) { + if (argumentsRegister != InvalidVirtualRegister + && (variableAccessData->local() == argumentsRegister + || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) { if (node.codeOrigin.inlineCallFrame == source.codeOrigin.inlineCallFrame) break; m_createsArguments.add(source.codeOrigin.inlineCallFrame); @@ -258,7 +284,7 @@ public: break; } - if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) + if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) { observeBadArgumentsUses(node); break; @@ -398,10 +424,25 @@ public: if (source.op() != CreateArguments) break; + if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) + break; + VariableAccessData* variableAccessData = node.variableAccessData(); - if (variableAccessData->isCaptured()) + if (variableAccessData->isCaptured()) { + ASSERT(m_graph.argumentsRegisterFor(node.codeOrigin) == variableAccessData->local() + || unmodifiedArgumentsRegister(m_graph.argumentsRegisterFor(node.codeOrigin)) == variableAccessData->local()); + // The child of this store should really be the empty value. + Node emptyJSValue(JSConstant, node.codeOrigin, OpInfo(codeBlock()->addOrFindConstant(JSValue()))); + emptyJSValue.ref(); + NodeIndex emptyJSValueIndex = m_graph.size(); + m_graph.deref(node.child1()); + node.children.child1() = Edge(emptyJSValueIndex); + m_graph.append(emptyJSValue); + insertionSet.append(indexInBlock, emptyJSValueIndex); + changed = true; break; + } // If this is a store into a VariableAccessData* that is marked as // arguments aliasing for an InlineCallFrame* that does not create @@ -410,11 +451,8 @@ public: // things. Note also that the SetLocal should become dead as soon as // we replace all uses of this variable with GetMyArgumentsLength and // GetMyArgumentByVal. - if (m_argumentsAliasing.find(variableAccessData)->second.isValid() - && !m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) { - changed |= variableAccessData->mergeIsArgumentsAlias(true); - break; - } + ASSERT(m_argumentsAliasing.find(variableAccessData)->second.isValid()); + changed |= variableAccessData->mergeIsArgumentsAlias(true); break; } @@ -439,7 +477,7 @@ public: || !m_graph[node.child2()].prediction()) break; - if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) + if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) break; @@ -487,19 +525,21 @@ public: node.setOp(GetMyArgumentsLength); changed = true; } - if (!node.codeOrigin.inlineCallFrame) + + CodeOrigin codeOrigin = node.codeOrigin; + if (!codeOrigin.inlineCallFrame) break; // We know exactly what this will return. But only after we have checked // that nobody has escaped our arguments. - Node check(CheckArgumentsNotCreated, node.codeOrigin); + Node check(CheckArgumentsNotCreated, codeOrigin); check.ref(); NodeIndex checkIndex = m_graph.size(); m_graph.append(check); insertionSet.append(indexInBlock, checkIndex); m_graph.convertToConstant( - nodeIndex, jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1)); + nodeIndex, jsNumber(codeOrigin.inlineCallFrame->arguments.size() - 1)); changed = true; break; } @@ -559,6 +599,16 @@ public: break; } + case TearOffArguments: { + if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) + continue; + + node.setOpAndDefaultFlags(Nop); + m_graph.clearAndDerefChild1(node); + node.setRefCount(0); + break; + } + default: break; } @@ -573,8 +623,6 @@ public: for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { NodeIndex nodeIndex = block->at(indexInBlock); Node& node = m_graph[nodeIndex]; - if (!node.shouldGenerate()) - continue; if (node.op() != CreateArguments) continue; // If this is a CreateArguments for an InlineCallFrame* that does @@ -583,14 +631,16 @@ public: // empty value) in DFG and arguments creation for OSR exit. if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) continue; - Node phantom(Phantom, node.codeOrigin); - phantom.children = node.children; - phantom.ref(); + if (node.shouldGenerate()) { + Node phantom(Phantom, node.codeOrigin); + phantom.children = node.children; + phantom.ref(); + NodeIndex phantomNodeIndex = m_graph.size(); + m_graph.append(phantom); + insertionSet.append(indexInBlock, phantomNodeIndex); + } node.setOpAndDefaultFlags(PhantomArguments); node.children.reset(); - NodeIndex phantomNodeIndex = m_graph.size(); - m_graph.append(phantom); - insertionSet.append(indexInBlock, phantomNodeIndex); } insertionSet.execute(*block); } @@ -622,7 +672,10 @@ private: } case GetLocal: { - if (child.local() == m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)) { + int argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin); + if (argumentsRegister != InvalidVirtualRegister + && (child.local() == argumentsRegister + || child.local() == unmodifiedArgumentsRegister(argumentsRegister))) { m_createsArguments.add(child.codeOrigin.inlineCallFrame); break; } @@ -684,25 +737,31 @@ private: bool isOKToOptimize(Node& source) { + if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) + return false; + switch (source.op()) { case GetLocal: { VariableAccessData* variableAccessData = source.variableAccessData(); - if (variableAccessData->isCaptured()) + if (variableAccessData->isCaptured()) { + int argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(source.codeOrigin); + if (argumentsRegister == InvalidVirtualRegister) + break; + if (argumentsRegister == variableAccessData->local()) + return true; + if (unmodifiedArgumentsRegister(argumentsRegister) == variableAccessData->local()) + return true; break; + } ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second; if (!data.isValid()) break; - if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) - break; return true; } case CreateArguments: { - if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) - break; - return true; } diff --git a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h index 9087eec57..f86c15e65 100644 --- a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h @@ -115,21 +115,6 @@ public: #endif } - static Address addressForGlobalVar(GPRReg global, int32_t varNumber) - { - return Address(global, varNumber * sizeof(Register)); - } - - static Address tagForGlobalVar(GPRReg global, int32_t varNumber) - { - return Address(global, varNumber * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); - } - - static Address payloadForGlobalVar(GPRReg global, int32_t varNumber) - { - return Address(global, varNumber * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); - } - static Address addressFor(VirtualRegister virtualRegister) { return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register)); diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 358171029..317a08504 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -93,7 +93,10 @@ private: // Handle setting the result of an intrinsic. void setIntrinsicResult(bool usesResult, int resultOperand, NodeIndex); // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call. - bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, PredictedType prediction); + bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction); + void handleGetById( + int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber, + const GetByIdStatus&); // Prepare to parse a block. void prepareToParseBlock(); // Parse a single basic block of bytecode instructions. @@ -109,7 +112,7 @@ private: template<PhiStackType stackType> void processPhiStack(); - void fixVariableAccessPredictions(); + void fixVariableAccessSpeculations(); // Add spill locations to nodes. void allocateVirtualRegisters(); @@ -159,17 +162,17 @@ private: setDirect(m_inlineStackTop->remapOperand(operand), value, setMode); } - NodeIndex injectLazyOperandPrediction(NodeIndex nodeIndex) + NodeIndex injectLazyOperandSpeculation(NodeIndex nodeIndex) { Node& node = m_graph[nodeIndex]; ASSERT(node.op() == GetLocal); ASSERT(node.codeOrigin.bytecodeIndex == m_currentIndex); - PredictedType prediction = + SpeculatedType prediction = m_inlineStackTop->m_lazyOperands.prediction( LazyOperandValueProfileKey(m_currentIndex, node.local())); #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("Lazy operand [@%u, bc#%u, r%d] prediction: %s\n", - nodeIndex, m_currentIndex, node.local(), predictionToString(prediction)); + nodeIndex, m_currentIndex, node.local(), speculationToString(prediction)); #endif node.variableAccessData()->predict(prediction); return nodeIndex; @@ -192,7 +195,7 @@ private: if (flushChild.op() == Phi) { VariableAccessData* variableAccessData = flushChild.variableAccessData(); variableAccessData->mergeIsCaptured(isCaptured); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex)); m_currentBlock->variablesAtTail.local(operand) = nodeIndex; return nodeIndex; } @@ -213,7 +216,7 @@ private: if (nodePtr->op() == GetLocal) nodeIndex = nodePtr->child1().index(); - return injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); + return injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); } if (nodePtr->op() == GetLocal) @@ -230,7 +233,7 @@ private: NodeIndex phi = addToGraph(Phi, OpInfo(variableAccessData)); m_localPhiStack.append(PhiStackEntry(m_currentBlock, phi, operand)); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), phi)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variableAccessData), phi)); m_currentBlock->variablesAtTail.local(operand) = nodeIndex; m_currentBlock->variablesAtHead.setLocalFirstTime(operand, nodeIndex); @@ -274,7 +277,7 @@ private: if (flushChild.op() == Phi) { VariableAccessData* variableAccessData = flushChild.variableAccessData(); variableAccessData->mergeIsCaptured(isCaptured); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex)); m_currentBlock->variablesAtTail.argument(argument) = nodeIndex; return nodeIndex; } @@ -290,7 +293,7 @@ private: // We're getting an argument in the first basic block; link // the GetLocal to the SetArgument. ASSERT(nodePtr->local() == static_cast<VirtualRegister>(operand)); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); m_currentBlock->variablesAtTail.argument(argument) = nodeIndex; return nodeIndex; } @@ -298,7 +301,7 @@ private: if (isCaptured) { if (nodePtr->op() == GetLocal) nodeIndex = nodePtr->child1().index(); - return injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); + return injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); } if (nodePtr->op() == GetLocal) @@ -312,7 +315,7 @@ private: NodeIndex phi = addToGraph(Phi, OpInfo(variableAccessData)); m_argumentPhiStack.append(PhiStackEntry(m_currentBlock, phi, argument)); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), phi)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variableAccessData), phi)); m_currentBlock->variablesAtTail.argument(argument) = nodeIndex; m_currentBlock->variablesAtHead.setArgumentFirstTime(argument, nodeIndex); @@ -725,7 +728,7 @@ private: { Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call); - PredictedType prediction = PredictNone; + SpeculatedType prediction = SpecNone; if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { m_currentProfilingIndex = m_currentIndex + OPCODE_LENGTH(op_call); prediction = getPrediction(); @@ -747,23 +750,44 @@ private: return call; } - PredictedType getPredictionWithoutOSRExit(NodeIndex nodeIndex, unsigned bytecodeIndex) + NodeIndex addStructureTransitionCheck(JSCell* object, Structure* structure) + { + // Add a weak JS constant for the object regardless, since the code should + // be jettisoned if the object ever dies. + NodeIndex objectIndex = cellConstant(object); + + if (object->structure() == structure && structure->transitionWatchpointSetIsStillValid()) { + addToGraph(StructureTransitionWatchpoint, OpInfo(structure), objectIndex); + return objectIndex; + } + + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structure)), objectIndex); + + return objectIndex; + } + + NodeIndex addStructureTransitionCheck(JSCell* object) + { + return addStructureTransitionCheck(object, object->structure()); + } + + SpeculatedType getPredictionWithoutOSRExit(NodeIndex nodeIndex, unsigned bytecodeIndex) { UNUSED_PARAM(nodeIndex); - PredictedType prediction = m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(bytecodeIndex); + SpeculatedType prediction = m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(bytecodeIndex); #if DFG_ENABLE(DEBUG_VERBOSE) - dataLog("Dynamic [@%u, bc#%u] prediction: %s\n", nodeIndex, bytecodeIndex, predictionToString(prediction)); + dataLog("Dynamic [@%u, bc#%u] prediction: %s\n", nodeIndex, bytecodeIndex, speculationToString(prediction)); #endif return prediction; } - PredictedType getPrediction(NodeIndex nodeIndex, unsigned bytecodeIndex) + SpeculatedType getPrediction(NodeIndex nodeIndex, unsigned bytecodeIndex) { - PredictedType prediction = getPredictionWithoutOSRExit(nodeIndex, bytecodeIndex); + SpeculatedType prediction = getPredictionWithoutOSRExit(nodeIndex, bytecodeIndex); - if (prediction == PredictNone) { + if (prediction == SpecNone) { // We have no information about what values this node generates. Give up // on executing this code, since we're likely to do more damage than good. addToGraph(ForceOSRExit); @@ -772,12 +796,12 @@ private: return prediction; } - PredictedType getPredictionWithoutOSRExit() + SpeculatedType getPredictionWithoutOSRExit() { return getPredictionWithoutOSRExit(m_graph.size(), m_currentProfilingIndex); } - PredictedType getPrediction() + SpeculatedType getPrediction() { return getPrediction(m_graph.size(), m_currentProfilingIndex); } @@ -1020,7 +1044,7 @@ private: VirtualRegister m_returnValue; - // Predictions about variable types collected from the profiled code block, + // Speculations about variable types collected from the profiled code block, // which are based on OSR exit profiles that past DFG compilatins of this // code block had gathered. LazyOperandValueProfileParser m_lazyOperands; @@ -1147,7 +1171,7 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn int resultOperand = 0; // make compiler happy unsigned nextOffset = m_currentIndex + OPCODE_LENGTH(op_call); Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call); - PredictedType prediction = PredictNone; + SpeculatedType prediction = SpecNone; if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { resultOperand = putInstruction[1].u.operand; usesResult = true; @@ -1231,6 +1255,9 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c // Does the code block's size match the heuristics/requirements for being // an inline candidate? CodeBlock* profiledBlock = executable->profiledCodeBlockFor(kind); + if (!profiledBlock) + return false; + if (!mightInlineFunctionFor(profiledBlock, kind)) return false; @@ -1270,6 +1297,8 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c for (size_t i = 0; i < m_graph.m_blocks.size(); ++i) m_graph.m_blocks[i]->ensureLocals(newNumLocals); } + + size_t argumentPositionStart = m_graph.m_argumentPositions.size(); InlineStackEntry inlineStackEntry( this, codeBlock, profiledBlock, m_graph.m_blocks.size() - 1, @@ -1284,7 +1313,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c m_currentIndex = 0; m_currentProfilingIndex = 0; - addToGraph(InlineStart); + addToGraph(InlineStart, OpInfo(argumentPositionStart)); parseCodeBlock(); @@ -1418,7 +1447,7 @@ bool ByteCodeParser::handleMinMax(bool usesResult, int resultOperand, NodeType o // FIXME: We dead-code-eliminate unused Math intrinsics, but that's invalid because // they need to perform the ToNumber conversion, which can have side-effects. -bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, PredictedType prediction) +bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction) { switch (intrinsic) { case AbsIntrinsic: { @@ -1482,7 +1511,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return false; int thisOperand = registerOffset + argumentToOperand(0); - if (!(m_graph[get(thisOperand)].prediction() & PredictString)) + if (!(m_graph[get(thisOperand)].prediction() & SpecString)) return false; int indexOperand = registerOffset + argumentToOperand(1); @@ -1499,7 +1528,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return false; int thisOperand = registerOffset + argumentToOperand(0); - if (!(m_graph[get(thisOperand)].prediction() & PredictString)) + if (!(m_graph[get(thisOperand)].prediction() & SpecString)) return false; int indexOperand = registerOffset + argumentToOperand(1); @@ -1538,6 +1567,80 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins } } +void ByteCodeParser::handleGetById( + int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber, + const GetByIdStatus& getByIdStatus) +{ + if (!getByIdStatus.isSimple() + || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { + set(destinationOperand, + addToGraph( + getByIdStatus.makesCalls() ? GetByIdFlush : GetById, + OpInfo(identifierNumber), OpInfo(prediction), base)); + return; + } + + ASSERT(getByIdStatus.structureSet().size()); + + // The implementation of GetByOffset does not know to terminate speculative + // execution if it doesn't have a prediction, so we do it manually. + if (prediction == SpecNone) + addToGraph(ForceOSRExit); + + NodeIndex originalBaseForBaselineJIT = base; + + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.structureSet())), base); + + bool useInlineStorage; + if (!getByIdStatus.chain().isEmpty()) { + Structure* currentStructure = getByIdStatus.structureSet().singletonStructure(); + JSObject* currentObject = 0; + for (unsigned i = 0; i < getByIdStatus.chain().size(); ++i) { + currentObject = asObject(currentStructure->prototypeForLookup(m_inlineStackTop->m_codeBlock)); + currentStructure = getByIdStatus.chain()[i]; + base = addStructureTransitionCheck(currentObject, currentStructure); + } + useInlineStorage = currentStructure->isUsingInlineStorage(); + } else + useInlineStorage = getByIdStatus.structureSet().allAreUsingInlinePropertyStorage(); + + // Unless we want bugs like https://bugs.webkit.org/show_bug.cgi?id=88783, we need to + // ensure that the base of the original get_by_id is kept alive until we're done with + // all of the speculations. We only insert the Phantom if there had been a CheckStructure + // on something other than the base following the CheckStructure on base, or if the + // access was compiled to a WeakJSConstant specific value, in which case we might not + // have any explicit use of the base at all. + if (getByIdStatus.specificValue() || originalBaseForBaselineJIT != base) + addToGraph(Phantom, originalBaseForBaselineJIT); + + if (getByIdStatus.specificValue()) { + ASSERT(getByIdStatus.specificValue().isCell()); + + set(destinationOperand, cellConstant(getByIdStatus.specificValue().asCell())); + return; + } + + NodeIndex propertyStorage; + size_t offsetOffset; + if (useInlineStorage) { + propertyStorage = base; + ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue))); + offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue); + } else { + propertyStorage = addToGraph(GetPropertyStorage, base); + offsetOffset = 0; + } + set(destinationOperand, + addToGraph( + GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), + propertyStorage)); + + StorageAccessData storageAccessData; + storageAccessData.offset = getByIdStatus.offset() + offsetOffset; + storageAccessData.identifierNumber = identifierNumber; + m_graph.m_storageAccessData.append(storageAccessData); +} + void ByteCodeParser::prepareToParseBlock() { for (unsigned i = 0; i < m_constants.size(); ++i) @@ -1972,7 +2075,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) // === Property access operations === case op_get_by_val: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); NodeIndex base = get(currentInstruction[2].u.operand); NodeIndex property = get(currentInstruction[3].u.operand); @@ -1997,7 +2100,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) m_currentProfilingIndex += OPCODE_LENGTH(op_method_check); Instruction* getInstruction = currentInstruction + OPCODE_LENGTH(op_method_check); - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); ASSERT(interpreter->getOpcodeID(getInstruction->u.opcode) == op_get_by_id); @@ -2020,18 +2123,22 @@ bool ByteCodeParser::parseBlock(unsigned limit) // but the slow path (i.e. the normal get_by_id) never fired. addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCallStatus.structure())), base); - if (methodCallStatus.needsPrototypeCheck()) - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCallStatus.prototypeStructure())), cellConstant(methodCallStatus.prototype())); - + if (methodCallStatus.needsPrototypeCheck()) { + addStructureTransitionCheck( + methodCallStatus.prototype(), methodCallStatus.prototypeStructure()); + addToGraph(Phantom, base); + } set(getInstruction[1].u.operand, cellConstant(methodCallStatus.function())); - } else - set(getInstruction[1].u.operand, addToGraph(getByIdStatus.makesCalls() ? GetByIdFlush : GetById, OpInfo(identifier), OpInfo(prediction), base)); + } else { + handleGetById( + getInstruction[1].u.operand, prediction, base, identifier, getByIdStatus); + } m_currentIndex += OPCODE_LENGTH(op_method_check) + OPCODE_LENGTH(op_get_by_id); continue; } case op_get_scoped_var: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); int dst = currentInstruction[1].u.operand; int slot = currentInstruction[2].u.operand; int depth = currentInstruction[3].u.operand; @@ -2049,7 +2156,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) NEXT_OPCODE(op_put_scoped_var); } case op_get_by_id: { - PredictedType prediction = getPredictionWithoutOSRExit(); + SpeculatedType prediction = getPredictionWithoutOSRExit(); NodeIndex base = get(currentInstruction[2].u.operand); unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand]; @@ -2058,34 +2165,8 @@ bool ByteCodeParser::parseBlock(unsigned limit) GetByIdStatus getByIdStatus = GetByIdStatus::computeFor( m_inlineStackTop->m_profiledBlock, m_currentIndex, identifier); - if (getByIdStatus.isSimpleDirect() - && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { - ASSERT(getByIdStatus.structureSet().size()); - - // The implementation of GetByOffset does not know to terminate speculative - // execution if it doesn't have a prediction, so we do it manually. - if (prediction == PredictNone) - addToGraph(ForceOSRExit); - - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.structureSet())), base); - NodeIndex propertyStorage; - size_t offsetOffset; - if (getByIdStatus.structureSet().allAreUsingInlinePropertyStorage()) { - propertyStorage = base; - ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue))); - offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue); - } else { - propertyStorage = addToGraph(GetPropertyStorage, base); - offsetOffset = 0; - } - set(currentInstruction[1].u.operand, addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage)); - - StorageAccessData storageAccessData; - storageAccessData.offset = getByIdStatus.offset() + offsetOffset; - storageAccessData.identifierNumber = identifierNumber; - m_graph.m_storageAccessData.append(storageAccessData); - } else - set(currentInstruction[1].u.operand, addToGraph(getByIdStatus.makesCalls() ? GetByIdFlush : GetById, OpInfo(identifierNumber), OpInfo(prediction), base)); + handleGetById( + currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus); NEXT_OPCODE(op_get_by_id); } @@ -2134,23 +2215,20 @@ bool ByteCodeParser::parseBlock(unsigned limit) addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base); if (!direct) { - if (!putByIdStatus.oldStructure()->storedPrototype().isNull()) - addToGraph( - CheckStructure, - OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure()->storedPrototype().asCell()->structure())), - cellConstant(putByIdStatus.oldStructure()->storedPrototype().asCell())); + if (!putByIdStatus.oldStructure()->storedPrototype().isNull()) { + addStructureTransitionCheck( + putByIdStatus.oldStructure()->storedPrototype().asCell()); + } for (WriteBarrier<Structure>* it = putByIdStatus.structureChain()->head(); *it; ++it) { JSValue prototype = (*it)->storedPrototype(); if (prototype.isNull()) continue; ASSERT(prototype.isCell()); - addToGraph( - CheckStructure, - OpInfo(m_graph.addStructureSet(prototype.asCell()->structure())), - cellConstant(prototype.asCell())); + addStructureTransitionCheck(prototype.asCell()); } } + ASSERT(putByIdStatus.oldStructure()->transitionWatchpointSetHasBeenInvalidated()); addToGraph( PutStructure, OpInfo( @@ -2192,19 +2270,94 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_get_global_var: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); - NodeIndex getGlobalVar = addToGraph(GetGlobalVar, OpInfo(currentInstruction[2].u.operand), OpInfo(prediction)); + JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject(); + + NodeIndex getGlobalVar = addToGraph( + GetGlobalVar, + OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)), + OpInfo(prediction)); set(currentInstruction[1].u.operand, getGlobalVar); NEXT_OPCODE(op_get_global_var); } + + case op_get_global_var_watchable: { + SpeculatedType prediction = getPrediction(); + + JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject(); + + unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand]; + Identifier identifier = m_codeBlock->identifier(identifierNumber); + SymbolTableEntry entry = globalObject->symbolTable().get(identifier.impl()); + if (!entry.couldBeWatched()) { + NodeIndex getGlobalVar = addToGraph( + GetGlobalVar, + OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)), + OpInfo(prediction)); + set(currentInstruction[1].u.operand, getGlobalVar); + NEXT_OPCODE(op_get_global_var_watchable); + } + + // The watchpoint is still intact! This means that we will get notified if the + // current value in the global variable changes. So, we can inline that value. + // Moreover, currently we can assume that this value is a JSFunction*, which + // implies that it's a cell. This simplifies things, since in general we'd have + // to use a JSConstant for non-cells and a WeakJSConstant for cells. So instead + // of having both cases we just assert that the value is a cell. + + // NB. If it wasn't for CSE, GlobalVarWatchpoint would have no need for the + // register pointer. But CSE tracks effects on global variables by comparing + // register pointers. Because CSE executes multiple times while the backend + // executes once, we use the following performance trade-off: + // - The node refers directly to the register pointer to make CSE super cheap. + // - To perform backend code generation, the node only contains the identifier + // number, from which it is possible to get (via a few average-time O(1) + // lookups) to the WatchpointSet. + + addToGraph( + GlobalVarWatchpoint, + OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)), + OpInfo(identifierNumber)); + + JSValue specificValue = globalObject->registerAt(entry.getIndex()).get(); + ASSERT(specificValue.isCell()); + set(currentInstruction[1].u.operand, cellConstant(specificValue.asCell())); + + NEXT_OPCODE(op_get_global_var_watchable); + } case op_put_global_var: { NodeIndex value = get(currentInstruction[2].u.operand); - addToGraph(PutGlobalVar, OpInfo(currentInstruction[1].u.operand), value); + addToGraph( + PutGlobalVar, + OpInfo(m_inlineStackTop->m_codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)), + value); NEXT_OPCODE(op_put_global_var); } + case op_put_global_var_check: { + NodeIndex value = get(currentInstruction[2].u.operand); + CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock; + JSGlobalObject* globalObject = codeBlock->globalObject(); + unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[4].u.operand]; + Identifier identifier = m_codeBlock->identifier(identifierNumber); + SymbolTableEntry entry = globalObject->symbolTable().get(identifier.impl()); + if (!entry.couldBeWatched()) { + addToGraph( + PutGlobalVar, + OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)), + value); + NEXT_OPCODE(op_put_global_var_check); + } + addToGraph( + PutGlobalVarCheck, + OpInfo(codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)), + OpInfo(identifierNumber), + value); + NEXT_OPCODE(op_put_global_var_check); + } + // === Block terminators. === case op_jmp: { @@ -2433,7 +2586,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call_varargs); - PredictedType prediction = PredictNone; + SpeculatedType prediction = SpecNone; if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { m_currentProfilingIndex = m_currentIndex + OPCODE_LENGTH(op_call_varargs); prediction = getPrediction(); @@ -2471,7 +2624,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) LAST_OPCODE(op_jneq_ptr); case op_resolve: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand]; @@ -2482,7 +2635,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_resolve_base: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand]; @@ -2493,7 +2646,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_resolve_global: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); NodeIndex resolve = addToGraph(ResolveGlobal, OpInfo(m_graph.m_resolveGlobalData.size()), OpInfo(prediction)); m_graph.m_resolveGlobalData.append(ResolveGlobalData()); @@ -2747,7 +2900,7 @@ void ByteCodeParser::processPhiStack() } } -void ByteCodeParser::fixVariableAccessPredictions() +void ByteCodeParser::fixVariableAccessSpeculations() { for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) { VariableAccessData* data = &m_graph.m_variableAccessData[i]; @@ -2843,7 +2996,7 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry( , m_caller(byteCodeParser->m_inlineStackTop) { m_argumentPositions.resize(argumentCountIncludingThis); - for (unsigned i = argumentCountIncludingThis; i--;) { + for (int i = 0; i < argumentCountIncludingThis; ++i) { byteCodeParser->m_graph.m_argumentPositions.append(ArgumentPosition()); ArgumentPosition* argumentPosition = &byteCodeParser->m_graph.m_argumentPositions.last(); m_argumentPositions[i] = argumentPosition; @@ -3073,7 +3226,7 @@ bool ByteCodeParser::parse() m_graph.m_blocks[blockIndex].clear(); } - fixVariableAccessPredictions(); + fixVariableAccessSpeculations(); m_graph.m_preservedVars = m_preservedVars; m_graph.m_localVars = m_numLocals; diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h index dc3af636e..4cacd45c1 100644 --- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h @@ -94,6 +94,12 @@ public: addCallArgument(arg1); addCallArgument(arg2); } + + ALWAYS_INLINE void setupArguments(TrustedImmPtr arg1) + { + resetCallArguments(); + addCallArgument(arg1); + } ALWAYS_INLINE void setupArgumentsExecState() { @@ -216,6 +222,15 @@ public: addCallArgument(arg4); } + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImmPtr arg2, GPRReg arg3) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + } + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4) { resetCallArguments(); @@ -424,6 +439,11 @@ public: { setupTwoStubArgs<GPRInfo::argumentGPR0, GPRInfo::argumentGPR1>(arg1, arg2); } + + ALWAYS_INLINE void setupArguments(TrustedImmPtr arg1) + { + move(arg1, GPRInfo::argumentGPR0); + } ALWAYS_INLINE void setupArgumentsExecState() { @@ -554,6 +574,14 @@ public: move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); } + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImmPtr arg2, GPRReg arg3) + { + move(arg3, GPRInfo::argumentGPR3); + move(arg1, GPRInfo::argumentGPR1); + move(arg2, GPRInfo::argumentGPR2); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, TrustedImm32 arg3) { move(arg2, GPRInfo::argumentGPR2); diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp index 0f0a22562..161f51e30 100644 --- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp @@ -288,7 +288,7 @@ private: if (child.op() != GetLocal) return; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog(" Considering GetLocal at @%u.\n", edge.index()); + dataLog(" Considering GetLocal at @%u, local r%d.\n", edge.index(), child.local()); #endif if (child.variableAccessData()->isCaptured()) { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) @@ -302,6 +302,10 @@ private: #endif ASSERT(originalNodeIndex != NoNode); Node* originalNode = &m_graph[originalNodeIndex]; +#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) + dataLog(" Original has local r%d.\n", originalNode->local()); +#endif + ASSERT(child.local() == originalNode->local()); if (changeRef) ASSERT(originalNode->shouldGenerate()); // Possibilities: @@ -389,7 +393,7 @@ private: if (myNode.op() == GetLocal) myNodeIndex = myNode.child1().index(); for (unsigned j = 0; j < AdjacencyList::Size; ++j) - removePotentiallyDeadPhiReference(myNodeIndex, phiNode, j); + removePotentiallyDeadPhiReference(myNodeIndex, phiNode, j, sourceBlock->isReachable); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog("\n"); #endif @@ -414,14 +418,14 @@ private: fixPhis(blockIndex, jettisonedBlockIndex); } - void removePotentiallyDeadPhiReference(NodeIndex myNodeIndex, Node& phiNode, unsigned edgeIndex) + void removePotentiallyDeadPhiReference(NodeIndex myNodeIndex, Node& phiNode, unsigned edgeIndex, bool changeRef) { if (phiNode.children.child(edgeIndex).indexUnchecked() != myNodeIndex) return; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog(" Removing reference at child %u.", edgeIndex); #endif - if (phiNode.shouldGenerate()) + if (changeRef && phiNode.shouldGenerate()) m_graph.deref(myNodeIndex); phiNode.children.removeEdgeFromBag(edgeIndex); } @@ -600,6 +604,8 @@ private: NodeIndex nodeIndex = secondBlock->at(i); Node& node = m_graph[nodeIndex]; + bool childrenAlreadyFixed = false; + switch (node.op()) { case Phantom: { if (!node.child1()) @@ -611,8 +617,12 @@ private: NodeIndex setLocalIndex = firstBlock->variablesAtTail.operand(possibleLocalOp.local()); Node& setLocal = m_graph[setLocalIndex]; - if (setLocal.op() == SetLocal) + if (setLocal.op() == SetLocal) { m_graph.changeEdge(node.children.child1(), setLocal.child1()); + ASSERT(!node.child2()); + ASSERT(!node.child3()); + childrenAlreadyFixed = true; + } } break; } @@ -632,6 +642,19 @@ private: NodeIndex atFirstIndex = firstBlock->variablesAtTail.operand(node.local()); m_graph.changeEdge(node.children.child1(), Edge(skipGetLocal(atFirstIndex)), node.shouldGenerate()); + childrenAlreadyFixed = true; + + if (node.op() != GetLocal) + break; + + NodeIndex atFirstHeadIndex = firstBlock->variablesAtHead.operand(node.local()); + if (atFirstHeadIndex == NoNode) + break; + + if (m_graph[atFirstHeadIndex].op() != Phi) + break; + + firstBlock->variablesAtHead.operand(node.local()) = nodeIndex; break; } @@ -639,20 +662,22 @@ private: break; } - bool changeRef = node.shouldGenerate(); + if (!childrenAlreadyFixed) { + bool changeRef = node.shouldGenerate(); - // If the child is a GetLocal, then we might like to fix it. - if (node.flags() & NodeHasVarArgs) { - for (unsigned childIdx = node.firstChild(); - childIdx < node.firstChild() + node.numChildren(); - ++childIdx) - fixPossibleGetLocal(firstBlock, m_graph.m_varArgChildren[childIdx], changeRef); - } else if (!!node.child1()) { - fixPossibleGetLocal(firstBlock, node.children.child1(), changeRef); - if (!!node.child2()) { - fixPossibleGetLocal(firstBlock, node.children.child2(), changeRef); - if (!!node.child3()) - fixPossibleGetLocal(firstBlock, node.children.child3(), changeRef); + // If the child is a GetLocal, then we might like to fix it. + if (node.flags() & NodeHasVarArgs) { + for (unsigned childIdx = node.firstChild(); + childIdx < node.firstChild() + node.numChildren(); + ++childIdx) + fixPossibleGetLocal(firstBlock, m_graph.m_varArgChildren[childIdx], changeRef); + } else if (!!node.child1()) { + fixPossibleGetLocal(firstBlock, node.children.child1(), changeRef); + if (!!node.child2()) { + fixPossibleGetLocal(firstBlock, node.children.child2(), changeRef); + if (!!node.child3()) + fixPossibleGetLocal(firstBlock, node.children.child3(), changeRef); + } } } diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp index 31488cb1c..a362e6e97 100644 --- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp @@ -48,9 +48,10 @@ public: bool run() { + m_changed = false; for (unsigned block = 0; block < m_graph.m_blocks.size(); ++block) performBlockCSE(m_graph.m_blocks[block].get()); - return true; // Maybe we'll need to make this reason about whether it changed the graph in an actionable way? + return m_changed; } private: @@ -193,18 +194,18 @@ private: return NoNode; } - NodeIndex globalVarLoadElimination(unsigned varNumber, JSGlobalObject* globalObject) + NodeIndex globalVarLoadElimination(WriteBarrier<Unknown>* registerPointer) { for (unsigned i = m_indexInBlock; i--;) { NodeIndex index = m_currentBlock->at(i); Node& node = m_graph[index]; switch (node.op()) { case GetGlobalVar: - if (node.varNumber() == varNumber && codeBlock()->globalObjectFor(node.codeOrigin) == globalObject) + if (node.registerPointer() == registerPointer) return index; break; case PutGlobalVar: - if (node.varNumber() == varNumber && codeBlock()->globalObjectFor(node.codeOrigin) == globalObject) + if (node.registerPointer() == registerPointer) return node.child1().index(); break; default: @@ -216,7 +217,30 @@ private: return NoNode; } - NodeIndex globalVarStoreElimination(unsigned varNumber, JSGlobalObject* globalObject) + bool globalVarWatchpointElimination(WriteBarrier<Unknown>* registerPointer) + { + for (unsigned i = m_indexInBlock; i--;) { + NodeIndex index = m_currentBlock->at(i); + Node& node = m_graph[index]; + switch (node.op()) { + case GlobalVarWatchpoint: + if (node.registerPointer() == registerPointer) + return true; + break; + case PutGlobalVar: + if (node.registerPointer() == registerPointer) + return false; + break; + default: + break; + } + if (m_graph.clobbersWorld(index)) + break; + } + return false; + } + + NodeIndex globalVarStoreElimination(WriteBarrier<Unknown>* registerPointer) { for (unsigned i = m_indexInBlock; i--;) { NodeIndex index = m_currentBlock->at(i); @@ -225,12 +249,13 @@ private: continue; switch (node.op()) { case PutGlobalVar: - if (node.varNumber() == varNumber && codeBlock()->globalObjectFor(node.codeOrigin) == globalObject) + case PutGlobalVarCheck: + if (node.registerPointer() == registerPointer) return index; break; case GetGlobalVar: - if (node.varNumber() == varNumber && codeBlock()->globalObjectFor(node.codeOrigin) == globalObject) + if (node.registerPointer() == registerPointer) return NoNode; break; @@ -316,6 +341,12 @@ private: return true; break; + case StructureTransitionWatchpoint: + if (node.child1() == child1 + && structureSet.contains(node.structure())) + return true; + break; + case PutStructure: if (node.child1() == child1 && structureSet.contains(node.structureTransitionData().newStructure)) @@ -347,6 +378,53 @@ private: return false; } + bool structureTransitionWatchpointElimination(Structure* structure, NodeIndex child1) + { + for (unsigned i = m_indexInBlock; i--;) { + NodeIndex index = m_currentBlock->at(i); + if (index == child1) + break; + + Node& node = m_graph[index]; + switch (node.op()) { + case CheckStructure: + if (node.child1() == child1 + && node.structureSet().containsOnly(structure)) + return true; + break; + + case PutStructure: + ASSERT(node.structureTransitionData().previousStructure != structure); + break; + + case PutByOffset: + // Setting a property cannot change the structure. + break; + + case PutByVal: + case PutByValAlias: + if (m_graph.byValIsPure(node)) { + // If PutByVal speculates that it's accessing an array with an + // integer index, then it's impossible for it to cause a structure + // change. + break; + } + return false; + + case StructureTransitionWatchpoint: + if (node.structure() == structure && node.child1() == child1) + return true; + break; + + default: + if (m_graph.clobbersWorld(index)) + return false; + break; + } + } + return false; + } + NodeIndex putStructureStoreElimination(NodeIndex child1) { for (unsigned i = m_indexInBlock; i--;) { @@ -538,8 +616,8 @@ private: Node& node = m_graph[index]; switch (node.op()) { case GetIndexedPropertyStorage: { - PredictedType basePrediction = m_graph[node.child2()].prediction(); - bool nodeHasIntegerIndexPrediction = !(!(basePrediction & PredictInt32) && basePrediction); + SpeculatedType basePrediction = m_graph[node.child2()].prediction(); + bool nodeHasIntegerIndexPrediction = !(!(basePrediction & SpecInt32) && basePrediction); if (node.child1() == child1 && hasIntegerIndexPrediction == nodeHasIntegerIndexPrediction) return index; break; @@ -556,7 +634,7 @@ private: break; case PutByVal: - if (isFixedIndexedStorageObjectPrediction(m_graph[node.child1()].prediction()) && m_graph.byValIsPure(node)) + if (isFixedIndexedStorageObjectSpeculation(m_graph[node.child1()].prediction()) && m_graph.byValIsPure(node)) break; return NoNode; @@ -619,9 +697,22 @@ private: return NoNode; } - // This returns the Flush node that is keeping a SetLocal alive. - NodeIndex setLocalStoreElimination(VirtualRegister local, NodeIndex expectedNodeIndex) + struct SetLocalStoreEliminationResult { + SetLocalStoreEliminationResult() + : mayBeAccessed(false) + , mayExit(false) + , mayClobberWorld(false) + { + } + + bool mayBeAccessed; + bool mayExit; + bool mayClobberWorld; + }; + SetLocalStoreEliminationResult setLocalStoreElimination( + VirtualRegister local, NodeIndex expectedNodeIndex) { + SetLocalStoreEliminationResult result; for (unsigned i = m_indexInBlock; i--;) { NodeIndex index = m_currentBlock->at(i); Node& node = m_graph[index]; @@ -631,46 +722,67 @@ private: case GetLocal: case Flush: if (node.local() == local) - return NoNode; + result.mayBeAccessed = true; break; case GetLocalUnlinked: if (node.unlinkedLocal() == local) - return NoNode; + result.mayBeAccessed = true; break; case SetLocal: { if (node.local() != local) break; if (index != expectedNodeIndex) - return NoNode; + result.mayBeAccessed = true; if (m_graph[index].refCount() > 1) - return NoNode; - return index; + result.mayBeAccessed = true; + return result; } case GetScopeChain: if (m_graph.uncheckedActivationRegisterFor(node.codeOrigin) == local) - return NoNode; + result.mayBeAccessed = true; + break; + + case CheckArgumentsNotCreated: + case GetMyArgumentsLength: + case GetMyArgumentsLengthSafe: + if (m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin) == local) + result.mayBeAccessed = true; + break; + + case GetMyArgumentByVal: + case GetMyArgumentByValSafe: + result.mayBeAccessed = true; + break; + + case GetByVal: + // If this is accessing arguments then it's potentially accessing locals. + if (m_graph[node.child1()].shouldSpeculateArguments()) + result.mayBeAccessed = true; break; + case CreateArguments: case TearOffActivation: case TearOffArguments: // If an activation is being torn off then it means that captured variables // are live. We could be clever here and check if the local qualifies as an // argument register. But that seems like it would buy us very little since // any kind of tear offs are rare to begin with. - return NoNode; + result.mayBeAccessed = true; + break; default: - if (m_graph.clobbersWorld(index)) - return NoNode; break; } - if (node.canExit()) - return NoNode; + result.mayExit |= node.canExit(); + result.mayClobberWorld |= m_graph.clobbersWorld(index); } - return NoNode; + ASSERT_NOT_REACHED(); + // Be safe in release mode. + result.mayBeAccessed = true; + return result; } void performSubstitution(Edge& child, bool addRef = true) @@ -848,35 +960,64 @@ private: m_graph.ref(phiIndex); } } + m_changed = true; break; } case GetLocalUnlinked: { NodeIndex relevantLocalOpIgnored; - setReplacement(getLocalLoadElimination(node.unlinkedLocal(), relevantLocalOpIgnored)); + m_changed |= setReplacement(getLocalLoadElimination(node.unlinkedLocal(), relevantLocalOpIgnored)); break; } case Flush: { - if (m_fixpointState == FixpointNotConverged) - break; VariableAccessData* variableAccessData = node.variableAccessData(); - if (!variableAccessData->isCaptured()) - break; VirtualRegister local = variableAccessData->local(); - NodeIndex replacementIndex = setLocalStoreElimination(local, node.child1().index()); - if (replacementIndex == NoNode) - break; + NodeIndex replacementIndex = node.child1().index(); Node& replacement = m_graph[replacementIndex]; + if (replacement.op() != SetLocal) + break; + ASSERT(replacement.variableAccessData() == variableAccessData); + // FIXME: We should be able to remove SetLocals that can exit; we just need + // to replace them with appropriate type checks. + if (m_fixpointState == FixpointNotConverged) { + // Need to be conservative at this time; if the SetLocal has any chance of performing + // any speculations then we cannot do anything. + if (variableAccessData->isCaptured()) { + // Captured SetLocals never speculate and hence never exit. + } else { + if (variableAccessData->shouldUseDoubleFormat()) + break; + SpeculatedType prediction = variableAccessData->argumentAwarePrediction(); + if (isInt32Speculation(prediction)) + break; + if (isArraySpeculation(prediction)) + break; + if (isBooleanSpeculation(prediction)) + break; + } + } else { + if (replacement.canExit()) + break; + } + SetLocalStoreEliminationResult result = + setLocalStoreElimination(local, replacementIndex); + if (result.mayBeAccessed || result.mayClobberWorld) + break; ASSERT(replacement.op() == SetLocal); ASSERT(replacement.refCount() == 1); ASSERT(replacement.shouldGenerate()); + // FIXME: Investigate using mayExit as a further optimization. node.setOpAndDefaultFlags(Phantom); NodeIndex dataNodeIndex = replacement.child1().index(); ASSERT(m_graph[dataNodeIndex].hasResult()); m_graph.clearAndDerefChild1(node); node.children.child1() = Edge(dataNodeIndex); m_graph.ref(dataNodeIndex); + NodeIndex oldTailIndex = m_currentBlock->variablesAtTail.operand(local); + if (oldTailIndex == m_compileIndex) + m_currentBlock->variablesAtTail.operand(local) = replacementIndex; + m_changed = true; break; } @@ -918,13 +1059,19 @@ private: // Finally handle heap accesses. These are not quite pure, but we can still // optimize them provided that some subtle conditions are met. case GetGlobalVar: - setReplacement(globalVarLoadElimination(node.varNumber(), codeBlock()->globalObjectFor(node.codeOrigin))); + setReplacement(globalVarLoadElimination(node.registerPointer())); + break; + + case GlobalVarWatchpoint: + if (globalVarWatchpointElimination(node.registerPointer())) + eliminate(); break; case PutGlobalVar: + case PutGlobalVarCheck: if (m_fixpointState == FixpointNotConverged) break; - eliminate(globalVarStoreElimination(node.varNumber(), codeBlock()->globalObjectFor(node.codeOrigin))); + eliminate(globalVarStoreElimination(node.registerPointer())); break; case GetByVal: @@ -944,6 +1091,11 @@ private: eliminate(); break; + case StructureTransitionWatchpoint: + if (structureTransitionWatchpointElimination(node.structure(), node.child1().index())) + eliminate(); + break; + case PutStructure: if (m_fixpointState == FixpointNotConverged) break; @@ -956,8 +1108,8 @@ private: break; case GetIndexedPropertyStorage: { - PredictedType basePrediction = m_graph[node.child2()].prediction(); - bool nodeHasIntegerIndexPrediction = !(!(basePrediction & PredictInt32) && basePrediction); + SpeculatedType basePrediction = m_graph[node.child2()].prediction(); + bool nodeHasIntegerIndexPrediction = !(!(basePrediction & SpecInt32) && basePrediction); setReplacement(getIndexedPropertyStorageLoadElimination(node.child1().index(), nodeHasIntegerIndexPrediction)); break; } @@ -1010,6 +1162,7 @@ private: Vector<NodeIndex, 16> m_replacements; FixedArray<unsigned, LastNodeType> m_lastSeen; OptimizationFixpointState m_fixpointState; + bool m_changed; // Only tracks changes that have a substantive effect on other optimizations. }; bool performCSE(Graph& graph, OptimizationFixpointState fixpointState) diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.h b/Source/JavaScriptCore/dfg/DFGCapabilities.h index 694e886ee..027b0f78b 100644 --- a/Source/JavaScriptCore/dfg/DFGCapabilities.h +++ b/Source/JavaScriptCore/dfg/DFGCapabilities.h @@ -123,7 +123,9 @@ inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instructi case op_put_by_id_transition_direct: case op_put_by_id_transition_normal: case op_get_global_var: + case op_get_global_var_watchable: case op_put_global_var: + case op_put_global_var_check: case op_jmp: case op_loop: case op_jtrue: diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h index b2e3bb4ee..fce76c68c 100644 --- a/Source/JavaScriptCore/dfg/DFGCommon.h +++ b/Source/JavaScriptCore/dfg/DFGCommon.h @@ -55,6 +55,8 @@ #else #define DFG_ENABLE_VALIDATION 0 #endif +// Enable validation on completion of each phase. +#define DFG_ENABLE_PER_PHASE_VALIDATION 0 // Consistency check contents compiler data structures. #define DFG_ENABLE_CONSISTENCY_CHECK 0 // Emit a breakpoint into the head of every generated function, to aid debugging in GDB. diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp index 1e75ddea1..9e6720c80 100644 --- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp @@ -56,15 +56,44 @@ public: continue; if (!block->cfaFoundConstants) continue; +#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) + dataLog("Constant folding considering Block #%u.\n", blockIndex); +#endif state.beginBasicBlock(block); for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { if (!state.isValid()) break; - state.execute(indexInBlock); NodeIndex nodeIndex = block->at(indexInBlock); Node& node = m_graph[nodeIndex]; + + bool eliminated = false; + + switch (node.op()) { + case CheckArgumentsNotCreated: { + if (!isEmptySpeculation( + state.variables().operand( + m_graph.argumentsRegisterFor(node.codeOrigin)).m_type)) + break; + ASSERT(node.refCount() == 1); + node.setOpAndDefaultFlags(Phantom); + eliminated = true; + break; + } + + // FIXME: This would be a great place to remove CheckStructure's. + + default: + break; + } + + if (eliminated) { + changed = true; + continue; + } + + state.execute(indexInBlock); if (!node.shouldGenerate() - || m_graph.clobbersWorld(node) + || state.didClobber() || node.hasConstant()) continue; JSValue value = state.forNode(nodeIndex).value(); @@ -74,11 +103,9 @@ public: Node phantom(Phantom, node.codeOrigin); if (node.op() == GetLocal) { - ASSERT(m_graph[node.child1()].op() == Phi); - ASSERT(!m_graph[node.child1()].hasResult()); - NodeIndex previousLocalAccess = NoNode; - if (block->variablesAtHead.operand(node.local()) == nodeIndex) { + if (block->variablesAtHead.operand(node.local()) == nodeIndex + && m_graph[node.child1()].op() == Phi) { // We expect this to be the common case. ASSERT(block->isInPhis(node.child1().index())); previousLocalAccess = node.child1().index(); @@ -86,7 +113,7 @@ public: } else { ASSERT(indexInBlock > 0); // Must search for the previous access to this local. - for (BlockIndex subIndexInBlock = indexInBlock - 1; subIndexInBlock--;) { + for (BlockIndex subIndexInBlock = indexInBlock; subIndexInBlock--;) { NodeIndex subNodeIndex = block->at(subIndexInBlock); Node& subNode = m_graph[subNodeIndex]; if (!subNode.shouldGenerate()) @@ -97,13 +124,6 @@ public: continue; // The two must have been unified. ASSERT(subNode.variableAccessData() == node.variableAccessData()); - // Currently, the previous node must be a flush. - // NOTE: This assertion should be removed if we ever do - // constant folding on captured variables. In particular, - // this code does not require the previous node to be a flush, - // but we are asserting this anyway because it is a constraint - // of the IR and this is as good a place as any to assert it. - ASSERT(subNode.op() == Flush); previousLocalAccess = subNodeIndex; break; } diff --git a/Source/JavaScriptCore/dfg/DFGCorrectableJumpPoint.h b/Source/JavaScriptCore/dfg/DFGCorrectableJumpPoint.h index bfa149604..93cb49c01 100644 --- a/Source/JavaScriptCore/dfg/DFGCorrectableJumpPoint.h +++ b/Source/JavaScriptCore/dfg/DFGCorrectableJumpPoint.h @@ -66,6 +66,11 @@ public: #endif } + bool isSet() + { + return m_codeOffset != std::numeric_limits<uint32_t>::max(); + } + void switchToLateJump(MacroAssembler::PatchableJump check) { #ifndef NDEBUG diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp index 6ebe338f5..e932792df 100644 --- a/Source/JavaScriptCore/dfg/DFGDriver.cpp +++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp @@ -82,10 +82,11 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo changed |= performConstantFolding(dfg); changed |= performArgumentsSimplification(dfg); changed |= performCFGSimplification(dfg); + changed |= performCSE(dfg, FixpointNotConverged); if (!changed) break; - performCSE(dfg, FixpointNotConverged); dfg.resetExitStates(); + performFixup(dfg); } performCSE(dfg, FixpointConverged); #if DFG_ENABLE(DEBUG_VERBOSE) @@ -94,10 +95,13 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo dfg.m_dominators.compute(dfg); performVirtualRegisterAllocation(dfg); + GraphDumpMode modeForFinalValidate = DumpGraph; #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("Graph after optimization:\n"); dfg.dump(); + modeForFinalValidate = DontDumpGraph; #endif + validate(dfg, modeForFinalValidate); JITCompiler dataFlowJIT(dfg); bool result; diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp index e54d2cfaf..f6e3c0a96 100644 --- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp @@ -74,13 +74,13 @@ private: switch (op) { case GetById: { - if (!isInt32Prediction(m_graph[m_compileIndex].prediction())) + if (!isInt32Speculation(m_graph[m_compileIndex].prediction())) break; if (codeBlock()->identifier(node.identifierNumber()) != globalData().propertyNames->length) break; - bool isArray = isArrayPrediction(m_graph[node.child1()].prediction()); - bool isArguments = isArgumentsPrediction(m_graph[node.child1()].prediction()); - bool isString = isStringPrediction(m_graph[node.child1()].prediction()); + bool isArray = isArraySpeculation(m_graph[node.child1()].prediction()); + bool isArguments = isArgumentsSpeculation(m_graph[node.child1()].prediction()); + bool isString = isStringSpeculation(m_graph[node.child1()].prediction()); bool isInt8Array = m_graph[node.child1()].shouldSpeculateInt8Array(); bool isInt16Array = m_graph[node.child1()].shouldSpeculateInt16Array(); bool isInt32Array = m_graph[node.child1()].shouldSpeculateInt32Array(); @@ -129,10 +129,10 @@ private: break; } case GetIndexedPropertyStorage: { - PredictedType basePrediction = m_graph[node.child2()].prediction(); - if ((!(basePrediction & PredictInt32) && basePrediction) + SpeculatedType basePrediction = m_graph[node.child2()].prediction(); + if ((!(basePrediction & SpecInt32) && basePrediction) || m_graph[node.child1()].shouldSpeculateArguments() - || !isActionableArrayPrediction(m_graph[node.child1()].prediction())) { + || !isActionableArraySpeculation(m_graph[node.child1()].prediction())) { node.setOpAndDefaultFlags(Nop); m_graph.clearAndDerefChild1(node); m_graph.clearAndDerefChild2(node); @@ -150,7 +150,8 @@ private: } case ValueToInt32: { - if (m_graph[node.child1()].shouldSpeculateNumber()) { + if (m_graph[node.child1()].shouldSpeculateNumber() + && node.mustGenerate()) { node.clearFlags(NodeMustGenerate); m_graph.deref(m_compileIndex); } @@ -284,7 +285,7 @@ private: Node newDivision = oldDivision; newDivision.setRefCount(2); - newDivision.predict(PredictDouble); + newDivision.predict(SpecDouble); NodeIndex newDivisionIndex = m_graph.size(); oldDivision.setOp(DoubleAsInt32); @@ -318,7 +319,7 @@ private: break; if (!m_graph[node.child2()].shouldSpeculateInteger()) break; - if (isActionableIntMutableArrayPrediction(m_graph[node.child1()].prediction())) { + if (isActionableIntMutableArraySpeculation(m_graph[node.child1()].prediction())) { if (m_graph[node.child3()].isConstant()) break; if (m_graph[node.child3()].shouldSpeculateInteger()) @@ -326,7 +327,7 @@ private: fixDoubleEdge(2); break; } - if (isActionableFloatMutableArrayPrediction(m_graph[node.child1()].prediction())) { + if (isActionableFloatMutableArraySpeculation(m_graph[node.child1()].prediction())) { fixDoubleEdge(2); break; } @@ -390,7 +391,7 @@ private: m_insertionSet.append(m_indexInBlock, resultIndex); Node& int32ToDouble = m_graph[resultIndex]; - int32ToDouble.predict(PredictDouble); + int32ToDouble.predict(SpecDouble); int32ToDouble.ref(); } diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp index 4562e30ee..93de024d7 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.cpp +++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp @@ -76,7 +76,7 @@ const char* Graph::nameOfVariableAccessData(VariableAccessData* variableAccessDa if (variableAccessData->isCaptured()) *ptr++ = '*'; - ptr.strcat(predictionToAbbreviatedString(variableAccessData->prediction())); + ptr.strcat(speculationToAbbreviatedString(variableAccessData->prediction())); *ptr++ = 0; @@ -169,7 +169,7 @@ void Graph::dump(NodeIndex nodeIndex) dataLog("%s@%u%s", useKindToString(m_varArgChildren[childIdx].useKind()), m_varArgChildren[childIdx].index(), - predictionToAbbreviatedString( + speculationToAbbreviatedString( at(m_varArgChildren[childIdx]).prediction())); } } else { @@ -177,19 +177,19 @@ void Graph::dump(NodeIndex nodeIndex) dataLog("%s@%u%s", useKindToString(node.child1().useKind()), node.child1().index(), - predictionToAbbreviatedString(at(node.child1()).prediction())); + speculationToAbbreviatedString(at(node.child1()).prediction())); } if (!!node.child2()) { dataLog(", %s@%u%s", useKindToString(node.child2().useKind()), node.child2().index(), - predictionToAbbreviatedString(at(node.child2()).prediction())); + speculationToAbbreviatedString(at(node.child2()).prediction())); } if (!!node.child3()) { dataLog(", %s@%u%s", useKindToString(node.child3().useKind()), node.child3().index(), - predictionToAbbreviatedString(at(node.child3()).prediction())); + speculationToAbbreviatedString(at(node.child3()).prediction())); } hasPrinted = !!node.child1(); } @@ -202,6 +202,13 @@ void Graph::dump(NodeIndex nodeIndex) dataLog("%svar%u", hasPrinted ? ", " : "", node.varNumber()); hasPrinted = true; } + if (node.hasRegisterPointer()) { + dataLog( + "%sglobal%u(%p)", hasPrinted ? ", " : "", + globalObjectFor(node.codeOrigin)->findRegisterIndex(node.registerPointer()), + node.registerPointer()); + hasPrinted = true; + } if (node.hasIdentifier()) { dataLog("%sid%u{%s}", hasPrinted ? ", " : "", node.identifierNumber(), m_codeBlock->identifier(node.identifierNumber()).ustring().utf8().data()); hasPrinted = true; @@ -212,6 +219,10 @@ void Graph::dump(NodeIndex nodeIndex) hasPrinted = true; } } + if (node.hasStructure()) { + dataLog("%sstruct(%p)", hasPrinted ? ", " : "", node.structure()); + hasPrinted = true; + } if (node.hasStructureTransitionData()) { dataLog("%sstruct(%p -> %p)", hasPrinted ? ", " : "", node.structureTransitionData().previousStructure, node.structureTransitionData().newStructure); hasPrinted = true; @@ -269,9 +280,9 @@ void Graph::dump(NodeIndex nodeIndex) if (!skipped) { if (node.hasVariableAccessData()) - dataLog(" predicting %s, double ratio %lf%s", predictionToString(node.variableAccessData()->prediction()), node.variableAccessData()->doubleVoteRatio(), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : ""); + dataLog(" predicting %s, double ratio %lf%s", speculationToString(node.variableAccessData()->prediction()), node.variableAccessData()->doubleVoteRatio(), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : ""); else if (node.hasHeapPrediction()) - dataLog(" predicting %s", predictionToString(node.getHeapPrediction())); + dataLog(" predicting %s", speculationToString(node.getHeapPrediction())); } dataLog("\n"); @@ -386,7 +397,7 @@ void Graph::predictArgumentTypes() at(m_arguments[arg]).variableAccessData()->predict(profile->computeUpdatedPrediction()); #if DFG_ENABLE(DEBUG_VERBOSE) - dataLog("Argument [%zu] prediction: %s\n", arg, predictionToString(at(m_arguments[arg]).variableAccessData()->prediction())); + dataLog("Argument [%zu] prediction: %s\n", arg, speculationToString(at(m_arguments[arg]).variableAccessData()->prediction())); #endif } } diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index 8ca3e2047..acc9ff472 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -187,9 +187,9 @@ public: BlockIndex blockIndexForBytecodeOffset(Vector<BlockIndex>& blocks, unsigned bytecodeBegin); - PredictedType getJSConstantPrediction(Node& node) + SpeculatedType getJSConstantSpeculation(Node& node) { - return predictionFromValue(node.valueOfJSConstant(m_codeBlock)); + return speculationFromValue(node.valueOfJSConstant(m_codeBlock)); } bool addShouldSpeculateInteger(Node& add) @@ -258,6 +258,13 @@ public: { return at(nodeIndex).isBooleanConstant(m_codeBlock); } + bool isCellConstant(NodeIndex nodeIndex) + { + if (!isJSConstant(nodeIndex)) + return false; + JSValue value = valueOfJSConstant(nodeIndex); + return value.isCell() && !!value; + } bool isFunctionConstant(NodeIndex nodeIndex) { if (!isJSConstant(nodeIndex)) @@ -310,6 +317,11 @@ public: return &m_structureTransitionData.last(); } + JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin) + { + return m_codeBlock->globalObjectFor(codeOrigin); + } + ExecutableBase* executableFor(InlineCallFrame* inlineCallFrame) { if (!inlineCallFrame) @@ -424,17 +436,17 @@ public: bool isPredictedNumerical(Node& node) { - PredictedType left = at(node.child1()).prediction(); - PredictedType right = at(node.child2()).prediction(); - return isNumberPrediction(left) && isNumberPrediction(right); + SpeculatedType left = at(node.child1()).prediction(); + SpeculatedType right = at(node.child2()).prediction(); + return isNumberSpeculation(left) && isNumberSpeculation(right); } bool byValIsPure(Node& node) { return at(node.child2()).shouldSpeculateInteger() && ((node.op() == PutByVal || node.op() == PutByValAlias) - ? isActionableMutableArrayPrediction(at(node.child1()).prediction()) - : isActionableArrayPrediction(at(node.child1()).prediction())); + ? isActionableMutableArraySpeculation(at(node.child1()).prediction()) + : isActionableArraySpeculation(at(node.child1()).prediction())); } bool clobbersWorld(Node& node) diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp index 54b5aaee6..561f51615 100644 --- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp +++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp @@ -44,7 +44,11 @@ void JITCompiler::linkOSRExits() { for (unsigned i = 0; i < codeBlock()->numberOfOSRExits(); ++i) { OSRExit& exit = codeBlock()->osrExit(i); - exit.m_check.initialJump().link(this); + ASSERT(!exit.m_check.isSet() == (exit.m_watchpointIndex != std::numeric_limits<unsigned>::max())); + if (exit.m_watchpointIndex == std::numeric_limits<unsigned>::max()) + exit.m_check.initialJump().link(this); + else + codeBlock()->watchpoint(exit.m_watchpointIndex).setDestination(label()); jitAssertHasValidCallFrame(); store32(TrustedImm32(i), &globalData()->osrExitIndex); exit.m_check.switchToLateJump(patchableJump()); @@ -124,16 +128,14 @@ void JITCompiler::link(LinkBuffer& linkBuffer) for (unsigned i = 0; i < m_calls.size(); ++i) linkBuffer.link(m_calls[i].m_call, m_calls[i].m_function); - if (m_codeBlock->needsCallReturnIndices()) { - m_codeBlock->callReturnIndexVector().reserveCapacity(m_exceptionChecks.size()); - for (unsigned i = 0; i < m_exceptionChecks.size(); ++i) { - unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_exceptionChecks[i].m_call); - CodeOrigin codeOrigin = m_exceptionChecks[i].m_codeOrigin; - while (codeOrigin.inlineCallFrame) - codeOrigin = codeOrigin.inlineCallFrame->caller; - unsigned exceptionInfo = codeOrigin.bytecodeIndex; - m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(returnAddressOffset, exceptionInfo)); - } + m_codeBlock->callReturnIndexVector().reserveCapacity(m_exceptionChecks.size()); + for (unsigned i = 0; i < m_exceptionChecks.size(); ++i) { + unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_exceptionChecks[i].m_call); + CodeOrigin codeOrigin = m_exceptionChecks[i].m_codeOrigin; + while (codeOrigin.inlineCallFrame) + codeOrigin = codeOrigin.inlineCallFrame->caller; + unsigned exceptionInfo = codeOrigin.bytecodeIndex; + m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(returnAddressOffset, exceptionInfo)); } Vector<CodeOriginAtCallReturnOffset>& codeOrigins = m_codeBlock->codeOrigins(); @@ -190,6 +192,8 @@ void JITCompiler::link(LinkBuffer& linkBuffer) OSRExit& exit = codeBlock()->osrExit(i); linkBuffer.link(exit.m_check.lateJump(), target); exit.m_check.correctLateJump(linkBuffer); + if (exit.m_watchpointIndex != std::numeric_limits<unsigned>::max()) + codeBlock()->watchpoint(exit.m_watchpointIndex).correctLabels(linkBuffer); } codeBlock()->shrinkToFit(CodeBlock::LateShrink); @@ -216,7 +220,9 @@ bool JITCompiler::compile(JITCode& entry) link(linkBuffer); speculative.linkOSREntries(linkBuffer); - entry = JITCode(linkBuffer.finalizeCode(), JITCode::DFGJIT); + entry = JITCode( + FINALIZE_CODE(linkBuffer, ("DFG program/eval CodeBlock %p", m_codeBlock)), + JITCode::DFGJIT); return true; } @@ -298,7 +304,9 @@ bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi linkBuffer.link(callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck); entryWithArityCheck = linkBuffer.locationOf(arityCheck); - entry = JITCode(linkBuffer.finalizeCode(), JITCode::DFGJIT); + entry = JITCode( + FINALIZE_CODE(linkBuffer, ("DFG function CodeBlock %p", m_codeBlock)), + JITCode::DFGJIT); return true; } diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h index d3ff3be07..9d69ec9f3 100644 --- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h +++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h @@ -260,9 +260,9 @@ public: } // Helper methods to get predictions - PredictedType getPrediction(Node& node) { return node.prediction(); } - PredictedType getPrediction(NodeIndex nodeIndex) { return getPrediction(graph()[nodeIndex]); } - PredictedType getPrediction(Edge nodeUse) { return getPrediction(nodeUse.index()); } + SpeculatedType getSpeculation(Node& node) { return node.prediction(); } + SpeculatedType getSpeculation(NodeIndex nodeIndex) { return getSpeculation(graph()[nodeIndex]); } + SpeculatedType getSpeculation(Edge nodeUse) { return getSpeculation(nodeUse.index()); } #if USE(JSVALUE32_64) void* addressOfDoubleConstant(NodeIndex nodeIndex) @@ -288,6 +288,12 @@ public: m_codeBlock->appendWeakReference(target); } + void addWeakReferences(const StructureSet& structureSet) + { + for (unsigned i = structureSet.size(); i--;) + addWeakReference(structureSet[i]); + } + void addWeakReferenceTransition(JSCell* codeOrigin, JSCell* from, JSCell* to) { m_codeBlock->appendWeakReferenceTransition(codeOrigin, from, to); diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index 12ebba823..64e6fe097 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -39,7 +39,7 @@ #include "DFGVariableAccessData.h" #include "JSValue.h" #include "Operands.h" -#include "PredictedType.h" +#include "SpeculatedType.h" #include "ValueProfile.h" namespace JSC { namespace DFG { @@ -82,7 +82,7 @@ struct Node { , children(AdjacencyList::Fixed, child1, child2, child3) , m_virtualRegister(InvalidVirtualRegister) , m_refCount(0) - , m_prediction(PredictNone) + , m_prediction(SpecNone) { setOpAndDefaultFlags(op); ASSERT(!(m_flags & NodeHasVarArgs)); @@ -95,7 +95,7 @@ struct Node { , m_virtualRegister(InvalidVirtualRegister) , m_refCount(0) , m_opInfo(imm.m_value) - , m_prediction(PredictNone) + , m_prediction(SpecNone) { setOpAndDefaultFlags(op); ASSERT(!(m_flags & NodeHasVarArgs)); @@ -109,7 +109,7 @@ struct Node { , m_refCount(0) , m_opInfo(imm1.m_value) , m_opInfo2(safeCast<unsigned>(imm2.m_value)) - , m_prediction(PredictNone) + , m_prediction(SpecNone) { setOpAndDefaultFlags(op); ASSERT(!(m_flags & NodeHasVarArgs)); @@ -123,7 +123,7 @@ struct Node { , m_refCount(0) , m_opInfo(imm1.m_value) , m_opInfo2(safeCast<unsigned>(imm2.m_value)) - , m_prediction(PredictNone) + , m_prediction(SpecNone) { setOpAndDefaultFlags(op); ASSERT(m_flags & NodeHasVarArgs); @@ -421,7 +421,7 @@ struct Node { bool hasVarNumber() { - return op() == GetGlobalVar || op() == PutGlobalVar || op() == GetScopedVar || op() == PutScopedVar; + return op() == GetScopedVar || op() == PutScopedVar; } unsigned varNumber() @@ -429,6 +429,27 @@ struct Node { ASSERT(hasVarNumber()); return m_opInfo; } + + bool hasIdentifierNumberForCheck() + { + return op() == GlobalVarWatchpoint || op() == PutGlobalVarCheck; + } + + unsigned identifierNumberForCheck() + { + ASSERT(hasIdentifierNumberForCheck()); + return m_opInfo2; + } + + bool hasRegisterPointer() + { + return op() == GetGlobalVar || op() == PutGlobalVar || op() == GlobalVarWatchpoint || op() == PutGlobalVarCheck; + } + + WriteBarrier<Unknown>* registerPointer() + { + return bitwise_cast<WriteBarrier<Unknown>*>(m_opInfo); + } bool hasScopeChainDepth() { @@ -584,17 +605,17 @@ struct Node { } } - PredictedType getHeapPrediction() + SpeculatedType getHeapPrediction() { ASSERT(hasHeapPrediction()); - return static_cast<PredictedType>(m_opInfo2); + return static_cast<SpeculatedType>(m_opInfo2); } - bool predictHeap(PredictedType prediction) + bool predictHeap(SpeculatedType prediction) { ASSERT(hasHeapPrediction()); - return mergePrediction(m_opInfo2, prediction); + return mergeSpeculation(m_opInfo2, prediction); } bool hasFunctionCheckData() @@ -630,6 +651,17 @@ struct Node { return *reinterpret_cast<StructureSet*>(m_opInfo); } + bool hasStructure() + { + return op() == StructureTransitionWatchpoint; + } + + Structure* structure() + { + ASSERT(hasStructure()); + return reinterpret_cast<Structure*>(m_opInfo); + } + bool hasStorageAccessData() { return op() == GetByOffset || op() == PutByOffset; @@ -682,6 +714,17 @@ struct Node { ASSERT(m_virtualRegister == InvalidVirtualRegister); m_virtualRegister = virtualRegister; } + + bool hasArgumentPositionStart() + { + return op() == InlineStart; + } + + unsigned argumentPositionStart() + { + ASSERT(hasArgumentPositionStart()); + return m_opInfo; + } bool shouldGenerate() { @@ -756,114 +799,114 @@ struct Node { return children.numChildren(); } - PredictedType prediction() + SpeculatedType prediction() { return m_prediction; } - bool predict(PredictedType prediction) + bool predict(SpeculatedType prediction) { - return mergePrediction(m_prediction, prediction); + return mergeSpeculation(m_prediction, prediction); } bool shouldSpeculateInteger() { - return isInt32Prediction(prediction()); + return isInt32Speculation(prediction()); } bool shouldSpeculateDouble() { - return isDoublePrediction(prediction()); + return isDoubleSpeculation(prediction()); } bool shouldSpeculateNumber() { - return isNumberPrediction(prediction()); + return isNumberSpeculation(prediction()); } bool shouldSpeculateBoolean() { - return isBooleanPrediction(prediction()); + return isBooleanSpeculation(prediction()); } bool shouldSpeculateFinalObject() { - return isFinalObjectPrediction(prediction()); + return isFinalObjectSpeculation(prediction()); } bool shouldSpeculateFinalObjectOrOther() { - return isFinalObjectOrOtherPrediction(prediction()); + return isFinalObjectOrOtherSpeculation(prediction()); } bool shouldSpeculateArray() { - return isArrayPrediction(prediction()); + return isArraySpeculation(prediction()); } bool shouldSpeculateArguments() { - return isArgumentsPrediction(prediction()); + return isArgumentsSpeculation(prediction()); } bool shouldSpeculateInt8Array() { - return isInt8ArrayPrediction(prediction()); + return isInt8ArraySpeculation(prediction()); } bool shouldSpeculateInt16Array() { - return isInt16ArrayPrediction(prediction()); + return isInt16ArraySpeculation(prediction()); } bool shouldSpeculateInt32Array() { - return isInt32ArrayPrediction(prediction()); + return isInt32ArraySpeculation(prediction()); } bool shouldSpeculateUint8Array() { - return isUint8ArrayPrediction(prediction()); + return isUint8ArraySpeculation(prediction()); } bool shouldSpeculateUint8ClampedArray() { - return isUint8ClampedArrayPrediction(prediction()); + return isUint8ClampedArraySpeculation(prediction()); } bool shouldSpeculateUint16Array() { - return isUint16ArrayPrediction(prediction()); + return isUint16ArraySpeculation(prediction()); } bool shouldSpeculateUint32Array() { - return isUint32ArrayPrediction(prediction()); + return isUint32ArraySpeculation(prediction()); } bool shouldSpeculateFloat32Array() { - return isFloat32ArrayPrediction(prediction()); + return isFloat32ArraySpeculation(prediction()); } bool shouldSpeculateFloat64Array() { - return isFloat64ArrayPrediction(prediction()); + return isFloat64ArraySpeculation(prediction()); } bool shouldSpeculateArrayOrOther() { - return isArrayOrOtherPrediction(prediction()); + return isArrayOrOtherSpeculation(prediction()); } bool shouldSpeculateObject() { - return isObjectPrediction(prediction()); + return isObjectSpeculation(prediction()); } bool shouldSpeculateCell() { - return isCellPrediction(prediction()); + return isCellSpeculation(prediction()); } static bool shouldSpeculateInteger(Node& op1, Node& op2) @@ -921,7 +964,7 @@ private: uintptr_t m_opInfo; unsigned m_opInfo2; // The prediction ascribed to this node after propagation. - PredictedType m_prediction; + SpeculatedType m_prediction; }; } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h index 743f87955..4671f6b6c 100644 --- a/Source/JavaScriptCore/dfg/DFGNodeType.h +++ b/Source/JavaScriptCore/dfg/DFGNodeType.h @@ -118,6 +118,18 @@ namespace JSC { namespace DFG { macro(PutById, NodeMustGenerate | NodeClobbersWorld) \ macro(PutByIdDirect, NodeMustGenerate | NodeClobbersWorld) \ macro(CheckStructure, NodeMustGenerate) \ + /* Transition watchpoints are a contract between the party setting the watchpoint */\ + /* and the runtime system, where the party promises that the child object once had */\ + /* the structure being watched, and the runtime system in turn promises that the */\ + /* watchpoint will be turned into an OSR exit if any object with that structure */\ + /* ever transitions to a different structure. Hence, the child object must have */\ + /* previously had a CheckStructure executed on it or we're dealing with an object */\ + /* constant (WeakJSConstant) and the object was known to have that structure at */\ + /* compile-time. In the latter case this means that no structure checks have to be */\ + /* performed for this object by JITted code. In the former case this means that*/\ + /* the object's structure does not need to be rechecked due to side-effecting */\ + /* (clobbering) operations. */\ + macro(StructureTransitionWatchpoint, NodeMustGenerate) \ macro(PutStructure, NodeMustGenerate) \ macro(PhantomPutStructure, NodeMustGenerate | NodeDoesNotExit) \ macro(GetPropertyStorage, NodeResultStorage) \ @@ -141,6 +153,8 @@ namespace JSC { namespace DFG { macro(PutScopedVar, NodeMustGenerate | NodeClobbersWorld) \ macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \ macro(PutGlobalVar, NodeMustGenerate) \ + macro(GlobalVarWatchpoint, NodeMustGenerate) \ + macro(PutGlobalVarCheck, NodeMustGenerate) \ macro(CheckFunction, NodeMustGenerate) \ \ /* Optimizations for array mutation. */\ diff --git a/Source/JavaScriptCore/dfg/DFGOSRExit.cpp b/Source/JavaScriptCore/dfg/DFGOSRExit.cpp index bcb98a1ed..d0e0de9da 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExit.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExit.cpp @@ -51,6 +51,7 @@ OSRExit::OSRExit(ExitKind kind, JSValueSource jsValueSource, MethodOfGettingAVal , m_codeOrigin(jit->m_codeOriginForOSR) , m_codeOriginForExitProfile(m_codeOrigin) , m_recoveryIndex(recoveryIndex) + , m_watchpointIndex(std::numeric_limits<unsigned>::max()) , m_kind(kind) , m_count(0) , m_arguments(jit->m_arguments.size()) diff --git a/Source/JavaScriptCore/dfg/DFGOSRExit.h b/Source/JavaScriptCore/dfg/DFGOSRExit.h index 841fdddb3..683f260f1 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExit.h +++ b/Source/JavaScriptCore/dfg/DFGOSRExit.h @@ -96,6 +96,7 @@ struct OSRExit { CodeOrigin m_codeOriginForExitProfile; unsigned m_recoveryIndex; + unsigned m_watchpointIndex; ExitKind m_kind; uint32_t m_count; diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp index 888a4a2c5..d46d59650 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp @@ -79,11 +79,11 @@ void compileOSRExit(ExecState* exec) exitCompiler.compileExit(exit, recovery); LinkBuffer patchBuffer(*globalData, &jit, codeBlock); - exit.m_code = patchBuffer.finalizeCode(); - -#if DFG_ENABLE(DEBUG_VERBOSE) - dataLog("OSR exit code at [%p, %p).\n", patchBuffer.debugAddress(), static_cast<char*>(patchBuffer.debugAddress()) + patchBuffer.debugSize()); -#endif + exit.m_code = FINALIZE_CODE( + patchBuffer, + ("DFG OSR exit #%u (bc#%u, @%u, %s) from CodeBlock %p", + exitIndex, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, + exitKindToString(exit.m_kind), codeBlock)); } { diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h index 86345b0eb..ae29a92d5 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h @@ -78,7 +78,7 @@ private: }; extern "C" { -void DFG_OPERATION compileOSRExit(ExecState*); +void DFG_OPERATION compileOSRExit(ExecState*) WTF_INTERNAL; } } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp index d773cb4ac..09912b3e5 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp @@ -533,70 +533,6 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco } } - // 11) Create arguments if necessary and place them into the appropriate aliased - // registers. - - if (haveArguments) { - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); - if (recovery.technique() != ArgumentsThatWereNotCreated) - continue; - int operand = exit.operandForIndex(index); - // Find the right inline call frame. - InlineCallFrame* inlineCallFrame = 0; - for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame; - current; - current = current->caller.inlineCallFrame) { - if (current->stackOffset <= operand) { - inlineCallFrame = current; - break; - } - } - int argumentsRegister = m_jit.argumentsRegisterFor(inlineCallFrame); - - m_jit.load32(AssemblyHelpers::payloadFor(argumentsRegister), GPRInfo::regT0); - AssemblyHelpers::Jump haveArguments = m_jit.branch32( - AssemblyHelpers::NotEqual, - AssemblyHelpers::tagFor(argumentsRegister), - AssemblyHelpers::TrustedImm32(JSValue::EmptyValueTag)); - - if (inlineCallFrame) { - m_jit.setupArgumentsWithExecState( - AssemblyHelpers::TrustedImmPtr(inlineCallFrame)); - m_jit.move( - AssemblyHelpers::TrustedImmPtr( - bitwise_cast<void*>(operationCreateInlinedArguments)), - GPRInfo::nonArgGPR0); - } else { - m_jit.setupArgumentsExecState(); - m_jit.move( - AssemblyHelpers::TrustedImmPtr( - bitwise_cast<void*>(operationCreateArguments)), - GPRInfo::nonArgGPR0); - } - m_jit.call(GPRInfo::nonArgGPR0); - m_jit.store32( - AssemblyHelpers::TrustedImm32(JSValue::CellTag), - AssemblyHelpers::tagFor(argumentsRegister)); - m_jit.store32( - GPRInfo::returnValueGPR, - AssemblyHelpers::payloadFor(argumentsRegister)); - m_jit.store32( - AssemblyHelpers::TrustedImm32(JSValue::CellTag), - AssemblyHelpers::tagFor(unmodifiedArgumentsRegister(argumentsRegister))); - m_jit.store32( - GPRInfo::returnValueGPR, - AssemblyHelpers::payloadFor(unmodifiedArgumentsRegister(argumentsRegister))); - m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms. - - haveArguments.link(&m_jit); - m_jit.store32( - AssemblyHelpers::TrustedImm32(JSValue::CellTag), - AssemblyHelpers::tagFor(operand)); - m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor(operand)); - } - } - // 12) Adjust the old JIT's execute counter. Since we are exiting OSR, we know // that all new calls into this code will go to the new JIT, so the execute // counter only affects call frames that performed OSR exit and call frames @@ -635,14 +571,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco handleExitCounts(exit); - // 13) Load the result of the last bytecode operation into regT0. - - if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) { - m_jit.load32(AssemblyHelpers::payloadFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister); - m_jit.load32(AssemblyHelpers::tagFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister2); - } - - // 14) Fix call frame (s). + // 13) Reify inlined call frames. ASSERT(m_jit.baselineCodeBlock()->getJITType() == JITCode::BaselineJIT); m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(m_jit.baselineCodeBlock()), AssemblyHelpers::addressFor((VirtualRegister)RegisterFile::CodeBlock)); @@ -678,10 +607,83 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->callee.get()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::Callee))); } + // 14) Create arguments if necessary and place them into the appropriate aliased + // registers. + + if (haveArguments) { + for (int index = 0; index < exit.numberOfRecoveries(); ++index) { + const ValueRecovery& recovery = exit.valueRecovery(index); + if (recovery.technique() != ArgumentsThatWereNotCreated) + continue; + int operand = exit.operandForIndex(index); + // Find the right inline call frame. + InlineCallFrame* inlineCallFrame = 0; + for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame; + current; + current = current->caller.inlineCallFrame) { + if (current->stackOffset <= operand) { + inlineCallFrame = current; + break; + } + } + int argumentsRegister = m_jit.argumentsRegisterFor(inlineCallFrame); + + m_jit.load32(AssemblyHelpers::payloadFor(argumentsRegister), GPRInfo::regT0); + AssemblyHelpers::Jump haveArguments = m_jit.branch32( + AssemblyHelpers::NotEqual, + AssemblyHelpers::tagFor(argumentsRegister), + AssemblyHelpers::TrustedImm32(JSValue::EmptyValueTag)); + + if (inlineCallFrame) { + m_jit.setupArgumentsWithExecState( + AssemblyHelpers::TrustedImmPtr(inlineCallFrame)); + m_jit.move( + AssemblyHelpers::TrustedImmPtr( + bitwise_cast<void*>(operationCreateInlinedArguments)), + GPRInfo::nonArgGPR0); + } else { + m_jit.setupArgumentsExecState(); + m_jit.move( + AssemblyHelpers::TrustedImmPtr( + bitwise_cast<void*>(operationCreateArguments)), + GPRInfo::nonArgGPR0); + } + m_jit.call(GPRInfo::nonArgGPR0); + m_jit.store32( + AssemblyHelpers::TrustedImm32(JSValue::CellTag), + AssemblyHelpers::tagFor(argumentsRegister)); + m_jit.store32( + GPRInfo::returnValueGPR, + AssemblyHelpers::payloadFor(argumentsRegister)); + m_jit.store32( + AssemblyHelpers::TrustedImm32(JSValue::CellTag), + AssemblyHelpers::tagFor(unmodifiedArgumentsRegister(argumentsRegister))); + m_jit.store32( + GPRInfo::returnValueGPR, + AssemblyHelpers::payloadFor(unmodifiedArgumentsRegister(argumentsRegister))); + m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms. + + haveArguments.link(&m_jit); + m_jit.store32( + AssemblyHelpers::TrustedImm32(JSValue::CellTag), + AssemblyHelpers::tagFor(operand)); + m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor(operand)); + } + } + + // 15) Load the result of the last bytecode operation into regT0. + + if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) { + m_jit.load32(AssemblyHelpers::payloadFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister); + m_jit.load32(AssemblyHelpers::tagFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister2); + } + + // 16) Adjust the call frame pointer. + if (exit.m_codeOrigin.inlineCallFrame) m_jit.addPtr(AssemblyHelpers::TrustedImm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister); - // 15) Jump into the corresponding baseline JIT code. + // 17) Jump into the corresponding baseline JIT code. CodeBlock* baselineCodeBlock = m_jit.baselineCodeBlockFor(exit.m_codeOrigin); Vector<BytecodeAndMachineOffset>& decodedCodeMap = m_jit.decodedCodeMapFor(baselineCodeBlock); diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp index 22b236115..33ba69a35 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp @@ -511,58 +511,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco } } - // 13) Create arguments if necessary and place them into the appropriate aliased - // registers. - - if (haveArguments) { - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); - if (recovery.technique() != ArgumentsThatWereNotCreated) - continue; - int operand = exit.operandForIndex(index); - // Find the right inline call frame. - InlineCallFrame* inlineCallFrame = 0; - for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame; - current; - current = current->caller.inlineCallFrame) { - if (current->stackOffset <= operand) { - inlineCallFrame = current; - break; - } - } - int argumentsRegister = m_jit.argumentsRegisterFor(inlineCallFrame); - - m_jit.loadPtr(AssemblyHelpers::addressFor(argumentsRegister), GPRInfo::regT0); - AssemblyHelpers::Jump haveArguments = m_jit.branchTestPtr( - AssemblyHelpers::NonZero, GPRInfo::regT0); - - if (inlineCallFrame) { - m_jit.setupArgumentsWithExecState( - AssemblyHelpers::TrustedImmPtr(inlineCallFrame)); - m_jit.move( - AssemblyHelpers::TrustedImmPtr( - bitwise_cast<void*>(operationCreateInlinedArguments)), - GPRInfo::nonArgGPR0); - } else { - m_jit.setupArgumentsExecState(); - m_jit.move( - AssemblyHelpers::TrustedImmPtr( - bitwise_cast<void*>(operationCreateArguments)), - GPRInfo::nonArgGPR0); - } - m_jit.call(GPRInfo::nonArgGPR0); - m_jit.storePtr(GPRInfo::returnValueGPR, AssemblyHelpers::addressFor(argumentsRegister)); - m_jit.storePtr( - GPRInfo::returnValueGPR, - AssemblyHelpers::addressFor(unmodifiedArgumentsRegister(argumentsRegister))); - m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms. - - haveArguments.link(&m_jit); - m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor(operand)); - } - } - - // 14) Adjust the old JIT's execute counter. Since we are exiting OSR, we know + // 13) Adjust the old JIT's execute counter. Since we are exiting OSR, we know // that all new calls into this code will go to the new JIT, so the execute // counter only affects call frames that performed OSR exit and call frames // that were still executing the old JIT at the time of another call frame's @@ -600,12 +549,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco handleExitCounts(exit); - // 15) Load the result of the last bytecode operation into regT0. - - if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) - m_jit.loadPtr(AssemblyHelpers::addressFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister); - - // 16) Fix call frame(s). + // 14) Reify inlined call frames. ASSERT(m_jit.baselineCodeBlock()->getJITType() == JITCode::BaselineJIT); m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(m_jit.baselineCodeBlock()), AssemblyHelpers::addressFor((VirtualRegister)RegisterFile::CodeBlock)); @@ -638,10 +582,63 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->callee.get()), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::Callee))); } + // 15) Create arguments if necessary and place them into the appropriate aliased + // registers. + + if (haveArguments) { + for (int index = 0; index < exit.numberOfRecoveries(); ++index) { + const ValueRecovery& recovery = exit.valueRecovery(index); + if (recovery.technique() != ArgumentsThatWereNotCreated) + continue; + int operand = exit.operandForIndex(index); + // Find the right inline call frame. + InlineCallFrame* inlineCallFrame = 0; + for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame; + current; + current = current->caller.inlineCallFrame) { + if (current->stackOffset <= operand) { + inlineCallFrame = current; + break; + } + } + int argumentsRegister = m_jit.argumentsRegisterFor(inlineCallFrame); + + m_jit.loadPtr(AssemblyHelpers::addressFor(argumentsRegister), GPRInfo::regT0); + AssemblyHelpers::Jump haveArguments = m_jit.branchTestPtr( + AssemblyHelpers::NonZero, GPRInfo::regT0); + + if (inlineCallFrame) { + m_jit.addPtr(AssemblyHelpers::TrustedImm32(inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT0); + m_jit.setupArguments(GPRInfo::regT0); + } else + m_jit.setupArgumentsExecState(); + m_jit.move( + AssemblyHelpers::TrustedImmPtr( + bitwise_cast<void*>(operationCreateArguments)), + GPRInfo::nonArgGPR0); + m_jit.call(GPRInfo::nonArgGPR0); + m_jit.storePtr(GPRInfo::returnValueGPR, AssemblyHelpers::addressFor(argumentsRegister)); + m_jit.storePtr( + GPRInfo::returnValueGPR, + AssemblyHelpers::addressFor(unmodifiedArgumentsRegister(argumentsRegister))); + m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms. + + haveArguments.link(&m_jit); + m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor(operand)); + } + } + + // 16) Load the result of the last bytecode operation into regT0. + + if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) + m_jit.loadPtr(AssemblyHelpers::addressFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister); + + // 17) Adjust the call frame pointer. + if (exit.m_codeOrigin.inlineCallFrame) m_jit.addPtr(AssemblyHelpers::TrustedImm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister); - // 17) Jump into the corresponding baseline JIT code. + // 18) Jump into the corresponding baseline JIT code. CodeBlock* baselineCodeBlock = m_jit.baselineCodeBlockFor(exit.m_codeOrigin); Vector<BytecodeAndMachineOffset>& decodedCodeMap = m_jit.decodedCodeMapFor(baselineCodeBlock); diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index b5ac4601a..06a1cf883 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -51,7 +51,7 @@ HIDE_SYMBOL(function) "\n" \ SYMBOL_STRING(function) ":" "\n" \ "mov (%rsp), %" STRINGIZE(register) "\n" \ - "jmp " SYMBOL_STRING_RELOCATION(function##WithReturnAddress) "\n" \ + "jmp " LOCAL_REFERENCE(function##WithReturnAddress) "\n" \ ); #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rsi) #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rcx) @@ -68,7 +68,7 @@ SYMBOL_STRING(function) ":" "\n" \ "mov (%esp), %eax\n" \ "mov %eax, " STRINGIZE(offset) "(%esp)\n" \ - "jmp " SYMBOL_STRING_RELOCATION(function##WithReturnAddress) "\n" \ + "jmp " LOCAL_REFERENCE(function##WithReturnAddress) "\n" \ ); #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 8) #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 16) @@ -87,7 +87,7 @@ ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ SYMBOL_STRING(function) ":" "\n" \ "mov a2, lr" "\n" \ - "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ ); #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ @@ -100,7 +100,7 @@ ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ SYMBOL_STRING(function) ":" "\n" \ "mov a4, lr" "\n" \ - "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ ); // EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]). @@ -123,7 +123,7 @@ ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ SYMBOL_STRING(function) ":" "\n" \ INSTRUCTION_STORE_RETURN_ADDRESS_EJI "\n" \ - "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ ); #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ @@ -136,25 +136,25 @@ ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ SYMBOL_STRING(function) ":" "\n" \ INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "\n" \ - "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ ); #endif #define P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ -void* DFG_OPERATION function##WithReturnAddress(ExecState*, ReturnAddressPtr) REFERENCED_FROM_ASM; \ +void* DFG_OPERATION function##WithReturnAddress(ExecState*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) #define J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ -EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, JSCell*, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM; \ +EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, JSCell*, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) #define J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ -EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM; \ +EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) #define V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ -void DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, JSCell*, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM; \ +void DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, JSCell*, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) namespace JSC { namespace DFG { @@ -924,6 +924,11 @@ void* DFG_OPERATION operationVirtualConstruct(ExecState* execCallee) return virtualFor(execCallee, CodeForConstruct); } +void DFG_OPERATION operationNotifyGlobalVarWrite(WatchpointSet* watchpointSet) +{ + watchpointSet->notifyWrite(); +} + EncodedJSValue DFG_OPERATION operationResolve(ExecState* exec, Identifier* propertyName) { JSGlobalData* globalData = &exec->globalData(); @@ -1096,6 +1101,8 @@ void DFG_OPERATION operationTearOffInlinedArguments( EncodedJSValue DFG_OPERATION operationGetArgumentsLength(ExecState* exec, int32_t argumentsRegister) { + // Here we can assume that the argumernts were created. Because otherwise the JIT code would + // have not made this call. Identifier ident(&exec->globalData(), "length"); JSValue baseValue = exec->uncheckedR(argumentsRegister).jsValue(); PropertySlot slot(baseValue); @@ -1104,8 +1111,29 @@ EncodedJSValue DFG_OPERATION operationGetArgumentsLength(ExecState* exec, int32_ EncodedJSValue DFG_OPERATION operationGetArgumentByVal(ExecState* exec, int32_t argumentsRegister, int32_t index) { - return JSValue::encode( - exec->uncheckedR(argumentsRegister).jsValue().get(exec, index)); + JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue(); + + // If there are no arguments, and we're accessing out of bounds, then we have to create the + // arguments in case someone has installed a getter on a numeric property. + if (!argumentsValue) + exec->uncheckedR(argumentsRegister) = argumentsValue = Arguments::create(exec->globalData(), exec); + + return JSValue::encode(argumentsValue.get(exec, index)); +} + +EncodedJSValue DFG_OPERATION operationGetInlinedArgumentByVal( + ExecState* exec, int32_t argumentsRegister, InlineCallFrame* inlineCallFrame, int32_t index) +{ + JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue(); + + // If there are no arguments, and we're accessing out of bounds, then we have to create the + // arguments in case someone has installed a getter on a numeric property. + if (!argumentsValue) { + exec->uncheckedR(argumentsRegister) = argumentsValue = + Arguments::create(exec->globalData(), exec, inlineCallFrame); + } + + return JSValue::encode(argumentsValue.get(exec, index)); } JSCell* DFG_OPERATION operationNewFunction(ExecState* exec, JSCell* functionExecutable) @@ -1241,7 +1269,7 @@ HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" "mov -40(%r13), %r13\n" "mov %r13, %rdi\n" - "jmp " SYMBOL_STRING_RELOCATION(getHostCallReturnValueWithExecState) "\n" + "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); #elif CPU(X86) asm ( @@ -1251,7 +1279,7 @@ HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" "mov -40(%edi), %edi\n" "mov %edi, 4(%esp)\n" - "jmp " SYMBOL_STRING_RELOCATION(getHostCallReturnValueWithExecState) "\n" + "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); #elif CPU(ARM_THUMB2) asm ( @@ -1264,7 +1292,7 @@ HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" "ldr r5, [r5, #-40]" "\n" "mov r0, r5" "\n" - "b " SYMBOL_STRING_RELOCATION(getHostCallReturnValueWithExecState) "\n" + "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); #endif diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h index 03f198e9d..38166a83f 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.h +++ b/Source/JavaScriptCore/dfg/DFGOperations.h @@ -77,6 +77,7 @@ typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPP)(ExecState*, void*, vo typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPS)(ExecState*, void*, size_t); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ESS)(ExecState*, size_t, size_t); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZ)(ExecState*, int32_t); +typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZIcfZ)(ExecState*, int32_t, InlineCallFrame*, int32_t); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZZ)(ExecState*, int32_t, int32_t); typedef JSCell* DFG_OPERATION (*C_DFGOperation_E)(ExecState*); typedef JSCell* DFG_OPERATION (*C_DFGOperation_EC)(ExecState*, JSCell*); @@ -99,78 +100,81 @@ typedef void DFG_OPERATION (*V_DFGOperation_EJCI)(ExecState*, EncodedJSValue, JS typedef void DFG_OPERATION (*V_DFGOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue); typedef void DFG_OPERATION (*V_DFGOperation_EJPP)(ExecState*, EncodedJSValue, EncodedJSValue, void*); typedef void DFG_OPERATION (*V_DFGOperation_EPZJ)(ExecState*, void*, int32_t, EncodedJSValue); +typedef void DFG_OPERATION (*V_DFGOperation_W)(WatchpointSet*); typedef void* DFG_OPERATION (*P_DFGOperation_E)(ExecState*); // These routines are provide callbacks out to C++ implementations of operations too complex to JIT. -JSCell* DFG_OPERATION operationNewObject(ExecState*); -JSCell* DFG_OPERATION operationCreateThis(ExecState*, JSCell* constructor); -EncodedJSValue DFG_OPERATION operationConvertThis(ExecState*, EncodedJSValue encodedOp1); -EncodedJSValue DFG_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -EncodedJSValue DFG_OPERATION operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty); -EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty); -EncodedJSValue DFG_OPERATION operationGetById(ExecState*, EncodedJSValue, Identifier*); -EncodedJSValue DFG_OPERATION operationGetByIdBuildList(ExecState*, EncodedJSValue, Identifier*); -EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildList(ExecState*, EncodedJSValue, Identifier*); -EncodedJSValue DFG_OPERATION operationGetByIdOptimize(ExecState*, EncodedJSValue, Identifier*); -EncodedJSValue DFG_OPERATION operationCallCustomGetter(ExecState*, JSCell*, PropertySlot::GetValueFunc, Identifier*); -EncodedJSValue DFG_OPERATION operationCallGetter(ExecState*, JSCell*, JSCell*); -EncodedJSValue DFG_OPERATION operationResolve(ExecState*, Identifier*); -EncodedJSValue DFG_OPERATION operationResolveBase(ExecState*, Identifier*); -EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState*, Identifier*); -EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState*, GlobalResolveInfo*, Identifier*); -EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState*, EncodedJSValue); -EncodedJSValue DFG_OPERATION operationStrCat(ExecState*, void*, size_t); -EncodedJSValue DFG_OPERATION operationNewArray(ExecState*, void*, size_t); -EncodedJSValue DFG_OPERATION operationNewArrayBuffer(ExecState*, size_t, size_t); -EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState*, void*); -void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue); -void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue); -void DFG_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue); -void DFG_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue); -void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue); -void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue); -EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*); -EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*); -EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState*, JSCell*, JSCell*); -void DFG_OPERATION operationPutByIdStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdNonStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdDirectStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdDirectNonStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdNonStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdDirectStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdDirectNonStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdNonStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdDirectStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); +JSCell* DFG_OPERATION operationNewObject(ExecState*) WTF_INTERNAL; +JSCell* DFG_OPERATION operationCreateThis(ExecState*, JSCell* constructor) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationConvertThis(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetById(ExecState*, EncodedJSValue, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetByIdBuildList(ExecState*, EncodedJSValue, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildList(ExecState*, EncodedJSValue, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetByIdOptimize(ExecState*, EncodedJSValue, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationCallCustomGetter(ExecState*, JSCell*, PropertySlot::GetValueFunc, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationCallGetter(ExecState*, JSCell*, JSCell*) WTF_INTERNAL; +void DFG_OPERATION operationNotifyGlobalVarWrite(WatchpointSet* watchpointSet) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationResolve(ExecState*, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationResolveBase(ExecState*, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState*, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState*, GlobalResolveInfo*, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationStrCat(ExecState*, void*, size_t) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationNewArray(ExecState*, void*, size_t) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationNewArrayBuffer(ExecState*, size_t, size_t) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState*, void*) WTF_INTERNAL; +void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL; +void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL; +void DFG_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL; +void DFG_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL; +void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL; +void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState*, JSCell*, JSCell*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdNonStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdDirectStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdDirectNonStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdNonStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdDirectStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdDirectNonStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdNonStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdDirectStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; // These comparisons return a boolean within a size_t such that the value is zero extended to fill the register. -size_t DFG_OPERATION operationRegExpTest(ExecState*, JSCell*, JSCell*); -size_t DFG_OPERATION operationCompareLess(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -size_t DFG_OPERATION operationCompareLessEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -size_t DFG_OPERATION operationCompareGreater(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -size_t DFG_OPERATION operationCompareGreaterEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -size_t DFG_OPERATION operationCompareEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -size_t DFG_OPERATION operationCompareStrictEqCell(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -size_t DFG_OPERATION operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -void* DFG_OPERATION operationVirtualCall(ExecState*); -void* DFG_OPERATION operationLinkCall(ExecState*); -void* DFG_OPERATION operationVirtualConstruct(ExecState*); -void* DFG_OPERATION operationLinkConstruct(ExecState*); -JSCell* DFG_OPERATION operationCreateActivation(ExecState*); -JSCell* DFG_OPERATION operationCreateArguments(ExecState*); -JSCell* DFG_OPERATION operationCreateInlinedArguments(ExecState*, InlineCallFrame*); -void DFG_OPERATION operationTearOffActivation(ExecState*, JSCell*, int32_t unmodifiedArgumentsRegister); -void DFG_OPERATION operationTearOffArguments(ExecState*, JSCell*); -void DFG_OPERATION operationTearOffInlinedArguments(ExecState*, JSCell*, InlineCallFrame*); -EncodedJSValue DFG_OPERATION operationGetArgumentsLength(ExecState*, int32_t); -EncodedJSValue DFG_OPERATION operationGetArgumentByVal(ExecState*, int32_t, int32_t); -JSCell* DFG_OPERATION operationNewFunction(ExecState*, JSCell*); -JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState*, JSCell*); -double DFG_OPERATION operationFModOnInts(int32_t, int32_t); -size_t DFG_OPERATION operationIsObject(EncodedJSValue); -size_t DFG_OPERATION operationIsFunction(EncodedJSValue); +size_t DFG_OPERATION operationRegExpTest(ExecState*, JSCell*, JSCell*) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareLess(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareLessEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareGreater(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareGreaterEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareStrictEqCell(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +void* DFG_OPERATION operationVirtualCall(ExecState*) WTF_INTERNAL; +void* DFG_OPERATION operationLinkCall(ExecState*) WTF_INTERNAL; +void* DFG_OPERATION operationVirtualConstruct(ExecState*) WTF_INTERNAL; +void* DFG_OPERATION operationLinkConstruct(ExecState*) WTF_INTERNAL; +JSCell* DFG_OPERATION operationCreateActivation(ExecState*) WTF_INTERNAL; +JSCell* DFG_OPERATION operationCreateArguments(ExecState*) WTF_INTERNAL; +JSCell* DFG_OPERATION operationCreateInlinedArguments(ExecState*, InlineCallFrame*) WTF_INTERNAL; +void DFG_OPERATION operationTearOffActivation(ExecState*, JSCell*, int32_t unmodifiedArgumentsRegister) WTF_INTERNAL; +void DFG_OPERATION operationTearOffArguments(ExecState*, JSCell*) WTF_INTERNAL; +void DFG_OPERATION operationTearOffInlinedArguments(ExecState*, JSCell*, InlineCallFrame*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetArgumentsLength(ExecState*, int32_t) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetInlinedArgumentByVal(ExecState*, int32_t, InlineCallFrame*, int32_t) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetArgumentByVal(ExecState*, int32_t, int32_t) WTF_INTERNAL; +JSCell* DFG_OPERATION operationNewFunction(ExecState*, JSCell*) WTF_INTERNAL; +JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState*, JSCell*) WTF_INTERNAL; +double DFG_OPERATION operationFModOnInts(int32_t, int32_t) WTF_INTERNAL; +size_t DFG_OPERATION operationIsObject(EncodedJSValue) WTF_INTERNAL; +size_t DFG_OPERATION operationIsFunction(EncodedJSValue) WTF_INTERNAL; // This method is used to lookup an exception hander, keyed by faultLocation, which is // the return location from one of the calls out to one of the helper operations above. @@ -210,17 +214,17 @@ inline DFGHandlerEncoded dfgHandlerEncoded(ExecState* exec, void* handler) return createDFGHandler(exec, handler).u.encoded; } #endif -DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState*, uint32_t); -DFGHandlerEncoded DFG_OPERATION lookupExceptionHandlerInStub(ExecState*, StructureStubInfo*); +DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState*, uint32_t) WTF_INTERNAL; +DFGHandlerEncoded DFG_OPERATION lookupExceptionHandlerInStub(ExecState*, StructureStubInfo*) WTF_INTERNAL; // These operations implement the implicitly called ToInt32, ToNumber, and ToBoolean conversions from ES5. -double DFG_OPERATION dfgConvertJSValueToNumber(ExecState*, EncodedJSValue); +double DFG_OPERATION dfgConvertJSValueToNumber(ExecState*, EncodedJSValue) WTF_INTERNAL; // This conversion returns an int32_t within a size_t such that the value is zero extended to fill the register. -size_t DFG_OPERATION dfgConvertJSValueToInt32(ExecState*, EncodedJSValue); -size_t DFG_OPERATION dfgConvertJSValueToBoolean(ExecState*, EncodedJSValue); +size_t DFG_OPERATION dfgConvertJSValueToInt32(ExecState*, EncodedJSValue) WTF_INTERNAL; +size_t DFG_OPERATION dfgConvertJSValueToBoolean(ExecState*, EncodedJSValue) WTF_INTERNAL; #if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE) -void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState*, void*); +void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState*, void*) WTF_INTERNAL; #endif } // extern "C" diff --git a/Source/JavaScriptCore/dfg/DFGPhase.cpp b/Source/JavaScriptCore/dfg/DFGPhase.cpp index ecf669704..f97c49e31 100644 --- a/Source/JavaScriptCore/dfg/DFGPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,7 +39,9 @@ void Phase::beginPhase() dataLog("Graph before %s:\n", m_name); m_graph.dump(); } +#endif +#if DFG_ENABLE(PER_PHASE_VALIDATION) void Phase::endPhase() { validate(m_graph, DumpGraph); diff --git a/Source/JavaScriptCore/dfg/DFGPhase.h b/Source/JavaScriptCore/dfg/DFGPhase.h index 6d13bcd25..53055a215 100644 --- a/Source/JavaScriptCore/dfg/DFGPhase.h +++ b/Source/JavaScriptCore/dfg/DFGPhase.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -65,11 +65,14 @@ private: // Call these hooks when starting and finishing. #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) void beginPhase(); - void endPhase(); -#else // DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) +#else void beginPhase() { } +#endif +#if DFG_ENABLE(PER_PHASE_VALIDATION) + void endPhase(); +#else void endPhase() { } -#endif // DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) +#endif }; template<typename PhaseType> diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index 75f0b7a74..bcb79a96a 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -82,20 +82,20 @@ public: } private: - bool setPrediction(PredictedType prediction) + bool setPrediction(SpeculatedType prediction) { ASSERT(m_graph[m_compileIndex].hasResult()); // setPrediction() is used when we know that there is no way that we can change // our minds about what the prediction is going to be. There is no semantic - // difference between setPrediction() and mergePrediction() other than the + // difference between setPrediction() and mergeSpeculation() other than the // increased checking to validate this property. - ASSERT(m_graph[m_compileIndex].prediction() == PredictNone || m_graph[m_compileIndex].prediction() == prediction); + ASSERT(m_graph[m_compileIndex].prediction() == SpecNone || m_graph[m_compileIndex].prediction() == prediction); return m_graph[m_compileIndex].predict(prediction); } - bool mergePrediction(PredictedType prediction) + bool mergePrediction(SpeculatedType prediction) { ASSERT(m_graph[m_compileIndex].hasResult()); @@ -134,13 +134,13 @@ private: switch (op) { case JSConstant: case WeakJSConstant: { - changed |= setPrediction(predictionFromValue(m_graph.valueOfJSConstant(m_compileIndex))); + changed |= setPrediction(speculationFromValue(m_graph.valueOfJSConstant(m_compileIndex))); break; } case GetLocal: { VariableAccessData* variableAccessData = node.variableAccessData(); - PredictedType prediction = variableAccessData->prediction(); + SpeculatedType prediction = variableAccessData->prediction(); if (prediction) changed |= mergePrediction(prediction); @@ -168,7 +168,7 @@ private: case BitRShift: case BitLShift: case BitURShift: { - changed |= setPrediction(PredictInt32); + changed |= setPrediction(SpecInt32); flags |= NodeUsedAsInt; flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero); changed |= m_graph[node.child1()].mergeFlags(flags); @@ -177,7 +177,7 @@ private: } case ValueToInt32: { - changed |= setPrediction(PredictInt32); + changed |= setPrediction(SpecInt32); flags |= NodeUsedAsInt; flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero); changed |= m_graph[node.child1()].mergeFlags(flags); @@ -205,22 +205,22 @@ private: } case StringCharCodeAt: { - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); break; } case ArithMod: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (isInt32Prediction(mergePredictions(left, right)) + if (isInt32Speculation(mergeSpeculations(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags())) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } flags |= NodeUsedAsValue; @@ -231,29 +231,29 @@ private: case UInt32ToNumber: { if (nodeCanSpeculateInteger(node.arithNodeFlags())) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictNumber); + changed |= mergePrediction(SpecNumber); changed |= m_graph[node.child1()].mergeFlags(flags); break; } case ValueAdd: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (isNumberPrediction(left) && isNumberPrediction(right)) { + if (isNumberSpeculation(left) && isNumberSpeculation(right)) { if (m_graph.addShouldSpeculateInteger(node)) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); - } else if (!(left & PredictNumber) || !(right & PredictNumber)) { + changed |= mergePrediction(SpecDouble); + } else if (!(left & SpecNumber) || !(right & SpecNumber)) { // left or right is definitely something other than a number. - changed |= mergePrediction(PredictString); + changed |= mergePrediction(SpecString); } else - changed |= mergePrediction(PredictString | PredictInt32 | PredictDouble); + changed |= mergePrediction(SpecString | SpecInt32 | SpecDouble); } if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index())) @@ -265,14 +265,14 @@ private: } case ArithAdd: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (m_graph.addShouldSpeculateInteger(node)) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index())) @@ -284,14 +284,14 @@ private: } case ArithSub: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (m_graph.addShouldSpeculateInteger(node)) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } if (isNotZero(node.child1().index()) || isNotZero(node.child2().index())) @@ -305,9 +305,9 @@ private: case ArithNegate: if (m_graph[node.child1()].prediction()) { if (m_graph.negateShouldSpeculateInteger(node)) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } changed |= m_graph[node.child1()].mergeFlags(flags); @@ -315,15 +315,15 @@ private: case ArithMin: case ArithMax: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (isInt32Prediction(mergePredictions(left, right)) + if (isInt32Speculation(mergeSpeculations(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags())) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } flags |= NodeUsedAsNumber; @@ -333,14 +333,14 @@ private: } case ArithMul: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (m_graph.mulShouldSpeculateInteger(node)) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } // As soon as a multiply happens, we can easily end up in the part @@ -355,15 +355,15 @@ private: } case ArithDiv: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (isInt32Prediction(mergePredictions(left, right)) + if (isInt32Speculation(mergeSpeculations(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags())) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } // As soon as a multiply happens, we can easily end up in the part @@ -378,17 +378,17 @@ private: } case ArithSqrt: { - changed |= setPrediction(PredictDouble); + changed |= setPrediction(SpecDouble); changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue); break; } case ArithAbs: { - PredictedType child = m_graph[node.child1()].prediction(); + SpeculatedType child = m_graph[node.child1()].prediction(); if (nodeCanSpeculateInteger(node.arithNodeFlags())) changed |= mergePrediction(child); else - changed |= setPrediction(PredictDouble); + changed |= setPrediction(SpecDouble); flags &= ~NodeNeedsNegZero; changed |= m_graph[node.child1()].mergeFlags(flags); @@ -409,7 +409,7 @@ private: case IsString: case IsObject: case IsFunction: { - changed |= setPrediction(PredictBoolean); + changed |= setPrediction(SpecBoolean); changed |= mergeDefaultFlags(node); break; } @@ -428,7 +428,7 @@ private: case GetByVal: { if (m_graph[node.child1()].shouldSpeculateFloat32Array() || m_graph[node.child1()].shouldSpeculateFloat64Array()) - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); else changed |= mergePrediction(node.getHeapPrediction()); @@ -444,13 +444,13 @@ private: } case GetMyArgumentsLengthSafe: { - changed |= setPrediction(PredictInt32); + changed |= setPrediction(SpecInt32); break; } case GetPropertyStorage: case GetIndexedPropertyStorage: { - changed |= setPrediction(PredictOther); + changed |= setPrediction(SpecOther); changed |= mergeDefaultFlags(node); break; } @@ -474,11 +474,11 @@ private: } case ConvertThis: { - PredictedType prediction = m_graph[node.child1()].prediction(); + SpeculatedType prediction = m_graph[node.child1()].prediction(); if (prediction) { - if (prediction & ~PredictObjectMask) { - prediction &= PredictObjectMask; - prediction = mergePredictions(prediction, PredictObjectOther); + if (prediction & ~SpecObjectMask) { + prediction &= SpecObjectMask; + prediction = mergeSpeculations(prediction, SpecObjectOther); } changed |= mergePrediction(prediction); } @@ -491,7 +491,8 @@ private: break; } - case PutGlobalVar: { + case PutGlobalVar: + case PutGlobalVarCheck: { changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); break; } @@ -501,30 +502,30 @@ private: case ResolveBase: case ResolveBaseStrictPut: case ResolveGlobal: { - PredictedType prediction = node.getHeapPrediction(); + SpeculatedType prediction = node.getHeapPrediction(); changed |= mergePrediction(prediction); break; } case GetScopeChain: { - changed |= setPrediction(PredictCellOther); + changed |= setPrediction(SpecCellOther); break; } case GetCallee: { - changed |= setPrediction(PredictFunction); + changed |= setPrediction(SpecFunction); break; } case CreateThis: case NewObject: { - changed |= setPrediction(PredictFinalObject); + changed |= setPrediction(SpecFinalObject); changed |= mergeDefaultFlags(node); break; } case NewArray: { - changed |= setPrediction(PredictArray); + changed |= setPrediction(SpecArray); for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx) { @@ -535,24 +536,24 @@ private: } case NewArrayBuffer: { - changed |= setPrediction(PredictArray); + changed |= setPrediction(SpecArray); break; } case NewRegexp: { - changed |= setPrediction(PredictObjectOther); + changed |= setPrediction(SpecObjectOther); break; } case StringCharAt: { - changed |= setPrediction(PredictString); + changed |= setPrediction(SpecString); changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); break; } case StrCat: { - changed |= setPrediction(PredictString); + changed |= setPrediction(SpecString); for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx) @@ -561,20 +562,20 @@ private: } case ToPrimitive: { - PredictedType child = m_graph[node.child1()].prediction(); + SpeculatedType child = m_graph[node.child1()].prediction(); if (child) { - if (isObjectPrediction(child)) { + if (isObjectSpeculation(child)) { // I'd love to fold this case into the case below, but I can't, because - // removing PredictObjectMask from something that only has an object - // prediction and nothing else means we have an ill-formed PredictedType + // removing SpecObjectMask from something that only has an object + // prediction and nothing else means we have an ill-formed SpeculatedType // (strong predict-none). This should be killed once we remove all traces // of static (aka weak) predictions. - changed |= mergePrediction(PredictString); - } else if (child & PredictObjectMask) { + changed |= mergePrediction(SpecString); + } else if (child & SpecObjectMask) { // Objects get turned into strings. So if the input has hints of objectness, // the output will have hinsts of stringiness. changed |= mergePrediction( - mergePredictions(child & ~PredictObjectMask, PredictString)); + mergeSpeculations(child & ~SpecObjectMask, SpecString)); } else changed |= mergePrediction(child); } @@ -583,21 +584,21 @@ private: } case CreateActivation: { - changed |= setPrediction(PredictObjectOther); + changed |= setPrediction(SpecObjectOther); break; } case CreateArguments: { // At this stage we don't try to predict whether the arguments are ours or // someone else's. We could, but we don't, yet. - changed |= setPrediction(PredictArguments); + changed |= setPrediction(SpecArguments); break; } case NewFunction: case NewFunctionNoCheck: case NewFunctionExpression: { - changed |= setPrediction(PredictFunction); + changed |= setPrediction(SpecFunction); break; } @@ -663,12 +664,14 @@ private: case ForceOSRExit: case SetArgument: case CheckStructure: + case StructureTransitionWatchpoint: case CheckFunction: case PutStructure: case TearOffActivation: case TearOffArguments: case CheckNumber: case CheckArgumentsNotCreated: + case GlobalVarWatchpoint: changed |= mergeDefaultFlags(node); break; @@ -689,7 +692,7 @@ private: } #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog("%s\n", predictionToString(m_graph[m_compileIndex].prediction())); + dataLog("%s\n", speculationToString(m_graph[m_compileIndex].prediction())); #endif m_changed |= changed; @@ -784,12 +787,12 @@ private: case ValueAdd: case ArithAdd: case ArithSub: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); VariableAccessData::Ballot ballot; - if (isNumberPrediction(left) && isNumberPrediction(right) + if (isNumberSpeculation(left) && isNumberSpeculation(right) && !m_graph.addShouldSpeculateInteger(node)) ballot = VariableAccessData::VoteDouble; else @@ -801,12 +804,12 @@ private: } case ArithMul: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); VariableAccessData::Ballot ballot; - if (isNumberPrediction(left) && isNumberPrediction(right) + if (isNumberSpeculation(left) && isNumberSpeculation(right) && !m_graph.mulShouldSpeculateInteger(node)) ballot = VariableAccessData::VoteDouble; else @@ -821,12 +824,12 @@ private: case ArithMax: case ArithMod: case ArithDiv: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); VariableAccessData::Ballot ballot; - if (isNumberPrediction(left) && isNumberPrediction(right) + if (isNumberSpeculation(left) && isNumberSpeculation(right) && !(Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child1()]) && node.canSpeculateInteger())) ballot = VariableAccessData::VoteDouble; @@ -854,10 +857,10 @@ private: break; case SetLocal: { - PredictedType prediction = m_graph[node.child1()].prediction(); - if (isDoublePrediction(prediction)) + SpeculatedType prediction = m_graph[node.child1()].prediction(); + if (isDoubleSpeculation(prediction)) node.variableAccessData()->vote(VariableAccessData::VoteDouble); - else if (!isNumberPrediction(prediction) || isInt32Prediction(prediction)) + else if (!isNumberSpeculation(prediction) || isInt32Speculation(prediction)) node.variableAccessData()->vote(VariableAccessData::VoteValue); break; } diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp index 794538184..9c3391be5 100644 --- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp +++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp @@ -155,7 +155,10 @@ static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stu linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, successLabel, slowCaseLabel); - stubRoutine = patchBuffer.finalizeCode(); + stubRoutine = FINALIZE_CODE( + patchBuffer, + ("DFG prototype chain access stub for CodeBlock %p, return point %p", + exec->codeBlock(), successLabel.executableAddress())); } static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo) @@ -206,7 +209,11 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier linkRestoreScratch(patchBuffer, needToRestoreScratch, stubInfo, success, fail, failureCases); - stubInfo.stubRoutine = patchBuffer.finalizeCode(); + stubInfo.stubRoutine = FINALIZE_CODE( + patchBuffer, + ("DFG GetById array length stub for CodeBlock %p, return point %p", + exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset( + stubInfo.patch.dfg.deltaCallToDone).executableAddress())); RepatchBuffer repatchBuffer(codeBlock); repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine.code())); @@ -261,7 +268,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine.code())); repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdProtoBuildList); - stubInfo.initGetByIdChain(*globalData, codeBlock->ownerExecutable(), structure, prototypeChain); + stubInfo.initGetByIdChain(*globalData, codeBlock->ownerExecutable(), structure, prototypeChain, count, true); return true; } @@ -405,7 +412,11 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi patchBuffer.link(handlerCall, lookupExceptionHandlerInStub); } - MacroAssemblerCodeRef stubRoutine = patchBuffer.finalizeCode(); + MacroAssemblerCodeRef stubRoutine = FINALIZE_CODE( + patchBuffer, + ("DFG GetById polymorphic list access for CodeBlock %p, return point %p", + exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset( + stubInfo.patch.dfg.deltaCallToDone).executableAddress())); polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, isDirect); @@ -611,7 +622,11 @@ static void emitPutReplaceStub( patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToDone)); patchBuffer.link(failure, failureLabel); - stubRoutine = patchBuffer.finalizeCode(); + stubRoutine = FINALIZE_CODE( + patchBuffer, + ("DFG PutById replace stub for CodeBlock %p, return point %p", + exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset( + stubInfo.patch.dfg.deltaCallToDone).executableAddress())); } static void emitPutTransitionStub( @@ -649,6 +664,8 @@ static void emitPutTransitionStub( needToRestoreScratch = true; } + ASSERT(oldStructure->transitionWatchpointSetHasBeenInvalidated()); + failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(oldStructure))); testPrototype(stubJit, scratchGPR, oldStructure->storedPrototype(), failureCases); @@ -705,7 +722,11 @@ static void emitPutTransitionStub( else patchBuffer.link(failureCases, failureLabel); - stubRoutine = patchBuffer.finalizeCode(); + stubRoutine = FINALIZE_CODE( + patchBuffer, + ("DFG PutById transition stub for CodeBlock %p, return point %p", + exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset( + stubInfo.patch.dfg.deltaCallToDone).executableAddress())); } static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier& ident, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind) diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index 9b82121b3..852f74387 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -292,7 +292,7 @@ void SpeculativeJIT::writeBarrier(GPRReg ownerGPR, GPRReg valueGPR, Edge valueUs JITCompiler::Jump rhsNotCell; bool hadCellCheck = false; - if (!isKnownCell(valueUse.index()) && !isCellPrediction(m_jit.getPrediction(valueUse.index()))) { + if (!isKnownCell(valueUse.index()) && !isCellSpeculation(m_jit.getSpeculation(valueUse.index()))) { hadCellCheck = true; rhsNotCell = m_jit.branchIfNotCell(valueGPR); } @@ -354,7 +354,7 @@ void SpeculativeJIT::writeBarrier(JSCell* owner, GPRReg valueGPR, Edge valueUse, #if ENABLE(GGC) JITCompiler::Jump rhsNotCell; bool hadCellCheck = false; - if (!isKnownCell(valueUse.index()) && !isCellPrediction(m_jit.getPrediction(valueUse.index()))) { + if (!isKnownCell(valueUse.index()) && !isCellSpeculation(m_jit.getSpeculation(valueUse.index()))) { hadCellCheck = true; rhsNotCell = m_jit.branchIfNotCell(valueGPR); } @@ -826,7 +826,7 @@ void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNod jump(notTaken); } -void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex, const ClassInfo* classInfo, PredictionChecker predictionCheck) +void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex, const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { Node& branchNode = at(branchNodeIndex); BlockIndex taken = branchNode.takenBlockIndex(); @@ -847,9 +847,9 @@ void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchN GPRReg op1GPR = op1.gpr(); GPRReg op2GPR = op2.gpr(); - if (!predictionCheck(m_state.forNode(node.child1()).m_type)) + if (!speculatedTypeChecker(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo))); - if (!predictionCheck(m_state.forNode(node.child2()).m_type)) + if (!speculatedTypeChecker(m_state.forNode(node.child2()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo))); branchPtr(condition, op1GPR, op2GPR, taken); @@ -909,32 +909,32 @@ bool SpeculativeJIT::compilePeepHoleBranch(Node& node, MacroAssembler::Relationa at(node.child1()), at(node.child2()))) { compilePeepHoleObjectEquality( node, branchNodeIndex, &JSFinalObject::s_info, - isFinalObjectPrediction); + isFinalObjectSpeculation); } else if (Node::shouldSpeculateArray( at(node.child1()), at(node.child2()))) { compilePeepHoleObjectEquality( node, branchNodeIndex, &JSArray::s_info, - isArrayPrediction); + isArraySpeculation); } else if (at(node.child1()).shouldSpeculateFinalObject() && at(node.child2()).shouldSpeculateFinalObjectOrOther()) { compilePeepHoleObjectToObjectOrOtherEquality( node.child1(), node.child2(), branchNodeIndex, - &JSFinalObject::s_info, isFinalObjectPrediction); + &JSFinalObject::s_info, isFinalObjectSpeculation); } else if (at(node.child1()).shouldSpeculateFinalObjectOrOther() && at(node.child2()).shouldSpeculateFinalObject()) { compilePeepHoleObjectToObjectOrOtherEquality( node.child2(), node.child1(), branchNodeIndex, - &JSFinalObject::s_info, isFinalObjectPrediction); + &JSFinalObject::s_info, isFinalObjectSpeculation); } else if (at(node.child1()).shouldSpeculateArray() && at(node.child2()).shouldSpeculateArrayOrOther()) { compilePeepHoleObjectToObjectOrOtherEquality( node.child1(), node.child2(), branchNodeIndex, - &JSArray::s_info, isArrayPrediction); + &JSArray::s_info, isArraySpeculation); } else if (at(node.child1()).shouldSpeculateArrayOrOther() && at(node.child2()).shouldSpeculateArray()) { compilePeepHoleObjectToObjectOrOtherEquality( node.child2(), node.child1(), branchNodeIndex, - &JSArray::s_info, isArrayPrediction); + &JSArray::s_info, isArraySpeculation); } else { nonSpeculativePeepholeBranch(node, branchNodeIndex, condition, operation); return true; @@ -991,7 +991,7 @@ void SpeculativeJIT::compile(BasicBlock& block) if (nodeIndex == NoNode || m_jit.codeBlock()->argumentIsCaptured(i)) m_arguments[i] = ValueSource(ValueInRegisterFile); else - m_arguments[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction()); + m_arguments[i] = ValueSource::forSpeculation(at(nodeIndex).variableAccessData()->prediction()); } m_state.reset(); @@ -1011,7 +1011,7 @@ void SpeculativeJIT::compile(BasicBlock& block) else if (at(nodeIndex).variableAccessData()->shouldUseDoubleFormat()) m_variables[i] = ValueSource(DoubleInRegisterFile); else - m_variables[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->argumentAwarePrediction()); + m_variables[i] = ValueSource::forSpeculation(at(nodeIndex).variableAccessData()->argumentAwarePrediction()); } m_lastSetOperand = std::numeric_limits<int>::max(); @@ -1040,8 +1040,29 @@ void SpeculativeJIT::compile(BasicBlock& block) case InlineStart: { InlineCallFrame* inlineCallFrame = node.codeOrigin.inlineCallFrame; int argumentCountIncludingThis = inlineCallFrame->arguments.size(); + unsigned argumentPositionStart = node.argumentPositionStart(); + bool argumentsAreCaptured = + baselineCodeBlockForInlineCallFrame(inlineCallFrame)->argumentsAreCaptured(); for (int i = 0; i < argumentCountIncludingThis; ++i) { - ValueRecovery recovery = computeValueRecoveryFor(m_variables[inlineCallFrame->stackOffset + CallFrame::argumentOffsetIncludingThis(i)]); + ValueRecovery recovery; + if (argumentsAreCaptured) + recovery = ValueRecovery::alreadyInRegisterFile(); + else { + ArgumentPosition& argumentPosition = + m_jit.graph().m_argumentPositions[argumentPositionStart + i]; + ValueSource valueSource; + if (argumentPosition.shouldUseDoubleFormat()) + valueSource = ValueSource(DoubleInRegisterFile); + else if (isInt32Speculation(argumentPosition.prediction())) + valueSource = ValueSource(Int32InRegisterFile); + else if (isArraySpeculation(argumentPosition.prediction())) + valueSource = ValueSource(CellInRegisterFile); + else if (isBooleanSpeculation(argumentPosition.prediction())) + valueSource = ValueSource(BooleanInRegisterFile); + else + valueSource = ValueSource(ValueInRegisterFile); + recovery = computeValueRecoveryFor(valueSource); + } // The recovery should refer either to something that has already been // stored into the register file at the right place, or to a constant, // since the Arguments code isn't smart enough to handle anything else. @@ -1051,12 +1072,15 @@ void SpeculativeJIT::compile(BasicBlock& block) dataLog("\nRecovery for argument %d: ", i); recovery.dump(WTF::dataFile()); #endif - ASSERT(!i || (recovery.isAlreadyInRegisterFile() || recovery.isConstant())); inlineCallFrame->arguments[i] = recovery; } break; } + case WeakJSConstant: + m_jit.addWeakReference(node.weakConstant()); + break; + default: break; } @@ -1154,129 +1178,129 @@ void SpeculativeJIT::checkArgumentTypes() VariableAccessData* variableAccessData = node.variableAccessData(); VirtualRegister virtualRegister = variableAccessData->local(); - PredictedType predictedType = variableAccessData->prediction(); + SpeculatedType predictedType = variableAccessData->prediction(); JSValueSource valueSource = JSValueSource(JITCompiler::addressFor(virtualRegister)); #if USE(JSVALUE64) - if (isInt32Prediction(predictedType)) + if (isInt32Speculation(predictedType)) speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister)); - else if (isArrayPrediction(predictedType)) { + else if (isArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); - } else if (isBooleanPrediction(predictedType)) { + } else if (isBooleanSpeculation(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), TrustedImm32(static_cast<int32_t>(~1)))); - } else if (isInt8ArrayPrediction(predictedType)) { + } else if (isInt8ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int8ArrayDescriptor().m_classInfo))); - } else if (isInt16ArrayPrediction(predictedType)) { + } else if (isInt16ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int16ArrayDescriptor().m_classInfo))); - } else if (isInt32ArrayPrediction(predictedType)) { + } else if (isInt32ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int32ArrayDescriptor().m_classInfo))); - } else if (isUint8ArrayPrediction(predictedType)) { + } else if (isUint8ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ArrayDescriptor().m_classInfo))); - } else if (isUint8ClampedArrayPrediction(predictedType)) { + } else if (isUint8ClampedArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ClampedArrayDescriptor().m_classInfo))); - } else if (isUint16ArrayPrediction(predictedType)) { + } else if (isUint16ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint16ArrayDescriptor().m_classInfo))); - } else if (isUint32ArrayPrediction(predictedType)) { + } else if (isUint32ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint32ArrayDescriptor().m_classInfo))); - } else if (isFloat32ArrayPrediction(predictedType)) { + } else if (isFloat32ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float32ArrayDescriptor().m_classInfo))); - } else if (isFloat64ArrayPrediction(predictedType)) { + } else if (isFloat64ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float64ArrayDescriptor().m_classInfo))); } #else - if (isInt32Prediction(predictedType)) + if (isInt32Speculation(predictedType)) speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag))); - else if (isArrayPrediction(predictedType)) { + else if (isArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); - } else if (isBooleanPrediction(predictedType)) + } else if (isBooleanSpeculation(predictedType)) speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag))); - else if (isInt8ArrayPrediction(predictedType)) { + else if (isInt8ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int8ArrayDescriptor().m_classInfo))); - } else if (isInt16ArrayPrediction(predictedType)) { + } else if (isInt16ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int16ArrayDescriptor().m_classInfo))); - } else if (isInt32ArrayPrediction(predictedType)) { + } else if (isInt32ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int32ArrayDescriptor().m_classInfo))); - } else if (isUint8ArrayPrediction(predictedType)) { + } else if (isUint8ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ArrayDescriptor().m_classInfo))); - } else if (isUint8ClampedArrayPrediction(predictedType)) { + } else if (isUint8ClampedArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ClampedArrayDescriptor().m_classInfo))); - } else if (isUint16ArrayPrediction(predictedType)) { + } else if (isUint16ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint16ArrayDescriptor().m_classInfo))); - } else if (isUint32ArrayPrediction(predictedType)) { + } else if (isUint32ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint32ArrayDescriptor().m_classInfo))); - } else if (isFloat32ArrayPrediction(predictedType)) { + } else if (isFloat32ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float32ArrayDescriptor().m_classInfo))); - } else if (isFloat64ArrayPrediction(predictedType)) { + } else if (isFloat64ArraySpeculation(predictedType)) { GPRTemporary temp(this); m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); @@ -1506,8 +1530,8 @@ void SpeculativeJIT::compileGetCharCodeAt(Node& node) GPRReg indexReg = index.gpr(); GPRReg storageReg = storage.gpr(); - if (!isStringPrediction(m_state.forNode(node.child1()).m_type)) { - ASSERT(!(at(node.child1()).prediction() & PredictString)); + if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) { + ASSERT(!(at(node.child1()).prediction() & SpecString)); terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); noResult(m_compileIndex); return; @@ -1545,8 +1569,8 @@ void SpeculativeJIT::compileGetByValOnString(Node& node) GPRReg propertyReg = property.gpr(); GPRReg storageReg = storage.gpr(); - if (!isStringPrediction(m_state.forNode(node.child1()).m_type)) { - ASSERT(!(at(node.child1()).prediction() & PredictString)); + if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) { + ASSERT(!(at(node.child1()).prediction() & SpecString)); terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); noResult(m_compileIndex); return; @@ -1680,7 +1704,7 @@ void SpeculativeJIT::compileValueToInt32(Node& node) JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, gpr, GPRInfo::tagTypeNumberRegister); - if (!isNumberPrediction(m_state.forNode(node.child1()).m_type)) + if (!isNumberSpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(gpr), node.child1().index(), m_jit.branchTestPtr(MacroAssembler::Zero, gpr, GPRInfo::tagTypeNumberRegister)); // First, if we get here we have a double encoded as a JSValue @@ -1717,7 +1741,7 @@ void SpeculativeJIT::compileValueToInt32(Node& node) JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag)); - if (!isNumberPrediction(m_state.forNode(node.child1()).m_type)) + if (!isNumberSpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node.child1().index(), m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag))); unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr()); @@ -1829,7 +1853,7 @@ void SpeculativeJIT::compileInt32ToDouble(Node& node) } #endif - if (isInt32Prediction(m_state.forNode(node.child1()).m_type)) { + if (isInt32Speculation(m_state.forNode(node.child1()).m_type)) { SpeculateIntegerOperand op1(this, node.child1()); FPRTemporary result(this); m_jit.convertInt32ToDouble(op1.gpr(), result.fpr()); @@ -1850,9 +1874,11 @@ void SpeculativeJIT::compileInt32ToDouble(Node& node) JITCompiler::Jump isInteger = m_jit.branchPtr( MacroAssembler::AboveOrEqual, op1GPR, GPRInfo::tagTypeNumberRegister); - speculationCheck( - BadType, JSValueRegs(op1GPR), node.child1(), - m_jit.branchTestPtr(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister)); + if (!isNumberSpeculation(m_state.forNode(node.child1()).m_type)) { + speculationCheck( + BadType, JSValueRegs(op1GPR), node.child1(), + m_jit.branchTestPtr(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister)); + } m_jit.move(op1GPR, tempGPR); unboxDouble(tempGPR, resultFPR); @@ -1872,9 +1898,11 @@ void SpeculativeJIT::compileInt32ToDouble(Node& node) JITCompiler::Jump isInteger = m_jit.branch32( MacroAssembler::Equal, op1TagGPR, TrustedImm32(JSValue::Int32Tag)); - speculationCheck( - BadType, JSValueRegs(op1TagGPR, op1PayloadGPR), node.child1(), - m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag))); + if (!isNumberSpeculation(m_state.forNode(node.child1()).m_type)) { + speculationCheck( + BadType, JSValueRegs(op1TagGPR, op1PayloadGPR), node.child1(), + m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag))); + } unboxDouble(op1TagGPR, op1PayloadGPR, resultFPR, tempFPR); JITCompiler::Jump done = m_jit.jump(); @@ -2245,8 +2273,8 @@ void SpeculativeJIT::compileInstanceOfForObject(Node&, GPRReg valueReg, GPRReg p void SpeculativeJIT::compileInstanceOf(Node& node) { - if ((!!(at(node.child1()).prediction() & ~PredictCell) - && !!(m_state.forNode(node.child1()).m_type & ~PredictCell)) + if ((!!(at(node.child1()).prediction() & ~SpecCell) + && !!(m_state.forNode(node.child1()).m_type & ~SpecCell)) || at(node.child1()).adjustedRefCount() == 1) { // It might not be a cell. Speculate less aggressively. // Or: it might only be used once (i.e. by us), so we get zero benefit @@ -2780,12 +2808,12 @@ bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition con if (node.op() == CompareEq) { if (Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2()))) { - compileObjectEquality(node, &JSFinalObject::s_info, isFinalObjectPrediction); + compileObjectEquality(node, &JSFinalObject::s_info, isFinalObjectSpeculation); return false; } if (Node::shouldSpeculateArray(at(node.child1()), at(node.child2()))) { - compileObjectEquality(node, &JSArray::s_info, isArrayPrediction); + compileObjectEquality(node, &JSArray::s_info, isArraySpeculation); return false; } @@ -2793,7 +2821,7 @@ bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition con && at(node.child2()).shouldSpeculateFinalObjectOrOther()) { compileObjectToObjectOrOtherEquality( node.child1(), node.child2(), &JSFinalObject::s_info, - isFinalObjectPrediction); + isFinalObjectSpeculation); return false; } @@ -2801,7 +2829,7 @@ bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition con && at(node.child2()).shouldSpeculateFinalObject()) { compileObjectToObjectOrOtherEquality( node.child2(), node.child1(), &JSFinalObject::s_info, - isFinalObjectPrediction); + isFinalObjectSpeculation); return false; } @@ -2809,7 +2837,7 @@ bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition con && at(node.child2()).shouldSpeculateArrayOrOther()) { compileObjectToObjectOrOtherEquality( node.child1(), node.child2(), &JSArray::s_info, - isArrayPrediction); + isArraySpeculation); return false; } @@ -2817,7 +2845,7 @@ bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition con && at(node.child2()).shouldSpeculateArray()) { compileObjectToObjectOrOtherEquality( node.child2(), node.child1(), &JSArray::s_info, - isArrayPrediction); + isArraySpeculation); return false; } } @@ -2957,14 +2985,14 @@ bool SpeculativeJIT::compileStrictEq(Node& node) unsigned branchIndexInBlock = detectPeepHoleBranch(); if (branchIndexInBlock != UINT_MAX) { NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock); - compilePeepHoleObjectEquality(node, branchNodeIndex, &JSFinalObject::s_info, isFinalObjectPrediction); + compilePeepHoleObjectEquality(node, branchNodeIndex, &JSFinalObject::s_info, isFinalObjectSpeculation); use(node.child1()); use(node.child2()); m_indexInBlock = branchIndexInBlock; m_compileIndex = branchNodeIndex; return true; } - compileObjectEquality(node, &JSFinalObject::s_info, isFinalObjectPrediction); + compileObjectEquality(node, &JSFinalObject::s_info, isFinalObjectSpeculation); return false; } @@ -2972,14 +3000,14 @@ bool SpeculativeJIT::compileStrictEq(Node& node) unsigned branchIndexInBlock = detectPeepHoleBranch(); if (branchIndexInBlock != UINT_MAX) { NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock); - compilePeepHoleObjectEquality(node, branchNodeIndex, &JSArray::s_info, isArrayPrediction); + compilePeepHoleObjectEquality(node, branchNodeIndex, &JSArray::s_info, isArraySpeculation); use(node.child1()); use(node.child2()); m_indexInBlock = branchIndexInBlock; m_compileIndex = branchNodeIndex; return true; } - compileObjectEquality(node, &JSArray::s_info, isArrayPrediction); + compileObjectEquality(node, &JSArray::s_info, isArraySpeculation); return false; } @@ -2998,8 +3026,8 @@ void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node) SpeculateCellOperand base(this, node.child1()); GPRReg baseReg = base.gpr(); - PredictedType basePrediction = at(node.child2()).prediction(); - if (!(basePrediction & PredictInt32) && basePrediction) { + SpeculatedType basePrediction = at(node.child2()).prediction(); + if (!(basePrediction & SpecInt32) && basePrediction) { ASSERT_NOT_REACHED(); terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); noResult(m_compileIndex); @@ -3010,8 +3038,8 @@ void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node) GPRReg storageReg = storage.gpr(); if (at(node.child1()).shouldSpeculateArguments()) { ASSERT_NOT_REACHED(); - } else if (at(node.child1()).prediction() == PredictString) { - if (!isStringPrediction(m_state.forNode(node.child1()).m_type)) + } else if (at(node.child1()).prediction() == SpecString) { + if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSString::s_info))); m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), storageReg); @@ -3022,51 +3050,51 @@ void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node) m_jit.loadPtr(MacroAssembler::Address(storageReg, StringImpl::dataOffset()), storageReg); } else if (at(node.child1()).shouldSpeculateInt8Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->int8ArrayDescriptor(); - if (!isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateInt16Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->int16ArrayDescriptor(); - if (!isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateInt32Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->int32ArrayDescriptor(); - if (!isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateUint8Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ArrayDescriptor(); - if (!isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ClampedArrayDescriptor(); - if (!isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateUint16Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint16ArrayDescriptor(); - if (!isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateUint32Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint32ArrayDescriptor(); - if (!isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateFloat32Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->float32ArrayDescriptor(); - if (!isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateFloat64Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->float64ArrayDescriptor(); - if (!isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else { - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); } @@ -3094,7 +3122,7 @@ void SpeculativeJIT::compileGetByValOnArguments(Node& node) if (!m_compileOkay) return; - if (!isArgumentsPrediction(m_state.forNode(node.child1()).m_type)) { + if (!isArgumentsSpeculation(m_state.forNode(node.child1()).m_type)) { speculationCheck( BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr( @@ -3162,7 +3190,7 @@ void SpeculativeJIT::compileGetArgumentsLength(Node& node) if (!m_compileOkay) return; - if (!isArgumentsPrediction(m_state.forNode(node.child1()).m_type)) { + if (!isArgumentsSpeculation(m_state.forNode(node.child1()).m_type)) { speculationCheck( BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr( diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 56a1a1861..933784685 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -81,13 +81,13 @@ public: ASSERT(kind() == HaveNode); } - static ValueSource forPrediction(PredictedType prediction) + static ValueSource forSpeculation(SpeculatedType prediction) { - if (isInt32Prediction(prediction)) + if (isInt32Speculation(prediction)) return ValueSource(Int32InRegisterFile); - if (isArrayPrediction(prediction)) + if (isArraySpeculation(prediction)) return ValueSource(CellInRegisterFile); - if (isBooleanPrediction(prediction)) + if (isBooleanSpeculation(prediction)) return ValueSource(BooleanInRegisterFile); return ValueSource(ValueInRegisterFile); } @@ -1294,6 +1294,11 @@ public: m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), arg2); return appendCallWithExceptionCheckSetResult(operation, result); } + JITCompiler::Call callOperation(J_DFGOperation_EZIcfZ operation, GPRReg result, int32_t arg1, InlineCallFrame* inlineCallFrame, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), TrustedImmPtr(inlineCallFrame), arg2); + return appendCallWithExceptionCheckSetResult(operation, result); + } JITCompiler::Call callOperation(C_DFGOperation_E operation, GPRReg result) { m_jit.setupArgumentsExecState(); @@ -1409,6 +1414,11 @@ public: m_jit.setupArgumentsWithExecState(arg1, TrustedImm32(arg2)); return appendCallWithExceptionCheck(operation); } + JITCompiler::Call callOperation(V_DFGOperation_W operation, WatchpointSet* watchpointSet) + { + m_jit.setupArguments(TrustedImmPtr(watchpointSet)); + return appendCall(operation); + } template<typename FunctionType, typename ArgumentType1> JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1) { @@ -1547,6 +1557,11 @@ public: m_jit.setupArgumentsWithExecState(TrustedImm32(arg1)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } + JITCompiler::Call callOperation(J_DFGOperation_EZIcfZ operation, GPRReg resultTag, GPRReg resultPayload, int32_t arg1, InlineCallFrame* inlineCallFrame, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), TrustedImmPtr(inlineCallFrame), arg2); + return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); + } JITCompiler::Call callOperation(J_DFGOperation_EZZ operation, GPRReg resultTag, GPRReg resultPayload, int32_t arg1, GPRReg arg2) { m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), arg2); @@ -1662,6 +1677,11 @@ public: m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag); return appendCallWithExceptionCheck(operation); } + JITCompiler::Call callOperation(V_DFGOperation_W operation, WatchpointSet* watchpointSet) + { + m_jit.setupArguments(TrustedImmPtr(watchpointSet)); + return appendCall(operation); + } template<typename FunctionType, typename ArgumentType1> JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1) { @@ -1783,6 +1803,11 @@ public: m_jit.move(GPRInfo::returnValueGPR, result); return call; } + JITCompiler::Call appendCall(const FunctionPtr& function) + { + prepareForExternalCall(); + return m_jit.appendCall(function); + } JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, GPRReg result1, GPRReg result2) { JITCompiler::Call call = appendCallWithExceptionCheck(function); @@ -2034,12 +2059,12 @@ public: bool compilePeepHoleBranch(Node&, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_DFGOperation_EJJ); void compilePeepHoleIntegerBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition); void compilePeepHoleDoubleBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition); - void compilePeepHoleObjectEquality(Node&, NodeIndex branchNodeIndex, const ClassInfo*, PredictionChecker); + void compilePeepHoleObjectEquality(Node&, NodeIndex branchNodeIndex, const ClassInfo*, SpeculatedTypeChecker); void compilePeepHoleObjectToObjectOrOtherEquality( - Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex, const ClassInfo*, PredictionChecker); - void compileObjectEquality(Node&, const ClassInfo*, PredictionChecker); + Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex, const ClassInfo*, SpeculatedTypeChecker); + void compileObjectEquality(Node&, const ClassInfo*, SpeculatedTypeChecker); void compileObjectToObjectOrOtherEquality( - Edge leftChild, Edge rightChild, const ClassInfo*, PredictionChecker); + Edge leftChild, Edge rightChild, const ClassInfo*, SpeculatedTypeChecker); void compileValueAdd(Node&); void compileObjectOrOtherLogicalNot(Edge value, const ClassInfo*, bool needSpeculationCheck); void compileLogicalNot(Node&); @@ -2183,6 +2208,32 @@ public: ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes); speculationCheck(kind, jsValueSource, nodeUse.index(), jumpToFail, recovery); } + // Use this like you would use speculationCheck(), except that you don't pass it a jump + // (because you don't have to execute a branch; that's kind of the whole point), and you + // must register the returned Watchpoint with something relevant. In general, this should + // be used with extreme care. Use speculationCheck() unless you've got an amazing reason + // not to. + Watchpoint* speculationWatchpoint(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex) + { + if (!m_compileOkay) + return 0; + ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes); + OSRExit& exit = m_jit.codeBlock()->osrExit( + m_jit.codeBlock()->appendOSRExit( + OSRExit(kind, jsValueSource, + m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), + JITCompiler::Jump(), this))); + exit.m_watchpointIndex = m_jit.codeBlock()->appendWatchpoint( + Watchpoint(m_jit.watchpointLabel())); + return &m_jit.codeBlock()->watchpoint(exit.m_watchpointIndex); + } + // The default for speculation watchpoints is that they're uncounted, because the + // act of firing a watchpoint invalidates it. So, future recompilations will not + // attempt to set this watchpoint again. + Watchpoint* speculationWatchpoint() + { + return speculationWatchpoint(UncountableWatchpoint, JSValueSource(), NoNode); + } void forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail, const ValueRecovery& valueRecovery) { ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes); @@ -2197,7 +2248,7 @@ public: setLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock)); hadInt32ToDouble = true; } - if (setLocal->op() == Flush) + if (setLocal->op() == Flush || setLocal->op() == Phantom) setLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock)); if (hadInt32ToDouble) diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index 00a83000a..0c33e0748 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -30,6 +30,7 @@ #if ENABLE(DFG_JIT) #include "DFGSlowPathGenerator.h" +#include "JSVariableObject.h" namespace JSC { namespace DFG { @@ -1051,7 +1052,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& return allocate(); } - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1073,7 +1074,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& ASSERT_UNUSED(spillFormat, (spillFormat & DataFormatJS) || spillFormat == DataFormatInteger); // If we know this was spilled as an integer we can fill without checking. - if (!isInt32Prediction(type)) + if (!isInt32Speculation(type)) speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag))); GPRReg gpr = allocate(); @@ -1091,7 +1092,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& GPRReg payloadGPR = info.payloadGPR(); m_gprs.lock(tagGPR); m_gprs.lock(payloadGPR); - if (!isInt32Prediction(type)) + if (!isInt32Speculation(type)) speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::Int32Tag))); m_gprs.unlock(tagGPR); m_gprs.release(tagGPR); @@ -1147,7 +1148,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) return fprAllocate(); } - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1185,7 +1186,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) if (spillFormat != DataFormatJSInteger && spillFormat != DataFormatInteger) { JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)); - if (!isNumberPrediction(type)) + if (!isNumberSpeculation(type)) speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::AboveOrEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::LowestTag))); m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr); hasUnboxedDouble = m_jit.jump(); @@ -1219,7 +1220,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) if (info.registerFormat() != DataFormatJSInteger) { FPRTemporary scratch(this); JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag)); - if (!isNumberPrediction(type)) + if (!isNumberSpeculation(type)) speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag))); unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr()); hasUnboxedDouble = m_jit.jump(); @@ -1280,7 +1281,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) return allocate(); } - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1299,7 +1300,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) } ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatCell); - if (!isCellPrediction(type)) + if (!isCellSpeculation(type)) speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag))); GPRReg gpr = allocate(); m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr); @@ -1320,7 +1321,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) GPRReg payloadGPR = info.payloadGPR(); m_gprs.lock(tagGPR); m_gprs.lock(payloadGPR); - if (!isCellPrediction(type)) + if (!isCellSpeculation(type)) speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::CellTag))); m_gprs.unlock(tagGPR); m_gprs.release(tagGPR); @@ -1349,7 +1350,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("SpecBool@%d ", nodeIndex); #endif - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = m_jit.graph()[nodeIndex]; VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1374,7 +1375,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatBoolean); - if (!isBooleanPrediction(type)) + if (!isBooleanSpeculation(type)) speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag))); GPRReg gpr = allocate(); @@ -1396,7 +1397,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) GPRReg payloadGPR = info.payloadGPR(); m_gprs.lock(tagGPR); m_gprs.lock(payloadGPR); - if (!isBooleanPrediction(type)) + if (!isBooleanSpeculation(type)) speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::BooleanTag))); m_gprs.unlock(tagGPR); @@ -1439,16 +1440,16 @@ JITCompiler::Jump SpeculativeJIT::convertToDouble(JSValueOperand& op, FPRReg res return notNumber; } -void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInfo, PredictionChecker predictionCheck) +void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { SpeculateCellOperand op1(this, node.child1()); SpeculateCellOperand op2(this, node.child2()); GPRReg op1GPR = op1.gpr(); GPRReg op2GPR = op2.gpr(); - if (!predictionCheck(m_state.forNode(node.child1()).m_type)) + if (!speculatedTypeChecker(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo))); - if (!predictionCheck(m_state.forNode(node.child2()).m_type)) + if (!speculatedTypeChecker(m_state.forNode(node.child2()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo))); GPRTemporary resultPayload(this, op2); @@ -1466,7 +1467,7 @@ void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInf void SpeculativeJIT::compileObjectToObjectOrOtherEquality( Edge leftChild, Edge rightChild, - const ClassInfo* classInfo, PredictionChecker predictionCheck) + const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { SpeculateCellOperand op1(this, leftChild); JSValueOperand op2(this, rightChild); @@ -1477,7 +1478,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( GPRReg op2PayloadGPR = op2.payloadGPR(); GPRReg resultGPR = result.gpr(); - if (!predictionCheck(m_state.forNode(leftChild).m_type)) { + if (!speculatedTypeChecker(m_state.forNode(leftChild).m_type)) { speculationCheck( BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(), m_jit.branchPtr( @@ -1493,9 +1494,9 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the // proof, when filtered on cell, demonstrates that we have an object of the desired type - // (predictionCheck() will test for FinalObject or Array, currently), then we can skip the + // (speculationCheck() will test for FinalObject or Array, currently), then we can skip the // speculation. - if (!predictionCheck(m_state.forNode(rightChild).m_type & PredictCell)) { + if (!speculatedTypeChecker(m_state.forNode(rightChild).m_type & SpecCell)) { speculationCheck( BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(), m_jit.branchPtr( @@ -1514,7 +1515,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must not be a cell. Check if that is enough to // prove that it is either null or undefined. - if (!isOtherPrediction(m_state.forNode(rightChild).m_type & ~PredictCell)) { + if (!isOtherSpeculation(m_state.forNode(rightChild).m_type & ~SpecCell)) { m_jit.move(op2TagGPR, resultGPR); m_jit.or32(TrustedImm32(1), resultGPR); @@ -1537,7 +1538,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex, - const ClassInfo* classInfo, PredictionChecker predictionCheck) + const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { Node& branchNode = at(branchNodeIndex); BlockIndex taken = branchNode.takenBlockIndex(); @@ -1552,7 +1553,7 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( GPRReg op2PayloadGPR = op2.payloadGPR(); GPRReg resultGPR = result.gpr(); - if (!predictionCheck(m_state.forNode(leftChild).m_type)) { + if (!speculatedTypeChecker(m_state.forNode(leftChild).m_type)) { speculationCheck( BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(), m_jit.branchPtr( @@ -1568,9 +1569,9 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the // proof, when filtered on cell, demonstrates that we have an object of the desired type - // (predictionCheck() will test for FinalObject or Array, currently), then we can skip the + // (speculationCheck() will test for FinalObject or Array, currently), then we can skip the // speculation. - if (!predictionCheck(m_state.forNode(rightChild).m_type & PredictCell)) { + if (!speculatedTypeChecker(m_state.forNode(rightChild).m_type & SpecCell)) { speculationCheck( BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(), m_jit.branchPtr( @@ -1586,7 +1587,7 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must not be a cell. Check if that is enough to // prove that it is either null or undefined. - if (isOtherPrediction(m_state.forNode(rightChild).m_type & ~PredictCell)) + if (isOtherSpeculation(m_state.forNode(rightChild).m_type & ~SpecCell)) rightNotCell.link(&m_jit); else { jump(notTaken, ForceJump); @@ -1692,11 +1693,11 @@ void SpeculativeJIT::compileLogicalNot(Node& node) return; } if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) { - compileObjectOrOtherLogicalNot(node.child1(), &JSFinalObject::s_info, !isFinalObjectOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + compileObjectOrOtherLogicalNot(node.child1(), &JSFinalObject::s_info, !isFinalObjectOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); return; } if (at(node.child1()).shouldSpeculateArrayOrOther()) { - compileObjectOrOtherLogicalNot(node.child1(), &JSArray::s_info, !isArrayOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + compileObjectOrOtherLogicalNot(node.child1(), &JSArray::s_info, !isArrayOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); return; } if (at(node.child1()).shouldSpeculateInteger()) { @@ -1787,9 +1788,9 @@ void SpeculativeJIT::emitBranch(Node& node) noResult(m_compileIndex); } else if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) { - emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSFinalObject::s_info, !isFinalObjectOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSFinalObject::s_info, !isFinalObjectOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); } else if (at(node.child1()).shouldSpeculateArrayOrOther()) { - emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSArray::s_info, !isArrayOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSArray::s_info, !isArrayOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); } else if (at(node.child1()).shouldSpeculateNumber()) { if (at(node.child1()).shouldSpeculateInteger()) { bool invert = false; @@ -1848,7 +1849,13 @@ void SpeculativeJIT::compile(Node& node) switch (op) { case JSConstant: + initConstantInfo(m_compileIndex); + break; + case PhantomArguments: + // This should never be must-generate. + ASSERT_NOT_REACHED(); + // But as a release-mode fall-back make it the empty value. initConstantInfo(m_compileIndex); break; @@ -1858,11 +1865,11 @@ void SpeculativeJIT::compile(Node& node) break; case GetLocal: { - PredictedType prediction = node.variableAccessData()->prediction(); + SpeculatedType prediction = node.variableAccessData()->prediction(); AbstractValue& value = block()->valuesAtHead.operand(node.local()); // If we have no prediction for this local, then don't attempt to compile. - if (prediction == PredictNone) { + if (prediction == SpecNone) { terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); break; } @@ -1884,7 +1891,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isInt32Prediction(prediction)) { + if (isInt32Speculation(prediction)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -1896,7 +1903,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isArrayPrediction(prediction)) { + if (isArraySpeculation(prediction)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -1908,7 +1915,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isBooleanPrediction(prediction)) { + if (isBooleanSpeculation(prediction)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -1933,7 +1940,7 @@ void SpeculativeJIT::compile(Node& node) m_gprs.retain(tag.gpr(), virtualRegister, SpillOrderJS); DataFormat format; - if (isCellPrediction(value.m_type) + if (isCellSpeculation(value.m_type) && !node.variableAccessData()->isCaptured()) format = DataFormatJSCell; else @@ -1999,7 +2006,7 @@ void SpeculativeJIT::compile(Node& node) valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile); break; } - PredictedType predictedType = node.variableAccessData()->argumentAwarePrediction(); + SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction(); if (m_generationInfo[at(node.child1()).virtualRegister()].registerFormat() == DataFormatDouble) { DoubleOperand value(this, node.child1()); m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local())); @@ -2007,24 +2014,24 @@ void SpeculativeJIT::compile(Node& node) valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile); break; } - if (isInt32Prediction(predictedType)) { + if (isInt32Speculation(predictedType)) { SpeculateIntegerOperand value(this, node.child1()); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); valueSourceReferenceForOperand(node.local()) = ValueSource(Int32InRegisterFile); break; } - if (isArrayPrediction(predictedType)) { + if (isArraySpeculation(predictedType)) { SpeculateCellOperand cell(this, node.child1()); GPRReg cellGPR = cell.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile); break; } - if (isBooleanPrediction(predictedType)) { + if (isBooleanSpeculation(predictedType)) { SpeculateBooleanOperand value(this, node.child1()); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); @@ -2122,7 +2129,7 @@ void SpeculativeJIT::compile(Node& node) } case CheckNumber: { - if (!isNumberPrediction(m_state.forNode(node.child1()).m_type)) { + if (!isNumberSpeculation(m_state.forNode(node.child1()).m_type)) { JSValueOperand op1(this, node.child1()); JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, op1.tagGPR(), TrustedImm32(JSValue::Int32Tag)); speculationCheck( @@ -2326,7 +2333,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArrayPrediction(at(node.child1()).prediction())) { + if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArraySpeculation(at(node.child1()).prediction())) { SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right. JSValueOperand property(this, node.child2()); GPRReg baseGPR = base.gpr(); @@ -2349,7 +2356,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (at(node.child1()).prediction() == PredictString) { + if (at(node.child1()).prediction() == SpecString) { compileGetByValOnString(node); if (!m_compileOkay) return; @@ -2357,63 +2364,63 @@ void SpeculativeJIT::compile(Node& node) } if (at(node.child1()).shouldSpeculateInt8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat32Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat64Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; @@ -2434,7 +2441,7 @@ void SpeculativeJIT::compile(Node& node) { SpeculateCellOperand base(this, node.child1()); GPRReg baseReg = base.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); } @@ -2460,7 +2467,7 @@ void SpeculativeJIT::compile(Node& node) } if (!at(node.child2()).shouldSpeculateInteger() - || !isActionableMutableArrayPrediction(at(node.child1()).prediction()) + || !isActionableMutableArraySpeculation(at(node.child1()).prediction()) || at(node.child1()).shouldSpeculateArguments()) { SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right. JSValueOperand property(this, node.child2()); @@ -2481,63 +2488,63 @@ void SpeculativeJIT::compile(Node& node) SpeculateCellOperand base(this, node.child1()); SpeculateStrictInt32Operand property(this, node.child2()); if (at(node.child1()).shouldSpeculateInt8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat32Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat64Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; @@ -2562,7 +2569,7 @@ void SpeculativeJIT::compile(Node& node) // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). // If we have predicted the base to be type array, we can skip the check. - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); base.use(); @@ -2608,7 +2615,7 @@ void SpeculativeJIT::compile(Node& node) break; } - ASSERT(isActionableMutableArrayPrediction(at(node.child1()).prediction())); + ASSERT(isActionableMutableArraySpeculation(at(node.child1()).prediction())); ASSERT(at(node.child2()).shouldSpeculateInteger()); SpeculateCellOperand base(this, node.child1()); @@ -2763,7 +2770,7 @@ void SpeculativeJIT::compile(Node& node) writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); @@ -2801,7 +2808,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg storageGPR = storage.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); @@ -2947,7 +2954,7 @@ void SpeculativeJIT::compile(Node& node) op1.use(); - if (!(m_state.forNode(node.child1()).m_type & ~(PredictNumber | PredictBoolean))) { + if (!(m_state.forNode(node.child1()).m_type & ~(SpecNumber | SpecBoolean))) { m_jit.move(op1TagGPR, resultTagGPR); m_jit.move(op1PayloadGPR, resultPayloadGPR); } else { @@ -3053,7 +3060,7 @@ void SpeculativeJIT::compile(Node& node) } case ConvertThis: { - if (isObjectPrediction(m_state.forNode(node.child1()).m_type)) { + if (isObjectSpeculation(m_state.forNode(node.child1()).m_type)) { SpeculateCellOperand thisValue(this, node.child1()); GPRTemporary result(this, thisValue); m_jit.move(thisValue.gpr(), result.gpr()); @@ -3061,7 +3068,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isOtherPrediction(at(node.child1()).prediction())) { + if (isOtherSpeculation(at(node.child1()).prediction())) { JSValueOperand thisValue(this, node.child1()); GPRTemporary scratch(this); @@ -3080,11 +3087,11 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isObjectPrediction(at(node.child1()).prediction())) { + if (isObjectSpeculation(at(node.child1()).prediction())) { SpeculateCellOperand thisValue(this, node.child1()); GPRReg thisValueGPR = thisValue.gpr(); - if (!isObjectPrediction(m_state.forNode(node.child1()).m_type)) + if (!isObjectSpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(thisValueGPR), node.child1(), m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(thisValueGPR, JSCell::classInfoOffset()), JITCompiler::TrustedImmPtr(&JSString::s_info))); GPRTemporary result(this, thisValue); @@ -3214,7 +3221,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isCellPrediction(at(node.child1()).prediction())) { + if (isCellSpeculation(at(node.child1()).prediction())) { SpeculateCellOperand base(this, node.child1()); GPRTemporary resultTag(this, base); GPRTemporary resultPayload(this); @@ -3268,7 +3275,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isCellPrediction(at(node.child1()).prediction())) { + if (isCellSpeculation(at(node.child1()).prediction())) { SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); @@ -3317,7 +3324,7 @@ void SpeculativeJIT::compile(Node& node) SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); GPRTemporary result(this); @@ -3344,7 +3351,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg baseGPR = base.gpr(); GPRReg resultGPR = result.gpr(); - if (!isStringPrediction(m_state.forNode(node.child1()).m_type)) + if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSString::s_info))); m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR); @@ -3354,39 +3361,39 @@ void SpeculativeJIT::compile(Node& node) } case GetInt8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetInt16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetInt32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint8ClampedArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetFloat32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetFloat64ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } @@ -3400,7 +3407,7 @@ void SpeculativeJIT::compile(Node& node) case CheckStructure: { AbstractValue& value = m_state.forNode(node.child1()); if (value.m_structure.isSubsetOf(node.structureSet()) - && isCellPrediction(value.m_type)) { + && isCellSpeculation(value.m_type)) { noResult(m_compileIndex); break; } @@ -3430,7 +3437,23 @@ void SpeculativeJIT::compile(Node& node) break; } + case StructureTransitionWatchpoint: { + m_jit.addWeakReference(node.structure()); + node.structure()->addTransitionWatchpoint(speculationWatchpoint()); + +#if !ASSERT_DISABLED + SpeculateCellOperand op1(this, node.child1()); + JITCompiler::Jump isOK = m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(op1.gpr(), JSCell::structureOffset()), TrustedImmPtr(node.structure())); + m_jit.breakpoint(); + isOK.link(&m_jit); +#endif + + noResult(m_compileIndex); + break; + } + case PhantomPutStructure: { + ASSERT(node.structureTransitionData().previousStructure->transitionWatchpointSetHasBeenInvalidated()); m_jit.addWeakReferenceTransition( node.codeOrigin.codeOriginOwner(), node.structureTransitionData().previousStructure, @@ -3440,6 +3463,8 @@ void SpeculativeJIT::compile(Node& node) } case PutStructure: { + ASSERT(node.structureTransitionData().previousStructure->transitionWatchpointSetHasBeenInvalidated()); + SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); @@ -3558,34 +3583,89 @@ void SpeculativeJIT::compile(Node& node) } case GetGlobalVar: { - GPRTemporary result(this); - GPRTemporary scratch(this); + GPRTemporary resultPayload(this); + GPRTemporary resultTag(this); - JSVariableObject* globalObject = m_jit.globalObjectFor(node.codeOrigin); - m_jit.loadPtr(const_cast<WriteBarrier<Unknown>**>(globalObject->addressOfRegisters()), result.gpr()); - m_jit.load32(JITCompiler::tagForGlobalVar(result.gpr(), node.varNumber()), scratch.gpr()); - m_jit.load32(JITCompiler::payloadForGlobalVar(result.gpr(), node.varNumber()), result.gpr()); + m_jit.move(TrustedImmPtr(node.registerPointer()), resultPayload.gpr()); + m_jit.load32(JITCompiler::Address(resultPayload.gpr(), OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTag.gpr()); + m_jit.load32(JITCompiler::Address(resultPayload.gpr(), OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayload.gpr()); - jsValueResult(scratch.gpr(), result.gpr(), m_compileIndex); + jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex); break; } case PutGlobalVar: { JSValueOperand value(this, node.child1()); - GPRTemporary globalObject(this); - GPRTemporary scratch(this); - - GPRReg globalObjectReg = globalObject.gpr(); - GPRReg scratchReg = scratch.gpr(); + if (Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + GPRReg scratchReg = scratch.gpr(); + + writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.tagGPR(), node.child1(), WriteBarrierForVariableAccess, scratchReg); + } - m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)), globalObjectReg); + // FIXME: if we happen to have a spare register - and _ONLY_ if we happen to have + // a spare register - a good optimization would be to put the register pointer into + // a register and then do a zero offset store followed by a four-offset store (or + // vice-versa depending on endianness). + m_jit.store32(value.tagGPR(), node.registerPointer()->tagPointer()); + m_jit.store32(value.payloadGPR(), node.registerPointer()->payloadPointer()); - writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.tagGPR(), node.child1(), WriteBarrierForVariableAccess, scratchReg); + noResult(m_compileIndex); + break; + } - m_jit.loadPtr(MacroAssembler::Address(globalObjectReg, JSVariableObject::offsetOfRegisters()), scratchReg); - m_jit.store32(value.tagGPR(), JITCompiler::tagForGlobalVar(scratchReg, node.varNumber())); - m_jit.store32(value.payloadGPR(), JITCompiler::payloadForGlobalVar(scratchReg, node.varNumber())); + case PutGlobalVarCheck: { + JSValueOperand value(this, node.child1()); + + WatchpointSet* watchpointSet = + m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get( + identifier(node.identifierNumberForCheck())->impl()).watchpointSet(); + addSlowPathGenerator( + slowPathCall( + m_jit.branchTest8( + JITCompiler::NonZero, + JITCompiler::AbsoluteAddress(watchpointSet->addressOfIsWatched())), + this, operationNotifyGlobalVarWrite, NoResult, watchpointSet)); + + if (Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + GPRReg scratchReg = scratch.gpr(); + + writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.tagGPR(), node.child1(), WriteBarrierForVariableAccess, scratchReg); + } + // FIXME: if we happen to have a spare register - and _ONLY_ if we happen to have + // a spare register - a good optimization would be to put the register pointer into + // a register and then do a zero offset store followed by a four-offset store (or + // vice-versa depending on endianness). + m_jit.store32(value.tagGPR(), node.registerPointer()->tagPointer()); + m_jit.store32(value.payloadGPR(), node.registerPointer()->payloadPointer()); + + noResult(m_compileIndex); + break; + } + + case GlobalVarWatchpoint: { + m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get( + identifier(node.identifierNumberForCheck())->impl()).addWatchpoint( + speculationWatchpoint()); + +#if DFG_ENABLE(JIT_ASSERT) + GPRTemporary scratch(this); + GPRReg scratchGPR = scratch.gpr(); + m_jit.load32(node.registerPointer()->tagPointer(), scratchGPR); + JITCompiler::Jump notOK = m_jit.branch32( + JITCompiler::NotEqual, scratchGPR, + TrustedImm32(node.registerPointer()->get().tag())); + m_jit.load32(node.registerPointer()->payloadPointer(), scratchGPR); + JITCompiler::Jump ok = m_jit.branch32( + JITCompiler::Equal, scratchGPR, + TrustedImm32(node.registerPointer()->get().payload())); + notOK.link(&m_jit); + m_jit.breakpoint(); + ok.link(&m_jit); +#endif + noResult(m_compileIndex); break; } @@ -3858,16 +3938,15 @@ void SpeculativeJIT::compile(Node& node) } case CheckArgumentsNotCreated: { - if (!isEmptyPrediction( - m_state.variables().operand( - m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { - speculationCheck( - Uncountable, JSValueRegs(), NoNode, - m_jit.branch32( - JITCompiler::NotEqual, - JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)), - TrustedImm32(JSValue::EmptyValueTag))); - } + ASSERT(!isEmptySpeculation( + m_state.variables().operand( + m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)); + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branch32( + JITCompiler::NotEqual, + JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)), + TrustedImm32(JSValue::EmptyValueTag))); noResult(m_compileIndex); break; } @@ -3876,7 +3955,7 @@ void SpeculativeJIT::compile(Node& node) GPRTemporary result(this); GPRReg resultGPR = result.gpr(); - if (!isEmptyPrediction( + if (!isEmptySpeculation( m_state.variables().operand( m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { speculationCheck( @@ -3937,7 +4016,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg resultPayloadGPR = resultPayload.gpr(); GPRReg resultTagGPR = resultTag.gpr(); - if (!isEmptyPrediction( + if (!isEmptySpeculation( m_state.variables().operand( m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { speculationCheck( @@ -4033,11 +4112,20 @@ void SpeculativeJIT::compile(Node& node) baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR); - addSlowPathGenerator( - slowPathCall( - slowPath, this, operationGetArgumentByVal, - JSValueRegs(resultTagGPR, resultPayloadGPR), - m_jit.argumentsRegisterFor(node.codeOrigin), indexGPR)); + if (node.codeOrigin.inlineCallFrame) { + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationGetInlinedArgumentByVal, + JSValueRegs(resultTagGPR, resultPayloadGPR), + m_jit.argumentsRegisterFor(node.codeOrigin), + node.codeOrigin.inlineCallFrame, indexGPR)); + } else { + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationGetArgumentByVal, + JSValueRegs(resultTagGPR, resultPayloadGPR), + m_jit.argumentsRegisterFor(node.codeOrigin), indexGPR)); + } jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex); break; diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index ca57743a6..0b7606b2c 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -1028,7 +1028,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("SpecInt@%d ", nodeIndex); #endif - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1086,7 +1086,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& // Check the value is an integer. GPRReg gpr = info.gpr(); m_gprs.lock(gpr); - if (!isInt32Prediction(type)) + if (!isInt32Speculation(type)) speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchPtr(MacroAssembler::Below, gpr, GPRInfo::tagTypeNumberRegister)); info.fillJSValue(gpr, DataFormatJSInteger); // If !strict we're done, return. @@ -1175,7 +1175,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("SpecDouble@%d ", nodeIndex); #endif - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1260,7 +1260,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister); - if (!isNumberPrediction(type)) + if (!isNumberSpeculation(type)) speculationCheck(BadType, JSValueRegs(jsValueGpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::Zero, jsValueGpr, GPRInfo::tagTypeNumberRegister)); // First, if we get here we have a double encoded as a JSValue @@ -1328,7 +1328,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("SpecCell@%d ", nodeIndex); #endif - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1358,7 +1358,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); info.fillJSValue(gpr, DataFormatJS); - if (!isCellPrediction(type)) + if (!isCellSpeculation(type)) speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister)); info.fillJSValue(gpr, DataFormatJSCell); return gpr; @@ -1374,7 +1374,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) case DataFormatJS: { GPRReg gpr = info.gpr(); m_gprs.lock(gpr); - if (!isCellPrediction(type)) + if (!isCellSpeculation(type)) speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister)); info.fillJSValue(gpr, DataFormatJSCell); return gpr; @@ -1403,7 +1403,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("SpecBool@%d ", nodeIndex); #endif - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1433,7 +1433,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); info.fillJSValue(gpr, DataFormatJS); - if (!isBooleanPrediction(type)) { + if (!isBooleanSpeculation(type)) { m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg)); m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); @@ -1452,7 +1452,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) case DataFormatJS: { GPRReg gpr = info.gpr(); m_gprs.lock(gpr); - if (!isBooleanPrediction(type)) { + if (!isBooleanSpeculation(type)) { m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg)); m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); @@ -1499,7 +1499,7 @@ JITCompiler::Jump SpeculativeJIT::convertToDouble(GPRReg value, FPRReg result, G return notNumber; } -void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInfo, PredictionChecker predictionCheck) +void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { SpeculateCellOperand op1(this, node.child1()); SpeculateCellOperand op2(this, node.child2()); @@ -1509,9 +1509,9 @@ void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInf GPRReg op2GPR = op2.gpr(); GPRReg resultGPR = result.gpr(); - if (!predictionCheck(m_state.forNode(node.child1()).m_type)) + if (!speculatedTypeChecker(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(op1GPR), node.child1().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo))); - if (!predictionCheck(m_state.forNode(node.child2()).m_type)) + if (!speculatedTypeChecker(m_state.forNode(node.child2()).m_type)) speculationCheck(BadType, JSValueRegs(op2GPR), node.child2().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo))); MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR); @@ -1526,7 +1526,7 @@ void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInf void SpeculativeJIT::compileObjectToObjectOrOtherEquality( Edge leftChild, Edge rightChild, - const ClassInfo* classInfo, PredictionChecker predictionCheck) + const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { SpeculateCellOperand op1(this, leftChild); JSValueOperand op2(this, rightChild); @@ -1536,7 +1536,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( GPRReg op2GPR = op2.gpr(); GPRReg resultGPR = result.gpr(); - if (!predictionCheck(m_state.forNode(leftChild).m_type)) { + if (!speculatedTypeChecker(m_state.forNode(leftChild).m_type)) { speculationCheck( BadType, JSValueRegs(op1GPR), leftChild.index(), m_jit.branchPtr( @@ -1552,9 +1552,9 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the // proof, when filtered on cell, demonstrates that we have an object of the desired type - // (predictionCheck() will test for FinalObject or Array, currently), then we can skip the + // (speculationCheck() will test for FinalObject or Array, currently), then we can skip the // speculation. - if (!predictionCheck(m_state.forNode(rightChild).m_type & PredictCell)) { + if (!speculatedTypeChecker(m_state.forNode(rightChild).m_type & SpecCell)) { speculationCheck( BadType, JSValueRegs(op2GPR), rightChild.index(), m_jit.branchPtr( @@ -1573,7 +1573,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must not be a cell. Check if that is enough to // prove that it is either null or undefined. - if (!isOtherPrediction(m_state.forNode(rightChild).m_type & ~PredictCell)) { + if (!isOtherSpeculation(m_state.forNode(rightChild).m_type & ~SpecCell)) { m_jit.move(op2GPR, resultGPR); m_jit.andPtr(MacroAssembler::TrustedImm32(~TagBitUndefined), resultGPR); @@ -1596,7 +1596,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex, - const ClassInfo* classInfo, PredictionChecker predictionCheck) + const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { Node& branchNode = at(branchNodeIndex); BlockIndex taken = branchNode.takenBlockIndex(); @@ -1610,7 +1610,7 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( GPRReg op2GPR = op2.gpr(); GPRReg resultGPR = result.gpr(); - if (!predictionCheck(m_state.forNode(leftChild).m_type)) { + if (!speculatedTypeChecker(m_state.forNode(leftChild).m_type)) { speculationCheck( BadType, JSValueRegs(op1GPR), leftChild.index(), m_jit.branchPtr( @@ -1626,9 +1626,9 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the // proof, when filtered on cell, demonstrates that we have an object of the desired type - // (predictionCheck() will test for FinalObject or Array, currently), then we can skip the + // (speculationCheck() will test for FinalObject or Array, currently), then we can skip the // speculation. - if (!predictionCheck(m_state.forNode(rightChild).m_type & PredictCell)) { + if (!speculatedTypeChecker(m_state.forNode(rightChild).m_type & SpecCell)) { speculationCheck( BadType, JSValueRegs(op2GPR), rightChild.index(), m_jit.branchPtr( @@ -1644,7 +1644,7 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must not be a cell. Check if that is enough to // prove that it is either null or undefined. - if (isOtherPrediction(m_state.forNode(rightChild).m_type & ~PredictCell)) + if (isOtherSpeculation(m_state.forNode(rightChild).m_type & ~SpecCell)) rightNotCell.link(&m_jit); else { jump(notTaken, ForceJump); @@ -1739,11 +1739,11 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse, const ClassInf void SpeculativeJIT::compileLogicalNot(Node& node) { if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) { - compileObjectOrOtherLogicalNot(node.child1(), &JSFinalObject::s_info, !isFinalObjectOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + compileObjectOrOtherLogicalNot(node.child1(), &JSFinalObject::s_info, !isFinalObjectOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); return; } if (at(node.child1()).shouldSpeculateArrayOrOther()) { - compileObjectOrOtherLogicalNot(node.child1(), &JSArray::s_info, !isArrayOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + compileObjectOrOtherLogicalNot(node.child1(), &JSArray::s_info, !isArrayOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); return; } if (at(node.child1()).shouldSpeculateInteger()) { @@ -1766,9 +1766,9 @@ void SpeculativeJIT::compileLogicalNot(Node& node) return; } - PredictedType prediction = m_jit.getPrediction(node.child1()); - if (isBooleanPrediction(prediction)) { - if (isBooleanPrediction(m_state.forNode(node.child1()).m_type)) { + SpeculatedType prediction = m_jit.getSpeculation(node.child1()); + if (isBooleanSpeculation(prediction)) { + if (isBooleanSpeculation(m_state.forNode(node.child1()).m_type)) { SpeculateBooleanOperand value(this, node.child1()); GPRTemporary result(this, value); @@ -1841,9 +1841,9 @@ void SpeculativeJIT::emitBranch(Node& node) BlockIndex notTaken = node.notTakenBlockIndex(); if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) { - emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSFinalObject::s_info, !isFinalObjectOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSFinalObject::s_info, !isFinalObjectOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); } else if (at(node.child1()).shouldSpeculateArrayOrOther()) { - emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSArray::s_info, !isArrayOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSArray::s_info, !isArrayOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); } else if (at(node.child1()).shouldSpeculateNumber()) { if (at(node.child1()).shouldSpeculateInteger()) { bool invert = false; @@ -1870,10 +1870,10 @@ void SpeculativeJIT::emitBranch(Node& node) JSValueOperand value(this, node.child1()); GPRReg valueGPR = value.gpr(); - bool predictBoolean = isBooleanPrediction(m_jit.getPrediction(node.child1())); + bool predictBoolean = isBooleanSpeculation(m_jit.getSpeculation(node.child1())); if (predictBoolean) { - if (isBooleanPrediction(m_state.forNode(node.child1()).m_type)) { + if (isBooleanSpeculation(m_state.forNode(node.child1()).m_type)) { MacroAssembler::ResultCondition condition = MacroAssembler::NonZero; if (taken == nextBlock()) { @@ -1924,7 +1924,13 @@ void SpeculativeJIT::compile(Node& node) switch (op) { case JSConstant: + initConstantInfo(m_compileIndex); + break; + case PhantomArguments: + // This should never be must-generate. + ASSERT_NOT_REACHED(); + // But as a release-mode fall-back make it the empty value. initConstantInfo(m_compileIndex); break; @@ -1934,11 +1940,11 @@ void SpeculativeJIT::compile(Node& node) break; case GetLocal: { - PredictedType prediction = node.variableAccessData()->prediction(); + SpeculatedType prediction = node.variableAccessData()->prediction(); AbstractValue& value = block()->valuesAtHead.operand(node.local()); // If we have no prediction for this local, then don't attempt to compile. - if (prediction == PredictNone) { + if (prediction == SpecNone) { terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); break; } @@ -1960,7 +1966,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isInt32Prediction(value.m_type)) { + if (isInt32Speculation(value.m_type)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -1984,9 +1990,9 @@ void SpeculativeJIT::compile(Node& node) DataFormat format; if (node.variableAccessData()->isCaptured()) format = DataFormatJS; - else if (isCellPrediction(value.m_type)) + else if (isCellSpeculation(value.m_type)) format = DataFormatJSCell; - else if (isBooleanPrediction(value.m_type)) + else if (isBooleanSpeculation(value.m_type)) format = DataFormatJSBoolean; else format = DataFormatJS; @@ -2053,25 +2059,25 @@ void SpeculativeJIT::compile(Node& node) break; } - PredictedType predictedType = node.variableAccessData()->argumentAwarePrediction(); - if (isInt32Prediction(predictedType)) { + SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction(); + if (isInt32Speculation(predictedType)) { SpeculateIntegerOperand value(this, node.child1()); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); valueSourceReferenceForOperand(node.local()) = ValueSource(Int32InRegisterFile); break; } - if (isArrayPrediction(predictedType)) { + if (isArraySpeculation(predictedType)) { SpeculateCellOperand cell(this, node.child1()); GPRReg cellGPR = cell.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local())); noResult(m_compileIndex); valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile); break; } - if (isBooleanPrediction(predictedType)) { + if (isBooleanSpeculation(predictedType)) { SpeculateBooleanOperand boolean(this, node.child1()); m_jit.storePtr(boolean.gpr(), JITCompiler::addressFor(node.local())); noResult(m_compileIndex); @@ -2170,7 +2176,7 @@ void SpeculativeJIT::compile(Node& node) } case CheckNumber: { - if (!isNumberPrediction(m_state.forNode(node.child1()).m_type)) { + if (!isNumberSpeculation(m_state.forNode(node.child1()).m_type)) { JSValueOperand op1(this, node.child1()); JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, op1.gpr(), GPRInfo::tagTypeNumberRegister); speculationCheck( @@ -2370,7 +2376,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArrayPrediction(at(node.child1()).prediction())) { + if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArraySpeculation(at(node.child1()).prediction())) { JSValueOperand base(this, node.child1()); JSValueOperand property(this, node.child2()); GPRReg baseGPR = base.gpr(); @@ -2391,7 +2397,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (at(node.child1()).prediction() == PredictString) { + if (at(node.child1()).prediction() == SpecString) { compileGetByValOnString(node); if (!m_compileOkay) return; @@ -2399,63 +2405,63 @@ void SpeculativeJIT::compile(Node& node) } if (at(node.child1()).shouldSpeculateInt8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat32Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat64Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; @@ -2474,7 +2480,7 @@ void SpeculativeJIT::compile(Node& node) if (!m_compileOkay) return; - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); @@ -2495,7 +2501,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (!at(node.child2()).shouldSpeculateInteger() || !isActionableMutableArrayPrediction(at(node.child1()).prediction())) { + if (!at(node.child2()).shouldSpeculateInteger() || !isActionableMutableArraySpeculation(at(node.child1()).prediction())) { JSValueOperand arg1(this, node.child1()); JSValueOperand arg2(this, node.child2()); JSValueOperand arg3(this, node.child3()); @@ -2528,7 +2534,7 @@ void SpeculativeJIT::compile(Node& node) if (!m_compileOkay) return; - if (!isArgumentsPrediction(m_state.forNode(node.child1()).m_type)) { + if (!isArgumentsSpeculation(m_state.forNode(node.child1()).m_type)) { speculationCheck( BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr( @@ -2572,61 +2578,61 @@ void SpeculativeJIT::compile(Node& node) } if (at(node.child1()).shouldSpeculateInt8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); break; } if (at(node.child1()).shouldSpeculateUint16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat32Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat64Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; @@ -2650,7 +2656,7 @@ void SpeculativeJIT::compile(Node& node) // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). // If we have predicted the base to be type array, we can skip the check. - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); base.use(); @@ -2695,7 +2701,7 @@ void SpeculativeJIT::compile(Node& node) break; } - ASSERT(isActionableMutableArrayPrediction(at(node.child1()).prediction())); + ASSERT(isActionableMutableArraySpeculation(at(node.child1()).prediction())); ASSERT(at(node.child2()).shouldSpeculateInteger()); SpeculateCellOperand base(this, node.child1()); @@ -2847,7 +2853,7 @@ void SpeculativeJIT::compile(Node& node) writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); @@ -2885,7 +2891,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg storageGPR = storage.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); @@ -3012,7 +3018,7 @@ void SpeculativeJIT::compile(Node& node) op1.use(); - if (!(m_state.forNode(node.child1()).m_type & ~(PredictNumber | PredictBoolean))) + if (!(m_state.forNode(node.child1()).m_type & ~(SpecNumber | SpecBoolean))) m_jit.move(op1GPR, resultGPR); else { MacroAssembler::Jump alreadyPrimitive = m_jit.branchTestPtr(MacroAssembler::NonZero, op1GPR, GPRInfo::tagMaskRegister); @@ -3106,7 +3112,7 @@ void SpeculativeJIT::compile(Node& node) } case ConvertThis: { - if (isObjectPrediction(m_state.forNode(node.child1()).m_type)) { + if (isObjectSpeculation(m_state.forNode(node.child1()).m_type)) { SpeculateCellOperand thisValue(this, node.child1()); GPRTemporary result(this, thisValue); m_jit.move(thisValue.gpr(), result.gpr()); @@ -3114,13 +3120,13 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isOtherPrediction(at(node.child1()).prediction())) { + if (isOtherSpeculation(at(node.child1()).prediction())) { JSValueOperand thisValue(this, node.child1()); GPRTemporary scratch(this, thisValue); GPRReg thisValueGPR = thisValue.gpr(); GPRReg scratchGPR = scratch.gpr(); - if (!isOtherPrediction(m_state.forNode(node.child1()).m_type)) { + if (!isOtherSpeculation(m_state.forNode(node.child1()).m_type)) { m_jit.move(thisValueGPR, scratchGPR); m_jit.andPtr(MacroAssembler::TrustedImm32(~TagBitUndefined), scratchGPR); speculationCheck(BadType, JSValueRegs(thisValueGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, scratchGPR, MacroAssembler::TrustedImmPtr(reinterpret_cast<void*>(ValueNull)))); @@ -3131,13 +3137,13 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isObjectPrediction(at(node.child1()).prediction())) { + if (isObjectSpeculation(at(node.child1()).prediction())) { SpeculateCellOperand thisValue(this, node.child1()); GPRTemporary result(this, thisValue); GPRReg thisValueGPR = thisValue.gpr(); GPRReg resultGPR = result.gpr(); - if (!isObjectPrediction(m_state.forNode(node.child1()).m_type)) + if (!isObjectSpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(thisValueGPR), node.child1(), m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(thisValueGPR, JSCell::classInfoOffset()), JITCompiler::TrustedImmPtr(&JSString::s_info))); m_jit.move(thisValueGPR, resultGPR); @@ -3259,7 +3265,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isCellPrediction(at(node.child1()).prediction())) { + if (isCellSpeculation(at(node.child1()).prediction())) { SpeculateCellOperand base(this, node.child1()); GPRTemporary result(this, base); @@ -3309,7 +3315,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isCellPrediction(at(node.child1()).prediction())) { + if (isCellSpeculation(at(node.child1()).prediction())) { SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); @@ -3356,7 +3362,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg baseGPR = base.gpr(); GPRReg resultGPR = result.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR); @@ -3380,7 +3386,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg baseGPR = base.gpr(); GPRReg resultGPR = result.gpr(); - if (!isStringPrediction(m_state.forNode(node.child1()).m_type)) + if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSString::s_info))); m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR); @@ -3390,39 +3396,39 @@ void SpeculativeJIT::compile(Node& node) } case GetInt8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetInt16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetInt32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint8ClampedArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetFloat32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetFloat64ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case CheckFunction: { @@ -3434,7 +3440,7 @@ void SpeculativeJIT::compile(Node& node) case CheckStructure: { AbstractValue& value = m_state.forNode(node.child1()); if (value.m_structure.isSubsetOf(node.structureSet()) - && isCellPrediction(value.m_type)) { + && isCellSpeculation(value.m_type)) { noResult(m_compileIndex); break; } @@ -3464,7 +3470,23 @@ void SpeculativeJIT::compile(Node& node) break; } + case StructureTransitionWatchpoint: { + m_jit.addWeakReference(node.structure()); + node.structure()->addTransitionWatchpoint(speculationWatchpoint()); + +#if !ASSERT_DISABLED + SpeculateCellOperand op1(this, node.child1()); + JITCompiler::Jump isOK = m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(op1.gpr(), JSCell::structureOffset()), TrustedImmPtr(node.structure())); + m_jit.breakpoint(); + isOK.link(&m_jit); +#endif + + noResult(m_compileIndex); + break; + } + case PhantomPutStructure: { + ASSERT(node.structureTransitionData().previousStructure->transitionWatchpointSetHasBeenInvalidated()); m_jit.addWeakReferenceTransition( node.codeOrigin.codeOriginOwner(), node.structureTransitionData().previousStructure, @@ -3474,6 +3496,8 @@ void SpeculativeJIT::compile(Node& node) } case PutStructure: { + ASSERT(node.structureTransitionData().previousStructure->transitionWatchpointSetHasBeenInvalidated()); + SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); @@ -3587,9 +3611,7 @@ void SpeculativeJIT::compile(Node& node) case GetGlobalVar: { GPRTemporary result(this); - JSVariableObject* globalObject = m_jit.globalObjectFor(node.codeOrigin); - m_jit.loadPtr(globalObject->addressOfRegisters(), result.gpr()); - m_jit.loadPtr(JITCompiler::addressForGlobalVar(result.gpr(), node.varNumber()), result.gpr()); + m_jit.loadPtr(node.registerPointer(), result.gpr()); jsValueResult(result.gpr(), m_compileIndex); break; @@ -3597,22 +3619,65 @@ void SpeculativeJIT::compile(Node& node) case PutGlobalVar: { JSValueOperand value(this, node.child1()); - GPRTemporary globalObject(this); - GPRTemporary scratch(this); - GPRReg globalObjectReg = globalObject.gpr(); - GPRReg scratchReg = scratch.gpr(); - - m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)), globalObjectReg); + if (Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + GPRReg scratchReg = scratch.gpr(); + + writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.gpr(), node.child1(), WriteBarrierForVariableAccess, scratchReg); + } + + m_jit.storePtr(value.gpr(), node.registerPointer()); - writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.gpr(), node.child1(), WriteBarrierForVariableAccess, scratchReg); + noResult(m_compileIndex); + break; + } - m_jit.loadPtr(MacroAssembler::Address(globalObjectReg, JSVariableObject::offsetOfRegisters()), scratchReg); - m_jit.storePtr(value.gpr(), JITCompiler::addressForGlobalVar(scratchReg, node.varNumber())); + case PutGlobalVarCheck: { + JSValueOperand value(this, node.child1()); + + WatchpointSet* watchpointSet = + m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get( + identifier(node.identifierNumberForCheck())->impl()).watchpointSet(); + addSlowPathGenerator( + slowPathCall( + m_jit.branchTest8( + JITCompiler::NonZero, + JITCompiler::AbsoluteAddress(watchpointSet->addressOfIsWatched())), + this, operationNotifyGlobalVarWrite, NoResult, watchpointSet)); + + if (Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + GPRReg scratchReg = scratch.gpr(); + + writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.gpr(), node.child1(), WriteBarrierForVariableAccess, scratchReg); + } + + m_jit.storePtr(value.gpr(), node.registerPointer()); noResult(m_compileIndex); break; } + + case GlobalVarWatchpoint: { + m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get( + identifier(node.identifierNumberForCheck())->impl()).addWatchpoint( + speculationWatchpoint()); + +#if DFG_ENABLE(JIT_ASSERT) + GPRTemporary scratch(this); + GPRReg scratchGPR = scratch.gpr(); + m_jit.loadPtr(node.registerPointer(), scratchGPR); + JITCompiler::Jump ok = m_jit.branchPtr( + JITCompiler::Equal, scratchGPR, + TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(node.registerPointer()->get())))); + m_jit.breakpoint(); + ok.link(&m_jit); +#endif + + noResult(m_compileIndex); + break; + } case CheckHasInstance: { SpeculateCellOperand base(this, node.child1()); @@ -3880,7 +3945,7 @@ void SpeculativeJIT::compile(Node& node) GPRTemporary result(this); GPRReg resultGPR = result.gpr(); - if (!isEmptyPrediction( + if (!isEmptySpeculation( m_state.variables().operand( m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { speculationCheck( @@ -3939,7 +4004,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg indexGPR = index.gpr(); GPRReg resultGPR = result.gpr(); - if (!isEmptyPrediction( + if (!isEmptySpeculation( m_state.variables().operand( m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { speculationCheck( @@ -4021,27 +4086,35 @@ void SpeculativeJIT::compile(Node& node) : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register)), resultGPR); - addSlowPathGenerator( - slowPathCall( - slowPath, this, operationGetArgumentByVal, resultGPR, - m_jit.argumentsRegisterFor(node.codeOrigin), - indexGPR)); + if (node.codeOrigin.inlineCallFrame) { + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationGetInlinedArgumentByVal, resultGPR, + m_jit.argumentsRegisterFor(node.codeOrigin), + node.codeOrigin.inlineCallFrame, + indexGPR)); + } else { + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationGetArgumentByVal, resultGPR, + m_jit.argumentsRegisterFor(node.codeOrigin), + indexGPR)); + } jsValueResult(resultGPR, m_compileIndex); break; } case CheckArgumentsNotCreated: { - if (!isEmptyPrediction( - m_state.variables().operand( - m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { - speculationCheck( - ArgumentsEscaped, JSValueRegs(), NoNode, - m_jit.branchTestPtr( - JITCompiler::NonZero, - JITCompiler::addressFor( - m_jit.argumentsRegisterFor(node.codeOrigin)))); - } + ASSERT(!isEmptySpeculation( + m_state.variables().operand( + m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)); + speculationCheck( + ArgumentsEscaped, JSValueRegs(), NoNode, + m_jit.branchTestPtr( + JITCompiler::NonZero, + JITCompiler::addressFor( + m_jit.argumentsRegisterFor(node.codeOrigin)))); noResult(m_compileIndex); break; } diff --git a/Source/JavaScriptCore/dfg/DFGThunks.cpp b/Source/JavaScriptCore/dfg/DFGThunks.cpp index 1ed46c11f..08ca6eaa1 100644 --- a/Source/JavaScriptCore/dfg/DFGThunks.cpp +++ b/Source/JavaScriptCore/dfg/DFGThunks.cpp @@ -79,7 +79,7 @@ MacroAssemblerCodeRef osrExitGenerationThunkGenerator(JSGlobalData* globalData) patchBuffer.link(functionCall, compileOSRExit); - return patchBuffer.finalizeCode(); + return FINALIZE_CODE(patchBuffer, ("DFG OSR exit generation thunk")); } } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGVariableAccessData.h b/Source/JavaScriptCore/dfg/DFGVariableAccessData.h index 3dfd94d01..382907d27 100644 --- a/Source/JavaScriptCore/dfg/DFGVariableAccessData.h +++ b/Source/JavaScriptCore/dfg/DFGVariableAccessData.h @@ -29,7 +29,7 @@ #include "DFGDoubleFormatState.h" #include "DFGNodeFlags.h" #include "Operands.h" -#include "PredictedType.h" +#include "SpeculatedType.h" #include "VirtualRegister.h" #include <wtf/Platform.h> #include <wtf/UnionFind.h> @@ -43,8 +43,8 @@ public: VariableAccessData() : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min())) - , m_prediction(PredictNone) - , m_argumentAwarePrediction(PredictNone) + , m_prediction(SpecNone) + , m_argumentAwarePrediction(SpecNone) , m_flags(0) , m_doubleFormatState(EmptyDoubleFormatState) , m_isCaptured(false) @@ -55,8 +55,8 @@ public: VariableAccessData(VirtualRegister local, bool isCaptured) : m_local(local) - , m_prediction(PredictNone) - , m_argumentAwarePrediction(PredictNone) + , m_prediction(SpecNone) + , m_argumentAwarePrediction(SpecNone) , m_flags(0) , m_doubleFormatState(EmptyDoubleFormatState) , m_isCaptured(isCaptured) @@ -104,33 +104,33 @@ public: return m_isArgumentsAlias; } - bool predict(PredictedType prediction) + bool predict(SpeculatedType prediction) { VariableAccessData* self = find(); - bool result = mergePrediction(self->m_prediction, prediction); + bool result = mergeSpeculation(self->m_prediction, prediction); if (result) - mergePrediction(m_argumentAwarePrediction, m_prediction); + mergeSpeculation(m_argumentAwarePrediction, m_prediction); return result; } - PredictedType nonUnifiedPrediction() + SpeculatedType nonUnifiedPrediction() { return m_prediction; } - PredictedType prediction() + SpeculatedType prediction() { return find()->m_prediction; } - PredictedType argumentAwarePrediction() + SpeculatedType argumentAwarePrediction() { return find()->m_argumentAwarePrediction; } - bool mergeArgumentAwarePrediction(PredictedType prediction) + bool mergeArgumentAwarePrediction(SpeculatedType prediction) { - return mergePrediction(find()->m_argumentAwarePrediction, prediction); + return mergeSpeculation(find()->m_argumentAwarePrediction, prediction); } void clearVotes() @@ -161,12 +161,12 @@ public: // If the variable is not a number prediction, then this doesn't // make any sense. - if (!isNumberPrediction(prediction())) + if (!isNumberSpeculation(prediction())) return false; // If the variable is predicted to hold only doubles, then it's a // no-brainer: it should be formatted as a double. - if (isDoublePrediction(prediction())) + if (isDoubleSpeculation(prediction())) return true; // If the variable is known to be used as an integer, then be safe - @@ -225,7 +225,7 @@ public: if (m_doubleFormatState != UsingDoubleFormat) return false; - return mergePrediction(m_prediction, PredictDouble); + return mergeSpeculation(m_prediction, SpecDouble); } NodeFlags flags() const { return m_flags; } @@ -246,8 +246,8 @@ private: // usage for variable access nodes do be significant. VirtualRegister m_local; - PredictedType m_prediction; - PredictedType m_argumentAwarePrediction; + SpeculatedType m_prediction; + SpeculatedType m_argumentAwarePrediction; NodeFlags m_flags; float m_votes[2]; |