Changeset 163223 in webkit


Ignore:
Timestamp:
Jan 31, 2014 5:24:39 PM (10 years ago)
Author:
mark.lam@apple.com
Message:

Avoid eagerly creating the JSActivation when the debugger is attached.
<https://webkit.org/b/127910>

Reviewed by Oliver Hunt.

Octane scores for this patch:

baseline w/o WebInspector: 11621
patched w/o WebInspector: 11801
baseline w/ WebInspector: 3295
patched w/ WebInspector: 7070 2.1x improvement

  1. Because debugger can potentially create a closure from any call frame, we need every function to allocate an activation register and check for the need to tear off the activation (if needed) on return.

However, we do not need to eagerly create the activation object.
This patch implements the optimization to defer creation of the
activation object until we actually need it i.e. when:

  1. We encounter a "eval", "with", or "catch" statement.
  2. We've paused in the debugger, and called DebuggerCallFrame::scope().
  1. The UnlinkedCodeBlock provides a needsFullScopeChain flag that is used to indicate whether the linked CodeBlock will need an activation object or not. Under normal circumstances, needsFullScopeChain and needsActivation are synonymous. However, with a debugger attached, we want the CodeBlock to always allocate an activationRegister even if it does not need a "full scope chain".

Hence, we apply the following definitions to the "flags":

  1. UnlinkedCodeBlock::needsFullScopeChain() - this flag indicates that the parser discovered JS artifacts (e.g. use of "eval", "with", etc.) that requires an activation.

BytecodeGenerator's destinationForAssignResult() and leftHandSideNeedsCopy()
checks needsFullScopeChain().

  1. UnlinkedCodeBlock::hasActivationRegister() - this flag indicates that an activation register was created for the UnlinkedCodeBlock either because it needsFullScopeChain() or because the debugger is attached.
  1. CodeBlock::needsActivation() reflects UnlinkedCodeBlock's hasActivationRegister().
  1. Introduced BytecodeGenerator::emitPushFunctionNameScope() and BytecodeGenerator::emitPushCatchScope() because the JSNameScope pushed for a function name cannot be popped unlike the JSNameScope pushed for a "catch". Hence, we have 2 functions to handle the 2 cases differently.
  1. Removed DebuggerCallFrame::evaluateWithCallFrame() and require that all debugger evaluations go through the DebuggerCallFrame::evaluate(). This ensures that debugger evaluations require a DebuggerCallFrame.

DebuggerCallFrame::evaluateWithCallFrame() was used previously because
we didn't want to instantiate a DebuggerCallFrame on every debug hook
callback. However, we now only call the debug hooks when needed, and
this no longer poses a performance problem.

In addition, when the debug hook does an eval to test a breakpoint
condition, it is incorrect to evaluate it without a DebuggerCallFrame
anyway.

  1. Added some utility functions to the CallFrame to make it easier to work with the activation register in the frame (if present). These utility functions should only be called if the CodeBlock::needsActivation() is true (which indicates the presence of the activation register). The utlity functions are:
  1. CallFrame::hasActivation()
    • checks if the frame's activation object has been created.
  1. CallFrame::activation()
    • returns the frame's activation object.
  1. CallFrame::uncheckedActivation()
    • returns the JSValue in the frame's activation register. May be null.
  1. CallFrame::setActivation()
    • sets the frame's activation object.
  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode):

  • added symbollic dumping of ResolveMode and ResolveType values for some bytecodes.

(JSC::CodeBlock::CodeBlock):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::activationRegister):
(JSC::CodeBlock::uncheckedActivationRegister):
(JSC::CodeBlock::needsActivation):

  • bytecode/UnlinkedCodeBlock.h:

(JSC::UnlinkedCodeBlock::needsFullScopeChain):
(JSC::UnlinkedCodeBlock::hasActivationRegister):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::resolveCallee):
(JSC::BytecodeGenerator::createActivationIfNecessary):
(JSC::BytecodeGenerator::emitCallEval):
(JSC::BytecodeGenerator::emitReturn):
(JSC::BytecodeGenerator::emitPushWithScope):
(JSC::BytecodeGenerator::emitPushFunctionNameScope):
(JSC::BytecodeGenerator::emitPushCatchScope):

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::TryNode::emitBytecode):

  • debugger/Debugger.cpp:

(JSC::Debugger::hasBreakpoint):
(JSC::Debugger::pauseIfNeeded):

  • debugger/DebuggerCallFrame.cpp:

(JSC::DebuggerCallFrame::scope):
(JSC::DebuggerCallFrame::evaluate):

  • debugger/DebuggerCallFrame.h:
  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseCodeBlock):

  • dfg/DFGGraph.h:
  • Removed an unused function DFGGraph::needsActivation().
  • interpreter/CallFrame.cpp:

(JSC::CallFrame::activation):
(JSC::CallFrame::setActivation):

  • interpreter/CallFrame.h:

(JSC::ExecState::hasActivation):
(JSC::ExecState::registers):

  • interpreter/CallFrameInlines.h:

(JSC::CallFrame::uncheckedActivation):

  • interpreter/Interpreter.cpp:

(JSC::unwindCallFrame):
(JSC::Interpreter::unwind):

  • jit/JITOperations.cpp:
  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

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

(JSC::resolveModeName):
(JSC::resolveTypeName):

  • utility functions for decoding names of the ResolveMode and ResolveType. These are used in CodeBlock::dumpBytecode().
Location:
trunk/Source/JavaScriptCore
Files:
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r163214 r163223  
     12014-01-31  Mark Lam  <mark.lam@apple.com>
     2
     3        Avoid eagerly creating the JSActivation when the debugger is attached.
     4        <https://webkit.org/b/127910>
     5
     6        Reviewed by Oliver Hunt.
     7
     8        Octane scores for this patch:
     9            baseline w/o WebInspector: 11621
     10            patched  w/o WebInspector: 11801
     11            baseline w/ WebInspector:  3295
     12            patched  w/ WebInspector:  7070   2.1x improvement
     13
     14        1. Because debugger can potentially create a closure from any call frame,
     15           we need every function to allocate an activation register and check for
     16           the need to tear off the activation (if needed) on return.
     17
     18           However, we do not need to eagerly create the activation object.
     19           This patch implements the optimization to defer creation of the
     20           activation object until we actually need it i.e. when:
     21
     22           1. We encounter a "eval", "with", or "catch" statement.
     23           2. We've paused in the debugger, and called DebuggerCallFrame::scope().
     24
     25        2. The UnlinkedCodeBlock provides a needsFullScopeChain flag that is used
     26           to indicate whether the linked CodeBlock will need an activation
     27           object or not. Under normal circumstances, needsFullScopeChain and
     28           needsActivation are synonymous. However, with a debugger attached, we
     29           want the CodeBlock to always allocate an activationRegister even if
     30           it does not need a "full scope chain".
     31
     32           Hence, we apply the following definitions to the "flags":
     33
     34           1. UnlinkedCodeBlock::needsFullScopeChain() - this flag indicates that
     35              the parser discovered JS artifacts (e.g. use of "eval", "with", etc.)
     36              that requires an activation.
     37
     38              BytecodeGenerator's destinationForAssignResult() and leftHandSideNeedsCopy()
     39              checks needsFullScopeChain().
     40
     41           2. UnlinkedCodeBlock::hasActivationRegister() - this flag indicates that
     42              an activation register was created for the UnlinkedCodeBlock either
     43              because it needsFullScopeChain() or because the debugger is attached.
     44
     45           3. CodeBlock::needsActivation() reflects UnlinkedCodeBlock's
     46              hasActivationRegister().
     47
     48        3. Introduced BytecodeGenerator::emitPushFunctionNameScope() and
     49           BytecodeGenerator::emitPushCatchScope() because the JSNameScope
     50           pushed for a function name cannot be popped unlike the JSNameScope
     51           pushed for a "catch". Hence, we have 2 functions to handle the 2 cases
     52           differently.
     53
     54        4. Removed DebuggerCallFrame::evaluateWithCallFrame() and require that all
     55           debugger evaluations go through the DebuggerCallFrame::evaluate(). This
     56           ensures that debugger evaluations require a DebuggerCallFrame.
     57
     58           DebuggerCallFrame::evaluateWithCallFrame() was used previously because
     59           we didn't want to instantiate a DebuggerCallFrame on every debug hook
     60           callback. However, we now only call the debug hooks when needed, and
     61           this no longer poses a performance problem.
     62
     63           In addition, when the debug hook does an eval to test a breakpoint
     64           condition, it is incorrect to evaluate it without a DebuggerCallFrame
     65           anyway.
     66
     67        5. Added some utility functions to the CallFrame to make it easier to work
     68           with the activation register in the frame (if present). These utility
     69           functions should only be called if the CodeBlock::needsActivation() is
     70           true (which indicates the presence of the activation register). The
     71           utlity functions are:
     72
     73           1. CallFrame::hasActivation()
     74              - checks if the frame's activation object has been created.
     75
     76           2. CallFrame::activation()
     77              - returns the frame's activation object.
     78
     79           3. CallFrame::uncheckedActivation()
     80              - returns the JSValue in the frame's activation register. May be null.
     81
     82           4. CallFrame::setActivation()
     83              - sets the frame's activation object.
     84
     85        * bytecode/CodeBlock.cpp:
     86        (JSC::CodeBlock::dumpBytecode):
     87        - added symbollic dumping of ResolveMode and ResolveType values for some
     88          bytecodes.
     89        (JSC::CodeBlock::CodeBlock):
     90        * bytecode/CodeBlock.h:
     91        (JSC::CodeBlock::activationRegister):
     92        (JSC::CodeBlock::uncheckedActivationRegister):
     93        (JSC::CodeBlock::needsActivation):
     94        * bytecode/UnlinkedCodeBlock.h:
     95        (JSC::UnlinkedCodeBlock::needsFullScopeChain):
     96        (JSC::UnlinkedCodeBlock::hasActivationRegister):
     97        * bytecompiler/BytecodeGenerator.cpp:
     98        (JSC::BytecodeGenerator::BytecodeGenerator):
     99        (JSC::BytecodeGenerator::resolveCallee):
     100        (JSC::BytecodeGenerator::createActivationIfNecessary):
     101        (JSC::BytecodeGenerator::emitCallEval):
     102        (JSC::BytecodeGenerator::emitReturn):
     103        (JSC::BytecodeGenerator::emitPushWithScope):
     104        (JSC::BytecodeGenerator::emitPushFunctionNameScope):
     105        (JSC::BytecodeGenerator::emitPushCatchScope):
     106        * bytecompiler/BytecodeGenerator.h:
     107        * bytecompiler/NodesCodegen.cpp:
     108        (JSC::TryNode::emitBytecode):
     109        * debugger/Debugger.cpp:
     110        (JSC::Debugger::hasBreakpoint):
     111        (JSC::Debugger::pauseIfNeeded):
     112        * debugger/DebuggerCallFrame.cpp:
     113        (JSC::DebuggerCallFrame::scope):
     114        (JSC::DebuggerCallFrame::evaluate):
     115        * debugger/DebuggerCallFrame.h:
     116        * dfg/DFGByteCodeParser.cpp:
     117        (JSC::DFG::ByteCodeParser::parseCodeBlock):
     118        * dfg/DFGGraph.h:
     119        - Removed an unused function DFGGraph::needsActivation().
     120        * interpreter/CallFrame.cpp:
     121        (JSC::CallFrame::activation):
     122        (JSC::CallFrame::setActivation):
     123        * interpreter/CallFrame.h:
     124        (JSC::ExecState::hasActivation):
     125        (JSC::ExecState::registers):
     126        * interpreter/CallFrameInlines.h:
     127        (JSC::CallFrame::uncheckedActivation):
     128        * interpreter/Interpreter.cpp:
     129        (JSC::unwindCallFrame):
     130        (JSC::Interpreter::unwind):
     131        * jit/JITOperations.cpp:
     132        * llint/LLIntSlowPaths.cpp:
     133        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
     134        * runtime/CommonSlowPaths.cpp:
     135        (JSC::SLOW_PATH_DECL):
     136
     137        * runtime/JSScope.cpp:
     138        * runtime/JSScope.h:
     139        (JSC::resolveModeName):
     140        (JSC::resolveTypeName):
     141        - utility functions for decoding names of the ResolveMode and ResolveType.
     142          These are used in CodeBlock::dumpBytecode().
     143
    11442014-01-31  Michael Saboff  <msaboff@apple.com>
    2145
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r163195 r163223  
    533533            unmodifiedArgumentsRegister(argumentsRegister()).offset());
    534534    }
    535     if (needsFullScopeChain() && codeType() == FunctionCode)
     535    if (needsActivation() && codeType() == FunctionCode)
    536536        out.printf("; activation in r%d", activationRegister().offset());
    537537    out.printf("\n");
     
    13831383            int r0 = (++it)->u.operand;
    13841384            int id0 = (++it)->u.operand;
    1385             int resolveModeAndType = (++it)->u.operand;
    1386             ++it; // depth
     1385            ResolveModeAndType modeAndType = ResolveModeAndType((++it)->u.operand);
     1386            int depth = (++it)->u.operand;
    13871387            printLocationAndOp(out, exec, location, it, "resolve_scope");
    1388             out.printf("%s, %s, %d", registerName(r0).data(), idName(id0, identifier(id0)).data(), resolveModeAndType);
     1388            out.printf("%s, %s, %u<%s|%s>, %d", registerName(r0).data(), idName(id0, identifier(id0)).data(),
     1389                modeAndType.operand(), resolveModeName(modeAndType.mode()), resolveTypeName(modeAndType.type()),
     1390                depth);
    13891391            ++it;
    13901392            break;
     
    13941396            int r1 = (++it)->u.operand;
    13951397            int id0 = (++it)->u.operand;
    1396             int resolveModeAndType = (++it)->u.operand;
     1398            ResolveModeAndType modeAndType = ResolveModeAndType((++it)->u.operand);
    13971399            ++it; // Structure
    1398             ++it; // Operand
     1400            int operand = (++it)->u.operand; // Operand
    13991401            ++it; // Skip value profile.
    14001402            printLocationAndOp(out, exec, location, it, "get_from_scope");
    1401             out.printf("%s, %s, %s, %d", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data(), resolveModeAndType);
     1403            out.printf("%s, %s, %s, %u<%s|%s>, <structure>, %d",
     1404                registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data(),
     1405                modeAndType.operand(), resolveModeName(modeAndType.mode()), resolveTypeName(modeAndType.type()),
     1406                operand);
    14021407            break;
    14031408        }
     
    14061411            int id0 = (++it)->u.operand;
    14071412            int r1 = (++it)->u.operand;
    1408             int resolveModeAndType = (++it)->u.operand;
     1413            ResolveModeAndType modeAndType = ResolveModeAndType((++it)->u.operand);
    14091414            ++it; // Structure
    1410             ++it; // Operand
     1415            int operand = (++it)->u.operand; // Operand
    14111416            printLocationAndOp(out, exec, location, it, "put_to_scope");
    1412             out.printf("%s, %s, %s, %d", registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data(), resolveModeAndType);
     1417            out.printf("%s, %s, %s, %u<%s|%s>, <structure>, %d",
     1418                registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data(),
     1419                modeAndType.operand(), resolveModeName(modeAndType.mode()), resolveTypeName(modeAndType.type()),
     1420                operand);
    14131421            break;
    14141422        }
     
    15431551    , m_activationRegister(unlinkedCodeBlock->activationRegister())
    15441552    , m_isStrictMode(unlinkedCodeBlock->isStrictMode())
    1545     , m_needsActivation(unlinkedCodeBlock->needsFullScopeChain() && unlinkedCodeBlock->codeType() == FunctionCode)
     1553    , m_needsActivation(unlinkedCodeBlock->hasActivationRegister() && unlinkedCodeBlock->codeType() == FunctionCode)
    15461554    , m_source(sourceProvider)
    15471555    , m_sourceOffset(sourceOffset)
     
    18681876    if (Options::dumpGeneratedBytecodes())
    18691877        dumpBytecode();
    1870 
    18711878   
    18721879    m_heap->m_codeBlocks.add(this);
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.h

    r163195 r163223  
    306306    VirtualRegister thisRegister() const { return m_thisRegister; }
    307307
    308     bool needsFullScopeChain() const { return m_unlinkedCode->needsFullScopeChain(); }
    309308    bool usesEval() const { return m_unlinkedCode->usesEval(); }
    310309
     
    333332    VirtualRegister activationRegister() const
    334333    {
    335         ASSERT(needsFullScopeChain());
     334        ASSERT(m_activationRegister.isValid());
    336335        return m_activationRegister;
    337336    }
     
    339338    VirtualRegister uncheckedActivationRegister()
    340339    {
    341         if (!needsFullScopeChain())
    342             return VirtualRegister();
    343         return activationRegister();
     340        return m_activationRegister;
    344341    }
    345342
     
    348345    bool needsActivation() const
    349346    {
     347        ASSERT(m_activationRegister.isValid() == m_needsActivation);
    350348        return m_needsActivation;
    351349    }
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h

    r163195 r163223  
    11/*
    2  * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved.
     2 * Copyright (C) 2012, 2013, 2014 Apple Inc. All Rights Reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    270270
    271271    bool needsFullScopeChain() const { return m_needsFullScopeChain; }
    272     void setNeedsFullScopeChain(bool needsFullScopeChain) { m_needsFullScopeChain = needsFullScopeChain; }
    273272
    274273    void addExpressionInfo(unsigned instructionOffset, int divot,
     
    426425    VirtualRegister thisRegister() const { return m_thisRegister; }
    427426    VirtualRegister activationRegister() const { return m_activationRegister; }
    428 
     427    bool hasActivationRegister() const { return m_activationRegister.isValid(); }
    429428
    430429    void addPropertyAccessInstruction(unsigned propertyAccessInstruction)
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r163210 r163223  
    158158    , m_codeBlock(vm, codeBlock)
    159159    , m_thisRegister(CallFrame::thisArgumentOffset())
     160    , m_activationRegister(0)
    160161    , m_emptyValueRegister(0)
    161162    , m_globalObjectRegister(0)
     
    165166    , m_nextConstantOffset(0)
    166167    , m_globalConstantIndex(0)
    167     , m_hasCreatedActivation(true)
    168168    , m_firstLazyFunction(0)
    169169    , m_lastLazyFunction(0)
     
    178178    , m_isBuiltinFunction(false)
    179179{
    180     if (m_shouldEmitDebugHooks)
    181         m_codeBlock->setNeedsFullScopeChain(true);
    182 
    183180    m_codeBlock->setNumParameters(1); // Allocate space for "this"
    184181
     
    213210    , m_nextConstantOffset(0)
    214211    , m_globalConstantIndex(0)
    215     , m_hasCreatedActivation(false)
    216212    , m_firstLazyFunction(0)
    217213    , m_lastLazyFunction(0)
     
    231227    }
    232228
    233     if (m_shouldEmitDebugHooks)
    234         m_codeBlock->setNeedsFullScopeChain(true);
    235 
    236229    m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode());
    237230    Vector<Identifier> boundParameterProperties;
     
    247240
    248241    emitOpcode(op_enter);
    249     if (m_codeBlock->needsFullScopeChain()) {
     242    if (m_codeBlock->needsFullScopeChain() || m_shouldEmitDebugHooks) {
    250243        m_activationRegister = addVar();
    251244        emitInitLazyRegister(m_activationRegister);
     
    316309    // Captured variables and functions go first so that activations don't have
    317310    // to step over the non-captured locals to mark them.
    318     m_hasCreatedActivation = false;
    319311    if (functionBody->hasCapturedVariables()) {
    320312        for (size_t i = 0; i < functionStack.size(); ++i) {
     
    322314            const Identifier& ident = function->ident();
    323315            if (functionBody->captures(ident)) {
    324                 if (!m_hasCreatedActivation) {
    325                     m_hasCreatedActivation = true;
    326                     emitOpcode(op_create_activation);
    327                     instructions().append(m_activationRegister->index());
    328                 }
    329316                m_functions.add(ident.impl());
    330317                emitNewFunction(addVar(ident, IsVariable, IsWatchable), IsCaptured, function);
     
    337324        }
    338325    }
     326
     327    m_symbolTable->setCaptureEnd(virtualRegisterForLocal(codeBlock->m_numVars).offset());
     328
    339329    bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks;
    340     if (!canLazilyCreateFunctions && !m_hasCreatedActivation) {
    341         m_hasCreatedActivation = true;
    342         emitOpcode(op_create_activation);
    343         instructions().append(m_activationRegister->index());
    344     }
    345 
    346     m_symbolTable->setCaptureEnd(virtualRegisterForLocal(codeBlock->m_numVars).offset());
    347 
    348330    m_firstLazyFunction = codeBlock->m_numVars;
    349331    for (size_t i = 0; i < functionStack.size(); ++i) {
     
    428410    , m_codeBlock(vm, codeBlock)
    429411    , m_thisRegister(CallFrame::thisArgumentOffset())
     412    , m_activationRegister(0)
    430413    , m_emptyValueRegister(0)
    431414    , m_globalObjectRegister(0)
     
    435418    , m_nextConstantOffset(0)
    436419    , m_globalConstantIndex(0)
    437     , m_hasCreatedActivation(true)
    438420    , m_firstLazyFunction(0)
    439421    , m_lastLazyFunction(0)
     
    448430    , m_isBuiltinFunction(false)
    449431{
    450     m_codeBlock->setNeedsFullScopeChain(true);
    451 
    452432    m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode());
    453433    m_codeBlock->setNumParameters(1);
     
    492472    // If non-strict eval is in play, we use a separate object in the scope chain for the callee's name.
    493473    if (m_codeBlock->usesEval() && !m_codeBlock->isStrictMode())
    494         emitPushNameScope(functionBodyNode->ident(), &m_calleeRegister, ReadOnly | DontDelete);
     474        emitPushFunctionNameScope(functionBodyNode->ident(), &m_calleeRegister, ReadOnly | DontDelete);
    495475
    496476    if (!functionBodyNode->captures(functionBodyNode->ident()))
     
    16431623void BytecodeGenerator::createActivationIfNecessary()
    16441624{
    1645     if (m_hasCreatedActivation)
    1646         return;
    1647     if (!m_codeBlock->needsFullScopeChain())
     1625    if (!m_activationRegister)
    16481626        return;
    16491627    emitOpcode(op_create_activation);
     
    16531631RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, CallArguments& callArguments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
    16541632{
     1633    createActivationIfNecessary();
    16551634    return emitCall(op_call_eval, dst, func, NoExpectedFunction, callArguments, divot, divotStart, divotEnd);
    16561635}
     
    18251804RegisterID* BytecodeGenerator::emitReturn(RegisterID* src)
    18261805{
    1827     if (m_codeBlock->needsFullScopeChain()) {
     1806    if (m_activationRegister) {
    18281807        emitOpcode(op_tear_off_activation);
    18291808        instructions().append(m_activationRegister->index());
     
    19331912    m_localScopeDepth++;
    19341913
     1914    createActivationIfNecessary();
    19351915    return emitUnaryNoDstOp(op_push_with_scope, scope);
    19361916}
     
    22752255}
    22762256
    2277 void BytecodeGenerator::emitPushNameScope(const Identifier& property, RegisterID* value, unsigned attributes)
    2278 {
     2257void BytecodeGenerator::emitPushFunctionNameScope(const Identifier& property, RegisterID* value, unsigned attributes)
     2258{
     2259    emitOpcode(op_push_name_scope);
     2260    instructions().append(addConstant(property));
     2261    instructions().append(value->index());
     2262    instructions().append(attributes);
     2263}
     2264
     2265void BytecodeGenerator::emitPushCatchScope(const Identifier& property, RegisterID* value, unsigned attributes)
     2266{
     2267    createActivationIfNecessary();
     2268
    22792269    ControlFlowContext context;
    22802270    context.isFinallyBlock = false;
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r163195 r163223  
    11/*
    2  * Copyright (C) 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2009, 2012, 2013, 2014 Apple Inc. All rights reserved.
    33 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
    44 * Copyright (C) 2012 Igalia, S.L.
     
    426426        void emitThrowReferenceError(const String& message);
    427427
    428         void emitPushNameScope(const Identifier& property, RegisterID* value, unsigned attributes);
     428        void emitPushFunctionNameScope(const Identifier& property, RegisterID* value, unsigned attributes);
     429        void emitPushCatchScope(const Identifier& property, RegisterID* value, unsigned attributes);
    429430
    430431        RegisterID* emitPushWithScope(RegisterID* scope);
     
    656657        int m_globalVarStorageOffset;
    657658
    658         bool m_hasCreatedActivation;
    659659        int m_firstLazyFunction;
    660660        int m_lastLazyFunction;
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r163195 r163223  
    22172217        }
    22182218       
    2219         generator.emitPushNameScope(m_exceptionIdent, exceptionRegister.get(), DontDelete);
     2219        generator.emitPushCatchScope(m_exceptionIdent, exceptionRegister.get(), DontDelete);
    22202220        generator.emitNode(dst, m_catchBlock);
    22212221        generator.emitPopScope();
  • trunk/Source/JavaScriptCore/debugger/Debugger.cpp

    r162970 r163223  
    454454
    455455    JSValue exception;
    456     JSValue result = DebuggerCallFrame::evaluateWithCallFrame(m_currentCallFrame, breakpoints[i].condition, exception);
     456    DebuggerCallFrame* debuggerCallFrame = currentDebuggerCallFrame();
     457    JSValue result = debuggerCallFrame->evaluate(breakpoints[i].condition, exception);
    457458
    458459    // We can lose the debugger while executing JavaScript.
     
    622623    pauseNow |= (m_pauseOnCallFrame == m_currentCallFrame);
    623624
     625    DebuggerCallFrameScope debuggerCallFrameScope(*this);
     626
    624627    intptr_t sourceID = DebuggerCallFrame::sourceIDForCallFrame(m_currentCallFrame);
    625628    TextPosition position = DebuggerCallFrame::positionForCallFrame(m_currentCallFrame);
     
    628631    if (!pauseNow)
    629632        return;
    630 
    631     DebuggerCallFrameScope debuggerCallFrameScope(*this);
    632633
    633634    // Make sure we are not going to pause again on breakpoint actions by
  • trunk/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp

    r163027 r163223  
    11/*
    2  * Copyright (C) 2008, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2013, 2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3030#include "DebuggerCallFrame.h"
    3131
    32 #include "JSFunction.h"
     32#include "CallFrameInlines.h"
    3333#include "CodeBlock.h"
    3434#include "Interpreter.h"
     35#include "JSActivation.h"
     36#include "JSFunction.h"
    3537#include "Operations.h"
    3638#include "Parser.h"
     
    111113    if (!isValid())
    112114        return 0;
     115
     116    CodeBlock* codeBlock = m_callFrame->codeBlock();
     117    if (codeBlock && codeBlock->needsActivation() && !m_callFrame->hasActivation()) {
     118        JSActivation* activation = JSActivation::create(*codeBlock->vm(), m_callFrame, codeBlock);
     119        m_callFrame->setActivation(activation);
     120        m_callFrame->setScope(activation);
     121    }
     122
    113123    return m_callFrame->scope();
    114124}
     
    133143
    134144// Evaluate some JavaScript code in the scope of this frame.
    135 JSValue DebuggerCallFrame::evaluate(const String& script, JSValue& exception) const
    136 {
    137     ASSERT(isValid());
    138     return evaluateWithCallFrame(m_callFrame, script, exception);
    139 }
    140 
    141 JSValue DebuggerCallFrame::evaluateWithCallFrame(CallFrame* callFrame, const String& script, JSValue& exception)
    142 {
     145JSValue DebuggerCallFrame::evaluate(const String& script, JSValue& exception)
     146{
     147    ASSERT(isValid());
     148    CallFrame* callFrame = m_callFrame;
    143149    if (!callFrame)
    144150        return jsNull();
     
    158164
    159165    JSValue thisValue = thisValueForCallFrame(callFrame);
    160     JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, callFrame->scope());
     166    JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, scope());
    161167    if (vm.exception()) {
    162168        exception = vm.exception();
  • trunk/Source/JavaScriptCore/debugger/DebuggerCallFrame.h

    r162970 r163223  
    11/*
    2  * Copyright (C) 2008, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2013, 2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    6363    JS_EXPORT_PRIVATE Type type() const;
    6464    JS_EXPORT_PRIVATE JSValue thisValue() const;
    65     JS_EXPORT_PRIVATE JSValue evaluate(const String&, JSValue& exception) const;
     65    JSValue evaluate(const String&, JSValue& exception);
    6666
    6767    bool isValid() const { return !!m_callFrame; }
     
    7171    // made private soon. Other clients should not use these.
    7272
    73     JS_EXPORT_PRIVATE static JSValue evaluateWithCallFrame(CallFrame*, const String& script, JSValue& exception);
    7473    JS_EXPORT_PRIVATE static TextPosition positionForCallFrame(CallFrame*);
    7574    JS_EXPORT_PRIVATE static SourceID sourceIDForCallFrame(CallFrame*);
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r163069 r163223  
    36213621        dataLog(
    36223622            ": captureCount = ", codeBlock->symbolTable() ? codeBlock->symbolTable()->captureCount() : 0,
    3623             ", needsFullScopeChain = ", codeBlock->needsFullScopeChain(),
    3624             ", needsActivation = ", codeBlock->ownerExecutable()->needsActivation(),
     3623            ", needsActivation = ", codeBlock->needsActivation(),
    36253624            ", isStrictMode = ", codeBlock->ownerExecutable()->isStrictMode(), "\n");
    36263625        codeBlock->baselineVersion()->dumpBytecode();
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.h

    r163027 r163223  
    11/*
    2  * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    570570       
    571571        return MethodOfGettingAValueProfile(valueProfileFor(node));
    572     }
    573    
    574     bool needsActivation() const
    575     {
    576         return m_codeBlock->needsFullScopeChain() && m_codeBlock->codeType() != GlobalCode;
    577572    }
    578573   
  • trunk/Source/JavaScriptCore/interpreter/CallFrame.cpp

    r163027 r163223  
    11/*
    2  * Copyright (C) 2008, 2013 Apple Inc. All Rights Reserved.
     2 * Copyright (C) 2008, 2013, 2014 Apple Inc. All Rights Reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3030#include "CodeBlock.h"
    3131#include "Interpreter.h"
     32#include "JSActivation.h"
    3233#include "Operations.h"
    3334#include "VMEntryScope.h"
     
    135136}
    136137
     138JSActivation* CallFrame::activation() const
     139{
     140    CodeBlock* codeBlock = this->codeBlock();
     141    RELEASE_ASSERT(codeBlock->needsActivation());
     142    VirtualRegister activationRegister = codeBlock->activationRegister();
     143    return registers()[activationRegister.offset()].Register::activation();
     144}
     145
     146void CallFrame::setActivation(JSActivation* activation)
     147{
     148    CodeBlock* codeBlock = this->codeBlock();
     149    RELEASE_ASSERT(codeBlock->needsActivation());
     150    VirtualRegister activationRegister = codeBlock->activationRegister();
     151    registers()[activationRegister.offset()] = activation;
     152}
     153
    137154} // namespace JSC
  • trunk/Source/JavaScriptCore/interpreter/CallFrame.h

    r163027 r163223  
    22 *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
    33 *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
    4  *  Copyright (C) 2003, 2007, 2008, 2011, 2013 Apple Inc. All rights reserved.
     4 *  Copyright (C) 2003, 2007, 2008, 2011, 2013, 2014 Apple Inc. All rights reserved.
    55 *
    66 *  This library is free software; you can redistribute it and/or
     
    5050            return this[JSStack::ScopeChain].Register::scope();
    5151        }
     52
     53        bool hasActivation() const { return !!uncheckedActivation(); }
     54        JSActivation* activation() const;
     55        inline JSValue uncheckedActivation() const;
    5256
    5357        // Global object in which execution began.
     
    109113        static CallFrame* create(Register* callFrameBase) { return static_cast<CallFrame*>(callFrameBase); }
    110114        Register* registers() { return this; }
     115        const Register* registers() const { return this; }
    111116
    112117        CallFrame& operator=(const Register& r) { *static_cast<Register*>(this) = r; return *this; }
     
    202207        void setCallerFrame(CallFrame* frame) { callerFrameAndPC().callerFrame = frame; }
    203208        void setScope(JSScope* scope) { static_cast<Register*>(this)[JSStack::ScopeChain] = scope; }
     209        void setActivation(JSActivation*);
    204210
    205211        ALWAYS_INLINE void init(CodeBlock* codeBlock, Instruction* vPC, JSScope* scope,
  • trunk/Source/JavaScriptCore/interpreter/CallFrameInlines.h

    r156229 r163223  
    2828
    2929#include "CallFrame.h"
     30#include "CodeBlock.h"
    3031
    3132namespace JSC  {
     
    139140}
    140141
     142inline JSValue CallFrame::uncheckedActivation() const
     143{
     144    CodeBlock* codeBlock = this->codeBlock();
     145    RELEASE_ASSERT(codeBlock->needsActivation());
     146    VirtualRegister activationRegister = codeBlock->activationRegister();
     147    return registers()[activationRegister.offset()].jsValue();
     148}
     149
    141150} // namespace JSC
    142151
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r163195 r163223  
    3333#include "Arguments.h"
    3434#include "BatchedTransitionOptimizer.h"
    35 #include "CallFrame.h"
    3635#include "CallFrameClosure.h"
    3736#include "CallFrameInlines.h"
     
    429428        RELEASE_ASSERT(!visitor->isInlinedFrame());
    430429#endif
    431         activation = callFrame->uncheckedR(codeBlock->activationRegister().offset()).jsValue();
     430        activation = callFrame->uncheckedActivation();
    432431        if (activation)
    433432            jsCast<JSActivation*>(activation)->tearOff(*scope->vm());
     
    713712    // Unwind the scope chain within the exception handler's call frame.
    714713    int targetScopeDepth = handler->scopeDepth;
    715     if (codeBlock->needsActivation() && callFrame->uncheckedR(codeBlock->activationRegister().offset()).jsValue())
     714    if (codeBlock->needsActivation() && callFrame->hasActivation())
    716715        ++targetScopeDepth;
    717716
  • trunk/Source/JavaScriptCore/jit/JITOperations.cpp

    r163195 r163223  
    616616{
    617617    ASSERT(exec->codeBlock()->codeType() != FunctionCode
    618         || !exec->codeBlock()->needsFullScopeChain()
    619         || exec->uncheckedR(exec->codeBlock()->activationRegister().offset()).jsValue());
     618        || !exec->codeBlock()->needsActivation()
     619        || exec->hasActivation());
    620620
    621621    execCallee->setScope(exec->scope());
     
    15211521    NativeCallFrameTracer tracer(&vm, exec);
    15221522
    1523     ASSERT(exec->codeBlock()->needsFullScopeChain());
     1523    ASSERT(exec->codeBlock()->needsActivation());
    15241524    jsCast<JSActivation*>(activationCell)->tearOff(vm);
    15251525}
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

    r163195 r163223  
    983983    LLINT_BEGIN();
    984984    CodeBlock* codeBlock = exec->codeBlock();
    985     ASSERT(codeBlock->codeType() != FunctionCode
    986            || !codeBlock->needsFullScopeChain()
    987            || exec->uncheckedR(codeBlock->activationRegister().offset()).jsValue());
     985    ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsActivation() || exec->hasActivation());
    988986#if LLINT_SLOW_PATH_TRACING
    989987    dataLogF("Creating function!\n");
     
    12111209{
    12121210    LLINT_BEGIN();
    1213     ASSERT(exec->codeBlock()->needsFullScopeChain());
     1211    ASSERT(exec->codeBlock()->needsActivation());
    12141212    jsCast<JSActivation*>(LLINT_OP(1).jsValue())->tearOff(vm);
    12151213    LLINT_END();
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

    r163195 r163223  
    271271    BEGIN();
    272272    CodeBlock* codeBlock = exec->codeBlock();
    273     ASSERT(
    274         codeBlock->codeType() != FunctionCode
    275         || !codeBlock->needsFullScopeChain()
    276         || exec->uncheckedR(codeBlock->activationRegister().offset()).jsValue());
     273    ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsActivation() || exec->hasActivation());
    277274    JSValue value = JSFunction::create(vm, codeBlock->functionDecl(pc[2].u.operand), exec->scope());
    278275    if (VariableWatchpointSet* set = pc[3].u.watchpointSet)
  • trunk/Source/JavaScriptCore/runtime/JSScope.cpp

    r160109 r163223  
    11/*
    2  * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved.
     2 * Copyright (C) 2012, 2013, 2014 Apple Inc. All Rights Reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    158158}
    159159
     160const char* resolveModeName(ResolveMode mode)
     161{
     162    static const char* const names[] = {
     163        "ThrowIfNotFound",
     164        "DoNotThrowIfNotFound"
     165    };
     166    return names[mode];
     167}
     168
     169const char* resolveTypeName(ResolveType type)
     170{
     171    static const char* const names[] = {
     172        "GlobalProperty",
     173        "GlobalVar",
     174        "ClosureVar",
     175        "GlobalPropertyWithVarInjectionChecks",
     176        "GlobalVarWithVarInjectionChecks",
     177        "ClosureVarWithVarInjectionChecks",
     178        "Dynamic"
     179    };
     180    ASSERT(type < sizeof(names) / sizeof(names[0]));
     181    return names[type];
     182}
     183
    160184} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/JSScope.h

    r159834 r163223  
    11/*
    2  * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved.
     2 * Copyright (C) 2012, 2013, 2014 Apple Inc. All Rights Reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    5555};
    5656
     57const char* resolveModeName(ResolveMode mode);
     58const char* resolveTypeName(ResolveType type);
     59
    5760inline ResolveType makeType(ResolveType type, bool needsVarInjectionChecks)
    5861{
Note: See TracChangeset for help on using the changeset viewer.