Do all closed variable access through the local lexical object
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 2 Oct 2014 20:35:58 +0000 (20:35 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 2 Oct 2014 20:35:58 +0000 (20:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=136869

Reviewed by Filip Pizlo.

This patch makes all reads and writes from captured registers
go through the lexical record, and by doing so removes the
need for record tearoff.

To keep the patch simple we still number variables as though
they are local stack allocated registers, but ::local() will
fail. When local fails we perform a generic resolve, and in
that resolve we now use a ResolveScopeInfo struct to pass
around information about whether a lookup is a statically
known captured variable, and its location in the activation.
To ensure correct behaviour during codeblock linking we also
add a LocalClosureVariable resolution type.

To ensure correct semantics for the Arguments object, we now
have to eagerly create the Arguments object for any function
that uses both the Arguments object and requires a lexical
record.

* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finalizeUnconditionally):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::initializeCapturedVariable):
  During the entry to a function we are not yet in a position
  to allocate temporaries so we directly use the lexical
  environment register.
(JSC::BytecodeGenerator::resolveCallee):
(JSC::BytecodeGenerator::emitMove):
(JSC::BytecodeGenerator::local):
(JSC::BytecodeGenerator::constLocal):
(JSC::BytecodeGenerator::emitResolveScope):
(JSC::BytecodeGenerator::emitResolveConstantLocal):
  The two resolve scope operations could technically skip
  the op_resolve_scope, and simply perform
      op_mov dst, recordRegister
  but for now it seemed best to maintain the same basic
  behaviour.
(JSC::BytecodeGenerator::emitGetFromScope):
(JSC::BytecodeGenerator::emitPutToScope):
(JSC::BytecodeGenerator::createArgumentsIfNecessary):
  If we have an environment we've already created Arguments
  so no need to check again.
(JSC::BytecodeGenerator::emitReturn):
  Don't need to emit tearoff_environment
* bytecompiler/BytecodeGenerator.h:
(JSC::Local::Local):
(JSC::Local::operator bool):
(JSC::Local::get):
(JSC::Local::isReadOnly):
(JSC::Local::isSpecial):
(JSC::ResolveScopeInfo::ResolveScopeInfo):
(JSC::ResolveScopeInfo::isLocal):
(JSC::ResolveScopeInfo::localIndex):
(JSC::BytecodeGenerator::shouldCreateArgumentsEagerly):
(JSC::Local::isCaptured): Deleted.
(JSC::Local::captureMode): Deleted.
* bytecompiler/NodesCodegen.cpp:
(JSC::ResolveNode::emitBytecode):
(JSC::EvalFunctionCallNode::emitBytecode):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::PostfixNode::emitResolve):
(JSC::DeleteResolveNode::emitBytecode):
(JSC::TypeOfResolveNode::emitBytecode):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::ConstDeclNode::emitCodeSingle):
(JSC::EmptyVarExpression::emitBytecode):
(JSC::ForInNode::tryGetBoundLocal):
(JSC::ForInNode::emitLoopHeader):
(JSC::ForOfNode::emitBytecode):
(JSC::BindingNode::bindValue):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(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/DFGGraph.cpp:
(JSC::DFG::Graph::tryGetRegisters):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* interpreter/Interpreter.cpp:
(JSC::unwindCallFrame):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_captured_mov): Deleted.
(JSC::JIT::emit_op_tear_off_lexical_environment): Deleted.
(JSC::JIT::emitSlow_op_captured_mov): Deleted.
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_captured_mov): Deleted.
(JSC::JIT::emit_op_tear_off_lexical_environment): Deleted.
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_resolve_scope):
(JSC::JIT::emit_op_get_from_scope):
(JSC::JIT::emitPutClosureVar):
(JSC::JIT::emit_op_put_to_scope):
(JSC::JIT::emitSlow_op_put_to_scope):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_resolve_scope):
(JSC::JIT::emit_op_get_from_scope):
(JSC::JIT::emitPutClosureVar):
(JSC::JIT::emit_op_put_to_scope):
(JSC::JIT::emitSlow_op_put_to_scope):
* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/Arguments.cpp:
(JSC::Arguments::tearOff):
* runtime/Arguments.h:
(JSC::Arguments::argument):
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL): Deleted.
* runtime/CommonSlowPaths.h:
* runtime/JSLexicalEnvironment.cpp:
(JSC::JSLexicalEnvironment::visitChildren):
(JSC::JSLexicalEnvironment::symbolTableGet):
(JSC::JSLexicalEnvironment::symbolTablePut):
(JSC::JSLexicalEnvironment::getOwnNonIndexPropertyNames):
(JSC::JSLexicalEnvironment::getOwnPropertySlot):
(JSC::JSLexicalEnvironment::argumentsGetter):
* runtime/JSLexicalEnvironment.h:
(JSC::JSLexicalEnvironment::create):
(JSC::JSLexicalEnvironment::JSLexicalEnvironment):
(JSC::JSLexicalEnvironment::tearOff): Deleted.
(JSC::JSLexicalEnvironment::isTornOff): Deleted.
* runtime/JSScope.cpp:
(JSC::resolveTypeName):
* runtime/JSScope.h:
(JSC::makeType):
(JSC::needsVarInjectionChecks):
* runtime/WriteBarrier.h:
(JSC::WriteBarrier<Unknown>::WriteBarrier):

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

44 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/llint/LLIntData.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.h
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/runtime/Arguments.cpp
Source/JavaScriptCore/runtime/Arguments.h
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.h
Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp
Source/JavaScriptCore/runtime/JSLexicalEnvironment.h
Source/JavaScriptCore/runtime/JSScope.cpp
Source/JavaScriptCore/runtime/JSScope.h
Source/JavaScriptCore/runtime/WriteBarrier.h

index 8940871..7ce1f23 100644 (file)
@@ -1,3 +1,175 @@
+2014-10-01  Oliver Hunt  <oliver@apple.com>
+
+        Do all closed variable access through the local lexical object
+        https://bugs.webkit.org/show_bug.cgi?id=136869
+
+        Reviewed by Filip Pizlo.
+
+        This patch makes all reads and writes from captured registers
+        go through the lexical record, and by doing so removes the
+        need for record tearoff.
+
+        To keep the patch simple we still number variables as though
+        they are local stack allocated registers, but ::local() will
+        fail. When local fails we perform a generic resolve, and in
+        that resolve we now use a ResolveScopeInfo struct to pass
+        around information about whether a lookup is a statically
+        known captured variable, and its location in the activation.
+        To ensure correct behaviour during codeblock linking we also
+        add a LocalClosureVariable resolution type.
+
+        To ensure correct semantics for the Arguments object, we now
+        have to eagerly create the Arguments object for any function
+        that uses both the Arguments object and requires a lexical
+        record.
+
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        (JSC::CodeBlock::CodeBlock):
+        (JSC::CodeBlock::finalizeUnconditionally):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::initializeCapturedVariable):
+          During the entry to a function we are not yet in a position
+          to allocate temporaries so we directly use the lexical
+          environment register.
+        (JSC::BytecodeGenerator::resolveCallee):
+        (JSC::BytecodeGenerator::emitMove):
+        (JSC::BytecodeGenerator::local):
+        (JSC::BytecodeGenerator::constLocal):
+        (JSC::BytecodeGenerator::emitResolveScope):
+        (JSC::BytecodeGenerator::emitResolveConstantLocal):
+          The two resolve scope operations could technically skip
+          the op_resolve_scope, and simply perform 
+              op_mov dst, recordRegister
+          but for now it seemed best to maintain the same basic
+          behaviour.
+        (JSC::BytecodeGenerator::emitGetFromScope):
+        (JSC::BytecodeGenerator::emitPutToScope):
+        (JSC::BytecodeGenerator::createArgumentsIfNecessary):
+          If we have an environment we've already created Arguments
+          so no need to check again.
+        (JSC::BytecodeGenerator::emitReturn):
+          Don't need to emit tearoff_environment
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::Local::Local):
+        (JSC::Local::operator bool):
+        (JSC::Local::get):
+        (JSC::Local::isReadOnly):
+        (JSC::Local::isSpecial):
+        (JSC::ResolveScopeInfo::ResolveScopeInfo):
+        (JSC::ResolveScopeInfo::isLocal):
+        (JSC::ResolveScopeInfo::localIndex):
+        (JSC::BytecodeGenerator::shouldCreateArgumentsEagerly):
+        (JSC::Local::isCaptured): Deleted.
+        (JSC::Local::captureMode): Deleted.
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ResolveNode::emitBytecode):
+        (JSC::EvalFunctionCallNode::emitBytecode):
+        (JSC::FunctionCallResolveNode::emitBytecode):
+        (JSC::PostfixNode::emitResolve):
+        (JSC::DeleteResolveNode::emitBytecode):
+        (JSC::TypeOfResolveNode::emitBytecode):
+        (JSC::PrefixNode::emitResolve):
+        (JSC::ReadModifyResolveNode::emitBytecode):
+        (JSC::AssignResolveNode::emitBytecode):
+        (JSC::ConstDeclNode::emitCodeSingle):
+        (JSC::EmptyVarExpression::emitBytecode):
+        (JSC::ForInNode::tryGetBoundLocal):
+        (JSC::ForInNode::emitLoopHeader):
+        (JSC::ForOfNode::emitBytecode):
+        (JSC::BindingNode::bindValue):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (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/DFGGraph.cpp:
+        (JSC::DFG::Graph::tryGetRegisters):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * interpreter/Interpreter.cpp:
+        (JSC::unwindCallFrame):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileSlowCases):
+        * jit/JIT.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_captured_mov): Deleted.
+        (JSC::JIT::emit_op_tear_off_lexical_environment): Deleted.
+        (JSC::JIT::emitSlow_op_captured_mov): Deleted.
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_captured_mov): Deleted.
+        (JSC::JIT::emit_op_tear_off_lexical_environment): Deleted.
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_resolve_scope):
+        (JSC::JIT::emit_op_get_from_scope):
+        (JSC::JIT::emitPutClosureVar):
+        (JSC::JIT::emit_op_put_to_scope):
+        (JSC::JIT::emitSlow_op_put_to_scope):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_resolve_scope):
+        (JSC::JIT::emit_op_get_from_scope):
+        (JSC::JIT::emitPutClosureVar):
+        (JSC::JIT::emit_op_put_to_scope):
+        (JSC::JIT::emitSlow_op_put_to_scope):
+        * llint/LLIntData.cpp:
+        (JSC::LLInt::Data::performAssertions):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * llint/LLIntSlowPaths.h:
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/Arguments.cpp:
+        (JSC::Arguments::tearOff):
+        * runtime/Arguments.h:
+        (JSC::Arguments::argument):
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL): Deleted.
+        * runtime/CommonSlowPaths.h:
+        * runtime/JSLexicalEnvironment.cpp:
+        (JSC::JSLexicalEnvironment::visitChildren):
+        (JSC::JSLexicalEnvironment::symbolTableGet):
+        (JSC::JSLexicalEnvironment::symbolTablePut):
+        (JSC::JSLexicalEnvironment::getOwnNonIndexPropertyNames):
+        (JSC::JSLexicalEnvironment::getOwnPropertySlot):
+        (JSC::JSLexicalEnvironment::argumentsGetter):
+        * runtime/JSLexicalEnvironment.h:
+        (JSC::JSLexicalEnvironment::create):
+        (JSC::JSLexicalEnvironment::JSLexicalEnvironment):
+        (JSC::JSLexicalEnvironment::tearOff): Deleted.
+        (JSC::JSLexicalEnvironment::isTornOff): Deleted.
+        * runtime/JSScope.cpp:
+        (JSC::resolveTypeName):
+        * runtime/JSScope.h:
+        (JSC::makeType):
+        (JSC::needsVarInjectionChecks):
+        * runtime/WriteBarrier.h:
+        (JSC::WriteBarrier<Unknown>::WriteBarrier):
+
 2014-10-02  Filip Pizlo  <fpizlo@apple.com>
 
         Object allocation sinking should have a sound story for picking materialization points
index 850a956..4a9f12f 100644 (file)
@@ -17,7 +17,6 @@
             { "name" : "op_new_array_buffer", "length" : 5 },
             { "name" : "op_new_regexp", "length" : 3 },
             { "name" : "op_mov", "length" : 3 },
-            { "name" : "op_captured_mov", "length" : 4 },
             { "name" : "op_not", "length" : 3 },
             { "name" : "op_eq", "length" : 4 },
             { "name" : "op_eq_null", "length" : 3 },
@@ -99,7 +98,6 @@
             { "name" : "op_call", "length" : 9 },
             { "name" : "op_call_eval", "length" : 9 },
             { "name" : "op_call_varargs", "length" : 9 },
-            { "name" : "op_tear_off_lexical_environment", "length" : 2 },
             { "name" : "op_tear_off_arguments", "length" : 3 },
             { "name" : "op_ret", "length" : 2 },
             { "name" : "op_ret_object_or_this", "length" : 3 },
index 45b6548..00439bf 100644 (file)
@@ -62,7 +62,6 @@ void computeUsesForBytecodeOffset(
     case op_create_lexical_environment: 
     case op_create_arguments:
     case op_to_this:
-    case op_tear_off_lexical_environment:
     case op_profile_will_call:
     case op_profile_did_call:
     case op_profile_type:
@@ -141,7 +140,6 @@ void computeUsesForBytecodeOffset(
     case op_eq_null:
     case op_not:
     case op_mov:
-    case op_captured_mov:
     case op_new_array_with_size:
     case op_create_this:
     case op_del_by_id:
@@ -305,7 +303,6 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset,
     case op_next_enumerator_pname:
     case op_resolve_scope:
     case op_strcat:
-    case op_tear_off_lexical_environment:
     case op_to_primitive:
     case op_catch:
     case op_create_this:
@@ -365,7 +362,6 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset,
     case op_eq_null:
     case op_not:
     case op_mov:
-    case op_captured_mov:
     case op_new_object:
     case op_to_this:
     case op_get_callee:
index 04c1663..451be75 100644 (file)
@@ -833,14 +833,6 @@ void CodeBlock::dumpBytecode(
             out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
             break;
         }
-        case op_captured_mov: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "captured_mov");
-            out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
-            ++it;
-            break;
-        }
         case op_profile_type: {
             int r0 = (++it)->u.operand;
             ++it;
@@ -1316,12 +1308,7 @@ void CodeBlock::dumpBytecode(
             dumpValueProfiling(out, it, hasPrintedProfiling);
             break;
         }
-            
-        case op_tear_off_lexical_environment: {
-            int r0 = (++it)->u.operand;
-            printLocationOpAndRegisterOperand(out, exec, location, it, "tear_off_lexical_environment", r0);
-            break;
-        }
+
         case op_tear_off_arguments: {
             int r0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
@@ -1946,6 +1933,10 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
         case op_resolve_scope: {
             const Identifier& ident = identifier(pc[2].u.operand);
             ResolveType type = static_cast<ResolveType>(pc[3].u.operand);
+            if (type == LocalClosureVar) {
+                instructions[i + 3].u.operand = ClosureVar;
+                break;
+            }
 
             ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), needsActivation(), scope, ident, Get, type);
             instructions[i + 3].u.operand = op.type;
@@ -1962,8 +1953,14 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
             instructions[i + opLength - 1] = profile;
 
             // get_from_scope dst, scope, id, ResolveModeAndType, Structure, Operand
+
             const Identifier& ident = identifier(pc[3].u.operand);
             ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand);
+            if (modeAndType.type() == LocalClosureVar) {
+                instructions[i + 4] = ResolveModeAndType(modeAndType.mode(), ClosureVar).operand();
+                break;
+            }
+
             ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), needsActivation(), scope, ident, Get, modeAndType.type());
 
             instructions[i + 4].u.operand = ResolveModeAndType(modeAndType.mode(), op.type).operand();
@@ -1979,7 +1976,26 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
         case op_put_to_scope: {
             // put_to_scope scope, id, value, ResolveModeAndType, Structure, Operand
             const Identifier& ident = identifier(pc[2].u.operand);
+
             ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand);
+            if (modeAndType.type() == LocalClosureVar) {
+                if (pc[5].u.index == UINT_MAX) {
+                    instructions[i + 5].u.watchpointSet = 0;
+                    break;
+                }
+                StringImpl* uid = identifier(pc[5].u.index).impl();
+                RELEASE_ASSERT(didCloneSymbolTable);
+                if (ident != m_vm->propertyNames->arguments) {
+                    ConcurrentJITLocker locker(m_symbolTable->m_lock);
+                    SymbolTable::Map::iterator iter = m_symbolTable->find(locker, uid);
+                    ASSERT(iter != m_symbolTable->end(locker));
+                    iter->value.prepareToWatch(symbolTable());
+                    instructions[i + 5].u.watchpointSet = iter->value.watchpointSet();
+                } else
+                    instructions[i + 5].u.watchpointSet = nullptr;
+                break;
+            }
+
             ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), needsActivation(), scope, ident, Put, modeAndType.type());
 
             instructions[i + 4].u.operand = ResolveModeAndType(modeAndType.mode(), op.type).operand();
@@ -2031,6 +2047,19 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
 
                 break;
             }
+            case ProfileTypeBytecodePutToLocalScope:
+            case ProfileTypeBytecodeGetFromLocalScope: {
+                const Identifier& ident = identifier(pc[4].u.operand);
+                symbolTable = m_symbolTable.get();
+                ConcurrentJITLocker locker(symbolTable->m_lock);
+                // If our parent scope was created while profiling was disabled, it will not have prepared for profiling yet.
+                symbolTable->prepareForTypeProfiling(locker);
+                globalVariableID = symbolTable->uniqueIDForVariable(locker, ident.impl(), *vm());
+                globalTypeSet = symbolTable->globalTypeSetForVariable(locker, ident.impl(), *vm());
+
+                break;
+            }
+
             case ProfileTypeBytecodeHasGlobalID: {
                 symbolTable = m_symbolTable.get();
                 ConcurrentJITLocker locker(symbolTable->m_lock);
@@ -2075,7 +2104,6 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
             break;
         }
 
-        case op_captured_mov:
         case op_new_captured_func: {
             if (pc[3].u.index == UINT_MAX) {
                 instructions[i + 3].u.watchpointSet = 0;
@@ -2546,7 +2574,7 @@ void CodeBlock::finalizeUnconditionally()
             case op_put_to_scope: {
                 ResolveModeAndType modeAndType =
                     ResolveModeAndType(curInstruction[4].u.operand);
-                if (modeAndType.type() == GlobalVar || modeAndType.type() == GlobalVarWithVarInjectionChecks)
+                if (modeAndType.type() == GlobalVar || modeAndType.type() == GlobalVarWithVarInjectionChecks || modeAndType.type() == LocalClosureVar)
                     continue;
                 WriteBarrierBase<Structure>& structure = curInstruction[5].u.structure;
                 if (!structure || Heap::isMarked(structure.get()))
@@ -3868,7 +3896,6 @@ struct VerifyCapturedDef {
 
         switch (opcodeID) {
         case op_enter:
-        case op_captured_mov:
         case op_init_lazy_reg:
         case op_create_arguments:
         case op_new_captured_func:
@@ -3876,11 +3903,14 @@ struct VerifyCapturedDef {
         default:
             break;
         }
-        
+
         VirtualRegister virtualReg(operand);
         if (!virtualReg.isLocal())
             return;
-        
+
+        if (codeBlock->usesArguments() && virtualReg == codeBlock->argumentsRegister())
+            return;
+
         if (codeBlock->captureCount() && codeBlock->symbolTable()->isCaptured(operand)) {
             codeBlock->beginValidationDidFail();
             dataLog("    At bc#", bytecodeOffset, " encountered invalid assignment to captured variable loc", virtualReg.toLocal(), ".\n");
index 3e68154..326f810 100644 (file)
@@ -246,7 +246,6 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionBodyNode* functionBody, Unl
     emitOpcode(op_enter);
     if (m_codeBlock->needsFullScopeChain() || m_shouldEmitDebugHooks) {
         m_lexicalEnvironmentRegister = addVar();
-        emitInitLazyRegister(m_lexicalEnvironmentRegister);
         m_codeBlock->setActivationRegister(m_lexicalEnvironmentRegister->virtualRegister());
         emitOpcode(op_create_lexical_environment);
         instructions().append(m_lexicalEnvironmentRegister->index());
@@ -267,9 +266,15 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionBodyNode* functionBody, Unl
         emitInitLazyRegister(argumentsRegister);
         emitInitLazyRegister(unmodifiedArgumentsRegister);
         
-        if (shouldTearOffArgumentsEagerly()) {
+        if (shouldCreateArgumentsEagerly() || shouldTearOffArgumentsEagerly()) {
             emitOpcode(op_create_arguments);
             instructions().append(argumentsRegister->index());
+            if (m_codeBlock->hasActivationRegister()) {
+                RegisterID* argumentsRegister = &registerFor(m_codeBlock->argumentsRegister().offset());
+                initializeCapturedVariable(argumentsRegister, propertyNames().arguments, argumentsRegister);
+                RegisterID* uncheckedArgumentsRegister = &registerFor(JSC::unmodifiedArgumentsRegister(m_codeBlock->argumentsRegister()).offset());
+                initializeCapturedVariable(uncheckedArgumentsRegister, propertyNames().arguments, uncheckedArgumentsRegister);
+            }
         }
     }
 
@@ -316,23 +321,26 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionBodyNode* functionBody, Unl
 
     // Captured variables and functions go first so that activations don't have
     // to step over the non-captured locals to mark them.
-    if (functionBody->hasCapturedVariables()) {
+    if (functionBody->hasCapturedVariables() || shouldCaptureAllTheThings) {
         for (size_t i = 0; i < boundParameterProperties.size(); i++) {
             const Identifier& ident = boundParameterProperties[i];
-            if (functionBody->captures(ident))
+            if (functionBody->captures(ident) || shouldCaptureAllTheThings)
                 addVar(ident, IsVariable, IsWatchable);
         }
         for (size_t i = 0; i < functionStack.size(); ++i) {
             FunctionBodyNode* function = functionStack[i];
             const Identifier& ident = function->ident();
-            if (functionBody->captures(ident)) {
+            if (functionBody->captures(ident) || shouldCaptureAllTheThings) {
                 m_functions.add(ident.impl());
-                emitNewFunction(addVar(ident, IsVariable, IsWatchable), IsCaptured, function);
+                // We rely on still allocating stack space for captured variables
+                // here.
+                RegisterID* newFunction = emitNewFunction(addVar(ident, IsVariable, IsWatchable), IsCaptured, function);
+                initializeCapturedVariable(newFunction, ident, newFunction);
             }
         }
         for (size_t i = 0; i < varStack.size(); ++i) {
             const Identifier& ident = varStack[i].first;
-            if (functionBody->captures(ident))
+            if (functionBody->captures(ident) || shouldCaptureAllTheThings)
                 addVar(ident, (varStack[i].second & DeclarationStacks::IsConstant) ? IsConstant : IsVariable, IsWatchable);
         }
     }
@@ -341,37 +349,36 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionBodyNode* functionBody, Unl
 
     bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks && !m_vm->typeProfiler();
     m_firstLazyFunction = codeBlock->m_numVars;
-    for (size_t i = 0; i < functionStack.size(); ++i) {
-        FunctionBodyNode* function = functionStack[i];
-        const Identifier& ident = function->ident();
-        if (!functionBody->captures(ident)) {
-            m_functions.add(ident.impl());
-            RefPtr<RegisterID> reg = addVar(ident, IsVariable, NotWatchable);
-            // Don't lazily create functions that override the name 'arguments'
-            // as this would complicate lazy instantiation of actual arguments.
-            if (!canLazilyCreateFunctions || ident == propertyNames().arguments)
-                emitNewFunction(reg.get(), NotCaptured, function);
-            else {
-                emitInitLazyRegister(reg.get());
-                m_lazyFunctions.set(reg->virtualRegister().toLocal(), function);
+    if (!shouldCaptureAllTheThings) {
+        for (size_t i = 0; i < functionStack.size(); ++i) {
+            FunctionBodyNode* function = functionStack[i];
+            const Identifier& ident = function->ident();
+            if (!functionBody->captures(ident)) {
+                m_functions.add(ident.impl());
+                RefPtr<RegisterID> reg = addVar(ident, IsVariable, NotWatchable);
+                // Don't lazily create functions that override the name 'arguments'
+                // as this would complicate lazy instantiation of actual arguments.
+                if (!canLazilyCreateFunctions || ident == propertyNames().arguments)
+                    emitNewFunction(reg.get(), NotCaptured, function);
+                else {
+                    emitInitLazyRegister(reg.get());
+                    m_lazyFunctions.set(reg->virtualRegister().toLocal(), function);
+                }
             }
         }
-    }
-    m_lastLazyFunction = canLazilyCreateFunctions ? codeBlock->m_numVars : m_firstLazyFunction;
-    for (size_t i = 0; i < boundParameterProperties.size(); i++) {
-        const Identifier& ident = boundParameterProperties[i];
-        if (!functionBody->captures(ident))
-            addVar(ident, IsVariable, IsWatchable);
-    }
-    for (size_t i = 0; i < varStack.size(); ++i) {
-        const Identifier& ident = varStack[i].first;
-        if (!functionBody->captures(ident))
-            addVar(ident, (varStack[i].second & DeclarationStacks::IsConstant) ? IsConstant : IsVariable, NotWatchable);
+        m_lastLazyFunction = canLazilyCreateFunctions ? codeBlock->m_numVars : m_firstLazyFunction;
+        for (size_t i = 0; i < boundParameterProperties.size(); i++) {
+            const Identifier& ident = boundParameterProperties[i];
+            if (!functionBody->captures(ident))
+                addVar(ident, IsVariable, IsWatchable);
+        }
+        for (size_t i = 0; i < varStack.size(); ++i) {
+            const Identifier& ident = varStack[i].first;
+            if (!functionBody->captures(ident))
+                addVar(ident, (varStack[i].second & DeclarationStacks::IsConstant) ? IsConstant : IsVariable, NotWatchable);
+        }
     }
 
-    if (shouldCaptureAllTheThings)
-        m_symbolTable->setCaptureEnd(virtualRegisterForLocal(codeBlock->m_numVars).offset());
-
     if (m_symbolTable->captureCount())
         emitOpcode(op_touch_entry);
     
@@ -396,7 +403,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionBodyNode* functionBody, Unl
             ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(simpleParameter->boundProperty())) || shouldCaptureAllTheThings);
             index = capturedArguments[i]->index();
             RegisterID original(nextParameterIndex);
-            emitMove(capturedArguments[i], &original);
+            initializeCapturedVariable(capturedArguments[i], simpleParameter->boundProperty(), &original);
         }
         addParameter(simpleParameter->boundProperty(), index);
     }
@@ -476,6 +483,20 @@ RegisterID* BytecodeGenerator::emitInitLazyRegister(RegisterID* reg)
     return reg;
 }
 
+RegisterID* BytecodeGenerator::initializeCapturedVariable(RegisterID* dst, const Identifier& propertyName, RegisterID* value)
+{
+
+    m_codeBlock->addPropertyAccessInstruction(instructions().size());
+    emitOpcode(op_put_to_scope);
+    instructions().append(m_lexicalEnvironmentRegister->index());
+    instructions().append(addConstant(propertyName));
+    instructions().append(value->index());
+    instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand());
+    instructions().append(0);
+    instructions().append(dst->index());
+    return dst;
+}
+
 RegisterID* BytecodeGenerator::resolveCallee(FunctionBodyNode* functionBodyNode)
 {
     if (!functionNameIsInScope(functionBodyNode->ident(), functionBodyNode->functionMode()))
@@ -486,7 +507,7 @@ RegisterID* BytecodeGenerator::resolveCallee(FunctionBodyNode* functionBodyNode)
 
     m_calleeRegister.setIndex(JSStack::Callee);
     if (functionBodyNode->captures(functionBodyNode->ident()))
-        return emitMove(addVar(), IsCaptured, &m_calleeRegister);
+        return initializeCapturedVariable(addVar(), functionBodyNode->ident(), &m_calleeRegister);
 
     return &m_calleeRegister;
 }
@@ -996,15 +1017,13 @@ unsigned BytecodeGenerator::addRegExp(RegExp* r)
     return m_codeBlock->addRegExp(r);
 }
 
-RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, CaptureMode captureMode, RegisterID* src)
+RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
 {
     m_staticPropertyAnalyzer.mov(dst->index(), src->index());
-
-    emitOpcode(captureMode == IsCaptured ? op_captured_mov : op_mov);
+    ASSERT(dst->virtualRegister() == m_codeBlock->argumentsRegister() || !isCaptured(dst->index()));
+    emitOpcode(op_mov);
     instructions().append(dst->index());
     instructions().append(src->index());
-    if (captureMode == IsCaptured)
-        instructions().append(watchableVariable(dst->index()));
 
     if (!dst->isTemporary() && vm()->typeProfiler())
         emitProfileType(dst, ProfileTypeBytecodeHasGlobalID, nullptr);
@@ -1012,11 +1031,6 @@ RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, CaptureMode captureMode
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
-{
-    return emitMove(dst, captureMode(dst->index()), src);
-}
-
 RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src)
 {
     emitOpcode(opcodeID);
@@ -1197,9 +1211,9 @@ bool BytecodeGenerator::isCaptured(int operand)
 Local BytecodeGenerator::local(const Identifier& property)
 {
     if (property == propertyNames().thisIdentifier)
-        return Local(thisRegister(), ReadOnly, NotCaptured);
-    
-    if (property == propertyNames().arguments)
+        return Local(thisRegister(), ReadOnly, Local::SpecialLocal);
+    bool isArguments = property == propertyNames().arguments;
+    if (isArguments)
         createArgumentsIfNecessary();
 
     if (!shouldOptimizeLocals())
@@ -1209,8 +1223,13 @@ Local BytecodeGenerator::local(const Identifier& property)
     if (entry.isNull())
         return Local();
 
+
     RegisterID* local = createLazyRegisterIfNecessary(&registerFor(entry.getIndex()));
-    return Local(local, entry.getAttributes(), captureMode(local->index()));
+
+    if (isCaptured(local->index()) && m_lexicalEnvironmentRegister)
+        return Local();
+
+    return Local(local, entry.getAttributes(), isArguments ? Local::SpecialLocal : Local::NormalLocal);
 }
 
 Local BytecodeGenerator::constLocal(const Identifier& property)
@@ -1223,7 +1242,12 @@ Local BytecodeGenerator::constLocal(const Identifier& property)
         return Local();
 
     RegisterID* local = createLazyRegisterIfNecessary(&registerFor(entry.getIndex()));
-    return Local(local, entry.getAttributes(), captureMode(local->index()));
+
+    bool isArguments = property == propertyNames().arguments;
+    if (isCaptured(local->index()) && m_lexicalEnvironmentRegister)
+        return Local();
+
+    return Local(local, entry.getAttributes(), isArguments ? Local::SpecialLocal : Local::NormalLocal);
 }
 
 void BytecodeGenerator::emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target)
@@ -1247,10 +1271,24 @@ ResolveType BytecodeGenerator::resolveType()
     return GlobalProperty;
 }
 
-RegisterID* BytecodeGenerator::emitResolveScope(RegisterID* dst, const Identifier& identifier)
+RegisterID* BytecodeGenerator::emitResolveScope(RegisterID* dst, const Identifier& identifier, ResolveScopeInfo& info)
 {
     m_codeBlock->addPropertyAccessInstruction(instructions().size());
 
+    if (m_symbolTable && m_codeType == FunctionCode && !m_localScopeDepth) {
+        SymbolTableEntry entry = m_symbolTable->get(identifier.impl());
+        if (!entry.isNull()) {
+            emitOpcode(op_resolve_scope);
+            instructions().append(kill(dst));
+            instructions().append(addConstant(identifier));
+            instructions().append(LocalClosureVar);
+            instructions().append(0);
+            instructions().append(0);
+            info = ResolveScopeInfo(entry.getIndex());
+            return dst;
+        }
+    }
+
     ASSERT(!m_symbolTable || !m_symbolTable->contains(identifier.impl()) || resolveType() == Dynamic);
 
     // resolve_scope dst, id, ResolveType, depth
@@ -1263,7 +1301,20 @@ RegisterID* BytecodeGenerator::emitResolveScope(RegisterID* dst, const Identifie
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitGetFromScope(RegisterID* dst, RegisterID* scope, const Identifier& identifier, ResolveMode resolveMode)
+RegisterID* BytecodeGenerator::emitResolveConstantLocal(RegisterID* dst, const Identifier& identifier, ResolveScopeInfo& info)
+{
+    if (!m_symbolTable || m_codeType != FunctionCode)
+        return nullptr;
+
+    SymbolTableEntry entry = m_symbolTable->get(identifier.impl());
+    if (entry.isNull())
+        return nullptr;
+    info = ResolveScopeInfo(entry.getIndex());
+    return emitMove(dst, m_lexicalEnvironmentRegister);
+
+}
+
+RegisterID* BytecodeGenerator::emitGetFromScope(RegisterID* dst, RegisterID* scope, const Identifier& identifier, ResolveMode resolveMode, const ResolveScopeInfo& info)
 {
     m_codeBlock->addPropertyAccessInstruction(instructions().size());
 
@@ -1272,14 +1323,14 @@ RegisterID* BytecodeGenerator::emitGetFromScope(RegisterID* dst, RegisterID* sco
     instructions().append(kill(dst));
     instructions().append(scope->index());
     instructions().append(addConstant(identifier));
-    instructions().append(ResolveModeAndType(resolveMode, resolveType()).operand());
-    instructions().append(0);
+    instructions().append(ResolveModeAndType(resolveMode, info.isLocal() ? LocalClosureVar : resolveType()).operand());
     instructions().append(0);
+    instructions().append(info.localIndex());
     instructions().append(profile);
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitPutToScope(RegisterID* scope, const Identifier& identifier, RegisterID* value, ResolveMode resolveMode)
+RegisterID* BytecodeGenerator::emitPutToScope(RegisterID* scope, const Identifier& identifier, RegisterID* value, ResolveMode resolveMode, const ResolveScopeInfo& info)
 {
     m_codeBlock->addPropertyAccessInstruction(instructions().size());
 
@@ -1288,9 +1339,14 @@ RegisterID* BytecodeGenerator::emitPutToScope(RegisterID* scope, const Identifie
     instructions().append(scope->index());
     instructions().append(addConstant(identifier));
     instructions().append(value->index());
-    instructions().append(ResolveModeAndType(resolveMode, resolveType()).operand());
-    instructions().append(0);
-    instructions().append(0);
+    if (info.isLocal()) {
+        instructions().append(ResolveModeAndType(resolveMode, LocalClosureVar).operand());
+        instructions().append(watchableVariable(registerFor(info.localIndex()).index()));
+    } else {
+        instructions().append(ResolveModeAndType(resolveMode, resolveType()).operand());
+        instructions().append(0);
+    }
+    instructions().append(info.localIndex());
     return value;
 }
 
@@ -1659,7 +1715,7 @@ void BytecodeGenerator::createArgumentsIfNecessary()
     if (!m_codeBlock->usesArguments())
         return;
 
-    if (shouldTearOffArgumentsEagerly())
+    if (shouldTearOffArgumentsEagerly() || shouldCreateArgumentsEagerly())
         return;
 
     emitOpcode(op_create_arguments);
@@ -1855,11 +1911,6 @@ RegisterID* BytecodeGenerator::emitCallVarargs(OpcodeID opcode, RegisterID* dst,
 
 RegisterID* BytecodeGenerator::emitReturn(RegisterID* src)
 {
-    if (m_lexicalEnvironmentRegister) {
-        emitOpcode(op_tear_off_lexical_environment);
-        instructions().append(m_lexicalEnvironmentRegister->index());
-    }
-
     if (m_codeBlock->usesArguments() && m_codeBlock->numParameters() != 1 && !isStrictMode()) {
         emitOpcode(op_tear_off_arguments);
         instructions().append(m_codeBlock->argumentsRegister().offset());
index 01c619a..48506fc 100644 (file)
@@ -189,29 +189,51 @@ namespace JSC {
         Local()
             : m_local(0)
             , m_attributes(0)
+            , m_kind(NormalLocal)
         {
         }
 
-        Local(RegisterID* local, unsigned attributes, CaptureMode captureMode)
+        enum LocalKind { NormalLocal, SpecialLocal };
+
+        Local(RegisterID* local, unsigned attributes, LocalKind kind)
             : m_local(local)
             , m_attributes(attributes)
-            , m_isCaptured(captureMode == IsCaptured)
+            , m_kind(kind)
         {
         }
 
-        operator bool() { return m_local; }
+        operator bool() const { return m_local; }
 
-        RegisterID* get() { return m_local; }
+        RegisterID* get() const { return m_local; }
 
-        bool isReadOnly() { return m_attributes & ReadOnly; }
-        
-        bool isCaptured() { return m_isCaptured; }
-        CaptureMode captureMode() { return isCaptured() ? IsCaptured : NotCaptured; }
+        bool isReadOnly() const { return m_attributes & ReadOnly; }
+        bool isSpecial() const { return m_kind != NormalLocal; }
 
     private:
         RegisterID* m_local;
         unsigned m_attributes;
-        bool m_isCaptured;
+        LocalKind m_kind;
+    };
+
+    struct ResolveScopeInfo {
+        ResolveScopeInfo()
+            : m_localIndex(0)
+            , m_resolveScopeKind(NonLocalScope)
+        {
+        }
+
+        ResolveScopeInfo(int index)
+            : m_localIndex(index)
+            , m_resolveScopeKind(LocalScope)
+        {
+        }
+
+        bool isLocal() const { return m_resolveScopeKind == LocalScope; }
+        int localIndex() const { return m_localIndex; }
+
+    private:
+        int m_localIndex;
+        enum { LocalScope, NonLocalScope } m_resolveScopeKind;
     };
 
     struct TryRange {
@@ -223,6 +245,8 @@ namespace JSC {
     enum ProfileTypeBytecodeFlag {
         ProfileTypeBytecodePutToScope,
         ProfileTypeBytecodeGetFromScope,
+        ProfileTypeBytecodePutToLocalScope,
+        ProfileTypeBytecodeGetFromLocalScope,
         ProfileTypeBytecodeHasGlobalID,
         ProfileTypeBytecodeDoesNotHaveGlobalID,
         ProfileTypeBytecodeFunctionArgument,
@@ -431,7 +455,6 @@ namespace JSC {
         RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func);
         RegisterID* emitNewRegExp(RegisterID* dst, RegExp*);
 
-        RegisterID* emitMove(RegisterID* dst, CaptureMode, RegisterID* src);
         RegisterID* emitMove(RegisterID* dst, RegisterID* src);
 
         RegisterID* emitToNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_number, dst, src); }
@@ -473,9 +496,10 @@ namespace JSC {
         void emitToPrimitive(RegisterID* dst, RegisterID* src);
 
         ResolveType resolveType();
-        RegisterID* emitResolveScope(RegisterID* dst, const Identifier&);
-        RegisterID* emitGetFromScope(RegisterID* dst, RegisterID* scope, const Identifier&, ResolveMode);
-        RegisterID* emitPutToScope(RegisterID* scope, const Identifier&, RegisterID* value, ResolveMode);
+        RegisterID* emitResolveConstantLocal(RegisterID* dst, const Identifier&, ResolveScopeInfo&);
+        RegisterID* emitResolveScope(RegisterID* dst, const Identifier&, ResolveScopeInfo&);
+        RegisterID* emitGetFromScope(RegisterID* dst, RegisterID* scope, const Identifier&, ResolveMode, const ResolveScopeInfo&);
+        RegisterID* emitPutToScope(RegisterID* scope, const Identifier&, RegisterID* value, ResolveMode, const ResolveScopeInfo&);
 
         PassRefPtr<Label> emitLabel(Label*);
         void emitLoopHint();
@@ -633,7 +657,8 @@ namespace JSC {
         
         RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
         RegisterID* emitCallVarargs(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
-        
+        RegisterID* initializeCapturedVariable(RegisterID* dst, const Identifier&, RegisterID*);
+
     public:
         JSString* addStringConstant(const Identifier&);
 
@@ -671,6 +696,13 @@ namespace JSC {
             return m_codeType == FunctionCode && isStrictMode() && m_scopeNode->modifiesParameter();
         }
 
+        bool shouldCreateArgumentsEagerly()
+        {
+            if (m_codeType != FunctionCode)
+                return false;
+            return m_lexicalEnvironmentRegister && m_codeBlock->usesArguments();
+        }
+
         RegisterID* emitThrowExpressionTooDeepException();
 
         void createArgumentsIfNecessary();
index 8187e98..4b4e5a7 100644 (file)
@@ -168,11 +168,12 @@ RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID*
     
     JSTextPosition divot = m_start + m_ident.length();
     generator.emitExpressionInfo(divot, m_start, divot);
-    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), m_ident);
+    ResolveScopeInfo resolveScopeInfo;
+    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), m_ident, resolveScopeInfo);
     RegisterID* finalDest = generator.finalDestination(dst);
-    RegisterID* result = generator.emitGetFromScope(finalDest, scope.get(), m_ident, ThrowIfNotFound);
+    RegisterID* result = generator.emitGetFromScope(finalDest, scope.get(), m_ident, ThrowIfNotFound, resolveScopeInfo);
     if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(finalDest, ProfileTypeBytecodeGetFromScope, &m_ident);
+        generator.emitProfileType(finalDest, resolveScopeInfo.isLocal() ? ProfileTypeBytecodeGetFromLocalScope : ProfileTypeBytecodeGetFromScope, &m_ident);
         generator.emitTypeProfilerExpressionInfo(m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1));
     }
     return result;
@@ -489,8 +490,9 @@ RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, Reg
     CallArguments callArguments(generator, m_args);
     JSTextPosition newDivot = divotStart() + 4;
     generator.emitExpressionInfo(newDivot, divotStart(), newDivot);
-    generator.emitResolveScope(callArguments.thisRegister(), generator.propertyNames().eval);
-    generator.emitGetFromScope(func.get(), callArguments.thisRegister(), generator.propertyNames().eval, ThrowIfNotFound);
+    ResolveScopeInfo resolveScopeInfo;
+    generator.emitResolveScope(callArguments.thisRegister(), generator.propertyNames().eval, resolveScopeInfo);
+    generator.emitGetFromScope(func.get(), callArguments.thisRegister(), generator.propertyNames().eval, ThrowIfNotFound, resolveScopeInfo);
     return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd());
 }
 
@@ -537,8 +539,9 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
 
     JSTextPosition newDivot = divotStart() + m_ident.length();
     generator.emitExpressionInfo(newDivot, divotStart(), newDivot);
-    generator.emitResolveScope(callArguments.thisRegister(), m_ident);
-    generator.emitGetFromScope(func.get(), callArguments.thisRegister(), m_ident, ThrowIfNotFound);
+    ResolveScopeInfo resolveScopeInfo;
+    generator.emitResolveScope(callArguments.thisRegister(), m_ident, resolveScopeInfo);
+    generator.emitGetFromScope(func.get(), callArguments.thisRegister(), m_ident, ThrowIfNotFound, resolveScopeInfo);
     RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd());
     if (generator.vm()->typeProfiler()) {
         generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr);
@@ -802,7 +805,7 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
         if (local.isReadOnly()) {
             generator.emitReadOnlyExceptionIfNeeded();
             localReg = generator.emitMove(generator.tempDestination(dst), localReg);
-        } else if (local.isCaptured() || generator.vm()->typeProfiler()) {
+        } else if (generator.vm()->typeProfiler()) {
             RefPtr<RegisterID> tempDst = generator.finalDestination(dst);
             ASSERT(dst != localReg);
             RefPtr<RegisterID> tempDstSrc = generator.newTemporary();
@@ -818,12 +821,13 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
     }
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), ident);
-    RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), ident, ThrowIfNotFound);
+    ResolveScopeInfo resolveScopeInfo;
+    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), ident, resolveScopeInfo);
+    RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), ident, ThrowIfNotFound, resolveScopeInfo);
     RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
-    generator.emitPutToScope(scope.get(), ident, value.get(), ThrowIfNotFound);
+    generator.emitPutToScope(scope.get(), ident, value.get(), ThrowIfNotFound, resolveScopeInfo);
     if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(value.get(), ProfileTypeBytecodePutToScope, &ident);
+        generator.emitProfileType(value.get(), resolveScopeInfo.isLocal() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident);
         generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
     }
 
@@ -903,7 +907,8 @@ RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
         return generator.emitLoad(generator.finalDestination(dst), false);
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    RefPtr<RegisterID> base = generator.emitResolveScope(generator.tempDestination(dst), m_ident);
+    ResolveScopeInfo resolveScopeInfo;
+    RefPtr<RegisterID> base = generator.emitResolveScope(generator.tempDestination(dst), m_ident, resolveScopeInfo);
     return generator.emitDeleteById(generator.finalDestination(dst, base.get()), base.get(), m_ident);
 }
 
@@ -960,8 +965,9 @@ RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
         return generator.emitTypeOf(generator.finalDestination(dst), local.get());
     }
 
-    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), m_ident);
-    RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, DoNotThrowIfNotFound);
+    ResolveScopeInfo resolveScopeInfo;
+    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), m_ident, resolveScopeInfo);
+    RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, DoNotThrowIfNotFound, resolveScopeInfo);
     if (dst == generator.ignoredResult())
         return 0;
     return generator.emitTypeOf(generator.finalDestination(dst, scope.get()), value.get());
@@ -992,7 +998,7 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
         if (local.isReadOnly()) {
             generator.emitReadOnlyExceptionIfNeeded();
             localReg = generator.emitMove(generator.tempDestination(dst), localReg);
-        } else if (local.isCaptured() || generator.vm()->typeProfiler()) {
+        } else if (generator.vm()->typeProfiler()) {
             RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
             generator.emitMove(tempDst.get(), localReg);
             emitIncOrDec(generator, tempDst.get(), m_operator);
@@ -1006,12 +1012,13 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
     }
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), ident);
-    RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), ident, ThrowIfNotFound);
+    ResolveScopeInfo resolveScopeInfo;
+    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), ident, resolveScopeInfo);
+    RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), ident, ThrowIfNotFound, resolveScopeInfo);
     emitIncOrDec(generator, value.get(), m_operator);
-    generator.emitPutToScope(scope.get(), ident, value.get(), ThrowIfNotFound);
+    generator.emitPutToScope(scope.get(), ident, value.get(), ThrowIfNotFound, resolveScopeInfo);
     if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(value.get(), ProfileTypeBytecodePutToScope, &ident);
+        generator.emitProfileType(value.get(), resolveScopeInfo.isLocal() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident);
         generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
     }
     return generator.moveToDestinationIfNeeded(dst, value.get());
@@ -1505,8 +1512,7 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
             return emitReadModifyAssignment(generator, generator.finalDestination(dst), local.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
         }
         
-        if (local.isCaptured()
-            || generator.vm()->typeProfiler()
+        if (generator.vm()->typeProfiler()
             || generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) {
             RefPtr<RegisterID> result = generator.newTemporary();
             generator.emitMove(result.get(), local.get());
@@ -1524,12 +1530,13 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
     }
 
     generator.emitExpressionInfo(newDivot, divotStart(), newDivot);
-    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident);
-    RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, ThrowIfNotFound);
+    ResolveScopeInfo resolveScopeInfo;
+    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident, resolveScopeInfo);
+    RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, ThrowIfNotFound, resolveScopeInfo);
     RefPtr<RegisterID> result = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this);
-    RegisterID* returnResult = generator.emitPutToScope(scope.get(), m_ident, result.get(), ThrowIfNotFound);
+    RegisterID* returnResult = generator.emitPutToScope(scope.get(), m_ident, result.get(), ThrowIfNotFound, resolveScopeInfo);
     if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(result.get(), ProfileTypeBytecodePutToScope, &m_ident);
+        generator.emitProfileType(result.get(), resolveScopeInfo.isLocal() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_ident);
         generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
     }
     return returnResult;
@@ -1544,7 +1551,7 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
             generator.emitReadOnlyExceptionIfNeeded();
             return generator.emitNode(dst, m_right);
         }
-        if (local.isCaptured() || generator.vm()->typeProfiler()) {
+        if (local.isSpecial() || generator.vm()->typeProfiler()) {
             RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
             generator.emitNode(tempDst.get(), m_right);
             generator.emitMove(local.get(), tempDst.get());
@@ -1560,14 +1567,15 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
 
     if (generator.isStrictMode())
         generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident);
+    ResolveScopeInfo resolveScopeInfo;
+    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident, resolveScopeInfo);
     if (dst == generator.ignoredResult())
         dst = 0;
     RefPtr<RegisterID> result = generator.emitNode(dst, m_right);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    RegisterID* returnResult = generator.emitPutToScope(scope.get(), m_ident, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+    RegisterID* returnResult = generator.emitPutToScope(scope.get(), m_ident, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, resolveScopeInfo);
     if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(result.get(), ProfileTypeBytecodePutToScope, &m_ident);
+        generator.emitProfileType(result.get(), resolveScopeInfo.isLocal() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_ident);
         generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
     } 
     return returnResult;
@@ -1676,7 +1684,7 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator)
             return local.get();
 
         // FIXME: Maybe call emitExpressionInfo here.
-        if (local.isCaptured() || generator.vm()->typeProfiler()) {
+        if (local.isSpecial() || generator.vm()->typeProfiler()) {
             RefPtr<RegisterID> tempDst = generator.newTemporary();
             generator.emitNode(tempDst.get(), m_init);
             return generator.emitMove(local.get(), tempDst.get());
@@ -1690,12 +1698,19 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator)
     if (generator.codeType() == GlobalCode)
         return generator.emitInitGlobalConst(m_ident, value.get());
 
-    if (generator.codeType() != EvalCode)
+    if (generator.codeType() != EvalCode) {
+
+        ResolveScopeInfo resolveScopeInfo;
+        if (RefPtr<RegisterID> scope = generator.emitResolveConstantLocal(generator.newTemporary(), m_ident, resolveScopeInfo))
+            return generator.emitPutToScope(scope.get(), m_ident, value.get(), DoNotThrowIfNotFound, resolveScopeInfo);
+
         return value.get();
+    }
 
     // FIXME: This will result in incorrect assignment if m_ident exists in an intervening with scope.
-    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident);
-    return generator.emitPutToScope(scope.get(), m_ident, value.get(), DoNotThrowIfNotFound);
+    ResolveScopeInfo resolveScopeInfo;
+    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident, resolveScopeInfo);
+    return generator.emitPutToScope(scope.get(), m_ident, value.get(), DoNotThrowIfNotFound, resolveScopeInfo);
 }
 
 RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
@@ -1792,9 +1807,10 @@ RegisterID* EmptyVarExpression::emitBytecode(BytecodeGenerator& generator, Regis
     if (Local local = generator.local(m_ident))
         generator.emitProfileType(local.get(), ProfileTypeBytecodeHasGlobalID, nullptr);
     else {
-        RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident);
-        RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, DoNotThrowIfNotFound);
-        generator.emitProfileType(value.get(), ProfileTypeBytecodeGetFromScope, &m_ident);
+        ResolveScopeInfo resolveScopeInfo;
+        RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident, resolveScopeInfo);
+        RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, DoNotThrowIfNotFound, resolveScopeInfo);
+        generator.emitProfileType(value.get(), resolveScopeInfo.isLocal() ? ProfileTypeBytecodeGetFromLocalScope : ProfileTypeBytecodeGetFromScope, &m_ident);
     }
 
     generator.emitTypeProfilerExpressionInfo(position(), JSTextPosition(-1, position().offset + m_ident.length(), -1));
@@ -1955,8 +1971,6 @@ RegisterID* ForInNode::tryGetBoundLocal(BytecodeGenerator& generator)
     if (m_lexpr->isResolveNode()) {
         const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier();
         Local local = generator.local(ident);
-        if (local.isCaptured())
-            return nullptr;
         return local.get();
     }
 
@@ -1969,7 +1983,7 @@ RegisterID* ForInNode::tryGetBoundLocal(BytecodeGenerator& generator)
         auto simpleBinding = static_cast<BindingNode*>(binding);
         const Identifier& ident = simpleBinding->boundProperty();
         Local local = generator.local(ident);
-        if (local.isCaptured())
+        if (local.isSpecial())
             return nullptr;
         return local.get();
     }
@@ -1987,9 +2001,10 @@ void ForInNode::emitLoopHeader(BytecodeGenerator& generator, RegisterID* propert
         else {
             if (generator.isStrictMode())
                 generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-            RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident);
+            ResolveScopeInfo resolveScopeInfo;
+            RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident, resolveScopeInfo);
             generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-            generator.emitPutToScope(scope, ident, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+            generator.emitPutToScope(scope, ident, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, resolveScopeInfo);
         }
         return;
     }
@@ -2021,7 +2036,7 @@ void ForInNode::emitLoopHeader(BytecodeGenerator& generator, RegisterID* propert
         auto simpleBinding = static_cast<BindingNode*>(binding);
         const Identifier& ident = simpleBinding->boundProperty();
         Local local = generator.local(ident);
-        if (!local.get() || local.isCaptured()) {
+        if (!local.get() || local.isSpecial()) {
             assignNode->bindings()->bindValue(generator, propertyName);
             return;
         }
@@ -2183,9 +2198,10 @@ void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
             else {
                 if (generator.isStrictMode())
                     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-                RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident);
+                ResolveScopeInfo resolveScopeInfo;
+                RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident, resolveScopeInfo);
                 generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-                generator.emitPutToScope(scope, ident, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+                generator.emitPutToScope(scope, ident, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, resolveScopeInfo);
             }
         } else if (m_lexpr->isDotAccessorNode()) {
             DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr);
@@ -2822,11 +2838,12 @@ void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) con
     }
     if (generator.isStrictMode())
         generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
-    RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), m_boundProperty);
+    ResolveScopeInfo resolveScopeInfo;
+    RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), m_boundProperty, resolveScopeInfo);
     generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
-    generator.emitPutToScope(scope, m_boundProperty, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+    generator.emitPutToScope(scope, m_boundProperty, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, resolveScopeInfo);
     if (generator.vm()->typeProfiler()) {
-        generator.emitProfileType(value, ProfileTypeBytecodePutToScope, &m_boundProperty);
+        generator.emitProfileType(value, resolveScopeInfo.isLocal() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_boundProperty);
         generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
     }
     return;
index 842630e..c309db3 100644 (file)
@@ -1299,7 +1299,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         forNode(node).merge(SpecArguments);
         break;
         
-    case TearOffActivation:
     case TearOffArguments:
         // Does nothing that is user-visible.
         break;
index a1d939e..1eecf3c 100644 (file)
@@ -2630,16 +2630,6 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             set(VirtualRegister(currentInstruction[1].u.operand), op);
             NEXT_OPCODE(op_mov);
         }
-            
-        case op_captured_mov: {
-            Node* op = get(VirtualRegister(currentInstruction[2].u.operand));
-            if (VariableWatchpointSet* set = currentInstruction[3].u.watchpointSet) {
-                if (set->state() != IsInvalidated)
-                    addToGraph(NotifyWrite, OpInfo(set), op);
-            }
-            set(VirtualRegister(currentInstruction[1].u.operand), op);
-            NEXT_OPCODE(op_captured_mov);
-        }
 
         case op_check_has_instance:
             addToGraph(CheckHasInstance, get(VirtualRegister(currentInstruction[3].u.operand)));
@@ -3196,6 +3186,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             case GlobalVarWithVarInjectionChecks:
                 set(VirtualRegister(dst), weakJSConstant(m_inlineStackTop->m_codeBlock->globalObject()));
                 break;
+            case LocalClosureVar:
             case ClosureVar:
             case ClosureVarWithVarInjectionChecks: {
                 JSLexicalEnvironment* lexicalEnvironment = currentInstruction[5].u.lexicalEnvironment.get();
@@ -3271,6 +3262,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                 set(VirtualRegister(dst), weakJSConstant(inferredValue));
                 break;
             }
+            case LocalClosureVar:
             case ClosureVar:
             case ClosureVarWithVarInjectionChecks: {
                 Node* scopeNode = get(VirtualRegister(scope));
@@ -3314,7 +3306,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             uintptr_t operand;
             {
                 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
-                if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks)
+                if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == LocalClosureVar)
                     watchpoints = currentInstruction[5].u.watchpointSet;
                 else
                     structure = currentInstruction[5].u.structure.get();
@@ -3353,11 +3345,17 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                 addToGraph(Phantom, get(VirtualRegister(scope)));
                 break;
             }
+            case LocalClosureVar:
             case ClosureVar:
             case ClosureVarWithVarInjectionChecks: {
                 Node* scopeNode = get(VirtualRegister(scope));
                 Node* scopeRegisters = addToGraph(GetClosureRegisters, scopeNode);
-                addToGraph(PutClosureVar, OpInfo(operand), scopeNode, scopeRegisters, get(VirtualRegister(value)));
+                Node* valueNode = get(VirtualRegister(value));
+
+                if (watchpoints && watchpoints->state() != IsInvalidated)
+                    addToGraph(NotifyWrite, OpInfo(watchpoints), valueNode);
+
+                addToGraph(PutClosureVar, OpInfo(operand), scopeNode, scopeRegisters, valueNode);
                 break;
             }
             case Dynamic:
@@ -3406,11 +3404,6 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             set(unmodifiedArgumentsRegister(VirtualRegister(currentInstruction[1].u.operand)), createArguments);
             NEXT_OPCODE(op_create_arguments);
         }
-            
-        case op_tear_off_lexical_environment: {
-            addToGraph(TearOffActivation, get(VirtualRegister(currentInstruction[1].u.operand)));
-            NEXT_OPCODE(op_tear_off_lexical_environment);
-        }
 
         case op_tear_off_arguments: {
             m_graph.m_hasArguments = true;
index 220a1e3..33e2f05 100644 (file)
@@ -122,7 +122,6 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
     case op_profile_did_call:
     case op_profile_type:
     case op_mov:
-    case op_captured_mov:
     case op_check_has_instance:
     case op_instanceof:
     case op_is_undefined:
@@ -232,7 +231,6 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
 
     case op_new_regexp: 
     case op_create_lexical_environment:
-    case op_tear_off_lexical_environment:
     case op_new_func:
     case op_new_captured_func:
     case op_new_func_exp:
index 60f884f..aed5c99 100644 (file)
@@ -848,11 +848,6 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
             RELEASE_ASSERT_NOT_REACHED();
             return;
         }
-
-    case TearOffActivation:
-        read(Variables);
-        write(JSEnvironmentRecord_registers);
-        return;
         
     case TearOffArguments:
         read(Variables);
index fd17065..bf45abc 100644 (file)
@@ -138,7 +138,6 @@ bool doesGC(Graph& graph, Node* node)
     case ToPrimitive:
     case ToString:
     case In:
-    case TearOffActivation:
     case PhantomArguments:
     case TearOffArguments:
     case GetMyArgumentsLength:
index 0b9501a..adb900a 100644 (file)
@@ -1040,14 +1040,6 @@ private:
             break;
         }
 
-        case TearOffActivation: {
-            Node* barrierNode = m_graph.addNode(
-                SpecNone, StoreBarrierWithNullCheck, m_currentNode->origin, 
-                Edge(node->child1().node(), UntypedUse));
-            m_insertionSet.insert(m_indexInBlock, barrierNode);
-            break;
-        }
-
         case IsString:
             if (node->child1()->shouldSpeculateString()) {
                 m_insertionSet.insertNode(
index e5b5718..4df7e86 100644 (file)
@@ -1013,8 +1013,6 @@ WriteBarrierBase<Unknown>* Graph::tryGetRegisters(Node* node)
     JSLexicalEnvironment* lexicalEnvironment = tryGetActivation(node);
     if (!lexicalEnvironment)
         return 0;
-    if (!lexicalEnvironment->isTornOff())
-        return 0;
     return lexicalEnvironment->registers();
 }
 
index fb5c6fa..5670630 100644 (file)
@@ -263,7 +263,6 @@ namespace JSC { namespace DFG {
     /* epilgoues via TearOffActivation, and all CreateActivation nodes kept alive by */\
     /* being threaded with each other. */\
     macro(CreateActivation, NodeResultJS) \
-    macro(TearOffActivation, NodeMustGenerate) \
     \
     /* Nodes used for arguments. Similar to lexical environment support, only it makes even less */\
     /* sense. */\
index 6b5f043..4181075 100644 (file)
@@ -656,7 +656,6 @@ private:
         case CheckCell:
         case CheckBadCell:
         case PutStructure:
-        case TearOffActivation:
         case TearOffArguments:
         case CheckArgumentsNotCreated:
         case VariableWatchpoint:
index f4e7cb7..e0f720c 100644 (file)
@@ -217,7 +217,6 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case MakeRope:
     case In:
     case CreateActivation:
-    case TearOffActivation:
     case CreateArguments:
     case PhantomArguments:
     case TearOffArguments:
index 7fc4068..9a6dad9 100644 (file)
@@ -4170,21 +4170,11 @@ void SpeculativeJIT::compile(Node* node)
         break;
 
     case CreateActivation: {
-        JSValueOperand value(this, node->child1());
-        GPRTemporary result(this, Reuse, value, PayloadWord);
-        
-        GPRReg valueTagGPR = value.tagGPR();
-        GPRReg valuePayloadGPR = value.payloadGPR();
+        GPRTemporary result(this);
         GPRReg resultGPR = result.gpr();
-        
-        m_jit.move(valuePayloadGPR, resultGPR);
-        
-        JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
-        
-        addSlowPathGenerator(
-            slowPathCall(
-                notCreated, this, operationCreateActivation, resultGPR,
-                framePointerOffsetToGetActivationRegisters()));
+
+        flushRegisters();
+        callOperation(operationCreateActivation, resultGPR, framePointerOffsetToGetActivationRegisters());
         
         cellResult(resultGPR, node);
         break;
@@ -4242,45 +4232,6 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
         
-    case TearOffActivation: {
-        JSValueOperand activationValue(this, node->child1());
-        GPRTemporary scratch(this);
-        
-        GPRReg activationValueTagGPR = activationValue.tagGPR();
-        GPRReg activationValuePayloadGPR = activationValue.payloadGPR();
-        GPRReg scratchGPR = scratch.gpr();
-
-        JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, activationValueTagGPR, TrustedImm32(JSValue::EmptyValueTag));
-
-        SymbolTable* symbolTable = m_jit.symbolTableFor(node->origin.semantic);
-        int registersOffset = JSLexicalEnvironment::registersOffset(symbolTable);
-
-        int bytecodeCaptureStart = symbolTable->captureStart();
-        int machineCaptureStart = m_jit.graph().m_machineCaptureStart;
-        for (int i = symbolTable->captureCount(); i--;) {
-            m_jit.loadPtr(
-                JITCompiler::Address(
-                    GPRInfo::callFrameRegister, (machineCaptureStart - i) * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
-                scratchGPR);
-            m_jit.storePtr(
-                scratchGPR, JITCompiler::Address(
-                    activationValuePayloadGPR, registersOffset + (bytecodeCaptureStart - i) * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
-            m_jit.loadPtr(
-                JITCompiler::Address(
-                    GPRInfo::callFrameRegister, (machineCaptureStart - i) * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
-                scratchGPR);
-            m_jit.storePtr(
-                scratchGPR, JITCompiler::Address(
-                    activationValuePayloadGPR, registersOffset + (bytecodeCaptureStart - i) * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
-        }
-        m_jit.addPtr(TrustedImm32(registersOffset), activationValuePayloadGPR, scratchGPR);
-        m_jit.storePtr(scratchGPR, JITCompiler::Address(activationValuePayloadGPR, JSLexicalEnvironment::offsetOfRegisters()));
-        
-        notCreated.link(&m_jit);
-        noResult(node);
-        break;
-    }
-        
     case TearOffArguments: {
         JSValueOperand unmodifiedArgumentsValue(this, node->child1());
         JSValueOperand activationValue(this, node->child2());
index 047bae8..f09f6a3 100644 (file)
@@ -4236,21 +4236,12 @@ void SpeculativeJIT::compile(Node* node)
     case CreateActivation: {
         DFG_ASSERT(m_jit.graph(), node, !node->origin.semantic.inlineCallFrame);
         
-        JSValueOperand value(this, node->child1());
-        GPRTemporary result(this, Reuse, value);
-        
-        GPRReg valueGPR = value.gpr();
+        GPRTemporary result(this);
         GPRReg resultGPR = result.gpr();
-        
-        m_jit.move(valueGPR, resultGPR);
-        
-        JITCompiler::Jump notCreated = m_jit.branchTest64(JITCompiler::Zero, resultGPR);
-        
-        addSlowPathGenerator(
-            slowPathCall(
-                notCreated, this, operationCreateActivation, resultGPR,
-                framePointerOffsetToGetActivationRegisters()));
-        
+    
+        flushRegisters();
+        callOperation(operationCreateActivation, resultGPR, framePointerOffsetToGetActivationRegisters());
+
         cellResult(resultGPR, node);
         break;
     }
@@ -4306,41 +4297,6 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
-    case TearOffActivation: {
-        DFG_ASSERT(m_jit.graph(), node, !node->origin.semantic.inlineCallFrame);
-
-        JSValueOperand activationValue(this, node->child1());
-        GPRTemporary scratch(this);
-        GPRReg activationValueGPR = activationValue.gpr();
-        GPRReg scratchGPR = scratch.gpr();
-
-        JITCompiler::Jump notCreated = m_jit.branchTest64(JITCompiler::Zero, activationValueGPR);
-
-        SymbolTable* symbolTable = m_jit.symbolTableFor(node->origin.semantic);
-        int registersOffset = JSLexicalEnvironment::registersOffset(symbolTable);
-
-        int bytecodeCaptureStart = symbolTable->captureStart();
-        int machineCaptureStart = m_jit.graph().m_machineCaptureStart;
-        for (int i = symbolTable->captureCount(); i--;) {
-            m_jit.load64(
-                JITCompiler::Address(
-                    GPRInfo::callFrameRegister,
-                    (machineCaptureStart - i) * sizeof(Register)),
-                scratchGPR);
-            m_jit.store64(
-                scratchGPR,
-                JITCompiler::Address(
-                    activationValueGPR,
-                    registersOffset + (bytecodeCaptureStart - i) * sizeof(Register)));
-        }
-        m_jit.addPtr(TrustedImm32(registersOffset), activationValueGPR, scratchGPR);
-        m_jit.storePtr(scratchGPR, JITCompiler::Address(activationValueGPR, JSLexicalEnvironment::offsetOfRegisters()));
-
-        notCreated.link(&m_jit);
-        noResult(node);
-        break;
-    }
-
     case TearOffArguments: {
         JSValueOperand unmodifiedArgumentsValue(this, node->child1());
         JSValueOperand activationValue(this, node->child2());
index 5dcc90c..a27ace0 100644 (file)
@@ -369,7 +369,7 @@ CapabilityLevel canCompile(Graph& graph)
     
     if (graph.m_codeBlock->needsActivation()) {
         // Need this because although we also don't support
-        // CreateActivation/TearOffActivation, we might not see those nodes in case of
+        // CreateActivation, we might not see those nodes in case of
         // OSR entry.
         // FIXME: Support activations.
         // https://bugs.webkit.org/show_bug.cgi?id=129576
index 3e6986d..88feffd 100644 (file)
@@ -439,8 +439,6 @@ static bool unwindCallFrame(StackVisitor& visitor)
 {
     CallFrame* callFrame = visitor->callFrame();
     CodeBlock* codeBlock = visitor->codeBlock();
-    JSScope* scope = callFrame->scope();
-
     if (Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger()) {
         ClearExceptionScope scope(&callFrame->vm());
         if (jsDynamicCast<JSFunction*>(callFrame->callee()))
@@ -455,15 +453,6 @@ static bool unwindCallFrame(StackVisitor& visitor)
 #if ENABLE(DFG_JIT)
         RELEASE_ASSERT(!visitor->isInlinedFrame());
 #endif
-        lexicalEnvironment = callFrame->uncheckedActivation();
-        // Protect against the lexical environment not being created, or the variable still being
-        // initialized to Undefined inside op_enter.
-        if (lexicalEnvironment && lexicalEnvironment.isCell()) {
-            JSLexicalEnvironment* activationObject = jsCast<JSLexicalEnvironment*>(lexicalEnvironment);
-            // Protect against throwing exceptions after tear-off.
-            if (!activationObject->isTornOff())
-                activationObject->tearOff(*scope->vm());
-        }
     }
 
     if (codeBlock->codeType() == FunctionCode && codeBlock->usesArguments()) {
index 3d4d847..a2dcd63 100644 (file)
@@ -247,7 +247,6 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_loop_hint)
         DEFINE_OP(op_lshift)
         DEFINE_OP(op_mod)
-        DEFINE_OP(op_captured_mov)
         DEFINE_OP(op_mov)
         DEFINE_OP(op_mul)
         DEFINE_OP(op_negate)
@@ -296,7 +295,6 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_switch_char)
         DEFINE_OP(op_switch_imm)
         DEFINE_OP(op_switch_string)
-        DEFINE_OP(op_tear_off_lexical_environment)
         DEFINE_OP(op_tear_off_arguments)
         DEFINE_OP(op_throw)
         DEFINE_OP(op_throw_static_error)
@@ -384,7 +382,6 @@ void JIT::privateCompileSlowCases()
         DEFINE_SLOWCASE_OP(op_construct)
         DEFINE_SLOWCASE_OP(op_to_this)
         DEFINE_SLOWCASE_OP(op_create_this)
-        DEFINE_SLOWCASE_OP(op_captured_mov)
         DEFINE_SLOWCASE_OP(op_div)
         DEFINE_SLOWCASE_OP(op_eq)
         DEFINE_SLOWCASE_OP(op_get_callee)
index a95f1d9..c49463e 100644 (file)
@@ -463,7 +463,6 @@ namespace JSC {
         void emit_op_call_eval(Instruction*);
         void emit_op_call_varargs(Instruction*);
         void emit_op_construct_varargs(Instruction*);
-        void emit_op_captured_mov(Instruction*);
         void emit_op_catch(Instruction*);
         void emit_op_construct(Instruction*);
         void emit_op_get_callee(Instruction*);
@@ -543,7 +542,6 @@ namespace JSC {
         void emit_op_switch_char(Instruction*);
         void emit_op_switch_imm(Instruction*);
         void emit_op_switch_string(Instruction*);
-        void emit_op_tear_off_lexical_environment(Instruction*);
         void emit_op_tear_off_arguments(Instruction*);
         void emit_op_throw(Instruction*);
         void emit_op_throw_static_error(Instruction*);
@@ -570,7 +568,6 @@ namespace JSC {
         void emitSlow_op_call_eval(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_call_varargs(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_construct_varargs(Instruction*, Vector<SlowCaseEntry>::iterator&);
-        void emitSlow_op_captured_mov(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_construct(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_to_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_create_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
@@ -640,7 +637,7 @@ namespace JSC {
         void emitNotifyWrite(RegisterID tag, RegisterID payload, RegisterID scratch, VariableWatchpointSet*);
 #endif
         void emitPutGlobalVar(uintptr_t operand, int value, VariableWatchpointSet*);
-        void emitPutClosureVar(int scope, uintptr_t operand, int value);
+        void emitPutClosureVar(int scope, uintptr_t operand, int value, VariableWatchpointSet*);
 
         void emitInitRegister(int dst);
 
index fa698f3..214bef1 100644 (file)
@@ -63,15 +63,6 @@ void JIT::emit_op_mov(Instruction* currentInstruction)
     emitPutVirtualRegister(dst);
 }
 
-void JIT::emit_op_captured_mov(Instruction* currentInstruction)
-{
-    int dst = currentInstruction[1].u.operand;
-    int src = currentInstruction[2].u.operand;
-
-    emitGetVirtualRegister(src, regT0);
-    emitNotifyWrite(regT0, regT1, currentInstruction[3].u.watchpointSet);
-    emitPutVirtualRegister(dst);
-}
 
 void JIT::emit_op_end(Instruction* currentInstruction)
 {
@@ -233,15 +224,6 @@ void JIT::emit_op_is_string(Instruction* currentInstruction)
     emitPutVirtualRegister(dst);
 }
 
-void JIT::emit_op_tear_off_lexical_environment(Instruction* currentInstruction)
-{
-    int lexicalEnvironment = currentInstruction[1].u.operand;
-    Jump activationNotCreated = branchTest64(Zero, addressFor(lexicalEnvironment));
-    emitGetVirtualRegister(lexicalEnvironment, regT0);
-    callOperation(operationTearOffActivation, regT0);
-    activationNotCreated.link(this);
-}
-
 void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction)
 {
     int arguments = currentInstruction[1].u.operand;
@@ -1100,19 +1082,6 @@ void JIT::emit_op_new_array_buffer(Instruction* currentInstruction)
     callOperation(operationNewArrayBufferWithProfile, dst, currentInstruction[4].u.arrayAllocationProfile, values, size);
 }
 
-void JIT::emitSlow_op_captured_mov(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
-    VariableWatchpointSet* set = currentInstruction[3].u.watchpointSet;
-    if (!set || set->state() == IsInvalidated)
-        return;
-#if USE(JSVALUE32_64)
-    linkSlowCase(iter);
-#endif
-    linkSlowCase(iter);
-    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_captured_mov);
-    slowPathCall.call();
-}
-
 #if USE(JSVALUE64)
 void JIT::emit_op_get_enumerable_length(Instruction* currentInstruction)
 {
index 1c85a51..6c48e7e 100644 (file)
@@ -153,16 +153,6 @@ void JIT::emit_op_mov(Instruction* currentInstruction)
     }
 }
 
-void JIT::emit_op_captured_mov(Instruction* currentInstruction)
-{
-    int dst = currentInstruction[1].u.operand;
-    int src = currentInstruction[2].u.operand;
-
-    emitLoad(src, regT1, regT0);
-    emitNotifyWrite(regT1, regT0, regT2, currentInstruction[3].u.watchpointSet);
-    emitStore(dst, regT1, regT0);
-}
-
 void JIT::emit_op_end(Instruction* currentInstruction)
 {
     ASSERT(returnValueGPR != callFrameRegister);
@@ -350,15 +340,6 @@ void JIT::emit_op_is_string(Instruction* currentInstruction)
     emitStoreBool(dst, regT0);
 }
 
-void JIT::emit_op_tear_off_lexical_environment(Instruction* currentInstruction)
-{
-    int lexicalEnvironment = currentInstruction[1].u.operand;
-    Jump activationNotCreated = branch32(Equal, tagFor(lexicalEnvironment), TrustedImm32(JSValue::EmptyValueTag));
-    emitLoadPayload(lexicalEnvironment, regT0);
-    callOperation(operationTearOffActivation, regT0);
-    activationNotCreated.link(this);
-}
-
 void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction)
 {
     VirtualRegister arguments = VirtualRegister(currentInstruction[1].u.operand);
index 088dff9..f3961bf 100644 (file)
@@ -1589,15 +1589,6 @@ EncodedJSValue JIT_OPERATION operationGetByValString(ExecState* exec, EncodedJSV
 
     return JSValue::encode(result);
 }
-    
-void JIT_OPERATION operationTearOffActivation(ExecState* exec, JSCell* activationCell)
-{
-    VM& vm = exec->vm();
-    NativeCallFrameTracer tracer(&vm, exec);
-
-    ASSERT(exec->codeBlock()->needsActivation());
-    jsCast<JSLexicalEnvironment*>(activationCell)->tearOff(vm);
-}
 
 void JIT_OPERATION operationTearOffArguments(ExecState* exec, JSCell* argumentsCell, JSCell* activationCell)
 {
@@ -1771,7 +1762,13 @@ void JIT_OPERATION operationPutToScope(ExecState* exec, Instruction* bytecodePC)
     JSObject* scope = jsCast<JSObject*>(exec->uncheckedR(pc[1].u.operand).jsValue());
     JSValue value = exec->r(pc[3].u.operand).jsValue();
     ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand);
-
+    if (modeAndType.type() == LocalClosureVar) {
+        JSLexicalEnvironment* environment = jsCast<JSLexicalEnvironment*>(scope);
+        environment->registerAt(pc[6].u.operand).set(vm, environment, value);
+        if (VariableWatchpointSet* set = pc[5].u.watchpointSet)
+            set->notifyWrite(vm, value, "Executed op_put_scope<LocalClosureVar>");
+        return;
+    }
     if (modeAndType.mode() == ThrowIfNotFound && !scope->hasProperty(exec, ident)) {
         exec->vm().throwException(exec, createUndefinedVariableError(exec, ident));
         return;
index 0e1e05d..e9899d4 100644 (file)
@@ -292,7 +292,6 @@ EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState*, EncodedJSValue
 EncodedJSValue JIT_OPERATION operationGetByValString(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
-void JIT_OPERATION operationTearOffActivation(ExecState*, JSCell*) WTF_INTERNAL;
 void JIT_OPERATION operationTearOffArguments(ExecState*, JSCell*, JSCell*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationDeleteById(ExecState*, EncodedJSValue base, const Identifier*) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationGetPNames(ExecState*, JSObject*) WTF_INTERNAL;
index 223b368..75e8ce6 100644 (file)
@@ -621,6 +621,8 @@ void JIT::emit_op_resolve_scope(Instruction* currentInstruction)
     case Dynamic:
         addSlowCase(jump());
         break;
+    case LocalClosureVar:
+        RELEASE_ASSERT_NOT_REACHED();
     }
 }
 
@@ -691,6 +693,8 @@ void JIT::emit_op_get_from_scope(Instruction* currentInstruction)
     case Dynamic:
         addSlowCase(jump());
         break;
+    case LocalClosureVar:
+        RELEASE_ASSERT_NOT_REACHED();
     }
     emitPutVirtualRegister(dst);
     emitValueProfilingSite();
@@ -738,11 +742,12 @@ void JIT::emitPutGlobalVar(uintptr_t operand, int value, VariableWatchpointSet*
     storePtr(regT0, reinterpret_cast<void*>(operand));
 }
 
-void JIT::emitPutClosureVar(int scope, uintptr_t operand, int value)
+void JIT::emitPutClosureVar(int scope, uintptr_t operand, int value, VariableWatchpointSet* set)
 {
     emitGetVirtualRegister(value, regT1);
     emitGetVirtualRegister(scope, regT0);
     loadPtr(Address(regT0, JSEnvironmentRecord::offsetOfRegisters()), regT0);
+    emitNotifyWrite(regT1, regT2, set);
     storePtr(regT1, Address(regT0, operand * sizeof(Register)));
 }
 
@@ -767,11 +772,12 @@ void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
         emitPutGlobalVar(*operandSlot, value, currentInstruction[5].u.watchpointSet);
         break;
+    case LocalClosureVar:
     case ClosureVar:
     case ClosureVarWithVarInjectionChecks:
         emitWriteBarrier(scope, value, ShouldFilterValue);
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
-        emitPutClosureVar(scope, *operandSlot, value);
+        emitPutClosureVar(scope, *operandSlot, value, currentInstruction[5].u.watchpointSet);
         break;
     case Dynamic:
         addSlowCase(jump());
@@ -783,9 +789,9 @@ void JIT::emitSlow_op_put_to_scope(Instruction* currentInstruction, Vector<SlowC
 {
     ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
     unsigned linkCount = 0;
-    if (resolveType != GlobalVar && resolveType != ClosureVar)
+    if (resolveType != GlobalVar && resolveType != ClosureVar && resolveType != LocalClosureVar)
         linkCount++;
-    if ((resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks)
+    if ((resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == LocalClosureVar)
         && currentInstruction[5].u.watchpointSet->state() != IsInvalidated)
         linkCount++;
     if (resolveType == GlobalProperty || resolveType == GlobalPropertyWithVarInjectionChecks)
index d591f30..83afcdd 100644 (file)
@@ -645,6 +645,8 @@ void JIT::emit_op_resolve_scope(Instruction* currentInstruction)
     case Dynamic:
         addSlowCase(jump());
         break;
+    case LocalClosureVar:
+        RELEASE_ASSERT_NOT_REACHED();
     }
 }
 
@@ -716,6 +718,8 @@ void JIT::emit_op_get_from_scope(Instruction* currentInstruction)
     case Dynamic:
         addSlowCase(jump());
         break;
+    case LocalClosureVar:
+        RELEASE_ASSERT_NOT_REACHED();
     }
     emitValueProfilingSite();
     emitStore(dst, regT1, regT0);
@@ -769,10 +773,11 @@ void JIT::emitPutGlobalVar(uintptr_t operand, int value, VariableWatchpointSet*
     store32(regT0, reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
 }
 
-void JIT::emitPutClosureVar(int scope, uintptr_t operand, int value)
+void JIT::emitPutClosureVar(int scope, uintptr_t operand, int value, VariableWatchpointSet* set)
 {
     emitLoad(value, regT3, regT2);
     emitLoad(scope, regT1, regT0);
+    emitNotifyWrite(regT3, regT2, regT4, set);
     loadPtr(Address(regT0, JSEnvironmentRecord::offsetOfRegisters()), regT0);
     store32(regT3, Address(regT0, operand * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
     store32(regT2, Address(regT0, operand * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
@@ -799,11 +804,12 @@ void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
         emitPutGlobalVar(*operandSlot, value, currentInstruction[5].u.watchpointSet);
         break;
+    case LocalClosureVar:
     case ClosureVar:
     case ClosureVarWithVarInjectionChecks:
         emitWriteBarrier(scope, value, ShouldFilterValue);
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
-        emitPutClosureVar(scope, *operandSlot, value);
+        emitPutClosureVar(scope, *operandSlot, value, currentInstruction[5].u.watchpointSet);
         break;
     case Dynamic:
         addSlowCase(jump());
@@ -815,9 +821,9 @@ void JIT::emitSlow_op_put_to_scope(Instruction* currentInstruction, Vector<SlowC
 {
     ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
     unsigned linkCount = 0;
-    if (resolveType != GlobalVar && resolveType != ClosureVar)
+    if (resolveType != GlobalVar && resolveType != ClosureVar && resolveType != LocalClosureVar)
         linkCount++;
-    if ((resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks)
+    if ((resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == LocalClosureVar)
         && currentInstruction[5].u.watchpointSet->state() != IsInvalidated)
         linkCount += 2;
     if (!linkCount)
index a352a6c..6919aea 100644 (file)
@@ -143,13 +143,14 @@ void Data::performAssertions(VM& vm)
     ASSERT(EvalCode == 1);
     ASSERT(FunctionCode == 2);
 
-    ASSERT(GlobalProperty == 0);
-    ASSERT(GlobalVar == 1);
-    ASSERT(ClosureVar == 2);
-    ASSERT(GlobalPropertyWithVarInjectionChecks == 3);
-    ASSERT(GlobalVarWithVarInjectionChecks == 4);
-    ASSERT(ClosureVarWithVarInjectionChecks == 5);
-    ASSERT(Dynamic == 6);
+    static_assert(GlobalProperty == 0, "LLInt assumes GlobalProperty ResultType is == 0");
+    static_assert(GlobalVar == 1, "LLInt assumes GlobalVar ResultType is == 1");
+    static_assert(ClosureVar == 2, "LLInt assumes ClosureVar ResultType is == 2");
+    static_assert(LocalClosureVar == 3, "LLInt assumes LocalClosureVar ResultType is == 3");
+    static_assert(GlobalPropertyWithVarInjectionChecks == 4, "LLInt assumes GlobalPropertyWithVarInjectionChecks ResultType is == 4");
+    static_assert(GlobalVarWithVarInjectionChecks == 5, "LLInt assumes GlobalVarWithVarInjectionChecks ResultType is == 5");
+    static_assert(ClosureVarWithVarInjectionChecks == 6, "LLInt assumes ClosureVarWithVarInjectionChecks ResultType is == 6");
+    static_assert(Dynamic == 7, "LLInt assumes Dynamic ResultType is == 7");
     
     ASSERT(ResolveModeAndType::mask == 0xffff);
 
index ebc76b0..ca93aeb 100644 (file)
@@ -1245,14 +1245,6 @@ LLINT_SLOW_PATH_DECL(slow_path_call_eval)
     LLINT_CALL_RETURN(exec, execCallee, LLInt::getCodePtr(getHostCallReturnValue));
 }
 
-LLINT_SLOW_PATH_DECL(slow_path_tear_off_lexical_environment)
-{
-    LLINT_BEGIN();
-    ASSERT(exec->codeBlock()->needsActivation());
-    jsCast<JSLexicalEnvironment*>(LLINT_OP(1).jsValue())->tearOff(vm);
-    LLINT_END();
-}
-
 LLINT_SLOW_PATH_DECL(slow_path_tear_off_arguments)
 {
     LLINT_BEGIN();
@@ -1411,6 +1403,13 @@ LLINT_SLOW_PATH_DECL(slow_path_put_to_scope)
     JSObject* scope = jsCast<JSObject*>(LLINT_OP(1).jsValue());
     JSValue value = LLINT_OP_C(3).jsValue();
     ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand);
+    if (modeAndType.type() == LocalClosureVar) {
+        JSLexicalEnvironment* environment = jsCast<JSLexicalEnvironment*>(scope);
+        environment->registerAt(pc[6].u.operand).set(vm, environment, value);
+        if (VariableWatchpointSet* set = pc[5].u.watchpointSet)
+            set->notifyWrite(vm, value, "Executed op_put_scope<LocalClosureVar>");
+        LLINT_END();
+    }
 
     if (modeAndType.mode() == ThrowIfNotFound && !scope->hasProperty(exec, ident))
         LLINT_THROW(createUndefinedVariableError(exec, ident));
index be7abec..4bf7deb 100644 (file)
@@ -102,7 +102,6 @@ LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_size_frame_for_varargs);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_call_varargs);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_construct_varargs);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_call_eval);
-LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_tear_off_lexical_environment);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_tear_off_arguments);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_strcat);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_to_primitive);
index 3347ae7..a0ce1f5 100644 (file)
@@ -183,10 +183,11 @@ const firstOutOfLineOffset = 100
 const GlobalProperty = 0
 const GlobalVar = 1
 const ClosureVar = 2
-const GlobalPropertyWithVarInjectionChecks = 3
-const GlobalVarWithVarInjectionChecks = 4
-const ClosureVarWithVarInjectionChecks = 5
-const Dynamic = 6
+const LocalClosureVar = 3
+const GlobalPropertyWithVarInjectionChecks = 4
+const GlobalVarWithVarInjectionChecks = 5
+const ClosureVarWithVarInjectionChecks = 6
+const Dynamic = 7
 
 const ResolveModeMask = 0xffff
 
index a3ea55b..6b2dd96 100644 (file)
@@ -824,24 +824,6 @@ macro notifyWrite(set, valueTag, valuePayload, scratch, slow)
 .done:
 end
 
-_llint_op_captured_mov:
-    traceExecution()
-    loadi 8[PC], t1
-    loadConstantOrVariable(t1, t2, t3)
-    loadpFromInstruction(3, t0)
-    btpz t0, .opCapturedMovReady
-    notifyWrite(t0, t2, t3, t1, .opCapturedMovSlow)
-.opCapturedMovReady:
-    loadi 4[PC], t0
-    storei t2, TagOffset[cfr, t0, 8]
-    storei t3, PayloadOffset[cfr, t0, 8]
-    dispatch(4)
-
-.opCapturedMovSlow:
-    callSlowPath(_slow_path_captured_mov)
-    dispatch(4)
-
-
 _llint_op_not:
     traceExecution()
     loadi 8[PC], t0
@@ -1970,16 +1952,6 @@ macro doCall(slowPath)
     slowPathForCall(slowPath)
 end
 
-
-_llint_op_tear_off_lexical_environment:
-    traceExecution()
-    loadi 4[PC], t0
-    bieq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffActivationNotCreated
-    callSlowPath(_llint_slow_path_tear_off_lexical_environment)
-.opTearOffActivationNotCreated:
-    dispatch(2)
-
-
 _llint_op_tear_off_arguments:
     traceExecution()
     loadi 4[PC], t0
@@ -2370,7 +2342,14 @@ _llint_op_put_to_scope:
     loadisFromInstruction(4, t0)
     andi ResolveModeMask, t0
 
-#pGlobalProperty:
+#pLocalClosureVar:
+    bineq t0, LocalClosureVar, .pGlobalProperty
+    writeBarrierOnOperands(1, 3)
+    loadVariable(1, t2, t1, t0)
+    putClosureVar()
+    dispatch(7)
+
+.pGlobalProperty:
     bineq t0, GlobalProperty, .pGlobalVar
     writeBarrierOnOperands(1, 3)
     loadWithStructureCheck(1, .pDynamic)
index 8142f8a..35bec6e 100644 (file)
@@ -707,23 +707,6 @@ macro notifyWrite(set, value, scratch, slow)
 .done:
 end
 
-_llint_op_captured_mov:
-    traceExecution()
-    loadisFromInstruction(2, t1)
-    loadConstantOrVariable(t1, t2)
-    loadpFromInstruction(3, t0)
-    btpz t0, .opCapturedMovReady
-    notifyWrite(t0, t2, t1, .opCapturedMovSlow)
-.opCapturedMovReady:
-    loadisFromInstruction(1, t0)
-    storeq t2, [cfr, t0, 8]
-    dispatch(4)
-
-.opCapturedMovSlow:
-    callSlowPath(_slow_path_captured_mov)
-    dispatch(4)
-
-
 _llint_op_not:
     traceExecution()
     loadisFromInstruction(2, t0)
@@ -1827,16 +1810,6 @@ macro doCall(slowPath)
     slowPathForCall(slowPath)
 end
 
-
-_llint_op_tear_off_lexical_environment:
-    traceExecution()
-    loadisFromInstruction(1, t0)
-    btqz [cfr, t0, 8], .opTearOffActivationNotCreated
-    callSlowPath(_llint_slow_path_tear_off_lexical_environment)
-.opTearOffActivationNotCreated:
-    dispatch(2)
-
-
 _llint_op_tear_off_arguments:
     traceExecution()
     loadisFromInstruction(1, t0)
@@ -2189,13 +2162,29 @@ macro putClosureVar()
     storeq t2, [t0, t1, 8]
 end
 
+macro putLocalClosureVar()
+    loadisFromInstruction(3, t1)
+    loadConstantOrVariable(t1, t2)
+    notifyWrite(t0, t2, t1, .pDynamic)
+    loadp JSEnvironmentRecord::m_registers[t0], t0
+    loadisFromInstruction(6, t1)
+    storeq t2, [t0, t1, 8]
+end
+
 
 _llint_op_put_to_scope:
     traceExecution()
     loadisFromInstruction(4, t0)
     andi ResolveModeMask, t0
 
-#pGlobalProperty:
+#pLocalClosureVar:
+    bineq t0, LocalClosureVar, .pGlobalProperty
+    writeBarrierOnOperands(1, 3)
+    loadVariable(1, t0)
+    putLocalClosureVar()
+    dispatch(7)
+
+.pGlobalProperty:
     bineq t0, GlobalProperty, .pGlobalVar
     writeBarrierOnOperands(1, 3)
     loadWithStructureCheck(1, .pDynamic)
index fb0250c..d9abfe6 100644 (file)
@@ -384,20 +384,11 @@ void Arguments::tearOff(CallFrame* callFrame)
     allocateRegisterArray(callFrame->vm());
     m_registers = m_registerArray.get() - CallFrame::offsetFor(1) - 1;
 
-    // If we have a captured argument that logically aliases lexical environment storage,
-    // but we optimize away the lexicalEnvironment, the argument needs to tear off into
-    // our storage. The simplest way to do this is to revert it to Normal status.
-    if (m_slowArgumentData && !m_lexicalEnvironment) {
-        for (size_t i = 0; i < m_numArguments; ++i) {
-            if (m_slowArgumentData->slowArguments()[i].status != SlowArgument::Captured)
-                continue;
-            m_slowArgumentData->slowArguments()[i].status = SlowArgument::Normal;
-            m_slowArgumentData->slowArguments()[i].index = CallFrame::argumentOffset(i);
-        }
-    }
-
-    for (size_t i = 0; i < m_numArguments; ++i)
+    for (size_t i = 0; i < m_numArguments; ++i) {
+        if (m_slowArgumentData && m_slowArgumentData->slowArguments()[i].status == SlowArgument::Captured)
+            continue;
         trySetArgument(callFrame->vm(), i, callFrame->argumentAfterCapture(i));
+    }
 }
 
 void Arguments::didTearOffActivation(ExecState* exec, JSLexicalEnvironment* lexicalEnvironment)
index 7c8e857..7f2e23c 100644 (file)
@@ -270,10 +270,13 @@ inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument)
         return m_registers[CallFrame::argumentOffset(argument)];
 
     int index = m_slowArgumentData->slowArguments()[argument].index;
-    if (!m_lexicalEnvironment || m_slowArgumentData->slowArguments()[argument].status != SlowArgument::Captured)
+    if (m_slowArgumentData->slowArguments()[argument].status != SlowArgument::Captured)
         return m_registers[index];
 
-    return m_lexicalEnvironment->registerAt(index - m_slowArgumentData->bytecodeToMachineCaptureOffset());
+    JSLexicalEnvironment* lexicalEnvironment = m_lexicalEnvironment.get();
+    if (!lexicalEnvironment)
+        lexicalEnvironment = CallFrame::create(reinterpret_cast<Register*>(m_registers))->lexicalEnvironment();
+    return lexicalEnvironment->registerAt(index - m_slowArgumentData->bytecodeToMachineCaptureOffset());
 }
 
 inline void Arguments::finishCreation(CallFrame* callFrame, ArgumentsMode mode)
index 2354177..5408da7 100644 (file)
@@ -262,15 +262,6 @@ SLOW_PATH_DECL(slow_path_to_this)
     RETURN(v1.toThis(exec, exec->codeBlock()->isStrictMode() ? StrictMode : NotStrictMode));
 }
 
-SLOW_PATH_DECL(slow_path_captured_mov)
-{
-    BEGIN();
-    JSValue value = OP_C(2).jsValue();
-    if (VariableWatchpointSet* set = pc[3].u.watchpointSet)
-        set->notifyWrite(vm, value, "Executed op_captured_mov");
-    RETURN(value);
-}
-
 SLOW_PATH_DECL(slow_path_new_captured_func)
 {
     BEGIN();
index 39f45bb..ef5dd5c 100644 (file)
@@ -190,7 +190,6 @@ SLOW_PATH_HIDDEN_DECL(slow_path_create_this);
 SLOW_PATH_HIDDEN_DECL(slow_path_enter);
 SLOW_PATH_HIDDEN_DECL(slow_path_get_callee);
 SLOW_PATH_HIDDEN_DECL(slow_path_to_this);
-SLOW_PATH_HIDDEN_DECL(slow_path_captured_mov);
 SLOW_PATH_HIDDEN_DECL(slow_path_new_captured_func);
 SLOW_PATH_HIDDEN_DECL(slow_path_not);
 SLOW_PATH_HIDDEN_DECL(slow_path_eq);
index 00e9ef2..d5cd189 100644 (file)
@@ -46,10 +46,6 @@ void JSLexicalEnvironment::visitChildren(JSCell* cell, SlotVisitor& visitor)
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     Base::visitChildren(thisObject, visitor);
 
-    // No need to mark our registers if they're still in the JSStack.
-    if (!thisObject->isTornOff())
-        return;
-
     for (int i = 0; i < thisObject->symbolTable()->captureCount(); ++i)
         visitor.append(&thisObject->storage()[i]);
 }
@@ -61,7 +57,7 @@ inline bool JSLexicalEnvironment::symbolTableGet(PropertyName propertyName, Prop
         return false;
 
     // Defend against the inspector asking for a var after it has been optimized out.
-    if (isTornOff() && !isValid(entry))
+    if (!isValid(entry))
         return false;
 
     slot.setValue(this, DontEnum, registerAt(entry.getIndex()).get());
@@ -75,7 +71,7 @@ inline bool JSLexicalEnvironment::symbolTableGet(PropertyName propertyName, Prop
         return false;
 
     // Defend against the inspector asking for a var after it has been optimized out.
-    if (isTornOff() && !isValid(entry))
+    if (!isValid(entry))
         return false;
 
     descriptor.setDescriptor(registerAt(entry.getIndex()).get(), entry.getAttributes());
@@ -100,7 +96,7 @@ inline bool JSLexicalEnvironment::symbolTablePut(ExecState* exec, PropertyName p
             return true;
         }
         // Defend against the inspector asking for a var after it has been optimized out.
-        if (isTornOff() && !isValid(iter->value))
+        if (!isValid(iter->value))
             return false;
         if (VariableWatchpointSet* set = iter->value.watchpointSet())
             set->invalidate(VariableWriteFireDetail(this, propertyName)); // Don't mess around - if we had found this statically, we would have invcalidated it.
@@ -114,10 +110,6 @@ void JSLexicalEnvironment::getOwnNonIndexPropertyNames(JSObject* object, ExecSta
 {
     JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(object);
 
-    CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(thisObject->m_registers));
-    if (shouldIncludeDontEnumProperties(mode) && !thisObject->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval()))
-        propertyNames.add(exec->propertyNames().arguments);
-
     {
         ConcurrentJITLocker locker(thisObject->symbolTable()->m_lock);
         SymbolTable::Map::iterator end = thisObject->symbolTable()->end(locker);
@@ -159,15 +151,6 @@ bool JSLexicalEnvironment::getOwnPropertySlot(JSObject* object, ExecState* exec,
 {
     JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(object);
 
-    if (propertyName == exec->propertyNames().arguments) {
-        // Defend against the inspector asking for the arguments object after it has been optimized out.
-        CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(thisObject->m_registers));
-        if (!thisObject->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval())) {
-            slot.setCustom(thisObject, DontEnum, argumentsGetter);
-            return true;
-        }
-    }
-
     if (thisObject->symbolTableGet(propertyName, slot))
         return true;
 
@@ -218,9 +201,7 @@ EncodedJSValue JSLexicalEnvironment::argumentsGetter(ExecState*, JSObject* slotB
 {
     JSLexicalEnvironment* lexicalEnvironment = jsCast<JSLexicalEnvironment*>(slotBase);
     CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(lexicalEnvironment->m_registers));
-    ASSERT(!lexicalEnvironment->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval()));
-    if (lexicalEnvironment->isTornOff() || !(callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval()))
-        return JSValue::encode(jsUndefined());
+    return JSValue::encode(jsUndefined());
 
     VirtualRegister argumentsRegister = callFrame->codeBlock()->argumentsRegister();
     if (JSValue arguments = callFrame->uncheckedR(argumentsRegister.offset()).jsValue())
index 72e9658..cbe0076 100644 (file)
@@ -41,7 +41,7 @@ class Register;
     
 class JSLexicalEnvironment : public JSEnvironmentRecord {
 private:
-    JSLexicalEnvironment(VM&, CallFrame*, Register*, SymbolTable*);
+    JSLexicalEnvironment(VM&, CallFrame*, Register*, CodeBlock*);
     
 public:
     typedef JSEnvironmentRecord Base;
@@ -56,7 +56,7 @@ public:
                 vm.heap,
                 allocationSize(symbolTable)
             )
-        ) JSLexicalEnvironment(vm, callFrame, registers, symbolTable);
+        ) JSLexicalEnvironment(vm, callFrame, registers, codeBlock);
         lexicalEnvironment->finishCreation(vm);
         return lexicalEnvironment;
     }
@@ -77,8 +77,6 @@ public:
 
     static JSValue toThis(JSCell*, ExecState*, ECMAMode);
 
-    void tearOff(VM&);
-        
     DECLARE_INFO;
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject) { return Structure::create(vm, globalObject, jsNull(), TypeInfo(ActivationObjectType, StructureFlags), info()); }
@@ -86,7 +84,6 @@ public:
     WriteBarrierBase<Unknown>& registerAt(int) const;
     bool isValidIndex(int) const;
     bool isValid(const SymbolTableEntry&) const;
-    bool isTornOff();
     int registersOffset();
     static int registersOffset(SymbolTable*);
 
@@ -111,18 +108,21 @@ private:
 extern int activationCount;
 extern int allTheThingsCount;
 
-inline JSLexicalEnvironment::JSLexicalEnvironment(VM& vm, CallFrame* callFrame, Register* registers, SymbolTable* symbolTable)
+inline JSLexicalEnvironment::JSLexicalEnvironment(VM& vm, CallFrame* callFrame, Register* registers, CodeBlock* codeBlock)
     : Base(
         vm,
         callFrame->lexicalGlobalObject()->activationStructure(),
         registers,
         callFrame->scope(),
-        symbolTable)
+        codeBlock->symbolTable())
 {
+    SymbolTable* symbolTable = codeBlock->symbolTable();
     WriteBarrier<Unknown>* storage = this->storage();
     size_t captureCount = symbolTable->captureCount();
     for (size_t i = 0; i < captureCount; ++i)
-        new (NotNull, &storage[i]) WriteBarrier<Unknown>;
+        new (NotNull, &storage[i]) WriteBarrier<Unknown>(UndefinedWriteBarrierTag);
+    m_registers = reinterpret_cast_ptr<WriteBarrierBase<Unknown>*>(
+        reinterpret_cast<char*>(this) + registersOffset(symbolTable));
 }
 
 JSLexicalEnvironment* asActivation(JSValue);
@@ -143,28 +143,6 @@ inline int JSLexicalEnvironment::registersOffset(SymbolTable* symbolTable)
     return storageOffset() + ((symbolTable->captureCount() - symbolTable->captureStart()  - 1) * sizeof(WriteBarrier<Unknown>));
 }
 
-inline void JSLexicalEnvironment::tearOff(VM& vm)
-{
-    ASSERT(!isTornOff());
-
-    WriteBarrierBase<Unknown>* dst = reinterpret_cast_ptr<WriteBarrierBase<Unknown>*>(
-        reinterpret_cast<char*>(this) + registersOffset(symbolTable()));
-    WriteBarrierBase<Unknown>* src = m_registers;
-
-    int captureEnd = symbolTable()->captureEnd();
-    for (int i = symbolTable()->captureStart(); i > captureEnd; --i)
-        dst[i].set(vm, this, src[i].get());
-
-    m_registers = dst;
-    ASSERT(isTornOff());
-}
-
-inline bool JSLexicalEnvironment::isTornOff()
-{
-    return m_registers == reinterpret_cast_ptr<WriteBarrierBase<Unknown>*>(
-        reinterpret_cast<char*>(this) + registersOffset(symbolTable()));
-}
-
 inline size_t JSLexicalEnvironment::storageOffset()
 {
     return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSLexicalEnvironment));
index fb608db..300cbef 100644 (file)
@@ -180,12 +180,12 @@ const char* resolveTypeName(ResolveType type)
         "GlobalProperty",
         "GlobalVar",
         "ClosureVar",
+        "LocalClosureVar",
         "GlobalPropertyWithVarInjectionChecks",
         "GlobalVarWithVarInjectionChecks",
         "ClosureVarWithVarInjectionChecks",
         "Dynamic"
     };
-    ASSERT(type < sizeof(names) / sizeof(names[0]));
     return names[type];
 }
 
index 5ab822e..70e7f85 100644 (file)
@@ -43,6 +43,7 @@ enum ResolveType {
     GlobalProperty,
     GlobalVar,
     ClosureVar,
+    LocalClosureVar,
 
     // Ditto, but at least one intervening scope used non-strict eval, which
     // can inject an intercepting var delcaration at runtime.
@@ -68,6 +69,7 @@ inline ResolveType makeType(ResolveType type, bool needsVarInjectionChecks)
     case GlobalVar:
         return GlobalVarWithVarInjectionChecks;
     case ClosureVar:
+    case LocalClosureVar:
         return ClosureVarWithVarInjectionChecks;
     case GlobalPropertyWithVarInjectionChecks:
     case GlobalVarWithVarInjectionChecks:
@@ -86,6 +88,7 @@ inline bool needsVarInjectionChecks(ResolveType type)
     case GlobalProperty:
     case GlobalVar:
     case ClosureVar:
+    case LocalClosureVar:
         return false;
     case GlobalPropertyWithVarInjectionChecks:
     case GlobalVarWithVarInjectionChecks:
index c5fe089..b7a42c9 100644 (file)
@@ -201,6 +201,7 @@ public:
     }
 };
 
+enum UndefinedWriteBarrierTagType { UndefinedWriteBarrierTag };
 template <> class WriteBarrier<Unknown> : public WriteBarrierBase<Unknown> {
     WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -208,6 +209,10 @@ public:
     {
         this->setWithoutWriteBarrier(JSValue());
     }
+    WriteBarrier(UndefinedWriteBarrierTagType)
+    {
+        this->setWithoutWriteBarrier(jsUndefined());
+    }
 
     WriteBarrier(VM& vm, const JSCell* owner, JSValue value)
     {