source: webkit/trunk/JavaScriptCore/API/JSClassRef.cpp@ 52978

Last change on this file since 52978 was 52978, checked in by Simon Hausmann, 15 years ago

RVCT compiler with "-Otime -O3" optimization tries to optimize out
inline new'ed pointers that are passed as arguments.
Proposed patch assigns new'ed pointer explicitly outside function call.

Patch by Norbert Leser <[email protected]> on 2010-01-08
Reviewed by Darin Adler.

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

  • API/JSClassRef.cpp:

(OpaqueJSClass::OpaqueJSClass):
(OpaqueJSClassContextData::OpaqueJSClassContextData):

  • Property svn:eol-style set to native
File size: 10.0 KB
Line 
1/*
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "JSClassRef.h"
28
29#include "APICast.h"
30#include "JSCallbackObject.h"
31#include "JSObjectRef.h"
32#include <runtime/InitializeThreading.h>
33#include <runtime/JSGlobalObject.h>
34#include <runtime/ObjectPrototype.h>
35#include <runtime/Identifier.h>
36
37using namespace JSC;
38
39const JSClassDefinition kJSClassDefinitionEmpty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
40
41OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* protoClass)
42 : parentClass(definition->parentClass)
43 , prototypeClass(0)
44 , initialize(definition->initialize)
45 , finalize(definition->finalize)
46 , hasProperty(definition->hasProperty)
47 , getProperty(definition->getProperty)
48 , setProperty(definition->setProperty)
49 , deleteProperty(definition->deleteProperty)
50 , getPropertyNames(definition->getPropertyNames)
51 , callAsFunction(definition->callAsFunction)
52 , callAsConstructor(definition->callAsConstructor)
53 , hasInstance(definition->hasInstance)
54 , convertToType(definition->convertToType)
55 , m_className(UString::createFromUTF8(definition->className).rep()->ref())
56 , m_staticValues(0)
57 , m_staticFunctions(0)
58{
59 initializeThreading();
60
61 if (const JSStaticValue* staticValue = definition->staticValues) {
62 m_staticValues = new OpaqueJSClassStaticValuesTable();
63 while (staticValue->name) {
64 // Use a local variable here to sidestep an RVCT compiler bug.
65 StaticValueEntry* entry = new StaticValueEntry(staticValue->getProperty, staticValue->setProperty, staticValue->attributes);
66 m_staticValues->add(UString::createFromUTF8(staticValue->name).rep()->ref(), entry);
67 ++staticValue;
68 }
69 }
70
71 if (const JSStaticFunction* staticFunction = definition->staticFunctions) {
72 m_staticFunctions = new OpaqueJSClassStaticFunctionsTable();
73 while (staticFunction->name) {
74 // Use a local variable here to sidestep an RVCT compiler bug.
75 StaticFunctionEntry* entry = new StaticFunctionEntry(staticFunction->callAsFunction, staticFunction->attributes);
76 m_staticFunctions->add(UString::createFromUTF8(staticFunction->name).rep()->ref(), entry);
77 ++staticFunction;
78 }
79 }
80
81 if (protoClass)
82 prototypeClass = JSClassRetain(protoClass);
83}
84
85OpaqueJSClass::~OpaqueJSClass()
86{
87 ASSERT(!m_className.rep()->isIdentifier());
88
89 if (m_staticValues) {
90 OpaqueJSClassStaticValuesTable::const_iterator end = m_staticValues->end();
91 for (OpaqueJSClassStaticValuesTable::const_iterator it = m_staticValues->begin(); it != end; ++it) {
92 ASSERT(!it->first->isIdentifier());
93 delete it->second;
94 }
95 delete m_staticValues;
96 }
97
98 if (m_staticFunctions) {
99 OpaqueJSClassStaticFunctionsTable::const_iterator end = m_staticFunctions->end();
100 for (OpaqueJSClassStaticFunctionsTable::const_iterator it = m_staticFunctions->begin(); it != end; ++it) {
101 ASSERT(!it->first->isIdentifier());
102 delete it->second;
103 }
104 delete m_staticFunctions;
105 }
106
107 if (prototypeClass)
108 JSClassRelease(prototypeClass);
109}
110
111PassRefPtr<OpaqueJSClass> OpaqueJSClass::createNoAutomaticPrototype(const JSClassDefinition* definition)
112{
113 return adoptRef(new OpaqueJSClass(definition, 0));
114}
115
116static void clearReferenceToPrototype(JSObjectRef prototype)
117{
118 OpaqueJSClassContextData* jsClassData = static_cast<OpaqueJSClassContextData*>(JSObjectGetPrivate(prototype));
119 ASSERT(jsClassData);
120 jsClassData->cachedPrototype = 0;
121}
122
123PassRefPtr<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* definition)
124{
125 if (const JSStaticFunction* staticFunctions = definition->staticFunctions) {
126 // copy functions into a prototype class
127 JSClassDefinition protoDefinition = kJSClassDefinitionEmpty;
128 protoDefinition.staticFunctions = staticFunctions;
129 protoDefinition.finalize = clearReferenceToPrototype;
130
131 // We are supposed to use JSClassRetain/Release but since we know that we currently have
132 // the only reference to this class object we cheat and use a RefPtr instead.
133 RefPtr<OpaqueJSClass> protoClass = adoptRef(new OpaqueJSClass(&protoDefinition, 0));
134
135 // remove functions from the original class
136 JSClassDefinition objectDefinition = *definition;
137 objectDefinition.staticFunctions = 0;
138
139 return adoptRef(new OpaqueJSClass(&objectDefinition, protoClass.get()));
140 }
141
142 return adoptRef(new OpaqueJSClass(definition, 0));
143}
144
145OpaqueJSClassContextData::OpaqueJSClassContextData(OpaqueJSClass* jsClass)
146 : m_class(jsClass)
147{
148 if (jsClass->m_staticValues) {
149 staticValues = new OpaqueJSClassStaticValuesTable;
150 OpaqueJSClassStaticValuesTable::const_iterator end = jsClass->m_staticValues->end();
151 for (OpaqueJSClassStaticValuesTable::const_iterator it = jsClass->m_staticValues->begin(); it != end; ++it) {
152 ASSERT(!it->first->isIdentifier());
153 // Use a local variable here to sidestep an RVCT compiler bug.
154 StaticValueEntry* entry = new StaticValueEntry(it->second->getProperty, it->second->setProperty, it->second->attributes);
155 staticValues->add(UString::Rep::createCopying(it->first->data(), it->first->size()), entry);
156
157 }
158
159 } else
160 staticValues = 0;
161
162
163 if (jsClass->m_staticFunctions) {
164 staticFunctions = new OpaqueJSClassStaticFunctionsTable;
165 OpaqueJSClassStaticFunctionsTable::const_iterator end = jsClass->m_staticFunctions->end();
166 for (OpaqueJSClassStaticFunctionsTable::const_iterator it = jsClass->m_staticFunctions->begin(); it != end; ++it) {
167 ASSERT(!it->first->isIdentifier());
168 // Use a local variable here to sidestep an RVCT compiler bug.
169 StaticFunctionEntry* entry = new StaticFunctionEntry(it->second->callAsFunction, it->second->attributes);
170 staticFunctions->add(UString::Rep::createCopying(it->first->data(), it->first->size()), entry);
171 }
172
173 } else
174 staticFunctions = 0;
175}
176
177OpaqueJSClassContextData::~OpaqueJSClassContextData()
178{
179 if (staticValues) {
180 deleteAllValues(*staticValues);
181 delete staticValues;
182 }
183
184 if (staticFunctions) {
185 deleteAllValues(*staticFunctions);
186 delete staticFunctions;
187 }
188}
189
190OpaqueJSClassContextData& OpaqueJSClass::contextData(ExecState* exec)
191{
192 OpaqueJSClassContextData*& contextData = exec->globalData().opaqueJSClassData.add(this, 0).first->second;
193 if (!contextData)
194 contextData = new OpaqueJSClassContextData(this);
195 return *contextData;
196}
197
198UString OpaqueJSClass::className()
199{
200 // Make a deep copy, so that the caller has no chance to put the original into IdentifierTable.
201 return UString(m_className.data(), m_className.size());
202}
203
204OpaqueJSClassStaticValuesTable* OpaqueJSClass::staticValues(JSC::ExecState* exec)
205{
206 OpaqueJSClassContextData& jsClassData = contextData(exec);
207 return jsClassData.staticValues;
208}
209
210OpaqueJSClassStaticFunctionsTable* OpaqueJSClass::staticFunctions(JSC::ExecState* exec)
211{
212 OpaqueJSClassContextData& jsClassData = contextData(exec);
213 return jsClassData.staticFunctions;
214}
215
216/*!
217// Doc here in case we make this public. (Hopefully we won't.)
218@function
219 @abstract Returns the prototype that will be used when constructing an object with a given class.
220 @param ctx The execution context to use.
221 @param jsClass A JSClass whose prototype you want to get.
222 @result The JSObject prototype that was automatically generated for jsClass, or NULL if no prototype was automatically generated. This is the prototype that will be used when constructing an object using jsClass.
223*/
224JSObject* OpaqueJSClass::prototype(ExecState* exec)
225{
226 /* Class (C++) and prototype (JS) inheritance are parallel, so:
227 * (C++) | (JS)
228 * ParentClass | ParentClassPrototype
229 * ^ | ^
230 * | | |
231 * DerivedClass | DerivedClassPrototype
232 */
233
234 if (!prototypeClass)
235 return 0;
236
237 OpaqueJSClassContextData& jsClassData = contextData(exec);
238
239 if (!jsClassData.cachedPrototype) {
240 // Recursive, but should be good enough for our purposes
241 jsClassData.cachedPrototype = new (exec) JSCallbackObject<JSObject>(exec, exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData); // set jsClassData as the object's private data, so it can clear our reference on destruction
242 if (parentClass) {
243 if (JSObject* prototype = parentClass->prototype(exec))
244 jsClassData.cachedPrototype->setPrototype(prototype);
245 }
246 }
247 return jsClassData.cachedPrototype.get();
248}
Note: See TracBrowser for help on using the repository browser.