Changeset 58986 in webkit for trunk/JavaScriptCore/interpreter


Ignore:
Timestamp:
May 7, 2010, 5:05:00 PM (15 years ago)
Author:
[email protected]
Message:

2010-05-07 Oliver Hunt <[email protected]>

Reviewed by Geoffrey Garen.

Optimize access to the global object from a function that uses eval
https://bugs.webkit.org/show_bug.cgi?id=38644

Add op_resolve_global_dynamic, a variant of op_resolve_global that
checks each node in the scope chain for dynamically inserted properties
and falls back to the normal resolve logic in that case.

  • JavaScriptCore.exp:
  • bytecode/CodeBlock.cpp: (JSC::isGlobalResolve): (JSC::CodeBlock::printStructures): (JSC::CodeBlock::dump): (JSC::CodeBlock::derefStructures):
  • bytecode/Opcode.h:
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::findScopedProperty):

Now take an additional reference parameter to used to indicate that
there were nodes that may gain dynamic properties

(JSC::BytecodeGenerator::emitResolve):
(JSC::BytecodeGenerator::emitResolveBase):
(JSC::BytecodeGenerator::emitResolveWithBase):

deal with additional argument to findScopedProperty

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp: (JSC::FunctionCallResolveNode::emitBytecode): (JSC::PostfixResolveNode::emitBytecode): (JSC::PrefixResolveNode::emitBytecode): (JSC::ReadModifyResolveNode::emitBytecode): (JSC::AssignResolveNode::emitBytecode):

These functions use findScopedProperty directly in order to
optimise lookup. They cannot trivially handle any degree of
dynamism in the lookup so we just give up in such case.

  • interpreter/Interpreter.cpp: (JSC::Interpreter::resolveGlobalDynamic): (JSC::Interpreter::execute): (JSC::Interpreter::privateExecute):
  • interpreter/Interpreter.h:
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompileSlowCases):
  • jit/JIT.h:
  • jit/JITOpcodes.cpp: (JSC::JIT::emit_op_resolve_global): (JSC::JIT::emit_op_resolve_global_dynamic): (JSC::JIT::emitSlow_op_resolve_global): (JSC::JIT::emitSlow_op_resolve_global_dynamic):

Happily resolve_global_dynamic can share the slow case!

  • jit/JITStubs.h: (JSC::):
  • runtime/JSActivation.cpp: (JSC::JSActivation::isDynamicScope):
  • runtime/JSActivation.h:
  • runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::isDynamicScope):
  • runtime/JSGlobalObject.h:
  • runtime/JSStaticScopeObject.cpp: (JSC::JSStaticScopeObject::isDynamicScope):
  • runtime/JSStaticScopeObject.h:
  • runtime/JSVariableObject.h:
Location:
trunk/JavaScriptCore/interpreter
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/interpreter/Interpreter.cpp

    r58902 r58986  
    192192}
    193193
     194NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
     195{
     196    int dst = vPC[1].u.operand;
     197    JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(vPC[2].u.jsCell);
     198    ASSERT(globalObject->isGlobalObject());
     199    int property = vPC[3].u.operand;
     200    Structure* structure = vPC[4].u.structure;
     201    int offset = vPC[5].u.operand;
     202    CodeBlock* codeBlock = callFrame->codeBlock();
     203    int skip = vPC[6].u.operand + codeBlock->needsFullScopeChain();
     204   
     205    ScopeChainNode* scopeChain = callFrame->scopeChain();
     206    ScopeChainIterator iter = scopeChain->begin();
     207    ScopeChainIterator end = scopeChain->end();
     208    ASSERT(iter != end);
     209    while (skip--) {
     210        JSObject* o = *iter;
     211        if (o->hasCustomProperties()) {
     212            Identifier& ident = codeBlock->identifier(property);
     213            do {
     214                PropertySlot slot(o);
     215                if (o->getPropertySlot(callFrame, ident, slot)) {
     216                    JSValue result = slot.getValue(callFrame, ident);
     217                    exceptionValue = callFrame->globalData().exception;
     218                    if (exceptionValue)
     219                        return false;
     220                    callFrame->r(dst) = JSValue(result);
     221                    return true;
     222                }
     223                if (iter == end)
     224                    break;
     225                o = *iter;
     226                ++iter;
     227            } while (true);
     228            exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
     229            return false;
     230        }
     231        ++iter;
     232    }
     233   
     234    if (structure == globalObject->structure()) {
     235        callFrame->r(dst) = JSValue(globalObject->getDirectOffset(offset));
     236        return true;
     237    }
     238
     239    Identifier& ident = codeBlock->identifier(property);
     240    PropertySlot slot(globalObject);
     241    if (globalObject->getPropertySlot(callFrame, ident, slot)) {
     242        JSValue result = slot.getValue(callFrame, ident);
     243        if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
     244            if (vPC[4].u.structure)
     245                vPC[4].u.structure->deref();
     246            globalObject->structure()->ref();
     247            vPC[4] = globalObject->structure();
     248            vPC[5] = slot.cachedOffset();
     249            callFrame->r(dst) = JSValue(result);
     250            return true;
     251        }
     252       
     253        exceptionValue = callFrame->globalData().exception;
     254        if (exceptionValue)
     255            return false;
     256        callFrame->r(dst) = JSValue(result);
     257        return true;
     258    }
     259   
     260    exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
     261    return false;
     262}
     263
    194264NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC)
    195265{
     
    800870    }
    801871
    802     { // Scope for BatchedTransitionOptimizer
    803 
     872    unsigned numVariables = codeBlock->numVariables();
     873    int numFunctions = codeBlock->numberOfFunctionDecls();
     874    if (numVariables || numFunctions) {
     875        // Scope for BatchedTransitionOptimizer
    804876        BatchedTransitionOptimizer optimizer(variableObject);
    805877
    806         unsigned numVariables = codeBlock->numVariables();
    807878        for (unsigned i = 0; i < numVariables; ++i) {
    808879            const Identifier& ident = codeBlock->variable(i);
     
    813884        }
    814885
    815         int numFunctions = codeBlock->numberOfFunctionDecls();
    816886        for (int i = 0; i < numFunctions; ++i) {
    817887            FunctionExecutable* function = codeBlock->functionDecl(i);
     
    819889            variableObject->put(callFrame, function->name(), function->make(callFrame, scopeChain), slot);
    820890        }
    821 
    822891    }
    823892
     
    19902059        NEXT_INSTRUCTION();
    19912060    }
     2061    DEFINE_OPCODE(op_resolve_global_dynamic) {
     2062        /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n), depth(n)
     2063         
     2064         Performs a dynamic property lookup for the given property, on the provided
     2065         global object.  If structure matches the Structure of the global then perform
     2066         a fast lookup using the case offset, otherwise fall back to a full resolve and
     2067         cache the new structure and offset.
     2068         
     2069         This walks through n levels of the scope chain to verify that none of those levels
     2070         in the scope chain include dynamically added properties.
     2071         */
     2072        if (UNLIKELY(!resolveGlobalDynamic(callFrame, vPC, exceptionValue)))
     2073            goto vm_throw;
     2074       
     2075        vPC += OPCODE_LENGTH(op_resolve_global_dynamic);
     2076       
     2077        NEXT_INSTRUCTION();
     2078    }
    19922079    DEFINE_OPCODE(op_get_global_var) {
    19932080        /* get_global_var dst(r) globalObject(c) index(n)
     
    20172104        vPC += OPCODE_LENGTH(op_put_global_var);
    20182105        NEXT_INSTRUCTION();
    2019     }           
     2106    }
    20202107    DEFINE_OPCODE(op_get_scoped_var) {
    20212108        /* get_scoped_var dst(r) index(n) skip(n)
     
    20362123            ASSERT(iter != end);
    20372124        }
    2038 
    20392125        ASSERT((*iter)->isVariableObject());
    20402126        JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
  • trunk/JavaScriptCore/interpreter/Interpreter.h

    r58012 r58986  
    128128        NEVER_INLINE bool resolveSkip(CallFrame*, Instruction*, JSValue& exceptionValue);
    129129        NEVER_INLINE bool resolveGlobal(CallFrame*, Instruction*, JSValue& exceptionValue);
     130        NEVER_INLINE bool resolveGlobalDynamic(CallFrame*, Instruction*, JSValue& exceptionValue);
    130131        NEVER_INLINE void resolveBase(CallFrame*, Instruction* vPC);
    131132        NEVER_INLINE bool resolveBaseAndProperty(CallFrame*, Instruction*, JSValue& exceptionValue);
Note: See TracChangeset for help on using the changeset viewer.