Changeset 42065 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
Mar 27, 2009, 8:50:39 PM (16 years ago)
Author:
[email protected]
Message:

Improve performance of Function.prototype.call
<https://bugs.webkit.org/show_bug.cgi?id=24907>

Reviewed by Gavin Barraclough

Optimistically assume that expression.call(..) is going to be a call to
Function.prototype.call, and handle it specially to attempt to reduce the
degree of VM reentrancy.

When everything goes right this removes the vm reentry improving .call()
by around a factor of 10.

Location:
trunk/JavaScriptCore
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r42037 r42065  
     12009-03-27  Oliver Hunt  <[email protected]>
     2
     3        Reviewed by Gavin Barraclough.
     4
     5        Improve performance of Function.prototype.call
     6        <https://bugs.webkit.org/show_bug.cgi?id=24907>
     7
     8        Optimistically assume that expression.call(..) is going to be a call to
     9        Function.prototype.call, and handle it specially to attempt to reduce the
     10        degree of VM reentrancy.
     11
     12        When everything goes right this removes the vm reentry improving .call()
     13        by around a factor of 10.
     14
     15        * JavaScriptCore.xcodeproj/project.pbxproj:
     16        * bytecode/CodeBlock.cpp:
     17        (JSC::CodeBlock::dump):
     18        * bytecode/Opcode.h:
     19        * bytecompiler/BytecodeGenerator.cpp:
     20        (JSC::BytecodeGenerator::emitJumpIfNotFunctionCall):
     21        * bytecompiler/BytecodeGenerator.h:
     22        * interpreter/Interpreter.cpp:
     23        (JSC::Interpreter::privateExecute):
     24        * jit/JIT.cpp:
     25        (JSC::JIT::privateCompileMainPass):
     26        * parser/Grammar.y:
     27        * parser/Nodes.cpp:
     28        (JSC::CallFunctionCallDotNode::emitBytecode):
     29        * parser/Nodes.h:
     30        (JSC::CallFunctionCallDotNode::):
     31        * runtime/FunctionPrototype.cpp:
     32        (JSC::FunctionPrototype::addFunctionProperties):
     33        * runtime/FunctionPrototype.h:
     34        * runtime/JSGlobalObject.cpp:
     35        (JSC::JSGlobalObject::reset):
     36        (JSC::JSGlobalObject::mark):
     37        * runtime/JSGlobalObject.h:
     38
    1392009-03-27  Laszlo Gombos  <[email protected]>
    240
  • trunk/JavaScriptCore/bytecode/CodeBlock.cpp

    r40993 r42065  
    889889            break;
    890890        }
    891         case op_jnless: {
     891        case op_jneq_ptr: {
    892892            int r0 = (++it)->u.operand;
    893893            int r1 = (++it)->u.operand;
    894894            int offset = (++it)->u.operand;
    895             printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
     895            printf("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
     896            break;
     897        }
     898        case op_jnless: {
     899            int r0 = (++it)->u.operand;
     900            JSValuePtr function = JSValuePtr((++it)->u.jsCell);
     901            int offset = (++it)->u.operand;
     902            printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), valueToSourceString(exec, function).ascii(), offset, locationForOffset(begin, it, offset));
    896903            break;
    897904        }
  • trunk/JavaScriptCore/bytecode/Opcode.h

    r39752 r42065  
    126126        macro(op_jeq_null, 3) \
    127127        macro(op_jneq_null, 3) \
     128        macro(op_jneq_ptr, 4) \
    128129        macro(op_jnless, 4) \
    129130        macro(op_jmp_scopes, 3) \
  • trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r40993 r42065  
    692692    emitOpcode(op_jfalse);
    693693    instructions().append(cond->index());
     694    instructions().append(target->offsetFrom(instructions().size()));
     695    return target;
     696}
     697
     698PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionCall(RegisterID* cond, Label* target)
     699{
     700    emitOpcode(op_jneq_ptr);
     701    instructions().append(cond->index());
     702    instructions().append(m_scopeChain->globalObject()->d()->callFunction);
    694703    instructions().append(target->offsetFrom(instructions().size()));
    695704    return target;
  • trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r41998 r42065  
    299299        PassRefPtr<Label> emitJumpIfTrue(RegisterID* cond, Label* target);
    300300        PassRefPtr<Label> emitJumpIfFalse(RegisterID* cond, Label* target);
     301        PassRefPtr<Label> emitJumpIfNotFunctionCall(RegisterID* cond, Label* target);
    301302        PassRefPtr<Label> emitJumpScopes(Label* target, int targetScopeDepth);
    302303
  • trunk/JavaScriptCore/interpreter/Interpreter.cpp

    r41999 r42065  
    26672667        NEXT_INSTRUCTION();
    26682668    }
     2669    DEFINE_OPCODE(op_jneq_ptr) {
     2670        /* jneq_ptr src(r) ptr(jsCell) target(offset)
     2671         
     2672           Jumps to offset target from the current instruction, if the value r is equal
     2673           to ptr, using pointer equality.
     2674         */
     2675        int src = (++vPC)->u.operand;
     2676        JSValuePtr ptr = JSValuePtr((++vPC)->u.jsCell);
     2677        int target = (++vPC)->u.operand;
     2678        JSValuePtr srcValue = callFrame[src].jsValue(callFrame);
     2679        if (srcValue != ptr) {
     2680            vPC += target;
     2681            NEXT_INSTRUCTION();
     2682        }
     2683
     2684        ++vPC;
     2685        NEXT_INSTRUCTION();
     2686    }
    26692687    DEFINE_OPCODE(op_loop_if_less) {
    26702688        /* loop_if_less src1(r) src2(r) target(offset)
  • trunk/JavaScriptCore/jit/JIT.cpp

    r41544 r42065  
    820820            NEXT_OPCODE(op_jneq_null);
    821821        }
     822        case op_jneq_ptr: {
     823            unsigned src = currentInstruction[1].u.operand;
     824            JSCell* ptr = currentInstruction[2].u.jsCell;
     825            unsigned target = currentInstruction[3].u.operand;
     826           
     827            emitGetVirtualRegister(src, regT0);
     828            addJump(branchPtr(NotEqual, regT0, ImmPtr(JSValuePtr::encode(JSValuePtr(ptr)))), target + 3);           
     829
     830            RECORD_JUMP_TARGET(target + 3);
     831            NEXT_OPCODE(op_jneq_ptr);
     832        }
    822833        case op_post_inc: {
    823834            compileFastArith_op_post_inc(currentInstruction[1].u.operand, currentInstruction[2].u.operand);
  • trunk/JavaScriptCore/parser/Grammar.y

    r39554 r42065  
    19261926    ASSERT(func.m_node->isDotAccessorNode());
    19271927    DotAccessorNode* dot = static_cast<DotAccessorNode*>(func.m_node);
    1928     FunctionCallDotNode* node = new FunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot);
     1928    FunctionCallDotNode* node;
     1929    if (dot->identifier() == GLOBAL_DATA->propertyNames->call)
     1930        node = new CallFunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot);
     1931    else
     1932        node = new FunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot);
    19291933    node->setSubexpressionInfo(dot->divot(), dot->endOffset());
    19301934    return createNodeInfo<ExpressionNode*>(node, features, numConstants);
  • trunk/JavaScriptCore/parser/Nodes.cpp

    r41806 r42065  
    693693    RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get());
    694694    return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
     695}
     696
     697RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
     698{
     699    RefPtr<Label> realCall = generator.newLabel();
     700    RefPtr<Label> end = generator.newLabel();
     701    RefPtr<RegisterID> base = generator.emitNode(m_base.get());
     702    generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset);
     703    RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
     704    RefPtr<RegisterID> finalDestination = generator.finalDestination(dst, function.get());
     705    generator.emitJumpIfNotFunctionCall(function.get(), realCall.get());
     706    {
     707        RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
     708        RefPtr<RegisterID> thisRegister = generator.newTemporary();
     709        RefPtr<ArgumentListNode> oldList = m_args->m_listNode;
     710        if (m_args->m_listNode && m_args->m_listNode->m_expr) {
     711            generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr.get());
     712            m_args->m_listNode = m_args->m_listNode->m_next;
     713        } else {
     714            generator.emitLoad(thisRegister.get(), jsNull());
     715        }
     716        generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
     717        generator.emitJump(end.get());
     718        m_args->m_listNode = oldList;
     719    }
     720    generator.emitLabel(realCall.get());
     721    {
     722        RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get());
     723        generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset());
     724    }
     725    generator.emitLabel(end.get());
     726    return finalDestination.get();
    695727}
    696728
  • trunk/JavaScriptCore/parser/Nodes.h

    r41343 r42065  
    764764        virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
    765765
    766     private:
     766    protected:
    767767        RefPtr<ExpressionNode> m_base;
    768768        Identifier m_ident;
    769769        RefPtr<ArgumentsNode> m_args;
     770    };
     771
     772    class CallFunctionCallDotNode : public FunctionCallDotNode {
     773    public:
     774        CallFunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
     775            : FunctionCallDotNode(globalData, base, ident, args, divot, startOffset, endOffset)
     776        {
     777        }
     778        virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
    770779    };
    771780
  • trunk/JavaScriptCore/runtime/FunctionPrototype.cpp

    r41168 r42065  
    4444}
    4545
    46 void FunctionPrototype::addFunctionProperties(ExecState* exec, Structure* prototypeFunctionStructure)
     46void FunctionPrototype::addFunctionProperties(ExecState* exec, Structure* prototypeFunctionStructure, PrototypeFunction** callFunction)
    4747{
    4848    putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, functionProtoFuncToString), DontEnum);
    4949    putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 2, exec->propertyNames().apply, functionProtoFuncApply), DontEnum);
    50     putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 1, exec->propertyNames().call, functionProtoFuncCall), DontEnum);
     50    *callFunction = new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 1, exec->propertyNames().call, functionProtoFuncCall);
     51    putDirectFunctionWithoutTransition(exec, *callFunction, DontEnum);
    5152}
    5253
  • trunk/JavaScriptCore/runtime/FunctionPrototype.h

    r39670 r42065  
    2626namespace JSC {
    2727
     28    class PrototypeFunction;
     29
    2830    class FunctionPrototype : public InternalFunction {
    2931    public:
    3032        FunctionPrototype(ExecState*, PassRefPtr<Structure>);
    31         void addFunctionProperties(ExecState*, Structure* prototypeFunctionStructure);
     33        void addFunctionProperties(ExecState*, Structure* prototypeFunctionStructure, PrototypeFunction** callFunction);
    3234
    3335        static PassRefPtr<Structure> createStructure(JSValuePtr proto)
  • trunk/JavaScriptCore/runtime/JSGlobalObject.cpp

    r41846 r42065  
    204204    d()->functionPrototype = new (exec) FunctionPrototype(exec, FunctionPrototype::createStructure(jsNull())); // The real prototype will be set once ObjectPrototype is created.
    205205    d()->prototypeFunctionStructure = PrototypeFunction::createStructure(d()->functionPrototype);
    206     d()->functionPrototype->addFunctionProperties(exec, d()->prototypeFunctionStructure.get());
     206    PrototypeFunction* callFunction = 0;
     207    d()->functionPrototype->addFunctionProperties(exec, d()->prototypeFunctionStructure.get(), &callFunction);
     208    d()->callFunction = callFunction;
    207209    d()->objectPrototype = new (exec) ObjectPrototype(exec, ObjectPrototype::createStructure(jsNull()), d()->prototypeFunctionStructure.get());
    208210    d()->functionPrototype->structure()->setPrototypeWithoutTransition(d()->objectPrototype);
     
    371373
    372374    markIfNeeded(d()->evalFunction);
     375    markIfNeeded(d()->callFunction);
    373376
    374377    markIfNeeded(d()->objectPrototype);
  • trunk/JavaScriptCore/runtime/JSGlobalObject.h

    r41232 r42065  
    4141    class NativeErrorConstructor;
    4242    class ProgramCodeBlock;
     43    class PrototypeFunction;
    4344    class RegExpConstructor;
    4445    class RegExpPrototype;
     
    105106
    106107            GlobalEvalFunction* evalFunction;
     108            PrototypeFunction* callFunction;
    107109
    108110            ObjectPrototype* objectPrototype;
Note: See TracChangeset for help on using the changeset viewer.