- Source/JavaScriptCore/ChangeLog +32 lines
Lines 1-3 Source/JavaScriptCore/ChangeLog_sec1
1
2013-12-20  Mark Lam  <mark.lam@apple.com>
2
3
        CStack: Introduce JSStack::ensureCapacityFor().
4
        https://bugs.webkit.org/show_bug.cgi?id=126109.
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Client code should use JSStack::ensureCapacityFor() when checking for
9
        available stack space for pushing JS frames or making arity adjustments.
10
        JSStack::ensureCapacityFor() works for both cases of the JS stack on the
11
        C stack or as a sperate stack.
12
13
        JSStack::grow() is now private, and is only used by the C Loop LLINT.
14
15
        Also made some other JSStack methods private as they are not needed
16
        outside of the JSSTack class.
17
18
        * dfg/DFGOSREntry.cpp:
19
        (JSC::DFG::prepareOSREntry):
20
        * ftl/FTLOSREntry.cpp:
21
        (JSC::FTL::prepareOSREntry):
22
        * interpreter/Interpreter.cpp:
23
        (JSC::sizeFrameForVarargs):
24
        * interpreter/JSStack.h:
25
        * interpreter/JSStackInlines.h:
26
        (JSC::JSStack::ensureCapacityFor):
27
        (JSC::JSStack::topOfStackForCapacityCheck):
28
        * llint/LLIntSlowPaths.cpp:
29
        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
30
        * runtime/CommonSlowPaths.h:
31
        (JSC::CommonSlowPaths::arityCheckFor):
32
1
2013-12-20  Filip Pizlo  <fpizlo@apple.com>
33
2013-12-20  Filip Pizlo  <fpizlo@apple.com>
2
34
3
        Arity check stack restoration should preserve the ArgumentCount in case there is a register restoration thunk below it
35
        Arity check stack restoration should preserve the ArgumentCount in case there is a register restoration thunk below it
- Source/JavaScriptCore/dfg/DFGOSREntry.cpp -1 / +1 lines
Lines 188-194 void* prepareOSREntry(ExecState* exec, C Source/JavaScriptCore/dfg/DFGOSREntry.cpp_sec1
188
    //    would have otherwise just kept running albeit less quickly.
188
    //    would have otherwise just kept running albeit less quickly.
189
    
189
    
190
    unsigned frameSize = jitCode->common.requiredRegisterCountForExecutionAndExit();
190
    unsigned frameSize = jitCode->common.requiredRegisterCountForExecutionAndExit();
191
    if (!vm->interpreter->stack().grow(&exec->registers()[virtualRegisterForLocal(frameSize).offset()])) {
191
    if (!vm->interpreter->stack().ensureCapacityFor(&exec->registers()[virtualRegisterForLocal(frameSize - 1).offset()])) {
192
        if (Options::verboseOSR())
192
        if (Options::verboseOSR())
193
            dataLogF("    OSR failed because stack growth failed.\n");
193
            dataLogF("    OSR failed because stack growth failed.\n");
194
        return 0;
194
        return 0;
- Source/JavaScriptCore/ftl/FTLOSREntry.cpp -1 / +1 lines
Lines 80-86 void* prepareOSREntry( Source/JavaScriptCore/ftl/FTLOSREntry.cpp_sec1
80
        scratch[local] = JSValue::encode(values.local(local));
80
        scratch[local] = JSValue::encode(values.local(local));
81
    
81
    
82
    int stackFrameSize = entryCode->common.requiredRegisterCountForExecutionAndExit();
82
    int stackFrameSize = entryCode->common.requiredRegisterCountForExecutionAndExit();
83
    if (!vm.interpreter->stack().grow(&exec->registers()[virtualRegisterForLocal(stackFrameSize).offset()])) {
83
    if (!vm.interpreter->stack().ensureCapacityFor(&exec->registers()[virtualRegisterForLocal(stackFrameSize - 1).offset()])) {
84
        if (Options::verboseOSR())
84
        if (Options::verboseOSR())
85
            dataLog("    OSR failed because stack growth failed.\n");
85
            dataLog("    OSR failed because stack growth failed.\n");
86
        return 0;
86
        return 0;
- Source/JavaScriptCore/interpreter/Interpreter.cpp -5 / +5 lines
Lines 160-166 CallFrame* sizeFrameForVarargs(CallFrame Source/JavaScriptCore/interpreter/Interpreter.cpp_sec1
160
        unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
160
        unsigned argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
161
        unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize + 1);
161
        unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize + 1);
162
        CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
162
        CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
163
        if (argumentCountIncludingThis > Arguments::MaxArguments + 1 || !stack->grow(newCallFrame->registers())) {
163
        if (argumentCountIncludingThis > Arguments::MaxArguments + 1 || !stack->ensureCapacityFor(newCallFrame->registers())) {
164
            callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
164
            callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
165
            return 0;
165
            return 0;
166
        }
166
        }
Lines 171-177 CallFrame* sizeFrameForVarargs(CallFrame Source/JavaScriptCore/interpreter/Interpreter.cpp_sec2
171
        unsigned argumentCountIncludingThis = 1;
171
        unsigned argumentCountIncludingThis = 1;
172
        unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(),  -firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize + 1);
172
        unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(),  -firstFreeRegister + argumentCountIncludingThis + JSStack::CallFrameHeaderSize + 1);
173
        CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
173
        CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
174
        if (!stack->grow(newCallFrame->registers())) {
174
        if (!stack->ensureCapacityFor(newCallFrame->registers())) {
175
            callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
175
            callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
176
            return 0;
176
            return 0;
177
        }
177
        }
Lines 188-194 CallFrame* sizeFrameForVarargs(CallFrame Source/JavaScriptCore/interpreter/Interpreter.cpp_sec3
188
        unsigned argCount = argsObject->length(callFrame);
188
        unsigned argCount = argsObject->length(callFrame);
189
        unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1));
189
        unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1));
190
        CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
190
        CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
191
        if (argCount > Arguments::MaxArguments || !stack->grow(newCallFrame->registers())) {
191
        if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) {
192
            callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
192
            callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
193
            return 0;
193
            return 0;
194
        }
194
        }
Lines 200-206 CallFrame* sizeFrameForVarargs(CallFrame Source/JavaScriptCore/interpreter/Interpreter.cpp_sec4
200
        unsigned argCount = array->length();
200
        unsigned argCount = array->length();
201
        unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1));
201
        unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1));
202
        CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
202
        CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
203
        if (argCount > Arguments::MaxArguments || !stack->grow(newCallFrame->registers())) {
203
        if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) {
204
            callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
204
            callFrame->vm().throwException(callFrame, createStackOverflowError(callFrame));
205
            return 0;
205
            return 0;
206
        }
206
        }
Lines 211-217 CallFrame* sizeFrameForVarargs(CallFrame Source/JavaScriptCore/interpreter/Interpreter.cpp_sec5
211
    unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
211
    unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
212
    unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1));
212
    unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), -firstFreeRegister + CallFrame::offsetFor(argCount + 1));
213
    CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
213
    CallFrame* newCallFrame = CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
214
    if (argCount > Arguments::MaxArguments || !stack->grow(newCallFrame->registers())) {
214
    if (argCount > Arguments::MaxArguments || !stack->ensureCapacityFor(newCallFrame->registers())) {
215
        callFrame->vm().throwException(callFrame,  createStackOverflowError(callFrame));
215
        callFrame->vm().throwException(callFrame,  createStackOverflowError(callFrame));
216
        return 0;
216
        return 0;
217
    }
217
    }
- Source/JavaScriptCore/interpreter/JSStack.h -4 / +8 lines
Lines 81-86 namespace JSC { Source/JavaScriptCore/interpreter/JSStack.h_sec1
81
        JSStack(VM&, size_t capacity = defaultCapacity);
81
        JSStack(VM&, size_t capacity = defaultCapacity);
82
        ~JSStack();
82
        ~JSStack();
83
        
83
        
84
        bool ensureCapacityFor(Register* newTopOfStack);
85
84
        void gatherConservativeRoots(ConservativeRoots&);
86
        void gatherConservativeRoots(ConservativeRoots&);
85
        void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&);
87
        void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&);
86
        void sanitizeStack();
88
        void sanitizeStack();
Lines 92-105 namespace JSC { Source/JavaScriptCore/interpreter/JSStack.h_sec2
92
94
93
        size_t size() const { return highAddress() - lowAddress(); }
95
        size_t size() const { return highAddress() - lowAddress(); }
94
96
95
        bool grow(Register* topOfStack);
96
        
97
        static size_t committedByteCount();
97
        static size_t committedByteCount();
98
        static void initializeThreading();
98
        static void initializeThreading();
99
99
100
        Register* topOfFrameFor(CallFrame*);
101
        Register* startOfFrameFor(CallFrame*);
100
        Register* startOfFrameFor(CallFrame*);
102
        Register* topOfStack();
103
101
104
        CallFrame* pushFrame(class CodeBlock*, JSScope*, int argsCount, JSObject* callee);
102
        CallFrame* pushFrame(class CodeBlock*, JSScope*, int argsCount, JSObject* callee);
105
103
Lines 120-125 namespace JSC { Source/JavaScriptCore/interpreter/JSStack.h_sec3
120
#endif // !ENABLE(DEBUG_JSSTACK)
118
#endif // !ENABLE(DEBUG_JSSTACK)
121
119
122
    private:
120
    private:
121
122
        inline Register* topOfFrameFor(CallFrame*);
123
        inline Register* topOfStack();
124
        inline Register* topOfStackForCapacityCheck();
125
123
        Register* lowAddress() const
126
        Register* lowAddress() const
124
        {
127
        {
125
            return m_end;
128
            return m_end;
Lines 143-148 namespace JSC { Source/JavaScriptCore/interpreter/JSStack.h_sec4
143
        void installTrapsAfterFrame(CallFrame*) { }
146
        void installTrapsAfterFrame(CallFrame*) { }
144
#endif
147
#endif
145
148
149
        bool grow(Register* topOfStack);
146
        bool growSlowCase(Register*);
150
        bool growSlowCase(Register*);
147
        void shrink(Register*);
151
        void shrink(Register*);
148
        void releaseExcessCapacity();
152
        void releaseExcessCapacity();
- Source/JavaScriptCore/interpreter/JSStackInlines.h +30 lines
Lines 33-38 Source/JavaScriptCore/interpreter/JSStackInlines.h_sec1
33
33
34
namespace JSC {
34
namespace JSC {
35
35
36
inline bool JSStack::ensureCapacityFor(Register* newTopOfStack)
37
{
38
#if ENABLE(LLINT_C_LOOP)
39
    return grow(newTopOfStack);
40
#else
41
    ASSERT(wtfThreadData().stack().isGrowingDownward());
42
    Register* topOfStack = topOfStackForCapacityCheck();
43
    if (newTopOfStack > topOfStack)
44
        return true;
45
    size_t neededCapacity = (topOfStack - newTopOfStack) * sizeof(Register);
46
    return m_vm.isSafeToRecurse(neededCapacity);
47
#endif
48
}
49
50
inline Register* JSStack::topOfStackForCapacityCheck()
51
{
52
#if !ENABLE(LLINT_C_LOOP)
53
    // We're trying to get an estimate of the top of the stack for the purpose
54
    // of a capacity check. If m_topCallFrame is 0, then we can't calculate an
55
    // accurate top of stack value. Just use the current stack position as an
56
    // estimate for the top of the stack from where JS code will start executing.
57
    // This is conservative, but it will be safe.
58
    if (!m_topCallFrame) {
59
        Register* p = reinterpret_cast<Register*>(&p);
60
        return p;
61
    }
62
#endif
63
    return topOfStack() + 1;
64
}
65
36
inline Register* JSStack::topOfFrameFor(CallFrame* frame)
66
inline Register* JSStack::topOfFrameFor(CallFrame* frame)
37
{
67
{
38
    if (UNLIKELY(!frame))
68
    if (UNLIKELY(!frame))
- Source/JavaScriptCore/llint/LLIntSlowPaths.cpp -2 / +9 lines
Lines 441-448 LLINT_SLOW_PATH_DECL(stack_check) Source/JavaScriptCore/llint/LLIntSlowPaths.cpp_sec1
441
    dataLogF("Num vars = %u.\n", exec->codeBlock()->m_numVars);
441
    dataLogF("Num vars = %u.\n", exec->codeBlock()->m_numVars);
442
    dataLogF("Current end is at %p.\n", exec->vm().interpreter->stack().end());
442
    dataLogF("Current end is at %p.\n", exec->vm().interpreter->stack().end());
443
#endif
443
#endif
444
    ASSERT(!exec->vm().interpreter->stack().containsAddress(&exec->registers()[virtualRegisterForLocal(exec->codeBlock()->m_numCalleeRegisters).offset()]));
444
445
    if (UNLIKELY(!vm.interpreter->stack().grow(&exec->registers()[virtualRegisterForLocal(exec->codeBlock()->m_numCalleeRegisters).offset()]))) {
445
    // For JIT enabled builds which uses the C stack, the stack is not growable.
446
    // Hence, if we get here, then we know a stack overflow is imminent. So, just
447
    // throw the StackOverflowError unconditionally.
448
#if ENABLE(LLINT_C_LOOP)
449
    ASSERT(!exec->vm().interpreter->stack().containsAddress(exec->topOfFrame()));
450
    if (UNLIKELY(!vm.interpreter->stack().ensureCapacityFor(exec->topOfFrame())))
451
#endif
452
    {
446
        exec = exec->callerFrame();
453
        exec = exec->callerFrame();
447
        CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec));
454
        CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec));
448
        pc = returnToThrowForThrownException(exec);
455
        pc = returnToThrowForThrownException(exec);
- Source/JavaScriptCore/runtime/CommonSlowPaths.h -8 / +1 lines
Lines 67-81 ALWAYS_INLINE int arityCheckFor(ExecStat Source/JavaScriptCore/runtime/CommonSlowPaths.h_sec1
67
    int neededStackSpace = missingArgumentCount + 1; // Allow space to save the original return PC.
67
    int neededStackSpace = missingArgumentCount + 1; // Allow space to save the original return PC.
68
    int paddedStackSpace = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), neededStackSpace);
68
    int paddedStackSpace = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), neededStackSpace);
69
69
70
#if ENABLE(LLINT_CLOOP)
70
    if (!stack->ensureCapacityFor(exec->registers() - paddedStackSpace))
71
    if (!stack->grow(exec->registers() - passedStackSpace))
72
        return -1;
71
        return -1;
73
#else
74
    UNUSED_PARAM(stack);
75
    if (!exec->vm().isSafeToRecurse(paddedStackSpace * sizeof(Register)))
76
        return -1;
77
#endif // ENABLE(LLINT_CLOOP)
78
79
    return paddedStackSpace / stackAlignmentRegisters();
72
    return paddedStackSpace / stackAlignmentRegisters();
80
}
73
}
81
74

Return to Bug 126109