Skip to content

Commit 2a7b2b5

Browse files
committed
Fixed memory leaks and crashes related to global TypedArra constructors and prototypes
1 parent fc39bbd commit 2a7b2b5

File tree

8 files changed

+133
-29
lines changed

8 files changed

+133
-29
lines changed

JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,10 @@
557557
B6D1888C1673751400D1037C /* GlobalDataHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = B6D188881673751400D1037C /* GlobalDataHelper.h */; };
558558
B6D1888E167381A400D1037C /* JSFloat32ArrayCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6D1888D167381A300D1037C /* JSFloat32ArrayCustom.cpp */; };
559559
B6D1888F167381A400D1037C /* JSFloat32ArrayCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6D1888D167381A300D1037C /* JSFloat32ArrayCustom.cpp */; };
560+
B6E02BB916D1666300616925 /* TypedArrayHashTableMap.h in Headers */ = {isa = PBXBuildFile; fileRef = B6E02BB616D1666300616925 /* TypedArrayHashTableMap.h */; };
561+
B6E02BBA16D1666300616925 /* TypedArrayHashTableMap.h in Headers */ = {isa = PBXBuildFile; fileRef = B6E02BB616D1666300616925 /* TypedArrayHashTableMap.h */; };
562+
B6E02BBC16D17CC400616925 /* TypedArrayHashTableMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6E02BBB16D17CC400616925 /* TypedArrayHashTableMap.cpp */; };
563+
B6E02BBD16D17CC400616925 /* TypedArrayHashTableMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6E02BBB16D17CC400616925 /* TypedArrayHashTableMap.cpp */; };
560564
B6E69991166BD63D005EF4B1 /* AbstractMacroAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161DF0F3A83C100F84710 /* AbstractMacroAssembler.h */; };
561565
B6E69992166BD63D005EF4B1 /* APICast.h in Headers */ = {isa = PBXBuildFile; fileRef = 1482B78A0A4305AB00517CFC /* APICast.h */; settings = {ATTRIBUTES = (Private, ); }; };
562566
B6E69993166BD63D005EF4B1 /* APIShims.h in Headers */ = {isa = PBXBuildFile; fileRef = 865F408710E7D56300947361 /* APIShims.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -1886,6 +1890,8 @@
18861890
B6D1886F1672DFE700D1037C /* JSFloat32Array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSFloat32Array.h; sourceTree = "<group>"; };
18871891
B6D188881673751400D1037C /* GlobalDataHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GlobalDataHelper.h; sourceTree = "<group>"; };
18881892
B6D1888D167381A300D1037C /* JSFloat32ArrayCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFloat32ArrayCustom.cpp; sourceTree = "<group>"; };
1893+
B6E02BB616D1666300616925 /* TypedArrayHashTableMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypedArrayHashTableMap.h; sourceTree = "<group>"; };
1894+
B6E02BBB16D17CC400616925 /* TypedArrayHashTableMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TypedArrayHashTableMap.cpp; sourceTree = "<group>"; };
18891895
B6E69BC4166BD63D005EF4B1 /* libJavaScriptCore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libJavaScriptCore.a; sourceTree = BUILT_PRODUCTS_DIR; };
18901896
B6E69BDB166BD6C1005EF4B1 /* libJSCLLIntOffsetsExtractor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libJSCLLIntOffsetsExtractor.a; sourceTree = BUILT_PRODUCTS_DIR; };
18911897
B6E69BFD166BDCE7005EF4B1 /* libWTF.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libWTF.a; path = ../Build/libWTF.a; sourceTree = "<group>"; };
@@ -2964,6 +2970,8 @@
29642970
isa = PBXGroup;
29652971
children = (
29662972
B6D188881673751400D1037C /* GlobalDataHelper.h */,
2973+
B6E02BBB16D17CC400616925 /* TypedArrayHashTableMap.cpp */,
2974+
B6E02BB616D1666300616925 /* TypedArrayHashTableMap.h */,
29672975
B6D18814166FA73400D1037C /* JSArrayBuffer.cpp */,
29682976
B6D18815166FA73400D1037C /* JSArrayBuffer.h */,
29692977
B6D18816166FA73400D1037C /* JSArrayBufferCustom.cpp */,
@@ -3372,6 +3380,7 @@
33723380
B6F114B91673B116001F1324 /* JSUint16Array.h in Headers */,
33733381
B6F114BF1673B116001F1324 /* JSUint32Array.h in Headers */,
33743382
B6F114CA16755F98001F1324 /* JSTypedArray.h in Headers */,
3383+
B6E02BB916D1666300616925 /* TypedArrayHashTableMap.h in Headers */,
33753384
);
33763385
runOnlyForDeploymentPostprocessing = 0;
33773386
};
@@ -3731,6 +3740,7 @@
37313740
B6F114BA1673B116001F1324 /* JSUint16Array.h in Headers */,
37323741
B6F114C01673B116001F1324 /* JSUint32Array.h in Headers */,
37333742
B6F114CB16755F98001F1324 /* JSTypedArray.h in Headers */,
3743+
B6E02BBA16D1666300616925 /* TypedArrayHashTableMap.h in Headers */,
37343744
);
37353745
runOnlyForDeploymentPostprocessing = 0;
37363746
};
@@ -4498,6 +4508,7 @@
44984508
B6F114BD1673B116001F1324 /* JSUint32Array.cpp in Sources */,
44994509
B6F114C11673B116001F1324 /* JSUint32ArrayCustom.cpp in Sources */,
45004510
B6F114C816755F98001F1324 /* JSTypedArray.cpp in Sources */,
4511+
B6E02BBC16D17CC400616925 /* TypedArrayHashTableMap.cpp in Sources */,
45014512
);
45024513
runOnlyForDeploymentPostprocessing = 0;
45034514
};
@@ -4744,6 +4755,7 @@
47444755
B6F114BE1673B116001F1324 /* JSUint32Array.cpp in Sources */,
47454756
B6F114C21673B116001F1324 /* JSUint32ArrayCustom.cpp in Sources */,
47464757
B6F114C916755F98001F1324 /* JSTypedArray.cpp in Sources */,
4758+
B6E02BBD16D17CC400616925 /* TypedArrayHashTableMap.cpp in Sources */,
47474759
);
47484760
runOnlyForDeploymentPostprocessing = 0;
47494761
};

JavaScriptCore/runtime/JSGlobalData.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
#include <wtf/ListHashSet.h>
5656
#endif
5757

58+
#include "TypedArrayHashTableMap.h"
59+
5860
struct OpaqueJSClass;
5961
struct OpaqueJSClassContextData;
6062

@@ -405,6 +407,9 @@ namespace JSC {
405407
registerTypedArrayFunction(float32, Float32);
406408
registerTypedArrayFunction(float64, Float64);
407409
#undef registerTypedArrayFunction
410+
411+
WebCore::TypedArrayHashTableMap typedArrayHashTableMap;
412+
408413

409414
JSLock& apiLock() { return m_apiLock; }
410415

JavaScriptCore/runtime/JSGlobalObject.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#include <wtf/OwnPtr.h>
3535
#include <wtf/RandomNumber.h>
3636

37+
#include "WriteBarrier.h"
38+
3739
namespace JSC {
3840

3941
class ArrayPrototype;
@@ -167,6 +169,9 @@ namespace JSC {
167169
}
168170

169171
static JS_EXPORTDATA const ClassInfo s_info;
172+
173+
HashMap<const JSC::ClassInfo*, JSC::WriteBarrier<JSC::JSObject> > typedArrayConstructorMap;
174+
HashMap<const JSC::ClassInfo*, JSC::WriteBarrier<JSC::JSObject> > typedArrayPrototypeMap;
170175

171176
protected:
172177
explicit JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable = 0)

JavaScriptCore/runtime/TypedArrays/GlobalDataHelper.h

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,37 +23,38 @@ enum ParameterDefaultPolicy {
2323
#define MAYBE_MISSING_PARAMETER(exec, index, policy) (((policy) == DefaultIsNullString && (index) >= (exec)->argumentCount()) ? (JSValue()) : ((exec)->argument(index)))
2424

2525
static inline const JSC::HashTable* getHashTableForGlobalData(JSC::JSGlobalData& globalData, const JSC::HashTable* staticTable) {
26-
ASSERT_UNUSED(&globalData, &globalData);
27-
// PL FIXME: this should return a copy per globalData. I think.
28-
return staticTable;
26+
return globalData.typedArrayHashTableMap.get(staticTable);
2927
}
3028

31-
3229
template<class ConstructorClass>
33-
static inline JSC::JSObject* getDOMConstructor(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
30+
inline JSC::JSObject* getDOMConstructor(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
3431
{
35-
static ConstructorClass * globalConstructor;
36-
if( !globalConstructor ) {
37-
globalConstructor = ConstructorClass::create(exec, ConstructorClass::createStructure(exec->globalData(), globalObject, globalObject->objectPrototype()), globalObject);
38-
}
39-
return (JSC::JSObject *)globalConstructor;
32+
if (JSC::JSObject* constructor = globalObject->typedArrayConstructorMap.get(&ConstructorClass::s_info).get())
33+
return constructor;
34+
35+
JSC::JSObject* constructor = ConstructorClass::create(exec, ConstructorClass::createStructure(exec->globalData(), globalObject, globalObject->objectPrototype()), globalObject);
36+
37+
ASSERT(!globalObject->typedArrayConstructorMap.contains(&ConstructorClass::s_info));
38+
JSC::WriteBarrier<JSC::JSObject> temp;
39+
globalObject->typedArrayConstructorMap.add(&ConstructorClass::s_info, temp).iterator->second.set(exec->globalData(), globalObject, constructor);
40+
return constructor;
4041
}
4142

42-
4343
template<class PrototypeClass>
44-
static inline JSC::JSObject* getDOMPrototype(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
44+
inline JSC::JSObject* getDOMPrototype(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
4545
{
46-
static PrototypeClass * globalPrototype;
47-
if( !globalPrototype ) {
48-
JSC::JSGlobalData &data = exec->globalData();
46+
if (JSC::JSObject* prototype = globalObject->typedArrayPrototypeMap.get(&PrototypeClass::s_info).get())
47+
return prototype;
4948

50-
globalPrototype = PrototypeClass::create(data, globalObject,
51-
PrototypeClass::createStructure(data, globalObject, globalObject->objectPrototype()));
52-
}
53-
return (JSC::JSObject *)globalPrototype;
49+
JSC::JSObject* prototype = PrototypeClass::create(exec->globalData(), globalObject,
50+
PrototypeClass::createStructure(exec->globalData(), globalObject, globalObject->objectPrototype()));
51+
52+
ASSERT(!globalObject->typedArrayPrototypeMap.contains(&PrototypeClass::s_info));
53+
JSC::WriteBarrier<JSC::JSObject> temp;
54+
globalObject->typedArrayPrototypeMap.add(&PrototypeClass::s_info, temp).iterator->second.set(exec->globalData(), globalObject, prototype);
55+
return prototype;
5456
}
5557

56-
5758
}
5859

5960
#endif /* defined(__JavaScriptCore__GlobalDataHelper__) */

JavaScriptCore/runtime/TypedArrays/JSArrayBuffer.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,20 +96,15 @@ static const HashTableValue JSArrayBufferPrototypeTableValues[] =
9696
static const HashTable JSArrayBufferPrototypeTable = { 2, 1, JSArrayBufferPrototypeTableValues, 0 };
9797
static const HashTable* getJSArrayBufferPrototypeTable(ExecState* exec)
9898
{
99-
ASSERT_UNUSED(exec, exec);
100-
return &JSArrayBufferPrototypeTable; // PL FIXME: should be one instance per global data, not super global
99+
return getHashTableForGlobalData(exec->globalData(), &JSArrayBufferPrototypeTable);
101100
}
102101

103102
const ClassInfo JSArrayBufferPrototype::s_info = { "ArrayBufferPrototype", &Base::s_info, 0, getJSArrayBufferPrototypeTable, CREATE_METHOD_TABLE(JSArrayBufferPrototype) };
104103

105104
static JSObject * globalProto = NULL;
106105
JSObject* JSArrayBufferPrototype::self(ExecState* exec, JSGlobalObject* globalObject)
107106
{
108-
// PL FIXME: dirty hack to provide one global prototype
109-
if( !globalProto ) {
110-
globalProto = JSArrayBuffer::createPrototype(exec, globalObject);
111-
}
112-
return globalProto;
107+
return getDOMPrototype<JSArrayBufferPrototype>(exec, globalObject);
113108
}
114109

115110
bool JSArrayBufferPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)

JavaScriptCore/runtime/TypedArrays/JSArrayBufferView.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ static const HashTableValue JSArrayBufferViewPrototypeTableValues[] =
5555
static const HashTable JSArrayBufferViewPrototypeTable = { 1, 0, JSArrayBufferViewPrototypeTableValues, 0 };
5656
static const HashTable* getJSArrayBufferViewPrototypeTable(ExecState* exec)
5757
{
58-
ASSERT_UNUSED(exec, exec);
59-
return &JSArrayBufferViewPrototypeTable; // PL FIXME: should be one instance per global data, not super global
58+
return getHashTableForGlobalData(exec->globalData(), &JSArrayBufferViewPrototypeTable);
6059
}
6160

6261
const ClassInfo JSArrayBufferViewPrototype::s_info = { "ArrayBufferViewPrototype", &Base::s_info, 0, getJSArrayBufferViewPrototypeTable, CREATE_METHOD_TABLE(JSArrayBufferViewPrototype) };
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (C) 1999-2001 Harri Porten ([email protected])
3+
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4+
* Copyright (C) 2007 Samuel Weinig <[email protected]>
5+
*
6+
* This library is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 2 of the License, or (at your option) any later version.
10+
*
11+
* This library is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public
17+
* License along with this library; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19+
*/
20+
21+
#include "config.h"
22+
#include "TypedArrayHashTableMap.h"
23+
#include "Lookup.h"
24+
25+
namespace WebCore{
26+
27+
TypedArrayHashTableMap::~TypedArrayHashTableMap()
28+
{
29+
for (HashMap<const JSC::HashTable*, JSC::HashTable>::iterator iter = m_map.begin(); iter != m_map.end(); ++iter)
30+
iter->second.deleteTable();
31+
}
32+
33+
const JSC::HashTable* TypedArrayHashTableMap::get(const JSC::HashTable* staticTable)
34+
{
35+
HashMap<const JSC::HashTable*, JSC::HashTable>::iterator iter = m_map.find(staticTable);
36+
if (iter != m_map.end())
37+
return &iter->second;
38+
return &m_map.set(staticTable, JSC::HashTable(*staticTable)).iterator->second;
39+
}
40+
41+
} // namespace WebCore
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (C) 1999-2001 Harri Porten ([email protected])
3+
* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Apple Inc. All rights reserved.
4+
* Copyright (C) 2007 Samuel Weinig <[email protected]>
5+
* Copyright (C) 2009 Google, Inc. All rights reserved.
6+
*
7+
* This library is free software; you can redistribute it and/or
8+
* modify it under the terms of the GNU Lesser General Public
9+
* License as published by the Free Software Foundation; either
10+
* version 2 of the License, or (at your option) any later version.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
22+
#ifndef TypedArrayHashTableMap_h
23+
#define TypedArrayHashTableMap_h
24+
25+
#include <wtf/HashMap.h>
26+
27+
28+
namespace JSC {
29+
class JSGlobalData;
30+
struct HashTable;
31+
}
32+
33+
namespace WebCore {
34+
35+
// Map from static HashTable instances to per-GlobalData ones.
36+
class TypedArrayHashTableMap {
37+
public:
38+
~TypedArrayHashTableMap();
39+
const JSC::HashTable* get(const JSC::HashTable* staticTable);
40+
private:
41+
HashMap<const JSC::HashTable*, JSC::HashTable> m_map;
42+
};
43+
44+
} // namespace JSC
45+
46+
#endif // TypedArrayHashTableMap_h

0 commit comments

Comments
 (0)