Diff
Modified: trunk/Source/_javascript_Core/API/JSBase.cpp (146681 => 146682)
--- trunk/Source/_javascript_Core/API/JSBase.cpp 2013-03-22 23:48:40 UTC (rev 146681)
+++ trunk/Source/_javascript_Core/API/JSBase.cpp 2013-03-22 23:49:52 UTC (rev 146682)
@@ -111,7 +111,7 @@
exec->globalData().heap.reportExtraMemoryCost(size);
}
-JS_EXPORT void JSSynchronousGarbageCollectForDebugging(JSContextRef);
+extern "C" JS_EXPORT void JSSynchronousGarbageCollectForDebugging(JSContextRef);
void JSSynchronousGarbageCollectForDebugging(JSContextRef ctx)
{
Modified: trunk/Source/_javascript_Core/API/JSClassRef.cpp (146681 => 146682)
--- trunk/Source/_javascript_Core/API/JSClassRef.cpp 2013-03-22 23:48:40 UTC (rev 146681)
+++ trunk/Source/_javascript_Core/API/JSClassRef.cpp 2013-03-22 23:49:52 UTC (rev 146682)
@@ -151,7 +151,7 @@
OpaqueJSClassContextData& OpaqueJSClass::contextData(ExecState* exec)
{
- OwnPtr<OpaqueJSClassContextData>& contextData = exec->globalData().opaqueJSClassData.add(this, nullptr).iterator->value;
+ OwnPtr<OpaqueJSClassContextData>& contextData = exec->lexicalGlobalObject()->opaqueJSClassData().add(this, nullptr).iterator->value;
if (!contextData)
contextData = adoptPtr(new OpaqueJSClassContextData(exec->globalData(), this));
return *contextData;
Modified: trunk/Source/_javascript_Core/API/JSClassRef.h (146681 => 146682)
--- trunk/Source/_javascript_Core/API/JSClassRef.h 2013-03-22 23:48:40 UTC (rev 146681)
+++ trunk/Source/_javascript_Core/API/JSClassRef.h 2013-03-22 23:49:52 UTC (rev 146682)
@@ -26,10 +26,9 @@
#ifndef JSClassRef_h
#define JSClassRef_h
-#include "JSObjectRef.h"
+#include <_javascript_Core/JSObjectRef.h>
#include "Weak.h"
-#include "JSObject.h"
#include "Protect.h"
#include <wtf/HashMap.h>
#include <wtf/text/WTFString.h>
@@ -87,7 +86,7 @@
struct OpaqueJSClass : public ThreadSafeRefCounted<OpaqueJSClass> {
static PassRefPtr<OpaqueJSClass> create(const JSClassDefinition*);
static PassRefPtr<OpaqueJSClass> createNoAutomaticPrototype(const JSClassDefinition*);
- ~OpaqueJSClass();
+ JS_EXPORT_PRIVATE ~OpaqueJSClass();
String className();
OpaqueJSClassStaticValuesTable* staticValues(JSC::ExecState*);
Modified: trunk/Source/_javascript_Core/API/tests/testapi.c (146681 => 146682)
--- trunk/Source/_javascript_Core/API/tests/testapi.c 2013-03-22 23:48:40 UTC (rev 146681)
+++ trunk/Source/_javascript_Core/API/tests/testapi.c 2013-03-22 23:49:52 UTC (rev 146682)
@@ -55,6 +55,8 @@
void testObjectiveCAPI(void);
#endif
+extern void JSSynchronousGarbageCollectForDebugging(JSContextRef);
+
static JSGlobalContextRef context;
int failed;
static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue)
@@ -132,6 +134,61 @@
JSStringRelease(valueAsString);
}
+static int leakedObject = 1;
+
+static void leakFinalize(JSObjectRef object)
+{
+ (void)object;
+ leakedObject = 0;
+}
+
+// This is a hack to avoid the C++ stack keeping the original JSObject alive.
+static void nestedAllocateObject(JSContextRef context, JSClassRef class, unsigned n)
+{
+ if (!n) {
+ JSObjectRef object = JSObjectMake(context, class, 0);
+ JSObjectRef globalObject = JSContextGetGlobalObject(context);
+ JSStringRef propertyName = JSStringCreateWithUTF8CString("value");
+ JSObjectSetProperty(context, globalObject, propertyName, object, kJSPropertyAttributeNone, 0);
+ JSStringRelease(propertyName);
+ return;
+ }
+ nestedAllocateObject(context, class, n - 1);
+}
+
+static void testLeakingPrototypesAcrossContexts()
+{
+ JSClassDefinition leakDefinition = kJSClassDefinitionEmpty;
+ leakDefinition.finalize = leakFinalize;
+ JSClassRef leakClass = JSClassCreate(&leakDefinition);
+
+ JSContextGroupRef group = JSContextGroupCreate();
+
+ {
+ JSGlobalContextRef context1 = JSGlobalContextCreateInGroup(group, NULL);
+ nestedAllocateObject(context1, leakClass, 10);
+ JSGlobalContextRelease(context1);
+ }
+
+ {
+ JSGlobalContextRef context2 = JSGlobalContextCreateInGroup(group, NULL);
+ JSObjectRef object2 = JSObjectMake(context2, leakClass, 0);
+ JSValueProtect(context2, object2);
+ JSSynchronousGarbageCollectForDebugging(context2);
+ if (leakedObject) {
+ printf("FAIL: Failed to finalize the original object after the first GC.\n");
+ failed = 1;
+ } else
+ printf("PASS: Finalized the original object as expected.\n");
+ JSValueUnprotect(context2, object2);
+ JSGlobalContextRelease(context2);
+ }
+
+ JSContextGroupRelease(group);
+
+ JSClassRelease(leakClass);
+}
+
static bool timeZoneIsPST()
{
char timeZoneName[70];
@@ -1685,6 +1742,8 @@
free(scriptUTF8);
}
+ testLeakingPrototypesAcrossContexts();
+
// Clear out local variables pointing at JSObjectRefs to allow their values to be collected
function = NULL;
v = NULL;
Modified: trunk/Source/_javascript_Core/API/tests/testapi.mm (146681 => 146682)
--- trunk/Source/_javascript_Core/API/tests/testapi.mm 2013-03-22 23:48:40 UTC (rev 146681)
+++ trunk/Source/_javascript_Core/API/tests/testapi.mm 2013-03-22 23:49:52 UTC (rev 146682)
@@ -25,7 +25,7 @@
#import <_javascript_Core/_javascript_Core.h>
-void JSSynchronousGarbageCollectForDebugging(JSContextRef);
+extern "C" void JSSynchronousGarbageCollectForDebugging(JSContextRef);
extern "C" bool _Block_has_signature(id);
extern "C" const char * _Block_signature(id);
Modified: trunk/Source/_javascript_Core/ChangeLog (146681 => 146682)
--- trunk/Source/_javascript_Core/ChangeLog 2013-03-22 23:48:40 UTC (rev 146681)
+++ trunk/Source/_javascript_Core/ChangeLog 2013-03-22 23:49:52 UTC (rev 146682)
@@ -1,3 +1,37 @@
+2013-03-22 Mark Hahnenberg <[email protected]>
+
+ opaqueJSClassData should be cached on JSGlobalObject, not the JSGlobalData
+ https://bugs.webkit.org/show_bug.cgi?id=113086
+
+ Reviewed by Geoffrey Garen.
+
+ opaqueJSClassData stores cached prototypes for JSClassRefs in the C API. It doesn't make sense to
+ share these prototypes within a JSGlobalData across JSGlobalObjects, and in fact doing so will cause
+ a leak of the original JSGlobalObject that these prototypes were created in. Therefore we should move
+ this cache to JSGlobalObject where it belongs and where it won't cause memory leaks.
+
+ * API/JSBase.cpp: Needed to add an extern "C" so that testapi.c can use the super secret GC function.
+ * API/JSClassRef.cpp: We now grab the cached context data from the global object rather than the global data.
+ (OpaqueJSClass::contextData):
+ * API/JSClassRef.h: Remove this header because it's unnecessary and causes circular dependencies.
+ * API/tests/testapi.c: Added a new test that makes sure that using the same JSClassRef in two different contexts
+ doesn't cause leaks of the original global object.
+ (leakFinalize):
+ (nestedAllocateObject): This is a hack to bypass the conservative scan of the GC, which was unnecessarily marking
+ objects and keeping them alive, ruining the test result.
+ (testLeakingPrototypesAcrossContexts):
+ (main):
+ * API/tests/testapi.mm: extern "C" this so we can continue using it here.
+ * runtime/JSGlobalData.cpp: Remove JSClassRef related stuff.
+ (JSC::JSGlobalData::~JSGlobalData):
+ * runtime/JSGlobalData.h:
+ (JSGlobalData):
+ * runtime/JSGlobalObject.h: Add the stuff that JSGlobalData had. We add it to JSGlobalObjectRareData so that
+ clients who don't use the C API don't have to pay the memory cost of this extra HashMap.
+ (JSGlobalObject):
+ (JSGlobalObjectRareData):
+ (JSC::JSGlobalObject::opaqueJSClassData):
+
2013-03-19 Martin Robinson <[email protected]>
[GTK] Add support for building the WebCore bindings to the gyp build
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (146681 => 146682)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2013-03-22 23:48:40 UTC (rev 146681)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2013-03-22 23:49:52 UTC (rev 146682)
@@ -742,7 +742,7 @@
BC18C41A0E16F5CD00B34460 /* JSCallbackFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 1440F88F0A508B100005F061 /* JSCallbackFunction.h */; };
BC18C41B0E16F5CD00B34460 /* JSCallbackObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 14ABDF5D0A437FEF00ECCA01 /* JSCallbackObject.h */; };
BC18C41C0E16F5CD00B34460 /* JSCallbackObjectFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = A8E894310CD0602400367179 /* JSCallbackObjectFunctions.h */; };
- BC18C41D0E16F5CD00B34460 /* JSClassRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 1440FCE10A51E46B0005F061 /* JSClassRef.h */; };
+ BC18C41D0E16F5CD00B34460 /* JSClassRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 1440FCE10A51E46B0005F061 /* JSClassRef.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC18C41E0E16F5CD00B34460 /* JSContextRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 14BD5A2A0A3E91F600BAF59C /* JSContextRef.h */; settings = {ATTRIBUTES = (Public, ); }; };
BC18C41F0E16F5CD00B34460 /* JSFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A85F0255597D01FF60F7 /* JSFunction.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC18C4200E16F5CD00B34460 /* JSGlobalData.h in Headers */ = {isa = PBXBuildFile; fileRef = E18E3A560DF9278C00D90B34 /* JSGlobalData.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -2956,6 +2956,7 @@
0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */,
0F63945515D07057006A597C /* ArrayProfile.h in Headers */,
BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */,
+ BC18C41D0E16F5CD00B34460 /* JSClassRef.h in Headers */,
86E3C61D167BABEE006D760A /* JSVirtualMachineInternal.h in Headers */,
BC18C5240E16FC8A00B34460 /* ArrayPrototype.lut.h in Headers */,
86E3C617167BABEE006D760A /* JSContextInternal.h in Headers */,
@@ -3154,7 +3155,6 @@
0F9749711687ADE400A4FF6A /* JSCellInlines.h in Headers */,
BC18C42B0E16F5CD00B34460 /* JSCJSValue.h in Headers */,
865A30F1135007E100CDB49E /* JSCJSValueInlines.h in Headers */,
- BC18C41D0E16F5CD00B34460 /* JSClassRef.h in Headers */,
86E3C613167BABD7006D760A /* JSContext.h in Headers */,
BC18C41E0E16F5CD00B34460 /* JSContextRef.h in Headers */,
148CD1D8108CF902008163C6 /* JSContextRefPrivate.h in Headers */,
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalData.cpp (146681 => 146682)
--- trunk/Source/_javascript_Core/runtime/JSGlobalData.cpp 2013-03-22 23:48:40 UTC (rev 146681)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalData.cpp 2013-03-22 23:49:52 UTC (rev 146682)
@@ -44,7 +44,6 @@
#include "JSActivation.h"
#include "JSAPIValueWrapper.h"
#include "JSArray.h"
-#include "JSClassRef.h"
#include "JSFunction.h"
#include "JSLock.h"
#include "JSNameScope.h"
@@ -306,8 +305,6 @@
fastDelete(const_cast<HashTable*>(regExpPrototypeTable));
fastDelete(const_cast<HashTable*>(stringConstructorTable));
- opaqueJSClassData.clear();
-
delete emptyList;
delete propertyNames;
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalData.h (146681 => 146682)
--- trunk/Source/_javascript_Core/runtime/JSGlobalData.h 2013-03-22 23:48:40 UTC (rev 146681)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalData.h 2013-03-22 23:49:52 UTC (rev 146682)
@@ -62,9 +62,6 @@
#include <wtf/ListHashSet.h>
#endif
-struct OpaqueJSClass;
-struct OpaqueJSClassContextData;
-
namespace JSC {
class CodeBlock;
@@ -369,8 +366,6 @@
void gatherConservativeRoots(ConservativeRoots&);
#endif
- HashMap<OpaqueJSClass*, OwnPtr<OpaqueJSClassContextData> > opaqueJSClassData;
-
JSGlobalObject* dynamicGlobalObject;
HashSet<JSObject*> stringRecursionCheckVisitedObjects;
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (146681 => 146682)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h 2013-03-22 23:48:40 UTC (rev 146681)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h 2013-03-22 23:49:52 UTC (rev 146682)
@@ -24,6 +24,7 @@
#include "ArrayAllocationProfile.h"
#include "JSArray.h"
+#include "JSClassRef.h"
#include "JSGlobalData.h"
#include "JSSegmentedVariableObject.h"
#include "JSWeakObjectMapRefInternal.h"
@@ -38,6 +39,9 @@
#include <wtf/OwnPtr.h>
#include <wtf/RandomNumber.h>
+struct OpaqueJSClass;
+struct OpaqueJSClassContextData;
+
namespace JSC {
class ArrayPrototype;
@@ -86,6 +90,7 @@
class JSGlobalObject : public JSSegmentedVariableObject {
private:
typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet;
+ typedef HashMap<OpaqueJSClass*, OwnPtr<OpaqueJSClassContextData> > OpaqueJSClassDataMap;
struct JSGlobalObjectRareData {
JSGlobalObjectRareData()
@@ -95,6 +100,8 @@
WeakMapSet weakMaps;
unsigned profileGroup;
+
+ OpaqueJSClassDataMap opaqueJSClassData;
};
protected:
@@ -395,6 +402,12 @@
m_rareData->weakMaps.remove(map);
}
+ OpaqueJSClassDataMap& opaqueJSClassData()
+ {
+ createRareDataIfNeeded();
+ return m_rareData->opaqueJSClassData;
+ }
+
double weakRandomNumber() { return m_weakRandom.get(); }
unsigned weakRandomInteger() { return m_weakRandom.getUint32(); }