Ensure that ForInContexts are invalidated if their loop local is over-written.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Sep 2018 00:57:56 +0000 (00:57 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Sep 2018 00:57:56 +0000 (00:57 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189571
<rdar://problem/44402277>

Reviewed by Saam Barati.

JSTests:

* stress/regress-189571.js: Added.

Source/JavaScriptCore:

Instead of hunting down every place in the BytecodeGenerator that potentially
needs to invalidate an enclosing ForInContext (if one exists), we simply iterate
the bytecode range of the loop body when the ForInContext is popped, and
invalidate the context if we ever find the loop temp variable over-written.

This has 2 benefits:
1. It ensures that every type of opcode that can write to the loop temp will be
   handled appropriately, not just the op_mov that we've hunted down.
2. It avoids us having to check the BytecodeGenerator's m_forInContextStack
   every time we emit an op_mov (or other opcodes that can write to a local)
   even when we're not inside a for-in loop.

JSC benchmarks show that that this change is performance neutral.

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::pushIndexedForInScope):
(JSC::BytecodeGenerator::popIndexedForInScope):
(JSC::BytecodeGenerator::pushStructureForInScope):
(JSC::BytecodeGenerator::popStructureForInScope):
(JSC::ForInContext::finalize):
(JSC::StructureForInContext::finalize):
(JSC::IndexedForInContext::finalize):
(JSC::BytecodeGenerator::invalidateForInContextForLocal): Deleted.
* bytecompiler/BytecodeGenerator.h:
(JSC::ForInContext::ForInContext):
(JSC::ForInContext::bodyBytecodeStartOffset const):
(JSC::StructureForInContext::StructureForInContext):
(JSC::IndexedForInContext::IndexedForInContext):
* bytecompiler/NodesCodegen.cpp:
(JSC::PostfixNode::emitResolve):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::EmptyLetExpression::emitBytecode):
(JSC::ForInNode::emitLoopHeader):
(JSC::ForOfNode::emitBytecode):
(JSC::BindingNode::bindValue const):
(JSC::AssignmentElementNode::bindValue const):
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@236161 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChangeLog
JSTests/stress/regress-189571.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

index 7582359..7213b67 100644 (file)
@@ -1,3 +1,13 @@
+2018-09-17  Mark Lam  <mark.lam@apple.com>
+
+        Ensure that ForInContexts are invalidated if their loop local is over-written.
+        https://bugs.webkit.org/show_bug.cgi?id=189571
+        <rdar://problem/44402277>
+
+        Reviewed by Saam Barati.
+
+        * stress/regress-189571.js: Added.
+
 2018-09-17  Saam barati  <sbarati@apple.com>
 
         We must convert ProfileType to CheckStructureOrEmpty instead of CheckStructure
diff --git a/JSTests/stress/regress-189571.js b/JSTests/stress/regress-189571.js
new file mode 100644 (file)
index 0000000..8bde9cf
--- /dev/null
@@ -0,0 +1,151 @@
+function assert(name, actual, expected) {
+    if (actual != expected) {
+        print("FAILED test " + name + ": expected " + expected + ", actual: " + actual);
+        throw "FAILED";
+    }
+}
+
+function checkResult(name, result, expectedK, expectedProp) {
+    assert(name, result[0], expectedK);
+    assert(name, result[1], expectedProp);
+}
+
+// ForIn on Indexed properties.
+
+function testIndexedProperties(o) {
+    for (var k in o) {
+        {
+            function k() { }
+        }
+        return [ k, o[k] ];
+    }
+}
+
+var o = [42];
+for (var i = 0; i < 10000; ++i) {
+    var result = testIndexedProperties(o);
+    checkResult("testIndexedProperties", result, "function k() { }", undefined);
+}
+
+function testIndexedProperties2(o) {
+    for (var k in o) {
+        {
+            k = "boo";
+            function k() { }
+        }
+        return [ k, o[k] ];
+    }
+}
+
+var o = [42];
+for (var i = 0; i < 10000; ++i) {
+    var result = testIndexedProperties2(o);
+    checkResult("testIndexedProperties2", result, "boo", undefined);
+}
+
+function testIndexedProperties3(o) {
+    for (var k in o) {
+        try {
+        } finally {
+            {
+                function k() { }
+            }
+        }
+        return [ k, o[k] ];
+    }
+}
+
+var o = [42];
+for (var i = 0; i < 10000; ++i) {
+    var result = testIndexedProperties3(o);
+    checkResult("testIndexedProperties3", result, "function k() { }", undefined);
+}
+
+function testIndexedProperties4(o) {
+    for (var k in o) {
+        try {
+        } finally {
+            {
+                k = "boo";
+                function k() { }
+            }
+        }
+        return [ k, o[k] ];
+    }
+}
+
+var o = [42];
+for (var i = 0; i < 10000; ++i) {
+    var result = testIndexedProperties4(o);
+    checkResult("testIndexedProperties4", result, "boo", undefined);
+}
+
+// ForIn on Structure properties.
+
+function testStructureProperties(o) {
+    for (var k in o) {
+        {
+            function k() { }
+        }
+        return [ k, o[k] ];
+    }
+}
+
+var o = {a: 42};
+for (var i = 0; i < 10000; ++i) {
+    var result = testStructureProperties(o);
+    checkResult("testStructureProperties", result, "function k() { }", undefined);
+}
+
+function testStructureProperties2(o) {
+    for (var k in o) {
+        {
+            k = 0x1234;
+            function k() { }
+        }
+        return [ k, o[k] ];
+    }
+}
+
+var o = {a: 42};
+for (var i = 0; i < 10000; ++i) {
+    var result = testStructureProperties2(o);
+    checkResult("testStructureProperties2", result, 0x1234, undefined);
+}
+
+function testStructureProperties3(o) {
+    for (var k in o) {
+        try {
+        } finally {
+            {
+                function k() { }
+            }
+        }
+        return [ k, o[k] ];
+    }
+}
+
+var o = {a: 42};
+for (var i = 0; i < 10000; ++i) {
+    var result = testStructureProperties3(o);
+    checkResult("testStructureProperties3", result, "function k() { }", undefined);
+}
+
+function testStructureProperties4(o) {
+    for (var k in o) {
+        try {
+        } finally {
+            {
+                k = 0x1234;
+                function k() { }
+            }
+        }
+        return [ k, o[k] ];
+    }
+}
+
+var o = {a: 42};
+for (var i = 0; i < 10000; ++i) {
+    var result = testStructureProperties4(o);
+    checkResult("testStructureProperties4", result, 0x1234, undefined);
+}
index 6ce7c33..86a03a5 100644 (file)
@@ -1,3 +1,52 @@
+2018-09-18  Mark Lam  <mark.lam@apple.com>
+
+        Ensure that ForInContexts are invalidated if their loop local is over-written.
+        https://bugs.webkit.org/show_bug.cgi?id=189571
+        <rdar://problem/44402277>
+
+        Reviewed by Saam Barati.
+
+        Instead of hunting down every place in the BytecodeGenerator that potentially
+        needs to invalidate an enclosing ForInContext (if one exists), we simply iterate
+        the bytecode range of the loop body when the ForInContext is popped, and
+        invalidate the context if we ever find the loop temp variable over-written.
+
+        This has 2 benefits:
+        1. It ensures that every type of opcode that can write to the loop temp will be
+           handled appropriately, not just the op_mov that we've hunted down.
+        2. It avoids us having to check the BytecodeGenerator's m_forInContextStack
+           every time we emit an op_mov (or other opcodes that can write to a local)
+           even when we're not inside a for-in loop.
+
+        JSC benchmarks show that that this change is performance neutral.
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::pushIndexedForInScope):
+        (JSC::BytecodeGenerator::popIndexedForInScope):
+        (JSC::BytecodeGenerator::pushStructureForInScope):
+        (JSC::BytecodeGenerator::popStructureForInScope):
+        (JSC::ForInContext::finalize):
+        (JSC::StructureForInContext::finalize):
+        (JSC::IndexedForInContext::finalize):
+        (JSC::BytecodeGenerator::invalidateForInContextForLocal): Deleted.
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::ForInContext::ForInContext):
+        (JSC::ForInContext::bodyBytecodeStartOffset const):
+        (JSC::StructureForInContext::StructureForInContext):
+        (JSC::IndexedForInContext::IndexedForInContext):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::PostfixNode::emitResolve):
+        (JSC::PrefixNode::emitResolve):
+        (JSC::ReadModifyResolveNode::emitBytecode):
+        (JSC::AssignResolveNode::emitBytecode):
+        (JSC::EmptyLetExpression::emitBytecode):
+        (JSC::ForInNode::emitLoopHeader):
+        (JSC::ForOfNode::emitBytecode):
+        (JSC::BindingNode::bindValue const):
+        (JSC::AssignmentElementNode::bindValue const):
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+
 2018-09-17  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: generate CSSKeywordCompletions from backend values
index da6febe..4b88a1b 100644 (file)
@@ -36,6 +36,7 @@
 #include "BuiltinNames.h"
 #include "BytecodeGeneratorification.h"
 #include "BytecodeLivenessAnalysis.h"
+#include "BytecodeUseDef.h"
 #include "CatchScope.h"
 #include "DefinePropertyAttributes.h"
 #include "Interpreter.h"
@@ -4624,14 +4625,16 @@ void BytecodeGenerator::pushIndexedForInScope(RegisterID* localRegister, Registe
 {
     if (!localRegister)
         return;
-    m_forInContextStack.append(adoptRef(*new IndexedForInContext(localRegister, indexRegister)));
+    unsigned bodyBytecodeStartOffset = instructions().size();
+    m_forInContextStack.append(adoptRef(*new IndexedForInContext(localRegister, indexRegister, bodyBytecodeStartOffset)));
 }
 
 void BytecodeGenerator::popIndexedForInScope(RegisterID* localRegister)
 {
     if (!localRegister)
         return;
-    m_forInContextStack.last()->asIndexedForInContext().finalize(*this);
+    unsigned bodyBytecodeEndOffset = instructions().size();
+    m_forInContextStack.last()->asIndexedForInContext().finalize(*this, m_codeBlock.get(), bodyBytecodeEndOffset);
     m_forInContextStack.removeLast();
 }
 
@@ -4734,37 +4737,19 @@ void BytecodeGenerator::pushStructureForInScope(RegisterID* localRegister, Regis
 {
     if (!localRegister)
         return;
-    m_forInContextStack.append(adoptRef(*new StructureForInContext(localRegister, indexRegister, propertyRegister, enumeratorRegister)));
+    unsigned bodyBytecodeStartOffset = instructions().size();
+    m_forInContextStack.append(adoptRef(*new StructureForInContext(localRegister, indexRegister, propertyRegister, enumeratorRegister, bodyBytecodeStartOffset)));
 }
 
 void BytecodeGenerator::popStructureForInScope(RegisterID* localRegister)
 {
     if (!localRegister)
         return;
-    m_forInContextStack.last()->asStructureForInContext().finalize(*this);
+    unsigned bodyBytecodeEndOffset = instructions().size();
+    m_forInContextStack.last()->asStructureForInContext().finalize(*this, m_codeBlock.get(), bodyBytecodeEndOffset);
     m_forInContextStack.removeLast();
 }
 
-void BytecodeGenerator::invalidateForInContextForLocal(RegisterID* localRegister)
-{
-    // Lexically invalidating ForInContexts is kind of weak sauce, but it only occurs if 
-    // either of the following conditions is true:
-    // 
-    // (1) The loop iteration variable is re-assigned within the body of the loop.
-    // (2) The loop iteration variable is captured in the lexical scope of the function.
-    //
-    // These two situations occur sufficiently rarely that it's okay to use this style of 
-    // "analysis" to make iteration faster. If we didn't want to do this, we would either have 
-    // 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--; ) {
-        ForInContext& context = m_forInContextStack[i].get();
-        if (context.local() == localRegister)
-            context.invalidate();
-    }
-}
-
 RegisterID* BytecodeGenerator::emitRestParameter(RegisterID* result, unsigned numParametersToSkip)
 {
     RefPtr<RegisterID> restArrayLength = newTemporary();
@@ -5190,8 +5175,37 @@ void BytecodeGenerator::emitJumpIf(OpcodeID compareOpcode, RegisterID* completio
     emitJumpIfTrue(equivalenceResult, jumpTarget);
 }
 
-void StructureForInContext::finalize(BytecodeGenerator& generator)
+void ForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlock* codeBlock, unsigned bodyBytecodeEndOffset)
+{
+    // Lexically invalidating ForInContexts is kind of weak sauce, but it only occurs if
+    // either of the following conditions is true:
+    //
+    // (1) The loop iteration variable is re-assigned within the body of the loop.
+    // (2) The loop iteration variable is captured in the lexical scope of the function.
+    //
+    // These two situations occur sufficiently rarely that it's okay to use this style of
+    // "analysis" to make iteration faster. If we didn't want to do this, we would either have
+    // 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 (unsigned offset = bodyBytecodeStartOffset(); isValid() && offset < bodyBytecodeEndOffset;) {
+        UnlinkedInstruction* instruction = &generator.instructions()[offset];
+        OpcodeID opcodeID = instruction->u.opcode;
+        unsigned opcodeLength = opcodeLengths[opcodeID];
+
+        ASSERT(opcodeID != op_enter);
+        computeDefsForBytecodeOffset(codeBlock, opcodeID, instruction, [&] (UnlinkedCodeBlock*, UnlinkedInstruction*, OpcodeID, int operand) {
+            if (local()->index() == operand)
+                invalidate();
+        });
+        offset += opcodeLength;
+    }
+}
+
+void StructureForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlock* codeBlock, unsigned bodyBytecodeEndOffset)
 {
+    Base::finalize(generator, codeBlock, bodyBytecodeEndOffset);
     if (isValid())
         return;
 
@@ -5219,8 +5233,9 @@ void StructureForInContext::finalize(BytecodeGenerator& generator)
     }
 }
 
-void IndexedForInContext::finalize(BytecodeGenerator& generator)
+void IndexedForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlock* codeBlock, unsigned bodyBytecodeEndOffset)
 {
+    Base::finalize(generator, codeBlock, bodyBytecodeEndOffset);
     if (isValid())
         return;
 
index 9cd4cf2..f88d84f 100644 (file)
@@ -211,23 +211,30 @@ namespace JSC {
         RegisterID* local() const { return m_localRegister.get(); }
 
     protected:
-        ForInContext(RegisterID* localRegister, Type type)
+        ForInContext(RegisterID* localRegister, Type type, unsigned bodyBytecodeStartOffset)
             : m_localRegister(localRegister)
             , m_type(type)
+            , m_bodyBytecodeStartOffset(bodyBytecodeStartOffset)
         { }
 
+        unsigned bodyBytecodeStartOffset() const { return m_bodyBytecodeStartOffset; }
+
+        void finalize(BytecodeGenerator&, UnlinkedCodeBlock*, unsigned bodyBytecodeEndOffset);
+
     private:
         RefPtr<RegisterID> m_localRegister;
         bool m_isValid { true };
         Type m_type;
+        unsigned m_bodyBytecodeStartOffset;
     };
 
     class StructureForInContext : public ForInContext {
+        using Base = ForInContext;
     public:
         using GetInst = std::tuple<unsigned, int, UnlinkedValueProfile>;
 
-        StructureForInContext(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister)
-            : ForInContext(localRegister, Type::StructureForIn)
+        StructureForInContext(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister, unsigned bodyBytecodeStartOffset)
+            : ForInContext(localRegister, Type::StructureForIn, bodyBytecodeStartOffset)
             , m_indexRegister(indexRegister)
             , m_propertyRegister(propertyRegister)
             , m_enumeratorRegister(enumeratorRegister)
@@ -243,7 +250,7 @@ namespace JSC {
             m_getInsts.append(GetInst { instIndex, propertyRegIndex, valueProfile });
         }
 
-        void finalize(BytecodeGenerator&);
+        void finalize(BytecodeGenerator&, UnlinkedCodeBlock*, unsigned bodyBytecodeEndOffset);
 
     private:
         RefPtr<RegisterID> m_indexRegister;
@@ -253,16 +260,17 @@ namespace JSC {
     };
 
     class IndexedForInContext : public ForInContext {
+        using Base = ForInContext;
     public:
-        IndexedForInContext(RegisterID* localRegister, RegisterID* indexRegister)
-            : ForInContext(localRegister, Type::IndexedForIn)
+        IndexedForInContext(RegisterID* localRegister, RegisterID* indexRegister, unsigned bodyBytecodeStartOffset)
+            : ForInContext(localRegister, Type::IndexedForIn, bodyBytecodeStartOffset)
             , m_indexRegister(indexRegister)
         {
         }
 
         RegisterID* index() const { return m_indexRegister.get(); }
 
-        void finalize(BytecodeGenerator&);
+        void finalize(BytecodeGenerator&, UnlinkedCodeBlock*, unsigned bodyBytecodeEndOffset);
         void addGetInst(unsigned instIndex, int propertyIndex) { m_getInsts.append({ instIndex, propertyIndex }); }
 
     private:
@@ -938,7 +946,6 @@ namespace JSC {
         void popIndexedForInScope(RegisterID* local);
         void pushStructureForInScope(RegisterID* local, RegisterID* index, RegisterID* property, RegisterID* enumerator);
         void popStructureForInScope(RegisterID* local);
-        void invalidateForInContextForLocal(RegisterID* local);
 
         LabelScope* breakTarget(const Identifier&);
         LabelScope* continueTarget(const Identifier&);
index 366964f..0437497 100644 (file)
@@ -1556,7 +1556,6 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
             generator.emitReadOnlyExceptionIfNeeded(var);
             localReg = generator.move(generator.tempDestination(dst), local);
         }
-        generator.invalidateForInContextForLocal(local);
         RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator);
         generator.emitProfileType(localReg.get(), var, divotStart(), divotEnd());
         return oldValue.get();
@@ -1769,7 +1768,6 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
             generator.emitReadOnlyExceptionIfNeeded(var);
             localReg = generator.move(generator.tempDestination(dst), localReg.get());
         } else if (generator.vm()->typeProfiler()) {
-            generator.invalidateForInContextForLocal(local);
             RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
             generator.move(tempDst.get(), localReg.get());
             emitIncOrDec(generator, tempDst.get(), m_operator);
@@ -1777,7 +1775,6 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
             generator.emitProfileType(localReg.get(), var, divotStart(), divotEnd());
             return generator.move(dst, tempDst.get());
         }
-        generator.invalidateForInContextForLocal(local);
         emitIncOrDec(generator, localReg.get(), m_operator);
         return generator.move(dst, localReg.get());
     }
@@ -2441,13 +2438,11 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
             generator.move(result.get(), local);
             emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
             generator.move(local, result.get());
-            generator.invalidateForInContextForLocal(local);
             generator.emitProfileType(local, divotStart(), divotEnd());
             return generator.move(dst, result.get());
         }
         
         RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
-        generator.invalidateForInContextForLocal(local);
         generator.emitProfileType(result, divotStart(), divotEnd());
         return generator.move(dst, result);
     }
@@ -2505,12 +2500,10 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
             generator.emitNode(tempDst.get(), m_right);
             generator.move(local, tempDst.get());
             generator.emitProfileType(local, var, divotStart(), divotEnd());
-            generator.invalidateForInContextForLocal(local);
             result = generator.move(dst, tempDst.get());
         } else {
             RegisterID* right = generator.emitNode(local, m_right);
             generator.emitProfileType(right, var, divotStart(), divotEnd());
-            generator.invalidateForInContextForLocal(local);
             result = generator.move(dst, right);
         }
 
@@ -2752,7 +2745,6 @@ RegisterID* EmptyLetExpression::emitBytecode(BytecodeGenerator& generator, Regis
     Variable var = generator.variable(m_ident);
     if (RegisterID* local = var.local()) {
         generator.emitLoad(local, jsUndefined());
-        generator.invalidateForInContextForLocal(local);
         generator.emitProfileType(local, var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1));
     } else {
         RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
@@ -2966,7 +2958,6 @@ void ForInNode::emitLoopHeader(BytecodeGenerator& generator, RegisterID* propert
             if (var.isReadOnly())
                 generator.emitReadOnlyExceptionIfNeeded(var);
             generator.move(local, propertyName);
-            generator.invalidateForInContextForLocal(local);
         } else {
             if (generator.isStrictMode())
                 generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
@@ -3034,7 +3025,6 @@ void ForInNode::emitLoopHeader(BytecodeGenerator& generator, RegisterID* propert
             return;
         }
         generator.move(var.local(), propertyName);
-        generator.invalidateForInContextForLocal(var.local());
         generator.emitProfileType(propertyName, var, simpleBinding->divotStart(), simpleBinding->divotEnd());
         return;
     }
@@ -3225,7 +3215,6 @@ void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
                 if (var.isReadOnly())
                     generator.emitReadOnlyExceptionIfNeeded(var);
                 generator.move(local, value);
-                generator.invalidateForInContextForLocal(local);
             } else {
                 if (generator.isStrictMode())
                     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
@@ -4399,7 +4388,6 @@ void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) con
             return;
         }
         generator.move(local, value);
-        generator.invalidateForInContextForLocal(local);
         generator.emitProfileType(local, var, divotStart(), divotEnd());
         if (m_bindingContext == AssignmentContext::DeclarationStatement || m_bindingContext == AssignmentContext::ConstDeclarationStatement)
             generator.liftTDZCheckIfPossible(var);
@@ -4448,7 +4436,6 @@ void AssignmentElementNode::bindValue(BytecodeGenerator& generator, RegisterID*
             if (isReadOnly)
                 generator.emitReadOnlyExceptionIfNeeded(var);
             else {
-                generator.invalidateForInContextForLocal(local);
                 generator.move(local, value);
                 generator.emitProfileType(local, divotStart(), divotEnd());
             }
index aa7524d..4e23fd7 100644 (file)
@@ -810,6 +810,7 @@ SLOW_PATH_DECL(slow_path_has_generic_property)
     JSObject* base = OP(2).jsValue().toObject(exec);
     CHECK_EXCEPTION();
     JSValue property = OP(3).jsValue();
+    ASSERT(property.isString());
     JSString* string = asString(property);
     auto propertyName = string->toIdentifier(exec);
     CHECK_EXCEPTION();
@@ -821,6 +822,7 @@ SLOW_PATH_DECL(slow_path_get_direct_pname)
     BEGIN();
     JSValue baseValue = OP_C(2).jsValue();
     JSValue property = OP(3).jsValue();
+    ASSERT(property.isString());
     JSString* string = asString(property);
     auto propertyName = string->toIdentifier(exec);
     CHECK_EXCEPTION();