Title: [217462] branches/safari-603-branch
Revision
217462
Author
jmarc...@apple.com
Date
2017-05-25 17:43:19 -0700 (Thu, 25 May 2017)

Log Message

Cherry-pick r217438. rdar://problem/32385704

Patch by Saam Barati <sbar...@apple.com> on 2017-05-25

JSTests:

* stress/for-in-invalidation-for-any-write.js: Added.
(assert):
(test):
(test.i):

Source/_javascript_Core:

* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitGetByVal):
(JSC::BytecodeGenerator::popIndexedForInScope):
(JSC::BytecodeGenerator::popStructureForInScope):
(JSC::BytecodeGenerator::invalidateForInContextForLocal):
(JSC::StructureForInContext::finalize):
(JSC::IndexedForInContext::finalize):
* bytecompiler/BytecodeGenerator.h:
(JSC::StructureForInContext::addGetInst):
(JSC::IndexedForInContext::addGetInst):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_nop):
* llint/LowLevelInterpreter.asm:

Modified Paths

Added Paths

Diff

Modified: branches/safari-603-branch/JSTests/ChangeLog (217461 => 217462)


--- branches/safari-603-branch/JSTests/ChangeLog	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/JSTests/ChangeLog	2017-05-26 00:43:19 UTC (rev 217462)
@@ -1,3 +1,12 @@
+2017-05-25  Saam Barati  <sbar...@apple.com>
+
+        Cherry-pick r217438. rdar://problem/32385704
+
+        * stress/for-in-invalidation-for-any-write.js: Added.
+        (assert):
+        (test):
+        (test.i):
+
 2017-05-24  Jason Marcell  <jmarc...@apple.com>
 
         Cherry-pick r217018. rdar://problem/32380054

Added: branches/safari-603-branch/JSTests/stress/for-in-invalidation-for-any-write.js (0 => 217462)


--- branches/safari-603-branch/JSTests/stress/for-in-invalidation-for-any-write.js	                        (rev 0)
+++ branches/safari-603-branch/JSTests/stress/for-in-invalidation-for-any-write.js	2017-05-26 00:43:19 UTC (rev 217462)
@@ -0,0 +1,146 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion");
+}
+noInline(assert);
+
+function test(f) {
+    noInline(f);
+    for (let i = 0; i < 1000; ++i)
+        f();
+}
+
+test(function() {
+    let o = {xx: 42};
+    for (let i in o) {
+        for (let j = 0; j < 2; j++) {
+            let r = o[i];
+            if (i === "xx")
+                assert(r === 42);
+            i = function() { }
+        }
+    }
+});
+
+test(function() {
+    let o = {xx: 42};
+    for (let i in {xx: 0}) {
+        for (let j = 0; j < 2; j++) {
+            let r = o[i];
+            if (i === "xx")
+                assert(r === 42);
+            i = new Uint32Array([0, 1, 0x777777, 0, 0]);
+        }
+    }
+});
+
+test(function() {
+    let o = {xx: 42};
+    for (let i in {xx: 0}) {
+        for (let j = 0; j < 2; j++) {
+            let r = o[i];
+            if (i === "xx")
+                assert(r === 42);
+            ([i] = [new Uint32Array([0, 1, 0x777777, 0, 0])]);
+        }
+    }
+});
+
+test(function() {
+    let o = {xx: 42};
+    for (let i in {xx: 0}) {
+        for (let j = 0; j < 2; j++) {
+            let r = o[i];
+            if (i === "xx")
+                assert(r === 42);
+            ({xyz: i} = {xyz: new Uint32Array([0, 1, 0x777777, 0, 0])});
+        }
+    }
+});
+
+test(function() {
+    let o = [1,2,3];
+    let toStringCalls = 0;
+    let first;
+    let num = 0;
+    let total = 0;
+    for (let i in o) {
+        first = true;
+        for (let j = 0; j < 3; j++) {
+            let r = o[i];
+            if (first)
+                assert(r === o[num]);
+            else
+                assert(r === undefined);
+            first = false;
+            i = {
+                toString() {
+                    ++toStringCalls;
+                    return "hello!";
+                }
+            }
+        }
+        ++num;
+    }
+
+    // Should be called twice per outer for-in loop.
+    assert(toStringCalls === o.length * 2);
+});
+
+test(function() {
+    let o = [1,2,3];
+    let toStringCalls = 0;
+    let first;
+    let num = 0;
+    let total = 0;
+    for (let i in o) {
+        first = true;
+        for (let j = 0; j < 3; j++) {
+            let r = o[i];
+            if (first)
+                assert(r === o[num]);
+            else
+                assert(r === undefined);
+            first = false;
+            ([i] = [{
+                toString() {
+                    ++toStringCalls;
+                    return "hello!";
+                }
+            }]);
+        }
+        ++num;
+    }
+
+    // Should be called twice per outer for-in loop.
+    assert(toStringCalls === o.length * 2);
+});
+
+test(function() {
+    let o = [1,2,3];
+    let toStringCalls = 0;
+    let first;
+    let num = 0;
+    let total = 0;
+    for (let i in o) {
+        first = true;
+        for (let j = 0; j < 3; j++) {
+            let r = o[i];
+            if (first)
+                assert(r === o[num]);
+            else
+                assert(r === undefined);
+            first = false;
+            ({xyz: i} = {xyz: {
+                toString() {
+                    ++toStringCalls;
+                    return "hello!";
+                }
+            }});
+        }
+        ++num;
+    }
+
+    // Should be called twice per outer for-in loop.
+    assert(toStringCalls === o.length * 2);
+});

Modified: branches/safari-603-branch/Source/_javascript_Core/ChangeLog (217461 => 217462)


--- branches/safari-603-branch/Source/_javascript_Core/ChangeLog	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/Source/_javascript_Core/ChangeLog	2017-05-26 00:43:19 UTC (rev 217462)
@@ -1,3 +1,34 @@
+2017-05-25  Saam Barati  <sbar...@apple.com>
+
+        Cherry-pick r217438. rdar://problem/32385704
+
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitGetByVal):
+        (JSC::BytecodeGenerator::popIndexedForInScope):
+        (JSC::BytecodeGenerator::popStructureForInScope):
+        (JSC::BytecodeGenerator::invalidateForInContextForLocal):
+        (JSC::StructureForInContext::finalize):
+        (JSC::IndexedForInContext::finalize):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::StructureForInContext::addGetInst):
+        (JSC::IndexedForInContext::addGetInst):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_nop):
+        * llint/LowLevelInterpreter.asm:
+
 2017-05-24  Jason Marcell  <jmarc...@apple.com>
 
         Cherry-pick r217016. rdar://problem/32380054

Modified: branches/safari-603-branch/Source/_javascript_Core/bytecode/BytecodeList.json (217461 => 217462)


--- branches/safari-603-branch/Source/_javascript_Core/bytecode/BytecodeList.json	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/Source/_javascript_Core/bytecode/BytecodeList.json	2017-05-26 00:43:19 UTC (rev 217462)
@@ -152,7 +152,8 @@
             { "name" : "op_yield", "length" : 4 },
             { "name" : "op_watchdog", "length" : 1 },
             { "name" : "op_log_shadow_chicken_prologue", "length" : 2},
-            { "name" : "op_log_shadow_chicken_tail", "length" : 3}
+            { "name" : "op_log_shadow_chicken_tail", "length" : 3},
+            { "name" : "op_nop", "length" : 1}
         ]
     },
     {

Modified: branches/safari-603-branch/Source/_javascript_Core/bytecode/BytecodeUseDef.h (217461 => 217462)


--- branches/safari-603-branch/Source/_javascript_Core/bytecode/BytecodeUseDef.h	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/Source/_javascript_Core/bytecode/BytecodeUseDef.h	2017-05-26 00:43:19 UTC (rev 217462)
@@ -55,6 +55,7 @@
     case op_get_rest_length:
     case op_watchdog:
     case op_get_argument:
+    case op_nop:
         return;
     case op_assert:
     case op_get_scope:
@@ -363,6 +364,7 @@
     case op_log_shadow_chicken_prologue:
     case op_log_shadow_chicken_tail:
     case op_yield:
+    case op_nop:
 #define LLINT_HELPER_OPCODES(opcode, length) case opcode:
         FOR_EACH_LLINT_OPCODE_EXTENSION(LLINT_HELPER_OPCODES);
 #undef LLINT_HELPER_OPCODES

Modified: branches/safari-603-branch/Source/_javascript_Core/bytecode/CodeBlock.cpp (217461 => 217462)


--- branches/safari-603-branch/Source/_javascript_Core/bytecode/CodeBlock.cpp	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/Source/_javascript_Core/bytecode/CodeBlock.cpp	2017-05-26 00:43:19 UTC (rev 217462)
@@ -1388,6 +1388,10 @@
             printLocationAndOp(out, exec, location, it, "watchdog");
             break;
         }
+        case op_nop: {
+            printLocationAndOp(out, exec, location, it, "nop");
+            break;
+        }
         case op_log_shadow_chicken_prologue: {
             int r0 = (++it)->u.operand;
             printLocationAndOp(out, exec, location, it, "log_shadow_chicken_prologue");

Modified: branches/safari-603-branch/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (217461 => 217462)


--- branches/safari-603-branch/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2017-05-26 00:43:19 UTC (rev 217462)
@@ -2775,15 +2775,15 @@
 
 RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
 {
-    for (size_t i = m_forInContextStack.size(); i > 0; i--) {
-        ForInContext* context = m_forInContextStack[i - 1].get();
+    for (size_t i = m_forInContextStack.size(); i--; ) {
+        ForInContext* context = m_forInContextStack[i].get();
         if (context->local() != property)
             continue;
 
-        if (!context->isValid())
-            break;
+        unsigned instIndex = instructions().size();
 
         if (context->type() == ForInContext::IndexedForInContextType) {
+            static_cast<IndexedForInContext*>(context)->addGetInst(instIndex, property->index());
             property = static_cast<IndexedForInContext*>(context)->index();
             break;
         }
@@ -2797,6 +2797,8 @@
         instructions().append(structureContext->index()->index());
         instructions().append(structureContext->enumerator()->index());
         instructions().append(profile);
+
+        structureContext->addGetInst(instIndex, property->index(), profile);
         return dst;
     }
 
@@ -4594,6 +4596,9 @@
 {
     if (!localRegister)
         return;
+
+    ASSERT(m_forInContextStack.last()->type() == ForInContext::IndexedForInContextType);
+    static_cast<IndexedForInContext*>(m_forInContextStack.last().get())->finalize(*this);
     m_forInContextStack.removeLast();
 }
 
@@ -4702,6 +4707,8 @@
 {
     if (!localRegister)
         return;
+    ASSERT(m_forInContextStack.last()->type() == ForInContext::StructureForInContextType);
+    static_cast<StructureForInContext*>(m_forInContextStack.last().get())->finalize(*this);
     m_forInContextStack.removeLast();
 }
 
@@ -4718,8 +4725,8 @@
     // to perform some flow-sensitive analysis to see if/when the loop iteration variable was 
     // reassigned, or we'd have to resort to runtime checks to see if the variable had been 
     // reassigned from its original value.
-    for (size_t i = m_forInContextStack.size(); i > 0; i--) {
-        ForInContext* context = m_forInContextStack[i - 1].get();
+    for (size_t i = m_forInContextStack.size(); i--; ) {
+        ForInContext* context = m_forInContextStack[i].get();
         if (context->local() != localRegister)
             continue;
         context->invalidate();
@@ -4941,6 +4948,51 @@
     emitPutById(generatorRegister(), propertyNames().builtinNames().generatorStatePrivateName(), completedState);
 }
 
+void StructureForInContext::finalize(BytecodeGenerator& generator)
+{
+    if (isValid())
+        return;
+
+    for (const auto& instTuple : m_getInsts) {
+        unsigned instIndex = std::get<0>(instTuple);
+        int propertyRegIndex = std::get<1>(instTuple);
+        UnlinkedValueProfile valueProfile = std::get<2>(instTuple);
+        OpcodeID op = generator.instructions()[instIndex].u.opcode;
+        RELEASE_ASSERT(op == op_get_direct_pname);
+        ASSERT(opcodeLength(op_get_direct_pname) == 7);
+        ASSERT(opcodeLength(op_get_by_val) == 6);
+
+        // 0. Change the opcode to get_by_val.
+        generator.instructions()[instIndex].u.opcode = op_get_by_val;
+        // 1. dst stays the same.
+        // 2. base stays the same.
+        // 3. property gets switched to the original property.
+        generator.instructions()[instIndex + 3].u.operand = propertyRegIndex;
+        // 4. add an array profile.
+        generator.instructions()[instIndex + 4].u.operand = generator.newArrayProfile();
+        // 5. set the result value profile.
+        generator.instructions()[instIndex + 5].u.operand = valueProfile;
+        // 6. nop out the last instruction word.
+        generator.instructions()[instIndex + 6].u.opcode = op_nop;
+    }
+}
+
+void IndexedForInContext::finalize(BytecodeGenerator& generator)
+{
+    if (isValid())
+        return;
+
+    for (const auto& instPair : m_getInsts) {
+        unsigned instIndex = instPair.first;
+        int propertyRegIndex = instPair.second;
+        OpcodeID op = generator.instructions()[instIndex].u.opcode;
+        RELEASE_ASSERT(op == op_get_by_val);
+        // We just need to perform the get_by_val with the original property here,
+        // not the indexed one.
+        generator.instructions()[instIndex + 3].u.operand = propertyRegIndex;
+    }
+}
+
 } // namespace JSC
 
 namespace WTF {

Modified: branches/safari-603-branch/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (217461 => 217462)


--- branches/safari-603-branch/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2017-05-26 00:43:19 UTC (rev 217462)
@@ -148,10 +148,18 @@
         RegisterID* property() const { return m_propertyRegister.get(); }
         RegisterID* enumerator() const { return m_enumeratorRegister.get(); }
 
+        void addGetInst(unsigned instIndex, int propertyRegIndex, UnlinkedValueProfile valueProfile)
+        {
+            m_getInsts.append({ instIndex, propertyRegIndex, valueProfile });
+        }
+
+        void finalize(BytecodeGenerator&);
+
     private:
         RefPtr<RegisterID> m_indexRegister;
         RefPtr<RegisterID> m_propertyRegister;
         RefPtr<RegisterID> m_enumeratorRegister;
+        Vector<std::tuple<unsigned, int, UnlinkedValueProfile>> m_getInsts;
     };
 
     class IndexedForInContext : public ForInContext {
@@ -169,8 +177,12 @@
 
         RegisterID* index() const { return m_indexRegister.get(); }
 
+        void finalize(BytecodeGenerator&);
+        void addGetInst(unsigned instIndex, int propertyIndex) { m_getInsts.append({ instIndex, propertyIndex }); }
+
     private:
         RefPtr<RegisterID> m_indexRegister;
+        Vector<std::pair<unsigned, int>> m_getInsts;
     };
 
     struct TryData {
@@ -772,6 +784,7 @@
         void popLexicalScope(VariableEnvironmentNode*);
         void prepareLexicalScopeForNextForLoopIteration(VariableEnvironmentNode*, RegisterID* loopSymbolTable);
         int labelScopeDepth() const;
+        UnlinkedArrayProfile newArrayProfile();
 
     private:
         ParserError generate();
@@ -781,7 +794,6 @@
         void emitOpcode(OpcodeID);
         UnlinkedArrayAllocationProfile newArrayAllocationProfile();
         UnlinkedObjectAllocationProfile newObjectAllocationProfile();
-        UnlinkedArrayProfile newArrayProfile();
         UnlinkedValueProfile emitProfiledOpcode(OpcodeID);
         int kill(RegisterID* dst)
         {

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (217461 => 217462)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-05-26 00:43:19 UTC (rev 217462)
@@ -5328,6 +5328,11 @@
             addToGraph(CheckWatchdogTimer);
             NEXT_OPCODE(op_watchdog); 
         }
+
+        case op_nop: {
+            addToGraph(Check); // We add a nop here so that basic block linking doesn't break.
+            NEXT_OPCODE(op_nop);
+        }
             
         case op_create_lexical_environment: {
             VirtualRegister symbolTableRegister(currentInstruction[3].u.operand);

Modified: branches/safari-603-branch/Source/_javascript_Core/dfg/DFGCapabilities.cpp (217461 => 217462)


--- branches/safari-603-branch/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2017-05-26 00:43:19 UTC (rev 217462)
@@ -188,6 +188,7 @@
     case op_jngreatereq:
     case op_loop_hint:
     case op_watchdog:
+    case op_nop:
     case op_ret:
     case op_end:
     case op_new_object:

Modified: branches/safari-603-branch/Source/_javascript_Core/jit/JIT.cpp (217461 => 217462)


--- branches/safari-603-branch/Source/_javascript_Core/jit/JIT.cpp	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/Source/_javascript_Core/jit/JIT.cpp	2017-05-26 00:43:19 UTC (rev 217462)
@@ -329,6 +329,7 @@
         DEFINE_OP(op_jtrue)
         DEFINE_OP(op_loop_hint)
         DEFINE_OP(op_watchdog)
+        DEFINE_OP(op_nop)
         DEFINE_OP(op_lshift)
         DEFINE_OP(op_mod)
         DEFINE_OP(op_mov)

Modified: branches/safari-603-branch/Source/_javascript_Core/jit/JIT.h (217461 => 217462)


--- branches/safari-603-branch/Source/_javascript_Core/jit/JIT.h	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/Source/_javascript_Core/jit/JIT.h	2017-05-26 00:43:19 UTC (rev 217462)
@@ -531,6 +531,7 @@
         void emit_op_jtrue(Instruction*);
         void emit_op_loop_hint(Instruction*);
         void emit_op_watchdog(Instruction*);
+        void emit_op_nop(Instruction*);
         void emit_op_lshift(Instruction*);
         void emit_op_mod(Instruction*);
         void emit_op_mov(Instruction*);

Modified: branches/safari-603-branch/Source/_javascript_Core/jit/JITOpcodes.cpp (217461 => 217462)


--- branches/safari-603-branch/Source/_javascript_Core/jit/JITOpcodes.cpp	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/Source/_javascript_Core/jit/JITOpcodes.cpp	2017-05-26 00:43:19 UTC (rev 217462)
@@ -956,6 +956,10 @@
     callOperation(operationHandleWatchdogTimer);
 }
 
+void JIT::emit_op_nop(Instruction*)
+{
+}
+
 void JIT::emit_op_new_regexp(Instruction* currentInstruction)
 {
     callOperation(operationNewRegexp, currentInstruction[1].u.operand, m_codeBlock->regexp(currentInstruction[2].u.operand));

Modified: branches/safari-603-branch/Source/_javascript_Core/llint/LowLevelInterpreter.asm (217461 => 217462)


--- branches/safari-603-branch/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2017-05-26 00:42:58 UTC (rev 217461)
+++ branches/safari-603-branch/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2017-05-26 00:43:19 UTC (rev 217462)
@@ -1601,6 +1601,10 @@
 end
 
 
+_llint_op_nop:
+    dispatch(1)
+
+
 _llint_op_switch_string:
     traceExecution()
     callOpcodeSlowPath(_llint_slow_path_switch_string)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to