Diff
Modified: branches/jsc-tailcall/Source/_javascript_Core/ChangeLog (188317 => 188318)
--- branches/jsc-tailcall/Source/_javascript_Core/ChangeLog 2015-08-12 01:46:06 UTC (rev 188317)
+++ branches/jsc-tailcall/Source/_javascript_Core/ChangeLog 2015-08-12 01:59:31 UTC (rev 188318)
@@ -1,5 +1,32 @@
2015-08-11 Basile Clement <[email protected]>
+ jsc-tailcall: Arity fixup should make use of the possible extra empty slots at top of the frame
+ https://bugs.webkit.org/show_bug.cgi?id=147893
+
+ Reviewed by Michael Saboff.
+
+ This changes the way arity fixup is performed. Since r187767, we always
+ ensure that the total amount of space reserved for a call frame is
+ stack-aligned, which means that for a non-aligned call frame size, we
+ have an additional "free" slot at the top of the frame. This makes it
+ so that when performing arity fixup, we first use that space if
+ necessary before moving the frame down.
+
+ This ensures that the total stack space used by a frame is always
+ max(argCount, numParameters) + JSStack::CallFrameHeaderSize, rounded up
+ to be a multiple of 2.
+
+ * jit/CCallHelpers.h:
+ * jit/ThunkGenerators.cpp:
+ (JSC::arityFixupGenerator):
+ * llint/LowLevelInterpreter.asm:
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+ * runtime/CommonSlowPaths.h:
+ (JSC::CommonSlowPaths::arityCheckFor): Returns the padding in amount of slots instead of aligned stack units
+
+2015-08-11 Basile Clement <[email protected]>
+
jsc-tailcall: Make tail call tests run in all tiers
https://bugs.webkit.org/show_bug.cgi?id=147895
Modified: branches/jsc-tailcall/Source/_javascript_Core/jit/CCallHelpers.h (188317 => 188318)
--- branches/jsc-tailcall/Source/_javascript_Core/jit/CCallHelpers.h 2015-08-12 01:46:06 UTC (rev 188317)
+++ branches/jsc-tailcall/Source/_javascript_Core/jit/CCallHelpers.h 2015-08-12 01:59:31 UTC (rev 188318)
@@ -2047,10 +2047,7 @@
loadPtr(Address(GPRInfo::callFrameRegister, JSStack::CodeBlock * static_cast<int>(sizeof(Register))), temp2);
load32(Address(temp2, CodeBlock::offsetOfNumParameters()), temp2);
MacroAssembler::Jump argumentCountWasNotFixedUp = branch32(BelowOrEqual, temp2, temp1);
- sub32(temp1, temp2);
- add32(TrustedImm32(stackAlignmentRegisters() - 1), temp2);
- and32(TrustedImm32(-stackAlignmentRegisters()), temp2);
- add32(temp2, temp1);
+ move(temp2, temp1);
argumentCountWasNotFixedUp.link(this);
add32(TrustedImm32(stackAlignmentRegisters() + JSStack::CallFrameHeaderSize - 1), temp1);
Modified: branches/jsc-tailcall/Source/_javascript_Core/jit/ThunkGenerators.cpp (188317 => 188318)
--- branches/jsc-tailcall/Source/_javascript_Core/jit/ThunkGenerators.cpp 2015-08-12 01:46:06 UTC (rev 188317)
+++ branches/jsc-tailcall/Source/_javascript_Core/jit/ThunkGenerators.cpp 2015-08-12 01:59:31 UTC (rev 188318)
@@ -367,7 +367,7 @@
{
JSInterfaceJIT jit(vm);
- // We enter with fixup count, in aligned stack units, in argumentGPR0 and the return thunk in argumentGPR1
+ // We enter with fixup count in argumentGPR0
// We have the guarantee that a0, a1, a2, t3, t4 and t5 (or t0 for Windows) are all distinct :-)
#if USE(JSVALUE64)
#if OS(WINDOWS)
@@ -378,12 +378,25 @@
# if CPU(X86_64)
jit.pop(JSInterfaceJIT::regT4);
# endif
- jit.lshift32(JSInterfaceJIT::TrustedImm32(logStackAlignmentRegisters()), JSInterfaceJIT::argumentGPR0);
- jit.neg64(JSInterfaceJIT::argumentGPR0);
jit.move(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::regT3);
jit.load32(JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, JSStack::ArgumentCount * sizeof(Register)), JSInterfaceJIT::argumentGPR2);
jit.add32(JSInterfaceJIT::TrustedImm32(JSStack::CallFrameHeaderSize), JSInterfaceJIT::argumentGPR2);
+ // Check to see if we have extra slots we can use
+ jit.move(JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::argumentGPR1);
+ jit.and32(JSInterfaceJIT::TrustedImm32(stackAlignmentRegisters() - 1), JSInterfaceJIT::argumentGPR1);
+ JSInterfaceJIT::Jump noExtraSlot = jit.branchTest32(MacroAssembler::Zero, JSInterfaceJIT::argumentGPR1);
+ jit.move(JSInterfaceJIT::TrustedImm64(ValueUndefined), extraTemp);
+ JSInterfaceJIT::Label fillExtraSlots(jit.label());
+ jit.store64(extraTemp, MacroAssembler::BaseIndex(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::argumentGPR2, JSInterfaceJIT::TimesEight));
+ jit.add32(JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2);
+ jit.branchSub32(JSInterfaceJIT::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR1).linkTo(fillExtraSlots, &jit);
+ jit.and32(JSInterfaceJIT::TrustedImm32(-stackAlignmentRegisters()), JSInterfaceJIT::argumentGPR0);
+ JSInterfaceJIT::Jump done = jit.branchTest32(MacroAssembler::Zero, JSInterfaceJIT::argumentGPR0);
+ noExtraSlot.link(&jit);
+
+ jit.neg64(JSInterfaceJIT::argumentGPR0);
+
// Move current frame down argumentGPR0 number of slots
JSInterfaceJIT::Label copyLoop(jit.label());
jit.load64(JSInterfaceJIT::regT3, extraTemp);
@@ -405,6 +418,8 @@
jit.addPtr(extraTemp, JSInterfaceJIT::callFrameRegister);
jit.addPtr(extraTemp, JSInterfaceJIT::stackPointerRegister);
+ done.link(&jit);
+
# if CPU(X86_64)
jit.push(JSInterfaceJIT::regT4);
# endif
@@ -413,18 +428,33 @@
# if CPU(X86)
jit.pop(JSInterfaceJIT::regT4);
# endif
- jit.lshift32(JSInterfaceJIT::TrustedImm32(logStackAlignmentRegisters()), JSInterfaceJIT::argumentGPR0);
- jit.neg32(JSInterfaceJIT::argumentGPR0);
jit.move(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::regT3);
jit.load32(JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, JSStack::ArgumentCount * sizeof(Register)), JSInterfaceJIT::argumentGPR2);
jit.add32(JSInterfaceJIT::TrustedImm32(JSStack::CallFrameHeaderSize), JSInterfaceJIT::argumentGPR2);
+ // Check to see if we have extra slots we can use
+ jit.move(JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::argumentGPR1);
+ jit.and32(JSInterfaceJIT::TrustedImm32(stackAlignmentRegisters() - 1), JSInterfaceJIT::argumentGPR1);
+ JSInterfaceJIT::Jump noExtraSlot = jit.branchTest32(MacroAssembler::Zero, JSInterfaceJIT::argumentGPR1);
+ JSInterfaceJIT::Label fillExtraSlots(jit.label());
+ jit.move(JSInterfaceJIT::TrustedImm32(0), JSInterfaceJIT::regT5);
+ jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::argumentGPR2, JSInterfaceJIT::TimesEight, PayloadOffset));
+ jit.move(JSInterfaceJIT::TrustedImm32(JSValue::UndefinedTag), JSInterfaceJIT::regT5);
+ jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::argumentGPR2, JSInterfaceJIT::TimesEight, TagOffset));
+ jit.add32(JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2);
+ jit.branchSub32(JSInterfaceJIT::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR1).linkTo(fillExtraSlots, &jit);
+ jit.and32(JSInterfaceJIT::TrustedImm32(-stackAlignmentRegisters()), JSInterfaceJIT::argumentGPR0);
+ JSInterfaceJIT::Jump done = jit.branchTest32(MacroAssembler::Zero, JSInterfaceJIT::argumentGPR0);
+ noExtraSlot.link(&jit);
+
+ jit.neg32(JSInterfaceJIT::argumentGPR0);
+
// Move current frame down argumentGPR0 number of slots
JSInterfaceJIT::Label copyLoop(jit.label());
- jit.load32(JSInterfaceJIT::regT3, JSInterfaceJIT::regT5);
- jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight));
- jit.load32(MacroAssembler::Address(JSInterfaceJIT::regT3, 4), JSInterfaceJIT::regT5);
- jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight, 4));
+ jit.load32(MacroAssembler::Address(JSInterfaceJIT::regT3, PayloadOffset), JSInterfaceJIT::regT5);
+ jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight, PayloadOffset));
+ jit.load32(MacroAssembler::Address(JSInterfaceJIT::regT3, TagOffset), JSInterfaceJIT::regT5);
+ jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight, TagOffset));
jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT3);
jit.branchSub32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2).linkTo(copyLoop, &jit);
@@ -432,9 +462,9 @@
jit.move(JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::argumentGPR2);
JSInterfaceJIT::Label fillUndefinedLoop(jit.label());
jit.move(JSInterfaceJIT::TrustedImm32(0), JSInterfaceJIT::regT5);
- jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight));
+ jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight, PayloadOffset));
jit.move(JSInterfaceJIT::TrustedImm32(JSValue::UndefinedTag), JSInterfaceJIT::regT5);
- jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight, 4));
+ jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight, TagOffset));
jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT3);
jit.branchAdd32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2).linkTo(fillUndefinedLoop, &jit);
@@ -445,6 +475,8 @@
jit.addPtr(JSInterfaceJIT::regT5, JSInterfaceJIT::callFrameRegister);
jit.addPtr(JSInterfaceJIT::regT5, JSInterfaceJIT::stackPointerRegister);
+ done.link(&jit);
+
# if CPU(X86)
jit.push(JSInterfaceJIT::regT4);
# endif
Modified: branches/jsc-tailcall/Source/_javascript_Core/llint/LowLevelInterpreter.asm (188317 => 188318)
--- branches/jsc-tailcall/Source/_javascript_Core/llint/LowLevelInterpreter.asm 2015-08-12 01:46:06 UTC (rev 188317)
+++ branches/jsc-tailcall/Source/_javascript_Core/llint/LowLevelInterpreter.asm 2015-08-12 01:59:31 UTC (rev 188318)
@@ -168,6 +168,7 @@
const DirectArguments_storage = (sizeof DirectArguments + SlotSize - 1) & ~(SlotSize - 1)
const StackAlignment = 16
+const StackAlignmentSlots = 2
const StackAlignmentMask = StackAlignment - 1
const CallerFrameAndPCSize = 2 * PtrSize
@@ -732,20 +733,15 @@
macro popFrame(temp1, temp2)
const argCount = temp1
const numParameters = temp2
- const missingArgCount = temp2
loadi PayloadOffset + ArgumentCount[cfr], argCount
- mulp SlotSize, argCount
loadp CodeBlock[cfr], numParameters
loadi CodeBlock::m_numParameters[numParameters], numParameters
- mulp SlotSize, numParameters
bilteq numParameters, argCount, .noArityFixup
+ move numParameters, argCount
- subi numParameters, argCount, missingArgCount
- addp StackAlignmentMask, missingArgCount
- andp ~StackAlignmentMask, missingArgCount
- addi missingArgCount, argCount
.noArityFixup:
+ mulp SlotSize, argCount
alignFrameSize(argCount)
addp argCount, cfr
end
Modified: branches/jsc-tailcall/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (188317 => 188318)
--- branches/jsc-tailcall/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2015-08-12 01:46:06 UTC (rev 188317)
+++ branches/jsc-tailcall/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2015-08-12 01:59:31 UTC (rev 188318)
@@ -585,13 +585,27 @@
.proceedInline:
loadi CommonSlowPaths::ArityCheckData::paddedStackSpace[r1], t1
btiz t1, .continue
+ loadi PayloadOffset + ArgumentCount[cfr], t2
+ addi CallFrameHeaderSlots, t2
- // Move frame up "t1 * 2" slots
- lshiftp 1, t1
+ // Check if there are some unaligned slots we can use
+ move t1, t3
+ andi StackAlignmentSlots - 1, t3
+ btiz t3, .noExtraSlot
+.fillExtraSlots:
+ move 0, t0
+ storei t0, PayloadOffset[cfr, t2, 8]
+ move UndefinedTag, t0
+ storei t0, TagOffset[cfr, t2, 8]
+ addi 1, t2
+ bsubinz 1, t3, .fillExtraSlots
+ andi ~(StackAlignmentSlots - 1), t1
+ btiz t1, .continue
+
+.noExtraSlot:
+ // Move frame up t1 slots
negi t1
move cfr, t3
- loadi PayloadOffset + ArgumentCount[cfr], t2
- addi CallFrameHeaderSlots, t2
.copyLoop:
loadi PayloadOffset[t3], t0
storei t0, PayloadOffset[t3, t1, 8]
Modified: branches/jsc-tailcall/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (188317 => 188318)
--- branches/jsc-tailcall/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2015-08-12 01:46:06 UTC (rev 188317)
+++ branches/jsc-tailcall/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2015-08-12 01:59:31 UTC (rev 188318)
@@ -496,14 +496,27 @@
.noError:
loadi CommonSlowPaths::ArityCheckData::paddedStackSpace[r1], t1
btiz t1, .continue
+ loadi PayloadOffset + ArgumentCount[cfr], t2
+ addi CallFrameHeaderSlots, t2
- // Move frame up "t1 * 2" slots
- lshiftp 1, t1
+ // Check if there are some unaligned slots we can use
+ move t1, t3
+ andi StackAlignmentSlots - 1, t3
+ btiz t3, .noExtraSlot
+ move ValueUndefined, t0
+.fillExtraSlots:
+ storeq t0, [cfr, t2, 8]
+ addi 1, t2
+ bsubinz 1, t3, .fillExtraSlots
+ andi ~(StackAlignmentSlots - 1), t1
+ btiz t1, .continue
+
+.noExtraSlot:
+ // Move frame up t1 slots
negq t1
move cfr, t3
subp CalleeSaveSpaceAsVirtualRegisters * 8, t3
- loadi PayloadOffset + ArgumentCount[cfr], t2
- addi CallFrameHeaderSlots + CalleeSaveSpaceAsVirtualRegisters, t2
+ addi CalleeSaveSpaceAsVirtualRegisters, t2
.copyLoop:
loadq [t3], t0
storeq t0, [t3, t1, 8]
Modified: branches/jsc-tailcall/Source/_javascript_Core/runtime/CommonSlowPaths.h (188317 => 188318)
--- branches/jsc-tailcall/Source/_javascript_Core/runtime/CommonSlowPaths.h 2015-08-12 01:46:06 UTC (rev 188317)
+++ branches/jsc-tailcall/Source/_javascript_Core/runtime/CommonSlowPaths.h 2015-08-12 01:59:31 UTC (rev 188318)
@@ -59,12 +59,14 @@
int argumentCountIncludingThis = exec->argumentCountIncludingThis();
ASSERT(argumentCountIncludingThis < newCodeBlock->numParameters());
- int missingArgumentCount = newCodeBlock->numParameters() - argumentCountIncludingThis;
- int paddedStackSpace = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), missingArgumentCount);
+ int frameSize = argumentCountIncludingThis + JSStack::CallFrameHeaderSize;
+ int alignedFrameSizeForParameters = WTF::roundUpToMultipleOf(stackAlignmentRegisters(),
+ newCodeBlock->numParameters() + JSStack::CallFrameHeaderSize);
+ int paddedStackSpace = alignedFrameSizeForParameters - frameSize;
- if (!stack->ensureCapacityFor(exec->registers() - paddedStackSpace))
+ if (!stack->ensureCapacityFor(exec->registers() - paddedStackSpace % stackAlignmentRegisters()))
return -1;
- return paddedStackSpace / stackAlignmentRegisters();
+ return paddedStackSpace;
}
inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal)