Ignore:
Timestamp:
Feb 9, 2015, 7:27:43 PM (11 years ago)
Author:
[email protected]
Message:

Varargs frame set-up should be factored out for use by other JITs
https://bugs.webkit.org/show_bug.cgi?id=141388

Reviewed by Michael Saboff.

Previously the code that dealt with varargs always assumed that we were setting up a varargs call
frame by literally following the execution semantics of op_call_varargs. This isn't how it'll
happen once the DFG and FTL do varargs calls, or when varargs calls get inlined. The DFG and FTL
don't literally execute bytecode; for example their stack frame layout has absolutely nothing in
common with what the bytecode says, and that will never change.

This patch makes two changes:

Setting up the varargs callee frame can be done in smaller steps: particularly in the case of a
varargs call that gets inlined, we aren't going to actually want to set up a callee frame in
full - we just want to put the arguments somewhere, and that place will not have much (if
anything) in common with the call frame format. This patch factors that out into something called
a loadVarargs. The thing we used to call loadVarargs is now called setupVarargsFrame. This patch
also separates loading varargs from setting this, since the fact that those two things are done
together is a detail made explicit in bytecode but it's not at all required in the higher-tier
engines. In the process of factoring this code out, I found a bunch of off-by-one errors in the
various calculations. I fixed them. The distance from the caller's frame pointer to the callee
frame pointer is always:

numUsedCallerSlots + argCount + 1 + CallFrameSize


where numUsedCallerSlots is toLocal(firstFreeRegister) - 1, which simplifies down to just
-firstFreeRegister. The code now speaks of numUsedCallerSlots rather than firstFreeRegister,
since the latter is a bytecode peculiarity that doesn't apply in the DFG or FTL. In the DFG, the
internally-computed frame size, minus the parameter slots, will be used for numUsedCallerSlots.
In the FTL, we will essentially compute numUsedCallerSlots dynamically by subtracting SP from FP.
Eventually, LLVM might give us some cleaner way of doing this, but it probably doesn't matter
very much.

The arguments forwarding optimization is factored out of the Baseline JIT: the DFG and FTL will
want to do this optimization as well, but it involves quite a bit of code. So, this code is now
factored out into SetupVarargsFrame.h|cpp, so that other JITs can use it. In the process of factoring
this code out I noticed that the 32-bit and 64-bit code is nearly identical, so I combined them.

(JSC::ExecState::r):
(JSC::ExecState::uncheckedR):

  • bytecode/VirtualRegister.h:

(JSC::VirtualRegister::operator+):
(JSC::VirtualRegister::operator-):
(JSC::VirtualRegister::operator+=):
(JSC::VirtualRegister::operator-=):

  • interpreter/CallFrame.h:
  • interpreter/Interpreter.cpp:

(JSC::sizeFrameForVarargs):
(JSC::loadVarargs):
(JSC::setupVarargsFrame):
(JSC::setupVarargsFrameAndSetThis):

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

(JSC::AssemblyHelpers::emitGetFromCallFrameHeaderPtr):
(JSC::AssemblyHelpers::emitGetFromCallFrameHeader32):
(JSC::AssemblyHelpers::emitGetFromCallFrameHeader64):

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

(JSC::JIT::compileSetupVarargsFrame):

  • jit/JITCall32_64.cpp:

(JSC::JIT::compileSetupVarargsFrame):

  • jit/JITInlines.h:

(JSC::JIT::callOperation):
(JSC::JIT::emitGetFromCallFrameHeaderPtr): Deleted.
(JSC::JIT::emitGetFromCallFrameHeader32): Deleted.
(JSC::JIT::emitGetFromCallFrameHeader64): Deleted.

  • jit/JITOperations.cpp:
  • jit/JITOperations.h:
  • jit/SetupVarargsFrame.cpp: Added.

(JSC::emitSetupVarargsFrameFastCase):

  • jit/SetupVarargsFrame.h: Added.
  • 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:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/jit/JITCall.cpp

    r179478 r179862  
    11/*
    2  * Copyright (C) 2008, 2013, 2014 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2013-2015 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4141#include "ResultType.h"
    4242#include "SamplingTool.h"
     43#include "SetupVarargsFrame.h"
    4344#include "StackAlignment.h"
    4445#include "ThunkGenerators.h"
     
    5556}
    5657
    57 void JIT::compileLoadVarargs(Instruction* instruction)
     58void JIT::compileSetupVarargsFrame(Instruction* instruction)
    5859{
    5960    int thisValue = instruction[3].u.operand;
     
    7172        emitGetVirtualRegister(arguments, regT0);
    7273        slowCase.append(branch64(NotEqual, regT0, TrustedImm64(JSValue::encode(JSValue()))));
    73 
    74         emitGetFromCallFrameHeader32(JSStack::ArgumentCount, regT0);
    75         if (firstVarArgOffset) {
    76             Jump sufficientArguments = branch32(GreaterThan, regT0, TrustedImm32(firstVarArgOffset + 1));
    77             move(TrustedImm32(1), regT0);
    78             Jump endVarArgs = jump();
    79             sufficientArguments.link(this);
    80             sub32(TrustedImm32(firstVarArgOffset), regT0);
    81             endVarArgs.link(this);
    82         }
    83         slowCase.append(branch32(Above, regT0, TrustedImm32(Arguments::MaxArguments + 1)));
    84         // regT0: argumentCountIncludingThis
    85         move(regT0, regT1);
    86         add64(TrustedImm32(-firstFreeRegister + JSStack::CallFrameHeaderSize), regT1);
    87         // regT1 now has the required frame size in Register units
    88         // Round regT1 to next multiple of stackAlignmentRegisters()
    89         add64(TrustedImm32(stackAlignmentRegisters() - 1), regT1);
    90         and64(TrustedImm32(~(stackAlignmentRegisters() - 1)), regT1);
    91 
    92         neg64(regT1);
    93         lshift64(TrustedImm32(3), regT1);
    94         addPtr(callFrameRegister, regT1);
    95         // regT1: newCallFrame
    96 
    97         slowCase.append(branchPtr(Above, AbsoluteAddress(m_vm->addressOfStackLimit()), regT1));
    98 
    99         // Initialize ArgumentCount.
    100         store32(regT0, Address(regT1, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
    101 
    102         // Initialize 'this'.
    103         emitGetVirtualRegister(thisValue, regT2);
    104         store64(regT2, Address(regT1, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))));
    105 
    106         // Copy arguments.
    107         signExtend32ToPtr(regT0, regT0);
    108         end.append(branchSub64(Zero, TrustedImm32(1), regT0));
    109         // regT0: argumentCount
    110 
    111         Label copyLoop = label();
    112         load64(BaseIndex(callFrameRegister, regT0, TimesEight, (CallFrame::thisArgumentOffset() + firstVarArgOffset) * static_cast<int>(sizeof(Register))), regT2);
    113         store64(regT2, BaseIndex(regT1, regT0, TimesEight, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))));
    114         branchSub64(NonZero, TrustedImm32(1), regT0).linkTo(copyLoop, this);
    115 
     74       
     75        move(TrustedImm32(-firstFreeRegister), regT1);
     76        emitSetupVarargsFrameFastCase(*this, regT1, regT0, regT1, regT2, 0, firstVarArgOffset, slowCase);
    11677        end.append(jump());
     78        slowCase.link(this);
    11779    }
    11880
    119     if (canOptimize)
    120         slowCase.link(this);
    121 
    12281    emitGetVirtualRegister(arguments, regT1);
    123     callOperation(operationSizeFrameForVarargs, regT1, firstFreeRegister, firstVarArgOffset);
     82    callOperation(operationSizeFrameForVarargs, regT1, -firstFreeRegister, firstVarArgOffset);
    12483    move(returnValueGPR, stackPointerRegister);
    125     emitGetVirtualRegister(thisValue, regT1);
    126     emitGetVirtualRegister(arguments, regT2);
    127     callOperation(operationLoadVarargs, returnValueGPR, regT1, regT2, firstVarArgOffset);
     84    emitGetVirtualRegister(arguments, regT1);
     85    callOperation(operationSetupVarargsFrame, returnValueGPR, regT1, firstVarArgOffset);
    12886    move(returnValueGPR, regT1);
    12987
     
    13189        end.link(this);
    13290   
     91    // Initialize 'this'.
     92    emitGetVirtualRegister(thisValue, regT0);
     93    store64(regT0, Address(regT1, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))));
     94
    13395    addPtr(TrustedImm32(sizeof(CallerFrameAndPC)), regT1, stackPointerRegister);
    13496}
     
    189151    COMPILE_ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct_varargs), call_and_construct_varargs_opcodes_must_be_same_length);
    190152    if (opcodeID == op_call_varargs || opcodeID == op_construct_varargs)
    191         compileLoadVarargs(instruction);
     153        compileSetupVarargsFrame(instruction);
    192154    else {
    193155        int argCount = instruction[3].u.operand;
Note: See TracChangeset for help on using the changeset viewer.