Commit bd1385d3 authored by mark.lam@apple.com's avatar mark.lam@apple.com

Source/JavaScriptCore: Introducing the VMStackBounds class.

https://bugs.webkit.org/show_bug.cgi?id=117862.

Reviewed by Geoffrey Garen.

- Removed Interpreter::StackPolicy.
- The new VMStackBounds will take over choosing the appropriate stack
  size requirements, and invoking the underlying WTF::StackBounds to
  to the real bounds check.
- VMStackBounds will now be used universally throughout JSC instead of
  WTF::StackBounds.

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
* bytecompiler/BytecodeGenerator.h:
* interpreter/Interpreter.cpp:
(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::prepareForRepeatCall):
* interpreter/Interpreter.h:
(JSC::Interpreter::isInErrorHandlingMode):
* parser/Parser.cpp:
(JSC::::Parser):
* parser/Parser.h:
* runtime/StringRecursionChecker.h:
(JSC::StringRecursionChecker::performCheck):
* runtime/VMStackBounds.h: Added.
(JSC::VMStackBounds::VMStackBounds):
(JSC::VMStackBounds::isSafeToRecurse):
(JSC::VMStackBounds::requiredCapacity):

LayoutTests: Reverting failure expectation for fast/xmlhttprequest/xmlhttprequest-recursive-sync-event.html.
https://bugs.webkit.org/show_bug.cgi?id=117862.

Reviewed by Geoffrey Garen.

* platform/mac/TestExpectations:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@151869 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent c9d644a3
2013-06-21 Mark Lam <mark.lam@apple.com>
Reverting failure expectation for fast/xmlhttprequest/xmlhttprequest-recursive-sync-event.html.
https://bugs.webkit.org/show_bug.cgi?id=117862.
Reviewed by Geoffrey Garen.
* platform/mac/TestExpectations:
2013-06-21 Brent Fulgham <bfulgham@apple.com>
AX: Title for ListItemRole should consist of concatenated child text elements.
......@@ -1336,5 +1336,3 @@ webkit.org/b/116388 fast/js/post-message-numeric-property.html
webkit.org/b/116582 [ Debug ] inspector/styles/import-pseudoclass-crash.html [ Pass Crash ]
webkit.org/b/116592 inspector/geolocation-error.html [ Pass Failure ]
webkit.org/b/117862 fast/xmlhttprequest/xmlhttprequest-recursive-sync-event.html [ Failure ]
2013-06-21 Mark Lam <mark.lam@apple.com>
Introducing the VMStackBounds class.
https://bugs.webkit.org/show_bug.cgi?id=117862.
Reviewed by Geoffrey Garen.
- Removed Interpreter::StackPolicy.
- The new VMStackBounds will take over choosing the appropriate stack
size requirements, and invoking the underlying WTF::StackBounds to
to the real bounds check.
- VMStackBounds will now be used universally throughout JSC instead of
WTF::StackBounds.
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
* bytecompiler/BytecodeGenerator.h:
* interpreter/Interpreter.cpp:
(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::prepareForRepeatCall):
* interpreter/Interpreter.h:
(JSC::Interpreter::isInErrorHandlingMode):
* parser/Parser.cpp:
(JSC::::Parser):
* parser/Parser.h:
* runtime/StringRecursionChecker.h:
(JSC::StringRecursionChecker::performCheck):
* runtime/VMStackBounds.h: Added.
(JSC::VMStackBounds::VMStackBounds):
(JSC::VMStackBounds::isSafeToRecurse):
(JSC::VMStackBounds::requiredCapacity):
2013-06-20 Mark Lam <mark.lam@apple.com>
Change stack capacity requirement to be more reasonable.
......
......@@ -871,6 +871,7 @@
FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */; settings = {ATTRIBUTES = (Private, ); }; };
FE4A331F15BD2E07006F54F3 /* VMInspector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE4A331D15BD2E07006F54F3 /* VMInspector.cpp */; };
FE4A332015BD2E07006F54F3 /* VMInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = FE4A331E15BD2E07006F54F3 /* VMInspector.h */; settings = {ATTRIBUTES = (Private, ); }; };
FE6617281774E03500495B00 /* VMStackBounds.h in Headers */ = {isa = PBXBuildFile; fileRef = FE6617271774E03500495B00 /* VMStackBounds.h */; settings = {ATTRIBUTES = (Private, ); }; };
FED287B215EC9A5700DA8161 /* LLIntOpcode.h in Headers */ = {isa = PBXBuildFile; fileRef = FED287B115EC9A5700DA8161 /* LLIntOpcode.h */; settings = {ATTRIBUTES = (Private, ); }; };
FED94F2E171E3E2300BE77A4 /* Watchdog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */; };
FED94F2F171E3E2300BE77A4 /* Watchdog.h in Headers */ = {isa = PBXBuildFile; fileRef = FED94F2C171E3E2300BE77A4 /* Watchdog.h */; settings = {ATTRIBUTES = (Private, ); }; };
......@@ -1817,6 +1818,7 @@
FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntCLoop.h; path = llint/LLIntCLoop.h; sourceTree = "<group>"; };
FE4A331D15BD2E07006F54F3 /* VMInspector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VMInspector.cpp; sourceTree = "<group>"; };
FE4A331E15BD2E07006F54F3 /* VMInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMInspector.h; sourceTree = "<group>"; };
FE6617271774E03500495B00 /* VMStackBounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMStackBounds.h; sourceTree = "<group>"; };
FED287B115EC9A5700DA8161 /* LLIntOpcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntOpcode.h; path = llint/LLIntOpcode.h; sourceTree = "<group>"; };
FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Watchdog.cpp; sourceTree = "<group>"; };
FED94F2C171E3E2300BE77A4 /* Watchdog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Watchdog.h; sourceTree = "<group>"; };
......@@ -2618,6 +2620,7 @@
5D53726E0E1C54880021E549 /* Tracing.h */,
0FEB3ECB16237F4700AB67AD /* TypedArrayDescriptor.h */,
866739D113BFDE710023D87C /* Uint16WithFraction.h */,
FE6617271774E03500495B00 /* VMStackBounds.h */,
FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */,
FED94F2C171E3E2300BE77A4 /* Watchdog.h */,
FED94F2D171E3E2300BE77A4 /* WatchdogMac.cpp */,
......@@ -2994,6 +2997,7 @@
BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */,
C2DF44301707AC0100A5CA96 /* SuperRegion.h in Headers */,
C20B25991706536200C21F4E /* Region.h in Headers */,
FE6617281774E03500495B00 /* VMStackBounds.h in Headers */,
C283190016FE4B7D00157BFD /* HandleBlock.h in Headers */,
BC18C41D0E16F5CD00B34460 /* JSClassRef.h in Headers */,
86E3C61D167BABEE006D760A /* JSVirtualMachineInternal.h in Headers */,
......
......@@ -179,7 +179,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, JSScope*, ProgramNode* programNode,
#ifndef NDEBUG
, m_lastOpcodePosition(0)
#endif
, m_stack(wtfThreadData().stack())
, m_stack(vm, wtfThreadData().stack())
, m_usesExceptions(false)
, m_expressionTooDeep(false)
{
......@@ -228,7 +228,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, JSScope* scope, FunctionBodyNode* f
#ifndef NDEBUG
, m_lastOpcodePosition(0)
#endif
, m_stack(wtfThreadData().stack())
, m_stack(vm, wtfThreadData().stack())
, m_usesExceptions(false)
, m_expressionTooDeep(false)
{
......@@ -425,7 +425,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, JSScope* scope, EvalNode* evalNode,
#ifndef NDEBUG
, m_lastOpcodePosition(0)
#endif
, m_stack(wtfThreadData().stack())
, m_stack(vm, wtfThreadData().stack())
, m_usesExceptions(false)
, m_expressionTooDeep(false)
{
......
......@@ -44,6 +44,7 @@
#include "Nodes.h"
#include "StaticPropertyAnalyzer.h"
#include "UnlinkedCodeBlock.h"
#include "VMStackBounds.h"
#include <wtf/PassRefPtr.h>
#include <wtf/SegmentedVector.h>
#include <wtf/Vector.h>
......@@ -825,7 +826,7 @@ namespace JSC {
size_t m_lastOpcodePosition;
#endif
StackBounds m_stack;
VMStackBounds m_stack;
bool m_usesExceptions;
bool m_expressionTooDeep;
......
......@@ -64,6 +64,7 @@
#include "SamplingTool.h"
#include "StrictEvalActivation.h"
#include "StrongInlines.h"
#include "VMStackBounds.h"
#include <limits.h>
#include <stdio.h>
#include <wtf/StackStats.h>
......@@ -98,45 +99,6 @@ Interpreter::ErrorHandlingMode::~ErrorHandlingMode()
m_interpreter.stack().disableErrorStackReserve();
}
// The Interpreter::StackPolicy class is used to compute a stack capacity
// requirement to ensure that we have enough room on the native stack for:
// 1. the max cumulative stack used by the interpreter and all code
// paths sub of it up till leaf functions.
// 2. the max cumulative stack used by the interpreter before it reaches
// the next checkpoint (execute...() function) in the interpreter.
//
// The interpreter can be run on different threads and hence, different
// native stacks (with different sizes) before exiting out of the first
// frame. Hence, the required capacity needs to be re-computed on every
// entry into the interpreter.
//
// Currently the requiredStack is computed based on a policy. See comments
// in StackPolicy::StackPolicy() for details.
Interpreter::StackPolicy::StackPolicy(Interpreter& interpreter, const StackBounds& stack)
: m_interpreter(interpreter)
{
const size_t size = stack.size();
// We have two separate stack limits, one for regular JS execution, and one
// for when we're handling errors. We need the error stack to be smaller
// otherwise there would obviously not be any stack left to execute JS in when
// there's a stack overflow.
//
// These sizes were derived from the stack usage of a number of sites when
// layout occurs when we've already consumed most of the C stack.
const size_t requiredStack = 32 * KB;
const size_t errorModeRequiredStack = 16 * KB;
size_t requiredCapacity = m_interpreter.m_errorHandlingModeReentry ? errorModeRequiredStack : requiredStack;
RELEASE_ASSERT(size >= requiredCapacity);
m_requiredCapacity = requiredCapacity;
}
static CallFrame* getCallerInfo(VM*, CallFrame*, unsigned& bytecodeOffset, CodeBlock*& callerOut);
// Returns the depth of the scope chain within a given call frame.
......@@ -829,9 +791,8 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, J
return jsNull();
StackStats::CheckPoint stackCheckPoint;
const StackBounds& nativeStack = wtfThreadData().stack();
StackPolicy policy(*this, nativeStack);
if (!nativeStack.isSafeToRecurse(policy.requiredCapacity()))
const VMStackBounds vmStackBounds(vm, wtfThreadData().stack());
if (!vmStackBounds.isSafeToRecurse())
return checkedReturn(throwStackOverflowError(callFrame));
// First check if the "program" is actually just a JSON object. If so,
......@@ -995,9 +956,8 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT
return jsNull();
StackStats::CheckPoint stackCheckPoint;
const StackBounds& nativeStack = wtfThreadData().stack();
StackPolicy policy(*this, nativeStack);
if (!nativeStack.isSafeToRecurse(policy.requiredCapacity()))
const VMStackBounds vmStackBounds(vm, wtfThreadData().stack());
if (!vmStackBounds.isSafeToRecurse())
return checkedReturn(throwStackOverflowError(callFrame));
bool isJSCall = (callType == CallTypeJS);
......@@ -1073,9 +1033,8 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
return checkedReturn(throwStackOverflowError(callFrame));
StackStats::CheckPoint stackCheckPoint;
const StackBounds& nativeStack = wtfThreadData().stack();
StackPolicy policy(*this, nativeStack);
if (!nativeStack.isSafeToRecurse(policy.requiredCapacity()))
const VMStackBounds vmStackBounds(vm, wtfThreadData().stack());
if (!vmStackBounds.isSafeToRecurse())
return checkedReturn(throwStackOverflowError(callFrame));
bool isJSConstruct = (constructType == ConstructTypeJS);
......@@ -1154,9 +1113,8 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionE
return CallFrameClosure();
StackStats::CheckPoint stackCheckPoint;
const StackBounds& nativeStack = wtfThreadData().stack();
StackPolicy policy(*this, nativeStack);
if (!nativeStack.isSafeToRecurse(policy.requiredCapacity())) {
const VMStackBounds vmStackBounds(vm, wtfThreadData().stack());
if (!vmStackBounds.isSafeToRecurse()) {
throwStackOverflowError(callFrame);
return CallFrameClosure();
}
......@@ -1257,9 +1215,8 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue
DynamicGlobalObjectScope globalObjectScope(vm, scope->globalObject());
StackStats::CheckPoint stackCheckPoint;
const StackBounds& nativeStack = wtfThreadData().stack();
StackPolicy policy(*this, nativeStack);
if (!nativeStack.isSafeToRecurse(policy.requiredCapacity()))
const VMStackBounds vmStackBounds(vm, wtfThreadData().stack());
if (!vmStackBounds.isSafeToRecurse())
return checkedReturn(throwStackOverflowError(callFrame));
// Compile the callee:
......
......@@ -216,6 +216,8 @@ namespace JSC {
SamplingTool* sampler() { return m_sampler.get(); }
bool isInErrorHandlingMode() { return m_errorHandlingModeReentry; }
NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset);
NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine, int column);
static const String getTraceLine(CallFrame*, StackFrameCodeType, const String&, int);
......@@ -229,16 +231,6 @@ namespace JSC {
JS_EXPORT_PRIVATE void dumpCallFrame(CallFrame*);
private:
class StackPolicy {
public:
StackPolicy(Interpreter&, const StackBounds&);
inline size_t requiredCapacity() { return m_requiredCapacity; }
private:
Interpreter& m_interpreter;
size_t m_requiredCapacity;
};
enum ExecutionFlag { Normal, InitializeAndReturn };
CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, JSFunction*, int argumentCountIncludingThis, JSScope*);
......
......@@ -66,7 +66,7 @@ template <typename LexerType>
Parser<LexerType>::Parser(VM* vm, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode)
: m_vm(vm)
, m_source(&source)
, m_stack(wtfThreadData().stack())
, m_stack(*vm, wtfThreadData().stack())
, m_hasStackOverflow(false)
, m_allowsIn(true)
, m_lastLine(0)
......
......@@ -35,6 +35,7 @@
#include "SourceProvider.h"
#include "SourceProviderCache.h"
#include "SourceProviderCacheItem.h"
#include "VMStackBounds.h"
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
#include <wtf/OwnPtr.h>
......@@ -938,7 +939,7 @@ private:
ParserArena* m_arena;
OwnPtr<LexerType> m_lexer;
StackBounds m_stack;
VMStackBounds m_stack;
bool m_hasStackOverflow;
String m_errorMessage;
JSToken m_token;
......
......@@ -21,6 +21,7 @@
#define StringRecursionChecker_h
#include "Interpreter.h"
#include "VMStackBounds.h"
#include <wtf/StackStats.h>
#include <wtf/WTFThreadData.h>
......@@ -49,10 +50,11 @@ private:
inline JSValue StringRecursionChecker::performCheck()
{
const StackBounds& nativeStack = wtfThreadData().stack();
VM& vm = m_exec->vm();
const VMStackBounds nativeStack(vm, wtfThreadData().stack());
if (!nativeStack.isSafeToRecurse())
return throwStackOverflowError();
bool alreadyVisited = !m_exec->vm().stringRecursionCheckVisitedObjects.add(m_thisObject).isNewEntry;
bool alreadyVisited = !vm.stringRecursionCheckVisitedObjects.add(m_thisObject).isNewEntry;
if (alreadyVisited)
return emptyString(); // Return empty string to avoid infinite recursion.
return JSValue(); // Indicate success.
......
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef VMStackBounds_h
#define VMStackBounds_h
#include "VM.h"
#include <wtf/StackBounds.h>
namespace JSC {
class VMStackBounds {
public:
VMStackBounds(VM& vm, const StackBounds& bounds)
: m_vm(vm)
, m_bounds(bounds)
{
}
bool isSafeToRecurse() const { return m_bounds.isSafeToRecurse(requiredCapacity()); }
private:
inline size_t requiredCapacity() const
{
Interpreter* interpreter = m_vm.interpreter;
// We have two separate stack limits, one for regular JS execution, and one
// for when we're handling errors. We need the error stack to be smaller
// otherwise there would obviously not be any stack left to execute JS in when
// there's a stack overflow.
//
// These sizes were derived from the stack usage of a number of sites when
// layout occurs when we've already consumed most of the C stack.
const size_t requiredStack = 128 * KB;
const size_t errorModeRequiredStack = 64 * KB;
size_t requiredCapacity = interpreter->isInErrorHandlingMode() ? errorModeRequiredStack : requiredStack;
RELEASE_ASSERT(m_bounds.size() >= requiredCapacity);
return requiredCapacity;
}
VM& m_vm;
const StackBounds& m_bounds;
};
} // namespace JSC
#endif // VMStackBounds_h
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment