Ignore:
Timestamp:
Jul 24, 2013, 9:02:40 PM (12 years ago)
Author:
[email protected]
Message:

fourthTier: Re-worked non-local variable resolution
https://bugs.webkit.org/show_bug.cgi?id=117375

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

This patch has two goals:

(1) Simplicity.

  • Net removes 15 opcodes.
  • Net removes 2,000 lines of code.
  • Removes setPair() from the DFG: All DFG nodes have 1 result register now.

(2) Performance.

  • 2%-3% speedup on SunSpider (20% in LLInt and Baseline JIT)
  • 2% speedup on v8-spider
  • 10% speedup on js-regress-hashmap*
  • Amusing 2X speedup on js-regress-poly-stricteq

The bytecode now separates the scope chain resolution opcode from the
scope access opcode.

OLD:

get_scoped_var r0, 1, 0
inc r0
put_scoped_var 1, 0, r0

NEW:

resolve_scope r0, x(@id0)
get_from_scope r1, r0, x(@id0)
inc r1
put_to_scope r0, x(@id0), r1

Also, we link non-local variable resolution opcodes at CodeBlock link
time instead of time of first opcode execution.

This means that we can represent all possible non-local variable
resolutions using just three opcodes, and any optimizations in these
opcodes naturally apply across-the-board.

  • API/JSCTestRunnerUtils.cpp:

(JSC::numberOfDFGCompiles):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode): Updated for removed things.

(JSC::CodeBlock::CodeBlock): Always provide the full scope chain when
creating a CodeBlock, so we can perform non-local variable resolution.

Added code to perform linking for these opcodes. This is where we figure
out which non-local variable resolutions are optimizable, and how.

(JSC::CodeBlock::finalizeUnconditionally):
(JSC::CodeBlock::noticeIncomingCall):
(JSC::CodeBlock::optimizeAfterWarmUp):
(JSC::CodeBlock::optimizeAfterLongWarmUp):
(JSC::CodeBlock::optimizeSoon): Updated for removed things.

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::needsActivation):
(JSC::GlobalCodeBlock::GlobalCodeBlock):
(JSC::ProgramCodeBlock::ProgramCodeBlock):
(JSC::EvalCodeBlock::EvalCodeBlock):
(JSC::FunctionCodeBlock::FunctionCodeBlock):

  • bytecode/EvalCodeCache.h:

(JSC::EvalCodeCache::getSlow): Updated for interface changes.

  • bytecode/GetByIdStatus.cpp:

(JSC::GetByIdStatus::computeFor): Treat global object access as
optimizable even though the global object has a custom property access
callback. This is what we've always done since, otherwise, we can't
optimize globals. (In future, we probably want to figure out a more
targeted policy than "any property access callback means no
optimization".)

  • bytecode/GlobalResolveInfo.h: Removed.
  • bytecode/Instruction.h:
  • bytecode/Opcode.h:

(JSC::padOpcodeName):

  • bytecode/PutByIdStatus.cpp:

(JSC::PutByIdStatus::computeFor): Like GetByIdStatus.

  • bytecode/ResolveGlobalStatus.cpp: Removed.
  • bytecode/ResolveGlobalStatus.h: Removed.
  • bytecode/ResolveOperation.h: Removed.
  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::generateFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::codeBlockFor):
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):

  • bytecode/UnlinkedCodeBlock.h: Don't provide a scope chain to unlinked

code blocks. Giving a scope to an unscoped compilation unit invites
programming errors.

  • bytecode/Watchpoint.h:

(JSC::WatchpointSet::addressOfIsInvalidated):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::resolveCallee):
(JSC::BytecodeGenerator::local):
(JSC::BytecodeGenerator::constLocal):
(JSC::BytecodeGenerator::resolveType):
(JSC::BytecodeGenerator::emitResolveScope):
(JSC::BytecodeGenerator::emitGetFromScope):
(JSC::BytecodeGenerator::emitPutToScope):
(JSC::BytecodeGenerator::emitInstanceOf):
(JSC::BytecodeGenerator::emitPushWithScope):
(JSC::BytecodeGenerator::emitPopScope):
(JSC::BytecodeGenerator::pushFinallyContext):
(JSC::BytecodeGenerator::emitComplexPopScopes):
(JSC::BytecodeGenerator::popTryAndEmitCatch):
(JSC::BytecodeGenerator::emitPushNameScope):
(JSC::BytecodeGenerator::isArgumentNumber):

  • bytecompiler/BytecodeGenerator.h:

(JSC::Local::Local):
(JSC::Local::operator bool):
(JSC::Local::get):
(JSC::Local::isReadOnly):
(JSC::BytecodeGenerator::scopeDepth):
(JSC::BytecodeGenerator::shouldOptimizeLocals):
(JSC::BytecodeGenerator::canOptimizeNonLocals): Refactored the bytecode
generator to resolve all variables within local scope, as if there
were no non-local scope. This helps provide a separation of concerns:
unlinked bytecode is always scope-free, and the linking stage links
in the provided scope.

  • bytecompiler/NodesCodegen.cpp:

(JSC::ResolveNode::isPure):
(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::ForInNode::emitBytecode): A bunch of this codegen is no longer
necessary, since it's redundant with the linking stage.

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::ByteCodeParser):
(JSC::DFG::ByteCodeParser::cellConstantWithStructureCheck):
(JSC::DFG::ByteCodeParser::handlePutByOffset):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::parseBlock): Updated for interface changes.
Notably, we can reuse existing DFG nodes -- but the mapping between
bytecode and DFG nodes has changed, and some nodes and corner cases have
been removed.

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::CSEPhase::scopedVarLoadElimination):
(JSC::DFG::CSEPhase::varInjectionWatchpointElimination):
(JSC::DFG::CSEPhase::globalVarStoreElimination):
(JSC::DFG::CSEPhase::scopedVarStoreElimination):
(JSC::DFG::CSEPhase::getLocalLoadElimination):
(JSC::DFG::CSEPhase::setLocalStoreElimination):
(JSC::DFG::CSEPhase::performNodeCSE): Added CSE for var injection
watchpoints. Even though watchpoints are "free", they're quite common
inside code that's subject to var injection, so I figured we'd save a
little memory.

  • dfg/DFGCapabilities.cpp:

(JSC::DFG::capabilityLevel):

  • dfg/DFGCapabilities.h: Removed detection for old forms.
  • dfg/DFGDriver.h:

(JSC::DFG::tryCompile):
(JSC::DFG::tryCompileFunction):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGGraph.h:
  • dfg/DFGJITCode.cpp:
  • dfg/DFGNode.h:

(JSC::DFG::Node::convertToStructureTransitionWatchpoint):
(JSC::DFG::Node::hasVarNumber):
(JSC::DFG::Node::hasIdentifierNumberForCheck):
(JSC::DFG::Node::hasRegisterPointer):
(JSC::DFG::Node::hasHeapPrediction):

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:

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

  • dfg/DFGRepatch.h:

(JSC::DFG::dfgResetGetByID):
(JSC::DFG::dfgResetPutByID):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation): Removed some unneeded things,
and updated for renames.

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile): The two primary changes here are:

(1) Use a watchpoint for var injection instead of looping over the scope
chain and checking. This is more efficient and much easier to model in
code generation.

(2) I've eliminated the notion of an optimized global assignment that
needs to check for whether it should fire a watchpiont. Instead, we
fire pre-emptively at the point of optimization. This removes a bunch
of edge cases, and it seems like a more honest representation of
the fact that our new optimization contradicts our old one.

  • dfg/DFGTypeCheckHoistingPhase.cpp:

(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):

  • heap/DFGCodeBlocks.cpp:

(JSC::DFGCodeBlocks::jettison):

  • interpreter/CallFrame.h:

(JSC::ExecState::trueCallFrame): Removed stuff that's unused now, and
fixed the build.

  • interpreter/Interpreter.cpp:

(JSC::eval):
(JSC::getBytecodeOffsetForCallFrame):
(JSC::getCallerInfo):
(JSC::Interpreter::throwException): Updated exception scope tracking
to match the rest of our linking strategy: The unlinked bytecode compiles
exception scope as if non-local scope did not exist, and we add in
non-local scope at link time. This means that we can restore the right
scope depth based on a simple number, without checking the contents of
the scope chain.

(JSC::Interpreter::execute): Make sure to establish the full scope chain
before linking eval code. We now require the full scope chain at link
time, in order to link non-local variable resolution opcodes.

  • jit/JIT.cpp:

(JSC::JIT::JIT):
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):

  • jit/JIT.h:
  • jit/JITArithmetic.cpp:

(JSC::JIT::emit_op_add):

  • jit/JITCode.cpp:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emitSlow_op_bitxor):
(JSC::JIT::emitSlow_op_bitor):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emitSlow_op_to_primitive):
(JSC::JIT::emit_op_strcat):
(JSC::JIT::emitSlow_op_create_this):
(JSC::JIT::emitSlow_op_to_this):

  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emitVarInjectionCheck):
(JSC::JIT::emitResolveClosure):
(JSC::JIT::emit_op_resolve_scope):
(JSC::JIT::emitSlow_op_resolve_scope):
(JSC::JIT::emitLoadWithStructureCheck):
(JSC::JIT::emitGetGlobalProperty):
(JSC::JIT::emitGetGlobalVar):
(JSC::JIT::emitGetClosureVar):
(JSC::JIT::emit_op_get_from_scope):
(JSC::JIT::emitSlow_op_get_from_scope):
(JSC::JIT::emitPutGlobalProperty):
(JSC::JIT::emitPutGlobalVar):
(JSC::JIT::emitPutClosureVar):
(JSC::JIT::emit_op_put_to_scope):
(JSC::JIT::emitSlow_op_put_to_scope):
(JSC::JIT::emit_op_init_global_const):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emitVarInjectionCheck):
(JSC::JIT::emitResolveClosure):
(JSC::JIT::emit_op_resolve_scope):
(JSC::JIT::emitSlow_op_resolve_scope):
(JSC::JIT::emitLoadWithStructureCheck):
(JSC::JIT::emitGetGlobalProperty):
(JSC::JIT::emitGetGlobalVar):
(JSC::JIT::emitGetClosureVar):
(JSC::JIT::emit_op_get_from_scope):
(JSC::JIT::emitSlow_op_get_from_scope):
(JSC::JIT::emitPutGlobalProperty):
(JSC::JIT::emitPutGlobalVar):
(JSC::JIT::emitPutClosureVar):
(JSC::JIT::emit_op_put_to_scope):
(JSC::JIT::emitSlow_op_put_to_scope):
(JSC::JIT::emit_op_init_global_const):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • jit/JITStubs.h: Re-wrote baseline JIT codegen for our new variable

resolution model.

  • llint/LLIntData.cpp:

(JSC::LLInt::Data::performAssertions):

  • llint/LLIntSlowPaths.cpp:
  • llint/LLIntSlowPaths.h:
  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter.cpp:

(JSC::CLoop::execute):

  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm: Ditto for LLInt.
  • offlineasm/x86.rb: Fixed a pre-existing encoding bug for a syntactic

form that we never used before.

  • runtime/ArrayPrototype.cpp:

(JSC::arrayProtoFuncToString):
(JSC::arrayProtoFuncToLocaleString):
(JSC::arrayProtoFuncJoin):
(JSC::arrayProtoFuncConcat):
(JSC::arrayProtoFuncPop):
(JSC::arrayProtoFuncPush):
(JSC::arrayProtoFuncReverse):
(JSC::arrayProtoFuncShift):
(JSC::arrayProtoFuncSlice):
(JSC::arrayProtoFuncSort):
(JSC::arrayProtoFuncSplice):
(JSC::arrayProtoFuncUnShift):
(JSC::arrayProtoFuncFilter):
(JSC::arrayProtoFuncMap):
(JSC::arrayProtoFuncEvery):
(JSC::arrayProtoFuncForEach):
(JSC::arrayProtoFuncSome):
(JSC::arrayProtoFuncReduce):
(JSC::arrayProtoFuncReduceRight):
(JSC::arrayProtoFuncIndexOf):
(JSC::arrayProtoFuncLastIndexOf): Fixed some pre-existing bugs in
'this' value conversion, which I made much more common by removing
special cases in bytecode generation.

These functions need to invoke toThis() because they observe the 'this'
value. Also, toLocaleString() is specified to accept non-array 'this'
values.

(Most other host functions don't need this fix because they perform
strict 'this' checking, which never coerces unexpected types.)

  • runtime/CodeCache.cpp:

(JSC::CodeCache::getCodeBlock):
(JSC::CodeCache::getProgramCodeBlock):
(JSC::CodeCache::getEvalCodeBlock):

  • runtime/CodeCache.h: Don't supply a scope to the unlinked code cache.

Unlinked code is supposed to be scope-free, so let's have the compiler
help verify that.

  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

  • runtime/CommonSlowPaths.h:
  • runtime/Executable.cpp:

(JSC::EvalExecutable::create):
(JSC::EvalExecutable::compileInternal):
(JSC::ProgramExecutable::compileInternal):
(JSC::FunctionExecutable::produceCodeBlockFor):
(JSC::FunctionExecutable::compileForCallInternal):
(JSC::FunctionExecutable::compileForConstructInternal):

  • runtime/Executable.h:

(JSC::EvalExecutable::numVariables):
(JSC::EvalExecutable::numberOfFunctionDecls):

  • runtime/ExecutionHarness.h:

(JSC::prepareForExecutionImpl):
(JSC::prepareFunctionForExecutionImpl):
(JSC::installOptimizedCode): Fiddled with executable initialization so
that we can always generate a full scope chain before we go to link a
code block. We need this because code block linking now depends on the
scope chain to link non-local variable resolution opcodes.

  • runtime/JSActivation.h:
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::JSGlobalObject):
(JSC::JSGlobalObject::createEvalCodeBlock):

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::varInjectionWatchpoint):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncEval):

  • runtime/JSNameScope.h:
  • runtime/JSScope.cpp:

(JSC::abstractAccess):
(JSC::JSScope::objectAtScope):
(JSC::JSScope::depth):
(JSC::JSScope::resolve):
(JSC::JSScope::abstractResolve): Updated to match changes explained above.

  • runtime/JSScope.h:

(JSC::makeType):
(JSC::needsVarInjectionChecks):
(JSC::ResolveOp::ResolveOp):
(JSC::ResolveModeAndType::ResolveModeAndType):
(JSC::ResolveModeAndType::mode):
(JSC::ResolveModeAndType::type):
(JSC::ResolveModeAndType::operand): Removed the old variable resolution
state machine, since it's unused now. Added logic for performing abstract
variable resolution at link time. This is used by codeblock linking.

  • runtime/ObjectPrototype.cpp:

(JSC::objectProtoFuncValueOf):
(JSC::objectProtoFuncHasOwnProperty):
(JSC::objectProtoFuncIsPrototypeOf):
(JSC::objectProtoFuncDefineGetter):
(JSC::objectProtoFuncDefineSetter):
(JSC::objectProtoFuncLookupGetter):
(JSC::objectProtoFuncLookupSetter):
(JSC::objectProtoFuncPropertyIsEnumerable):
(JSC::objectProtoFuncToLocaleString):
(JSC::objectProtoFuncToString): Fixed some pre-existing bugs in
'this' value conversion, which I made much more common by removing
special cases in bytecode generation.

These functions need to invoke toThis() because they observe the 'this'
value.

  • runtime/StringPrototype.cpp:

(JSC::checkObjectCoercible):
(JSC::stringProtoFuncReplace):
(JSC::stringProtoFuncCharAt):
(JSC::stringProtoFuncCharCodeAt):
(JSC::stringProtoFuncConcat):
(JSC::stringProtoFuncIndexOf):
(JSC::stringProtoFuncLastIndexOf):
(JSC::stringProtoFuncMatch):
(JSC::stringProtoFuncSearch):
(JSC::stringProtoFuncSlice):
(JSC::stringProtoFuncSplit):
(JSC::stringProtoFuncSubstr):
(JSC::stringProtoFuncSubstring):
(JSC::stringProtoFuncToLowerCase):
(JSC::stringProtoFuncToUpperCase):
(JSC::stringProtoFuncLocaleCompare):
(JSC::stringProtoFuncBig):
(JSC::stringProtoFuncSmall):
(JSC::stringProtoFuncBlink):
(JSC::stringProtoFuncBold):
(JSC::stringProtoFuncFixed):
(JSC::stringProtoFuncItalics):
(JSC::stringProtoFuncStrike):
(JSC::stringProtoFuncSub):
(JSC::stringProtoFuncSup):
(JSC::stringProtoFuncFontcolor):
(JSC::stringProtoFuncFontsize):
(JSC::stringProtoFuncAnchor):
(JSC::stringProtoFuncLink):
(JSC::trimString): Fixed some pre-existing bugs in
'this' value conversion, which I made much more common by removing
special cases in bytecode generation.

These functions need to invoke toThis() because they observe the 'this'
value.

  • runtime/StructureRareData.cpp:
  • runtime/VM.cpp:

(JSC::VM::~VM):

  • runtime/WriteBarrier.h:

(JSC::WriteBarrierBase::slot): Modified to reduce casting in client code.

LayoutTests:

This patch removed special-case 'this' resolution from bytecode, making
some pre-existing edge cases in 'this' value treatment much more common.

I updated the test results below, and added some tests, to match bug
fixes for these cases.

  • fast/js/script-tests/array-functions-non-arrays.js:
  • fast/js/array-functions-non-arrays-expected.txt: As specified, it's

not an error to pass a non-array to toLocaleString. Our new result
matches Firefox and Chrome.

  • fast/js/array-prototype-properties-expected.txt: Updated for slightly

clearer error message.

  • fast/js/basic-strict-mode-expected.txt: Updated for slightly more

standard error message.

  • fast/js/object-prototype-toString-expected.txt: Added.
  • fast/js/object-prototype-toString.html: Added. This test demonstrates

why we now fail a Sputnik test below, while Firefox and Chrome pass it.
(The test doesn't test what it thinks it tests, and this test verifies
that we get right what it does think it tests.)

  • fast/js/string-prototype-function-this-expected.txt: Added.
  • fast/js/string-prototype-function-this.html: Added. This test shows

that we CheckObjectCoercible in string prototype functions. (We used
to get this wrong, but Sputnik tests made it seem like we got it right
because they didn't test the dynamic scope case.)

  • sputnik/Conformance/11_Expressions/11.1_Primary_Expressions/11.1.1_The_this_Keyword/S11.1.1_A2-expected.txt:
  • sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.3_Array_prototype_toLocaleString/S15.4.4.3_A2_T1-expected.txt:
  • sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.10_String.prototype.match/S15.5.4.10_A1_T3-expected.txt:
  • sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.11_String.prototype.replace/S15.5.4.11_A1_T3-expected.txt:
  • sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.12_String.prototype.search/S15.5.4.12_A1_T3-expected.txt:
  • sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.13_String.prototype.slice/S15.5.4.13_A1_T3-expected.txt:
  • sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.14_String.prototype.split/S15.5.4.14_A1_T3-expected.txt:
  • sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.15_String.prototype.substring/S15.5.4.15_A1_T3-expected.txt:
  • sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.6_String.prototype.concat/S15.5.4.6_A1_T3-expected.txt:
  • sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.7_String.prototype.indexOf/S15.5.4.7_A1_T3-expected.txt:
  • sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.8_String.prototype.lastIndexOf/S15.5.4.8_A1_T3-expected.txt:

Updated to show failing results. Firefox and Chrome also fail these
tests, and the ES5 spec seems to mandate failure. Because these tests
resolve a String.prototype function at global scope, the 'this' value
for the call is an environment record. Logically, an environment record
converts to 'undefined' at the call site, and should then fail the
CheckObjectCoercible test.

Location:
trunk/Source/JavaScriptCore/bytecompiler
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r153200 r153221  
    3232#include "BytecodeGenerator.h"
    3333
    34 #include "BatchedTransitionOptimizer.h"
    3534#include "Interpreter.h"
    3635#include "JSActivation.h"
     
    5655        m_generator->m_instructions[m_unresolvedJumps[i].second].u.operand = m_location - m_unresolvedJumps[i].first;
    5756}
    58 
    59 #ifndef NDEBUG
    60 void ResolveResult::checkValidity()
    61 {
    62     switch (m_type) {
    63     case Register:
    64     case ReadOnlyRegister:
    65         ASSERT(m_local);
    66         return;
    67     case Dynamic:
    68         ASSERT(!m_local);
    69         return;
    70     case Lexical:
    71     case ReadOnlyLexical:
    72         ASSERT(!m_local);
    73         return;
    74     default:
    75         RELEASE_ASSERT_NOT_REACHED();
    76     }
    77 }
    78 #endif
    7957
    8058ParserError BytecodeGenerator::generate()
     
    158136}
    159137
    160 BytecodeGenerator::BytecodeGenerator(VM& vm, JSScope*, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
     138BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
    161139    : m_shouldEmitDebugHooks(debuggerMode == DebuggerOn)
    162140    , m_shouldEmitProfileHooks(profilerMode == ProfilerOn)
     
    168146    , m_globalObjectRegister(0)
    169147    , m_finallyDepth(0)
    170     , m_dynamicScopeDepth(0)
     148    , m_localScopeDepth(0)
    171149    , m_codeType(GlobalCode)
    172150    , m_nextConstantOffset(0)
     
    206184}
    207185
    208 BytecodeGenerator::BytecodeGenerator(VM& vm, JSScope* scope, FunctionBodyNode* functionBody, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
     186BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionBodyNode* functionBody, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
    209187    : m_shouldEmitDebugHooks(debuggerMode == DebuggerOn)
    210188    , m_shouldEmitProfileHooks(profilerMode == ProfilerOn)
    211189    , m_symbolTable(codeBlock->symbolTable())
    212190    , m_scopeNode(functionBody)
    213     , m_scope(vm, scope)
    214191    , m_codeBlock(vm, codeBlock)
    215192    , m_activationRegister(0)
     
    217194    , m_globalObjectRegister(0)
    218195    , m_finallyDepth(0)
    219     , m_dynamicScopeDepth(0)
     196    , m_localScopeDepth(0)
    220197    , m_codeType(FunctionCode)
    221198    , m_nextConstantOffset(0)
     
    403380}
    404381
    405 BytecodeGenerator::BytecodeGenerator(VM& vm, JSScope* scope, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
     382BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode)
    406383    : m_shouldEmitDebugHooks(debuggerMode == DebuggerOn)
    407384    , m_shouldEmitProfileHooks(profilerMode == ProfilerOn)
    408385    , m_symbolTable(codeBlock->symbolTable())
    409386    , m_scopeNode(evalNode)
    410     , m_scope(vm, scope)
    411387    , m_codeBlock(vm, codeBlock)
    412388    , m_thisRegister(CallFrame::thisArgumentOffset())
     
    414390    , m_globalObjectRegister(0)
    415391    , m_finallyDepth(0)
    416     , m_dynamicScopeDepth(0)
     392    , m_localScopeDepth(0)
    417393    , m_codeType(EvalCode)
    418394    , m_nextConstantOffset(0)
     
    471447
    472448    // If non-strict eval is in play, we use a separate object in the scope chain for the callee's name.
    473     if ((m_codeBlock->usesEval() && !m_codeBlock->isStrictMode()) || m_shouldEmitDebugHooks) {
    474         emitOpcode(op_push_name_scope);
    475         instructions().append(addConstant(functionBodyNode->ident()));
    476         instructions().append(m_calleeRegister.index());
    477         instructions().append(ReadOnly | DontDelete);
    478         return 0;
    479     }
     449    if ((m_codeBlock->usesEval() && !m_codeBlock->isStrictMode()) || m_shouldEmitDebugHooks)
     450        emitPushNameScope(functionBodyNode->ident(), &m_calleeRegister, ReadOnly | DontDelete);
    480451
    481452    if (!functionBodyNode->captures(functionBodyNode->ident()))
     
    11611132}
    11621133
    1163 ResolveResult BytecodeGenerator::resolve(const Identifier& property)
     1134Local BytecodeGenerator::local(const Identifier& property)
    11641135{
    11651136    if (property == propertyNames().thisIdentifier)
    1166         return ResolveResult::registerResolve(thisRegister(), ResolveResult::ReadOnlyFlag);
    1167 
    1168     // Check if the property should be allocated in a register.
    1169     if (m_codeType != GlobalCode && shouldOptimizeLocals() && m_symbolTable) {
    1170         SymbolTableEntry entry = symbolTable().get(property.impl());
    1171         if (!entry.isNull()) {
    1172             if (property == propertyNames().arguments)
    1173                 createArgumentsIfNecessary();
    1174             unsigned flags = entry.isReadOnly() ? ResolveResult::ReadOnlyFlag : 0;
    1175             RegisterID* local = createLazyRegisterIfNecessary(&registerFor(entry.getIndex()));
    1176             return ResolveResult::registerResolve(local, flags);
    1177         }
    1178     }
    1179     // Cases where we cannot statically optimize the lookup.
    1180     if (property == propertyNames().arguments || !canOptimizeNonLocals())
    1181         return ResolveResult::dynamicResolve();
    1182 
    1183     if (!m_scope || m_codeType != FunctionCode || m_shouldEmitDebugHooks)
    1184         return ResolveResult::dynamicResolve();
    1185 
    1186     ScopeChainIterator iter = m_scope->begin();
    1187     ScopeChainIterator end = m_scope->end();
    1188     size_t depth = m_codeBlock->needsFullScopeChain();
    1189     unsigned flags = 0;
    1190     for (; iter != end; ++iter, ++depth) {
    1191         JSObject* currentScope = iter.get();
    1192         if (!currentScope->isStaticScopeObject())
    1193             return ResolveResult::dynamicResolve();
    1194 
    1195         JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(currentScope);
    1196         SymbolTableEntry entry = currentVariableObject->symbolTable()->get(property.impl());
    1197 
    1198         // Found the property
    1199         if (!entry.isNull()) {
    1200             if (entry.isReadOnly())
    1201                 flags |= ResolveResult::ReadOnlyFlag;
    1202             if (++iter == end)
    1203                 return ResolveResult::dynamicResolve();
    1204 #if !ASSERT_DISABLED
    1205             if (JSActivation* activation = jsDynamicCast<JSActivation*>(currentVariableObject))
    1206                 ASSERT(activation->isValid(entry));
    1207 #endif
    1208             return ResolveResult::lexicalResolve(entry.getIndex(), depth, flags);
    1209         }
    1210         bool scopeRequiresDynamicChecks = false;
    1211         if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks))
    1212             break;
    1213         if (scopeRequiresDynamicChecks)
    1214             flags |= ResolveResult::DynamicFlag;
    1215     }
    1216 
    1217     return ResolveResult::dynamicResolve();
    1218 }
    1219 
    1220 ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property)
    1221 {
    1222     // Register-allocated const declarations.
    1223     if (m_codeType == FunctionCode && m_symbolTable) {
    1224         SymbolTableEntry entry = symbolTable().get(property.impl());
    1225         if (!entry.isNull()) {
    1226             unsigned flags = entry.isReadOnly() ? ResolveResult::ReadOnlyFlag : 0;
    1227             RegisterID* local = createLazyRegisterIfNecessary(&registerFor(entry.getIndex()));
    1228             return ResolveResult::registerResolve(local, flags);
    1229         }
    1230     }
    1231 
    1232     return ResolveResult::dynamicResolve();
     1137        return Local(thisRegister(), ReadOnly);
     1138
     1139    if (property == propertyNames().arguments)
     1140        createArgumentsIfNecessary();
     1141
     1142    if (!shouldOptimizeLocals())
     1143        return Local();
     1144
     1145    SymbolTableEntry entry = symbolTable().get(property.impl());
     1146    if (entry.isNull())
     1147        return Local();
     1148
     1149    RegisterID* local = createLazyRegisterIfNecessary(&registerFor(entry.getIndex()));
     1150    return Local(local, entry.getAttributes());
     1151}
     1152
     1153Local BytecodeGenerator::constLocal(const Identifier& property)
     1154{
     1155    if (m_codeType != FunctionCode)
     1156        return Local();
     1157
     1158    SymbolTableEntry entry = symbolTable().get(property.impl());
     1159    if (entry.isNull())
     1160        return Local();
     1161
     1162    RegisterID* local = createLazyRegisterIfNecessary(&registerFor(entry.getIndex()));
     1163    return Local(local, entry.getAttributes());
    12331164}
    12341165
     
    12411172    instructions().append(base->index());
    12421173    instructions().append(target->bind(begin, instructions().size()));
     1174}
     1175
     1176// Indicates the least upper bound of resolve type based on local scope. The bytecode linker
     1177// will start with this ResolveType and compute the least upper bound including intercepting scopes.
     1178ResolveType BytecodeGenerator::resolveType()
     1179{
     1180    if (m_localScopeDepth)
     1181        return Dynamic;
     1182    if (m_symbolTable && m_symbolTable->usesNonStrictEval())
     1183        return GlobalPropertyWithVarInjectionChecks;
     1184    return GlobalProperty;
     1185}
     1186
     1187RegisterID* BytecodeGenerator::emitResolveScope(RegisterID* dst, const Identifier& identifier)
     1188{
     1189    ASSERT(!m_symbolTable || !m_symbolTable->contains(identifier.impl()) || resolveType() == Dynamic);
     1190
     1191    // resolve_scope dst, id, ResolveType, depth
     1192    emitOpcode(op_resolve_scope);
     1193    instructions().append(kill(dst));
     1194    instructions().append(addConstant(identifier));
     1195    instructions().append(resolveType());
     1196    instructions().append(0);
     1197    return dst;
     1198}
     1199
     1200RegisterID* BytecodeGenerator::emitGetFromScope(RegisterID* dst, RegisterID* scope, const Identifier& identifier, ResolveMode resolveMode)
     1201{
     1202    m_codeBlock->addPropertyAccessInstruction(instructions().size());
     1203
     1204    // get_from_scope dst, scope, id, ResolveModeAndType, Structure, Operand
     1205    UnlinkedValueProfile profile = emitProfiledOpcode(op_get_from_scope);
     1206    instructions().append(kill(dst));
     1207    instructions().append(scope->index());
     1208    instructions().append(addConstant(identifier));
     1209    instructions().append(ResolveModeAndType(resolveMode, resolveType()).operand());
     1210    instructions().append(0);
     1211    instructions().append(0);
     1212    instructions().append(profile);
     1213    return dst;
     1214}
     1215
     1216RegisterID* BytecodeGenerator::emitPutToScope(RegisterID* scope, const Identifier& identifier, RegisterID* value, ResolveMode resolveMode)
     1217{
     1218    m_codeBlock->addPropertyAccessInstruction(instructions().size());
     1219
     1220    // put_to_scope scope, id, value, ResolveModeAndType, Structure, Operand
     1221    emitOpcode(op_put_to_scope);
     1222    instructions().append(scope->index());
     1223    instructions().append(addConstant(identifier));
     1224    instructions().append(value->index());
     1225    instructions().append(ResolveModeAndType(resolveMode, resolveType()).operand());
     1226    instructions().append(0);
     1227    instructions().append(0);
     1228    return value;
    12431229}
    12441230
     
    12521238}
    12531239
    1254 bool BytecodeGenerator::shouldAvoidResolveGlobal()
    1255 {
    1256     return !m_labelScopes.size();
    1257 }
    1258 
    1259 RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
    1260 {
    1261 
    1262     if (resolveResult.isStatic())
    1263         return emitGetStaticVar(dst, resolveResult, property);
    1264 
    1265     UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve);
    1266     instructions().append(kill(dst));
    1267     instructions().append(addConstant(property));
    1268     instructions().append(getResolveOperations(property));
    1269     instructions().append(profile);
    1270     return dst;
    1271 }
    1272 
    1273 RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property)
    1274 {
    1275     if (!resolveResult.isDynamic()) {
    1276         // Global object is the base
    1277         return emitLoadGlobalObject(dst);
    1278     }
    1279 
    1280     // We can't optimise at all :-(
    1281     UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_base);
    1282     instructions().append(kill(dst));
    1283     instructions().append(addConstant(property));
    1284     instructions().append(false);
    1285     instructions().append(getResolveBaseOperations(property));
    1286     instructions().append(0);
    1287     instructions().append(profile);
    1288     return dst;
    1289 }
    1290 
    1291 RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const ResolveResult&, const Identifier& property, NonlocalResolveInfo& verifier)
    1292 {
    1293     // We can't optimise at all :-(
    1294     UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_base);
    1295     instructions().append(kill(dst));
    1296     instructions().append(addConstant(property));
    1297     instructions().append(m_codeBlock->isStrictMode());
    1298     uint32_t putToBaseIndex = 0;
    1299     instructions().append(getResolveBaseForPutOperations(property, putToBaseIndex));
    1300     verifier.resolved(putToBaseIndex);
    1301     instructions().append(putToBaseIndex);
    1302     instructions().append(profile);
    1303     return dst;
    1304 }
    1305 
    1306 RegisterID* BytecodeGenerator::emitResolveWithBaseForPut(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property, NonlocalResolveInfo& verifier)
    1307 {
    1308     ASSERT_UNUSED(resolveResult, !resolveResult.isStatic());
    1309     UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_with_base);
    1310     instructions().append(kill(baseDst));
    1311     instructions().append(propDst->index());
    1312     instructions().append(addConstant(property));
    1313     uint32_t putToBaseIndex = 0;
    1314     instructions().append(getResolveWithBaseForPutOperations(property, putToBaseIndex));
    1315     verifier.resolved(putToBaseIndex);
    1316     instructions().append(putToBaseIndex);
    1317     instructions().append(profile);
    1318     return baseDst;
    1319 }
    1320 
    1321 RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult& resolveResult, const Identifier& property)
    1322 {
    1323     if (resolveResult.isStatic()) {
    1324         emitLoad(baseDst, jsUndefined());
    1325         emitGetStaticVar(propDst, resolveResult, property);
    1326         return baseDst;
    1327     }
    1328 
    1329     UnlinkedValueProfile profile = emitProfiledOpcode(op_resolve_with_this);
    1330     instructions().append(kill(baseDst));
    1331     instructions().append(propDst->index());
    1332     instructions().append(addConstant(property));
    1333     instructions().append(getResolveWithThisOperations(property));
    1334     instructions().append(profile);
    1335     return baseDst;
    1336 }
    1337 
    1338 RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult, const Identifier&)
    1339 {
    1340     ASSERT(m_codeType == FunctionCode);
    1341     switch (resolveResult.type()) {
    1342     case ResolveResult::Register:
    1343     case ResolveResult::ReadOnlyRegister:
    1344         if (dst == ignoredResult())
    1345             return 0;
    1346         return moveToDestinationIfNeeded(dst, resolveResult.local());
    1347 
    1348     case ResolveResult::Lexical:
    1349     case ResolveResult::ReadOnlyLexical: {
    1350         UnlinkedValueProfile profile = emitProfiledOpcode(op_get_scoped_var);
    1351         instructions().append(dst->index());
    1352         instructions().append(resolveResult.index());
    1353         instructions().append(resolveResult.depth());
    1354         instructions().append(profile);
    1355         return dst;
    1356     }
    1357 
    1358     default:
    1359         RELEASE_ASSERT_NOT_REACHED();
    1360         return 0;
    1361     }
    1362 }
    1363 
    13641240RegisterID* BytecodeGenerator::emitInitGlobalConst(const Identifier& identifier, RegisterID* value)
    13651241{
     
    13711247    instructions().append(addConstant(identifier));
    13721248    return value;
    1373 }
    1374 
    1375 RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, const Identifier&, RegisterID* value)
    1376 {
    1377     ASSERT(m_codeType == FunctionCode);
    1378     switch (resolveResult.type()) {
    1379     case ResolveResult::Register:
    1380     case ResolveResult::ReadOnlyRegister:
    1381         return moveToDestinationIfNeeded(resolveResult.local(), value);
    1382 
    1383     case ResolveResult::Lexical:
    1384     case ResolveResult::ReadOnlyLexical:
    1385         emitOpcode(op_put_scoped_var);
    1386         instructions().append(resolveResult.index());
    1387         instructions().append(resolveResult.depth());
    1388         instructions().append(value->index());
    1389         return value;
    1390 
    1391     default:
    1392         RELEASE_ASSERT_NOT_REACHED();
    1393         return 0;
    1394     }
    13951249}
    13961250
     
    14381292    instructions().append(0);
    14391293    instructions().append(0);
    1440     return value;
    1441 }
    1442 
    1443 RegisterID* BytecodeGenerator::emitPutToBase(RegisterID* base, const Identifier& property, RegisterID* value, NonlocalResolveInfo& resolveInfo)
    1444 {
    1445     emitOpcode(op_put_to_base);
    1446     instructions().append(base->index());
    1447     instructions().append(addConstant(property));
    1448     instructions().append(value->index());
    1449     instructions().append(resolveInfo.put());
    14501294    return value;
    14511295}
     
    20071851    context.isFinallyBlock = false;
    20081852    m_scopeContextStack.append(context);
    2009     m_dynamicScopeDepth++;
     1853    m_localScopeDepth++;
    20101854
    20111855    return emitUnaryNoDstOp(op_push_with_scope, scope);
     
    20201864
    20211865    m_scopeContextStack.removeLast();
    2022     m_dynamicScopeDepth--;
     1866    m_localScopeDepth--;
    20231867}
    20241868
     
    20531897        static_cast<unsigned>(m_labelScopes.size()),
    20541898        m_finallyDepth,
    2055         m_dynamicScopeDepth
     1899        m_localScopeDepth
    20561900    };
    20571901    scope.finallyContext = context;
     
    22222066            int savedFinallyDepth = m_finallyDepth;
    22232067            m_finallyDepth = finallyContext.finallyDepth;
    2224             int savedDynamicScopeDepth = m_dynamicScopeDepth;
    2225             m_dynamicScopeDepth = finallyContext.dynamicScopeDepth;
     2068            int savedDynamicScopeDepth = m_localScopeDepth;
     2069            m_localScopeDepth = finallyContext.dynamicScopeDepth;
    22262070           
    22272071            // Emit the finally block.
     
    22522096                m_labelScopes = savedLabelScopes;
    22532097            m_finallyDepth = savedFinallyDepth;
    2254             m_dynamicScopeDepth = savedDynamicScopeDepth;
     2098            m_localScopeDepth = savedDynamicScopeDepth;
    22552099           
    22562100            --topScope;
     
    23352179   
    23362180    emitLabel(tryRange.tryData->target.get());
    2337     tryRange.tryData->targetScopeDepth = m_dynamicScopeDepth;
     2181    tryRange.tryData->targetScopeDepth = m_localScopeDepth;
    23382182
    23392183    emitOpcode(op_catch);
     
    23542198    context.isFinallyBlock = false;
    23552199    m_scopeContextStack.append(context);
    2356     m_dynamicScopeDepth++;
     2200    m_localScopeDepth++;
    23572201
    23582202    emitOpcode(op_push_name_scope);
     
    24922336bool BytecodeGenerator::isArgumentNumber(const Identifier& ident, int argumentNumber)
    24932337{
    2494     RegisterID* registerID = resolve(ident).local();
     2338    RegisterID* registerID = local(ident).get();
    24952339    if (!registerID || registerID->index() >= 0)
    24962340         return 0;
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r153201 r153221  
    5454    class Identifier;
    5555    class Label;
    56     class JSScope;
    5756
    5857    enum ExpectedFunction {
     
    114113    };
    115114
     115    class Local {
     116    public:
     117        Local()
     118            : m_local(0)
     119            , m_attributes(0)
     120        {
     121        }
     122
     123        Local(RegisterID* local, unsigned attributes)
     124            : m_local(local)
     125            , m_attributes(attributes)
     126        {
     127        }
     128
     129        operator bool() { return m_local; }
     130
     131        RegisterID* get() { return m_local; }
     132
     133        bool isReadOnly() { return m_attributes & ReadOnly; }
     134
     135    private:
     136        RegisterID* m_local;
     137        unsigned m_attributes;
     138    };
     139
    116140    struct TryRange {
    117141        RefPtr<Label> start;
    118142        RefPtr<Label> end;
    119143        TryData* tryData;
    120     };
    121 
    122     class ResolveResult {
    123     public:
    124         enum Flags {
    125             // The property is locally bound, in a register.
    126             RegisterFlag = 0x1,
    127             // We need to traverse the scope chain at runtime, checking for
    128             // non-strict eval and/or `with' nodes.
    129             DynamicFlag = 0x2,
    130             // The resolved binding is immutable.
    131             ReadOnlyFlag = 0x4,
    132             // The property has a static location
    133             StaticFlag = 0x8,
    134             // Entry at scope distance "m_depth" and located at "m_index"
    135             ScopedFlag = 0x10
    136         };
    137 
    138         enum Type {
    139             // The property is local, and stored in a register.
    140             Register = RegisterFlag | StaticFlag,
    141             // A read-only local, created by "const".
    142             ReadOnlyRegister = RegisterFlag | ReadOnlyFlag | StaticFlag,
    143             // Lexically fixed location in the scope chain
    144             Lexical = ScopedFlag | StaticFlag,
    145             // A read-only Lexical, created by "const".
    146             ReadOnlyLexical = ScopedFlag | ReadOnlyFlag | StaticFlag,
    147             // Any other form of lookup
    148             Dynamic = DynamicFlag,
    149         };
    150 
    151         static ResolveResult registerResolve(RegisterID *local, unsigned flags)
    152         {
    153             return ResolveResult(Register | flags, local);
    154         }
    155         static ResolveResult dynamicResolve()
    156         {
    157             return ResolveResult(Dynamic, 0);
    158         }
    159         static ResolveResult lexicalResolve(int index, size_t depth, unsigned flags)
    160         {
    161             if (flags & DynamicFlag)
    162                 return dynamicResolve();
    163             return ResolveResult(Lexical | flags, index, depth);
    164         }
    165         unsigned type() const { return m_type; }
    166 
    167         // Returns the register corresponding to a local variable, or 0 if no
    168         // such register exists. Registers returned by ResolveResult::local() do
    169         // not require explicit reference counting.
    170         RegisterID* local() const { return m_local; }
    171 
    172         bool isRegister() const { return m_type & RegisterFlag; }
    173         bool isStatic() const { return (m_type & StaticFlag) && !isDynamic(); }
    174         bool isDynamic() const { return m_type & DynamicFlag; }
    175         bool isReadOnly() const { return (m_type & ReadOnlyFlag) && !isDynamic(); }
    176 
    177         unsigned depth() const { ASSERT(isStatic()); return m_depth; }
    178         int32_t index() const { ASSERT(isStatic()); return m_index; }
    179 
    180     private:
    181         ResolveResult(unsigned type, RegisterID* local)
    182             : m_type(type)
    183             , m_local(local)
    184             , m_index(0)
    185             , m_depth(0)
    186         {
    187 #ifndef NDEBUG
    188             checkValidity();
    189 #endif
    190         }
    191 
    192         ResolveResult(unsigned type, int index, unsigned depth)
    193             : m_type(type)
    194             , m_local(0)
    195             , m_index(index)
    196             , m_depth(depth)
    197         {
    198 #ifndef NDEBUG
    199             checkValidity();
    200 #endif
    201         }
    202 
    203 #ifndef NDEBUG
    204         void checkValidity();
    205 #endif
    206 
    207         unsigned m_type;
    208         RegisterID* m_local; // Local register, if RegisterFlag is set
    209         int m_index;
    210         unsigned m_depth;
    211     };
    212 
    213     struct NonlocalResolveInfo {
    214         friend class BytecodeGenerator;
    215         NonlocalResolveInfo()
    216             : m_state(Unused)
    217         {
    218         }
    219         ~NonlocalResolveInfo()
    220         {
    221             ASSERT(m_state == Put);
    222         }
    223     private:
    224         void resolved(uint32_t putToBaseIndex)
    225         {
    226             ASSERT(putToBaseIndex);
    227             ASSERT(m_state == Unused);
    228             m_state = Resolved;
    229             m_putToBaseIndex = putToBaseIndex;
    230         }
    231         uint32_t put()
    232         {
    233             ASSERT(m_state == Resolved);
    234             m_state = Put;
    235             return m_putToBaseIndex;
    236         }
    237         enum State { Unused, Resolved, Put };
    238         State m_state;
    239         uint32_t m_putToBaseIndex;
    240144    };
    241145
     
    246150        typedef DeclarationStacks::FunctionStack FunctionStack;
    247151
    248         BytecodeGenerator(VM&, JSScope*, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode);
    249         BytecodeGenerator(VM&, JSScope*, FunctionBodyNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode);
    250         BytecodeGenerator(VM&, JSScope*, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode);
     152        BytecodeGenerator(VM&, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode);
     153        BytecodeGenerator(VM&, FunctionBodyNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode);
     154        BytecodeGenerator(VM&, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode);
    251155
    252156        ~BytecodeGenerator();
     
    266170        RegisterID* uncheckedRegisterForArguments();
    267171
    268         // Resolve an identifier, given the current compile-time scope chain.
    269         ResolveResult resolve(const Identifier&);
    270         // Behaves as resolve does, but ignores dynamic scope as
    271         // dynamic scope should not interfere with const initialisation
    272         ResolveResult resolveConstDecl(const Identifier&);
     172        Local local(const Identifier&);
     173        Local constLocal(const Identifier&);
    273174
    274175        // Returns the register storing "this"
     
    436337        RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); }
    437338
    438         RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&, const Identifier&);
    439         RegisterID* emitPutStaticVar(const ResolveResult&, const Identifier&, RegisterID* value);
    440339        RegisterID* emitInitGlobalConst(const Identifier&, RegisterID* value);
    441 
    442         RegisterID* emitResolve(RegisterID* dst, const ResolveResult&, const Identifier& property);
    443         RegisterID* emitResolveBase(RegisterID* dst, const ResolveResult&, const Identifier& property);
    444         RegisterID* emitResolveBaseForPut(RegisterID* dst, const ResolveResult&, const Identifier& property, NonlocalResolveInfo&);
    445         RegisterID* emitResolveWithBaseForPut(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property, NonlocalResolveInfo&);
    446         RegisterID* emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property);
    447 
    448         RegisterID* emitPutToBase(RegisterID* base, const Identifier&, RegisterID* value, NonlocalResolveInfo&);
    449340
    450341        RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
     
    473364        void emitToPrimitive(RegisterID* dst, RegisterID* src);
    474365
     366        ResolveType resolveType();
     367        RegisterID* emitResolveScope(RegisterID* dst, const Identifier&);
     368        RegisterID* emitGetFromScope(RegisterID* dst, RegisterID* scope, const Identifier&, ResolveMode);
     369        RegisterID* emitPutToScope(RegisterID* scope, const Identifier&, RegisterID* value, ResolveMode);
     370
    475371        PassRefPtr<Label> emitLabel(Label*);
    476372        void emitLoopHint();
     
    507403        void emitDebugHook(DebugHookID, unsigned firstLine, unsigned lastLine, unsigned charOffset, unsigned lineStart);
    508404
    509         int scopeDepth() { return m_dynamicScopeDepth + m_finallyDepth; }
     405        int scopeDepth() { return m_localScopeDepth + m_finallyDepth; }
    510406        bool hasFinaliser() { return m_finallyDepth != 0; }
    511407
     
    561457        typedef HashMap<double, JSValue> NumberMap;
    562458        typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap;
    563         typedef struct {
    564             int resolveOperations;
    565             int putOperations;
    566         } ResolveCacheEntry;
    567         typedef HashMap<StringImpl*, ResolveCacheEntry, IdentifierRepHash> IdentifierResolvePutMap;
    568         typedef HashMap<StringImpl*, uint32_t, IdentifierRepHash> IdentifierResolveMap;
    569459       
    570460        // Helper for emitCall() and emitConstruct(). This works because the set of
     
    601491
    602492        void preserveLastVar();
    603         bool shouldAvoidResolveGlobal();
    604493
    605494        RegisterID& registerFor(int index)
     
    638527        bool shouldOptimizeLocals()
    639528        {
    640             if (m_dynamicScopeDepth)
    641                 return false;
    642 
    643529            if (m_codeType != FunctionCode)
    644530                return false;
    645531
     532            if (m_localScopeDepth)
     533                return false;
     534
    646535            return true;
    647536        }
     
    649538        bool canOptimizeNonLocals()
    650539        {
    651             if (m_dynamicScopeDepth)
     540            if (m_localScopeDepth)
    652541                return false;
    653542
     
    675564
    676565        ScopeNode* m_scopeNode;
    677         Strong<JSScope> m_scope;
    678566        Strong<UnlinkedCodeBlock> m_codeBlock;
    679567
     
    694582        RefPtr<RegisterID> m_lastVar;
    695583        int m_finallyDepth;
    696         int m_dynamicScopeDepth;
     584        int m_localScopeDepth;
    697585        CodeType m_codeType;
    698586
     
    724612        IdentifierStringMap m_stringMap;
    725613
    726         uint32_t getResolveOperations(const Identifier& property)
    727         {
    728             if (m_dynamicScopeDepth)
    729                 return m_codeBlock->addResolve();
    730             IdentifierResolveMap::AddResult result = m_resolveCacheMap.add(property.impl(), 0);
    731             if (result.isNewEntry)
    732                 result.iterator->value = m_codeBlock->addResolve();
    733             return result.iterator->value;
    734         }
    735 
    736         uint32_t getResolveWithThisOperations(const Identifier& property)
    737         {
    738             if (m_dynamicScopeDepth)
    739                 return m_codeBlock->addResolve();
    740             IdentifierResolveMap::AddResult result = m_resolveWithThisCacheMap.add(property.impl(), 0);
    741             if (result.isNewEntry)
    742                 result.iterator->value = m_codeBlock->addResolve();
    743             return result.iterator->value;
    744         }
    745 
    746         uint32_t getResolveBaseOperations(IdentifierResolvePutMap& map, const Identifier& property, uint32_t& putToBaseOperation)
    747         {
    748             if (m_dynamicScopeDepth) {
    749                 putToBaseOperation = m_codeBlock->addPutToBase();
    750                 return m_codeBlock->addResolve();
    751             }
    752             ResolveCacheEntry entry = {-1, -1};
    753             IdentifierResolvePutMap::AddResult result = map.add(property.impl(), entry);
    754             if (result.isNewEntry)
    755                 result.iterator->value.resolveOperations = m_codeBlock->addResolve();
    756             if (result.iterator->value.putOperations == -1)
    757                 result.iterator->value.putOperations = getPutToBaseOperation(property);
    758             putToBaseOperation = result.iterator->value.putOperations;
    759             return result.iterator->value.resolveOperations;
    760         }
    761 
    762         uint32_t getResolveBaseOperations(const Identifier& property)
    763         {
    764             uint32_t scratch;
    765             return getResolveBaseOperations(m_resolveBaseMap, property, scratch);
    766         }
    767 
    768         uint32_t getResolveBaseForPutOperations(const Identifier& property, uint32_t& putToBaseOperation)
    769         {
    770             return getResolveBaseOperations(m_resolveBaseForPutMap, property, putToBaseOperation);
    771         }
    772 
    773         uint32_t getResolveWithBaseForPutOperations(const Identifier& property, uint32_t& putToBaseOperation)
    774         {
    775             return getResolveBaseOperations(m_resolveWithBaseForPutMap, property, putToBaseOperation);
    776         }
    777 
    778         uint32_t getPutToBaseOperation(const Identifier& property)
    779         {
    780             if (m_dynamicScopeDepth)
    781                 return m_codeBlock->addPutToBase();
    782             IdentifierResolveMap::AddResult result = m_putToBaseMap.add(property.impl(), 0);
    783             if (result.isNewEntry)
    784                 result.iterator->value = m_codeBlock->addPutToBase();
    785             return result.iterator->value;
    786         }
    787 
    788         IdentifierResolveMap m_putToBaseMap;
    789         IdentifierResolveMap m_resolveCacheMap;
    790         IdentifierResolveMap m_resolveWithThisCacheMap;
    791         IdentifierResolvePutMap m_resolveBaseMap;
    792         IdentifierResolvePutMap m_resolveBaseForPutMap;
    793         IdentifierResolvePutMap m_resolveWithBaseForPutMap;
    794 
    795614        StaticPropertyAnalyzer m_staticPropertyAnalyzer;
    796615
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r153200 r153221  
    142142bool ResolveNode::isPure(BytecodeGenerator& generator) const
    143143{
    144     return generator.resolve(m_ident).isStatic();
     144    return generator.local(m_ident).get();
    145145}
    146146
    147147RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    148148{
    149     ResolveResult resolveResult = generator.resolve(m_ident);
    150     if (RegisterID* local = resolveResult.local()) {
     149    if (Local local = generator.local(m_ident)) {
    151150        if (dst == generator.ignoredResult())
    152151            return 0;
    153         return generator.moveToDestinationIfNeeded(dst, local);
     152        return generator.moveToDestinationIfNeeded(dst, local.get());
    154153    }
    155154   
    156155    unsigned divot = m_startOffset + m_ident.length();
    157156    generator.emitExpressionInfo(divot, m_ident.length(), 0, m_divotLine, m_divotLineStart);
    158     return generator.emitResolve(generator.finalDestination(dst), resolveResult, m_ident);
     157    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), m_ident);
     158    return generator.emitGetFromScope(generator.finalDestination(dst), scope.get(), m_ident, ThrowIfNotFound);
    159159}
    160160
     
    409409RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    410410{
    411     RefPtr<RegisterID> func = generator.tempDestination(dst);
     411    if (Local local = generator.local(generator.propertyNames().eval)) {
     412        RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local.get());
     413        CallArguments callArguments(generator, m_args);
     414        generator.emitLoad(callArguments.thisRegister(), jsUndefined());
     415        return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), divotEndOffset(), divotLine(), divotLineStart());
     416    }
     417
     418    RefPtr<RegisterID> func = generator.newTemporary();
    412419    CallArguments callArguments(generator, m_args);
    413420    generator.emitExpressionInfo(divot() - divotStartOffset() + 4, 4, 0, divotLine(), divotLineStart());
    414     generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), generator.resolve(generator.propertyNames().eval), generator.propertyNames().eval);
    415     return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart());
     421    generator.emitResolveScope(callArguments.thisRegister(), generator.propertyNames().eval);
     422    generator.emitGetFromScope(func.get(), callArguments.thisRegister(), generator.propertyNames().eval, ThrowIfNotFound);
     423    return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), divotEndOffset(), divotLine(), divotLineStart());
    416424}
    417425
     
    432440{
    433441    ExpectedFunction expectedFunction = generator.expectedFunctionForIdentifier(m_ident);
    434     ResolveResult resolveResult = generator.resolve(m_ident);
    435 
    436     if (RegisterID* local = resolveResult.local()) {
    437         RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local);
     442
     443    if (Local local = generator.local(m_ident)) {
     444        RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local.get());
    438445        RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
    439446        CallArguments callArguments(generator, m_args);
     
    444451    }
    445452
    446     if (resolveResult.isStatic()) {
    447         RefPtr<RegisterID> func = generator.newTemporary();
    448         RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
    449         CallArguments callArguments(generator, m_args);
    450         generator.emitGetStaticVar(func.get(), resolveResult, m_ident);
    451         generator.emitLoad(callArguments.thisRegister(), jsUndefined());
    452         return generator.emitCall(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart());
    453     }
    454 
    455453    RefPtr<RegisterID> func = generator.newTemporary();
    456454    RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
     
    459457
    460458    generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0, divotLine(), divotLineStart());
    461     generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), resolveResult, m_ident);
     459    generator.emitResolveScope(callArguments.thisRegister(), m_ident);
     460    generator.emitGetFromScope(func.get(), callArguments.thisRegister(), m_ident, ThrowIfNotFound);
    462461    return generator.emitCall(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart());
    463462}
     
    633632    const Identifier& ident = resolve->identifier();
    634633
    635     ResolveResult resolveResult = generator.resolve(ident);
    636 
    637     if (RefPtr<RegisterID> local = resolveResult.local()) {
    638         if (resolveResult.isReadOnly()) {
     634    if (Local local = generator.local(ident)) {
     635        if (local.isReadOnly()) {
    639636            generator.emitReadOnlyExceptionIfNeeded();
    640             local = generator.emitMove(generator.tempDestination(dst), local.get());
     637            local = Local(generator.emitMove(generator.tempDestination(dst), local.get()), 0);
    641638        }
    642639        return emitPostIncOrDec(generator, generator.finalDestination(dst), local.get(), m_operator);
    643640    }
    644641
    645     if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
    646         RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult, ident);
    647         RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
    648         generator.emitPutStaticVar(resolveResult, ident, value.get());
    649         return oldValue.get();
    650     }
    651 
    652642    generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart());
    653     RefPtr<RegisterID> value = generator.newTemporary();
    654     NonlocalResolveInfo resolveInfo;
    655     RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), value.get(), resolveResult, ident, resolveInfo);
     643    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), ident);
     644    RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), ident, ThrowIfNotFound);
    656645    RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
    657     generator.emitPutToBase(base.get(), ident, value.get(), resolveInfo);
     646    generator.emitPutToScope(scope.get(), ident, value.get(), ThrowIfNotFound);
    658647    return oldValue.get();
    659648}
     
    720709RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    721710{
    722     ResolveResult resolveResult = generator.resolve(m_ident);
    723     if (resolveResult.isRegister())
     711    if (generator.local(m_ident).get())
    724712        return generator.emitLoad(generator.finalDestination(dst), false);
    725713
    726714    generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart());
    727     RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), resolveResult, m_ident);
    728     return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident);
     715    RefPtr<RegisterID> base = generator.emitResolveScope(generator.tempDestination(dst), m_ident);
     716    return generator.emitDeleteById(generator.finalDestination(dst, base.get()), base.get(), m_ident);
    729717}
    730718
     
    776764RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    777765{
    778     ResolveResult resolveResult = generator.resolve(m_ident);
    779     if (RegisterID* local = resolveResult.local()) {
     766    if (Local local = generator.local(m_ident)) {
    780767        if (dst == generator.ignoredResult())
    781768            return 0;
    782         return generator.emitTypeOf(generator.finalDestination(dst), local);
    783     }
    784 
    785     if (resolveResult.isStatic()) {
    786         RefPtr<RegisterID> scratch = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident);
    787         return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get());
    788     }
    789 
    790     RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), resolveResult, m_ident);
    791     generator.emitGetById(scratch.get(), scratch.get(), m_ident);
     769        return generator.emitTypeOf(generator.finalDestination(dst), local.get());
     770    }
     771
     772    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), m_ident);
     773    RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, DoNotThrowIfNotFound);
    792774    if (dst == generator.ignoredResult())
    793775        return 0;
    794     return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get());
     776    return generator.emitTypeOf(generator.finalDestination(dst, scope.get()), value.get());
    795777}
    796778
     
    815797    const Identifier& ident = resolve->identifier();
    816798
    817     ResolveResult resolveResult = generator.resolve(ident);
    818     if (RefPtr<RegisterID> local = resolveResult.local()) {
    819         if (resolveResult.isReadOnly()) {
     799    if (Local local = generator.local(ident)) {
     800        if (local.isReadOnly()) {
    820801            generator.emitReadOnlyExceptionIfNeeded();
    821             local = generator.emitMove(generator.tempDestination(dst), local.get());
     802            local = Local(generator.emitMove(generator.tempDestination(dst), local.get()), 0);
    822803        }
    823804        emitIncOrDec(generator, local.get(), m_operator);
     
    825806    }
    826807
    827     if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
    828         RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, ident);
    829         emitIncOrDec(generator, propDst.get(), m_operator);
    830         generator.emitPutStaticVar(resolveResult, ident, propDst.get());
    831         return generator.moveToDestinationIfNeeded(dst, propDst.get());
    832     }
    833 
    834808    generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart());
    835     RefPtr<RegisterID> propDst = generator.tempDestination(dst);
    836     NonlocalResolveInfo resolveVerifier;
    837     RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), propDst.get(), resolveResult, ident, resolveVerifier);
    838     emitIncOrDec(generator, propDst.get(), m_operator);
    839     generator.emitPutToBase(base.get(), ident, propDst.get(), resolveVerifier);
    840     return generator.moveToDestinationIfNeeded(dst, propDst.get());
     809    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), ident);
     810    RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), ident, ThrowIfNotFound);
     811    emitIncOrDec(generator, value.get(), m_operator);
     812    generator.emitPutToScope(scope.get(), ident, value.get(), ThrowIfNotFound);
     813    return generator.moveToDestinationIfNeeded(dst, value.get());
    841814}
    842815
     
    13101283RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    13111284{
    1312     ResolveResult resolveResult = generator.resolve(m_ident);
    1313 
    1314     if (RegisterID *local = resolveResult.local()) {
    1315         if (resolveResult.isReadOnly()) {
     1285    if (Local local = generator.local(m_ident)) {
     1286        if (local.isReadOnly()) {
    13161287            generator.emitReadOnlyExceptionIfNeeded();
    1317             return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
     1288            return emitReadModifyAssignment(generator, generator.finalDestination(dst), local.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
    13181289        }
    13191290       
    13201291        if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) {
    13211292            RefPtr<RegisterID> result = generator.newTemporary();
    1322             generator.emitMove(result.get(), local);
     1293            generator.emitMove(result.get(), local.get());
    13231294            emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
    1324             generator.emitMove(local, result.get());
     1295            generator.emitMove(local.get(), result.get());
    13251296            return generator.moveToDestinationIfNeeded(dst, result.get());
    13261297        }
    13271298       
    1328         RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
     1299        RegisterID* result = emitReadModifyAssignment(generator, local.get(), local.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
    13291300        return generator.moveToDestinationIfNeeded(dst, result);
    13301301    }
    13311302
    1332     if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
    1333         RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident);
    1334         RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
    1335         generator.emitPutStaticVar(resolveResult, m_ident, result);
    1336         return result;
    1337     }
    1338 
    1339     RefPtr<RegisterID> src1 = generator.tempDestination(dst);
    13401303    generator.emitExpressionInfo(divot() - divotStartOffset() + m_ident.length(), m_ident.length(), 0, divotLine(), divotLineStart());
    1341     NonlocalResolveInfo resolveVerifier;
    1342     RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), src1.get(), resolveResult, m_ident, resolveVerifier);
    1343     RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this);
    1344     return generator.emitPutToBase(base.get(), m_ident, result, resolveVerifier);
     1304    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident);
     1305    RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, ThrowIfNotFound);
     1306    RefPtr<RegisterID> result = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this);
     1307    return generator.emitPutToScope(scope.get(), m_ident, result.get(), ThrowIfNotFound);
    13451308}
    13461309
     
    13491312RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    13501313{
    1351     ResolveResult resolveResult = generator.resolve(m_ident);
    1352 
    1353     if (RegisterID* local = resolveResult.local()) {
    1354         if (resolveResult.isReadOnly()) {
     1314    if (Local local = generator.local(m_ident)) {
     1315        if (local.isReadOnly()) {
    13551316            generator.emitReadOnlyExceptionIfNeeded();
    13561317            return generator.emitNode(dst, m_right);
    13571318        }
    1358         RegisterID* result = generator.emitNode(local, m_right);
     1319        RegisterID* result = generator.emitNode(local.get(), m_right);
    13591320        return generator.moveToDestinationIfNeeded(dst, result);
    13601321    }
    13611322
    1362     if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
    1363         if (dst == generator.ignoredResult())
    1364             dst = 0;
    1365         RegisterID* value = generator.emitNode(dst, m_right);
    1366         generator.emitPutStaticVar(resolveResult, m_ident, value);
    1367         return value;
    1368     }
    1369 
    1370     NonlocalResolveInfo resolveVerifier;
    1371     if (generator.isStrictMode())
    1372         generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart());
    1373     RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident, resolveVerifier);
     1323    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident);
    13741324    if (dst == generator.ignoredResult())
    13751325        dst = 0;
    1376     RegisterID* value = generator.emitNode(dst, m_right);
     1326    RefPtr<RegisterID> result = generator.emitNode(dst, m_right);
    13771327    generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart());
    1378     return generator.emitPutToBase(base.get(), m_ident, value, resolveVerifier);
     1328    return generator.emitPutToScope(scope.get(), m_ident, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
    13791329}
    13801330
     
    14591409RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator)
    14601410{
    1461     ResolveResult resolveResult = generator.resolveConstDecl(m_ident);
    1462 
    14631411    // FIXME: This code does not match the behavior of const in Firefox.
    1464     if (RegisterID* local = resolveResult.local()) {
     1412    if (RegisterID* local = generator.constLocal(m_ident).get()) {
    14651413        if (!m_init)
    14661414            return local;
     
    14781426
    14791427    // FIXME: This will result in incorrect assignment if m_ident exists in an intervening with scope.
    1480     RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), resolveResult, m_ident);
    1481     return generator.emitPutById(base.get(), m_ident, value.get());
     1428    RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident);
     1429    return generator.emitPutToScope(scope.get(), m_ident, value.get(), DoNotThrowIfNotFound);
    14821430}
    14831431
     
    17431691    if (m_lexpr->isResolveNode()) {
    17441692        const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier();
    1745         ResolveResult resolveResult = generator.resolve(ident);
    1746         propertyName = resolveResult.local();
     1693        Local local = generator.local(ident);
     1694        propertyName = local.get();
    17471695        if (!propertyName) {
    17481696            propertyName = generator.newTemporary();
    17491697            RefPtr<RegisterID> protect = propertyName;
    1750             NonlocalResolveInfo resolveVerifier;
    1751             if (generator.isStrictMode())
    1752                 generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart());
    1753             RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident, resolveVerifier);
    1754 
     1698            RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident);
    17551699            generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart());
    1756             generator.emitPutToBase(base, ident, propertyName, resolveVerifier);
     1700            generator.emitPutToScope(scope, ident, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
    17571701        } else {
    17581702            expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName);
Note: See TracChangeset for help on using the changeset viewer.