Commit ccbb2d03 authored by weinig@apple.com's avatar weinig@apple.com

JavaScriptCore:

2008-03-19  Sam Weinig  <sam@webkit.org>

        Reviewed by Anders Carlsson.

        Fix for <rdar://problem/5785694>
        Crash occurs at KJS::Collector::collect() when loading web clip widgets with a PAC file

        Make the activeExecStates stack per JSGlobalObject instead of static to ensure
        thread safety.

        * JavaScriptCore.exp:
        * kjs/ExecState.cpp:
        (KJS::InterpreterExecState::InterpreterExecState):
        (KJS::InterpreterExecState::~InterpreterExecState):
        (KJS::EvalExecState::EvalExecState):
        (KJS::EvalExecState::~EvalExecState):
        (KJS::FunctionExecState::FunctionExecState):
        (KJS::FunctionExecState::~FunctionExecState):
        * kjs/ExecState.h:
        (KJS::):
        * kjs/JSGlobalObject.cpp:
        (KJS::JSGlobalObject::mark):
        * kjs/JSGlobalObject.h:
        (KJS::JSGlobalObject::activeExecStates):
        * kjs/collector.cpp:
        (KJS::Collector::collect):
        (KJS::Collector::reportOutOfMemoryToAllExecStates): Iterate all JSGlobalObjects and report
        the OutOfMemory condition to all the ExecStates in each.

WebCore:

2008-03-19  Sam Weinig  <sam@webkit.org>

        Reviewed by Anders Carlsson.

        Fix for <rdar://problem/5785694>
        Crash occurs at KJS::Collector::collect() when loading web clip widgets with a PAC file

        Make the activeExecStates stack per JSGlobalObject instead of static to ensure
        thread safety.

        * bindings/objc/WebScriptObject.mm:
        (+[WebScriptObject throwException:]): Change to throw an exception on the current
        GlobalObject instead of the top of the static activeExecStates stack.
        (-[WebScriptObject setException:]): Change to use the top of the rootObjects GlobalObject
        instead of the top of the static activeExecStates stack.

        * bridge/c/c_instance.cpp:
        * bridge/c/c_instance.h:
        * bridge/jni/jni_instance.cpp:
        (JavaInstance::virtualBegin):
        (JavaInstance::virtualEnd):
        * bridge/jni/jni_instance.h:
        * bridge/objc/objc_instance.h:
        * bridge/objc/objc_instance.mm:
        (ObjcInstance::~ObjcInstance):
        (ObjcInstance::virtualBegin):
        (ObjcInstance::virtualEnd):
        * bridge/runtime.cpp:
        (KJS::Bindings::Instance::setDidExecuteFunction):
        (KJS::Bindings::Instance::didExecuteFunction):
        (KJS::Bindings::Instance::setCurrentGlobalObject): Added.
        (KJS::Bindings::Instance::currentGlobalObject): Added.
        (KJS::Bindings::Instance::begin):
        (KJS::Bindings::Instance::end):
        * bridge/runtime.h:
        (KJS::Bindings::Instance::virtualBegin): Renamed from begin().
        (KJS::Bindings::Instance::virtualEnd): Renamed from end().
        We now store the currently active globalObject everytime we cross the runtime
        object boundary.  To do this, we take advantage of the existing begin/end
        methods that are called when crossing this boundary, making begin set the current
        globalObject and then call the old begin, now called virtualBegin.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@31167 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 22f1098a
2008-03-19 Sam Weinig <sam@webkit.org>
Reviewed by Anders Carlsson.
Fix for <rdar://problem/5785694>
Crash occurs at KJS::Collector::collect() when loading web clip widgets with a PAC file
Make the activeExecStates stack per JSGlobalObject instead of static to ensure
thread safety.
* JavaScriptCore.exp:
* kjs/ExecState.cpp:
(KJS::InterpreterExecState::InterpreterExecState):
(KJS::InterpreterExecState::~InterpreterExecState):
(KJS::EvalExecState::EvalExecState):
(KJS::EvalExecState::~EvalExecState):
(KJS::FunctionExecState::FunctionExecState):
(KJS::FunctionExecState::~FunctionExecState):
* kjs/ExecState.h:
(KJS::):
* kjs/JSGlobalObject.cpp:
(KJS::JSGlobalObject::mark):
* kjs/JSGlobalObject.h:
(KJS::JSGlobalObject::activeExecStates):
* kjs/collector.cpp:
(KJS::Collector::collect):
(KJS::Collector::reportOutOfMemoryToAllExecStates): Iterate all JSGlobalObjects and report
the OutOfMemory condition to all the ExecStates in each.
2008-03-19 Jasper Bryant-Greene <jasper@unix.geek.nz>
Reviewed by Maciej Stachowiak.
......
......@@ -197,7 +197,6 @@ __ZN3KJS9Collector4sizeEv
__ZN3KJS9Collector7collectEv
__ZN3KJS9Collector7protectEPNS_7JSValueE
__ZN3KJS9Collector9unprotectEPNS_7JSValueE
__ZN3KJS9ExecState16activeExecStatesEv
__ZN3KJSeqERKNS_7UStringEPKc
__ZN3WTF10fastCallocEmm
__ZN3WTF10fastMallocEm
......
......@@ -144,24 +144,6 @@ JSGlobalObject* ExecState::lexicalGlobalObject() const
return m_globalObject;
}
void ExecState::markActiveExecStates()
{
ExecStateStack::const_iterator end = activeExecStates().end();
for (ExecStateStack::const_iterator it = activeExecStates().begin(); it != end; ++it)
(*it)->m_scopeChain.mark();
}
static inline ExecStateStack& inlineActiveExecStates()
{
static ExecStateStack staticActiveExecStates;
return staticActiveExecStates;
}
ExecStateStack& ExecState::activeExecStates()
{
return inlineActiveExecStates();
}
GlobalExecState::GlobalExecState(JSGlobalObject* globalObject)
: ExecState(globalObject)
{
......@@ -174,25 +156,25 @@ GlobalExecState::~GlobalExecState()
InterpreterExecState::InterpreterExecState(JSGlobalObject* globalObject, JSObject* thisObject, ProgramNode* programNode)
: ExecState(globalObject, thisObject, programNode)
{
inlineActiveExecStates().append(this);
m_globalObject->activeExecStates().append(this);
}
InterpreterExecState::~InterpreterExecState()
{
ASSERT(inlineActiveExecStates().last() == this);
inlineActiveExecStates().removeLast();
ASSERT(m_globalObject->activeExecStates().last() == this);
m_globalObject->activeExecStates().removeLast();
}
EvalExecState::EvalExecState(JSGlobalObject* globalObject, JSObject* thisObj, EvalNode* evalNode, ExecState* callingExec, const ScopeChain& scopeChain, JSVariableObject* variableObject)
: ExecState(globalObject, thisObj, evalNode, callingExec, scopeChain, variableObject)
{
inlineActiveExecStates().append(this);
m_globalObject->activeExecStates().append(this);
}
EvalExecState::~EvalExecState()
{
ASSERT(inlineActiveExecStates().last() == this);
inlineActiveExecStates().removeLast();
ASSERT(m_globalObject->activeExecStates().last() == this);
m_globalObject->activeExecStates().removeLast();
}
FunctionExecState::FunctionExecState(JSGlobalObject* globalObject, JSObject* thisObject,
......@@ -200,13 +182,13 @@ FunctionExecState::FunctionExecState(JSGlobalObject* globalObject, JSObject* thi
FunctionImp* func, const List& args)
: ExecState(globalObject, thisObject, functionBodyNode, callingExec, func, args)
{
inlineActiveExecStates().append(this);
m_globalObject->activeExecStates().append(this);
}
FunctionExecState::~FunctionExecState()
{
ASSERT(inlineActiveExecStates().last() == this);
inlineActiveExecStates().removeLast();
ASSERT(m_globalObject->activeExecStates().last() == this);
m_globalObject->activeExecStates().removeLast();
if (m_activation->needsPop())
m_globalObject->popActivation();
......
......@@ -45,12 +45,11 @@ namespace KJS {
class ScopeNode;
enum CodeType { GlobalCode, EvalCode, FunctionCode };
typedef Vector<ExecState*, 16> ExecStateStack;
// Represents the current state of script execution.
// Passed as the first argument to most functions.
class ExecState : Noncopyable {
friend class JSGlobalObject;
public:
// Global object that was in scope when the current script started executing.
JSGlobalObject* dynamicGlobalObject() const { return m_globalObject; }
......@@ -164,9 +163,6 @@ namespace KJS {
return 0;
}
static void markActiveExecStates();
static ExecStateStack& activeExecStates();
protected:
ExecState(JSGlobalObject*);
ExecState(JSGlobalObject*, JSObject* thisObject, ProgramNode*);
......
......@@ -483,6 +483,10 @@ void JSGlobalObject::mark()
{
JSVariableObject::mark();
ExecStateStack::const_iterator end = d()->activeExecStates.end();
for (ExecStateStack::const_iterator it = d()->activeExecStates.begin(); it != end; ++it)
(*it)->m_scopeChain.mark();
markIfNeeded(d()->globalExec.exception());
markIfNeeded(d()->objectConstructor);
......
......@@ -68,6 +68,8 @@ namespace KJS {
class UriErrorPrototype;
struct ActivationStackNode;
typedef Vector<ExecState*, 16> ExecStateStack;
class JSGlobalObject : public JSVariableObject {
protected:
using JSVariableObject::JSVariableObjectData;
......@@ -130,6 +132,8 @@ namespace KJS {
SymbolTable inlineSymbolTable;
ExecStateStack activeExecStates;
ActivationStackNode* activations;
size_t activationCount;
};
......@@ -233,6 +237,8 @@ namespace KJS {
virtual bool isDynamicScope() const;
ExecStateStack& activeExecStates() const { return d()->activeExecStates; }
private:
void init();
......
......@@ -935,7 +935,6 @@ bool Collector::collect()
markStackObjectsConservatively();
markProtectedObjects();
ExecState::markActiveExecStates();
List::markProtectedLists();
#if USE(MULTIPLE_THREADS)
if (!currentThreadIsMainThread)
......@@ -1045,10 +1044,16 @@ bool Collector::isBusy()
void Collector::reportOutOfMemoryToAllExecStates()
{
ExecStateStack::const_iterator end = ExecState::activeExecStates().end();
for (ExecStateStack::const_iterator it = ExecState::activeExecStates().begin(); it != end; ++it) {
(*it)->setException(Error::create(*it, GeneralError, "Out of memory"));
}
if (!JSGlobalObject::head())
return;
JSGlobalObject* globalObject = JSGlobalObject::head();
do {
ExecStateStack::const_iterator end = globalObject->activeExecStates().end();
for (ExecStateStack::const_iterator it = globalObject->activeExecStates().begin(); it != end; ++it)
(*it)->setException(Error::create(*it, GeneralError, "Out of memory"));
globalObject = globalObject->next();
} while (globalObject != JSGlobalObject::head());
}
} // namespace KJS
2008-03-19 Sam Weinig <sam@webkit.org>
Reviewed by Anders Carlsson.
Fix for <rdar://problem/5785694>
Crash occurs at KJS::Collector::collect() when loading web clip widgets with a PAC file
Make the activeExecStates stack per JSGlobalObject instead of static to ensure
thread safety.
* bindings/objc/WebScriptObject.mm:
(+[WebScriptObject throwException:]): Change to throw an exception on the current
GlobalObject instead of the top of the static activeExecStates stack.
(-[WebScriptObject setException:]): Change to use the top of the rootObjects GlobalObject
instead of the top of the static activeExecStates stack.
* bridge/c/c_instance.cpp:
* bridge/c/c_instance.h:
* bridge/jni/jni_instance.cpp:
(JavaInstance::virtualBegin):
(JavaInstance::virtualEnd):
* bridge/jni/jni_instance.h:
* bridge/objc/objc_instance.h:
* bridge/objc/objc_instance.mm:
(ObjcInstance::~ObjcInstance):
(ObjcInstance::virtualBegin):
(ObjcInstance::virtualEnd):
* bridge/runtime.cpp:
(KJS::Bindings::Instance::setDidExecuteFunction):
(KJS::Bindings::Instance::didExecuteFunction):
(KJS::Bindings::Instance::setCurrentGlobalObject): Added.
(KJS::Bindings::Instance::currentGlobalObject): Added.
(KJS::Bindings::Instance::begin):
(KJS::Bindings::Instance::end):
* bridge/runtime.h:
(KJS::Bindings::Instance::virtualBegin): Renamed from begin().
(KJS::Bindings::Instance::virtualEnd): Renamed from end().
We now store the currently active globalObject everytime we cross the runtime
object boundary. To do this, we take advantage of the existing begin/end
methods that are called when crossing this boundary, making begin set the current
globalObject and then call the old begin, now called virtualBegin.
2008-03-19 Brady Eidson <beidson@apple.com>
Reviewed by Anders
......@@ -250,17 +250,16 @@ static void _didExecute(WebScriptObject *obj)
+ (BOOL)throwException:(NSString *)exceptionMessage
{
JSLock lock;
// This code assumes that we only ever have one running interpreter. A
// good assumption for now, as we depend on that elsewhere. However,
// in the future we may have the ability to run multiple interpreters,
// in which case this will have to change.
if (ExecState::activeExecStates().size()) {
throwError(ExecState::activeExecStates().last(), GeneralError, exceptionMessage);
JSGlobalObject* globalObject = Instance::currentGlobalObject();
if (!globalObject)
return NO;
if (globalObject->activeExecStates().size()) {
throwError(globalObject->activeExecStates().last(), GeneralError, exceptionMessage);
return YES;
}
return NO;
}
......@@ -498,12 +497,13 @@ static void getListFromNSArray(ExecState *exec, NSArray *array, RootObject* root
JSLock lock;
ExecState* exec = 0;
JSObject* globalObject = [self _rootObject]->globalObject();
ExecStateStack::const_iterator end = ExecState::activeExecStates().end();
for (ExecStateStack::const_iterator it = ExecState::activeExecStates().begin(); it != end; ++it)
JSGlobalObject* globalObject = [self _rootObject]->globalObject();
ExecStateStack::const_iterator end = globalObject->activeExecStates().end();
for (ExecStateStack::const_iterator it = globalObject->activeExecStates().begin(); it != end; ++it) {
if ((*it)->dynamicGlobalObject() == globalObject)
exec = *it;
}
if (exec)
throwError(exec, GeneralError, description);
}
......
......@@ -62,16 +62,6 @@ Class *CInstance::getClass() const
return _class;
}
void CInstance::begin()
{
// Do nothing.
}
void CInstance::end()
{
// Do nothing.
}
bool CInstance::implementsCall() const
{
return (_object->_class->invokeDefault != 0);
......
......@@ -49,10 +49,7 @@ public:
~CInstance ();
virtual Class *getClass() const;
virtual void begin();
virtual void end();
virtual JSValue *valueOf() const;
virtual JSValue *defaultValue (JSType hint) const;
......
......@@ -60,12 +60,12 @@ JavaInstance::~JavaInstance ()
#define NUM_LOCAL_REFS 64
void JavaInstance::begin()
void JavaInstance::virtualBegin()
{
getJNIEnv()->PushLocalFrame (NUM_LOCAL_REFS);
}
void JavaInstance::end()
void JavaInstance::virtualEnd()
{
getJNIEnv()->PopLocalFrame (NULL);
}
......
......@@ -77,9 +77,6 @@ public:
virtual Class *getClass() const;
virtual void begin();
virtual void end();
virtual JSValue *valueOf() const;
virtual JSValue *defaultValue (JSType hint) const;
......@@ -93,9 +90,13 @@ public:
virtual BindingLanguage getBindingLanguage() const { return JavaLanguage; }
protected:
virtual void virtualBegin();
virtual void virtualEnd();
private:
JavaInstance(jobject instance, PassRefPtr<RootObject>);
RefPtr<JObjectWrapper> _instance;
mutable JavaClass *_class;
};
......
......@@ -45,10 +45,7 @@ public:
~ObjcInstance();
virtual Class *getClass() const;
virtual void begin();
virtual void end();
virtual JSValue *valueOf() const;
virtual JSValue *defaultValue(JSType hint) const;
......@@ -70,6 +67,10 @@ public:
virtual BindingLanguage getBindingLanguage() const { return ObjectiveCLanguage; }
protected:
virtual void virtualBegin();
virtual void virtualEnd();
private:
ObjcInstance(ObjectStructPtr instance, PassRefPtr<RootObject>);
......
......@@ -52,21 +52,22 @@ ObjcInstance::ObjcInstance(ObjectStructPtr instance, PassRefPtr<RootObject> root
ObjcInstance::~ObjcInstance()
{
begin(); // -finalizeForWebScript and -dealloc/-finalize may require autorelease pools.
// -finalizeForWebScript and -dealloc/-finalize may require autorelease pools.
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
if ([_instance.get() respondsToSelector:@selector(finalizeForWebScript)])
[_instance.get() performSelector:@selector(finalizeForWebScript)];
_instance = 0;
end();
[pool drain];
}
void ObjcInstance::begin()
void ObjcInstance::virtualBegin()
{
if (!_pool)
_pool = [[NSAutoreleasePool alloc] init];
_beginCount++;
}
void ObjcInstance::end()
void ObjcInstance::virtualEnd()
{
_beginCount--;
ASSERT(_beginCount >= 0);
......
/*
* Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -55,10 +55,40 @@ Instance::~Instance()
{
}
static KJSDidExecuteFunctionPtr _DidExecuteFunction;
static KJSDidExecuteFunctionPtr s_didExecuteFunction;
void Instance::setDidExecuteFunction(KJSDidExecuteFunctionPtr func) { _DidExecuteFunction = func; }
KJSDidExecuteFunctionPtr Instance::didExecuteFunction() { return _DidExecuteFunction; }
void Instance::setDidExecuteFunction(KJSDidExecuteFunctionPtr func)
{
s_didExecuteFunction = func;
}
KJSDidExecuteFunctionPtr Instance::didExecuteFunction()
{
return s_didExecuteFunction;
}
static JSGlobalObject* s_currentGlobalObject;
void Instance::setCurrentGlobalObject(JSGlobalObject* globalObject)
{
s_currentGlobalObject = globalObject;
}
JSGlobalObject* Instance::currentGlobalObject()
{
return s_currentGlobalObject;
}
void Instance::begin()
{
setCurrentGlobalObject(_rootObject && _rootObject->isValid() ? _rootObject->globalObject() : 0);
virtualBegin();
}
void Instance::end()
{
virtualEnd();
}
JSValue *Instance::getValueOfField(ExecState *exec, const Field *aField) const
{
......
/*
* Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -35,6 +35,7 @@
namespace KJS {
class Identifier;
class JSGlobalObject;
class List;
class PropertyNameArray;
......@@ -102,15 +103,18 @@ public:
static void setDidExecuteFunction(KJSDidExecuteFunctionPtr func);
static KJSDidExecuteFunctionPtr didExecuteFunction();
static void setCurrentGlobalObject(JSGlobalObject*);
static JSGlobalObject* currentGlobalObject();
static JSObject* createRuntimeObject(PassRefPtr<Instance>);
static Instance* getInstance(JSObject*, BindingLanguage);
// These functions are called before and after the main entry points into
// the native implementations. They can be used to establish and cleanup
// any needed state.
virtual void begin() {}
virtual void end() {}
void begin();
void end();
virtual Class *getClass() const = 0;
......@@ -138,6 +142,9 @@ public:
virtual BindingLanguage getBindingLanguage() const = 0;
protected:
virtual void virtualBegin() { }
virtual void virtualEnd() { }
RefPtr<RootObject> _rootObject;
};
......
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