Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (179886 => 179887)
--- trunk/Source/_javascript_Core/ChangeLog 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-02-10 23:16:36 UTC (rev 179887)
@@ -1,3 +1,50 @@
+2015-02-10 Filip Pizlo <[email protected]>
+
+ op_call_varargs should only load the length once
+ https://bugs.webkit.org/show_bug.cgi?id=141440
+ rdar://problem/19761683
+
+ Reviewed by Michael Saboff.
+
+ Refactors the pair of calls that set up the varargs frame so that the first call returns the
+ length, and the second call uses the length returned by the first one. It turns out that this
+ gave me an opportunity to shorten a lot of the code.
+
+ * interpreter/Interpreter.cpp:
+ (JSC::sizeFrameForVarargs):
+ (JSC::loadVarargs):
+ (JSC::setupVarargsFrame):
+ (JSC::setupVarargsFrameAndSetThis):
+ * interpreter/Interpreter.h:
+ (JSC::calleeFrameForVarargs):
+ * jit/CCallHelpers.h:
+ (JSC::CCallHelpers::setupArgumentsWithExecState):
+ * jit/JIT.h:
+ * jit/JITCall.cpp:
+ (JSC::JIT::compileSetupVarargsFrame):
+ * jit/JITCall32_64.cpp:
+ (JSC::JIT::compileSetupVarargsFrame):
+ * jit/JITInlines.h:
+ (JSC::JIT::callOperation):
+ * jit/JITOperations.cpp:
+ * jit/JITOperations.h:
+ * jit/SetupVarargsFrame.cpp:
+ (JSC::emitSetVarargsFrame):
+ (JSC::emitSetupVarargsFrameFastCase):
+ * jit/SetupVarargsFrame.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:
+ * runtime/VM.h:
+ * tests/stress/call-varargs-length-effects.js: Added.
+ (foo):
+ (bar):
+
2015-02-10 Michael Saboff <[email protected]>
Crash in JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq
Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (179886 => 179887)
--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2015-02-10 23:16:36 UTC (rev 179887)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009, 2010, 2012, 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2010, 2012, 2013, 2014, 2015 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
@@ -134,158 +134,80 @@
return interpreter->execute(eval, callFrame, thisValue, callerScopeChain);
}
-CallFrame* sizeFrameForVarargs(CallFrame* callFrame, JSStack* stack, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset)
+unsigned sizeFrameForVarargs(CallFrame* callFrame, JSStack* stack, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset)
{
- if (!arguments) { // f.apply(x, arguments), with arguments unmodified.
- unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
- if (argumentCountIncludingThis > firstVarArgOffset)
- argumentCountIncludingThis -= firstVarArgOffset;
- else
- argumentCountIncludingThis = 1;
- unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numUsedStackSlots + argumentCountIncludingThis + JSStack::CallFrameHeaderSize);
- CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
- if (argumentCountIncludingThis > Arguments::MaxArguments + 1 || !stack->ensureCapacityFor(newCallFrame->registers())) {
- throwStackOverflowError(callFrame);
- return 0;
- }
- return newCallFrame;
- }
-
- if (arguments.isUndefinedOrNull()) {
- unsigned argumentCountIncludingThis = 1;
- unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numUsedStackSlots + argumentCountIncludingThis + JSStack::CallFrameHeaderSize);
- CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
- if (!stack->ensureCapacityFor(newCallFrame->registers())) {
- throwStackOverflowError(callFrame);
- return 0;
- }
- return newCallFrame;
- }
-
- if (!arguments.isObject()) {
+ unsigned length;
+ if (!arguments)
+ length = callFrame->argumentCount();
+ else if (arguments.isUndefinedOrNull())
+ length = 0;
+ else if (!arguments.isObject()) {
callFrame->vm().throwException(callFrame, createInvalidParameterError(callFrame, "Function.prototype.apply", arguments));
return 0;
- }
-
- if (asObject(arguments)->classInfo() == Arguments::info()) {
- Arguments* argsObject = asArguments(arguments);
- unsigned argCount = argsObject->length(callFrame);
- if (argCount >= firstVarArgOffset)
- argCount -= firstVarArgOffset;
- else
- argCount = 0;
- unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numUsedStackSlots + argCount + 1 + JSStack::CallFrameHeaderSize);
- CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
- if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) {
- throwStackOverflowError(callFrame);
- return 0;
- }
- return newCallFrame;
- }
-
- if (isJSArray(arguments)) {
- JSArray* array = asArray(arguments);
- unsigned argCount = array->length();
- if (argCount >= firstVarArgOffset)
- argCount -= firstVarArgOffset;
- else
- argCount = 0;
- unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numUsedStackSlots + argCount + 1 + JSStack::CallFrameHeaderSize);
- CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
- if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) {
- throwStackOverflowError(callFrame);
- return 0;
- }
- return newCallFrame;
- }
-
- JSObject* argObject = asObject(arguments);
- unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
- if (argCount >= firstVarArgOffset)
- argCount -= firstVarArgOffset;
+ } else if (asObject(arguments)->classInfo() == Arguments::info())
+ length = asArguments(arguments)->length(callFrame);
+ else if (isJSArray(arguments))
+ length = asArray(arguments)->length();
else
- argCount = 0;
- unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numUsedStackSlots + argCount + 1 + JSStack::CallFrameHeaderSize);
- CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
- if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) {
+ length = asObject(arguments)->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
+
+ if (length >= firstVarArgOffset)
+ length -= firstVarArgOffset;
+ else
+ length = 0;
+
+ CallFrame* calleeFrame = calleeFrameForVarargs(callFrame, numUsedStackSlots, length + 1);
+ if (length > Arguments::MaxArguments || !stack->ensureCapacityFor(calleeFrame->registers())) {
throwStackOverflowError(callFrame);
return 0;
}
- return newCallFrame;
+
+ return length;
}
-void loadVarargs(CallFrame* callFrame, VirtualRegister firstElementDest, VirtualRegister countDest, JSValue arguments, uint32_t firstVarArgOffset)
+void loadVarargs(CallFrame* callFrame, VirtualRegister firstElementDest, JSValue arguments, uint32_t offset, uint32_t length)
{
if (!arguments) { // f.apply(x, arguments), with arguments unmodified.
- unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
- if (argumentCountIncludingThis > firstVarArgOffset)
- argumentCountIncludingThis -= firstVarArgOffset;
- else
- argumentCountIncludingThis = 1;
- callFrame->r(countDest).payload() = argumentCountIncludingThis;
- for (size_t i = firstVarArgOffset; i < callFrame->argumentCount(); ++i)
- callFrame->r(firstElementDest + i - firstVarArgOffset) = callFrame->argumentAfterCapture(i);
+ for (size_t i = 0; i < length; ++i)
+ callFrame->r(firstElementDest + i) = callFrame->argumentAfterCapture(i + offset);
return;
}
- if (arguments.isUndefinedOrNull()) {
- callFrame->r(countDest).payload() = 1;
+ if (arguments.isUndefinedOrNull())
return;
- }
if (asObject(arguments)->classInfo() == Arguments::info()) {
- Arguments* argsObject = asArguments(arguments);
- unsigned argCount = argsObject->length(callFrame);
- if (argCount >= firstVarArgOffset) {
- argCount -= firstVarArgOffset;
- callFrame->r(countDest).payload() = argCount + 1;
- argsObject->copyToArguments(callFrame, firstElementDest, argCount, firstVarArgOffset);
- } else
- callFrame->r(countDest).payload() = 1;
+ asArguments(arguments)->copyToArguments(callFrame, firstElementDest, offset, length);
return;
}
if (isJSArray(arguments)) {
- JSArray* array = asArray(arguments);
- unsigned argCount = array->length();
- if (argCount >= firstVarArgOffset) {
- argCount -= firstVarArgOffset;
- callFrame->r(countDest).payload() = argCount + 1;
- array->copyToArguments(callFrame, firstElementDest, argCount, firstVarArgOffset);
- } else
- callFrame->r(countDest).payload() = 1;
+ asArray(arguments)->copyToArguments(callFrame, firstElementDest, offset, length);
return;
}
- JSObject* argObject = asObject(arguments);
- unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
- if (argCount >= firstVarArgOffset) {
- argCount -= firstVarArgOffset;
- callFrame->r(countDest).payload() = argCount + 1;
- } else
- callFrame->r(countDest).payload() = 1;
-
- for (size_t i = 0; i < argCount; ++i) {
- callFrame->r(firstElementDest + i) = asObject(arguments)->get(callFrame, i + firstVarArgOffset);
+ for (unsigned i = 0; i < length; ++i) {
+ callFrame->r(firstElementDest + i) = asObject(arguments)->get(callFrame, i + offset);
if (UNLIKELY(callFrame->vm().exception()))
return;
}
}
-void setupVarargsFrame(CallFrame* callFrame, CallFrame* newCallFrame, JSValue arguments, uint32_t firstVarArgOffset)
+void setupVarargsFrame(CallFrame* callFrame, CallFrame* newCallFrame, JSValue arguments, uint32_t offset, uint32_t length)
{
VirtualRegister calleeFrameOffset(newCallFrame - callFrame);
loadVarargs(
callFrame,
calleeFrameOffset + CallFrame::argumentOffset(0),
- calleeFrameOffset + JSStack::ArgumentCount,
- arguments, firstVarArgOffset);
+ arguments, offset, length);
+
+ newCallFrame->setArgumentCountIncludingThis(length + 1);
}
-void setupVarargsFrameAndSetThis(CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset)
+void setupVarargsFrameAndSetThis(CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length)
{
- setupVarargsFrame(callFrame, newCallFrame, arguments, firstVarArgOffset);
+ setupVarargsFrame(callFrame, newCallFrame, arguments, firstVarArgOffset, length);
newCallFrame->setThisValue(thisValue);
}
Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.h (179886 => 179887)
--- trunk/Source/_javascript_Core/interpreter/Interpreter.h 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.h 2015-02-10 23:16:36 UTC (rev 179887)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2013, 2015 Apple Inc. All rights reserved.
* Copyright (C) 2012 Research In Motion Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,6 +39,7 @@
#include "LLIntData.h"
#include "Opcode.h"
#include "SourceProvider.h"
+#include "StackAlignment.h"
#include <wtf/HashMap.h>
#include <wtf/text/StringBuilder.h>
@@ -298,10 +299,19 @@
};
JSValue eval(CallFrame*);
- CallFrame* sizeFrameForVarargs(CallFrame* exec, JSStack*, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset);
- void loadVarargs(CallFrame* execCaller, VirtualRegister firstElementDest, VirtualRegister countDest, JSValue source, uint32_t offset);
- void setupVarargsFrame(CallFrame* execCaller, CallFrame* execCallee, JSValue arguments, uint32_t firstVarArgOffset);
- void setupVarargsFrameAndSetThis(CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset);
+
+ inline CallFrame* calleeFrameForVarargs(CallFrame* callFrame, unsigned numUsedStackSlots, unsigned argumentCountIncludingThis)
+ {
+ unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(
+ stackAlignmentRegisters(),
+ numUsedStackSlots + argumentCountIncludingThis + JSStack::CallFrameHeaderSize);
+ return CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
+ }
+
+ unsigned sizeFrameForVarargs(CallFrame* exec, JSStack*, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset);
+ void loadVarargs(CallFrame* execCaller, VirtualRegister firstElementDest, JSValue source, uint32_t offset, uint32_t length);
+ void setupVarargsFrame(CallFrame* execCaller, CallFrame* execCallee, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length);
+ void setupVarargsFrameAndSetThis(CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length);
} // namespace JSC
Modified: trunk/Source/_javascript_Core/jit/CCallHelpers.h (179886 => 179887)
--- trunk/Source/_javascript_Core/jit/CCallHelpers.h 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/jit/CCallHelpers.h 2015-02-10 23:16:36 UTC (rev 179887)
@@ -435,6 +435,17 @@
addCallArgument(arg4);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4, GPRReg arg5)
+ {
+ resetCallArguments();
+ addCallArgument(GPRInfo::callFrameRegister);
+ addCallArgument(arg1);
+ addCallArgument(arg2);
+ addCallArgument(arg3);
+ addCallArgument(arg4);
+ addCallArgument(arg5);
+ }
+
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImmPtr arg2, GPRReg arg3)
{
resetCallArguments();
@@ -1381,6 +1392,12 @@
setupArgumentsWithExecState(arg1, arg2, arg3);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4, GPRReg arg5)
+ {
+ poke(arg4, POKE_ARGUMENT_OFFSET);
+ setupArgumentsWithExecState(arg1, arg2, arg3);
+ }
+
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, GPRReg arg3, GPRReg arg4)
{
poke(arg4, POKE_ARGUMENT_OFFSET);
@@ -1528,6 +1545,12 @@
setupArgumentsWithExecState(arg1, arg2, arg3);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4)
+ {
+ poke(arg4, POKE_ARGUMENT_OFFSET);
+ setupArgumentsWithExecState(arg1, arg2, arg3);
+ }
+
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4, GPRReg arg5)
{
poke(arg5, POKE_ARGUMENT_OFFSET + 1);
@@ -1769,6 +1792,13 @@
move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4)
+ {
+ setupThreeStubArgsGPR<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2, GPRInfo::argumentGPR4>(arg1, arg2, arg4);
+ move(arg3, GPRInfo::argumentGPR3);
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ }
+
ALWAYS_INLINE void setupArguments(GPRReg arg1, TrustedImmPtr arg2, GPRReg arg3, GPRReg arg4, TrustedImmPtr arg5)
{
setupThreeStubArgsGPR<GPRInfo::argumentGPR0, GPRInfo::argumentGPR2, GPRInfo::argumentGPR3>(arg1, arg3, arg4);
Modified: trunk/Source/_javascript_Core/jit/JIT.h (179886 => 179887)
--- trunk/Source/_javascript_Core/jit/JIT.h 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/jit/JIT.h 2015-02-10 23:16:36 UTC (rev 179887)
@@ -679,7 +679,7 @@
MacroAssembler::Call callOperation(C_JITOperation_EL, TrustedImmPtr);
MacroAssembler::Call callOperation(C_JITOperation_ESt, Structure*);
MacroAssembler::Call callOperation(C_JITOperation_EZ, int32_t);
- MacroAssembler::Call callOperation(F_JITOperation_EJZZ, GPRReg, int32_t, int32_t);
+ MacroAssembler::Call callOperation(Z_JITOperation_EJZZ, GPRReg, int32_t, int32_t);
MacroAssembler::Call callOperation(J_JITOperation_E, int);
MacroAssembler::Call callOperation(J_JITOperation_EAapJ, int, ArrayAllocationProfile*, GPRReg);
MacroAssembler::Call callOperation(J_JITOperation_EAapJcpZ, int, ArrayAllocationProfile*, GPRReg, int32_t);
@@ -730,7 +730,7 @@
#endif
MacroAssembler::Call callOperation(V_JITOperation_EJIdJJ, RegisterID, const Identifier*, RegisterID, RegisterID);
#if USE(JSVALUE64)
- MacroAssembler::Call callOperation(F_JITOperation_EFJZ, RegisterID, RegisterID, int32_t);
+ MacroAssembler::Call callOperation(F_JITOperation_EFJZZ, RegisterID, RegisterID, int32_t, RegisterID);
MacroAssembler::Call callOperation(V_JITOperation_ESsiJJI, StructureStubInfo*, RegisterID, RegisterID, StringImpl*);
#else
MacroAssembler::Call callOperation(V_JITOperation_ESsiJJI, StructureStubInfo*, RegisterID, RegisterID, RegisterID, RegisterID, StringImpl*);
@@ -745,8 +745,8 @@
MacroAssembler::Call callOperationWithCallFrameRollbackOnException(V_JITOperation_ECb, CodeBlock*);
MacroAssembler::Call callOperationWithCallFrameRollbackOnException(Z_JITOperation_E);
#if USE(JSVALUE32_64)
- MacroAssembler::Call callOperation(F_JITOperation_EFJZ, RegisterID, RegisterID, RegisterID, int32_t);
- MacroAssembler::Call callOperation(F_JITOperation_EJZZ, GPRReg, GPRReg, int32_t, int32_t);
+ MacroAssembler::Call callOperation(F_JITOperation_EFJZZ, RegisterID, RegisterID, RegisterID, int32_t, RegisterID);
+ MacroAssembler::Call callOperation(Z_JITOperation_EJZZ, GPRReg, GPRReg, int32_t, int32_t);
MacroAssembler::Call callOperation(J_JITOperation_EAapJ, int, ArrayAllocationProfile*, GPRReg, GPRReg);
MacroAssembler::Call callOperation(J_JITOperation_EJ, int, GPRReg, GPRReg);
MacroAssembler::Call callOperation(J_JITOperation_EJIdc, int, GPRReg, GPRReg, const Identifier*);
Modified: trunk/Source/_javascript_Core/jit/JITCall.cpp (179886 => 179887)
--- trunk/Source/_javascript_Core/jit/JITCall.cpp 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/jit/JITCall.cpp 2015-02-10 23:16:36 UTC (rev 179887)
@@ -80,9 +80,11 @@
emitGetVirtualRegister(arguments, regT1);
callOperation(operationSizeFrameForVarargs, regT1, -firstFreeRegister, firstVarArgOffset);
- move(returnValueGPR, stackPointerRegister);
- emitGetVirtualRegister(arguments, regT1);
- callOperation(operationSetupVarargsFrame, returnValueGPR, regT1, firstVarArgOffset);
+ move(TrustedImm32(-firstFreeRegister), regT1);
+ emitSetVarargsFrame(*this, returnValueGPR, false, regT1, regT1);
+ addPtr(TrustedImm32(-(sizeof(CallerFrameAndPC) + WTF::roundUpToMultipleOf(stackAlignmentBytes(), 5 * sizeof(void*)))), regT1, stackPointerRegister);
+ emitGetVirtualRegister(arguments, regT2);
+ callOperation(operationSetupVarargsFrame, regT1, regT2, firstVarArgOffset, regT0);
move(returnValueGPR, regT1);
if (canOptimize)
Modified: trunk/Source/_javascript_Core/jit/JITCall32_64.cpp (179886 => 179887)
--- trunk/Source/_javascript_Core/jit/JITCall32_64.cpp 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/jit/JITCall32_64.cpp 2015-02-10 23:16:36 UTC (rev 179887)
@@ -140,16 +140,11 @@
emitLoad(arguments, regT1, regT0);
callOperation(operationSizeFrameForVarargs, regT1, regT0, -firstFreeRegister, firstVarArgOffset);
- // This is spectacularly dirty. We want to pass four arguments to operationSetupVarargsFrame. On x86-32 we
- // will pass them on the stack. We want four stack slots, or 16 bytes. Extending the stack by 8 bytes
- // over where we planned on pointing the FP gives us enough room. The reason is that the FP gives an
- // extra CallerFrameAndPC bytes beyond where SP should point prior to the call. So if we just did
- // move(returnValueGPR, stackPointerRegister), we'd have enough room for passing two args, or 8
- // bytes - except that we'd have a misaligned stack. So if we subtract *another* CallerFrameAndPC
- // bytes, we are up to 16 bytes of spare room *and* we have an aligned stack. Gross, but correct!
- addPtr(TrustedImm32(-sizeof(CallerFrameAndPC)), returnValueGPR, stackPointerRegister);
- emitLoad(arguments, regT2, regT1);
- callOperation(operationSetupVarargsFrame, returnValueGPR, regT2, regT1, firstVarArgOffset);
+ move(TrustedImm32(-firstFreeRegister), regT1);
+ emitSetVarargsFrame(*this, returnValueGPR, false, regT1, regT1);
+ addPtr(TrustedImm32(-(sizeof(CallerFrameAndPC) + WTF::roundUpToMultipleOf(stackAlignmentBytes(), 6 * sizeof(void*)))), regT1, stackPointerRegister);
+ emitLoad(arguments, regT2, regT4);
+ callOperation(operationSetupVarargsFrame, regT1, regT2, regT4, firstVarArgOffset, regT0);
move(returnValueGPR, regT1);
if (canOptimize)
Modified: trunk/Source/_javascript_Core/jit/JITInlines.h (179886 => 179887)
--- trunk/Source/_javascript_Core/jit/JITInlines.h 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/jit/JITInlines.h 2015-02-10 23:16:36 UTC (rev 179887)
@@ -369,15 +369,15 @@
#if USE(JSVALUE64)
-ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(F_JITOperation_EJZZ operation, GPRReg arg1, int32_t arg2, int32_t arg3)
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(Z_JITOperation_EJZZ operation, GPRReg arg1, int32_t arg2, int32_t arg3)
{
setupArgumentsWithExecState(arg1, TrustedImm32(arg2), TrustedImm32(arg3));
return appendCallWithExceptionCheck(operation);
}
-ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(F_JITOperation_EFJZ operation, GPRReg arg1, GPRReg arg2, int32_t arg3)
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(F_JITOperation_EFJZZ operation, GPRReg arg1, GPRReg arg2, int32_t arg3, GPRReg arg4)
{
- setupArgumentsWithExecState(arg1, arg2, TrustedImm32(arg3));
+ setupArgumentsWithExecState(arg1, arg2, TrustedImm32(arg3), arg4);
return appendCallWithExceptionCheck(operation);
}
@@ -516,15 +516,15 @@
return appendCall(operation);
}
-ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(F_JITOperation_EJZZ operation, GPRReg arg1Tag, GPRReg arg1Payload, int32_t arg2, int32_t arg3)
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(Z_JITOperation_EJZZ operation, GPRReg arg1Tag, GPRReg arg1Payload, int32_t arg2, int32_t arg3)
{
setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, TrustedImm32(arg2), TrustedImm32(arg3));
return appendCallWithExceptionCheck(operation);
}
-ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(F_JITOperation_EFJZ operation, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, int32_t arg3)
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(F_JITOperation_EFJZZ operation, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, int32_t arg3, GPRReg arg4)
{
- setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, TrustedImm32(arg3));
+ setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, TrustedImm32(arg3), arg4);
return appendCallWithExceptionCheck(operation);
}
Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (179886 => 179887)
--- trunk/Source/_javascript_Core/jit/JITOperations.cpp 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp 2015-02-10 23:16:36 UTC (rev 179887)
@@ -1604,22 +1604,21 @@
return JSValue::encode(jsBoolean(result));
}
-CallFrame* JIT_OPERATION operationSizeFrameForVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t numUsedStackSlots, int32_t firstVarArgOffset)
+int32_t JIT_OPERATION operationSizeFrameForVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t numUsedStackSlots, int32_t firstVarArgOffset)
{
VM& vm = exec->vm();
NativeCallFrameTracer tracer(&vm, exec);
JSStack* stack = &exec->interpreter()->stack();
JSValue arguments = JSValue::decode(encodedArguments);
- CallFrame* newCallFrame = sizeFrameForVarargs(exec, stack, arguments, numUsedStackSlots, firstVarArgOffset);
- return newCallFrame;
+ return sizeFrameForVarargs(exec, stack, arguments, numUsedStackSlots, firstVarArgOffset);
}
-CallFrame* JIT_OPERATION operationSetupVarargsFrame(ExecState* exec, CallFrame* newCallFrame, EncodedJSValue encodedArguments, int32_t firstVarArgOffset)
+CallFrame* JIT_OPERATION operationSetupVarargsFrame(ExecState* exec, CallFrame* newCallFrame, EncodedJSValue encodedArguments, int32_t firstVarArgOffset, int32_t length)
{
VM& vm = exec->vm();
NativeCallFrameTracer tracer(&vm, exec);
JSValue arguments = JSValue::decode(encodedArguments);
- setupVarargsFrame(exec, newCallFrame, arguments, firstVarArgOffset);
+ setupVarargsFrame(exec, newCallFrame, arguments, firstVarArgOffset, length);
return newCallFrame;
}
Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (179886 => 179887)
--- trunk/Source/_javascript_Core/jit/JITOperations.h 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h 2015-02-10 23:16:36 UTC (rev 179887)
@@ -87,8 +87,7 @@
Z: int32_t
*/
-typedef CallFrame* JIT_OPERATION (*F_JITOperation_EFJZ)(ExecState*, CallFrame*, EncodedJSValue, int32_t);
-typedef CallFrame* JIT_OPERATION (*F_JITOperation_EJZZ)(ExecState*, EncodedJSValue, int32_t, int32_t);
+typedef CallFrame* JIT_OPERATION (*F_JITOperation_EFJZZ)(ExecState*, CallFrame*, EncodedJSValue, int32_t, int32_t);
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_E)(ExecState*);
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EA)(ExecState*, JSArray*);
typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EAZ)(ExecState*, JSArray*, int32_t);
@@ -151,6 +150,7 @@
typedef int32_t JIT_OPERATION (*Z_JITOperation_D)(double);
typedef int32_t JIT_OPERATION (*Z_JITOperation_E)(ExecState*);
typedef int32_t JIT_OPERATION (*Z_JITOperation_EC)(ExecState*, JSCell*);
+typedef int32_t JIT_OPERATION (*Z_JITOperation_EJZZ)(ExecState*, EncodedJSValue, int32_t, int32_t);
typedef size_t JIT_OPERATION (*S_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
typedef size_t JIT_OPERATION (*S_JITOperation_EJ)(ExecState*, EncodedJSValue);
typedef size_t JIT_OPERATION (*S_JITOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
@@ -309,8 +309,8 @@
EncodedJSValue JIT_OPERATION operationDeleteById(ExecState*, EncodedJSValue base, const Identifier*) WTF_INTERNAL;
JSCell* JIT_OPERATION operationGetPNames(ExecState*, JSObject*) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationInstanceOf(ExecState*, EncodedJSValue, EncodedJSValue proto) WTF_INTERNAL;
-CallFrame* JIT_OPERATION operationSizeFrameForVarargs(ExecState*, EncodedJSValue arguments, int32_t numUsedStackSlots, int32_t firstVarArgOffset) WTF_INTERNAL;
-CallFrame* JIT_OPERATION operationSetupVarargsFrame(ExecState*, CallFrame*, EncodedJSValue arguments, int32_t firstVarArgOffset) WTF_INTERNAL;
+int32_t JIT_OPERATION operationSizeFrameForVarargs(ExecState*, EncodedJSValue arguments, int32_t numUsedStackSlots, int32_t firstVarArgOffset) WTF_INTERNAL;
+CallFrame* JIT_OPERATION operationSetupVarargsFrame(ExecState*, CallFrame*, EncodedJSValue arguments, int32_t firstVarArgOffset, int32_t length) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationToObject(ExecState*, EncodedJSValue) WTF_INTERNAL;
char* JIT_OPERATION operationSwitchCharWithUnknownKeyType(ExecState*, EncodedJSValue key, size_t tableIndex) WTF_INTERNAL;
Modified: trunk/Source/_javascript_Core/jit/SetupVarargsFrame.cpp (179886 => 179887)
--- trunk/Source/_javascript_Core/jit/SetupVarargsFrame.cpp 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/jit/SetupVarargsFrame.cpp 2015-02-10 23:16:36 UTC (rev 179887)
@@ -34,6 +34,23 @@
namespace JSC {
+void emitSetVarargsFrame(CCallHelpers& jit, GPRReg lengthGPR, bool lengthIncludesThis, GPRReg numUsedSlotsGPR, GPRReg resultGPR)
+{
+ jit.move(numUsedSlotsGPR, resultGPR);
+ jit.addPtr(lengthGPR, resultGPR);
+ jit.addPtr(CCallHelpers::TrustedImm32(JSStack::CallFrameHeaderSize + (lengthIncludesThis? 0 : 1)), resultGPR);
+
+ // resultGPR now has the required frame size in Register units
+ // Round resultGPR to next multiple of stackAlignmentRegisters()
+ jit.addPtr(CCallHelpers::TrustedImm32(stackAlignmentRegisters() - 1), resultGPR);
+ jit.andPtr(CCallHelpers::TrustedImm32(~(stackAlignmentRegisters() - 1)), resultGPR);
+
+ // Now resultGPR has the right stack frame offset in Register units.
+ jit.negPtr(resultGPR);
+ jit.lshiftPtr(CCallHelpers::Imm32(3), resultGPR);
+ jit.addPtr(GPRInfo::callFrameRegister, resultGPR);
+}
+
void emitSetupVarargsFrameFastCase(CCallHelpers& jit, GPRReg numUsedSlotsGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, GPRReg scratchGPR3, int inlineStackOffset, unsigned firstVarArgOffset, CCallHelpers::JumpList& slowCase)
{
CCallHelpers::JumpList end;
@@ -48,20 +65,9 @@
endVarArgs.link(&jit);
}
slowCase.append(jit.branch32(CCallHelpers::Above, scratchGPR1, CCallHelpers::TrustedImm32(Arguments::MaxArguments + 1)));
- // scratchGPR1: argumentCountIncludingThis
- jit.move(numUsedSlotsGPR, scratchGPR2);
- jit.addPtr(scratchGPR1, scratchGPR2);
- jit.addPtr(CCallHelpers::TrustedImm32(JSStack::CallFrameHeaderSize), scratchGPR2);
- // scratchGPR2 now has the required frame size in Register units
- // Round scratchGPR2 to next multiple of stackAlignmentRegisters()
- jit.addPtr(CCallHelpers::TrustedImm32(stackAlignmentRegisters() - 1), scratchGPR2);
- jit.andPtr(CCallHelpers::TrustedImm32(~(stackAlignmentRegisters() - 1)), scratchGPR2);
+
+ emitSetVarargsFrame(jit, scratchGPR1, true, numUsedSlotsGPR, scratchGPR2);
- jit.negPtr(scratchGPR2);
- jit.lshiftPtr(CCallHelpers::Imm32(3), scratchGPR2);
- jit.addPtr(GPRInfo::callFrameRegister, scratchGPR2);
- // scratchGPR2: newCallFrame
-
slowCase.append(jit.branchPtr(CCallHelpers::Above, CCallHelpers::AbsoluteAddress(jit.vm()->addressOfStackLimit()), scratchGPR2));
// Initialize ArgumentCount.
Modified: trunk/Source/_javascript_Core/jit/SetupVarargsFrame.h (179886 => 179887)
--- trunk/Source/_javascript_Core/jit/SetupVarargsFrame.h 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/jit/SetupVarargsFrame.h 2015-02-10 23:16:36 UTC (rev 179887)
@@ -33,9 +33,11 @@
namespace JSC {
+void emitSetVarargsFrame(CCallHelpers&, GPRReg lengthGPR, bool lengthIncludesThis, GPRReg numUsedSlotsGPR, GPRReg resultGPR);
+
// Assumes that SP refers to the last in-use stack location, and after this returns SP will point to
// the newly created frame plus the native header. scratchGPR2 may be the same as numUsedSlotsGPR.
-void emitSetupVarargsFrameFastCase(CCallHelpers& jit, GPRReg numUsedSlotsGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, GPRReg scratchGPR3, int inlineStackOffset, unsigned firstVarArgOffset, CCallHelpers::JumpList& slowCase);
+void emitSetupVarargsFrameFastCase(CCallHelpers&, GPRReg numUsedSlotsGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, GPRReg scratchGPR3, int inlineStackOffset, unsigned firstVarArgOffset, CCallHelpers::JumpList& slowCase);
} // namespace JSC
Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (179886 => 179887)
--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2015-02-10 23:16:36 UTC (rev 179887)
@@ -1164,10 +1164,13 @@
// This needs to:
// - Set up a call frame while respecting the variable arguments.
- ExecState* execCallee = sizeFrameForVarargs(exec, &vm.interpreter->stack(),
- LLINT_OP_C(4).jsValue(), -pc[5].u.operand, pc[6].u.operand);
+ unsigned numUsedStackSlots = -pc[5].u.operand;
+ unsigned length = sizeFrameForVarargs(exec, &vm.interpreter->stack(),
+ LLINT_OP_C(4).jsValue(), numUsedStackSlots, pc[6].u.operand);
LLINT_CALL_CHECK_EXCEPTION(exec, exec);
+ ExecState* execCallee = calleeFrameForVarargs(exec, numUsedStackSlots, length + 1);
+ vm.varargsLength = length;
vm.newCallFrameReturnValue = execCallee;
LLINT_RETURN_CALLEE_FRAME(execCallee);
@@ -1184,7 +1187,7 @@
ExecState* execCallee = vm.newCallFrameReturnValue;
- setupVarargsFrameAndSetThis(exec, execCallee, LLINT_OP_C(3).jsValue(), LLINT_OP_C(4).jsValue(), pc[6].u.operand);
+ setupVarargsFrameAndSetThis(exec, execCallee, LLINT_OP_C(3).jsValue(), LLINT_OP_C(4).jsValue(), pc[6].u.operand, vm.varargsLength);
LLINT_CALL_CHECK_EXCEPTION(exec, exec);
execCallee->uncheckedR(JSStack::Callee) = calleeAsValue;
@@ -1205,7 +1208,7 @@
ExecState* execCallee = vm.newCallFrameReturnValue;
- setupVarargsFrameAndSetThis(exec, execCallee, LLINT_OP_C(3).jsValue(), LLINT_OP_C(4).jsValue(), pc[6].u.operand);
+ setupVarargsFrameAndSetThis(exec, execCallee, LLINT_OP_C(3).jsValue(), LLINT_OP_C(4).jsValue(), pc[6].u.operand, vm.varargsLength);
LLINT_CALL_CHECK_EXCEPTION(exec, exec);
execCallee->uncheckedR(JSStack::Callee) = calleeAsValue;
Modified: trunk/Source/_javascript_Core/runtime/Arguments.cpp (179886 => 179887)
--- trunk/Source/_javascript_Core/runtime/Arguments.cpp 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/runtime/Arguments.cpp 2015-02-10 23:16:36 UTC (rev 179887)
@@ -87,22 +87,13 @@
static EncodedJSValue JSC_HOST_CALL argumentsFuncIterator(ExecState*);
-void Arguments::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, uint32_t copyLength, int32_t firstVarArgOffset)
+void Arguments::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length)
{
- uint32_t length = copyLength + firstVarArgOffset;
-
- if (UNLIKELY(m_overrodeLength)) {
- length = min(get(exec, exec->propertyNames().length).toUInt32(exec), length);
- for (unsigned i = firstVarArgOffset; i < length; i++)
- exec->r(firstElementDest + i - firstVarArgOffset) = get(exec, i);
- return;
- }
- ASSERT(length == this->length(exec));
- for (size_t i = firstVarArgOffset; i < length; ++i) {
- if (JSValue value = tryGetArgument(i))
- exec->r(firstElementDest + i - firstVarArgOffset) = value;
+ for (unsigned i = 0; i < length; ++i) {
+ if (JSValue value = tryGetArgument(i + offset))
+ exec->r(firstElementDest + i) = value;
else {
- exec->r(firstElementDest + i - firstVarArgOffset) = get(exec, i);
+ exec->r(firstElementDest + i) = get(exec, i + offset);
if (UNLIKELY(exec->vm().exception()))
return;
}
Modified: trunk/Source/_javascript_Core/runtime/Arguments.h (179886 => 179887)
--- trunk/Source/_javascript_Core/runtime/Arguments.h 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/runtime/Arguments.h 2015-02-10 23:16:36 UTC (rev 179887)
@@ -84,7 +84,7 @@
return m_numArguments;
}
- void copyToArguments(ExecState*, VirtualRegister firstElementDest, uint32_t copyLength, int32_t firstArgumentOffset);
+ void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length);
void tearOff(CallFrame*);
void tearOff(CallFrame*, InlineCallFrame*);
void tearOffForCloning(CallFrame*);
Modified: trunk/Source/_javascript_Core/runtime/JSArray.cpp (179886 => 179887)
--- trunk/Source/_javascript_Core/runtime/JSArray.cpp 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/runtime/JSArray.cpp 2015-02-10 23:16:36 UTC (rev 179887)
@@ -1570,12 +1570,12 @@
args.append(get(exec, i));
}
-void JSArray::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, uint32_t copyLength, int32_t firstVarArgOffset)
+void JSArray::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length)
{
- unsigned i = firstVarArgOffset;
+ unsigned i = offset;
WriteBarrier<Unknown>* vector;
unsigned vectorEnd;
- unsigned length = copyLength + firstVarArgOffset;
+ length += offset; // We like to think of the length as being our length, rather than the output length.
ASSERT(length == this->length());
switch (indexingType()) {
case ArrayClass:
@@ -1602,7 +1602,7 @@
double v = m_butterfly->contiguousDouble()[i];
if (v != v)
break;
- exec->r(firstElementDest + i - firstVarArgOffset) = JSValue(JSValue::EncodeAsDouble, v);
+ exec->r(firstElementDest + i - offset) = JSValue(JSValue::EncodeAsDouble, v);
}
break;
}
@@ -1627,11 +1627,11 @@
WriteBarrier<Unknown>& v = vector[i];
if (!v)
break;
- exec->r(firstElementDest + i - firstVarArgOffset) = v.get();
+ exec->r(firstElementDest + i - offset) = v.get();
}
for (; i < length; ++i) {
- exec->r(firstElementDest + i - firstVarArgOffset) = get(exec, i);
+ exec->r(firstElementDest + i - offset) = get(exec, i);
if (UNLIKELY(exec->vm().exception()))
return;
}
Modified: trunk/Source/_javascript_Core/runtime/JSArray.h (179886 => 179887)
--- trunk/Source/_javascript_Core/runtime/JSArray.h 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/runtime/JSArray.h 2015-02-10 23:16:36 UTC (rev 179887)
@@ -132,7 +132,7 @@
}
JS_EXPORT_PRIVATE void fillArgList(ExecState*, MarkedArgumentBuffer&);
- JS_EXPORT_PRIVATE void copyToArguments(ExecState*, VirtualRegister firstElementDest, uint32_t length, int32_t firstVarArgOffset);
+ JS_EXPORT_PRIVATE void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length);
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType)
{
Modified: trunk/Source/_javascript_Core/runtime/VM.h (179886 => 179887)
--- trunk/Source/_javascript_Core/runtime/VM.h 2015-02-10 23:07:47 UTC (rev 179886)
+++ trunk/Source/_javascript_Core/runtime/VM.h 2015-02-10 23:16:36 UTC (rev 179887)
@@ -410,6 +410,7 @@
const ClassInfo* const jsFinalObjectClassInfo;
JSValue hostCallReturnValue;
+ unsigned varargsLength;
ExecState* newCallFrameReturnValue;
VMEntryFrame* vmEntryFrameForThrow;
ExecState* callFrameForThrow;
Added: trunk/Source/_javascript_Core/tests/stress/call-varargs-length-effects.js (0 => 179887)
--- trunk/Source/_javascript_Core/tests/stress/call-varargs-length-effects.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/call-varargs-length-effects.js 2015-02-10 23:16:36 UTC (rev 179887)
@@ -0,0 +1,24 @@
+function foo() { return arguments.length; }
+
+var o = {};
+o[0] = 42;
+var callCount = 0;
+o.__defineGetter__("length", function() {
+ callCount++;
+ return 1;
+});
+
+function bar() {
+ callCount = 0;
+ var result = foo.apply(this, o);
+ if (result != 1)
+ throw "Error: bad result: " + result;
+ if (callCount != 1)
+ throw "Error: bad call count: " + callCount;
+}
+
+noInline(foo);
+noInline(bar);
+
+for (var i = 0; i < 10000; ++i)
+ bar();