Changeset 137683 in webkit


Ignore:
Timestamp:
Dec 13, 2012 4:32:55 PM (11 years ago)
Author:
oliver@apple.com
Message:

Support op_typeof in the DFG
https://bugs.webkit.org/show_bug.cgi?id=98898

Reviewed by Filip Pizlo.

Adds a TypeOf node to the DFG to support op_typeof.

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::execute):

We try to determine the result early here, and substitute in a constant.
Otherwise we leave the node intact, and set the result type to SpecString.

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

Parse op_typeof

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::CSEPhase::performNodeCSE):

TypeOf nodes can be subjected to pure CSE

  • dfg/DFGCapabilities.h:

(JSC::DFG::canCompileOpcode):

We can handle typeof.

  • dfg/DFGNodeType.h:

(DFG):

Define the node.

  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h: Add operationTypeOf to support the non-trivial cases.
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

Actual codegen

  • runtime/Operations.cpp:

(JSC::jsTypeStringForValue):
(JSC):

  • runtime/Operations.h:

(JSC):

Some refactoring to allow us to get the type string for an
object without needing a callframe.

Location:
trunk/Source/JavaScriptCore
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r137505 r137683  
     12012-13-11  Oliver Hunt  <oliver@apple.com>
     2
     3        Support op_typeof in the DFG
     4        https://bugs.webkit.org/show_bug.cgi?id=98898
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Adds a TypeOf node to the DFG to support op_typeof.
     9
     10        * dfg/DFGAbstractState.cpp:
     11        (JSC::DFG::AbstractState::execute):
     12          We try to determine the result early here, and substitute in a constant.
     13          Otherwise we leave the node intact, and set the result type to SpecString.
     14        * dfg/DFGByteCodeParser.cpp:
     15        (JSC::DFG::ByteCodeParser::parseBlock):
     16          Parse op_typeof
     17        * dfg/DFGCSEPhase.cpp:
     18        (JSC::DFG::CSEPhase::performNodeCSE):
     19          TypeOf nodes can be subjected to pure CSE
     20        * dfg/DFGCapabilities.h:
     21        (JSC::DFG::canCompileOpcode):
     22          We can handle typeof.
     23        * dfg/DFGNodeType.h:
     24        (DFG):
     25          Define the node.
     26        * dfg/DFGOperations.cpp:
     27        * dfg/DFGOperations.h:
     28          Add operationTypeOf to support the non-trivial cases.
     29        * dfg/DFGPredictionPropagationPhase.cpp:
     30        (JSC::DFG::PredictionPropagationPhase::propagate):
     31        * dfg/DFGSpeculativeJIT32_64.cpp:
     32        (JSC::DFG::SpeculativeJIT::compile):
     33        * dfg/DFGSpeculativeJIT64.cpp:
     34        (JSC::DFG::SpeculativeJIT::compile):
     35          Actual codegen
     36        * runtime/Operations.cpp:
     37        (JSC::jsTypeStringForValue):
     38        (JSC):
     39        * runtime/Operations.h:
     40        (JSC):
     41          Some refactoring to allow us to get the type string for an
     42          object without needing a callframe.
     43
    1442012-12-12  Filip Pizlo  <fpizlo@apple.com>
    245
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractState.cpp

    r137247 r137683  
    3232#include "DFGBasicBlock.h"
    3333#include "GetByIdStatus.h"
     34#include "Operations.h"
    3435#include "PutByIdStatus.h"
    3536
     
    708709                constantWasSet = trySetConstant(nodeIndex, jsBoolean(isJSString(child)));
    709710                break;
     711            case IsObject:
     712                if (child.isNull() || !child.isObject()) {
     713                    constantWasSet = trySetConstant(nodeIndex, jsBoolean(child.isNull()));
     714                    break;
     715                }
    710716            default:
    711717                constantWasSet = false;
     
    717723            }
    718724        }
     725
    719726        forNode(nodeIndex).set(SpecBoolean);
     727        break;
     728    }
     729
     730    case TypeOf: {
     731        JSGlobalData* globalData = m_codeBlock->globalData();
     732        JSValue child = forNode(node.child1()).value();
     733        AbstractValue& abstractChild = forNode(node.child1());
     734        if (child) {
     735            JSValue typeString = jsTypeStringForValue(*globalData, m_codeBlock->globalObjectFor(node.codeOrigin), child);
     736            if (trySetConstant(nodeIndex, typeString)) {
     737                m_foundConstants = true;
     738                break;
     739            }
     740        } else if (isNumberSpeculation(abstractChild.m_type)) {
     741            if (trySetConstant(nodeIndex, globalData->smallStrings.numberString(globalData))) {
     742                forNode(node.child1()).filter(SpecNumber);
     743                m_foundConstants = true;
     744                break;
     745            }
     746        } else if (isStringSpeculation(abstractChild.m_type)) {
     747            if (trySetConstant(nodeIndex, globalData->smallStrings.stringString(globalData))) {
     748                forNode(node.child1()).filter(SpecString);
     749                m_foundConstants = true;
     750                break;
     751            }
     752        } else if (isFinalObjectSpeculation(abstractChild.m_type) || isArraySpeculation(abstractChild.m_type) || isArgumentsSpeculation(abstractChild.m_type)) {
     753            if (trySetConstant(nodeIndex, globalData->smallStrings.objectString(globalData))) {
     754                forNode(node.child1()).filter(SpecFinalObject | SpecArray | SpecArguments);
     755                m_foundConstants = true;
     756                break;
     757            }
     758        } else if (isFunctionSpeculation(abstractChild.m_type)) {
     759            if (trySetConstant(nodeIndex, globalData->smallStrings.functionString(globalData))) {
     760                forNode(node.child1()).filter(SpecFunction);
     761                m_foundConstants = true;
     762                break;
     763            }
     764        } else if (isBooleanSpeculation(abstractChild.m_type)) {
     765            if (trySetConstant(nodeIndex, globalData->smallStrings.booleanString(globalData))) {
     766                forNode(node.child1()).filter(SpecBoolean);
     767                m_foundConstants = true;
     768                break;
     769            }
     770        } else {
     771            Node& childNode = m_graph[node.child1()];
     772            if (isCellSpeculation(childNode.prediction())) {
     773                if (isStringSpeculation(childNode.prediction()))
     774                    forNode(node.child1()).filter(SpecString);
     775                else
     776                    forNode(node.child1()).filter(SpecCell);
     777                node.setCanExit(true);
     778            }
     779        }
     780        forNode(nodeIndex).set(SpecString);
    720781        break;
    721782    }
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r137379 r137683  
    32563256        }
    32573257
     3258        case op_typeof: {
     3259            set(currentInstruction[1].u.operand,
     3260                addToGraph(TypeOf, get(currentInstruction[2].u.operand)));
     3261            NEXT_OPCODE(op_typeof);
     3262        }
     3263
    32583264        default:
    32593265            // Parse failed! This should not happen because the capabilities checker
  • trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp

    r137247 r137683  
    563563            case AllocatePropertyStorage:
    564564            case ReallocatePropertyStorage:
     565            case TypeOf:
    565566                return NoNode;
    566567               
     
    11281129        case SkipScope:
    11291130        case GetScopeRegisters:
     1131        case TypeOf:
    11301132            setReplacement(pureCSE(node));
    11311133            break;
  • trunk/Source/JavaScriptCore/dfg/DFGCapabilities.h

    r137094 r137683  
    197197    case op_put_to_base_variable:
    198198    case op_put_to_base:
     199    case op_typeof:
    199200        return CanCompile;
    200201       
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r136601 r137683  
    211211    macro(IsObject, NodeResultBoolean) \
    212212    macro(IsFunction, NodeResultBoolean) \
     213    macro(TypeOf, NodeResultJS) \
    213214    macro(LogicalNot, NodeResultBoolean) \
    214215    macro(ToPrimitive, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r137247 r137683  
    13691369{
    13701370    return jsIsFunctionType(JSValue::decode(value));
     1371}
     1372
     1373JSCell* DFG_OPERATION operationTypeOf(ExecState* exec, JSCell* value)
     1374{
     1375    return jsTypeStringForValue(exec, JSValue(value)).asCell();
    13711376}
    13721377
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r137247 r137683  
    199199size_t DFG_OPERATION operationIsObject(ExecState*, EncodedJSValue) WTF_INTERNAL;
    200200size_t DFG_OPERATION operationIsFunction(EncodedJSValue) WTF_INTERNAL;
     201JSCell* DFG_OPERATION operationTypeOf(ExecState*, JSCell*) WTF_INTERNAL;
    201202void DFG_OPERATION operationReallocateStorageAndFinishPut(ExecState*, JSObject*, Structure*, PropertyOffset, EncodedJSValue) WTF_INTERNAL;
    202203char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState*) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r136601 r137683  
    498498            break;
    499499        }
    500            
     500
     501        case TypeOf: {
     502            changed |= setPrediction(SpecString);
     503            changed |= mergeDefaultFlags(node);
     504            break;
     505        }
     506
    501507        case GetById: {
    502508            changed |= mergePrediction(node.getHeapPrediction());
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r136601 r137683  
    45594559        break;
    45604560    }
     4561    case TypeOf: {
     4562        JSValueOperand value(this, node.child1());
     4563        GPRReg tagGPR = value.tagGPR();
     4564        GPRReg payloadGPR = value.payloadGPR();
     4565        GPRTemporary temp(this);
     4566        GPRReg tempGPR = temp.gpr();
     4567        GPRResult result(this);
     4568        GPRReg resultGPR = result.gpr();
     4569        JITCompiler::JumpList doneJumps;
     4570
     4571        flushRegisters();
     4572
     4573        JITCompiler::Jump isNotCell = m_jit.branch32(JITCompiler::NotEqual, tagGPR, JITCompiler::TrustedImm32(JSValue::CellTag));
     4574        Node& child = m_jit.graph()[node.child1()];
     4575        if (child.shouldSpeculateCell())
     4576            speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node.child1(), isNotCell);
     4577
     4578        if (!child.shouldSpeculateNonStringCell()) {
     4579            m_jit.loadPtr(JITCompiler::Address(payloadGPR, JSCell::structureOffset()), tempGPR);
     4580            JITCompiler::Jump notString = m_jit.branch8(JITCompiler::NotEqual, JITCompiler::Address(tempGPR, Structure::typeInfoTypeOffset()), TrustedImm32(StringType));
     4581            if (child.shouldSpeculateString())
     4582                speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node.child1(), notString);
     4583            m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.stringString(m_jit.globalData())), resultGPR);
     4584            doneJumps.append(m_jit.jump());
     4585            if (!child.shouldSpeculateString()) {
     4586                notString.link(&m_jit);
     4587                callOperation(operationTypeOf, resultGPR, payloadGPR);
     4588                doneJumps.append(m_jit.jump());
     4589            }
     4590        } else {
     4591            callOperation(operationTypeOf, resultGPR, payloadGPR);
     4592            doneJumps.append(m_jit.jump());
     4593        }
     4594
     4595        if (!child.shouldSpeculateCell()) {
     4596            isNotCell.link(&m_jit);
     4597
     4598            m_jit.add32(TrustedImm32(1), tagGPR, tempGPR);
     4599            JITCompiler::Jump notNumber = m_jit.branch32(JITCompiler::AboveOrEqual, tempGPR, JITCompiler::TrustedImm32(JSValue::LowestTag + 1));
     4600            m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.numberString(m_jit.globalData())), resultGPR);
     4601            doneJumps.append(m_jit.jump());
     4602            notNumber.link(&m_jit);
     4603
     4604            JITCompiler::Jump notUndefined = m_jit.branch32(JITCompiler::NotEqual, tagGPR, TrustedImm32(JSValue::UndefinedTag));
     4605            m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.undefinedString(m_jit.globalData())), resultGPR);
     4606            doneJumps.append(m_jit.jump());
     4607            notUndefined.link(&m_jit);
     4608
     4609            JITCompiler::Jump notNull = m_jit.branch32(JITCompiler::NotEqual, tagGPR, TrustedImm32(JSValue::NullTag));
     4610            m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.objectString(m_jit.globalData())), resultGPR);
     4611            doneJumps.append(m_jit.jump());
     4612            notNull.link(&m_jit);
     4613
     4614            // Only boolean left
     4615            m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.booleanString(m_jit.globalData())), resultGPR);
     4616        }
     4617        doneJumps.link(&m_jit);
     4618        cellResult(resultGPR, m_compileIndex);
     4619        break;
     4620    }
    45614621
    45624622    case Phi:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r136601 r137683  
    40704070       
    40714071        jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
    4072        
     4072
    40734073        break;
    40744074    }
     
    44824482        m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
    44834483        jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
     4484        break;
     4485    }
     4486
     4487    case TypeOf: {
     4488        JSValueOperand value(this, node.child1());
     4489        GPRReg valueGPR = value.gpr();
     4490        GPRTemporary temp(this);
     4491        GPRReg tempGPR = temp.gpr();
     4492        GPRResult result(this);
     4493        GPRReg resultGPR = result.gpr();
     4494        JITCompiler::JumpList doneJumps;
     4495
     4496        flushRegisters();
     4497
     4498        JITCompiler::Jump isNotCell = m_jit.branchTest64(JITCompiler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
     4499        Node& child = m_jit.graph()[node.child1()];
     4500        if (child.shouldSpeculateCell())
     4501            speculationCheck(BadType, JSValueSource(valueGPR), node.child1(), isNotCell);
     4502
     4503        if (!child.shouldSpeculateNonStringCell()) {
     4504            m_jit.loadPtr(JITCompiler::Address(valueGPR, JSCell::structureOffset()), tempGPR);
     4505            JITCompiler::Jump notString = m_jit.branch8(JITCompiler::NotEqual, JITCompiler::Address(tempGPR, Structure::typeInfoTypeOffset()), TrustedImm32(StringType));
     4506            if (child.shouldSpeculateString())
     4507                speculationCheck(BadType, JSValueSource(valueGPR), node.child1(), notString);
     4508            m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.stringString(m_jit.globalData())), resultGPR);
     4509            doneJumps.append(m_jit.jump());
     4510            if (!child.shouldSpeculateString()) {
     4511                notString.link(&m_jit);
     4512                callOperation(operationTypeOf, resultGPR, valueGPR);
     4513                doneJumps.append(m_jit.jump());
     4514            }
     4515        } else {
     4516            callOperation(operationTypeOf, resultGPR, valueGPR);
     4517            doneJumps.append(m_jit.jump());
     4518        }
     4519
     4520        if (!child.shouldSpeculateCell()) {
     4521            isNotCell.link(&m_jit);
     4522            JITCompiler::Jump notNumber = m_jit.branchTest64(JITCompiler::Zero, valueGPR, GPRInfo::tagTypeNumberRegister);
     4523            m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.numberString(m_jit.globalData())), resultGPR);
     4524            doneJumps.append(m_jit.jump());
     4525            notNumber.link(&m_jit);
     4526
     4527            JITCompiler::Jump notUndefined = m_jit.branch64(JITCompiler::NotEqual, valueGPR, JITCompiler::TrustedImm64(ValueUndefined));
     4528            m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.undefinedString(m_jit.globalData())), resultGPR);
     4529            doneJumps.append(m_jit.jump());
     4530            notUndefined.link(&m_jit);
     4531
     4532            JITCompiler::Jump notNull = m_jit.branch64(JITCompiler::NotEqual, valueGPR, JITCompiler::TrustedImm64(ValueNull));
     4533            m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.objectString(m_jit.globalData())), resultGPR);
     4534            doneJumps.append(m_jit.jump());
     4535            notNull.link(&m_jit);
     4536
     4537            // Only boolean left
     4538            m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.booleanString(m_jit.globalData())), resultGPR);
     4539        }
     4540        doneJumps.link(&m_jit);
     4541        cellResult(resultGPR, m_compileIndex);
    44844542        break;
    44854543    }
  • trunk/Source/JavaScriptCore/runtime/Operations.cpp

    r126494 r137683  
    5757}
    5858
    59 JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v)
     59JSValue jsTypeStringForValue(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue v)
    6060{
    61     JSGlobalData& globalData = callFrame->globalData();
    6261    if (v.isUndefined())
    6362        return globalData.smallStrings.undefinedString(&globalData);
     
    7170        // Return "undefined" for objects that should be treated
    7271        // as null when doing comparisons.
    73         if (asObject(v)->structure()->masqueradesAsUndefined(callFrame->lexicalGlobalObject()))
     72        if (asObject(v)->structure()->masqueradesAsUndefined(globalObject))
    7473            return globalData.smallStrings.undefinedString(&globalData);
    7574        CallData callData;
     
    7978    }
    8079    return globalData.smallStrings.objectString(&globalData);
     80}
     81
     82JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v)
     83{
     84    return jsTypeStringForValue(callFrame->globalData(), callFrame->lexicalGlobalObject(), v);
    8185}
    8286
  • trunk/Source/JavaScriptCore/runtime/Operations.h

    r135454 r137683  
    3333    NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue);
    3434    JSValue jsTypeStringForValue(CallFrame*, JSValue);
     35    JSValue jsTypeStringForValue(JSGlobalData&, JSGlobalObject*, JSValue);
    3536    bool jsIsObjectType(CallFrame*, JSValue);
    3637    bool jsIsFunctionType(JSValue);
Note: See TracChangeset for help on using the changeset viewer.