FlushFormat VariableAccessData::flushFormat()
{
    ASSERT(find() == this);
    
    if (isArgumentsAlias())
        return FlushedArguments;
    
    if (!shouldUnboxIfPossible())
        return FlushedJSValue;
    
    if (shouldUseDoubleFormat())
        return FlushedDouble;
    
    SpeculatedType prediction = argumentAwarePrediction();
    
    // This guard is here to protect the call to couldRepresentInt52(), which will return
    // true for !prediction.
    if (!prediction)
        return FlushedJSValue;
    
    if (isInt32Speculation(prediction))
        return FlushedInt32;
    
    if (couldRepresentInt52Impl())
        return FlushedInt52;
    
    if (isCellSpeculation(prediction))
        return FlushedCell;
    
    if (isBooleanSpeculation(prediction))
        return FlushedBoolean;
    
    return FlushedJSValue;
}
FlushFormat VariableAccessData::flushFormat()
{
    ASSERT(find() == this);
    
    if (isArgumentsAlias())
        return FlushedArguments;
    
    if (!shouldUnboxIfPossible())
        return FlushedJSValue;
    
    if (shouldUseDoubleFormat())
        return FlushedDouble;
    
    SpeculatedType prediction = argumentAwarePrediction();
    if (isInt32Speculation(prediction))
        return FlushedInt32;
    
    if (enableInt52() && !m_local.isArgument() && isMachineIntSpeculation(prediction))
        return FlushedInt52;
    
    if (isCellSpeculation(prediction))
        return FlushedCell;
    
    if (isBooleanSpeculation(prediction))
        return FlushedBoolean;
    
    return FlushedJSValue;
}
Example #3
0
// We don't expose this because we don't want anyone relying on the fact that this method currently
// just returns string constants.
static const char* speculationToAbbreviatedString(SpeculatedType prediction)
{
    if (isFinalObjectSpeculation(prediction))
        return "<Final>";
    if (isArraySpeculation(prediction))
        return "<Array>";
    if (isStringIdentSpeculation(prediction))
        return "<StringIdent>";
    if (isStringSpeculation(prediction))
        return "<String>";
    if (isFunctionSpeculation(prediction))
        return "<Function>";
    if (isInt8ArraySpeculation(prediction))
        return "<Int8array>";
    if (isInt16ArraySpeculation(prediction))
        return "<Int16array>";
    if (isInt32ArraySpeculation(prediction))
        return "<Int32array>";
    if (isUint8ArraySpeculation(prediction))
        return "<Uint8array>";
    if (isUint16ArraySpeculation(prediction))
        return "<Uint16array>";
    if (isUint32ArraySpeculation(prediction))
        return "<Uint32array>";
    if (isFloat32ArraySpeculation(prediction))
        return "<Float32array>";
    if (isFloat64ArraySpeculation(prediction))
        return "<Float64array>";
    if (isDirectArgumentsSpeculation(prediction))
        return "<DirectArguments>";
    if (isScopedArgumentsSpeculation(prediction))
        return "<ScopedArguments>";
    if (isStringObjectSpeculation(prediction))
        return "<StringObject>";
    if (isStringOrStringObjectSpeculation(prediction))
        return "<StringOrStringObject>";
    if (isObjectSpeculation(prediction))
        return "<Object>";
    if (isCellSpeculation(prediction))
        return "<Cell>";
    if (isInt32Speculation(prediction))
        return "<Int32>";
    if (isInt52AsDoubleSpeculation(prediction))
        return "<Int52AsDouble>";
    if (isInt52Speculation(prediction))
        return "<Int52>";
    if (isMachineIntSpeculation(prediction))
        return "<MachineInt>";
    if (isDoubleSpeculation(prediction))
        return "<Double>";
    if (isFullNumberSpeculation(prediction))
        return "<Number>";
    if (isBooleanSpeculation(prediction))
        return "<Boolean>";
    if (isOtherSpeculation(prediction))
        return "<Other>";
    if (isMiscSpeculation(prediction))
        return "<Misc>";
    return "";
}
 bool shouldConsiderForHoisting(VariableAccessData* variable)
 {
     if (!variable->shouldUnboxIfPossible())
         return false;
     if (variable->structureCheckHoistingFailed())
         return false;
     if (!isCellSpeculation(variable->prediction()))
         return false;
     return true;
 }
Example #5
0
    bool run()
    {
        for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
            VariableAccessData* variable = &m_graph.m_variableAccessData[i];
            if (!variable->isRoot())
                continue;
            variable->clearVotes();
        }
        
        // Identify the set of variables that are always subject to the same structure
        // checks. For now, only consider monomorphic structure checks (one structure).
        
        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
            if (!block)
                continue;
            for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
                NodeIndex nodeIndex = block->at(indexInBlock);
                Node& node = m_graph[nodeIndex];
                if (!node.shouldGenerate())
                    continue;
                switch (node.op()) {
                case CheckStructure: {
                    Node& child = m_graph[node.child1()];
                    if (child.op() != GetLocal)
                        break;
                    VariableAccessData* variable = child.variableAccessData();
                    variable->vote(VoteStructureCheck);
                    if (variable->isCaptured() || variable->structureCheckHoistingFailed())
                        break;
                    if (!isCellSpeculation(variable->prediction()))
                        break;
                    noticeStructureCheck(variable, node.structureSet());
                    break;
                }
                    
                case ForwardCheckStructure:
                case ForwardStructureTransitionWatchpoint:
                    // We currently rely on the fact that we're the only ones who would
                    // insert this node.
                    ASSERT_NOT_REACHED();
                    break;
                    
                case GetByOffset:
                case PutByOffset:
                case PutStructure:
                case StructureTransitionWatchpoint:
                case AllocatePropertyStorage:
                case ReallocatePropertyStorage:
                case GetPropertyStorage:
                case GetByVal:
                case PutByVal:
                case PutByValAlias:
                case GetArrayLength:
                case CheckArray:
                case GetIndexedPropertyStorage:
                case Phantom:
                    // Don't count these uses.
                    break;
                    
                default:
                    m_graph.vote(node, VoteOther);
                    break;
                }
            }
        }
        
        // Disable structure hoisting on variables that appear to mostly be used in
        // contexts where it doesn't make sense.
        
        for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
            VariableAccessData* variable = &m_graph.m_variableAccessData[i];
            if (!variable->isRoot())
                continue;
            if (variable->voteRatio() >= Options::structureCheckVoteRatioForHoisting())
                continue;
            HashMap<VariableAccessData*, CheckData>::iterator iter = m_map.find(variable);
            if (iter == m_map.end())
                continue;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
            dataLog("Zeroing the structure to hoist for %s because the ratio is %lf.\n",
                    m_graph.nameOfVariableAccessData(variable), variable->voteRatio());
#endif
            iter->second.m_structure = 0;
        }

        // Identify the set of variables that are live across a structure clobber.
        
        Operands<VariableAccessData*> live(
            m_graph.m_blocks[0]->variablesAtTail.numberOfArguments(),
            m_graph.m_blocks[0]->variablesAtTail.numberOfLocals());
        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
            if (!block)
                continue;
            ASSERT(live.numberOfArguments() == block->variablesAtTail.numberOfArguments());
            ASSERT(live.numberOfLocals() == block->variablesAtTail.numberOfLocals());
            for (unsigned i = live.size(); i--;) {
                NodeIndex indexAtTail = block->variablesAtTail[i];
                VariableAccessData* variable;
                if (indexAtTail == NoNode)
                    variable = 0;
                else
                    variable = m_graph[indexAtTail].variableAccessData();
                live[i] = variable;
            }
            for (unsigned indexInBlock = block->size(); indexInBlock--;) {
                NodeIndex nodeIndex = block->at(indexInBlock);
                Node& node = m_graph[nodeIndex];
                if (!node.shouldGenerate())
                    continue;
                switch (node.op()) {
                case GetLocal:
                case Flush:
                    // This is a birth.
                    live.operand(node.local()) = node.variableAccessData();
                    break;
                    
                case SetLocal:
                case SetArgument:
                    ASSERT(live.operand(node.local())); // Must be live.
                    ASSERT(live.operand(node.local()) == node.variableAccessData()); // Must have the variable we expected.
                    // This is a death.
                    live.operand(node.local()) = 0;
                    break;
                    
                // Use the CFA's notion of what clobbers the world.
                case ValueAdd:
                    if (m_graph.addShouldSpeculateInteger(node))
                        break;
                    if (Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()]))
                        break;
                    clobber(live);
                    break;
                    
                case CompareLess:
                case CompareLessEq:
                case CompareGreater:
                case CompareGreaterEq:
                case CompareEq: {
                    Node& left = m_graph[node.child1()];
                    Node& right = m_graph[node.child2()];
                    if (Node::shouldSpeculateInteger(left, right))
                        break;
                    if (Node::shouldSpeculateNumber(left, right))
                        break;
                    if (node.op() == CompareEq) {
                        if ((m_graph.isConstant(node.child1().index())
                             && m_graph.valueOfJSConstant(node.child1().index()).isNull())
                            || (m_graph.isConstant(node.child2().index())
                                && m_graph.valueOfJSConstant(node.child2().index()).isNull()))
                            break;
                        
                        if (Node::shouldSpeculateFinalObject(left, right))
                            break;
                        if (Node::shouldSpeculateArray(left, right))
                            break;
                        if (left.shouldSpeculateFinalObject() && right.shouldSpeculateFinalObjectOrOther())
                            break;
                        if (right.shouldSpeculateFinalObject() && left.shouldSpeculateFinalObjectOrOther())
                            break;
                        if (left.shouldSpeculateArray() && right.shouldSpeculateArrayOrOther())
                            break;
                        if (right.shouldSpeculateArray() && left.shouldSpeculateArrayOrOther())
                            break;
                    }
                    clobber(live);
                    break;
                }
                    
                case GetByVal:
                case PutByVal:
                case PutByValAlias:
                    if (m_graph.byValIsPure(node))
                        break;
                    clobber(live);
                    break;
                    
                case GetMyArgumentsLengthSafe:
                case GetMyArgumentByValSafe:
                case GetById:
                case GetByIdFlush:
                case PutStructure:
                case PhantomPutStructure:
                case PutById:
                case PutByIdDirect:
                case Call:
                case Construct:
                case Resolve:
                case ResolveBase:
                case ResolveBaseStrictPut:
                case ResolveGlobal:
                    clobber(live);
                    break;
                    
                default:
                    ASSERT(node.op() != Phi);
                    break;
                }
            }
        }
        
        bool changed = false;

#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
        for (HashMap<VariableAccessData*, CheckData>::iterator it = m_map.begin();
             it != m_map.end(); ++it) {
            if (!it->second.m_structure) {
                dataLog("Not hoisting checks for %s because of heuristics.\n", m_graph.nameOfVariableAccessData(it->first));
                continue;
            }
            if (it->second.m_isClobbered && !it->second.m_structure->transitionWatchpointSetIsStillValid()) {
                dataLog("Not hoisting checks for %s because the structure is clobbered and has an invalid watchpoint set.\n", m_graph.nameOfVariableAccessData(it->first));
                continue;
            }
            dataLog("Hoisting checks for %s\n", m_graph.nameOfVariableAccessData(it->first));
        }
#endif // DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
        
        // Make changes:
        // 1) If a variable's live range does not span a clobber, then inject structure
        //    checks before the SetLocal.
        // 2) If a variable's live range spans a clobber but is watchpointable, then
        //    inject structure checks before the SetLocal and replace all other structure
        //    checks on that variable with structure transition watchpoints.
        
        InsertionSet<NodeIndex> insertionSet;
        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
            if (!block)
                continue;
            for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
                NodeIndex nodeIndex = block->at(indexInBlock);
                Node& node = m_graph[nodeIndex];
                // Be careful not to use 'node' after appending to the graph. In those switch
                // cases where we need to append, we first carefully extract everything we need
                // from the node, before doing any appending.
                if (!node.shouldGenerate())
                    continue;
                switch (node.op()) {
                case SetArgument: {
                    ASSERT(!blockIndex);
                    // Insert a GetLocal and a CheckStructure immediately following this
                    // SetArgument, if the variable was a candidate for structure hoisting.
                    // If the basic block previously only had the SetArgument as its
                    // variable-at-tail, then replace it with this GetLocal.
                    VariableAccessData* variable = node.variableAccessData();
                    HashMap<VariableAccessData*, CheckData>::iterator iter = m_map.find(variable);
                    if (iter == m_map.end())
                        break;
                    if (!iter->second.m_structure)
                        break;
                    if (iter->second.m_isClobbered && !iter->second.m_structure->transitionWatchpointSetIsStillValid())
                        break;
                    
                    node.ref();

                    CodeOrigin codeOrigin = node.codeOrigin;
                    
                    Node getLocal(GetLocal, codeOrigin, OpInfo(variable), nodeIndex);
                    getLocal.predict(variable->prediction());
                    getLocal.ref();
                    NodeIndex getLocalIndex = m_graph.size();
                    m_graph.append(getLocal);
                    insertionSet.append(indexInBlock + 1, getLocalIndex);
                    
                    Node checkStructure(CheckStructure, codeOrigin, OpInfo(m_graph.addStructureSet(iter->second.m_structure)), getLocalIndex);
                    checkStructure.ref();
                    NodeIndex checkStructureIndex = m_graph.size();
                    m_graph.append(checkStructure);
                    insertionSet.append(indexInBlock + 1, checkStructureIndex);
                    
                    if (block->variablesAtTail.operand(variable->local()) == nodeIndex)
                        block->variablesAtTail.operand(variable->local()) = getLocalIndex;
                    
                    m_graph.substituteGetLocal(*block, indexInBlock, variable, getLocalIndex);
                    
                    changed = true;
                    break;
                }
                    
                case SetLocal: {
                    VariableAccessData* variable = node.variableAccessData();
                    HashMap<VariableAccessData*, CheckData>::iterator iter = m_map.find(variable);
                    if (iter == m_map.end())
                        break;
                    if (!iter->second.m_structure)
                        break;
                    if (iter->second.m_isClobbered && !iter->second.m_structure->transitionWatchpointSetIsStillValid())
                        break;

                    // First insert a dead SetLocal to tell OSR that the child's value should
                    // be dropped into this bytecode variable if the CheckStructure decides
                    // to exit.
                    
                    CodeOrigin codeOrigin = node.codeOrigin;
                    NodeIndex child1 = node.child1().index();
                    
                    Node setLocal(SetLocal, codeOrigin, OpInfo(variable), child1);
                    NodeIndex setLocalIndex = m_graph.size();
                    m_graph.append(setLocal);
                    insertionSet.append(indexInBlock, setLocalIndex);
                    m_graph[child1].ref();
                    // Use a ForwardCheckStructure to indicate that we should exit to the
                    // next bytecode instruction rather than reexecuting the current one.
                    Node checkStructure(ForwardCheckStructure, codeOrigin, OpInfo(m_graph.addStructureSet(iter->second.m_structure)), child1);
                    checkStructure.ref();
                    NodeIndex checkStructureIndex = m_graph.size();
                    m_graph.append(checkStructure);
                    insertionSet.append(indexInBlock, checkStructureIndex);
                    changed = true;
                    break;
                }
                    
                case CheckStructure: {
                    Node& child = m_graph[node.child1()];
                    if (child.op() != GetLocal)
                        break;
                    HashMap<VariableAccessData*, CheckData>::iterator iter = m_map.find(child.variableAccessData());
                    if (iter == m_map.end())
                        break;
                    if (!iter->second.m_structure)
                        break;
                    if (!iter->second.m_isClobbered) {
                        node.setOpAndDefaultFlags(Phantom);
                        ASSERT(node.refCount() == 1);
                        break;
                    }
                    if (!iter->second.m_structure->transitionWatchpointSetIsStillValid())
                        break;
                    ASSERT(iter->second.m_structure == node.structureSet().singletonStructure());
                    node.convertToStructureTransitionWatchpoint();
                    changed = true;
                    break;
                }
                    
                default:
                    break;
                }
            }
            insertionSet.execute(*block);
        }
        
        return changed;
    }
Example #6
0
void InPlaceAbstractState::initialize()
{
    BasicBlock* root = m_graph.block(0);
    root->cfaShouldRevisit = true;
    root->cfaHasVisited = false;
    root->cfaFoundConstants = false;
    for (size_t i = 0; i < root->valuesAtHead.numberOfArguments(); ++i) {
        root->valuesAtTail.argument(i).clear();
        if (m_graph.m_form == SSA) {
            root->valuesAtHead.argument(i).makeTop();
            continue;
        }
        
        Node* node = root->variablesAtHead.argument(i);
        ASSERT(node->op() == SetArgument);
        if (!node->variableAccessData()->shouldUnboxIfPossible()) {
            root->valuesAtHead.argument(i).makeTop();
            continue;
        }
        
        SpeculatedType prediction =
            node->variableAccessData()->argumentAwarePrediction();
        if (isInt32Speculation(prediction))
            root->valuesAtHead.argument(i).setType(SpecInt32);
        else if (isBooleanSpeculation(prediction))
            root->valuesAtHead.argument(i).setType(SpecBoolean);
        else if (isCellSpeculation(prediction))
            root->valuesAtHead.argument(i).setType(SpecCell);
        else
            root->valuesAtHead.argument(i).makeTop();
    }
    for (size_t i = 0; i < root->valuesAtHead.numberOfLocals(); ++i) {
        Node* node = root->variablesAtHead.local(i);
        if (node && node->variableAccessData()->isCaptured())
            root->valuesAtHead.local(i).makeTop();
        else
            root->valuesAtHead.local(i).clear();
        root->valuesAtTail.local(i).clear();
    }
    for (BlockIndex blockIndex = 1 ; blockIndex < m_graph.numBlocks(); ++blockIndex) {
        BasicBlock* block = m_graph.block(blockIndex);
        if (!block)
            continue;
        ASSERT(block->isReachable);
        block->cfaShouldRevisit = false;
        block->cfaHasVisited = false;
        block->cfaFoundConstants = false;
        for (size_t i = 0; i < block->valuesAtHead.numberOfArguments(); ++i) {
            block->valuesAtHead.argument(i).clear();
            block->valuesAtTail.argument(i).clear();
        }
        for (size_t i = 0; i < block->valuesAtHead.numberOfLocals(); ++i) {
            block->valuesAtHead.local(i).clear();
            block->valuesAtTail.local(i).clear();
        }
        if (!block->isOSRTarget)
            continue;
        if (block->bytecodeBegin != m_graph.m_plan.osrEntryBytecodeIndex)
            continue;
        for (size_t i = 0; i < m_graph.m_plan.mustHandleValues.size(); ++i) {
            AbstractValue value;
            value.setMostSpecific(m_graph, m_graph.m_plan.mustHandleValues[i]);
            int operand = m_graph.m_plan.mustHandleValues.operandForIndex(i);
            block->valuesAtHead.operand(operand).merge(value);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
            dataLogF("    Initializing Block #%u, operand r%d, to ", blockIndex, operand);
            block->valuesAtHead.operand(operand).dump(WTF::dataFile());
            dataLogF("\n");
#endif
        }
        block->cfaShouldRevisit = true;
    }
    if (m_graph.m_form == SSA) {
        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
            BasicBlock* block = m_graph.block(blockIndex);
            if (!block)
                continue;
            setLiveValues(block->ssa->valuesAtHead, block->ssa->liveAtHead);
            setLiveValues(block->ssa->valuesAtTail, block->ssa->liveAtTail);
        }
    }
}
Example #7
0
ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, SpeculatedType value, NodeFlags flags) const
{
    if (!base || !index) {
        // It can be that we had a legitimate arrayMode but no incoming predictions. That'll
        // happen if we inlined code based on, say, a global variable watchpoint, but later
        // realized that the callsite could not have possibly executed. It may be worthwhile
        // to fix that, but for now I'm leaving it as-is.
        return ArrayMode(Array::ForceExit);
    }
    
    if (!isInt32Speculation(index) || !isCellSpeculation(base))
        return ArrayMode(Array::Generic);
    
    switch (type()) {
    case Array::Unprofiled:
        return ArrayMode(Array::ForceExit);
        
    case Array::Undecided:
        if (!value)
            return withType(Array::ForceExit);
        if (isInt32Speculation(value))
            return withTypeAndConversion(Array::Int32, Array::Convert);
        if (isNumberSpeculation(value))
            return withTypeAndConversion(Array::Double, Array::Convert);
        return withTypeAndConversion(Array::Contiguous, Array::Convert);
        
    case Array::Int32:
        if (!value || isInt32Speculation(value))
            return *this;
        if (isNumberSpeculation(value))
            return withTypeAndConversion(Array::Double, Array::Convert);
        return withTypeAndConversion(Array::Contiguous, Array::Convert);
        
    case Array::Double:
        if (flags & NodeUsedAsIntLocally)
            return withTypeAndConversion(Array::Contiguous, Array::RageConvert);
        if (!value || isNumberSpeculation(value))
            return *this;
        return withTypeAndConversion(Array::Contiguous, Array::Convert);
        
    case Array::Contiguous:
        if (doesConversion() && (flags & NodeUsedAsIntLocally))
            return withConversion(Array::RageConvert);
        return *this;
        
    case Array::SelectUsingPredictions:
        if (isStringSpeculation(base))
            return ArrayMode(Array::String);
        
        if (isArgumentsSpeculation(base))
            return ArrayMode(Array::Arguments);
        
        if (isInt8ArraySpeculation(base))
            return ArrayMode(Array::Int8Array);
        
        if (isInt16ArraySpeculation(base))
            return ArrayMode(Array::Int16Array);
        
        if (isInt32ArraySpeculation(base))
            return ArrayMode(Array::Int32Array);
        
        if (isUint8ArraySpeculation(base))
            return ArrayMode(Array::Uint8Array);
        
        if (isUint8ClampedArraySpeculation(base))
            return ArrayMode(Array::Uint8ClampedArray);
        
        if (isUint16ArraySpeculation(base))
            return ArrayMode(Array::Uint16Array);
        
        if (isUint32ArraySpeculation(base))
            return ArrayMode(Array::Uint32Array);
        
        if (isFloat32ArraySpeculation(base))
            return ArrayMode(Array::Float32Array);
        
        if (isFloat64ArraySpeculation(base))
            return ArrayMode(Array::Float64Array);

        return ArrayMode(Array::Generic);

    default:
        return *this;
    }
}