Title: [199279] trunk/Source/_javascript_Core
Revision
199279
Author
[email protected]
Date
2016-04-09 20:38:44 -0700 (Sat, 09 Apr 2016)

Log Message

tryGetById should be supported by the DFG/FTL
https://bugs.webkit.org/show_bug.cgi?id=156378

Reviewed by Filip Pizlo.

This patch adds support for tryGetById in the DFG/FTL. It adds a new DFG node
TryGetById, which acts similarly to the normal GetById DFG node. One key
difference between GetById and TryGetById is that in the LLInt and Baseline
we do not profile the result type. This profiling is unnessary for the current
use case of tryGetById, which is expected to be a strict equality comparision
against a specific object or undefined. In either case other DFG optimizations
will make this equally fast with or without the profiling information.

Additionally, this patch adds new reuse modes for JSValueRegsTemporary that take
an operand and attempt to reuse the registers for that operand if they are free
after the current DFG node.

* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeFromLLInt):
(JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasIdentifier):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileTryGetById):
(JSC::DFG::JSValueRegsTemporary::JSValueRegsTemporary):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::GPRTemporary::operator=):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileGetById):
(JSC::FTL::DFG::LowerDFGToB3::getById):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* tests/stress/try-get-by-id.js:
(tryGetByIdTextStrict):
(get let):
(let.get createBuiltin):
(get throw):
(getCaller.obj.1.throw.new.Error): Deleted.

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (199278 => 199279)


--- trunk/Source/_javascript_Core/ChangeLog	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-04-10 03:38:44 UTC (rev 199279)
@@ -1,3 +1,71 @@
+2016-04-09  Keith Miller  <[email protected]>
+
+        tryGetById should be supported by the DFG/FTL
+        https://bugs.webkit.org/show_bug.cgi?id=156378
+
+        Reviewed by Filip Pizlo.
+
+        This patch adds support for tryGetById in the DFG/FTL. It adds a new DFG node
+        TryGetById, which acts similarly to the normal GetById DFG node. One key
+        difference between GetById and TryGetById is that in the LLInt and Baseline
+        we do not profile the result type. This profiling is unnessary for the current
+        use case of tryGetById, which is expected to be a strict equality comparision
+        against a specific object or undefined. In either case other DFG optimizations
+        will make this equally fast with or without the profiling information.
+
+        Additionally, this patch adds new reuse modes for JSValueRegsTemporary that take
+        an operand and attempt to reuse the registers for that operand if they are free
+        after the current DFG node.
+
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeFromLLInt):
+        (JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasIdentifier):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileTryGetById):
+        (JSC::DFG::JSValueRegsTemporary::JSValueRegsTemporary):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::GPRTemporary::operator=):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::cachedGetById):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::cachedGetById):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetById):
+        (JSC::FTL::DFG::LowerDFGToB3::getById):
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * tests/stress/try-get-by-id.js:
+        (tryGetByIdTextStrict):
+        (get let):
+        (let.get createBuiltin):
+        (get throw):
+        (getCaller.obj.1.throw.new.Error): Deleted.
+
 2016-04-09  Saam barati  <[email protected]>
 
         Allocation sinking SSA Defs are allowed to have replacements

Modified: trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp (199278 => 199279)


--- trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp	2016-04-10 03:38:44 UTC (rev 199279)
@@ -75,7 +75,7 @@
     
     Instruction* instruction = profiledBlock->instructions().begin() + bytecodeIndex;
     
-    if (instruction[0].u.opcode == LLInt::getOpcode(op_get_array_length))
+    if (instruction[0].u.opcode == LLInt::getOpcode(op_get_array_length) || instruction[0].u.opcode == LLInt::getOpcode(op_try_get_by_id))
         return GetByIdStatus(NoInformation, false);
 
     StructureID structureID = instruction[4].u.structureID;
@@ -210,7 +210,8 @@
                 JSFunction* intrinsicFunction = nullptr;
 
                 switch (access.type()) {
-                case AccessCase::Load: {
+                case AccessCase::Load:
+                case AccessCase::GetGetter: {
                     break;
                 }
                 case AccessCase::IntrinsicGetter: {

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2016-04-10 03:38:44 UTC (rev 199279)
@@ -1972,7 +1972,13 @@
         
     case PutToArguments:
         break;
-            
+
+    case TryGetById:
+        // FIXME: This should constant fold at least as well as the normal GetById case.
+        // https://bugs.webkit.org/show_bug.cgi?id=156422
+        forNode(node).makeHeapTop();
+        break;
+
     case GetById:
     case GetByIdFlush: {
         if (!node->prediction()) {

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-04-10 03:38:44 UTC (rev 199279)
@@ -231,9 +231,10 @@
     Node* load(SpeculatedType, Node* base, unsigned identifierNumber, const VariantType&);
 
     Node* store(Node* base, unsigned identifier, const PutByIdVariant&, Node* value);
-        
+
+    void handleTryGetById(int destinationOperand, Node* base, unsigned identifierNumber, const GetByIdStatus&);
     void handleGetById(
-        int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber, GetByIdStatus);
+        int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber, GetByIdStatus, AccessType);
     void emitPutById(
         Node* base, unsigned identifierNumber, Node* value,  const PutByIdStatus&, bool isDirect);
     void handlePutById(
@@ -2887,7 +2888,7 @@
 
 void ByteCodeParser::handleGetById(
     int destinationOperand, SpeculatedType prediction, Node* base, unsigned identifierNumber,
-    GetByIdStatus getByIdStatus)
+    GetByIdStatus getByIdStatus, AccessType type)
 {
     // Attempt to reduce the set of things in the GetByIdStatus.
     if (base->op() == NewObject) {
@@ -2905,8 +2906,13 @@
             getByIdStatus.filter(base->structure());
     }
     
-    NodeType getById = getByIdStatus.makesCalls() ? GetByIdFlush : GetById;
-    
+    NodeType getById;
+    if (type == AccessType::Get)
+        getById = getByIdStatus.makesCalls() ? GetByIdFlush : GetById;
+    else
+        getById = TryGetById;
+
+    ASSERT(type == AccessType::Get || !getByIdStatus.makesCalls());
     if (!getByIdStatus.isSimple() || !getByIdStatus.numVariants() || !Options::useAccessInlining()) {
         set(VirtualRegister(destinationOperand),
             addToGraph(getById, OpInfo(identifierNumber), OpInfo(prediction), base));
@@ -2976,6 +2982,7 @@
     if (m_graph.compilation())
         m_graph.compilation()->noticeInlinedGetById();
 
+    ASSERT(type == AccessType::Get || !variant.callLinkStatus());
     if (!variant.callLinkStatus() && variant.intrinsic() == NoIntrinsic) {
         set(VirtualRegister(destinationOperand), loadedValue);
         return;
@@ -2991,8 +2998,7 @@
         return;
     }
 
-    if (variant.intrinsic() != NoIntrinsic)
-        ASSERT(variant.intrinsic() == NoIntrinsic);
+    ASSERT(variant.intrinsic() == NoIntrinsic);
 
     // Make a call. We don't try to get fancy with using the smallest operand number because
     // the stack layout phase should compress the stack anyway.
@@ -3793,7 +3799,7 @@
                         locker, m_inlineStackTop->m_profiledBlock,
                         byValInfo->stubInfo, currentCodeOrigin(), uid);
 
-                    handleGetById(currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus);
+                    handleGetById(currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus, AccessType::Get);
                 }
             }
 
@@ -3847,7 +3853,22 @@
 
             NEXT_OPCODE(op_put_by_val);
         }
-            
+
+        case op_try_get_by_id: {
+            Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
+            unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
+            UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber];
+
+            GetByIdStatus getByIdStatus = GetByIdStatus::computeFor(
+                m_inlineStackTop->m_profiledBlock, m_dfgCodeBlock,
+                m_inlineStackTop->m_stubInfos, m_dfgStubInfos,
+                currentCodeOrigin(), uid);
+
+            handleGetById(currentInstruction[1].u.operand, SpecHeapTop, base, identifierNumber, getByIdStatus, AccessType::GetPure);
+
+            NEXT_OPCODE(op_try_get_by_id);
+        }
+
         case op_get_by_id:
         case op_get_array_length: {
             SpeculatedType prediction = getPrediction();
@@ -3862,7 +3883,7 @@
                 currentCodeOrigin(), uid);
             
             handleGetById(
-                currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus);
+                currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus, AccessType::Get);
 
             NEXT_OPCODE(op_get_by_id);
         }

Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2016-04-10 03:38:44 UTC (rev 199279)
@@ -152,6 +152,7 @@
     case op_get_by_val:
     case op_put_by_val:
     case op_put_by_val_direct:
+    case op_try_get_by_id:
     case op_get_by_id:
     case op_get_array_length:
     case op_put_by_id:

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2016-04-10 03:38:44 UTC (rev 199279)
@@ -848,7 +848,12 @@
         def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node));
         return;
     }
-        
+
+    case TryGetById: {
+        read(Heap);
+        return;
+    }
+
     case MultiGetByOffset: {
         read(JSCell_structureID);
         read(JSObject_butterfly);

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2016-04-10 03:38:44 UTC (rev 199279)
@@ -96,6 +96,7 @@
     case ArithCos:
     case ArithLog:
     case ValueAdd:
+    case TryGetById:
     case GetById:
     case GetByIdFlush:
     case PutById:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2016-04-10 03:38:44 UTC (rev 199279)
@@ -1069,6 +1069,12 @@
             break;
         }
 
+        case TryGetById: {
+            if (node->child1()->shouldSpeculateCell())
+                fixEdge<CellUse>(node->child1());
+            break;
+        }
+
         case GetById:
         case GetByIdFlush: {
             // FIXME: This should be done in the ByteCodeParser based on reading the

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-04-10 03:38:44 UTC (rev 199279)
@@ -866,6 +866,7 @@
     bool hasIdentifier()
     {
         switch (op()) {
+        case TryGetById:
         case GetById:
         case GetByIdFlush:
         case PutById:

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2016-04-10 03:38:44 UTC (rev 199279)
@@ -182,6 +182,7 @@
     macro(PutByValDirect, NodeMustGenerate | NodeHasVarArgs) \
     macro(PutByVal, NodeMustGenerate | NodeHasVarArgs) \
     macro(PutByValAlias, NodeMustGenerate | NodeHasVarArgs) \
+    macro(TryGetById, NodeResultJS) \
     macro(GetById, NodeResultJS | NodeMustGenerate) \
     macro(GetByIdFlush, NodeResultJS | NodeMustGenerate) \
     macro(PutById, NodeMustGenerate) \

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2016-04-10 03:38:44 UTC (rev 199279)
@@ -172,7 +172,12 @@
             changed |= setPrediction(SpecInt32);
             break;
         }
-            
+
+        case TryGetById: {
+            changed |= setPrediction(SpecBytecodeTop);
+            break;
+        }
+
         case ArrayPop:
         case ArrayPush:
         case RegExpExec:

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2016-04-10 03:38:44 UTC (rev 199279)
@@ -191,6 +191,7 @@
     case ArithCos:
     case ArithLog:
     case ValueAdd:
+    case TryGetById:
     case GetById:
     case GetByIdFlush:
     case PutById:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2016-04-10 03:38:44 UTC (rev 199279)
@@ -964,6 +964,47 @@
     }
 }
 
+void SpeculativeJIT::compileTryGetById(Node* node)
+{
+    switch (node->child1().useKind()) {
+    case CellUse: {
+        SpeculateCellOperand base(this, node->child1());
+        JSValueRegsTemporary result(this, Reuse, base);
+
+        JSValueRegs baseRegs = JSValueRegs::payloadOnly(base.gpr());
+        JSValueRegs resultRegs = result.regs();
+
+        base.use();
+
+        cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), DontSpill, AccessType::GetPure);
+
+        jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
+        break;
+    }
+
+    case UntypedUse: {
+        JSValueOperand base(this, node->child1());
+        JSValueRegsTemporary result(this, Reuse, base);
+
+        JSValueRegs baseRegs = base.jsValueRegs();
+        JSValueRegs resultRegs = result.regs();
+
+        base.use();
+
+        JITCompiler::Jump notCell = m_jit.branchIfNotCell(baseRegs);
+
+        cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, DontSpill, AccessType::GetPure);
+
+        jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
+        break;
+    }
+
+    default:
+        DFG_CRASH(m_jit.graph(), node, "Bad use kind");
+        break;
+    } 
+}
+
 void SpeculativeJIT::compileIn(Node* node)
 {
     SpeculateCellOperand base(this, node->child2());
@@ -1168,6 +1209,44 @@
 {
 }
 
+#if USE(JSVALUE64)
+template<typename T>
+JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, T& operand, WhichValueWord)
+    : m_gpr(jit, Reuse, operand)
+{
+}
+#else
+template<typename T>
+JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, T& operand, WhichValueWord resultWord)
+{
+    if (resultWord == PayloadWord) {
+        m_payloadGPR = GPRTemporary(jit, Reuse, operand);
+        m_tagGPR = GPRTemporary(jit);
+    } else {
+        m_payloadGPR = GPRTemporary(jit);
+        m_tagGPR = GPRTemporary(jit, Reuse, operand);
+    }
+}
+#endif
+
+#if USE(JSVALUE64)
+JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, JSValueOperand& operand)
+{
+    m_gpr = GPRTemporary(jit, Reuse, operand);
+}
+#else
+JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit, ReuseTag, JSValueOperand& operand)
+{
+    if (jit->canReuse(operand.node())) {
+        m_payloadGPR = GPRTemporary(jit, Reuse, operand, PayloadWord);
+        m_tagGPR = GPRTemporary(jit, Reuse, operand, TagWord);
+    } else {
+        m_payloadGPR = GPRTemporary(jit);
+        m_tagGPR = GPRTemporary(jit);
+    }
+}
+#endif
+
 JSValueRegsTemporary::~JSValueRegsTemporary() { }
 
 JSValueRegs JSValueRegsTemporary::regs()

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2016-04-10 03:38:44 UTC (rev 199279)
@@ -703,14 +703,17 @@
     void compileMovHint(Node*);
     void compileMovHintAndCheck(Node*);
 
+    void cachedGetById(CodeOrigin, JSValueRegs base, JSValueRegs result, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill, AccessType = AccessType::Get);
+
 #if USE(JSVALUE64)
-    void cachedGetById(CodeOrigin, GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
+    void cachedGetById(CodeOrigin, GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill, AccessType = AccessType::Get);
     void cachedPutById(CodeOrigin, GPRReg base, GPRReg value, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
 #elif USE(JSVALUE32_64)
-    void cachedGetById(CodeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
+    void cachedGetById(CodeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill, AccessType = AccessType::Get);
     void cachedPutById(CodeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
 #endif
-    
+
+    void compileTryGetById(Node*);
     void compileIn(Node*);
     
     void compileBaseValueStoreBarrier(Edge& baseEdge, Edge& valueEdge);
@@ -2940,6 +2943,17 @@
     GPRTemporary(SpeculativeJIT*, ReuseTag, JSValueOperand&, WhichValueWord);
 #endif
 
+    GPRTemporary(GPRTemporary& other) = delete;
+
+    GPRTemporary& operator=(GPRTemporary&& other)
+    {
+        ASSERT(!m_jit);
+        ASSERT(m_gpr == InvalidGPRReg);
+        std::swap(m_jit, other.m_jit);
+        std::swap(m_gpr, other.m_gpr);
+        return *this;
+    }
+
     void adopt(GPRTemporary&);
 
     ~GPRTemporary()
@@ -2962,6 +2976,9 @@
 public:
     JSValueRegsTemporary();
     JSValueRegsTemporary(SpeculativeJIT*);
+    template<typename T>
+    JSValueRegsTemporary(SpeculativeJIT*, ReuseTag, T& operand, WhichValueWord resultRegWord = PayloadWord);
+    JSValueRegsTemporary(SpeculativeJIT*, ReuseTag, JSValueOperand&);
     ~JSValueRegsTemporary();
     
     JSValueRegs regs();

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2016-04-10 03:38:44 UTC (rev 199279)
@@ -165,9 +165,14 @@
     }
 }
 
+void SpeculativeJIT::cachedGetById(CodeOrigin origin, JSValueRegs base, JSValueRegs result, unsigned identifierNumber, JITCompiler::Jump slowPathTarget , SpillRegistersMode mode, AccessType type)
+{
+    cachedGetById(origin, base.tagGPR(), base.payloadGPR(), result.tagGPR(), result.payloadGPR(), identifierNumber, slowPathTarget, mode, type);
+}
+
 void SpeculativeJIT::cachedGetById(
     CodeOrigin codeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR,
-    unsigned identifierNumber, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
+    unsigned identifierNumber, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode, AccessType type)
 {
     // This is a hacky fix for when the register allocator decides to alias the base payload with the result tag. This only happens
     // in the case of GetByIdFlush, which has a relatively expensive register allocation story already so we probably don't need to
@@ -194,7 +199,7 @@
     JITGetByIdGenerator gen(
         m_jit.codeBlock(), codeOrigin, callSite, usedRegisters,
         JSValueRegs(baseTagGPROrNone, basePayloadGPR),
-        JSValueRegs(resultTagGPR, resultPayloadGPR), AccessType::Get);
+        JSValueRegs(resultTagGPR, resultPayloadGPR), type);
     
     gen.generateFastPath(m_jit);
     
@@ -203,16 +208,22 @@
         slowCases.append(slowPathTarget);
     slowCases.append(gen.slowPathJump());
 
+    J_JITOperation_ESsiJI getByIdFunction;
+    if (type == AccessType::Get)
+        getByIdFunction = operationGetByIdOptimize;
+    else
+        getByIdFunction = operationTryGetByIdOptimize;
+
     std::unique_ptr<SlowPathGenerator> slowPath;
     if (baseTagGPROrNone == InvalidGPRReg) {
         slowPath = slowPathCall(
-            slowCases, this, operationGetByIdOptimize,
+            slowCases, this, getByIdFunction,
             JSValueRegs(resultTagGPR, resultPayloadGPR), gen.stubInfo(),
             static_cast<int32_t>(JSValue::CellTag), basePayloadGPR,
             identifierUID(identifierNumber));
     } else {
         slowPath = slowPathCall(
-            slowCases, this, operationGetByIdOptimize,
+            slowCases, this, getByIdFunction,
             JSValueRegs(resultTagGPR, resultPayloadGPR), gen.stubInfo(), baseTagGPROrNone,
             basePayloadGPR, identifierUID(identifierNumber));
     }
@@ -3961,7 +3972,12 @@
         noResult(node);
         break;
     }
-        
+
+    case TryGetById: {
+        compileTryGetById(node);
+        break;
+    }
+
     case GetById: {
         ASSERT(node->prediction());
         

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (199278 => 199279)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2016-04-10 03:38:44 UTC (rev 199279)
@@ -153,8 +153,13 @@
     }
 }
 
-void SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
+void SpeculativeJIT::cachedGetById(CodeOrigin origin, JSValueRegs base, JSValueRegs result, unsigned identifierNumber, JITCompiler::Jump slowPathTarget , SpillRegistersMode mode, AccessType type)
 {
+    cachedGetById(origin, base.gpr(), result.gpr(), identifierNumber, slowPathTarget, mode, type);
+}
+
+void SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode, AccessType type)
+{
     CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size());
     RegisterSet usedRegisters = this->usedRegisters();
     if (spillMode == DontSpill) {
@@ -164,7 +169,7 @@
     }
     JITGetByIdGenerator gen(
         m_jit.codeBlock(), codeOrigin, callSite, usedRegisters, JSValueRegs(baseGPR),
-        JSValueRegs(resultGPR), AccessType::Get);
+        JSValueRegs(resultGPR), type);
     gen.generateFastPath(m_jit);
     
     JITCompiler::JumpList slowCases;
@@ -173,7 +178,7 @@
     slowCases.append(gen.slowPathJump());
     
     auto slowPath = slowPathCall(
-        slowCases, this, operationGetByIdOptimize, resultGPR, gen.stubInfo(), baseGPR,
+        slowCases, this, type == AccessType::Get ? operationGetByIdOptimize : operationTryGetByIdOptimize, resultGPR, gen.stubInfo(), baseGPR,
         identifierUID(identifierNumber), spillMode);
     
     m_jit.addGetById(gen, slowPath.get());
@@ -4019,6 +4024,12 @@
         noResult(node);
         break;
     }
+
+    case TryGetById: {
+        compileTryGetById(node);
+        break;
+    }
+
     case GetById: {
         ASSERT(node->prediction());
 

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (199278 => 199279)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2016-04-10 03:38:44 UTC (rev 199279)
@@ -166,6 +166,7 @@
     case CallStringConstructor:
     case MakeRope:
     case NewArrayWithSize:
+    case TryGetById:
     case GetById:
     case GetByIdFlush:
     case ToThis:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (199278 => 199279)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-04-10 03:38:44 UTC (rev 199279)
@@ -593,9 +593,12 @@
         case PutStructure:
             compilePutStructure();
             break;
+        case TryGetById:
+            compileGetById(AccessType::GetPure);
+            break;
         case GetById:
         case GetByIdFlush:
-            compileGetById();
+            compileGetById(AccessType::Get);
             break;
         case In:
             compileIn();
@@ -2302,11 +2305,12 @@
             cell, m_heaps.JSCell_structureID);
     }
     
-    void compileGetById()
+    void compileGetById(AccessType type)
     {
+        ASSERT(type == AccessType::Get || type == AccessType::GetPure);
         switch (m_node->child1().useKind()) {
         case CellUse: {
-            setJSValue(getById(lowCell(m_node->child1())));
+            setJSValue(getById(lowCell(m_node->child1()), type));
             return;
         }
             
@@ -2324,12 +2328,18 @@
                 isCell(value, provenType(m_node->child1())), unsure(cellCase), unsure(notCellCase));
             
             LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase);
-            ValueFromBlock cellResult = m_out.anchor(getById(value));
+            ValueFromBlock cellResult = m_out.anchor(getById(value, type));
             m_out.jump(continuation);
-            
+
+            J_JITOperation_EJI getByIdFunction;
+            if (type == AccessType::Get)
+                getByIdFunction = operationGetByIdGeneric;
+            else
+                getByIdFunction = operationTryGetByIdGeneric;
+
             m_out.appendTo(notCellCase, continuation);
             ValueFromBlock notCellResult = m_out.anchor(vmCall(
-                m_out.int64, m_out.operation(operationGetByIdGeneric),
+                m_out.int64, m_out.operation(getByIdFunction),
                 m_callFrame, value,
                 m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()])));
             m_out.jump(continuation);
@@ -7293,7 +7303,7 @@
         return m_out.phi(m_out.intPtr, fastButterfly, slowButterfly);
     }
     
-    LValue getById(LValue base)
+    LValue getById(LValue base, AccessType type)
     {
         Node* node = m_node;
         UniquedStringImpl* uid = m_graph.identifiers()[node->identifierNumber()];
@@ -7331,7 +7341,7 @@
                 auto generator = Box<JITGetByIdGenerator>::create(
                     jit.codeBlock(), node->origin.semantic, callSiteIndex,
                     params.unavailableRegisters(), JSValueRegs(params[1].gpr()),
-                    JSValueRegs(params[0].gpr()), AccessType::Get);
+                    JSValueRegs(params[0].gpr()), type);
 
                 generator->generateFastPath(jit);
                 CCallHelpers::Label done = jit.label();
@@ -7340,11 +7350,17 @@
                     [=] (CCallHelpers& jit) {
                         AllowMacroScratchRegisterUsage allowScratch(jit);
 
+                        J_JITOperation_ESsiJI optimizationFunction;
+                        if (type == AccessType::Get)
+                            optimizationFunction = operationGetByIdOptimize;
+                        else
+                            optimizationFunction = operationTryGetByIdOptimize;
+
                         generator->slowPathJump().link(&jit);
                         CCallHelpers::Label slowPathBegin = jit.label();
                         CCallHelpers::Call slowPathCall = callOperation(
                             *state, params.unavailableRegisters(), jit, node->origin.semantic,
-                            exceptions.get(), operationGetByIdOptimize, params[0].gpr(),
+                            exceptions.get(), optimizationFunction, params[0].gpr(),
                             CCallHelpers::TrustedImmPtr(generator->stubInfo()), params[1].gpr(),
                             CCallHelpers::TrustedImmPtr(uid)).call();
                         jit.jump().linkTo(done, &jit);

Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (199278 => 199279)


--- trunk/Source/_javascript_Core/jit/JITOperations.cpp	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp	2016-04-10 03:38:44 UTC (rev 199279)
@@ -170,6 +170,20 @@
     return JSValue::encode(slot.getPureResult());
 }
 
+
+EncodedJSValue JIT_OPERATION operationTryGetByIdGeneric(ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid)
+{
+    VM* vm = &exec->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+    Identifier ident = Identifier::fromUid(vm, uid);
+
+    JSValue baseValue = JSValue::decode(base);
+    PropertySlot slot(baseValue, PropertySlot::InternalMethodType::VMInquiry);
+    baseValue.getPropertySlot(exec, ident, slot);
+
+    return JSValue::encode(slot.getPureResult());
+}
+
 EncodedJSValue JIT_OPERATION operationTryGetByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
 {
     VM* vm = &exec->vm();

Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (199278 => 199279)


--- trunk/Source/_javascript_Core/jit/JITOperations.h	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h	2016-04-10 03:38:44 UTC (rev 199279)
@@ -288,6 +288,7 @@
 int32_t JIT_OPERATION operationCallArityCheck(ExecState*) WTF_INTERNAL;
 int32_t JIT_OPERATION operationConstructArityCheck(ExecState*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationTryGetById(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationTryGetByIdGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationTryGetByIdOptimize(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetById(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByIdGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/tests/stress/try-get-by-id.js (199278 => 199279)


--- trunk/Source/_javascript_Core/tests/stress/try-get-by-id.js	2016-04-10 01:46:27 UTC (rev 199278)
+++ trunk/Source/_javascript_Core/tests/stress/try-get-by-id.js	2016-04-10 03:38:44 UTC (rev 199279)
@@ -1,27 +1,38 @@
 function tryGetByIdText(propertyName) { return `(function (base) { return @tryGetById(base, '${propertyName}'); })`; }
 
+function tryGetByIdTextStrict(propertyName) { return `(function (base) { "use strict"; return @tryGetById(base, '${propertyName}'); })`; }
 
 // Test get value off object.
 {
-    let getCaller = createBuiltin(tryGetByIdText("caller"));
-    noInline(getCaller);
+    let get = createBuiltin(tryGetByIdText("caller"));
+    noInline(get);
+    let getStrict = createBuiltin(tryGetByIdTextStrict("caller"));
+    noInline(getStrict);
+
     let obj = {caller: 1};
 
     for (let i = 0; i < 100000; i++) {
-        if (getCaller(obj) !== 1)
+        if (get(obj) !== 1)
             throw new Error("wrong on iteration: " + i);
+        if (getStrict(obj) !== 1)
+            throw new Error("wrong on iteration: " + i);
     }
 }
 
 // Test slot is custom function trap for a value.
 {
-    let getCaller = createBuiltin(tryGetByIdText("caller"));
-    noInline(getCaller);
+    let get = createBuiltin(tryGetByIdText("caller"));
+    noInline(get);
+    let getStrict = createBuiltin(tryGetByIdTextStrict("caller"));
+    noInline(getStrict);
+
     let func = function () {};
 
     for (let i = 0; i < 100000; i++) {
-        if (getCaller(func) !== null)
+        if (get(func) !== null)
             throw new Error("wrong on iteration: " + i);
+        if (getStrict(func) !== null)
+            throw new Error("wrong on iteration: " + i);
     }
 }
 
@@ -29,12 +40,17 @@
 {
     let get = createBuiltin(tryGetByIdText("getterSetter"));
     noInline(get);
+    let getStrict = createBuiltin(tryGetByIdTextStrict("getterSetter"));
+    noInline(getStrict);
+
     let obj = {};
     Object.defineProperty(obj, "getterSetter", { get: function () { throw new Error("should not be called"); } });
 
     for (let i = 0; i < 100000; i++) {
         if (get(obj) !== getGetterSetter(obj, "getterSetter"))
             throw new Error("wrong on iteration: " + i);
+        if (getStrict(obj) !== getGetterSetter(obj, "getterSetter"))
+            throw new Error("wrong on iteration: " + i);
     }
 }
 
@@ -42,11 +58,16 @@
 {
     let get = createBuiltin(tryGetByIdText("getterSetter"));
     noInline(get);
+    let getStrict = createBuiltin(tryGetByIdTextStrict("getterSetter"));
+    noInline(getStrict);
+
     let obj = {};
 
     for (let i = 0; i < 100000; i++) {
         if (get(obj) !== undefined)
             throw new Error("wrong on iteration: " + i);
+        if (getStrict(obj) !== undefined)
+            throw new Error("wrong on iteration: " + i);
     }
 }
 
@@ -54,6 +75,8 @@
 {
     let get = createBuiltin(tryGetByIdText("value"));
     noInline(get);
+    let getStrict = createBuiltin(tryGetByIdTextStrict("value"));
+    noInline(getStrict);
 
     let obj = {value: 1};
     let p = new Proxy(obj, { get: function() { throw new Error("should not be called"); } });
@@ -61,6 +84,8 @@
     for (let i = 0; i < 100000; i++) {
         if (get(p) !== null)
             throw new Error("wrong on iteration: " + i);
+        if (getStrict(p) !== null)
+            throw new Error("wrong on iteration: " + i);
     }
 }
 
@@ -68,6 +93,8 @@
 {
     let get = createBuiltin(tryGetByIdText("caller"));
     noInline(get);
+    let getStrict = createBuiltin(tryGetByIdTextStrict("caller"));
+    noInline(getStrict);
 
     let obj = {caller : 1};
     let func = function() {};
@@ -76,9 +103,13 @@
         if (i % 100 === 0) {
             if (get(func) !== null)
                 throw new Error("wrong on iteration: " + i);
+            if (getStrict(func) !== null)
+            throw new Error("wrong on iteration: " + i);
         } else {
             if (get(obj) !== 1)
                 throw new Error("wrong on iteration: " + i);
+            if (getStrict(obj) !== 1)
+            throw new Error("wrong on iteration: " + i);
         }
     }
 }
@@ -87,6 +118,8 @@
 {
     let get = createBuiltin(tryGetByIdText("caller"));
     noInline(get);
+    let getStrict = createBuiltin(tryGetByIdTextStrict("caller"));
+    noInline(getStrict);
 
     let func = function() {};
 
@@ -94,10 +127,14 @@
         if (i % 100 === 0) {
             if (get(func) !== null)
                 throw new Error("wrong on iteration: " + i);
+            if (getStrict(func) !== null)
+            throw new Error("wrong on iteration: " + i);
         } else {
             let obj = {caller : 1};
             if (get(obj) !== 1)
                 throw new Error("wrong on iteration: " + i);
+            if (getStrict(obj) !== 1)
+            throw new Error("wrong on iteration: " + i);
         }
     }
 }
@@ -106,12 +143,30 @@
 {
     let get = createBuiltin(tryGetByIdText("length"));
     noInline(get);
+    let getStrict = createBuiltin(tryGetByIdTextStrict("length"));
+    noInline(getStrict);
 
     let arr = [];
 
     for (let i = 0; i < 100000; i++) {
         if (get(arr) !== null)
             throw new Error("wrong on iteration: " + i);
+        if (getStrict(arr) !== null)
+            throw new Error("wrong on iteration: " + i);
+    }
+}
 
+// Test with non-object.
+{
+    let get = createBuiltin(tryGetByIdText("length"));
+    noInline(get);
+    let getStrict = createBuiltin(tryGetByIdTextStrict("length"));
+    noInline(getStrict);
+
+    for (let i = 0; i < 100000; i++) {
+        if (get(1) !== undefined)
+            throw new Error("wrong on iteration: " + i);
+        if (getStrict(1) !== undefined)
+            throw new Error("wrong on iteration: " + i);
     }
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to