Ignore:
Timestamp:
Feb 24, 2014, 10:59:38 PM (12 years ago)
Author:
[email protected]
Message:

Spread operator has a bad time when applied to call function
https://bugs.webkit.org/show_bug.cgi?id=128853

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Follow on from the previous patch the added an extra slot to
op_call_varargs (and _call, _call_eval, _construct). We now
use the slot as an offset to in effect act as a 'slice' on
the spread subject. This allows us to automatically retain
all our existing argument and array optimisatons. Most of
this patch is simply threading the offset around.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitCall):
(JSC::BytecodeGenerator::emitCallVarargs):

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

(JSC::getArgumentByVal):
(JSC::CallFunctionCallDotNode::emitBytecode):
(JSC::ApplyFunctionCallDotNode::emitBytecode):

  • interpreter/Interpreter.cpp:

(JSC::sizeFrameForVarargs):
(JSC::loadVarargs):

  • interpreter/Interpreter.h:
  • jit/CCallHelpers.h:

(JSC::CCallHelpers::setupArgumentsWithExecState):

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

(JSC::JIT::compileLoadVarargs):

  • jit/JITInlines.h:

(JSC::JIT::callOperation):

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

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • runtime/Arguments.cpp:

(JSC::Arguments::copyToArguments):

  • runtime/Arguments.h:
  • runtime/JSArray.cpp:

(JSC::JSArray::copyToArguments):

  • runtime/JSArray.h:

LayoutTests:

Test case all the things!

  • js/regress/call-spread-call-expected.txt: Added.
  • js/regress/call-spread-call.html: Added.
  • js/regress/script-tests/call-spread-call.js: Added.

(testFunction):
(test2):
(test3):

File:
1 edited

Legend:

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

    r163960 r164630  
    530530}
    531531
     532static RegisterID* getArgumentByVal(BytecodeGenerator& generator, ExpressionNode* base, RegisterID* property, RegisterID* dst, JSTextPosition divot, JSTextPosition divotStart, JSTextPosition divotEnd)
     533{
     534    if (base->isResolveNode()
     535        && generator.willResolveToArguments(static_cast<ResolveNode*>(base)->identifier())
     536        && !generator.symbolTable().slowArguments()) {
     537        generator.emitExpressionInfo(divot, divotStart, divotEnd);
     538        return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property);
     539    }
     540    return nullptr;
     541}
     542
    532543RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    533544{
     
    536547    RefPtr<RegisterID> base = generator.emitNode(m_base);
    537548    generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
    538     RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().call);
    539     RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get());
     549    RefPtr<RegisterID> function;
    540550    bool emitCallCheck = !generator.isBuiltinFunction();
    541     if (emitCallCheck)
     551    if (emitCallCheck) {
     552        function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().call);
    542553        generator.emitJumpIfNotFunctionCall(function.get(), realCall.get());
    543 
     554    }
     555    RefPtr<RegisterID> returnValue = generator.finalDestination(dst);
    544556    {
    545         if (m_args->m_listNode && m_args->m_listNode->m_expr) {
     557        if (m_args->m_listNode && m_args->m_listNode->m_expr && m_args->m_listNode->m_expr->isSpreadExpression()) {
     558            RefPtr<RegisterID> profileHookRegister;
     559            if (generator.shouldEmitProfileHooks())
     560                profileHookRegister = generator.newTemporary();
     561            SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(m_args->m_listNode->m_expr);
     562            ExpressionNode* subject = spread->expression();
     563            RefPtr<RegisterID> thisRegister = getArgumentByVal(generator, subject, generator.emitLoad(0, jsNumber(0)), 0, spread->divot(), spread->divotStart(), spread->divotEnd());
     564            RefPtr<RegisterID> argumentsRegister;
     565            if (thisRegister)
     566                argumentsRegister = generator.uncheckedRegisterForArguments();
     567            else {
     568                argumentsRegister = generator.emitNode(subject);
     569                generator.emitExpressionInfo(spread->divot(), spread->divotStart(), spread->divotEnd());
     570                thisRegister = generator.emitGetByVal(generator.newTemporary(), argumentsRegister.get(), generator.emitLoad(0, jsNumber(0)));
     571            }
     572            generator.emitCallVarargs(returnValue.get(), base.get(), thisRegister.get(), argumentsRegister.get(), generator.newTemporary(), 1, profileHookRegister.get(), divot(), divotStart(), divotEnd());
     573        } else if (m_args->m_listNode && m_args->m_listNode->m_expr) {
    546574            ArgumentListNode* oldList = m_args->m_listNode;
    547575            m_args->m_listNode = m_args->m_listNode->m_next;
     
    630658        RefPtr<RegisterID> argsRegister;
    631659        ArgumentListNode* args = m_args->m_listNode->m_next;
    632         if (args->m_expr->isResolveNode() && generator.willResolveToArguments(static_cast<ResolveNode*>(args->m_expr)->identifier()))
     660        if (args->m_expr->isResolveNode() && generator.willResolveToArguments(static_cast<ResolveNode*>(args->m_expr)->identifier()) && !generator.symbolTable().slowArguments())
    633661            argsRegister = generator.uncheckedRegisterForArguments();
    634662        else
     
    640668            generator.emitNode(args->m_expr);
    641669
    642         generator.emitCallVarargs(returnValue.get(), realFunction.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), profileHookRegister.get(), divot(), divotStart(), divotEnd());
     670        generator.emitCallVarargs(returnValue.get(), realFunction.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), 0, profileHookRegister.get(), divot(), divotStart(), divotEnd());
    643671    }
    644672    if (emitCallCheck) {
Note: See TracChangeset for help on using the changeset viewer.