]> git.saurik.com Git - apple/javascriptcore.git/blob - API/JSClassRef.cpp
JavaScriptCore-521.tar.gz
[apple/javascriptcore.git] / API / JSClassRef.cpp
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
37 using namespace JSC;
38
39 const JSClassDefinition kJSClassDefinitionEmpty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
40
41 OpaqueJSClass::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::Rep::createFromUTF8(definition->className))
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 m_staticValues->add(UString::Rep::createFromUTF8(staticValue->name),
65 new StaticValueEntry(staticValue->getProperty, staticValue->setProperty, staticValue->attributes));
66 ++staticValue;
67 }
68 }
69
70 if (const JSStaticFunction* staticFunction = definition->staticFunctions) {
71 m_staticFunctions = new OpaqueJSClassStaticFunctionsTable();
72 while (staticFunction->name) {
73 m_staticFunctions->add(UString::Rep::createFromUTF8(staticFunction->name),
74 new StaticFunctionEntry(staticFunction->callAsFunction, staticFunction->attributes));
75 ++staticFunction;
76 }
77 }
78
79 if (protoClass)
80 prototypeClass = JSClassRetain(protoClass);
81 }
82
83 OpaqueJSClass::~OpaqueJSClass()
84 {
85 ASSERT(!m_className.rep()->identifierTable());
86
87 if (m_staticValues) {
88 OpaqueJSClassStaticValuesTable::const_iterator end = m_staticValues->end();
89 for (OpaqueJSClassStaticValuesTable::const_iterator it = m_staticValues->begin(); it != end; ++it) {
90 ASSERT(!it->first->identifierTable());
91 delete it->second;
92 }
93 delete m_staticValues;
94 }
95
96 if (m_staticFunctions) {
97 OpaqueJSClassStaticFunctionsTable::const_iterator end = m_staticFunctions->end();
98 for (OpaqueJSClassStaticFunctionsTable::const_iterator it = m_staticFunctions->begin(); it != end; ++it) {
99 ASSERT(!it->first->identifierTable());
100 delete it->second;
101 }
102 delete m_staticFunctions;
103 }
104
105 if (prototypeClass)
106 JSClassRelease(prototypeClass);
107 }
108
109 PassRefPtr<OpaqueJSClass> OpaqueJSClass::createNoAutomaticPrototype(const JSClassDefinition* definition)
110 {
111 return adoptRef(new OpaqueJSClass(definition, 0));
112 }
113
114 static void clearReferenceToPrototype(JSObjectRef prototype)
115 {
116 OpaqueJSClassContextData* jsClassData = static_cast<OpaqueJSClassContextData*>(JSObjectGetPrivate(prototype));
117 ASSERT(jsClassData);
118 jsClassData->cachedPrototype = 0;
119 }
120
121 PassRefPtr<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* definition)
122 {
123 if (const JSStaticFunction* staticFunctions = definition->staticFunctions) {
124 // copy functions into a prototype class
125 JSClassDefinition protoDefinition = kJSClassDefinitionEmpty;
126 protoDefinition.staticFunctions = staticFunctions;
127 protoDefinition.finalize = clearReferenceToPrototype;
128
129 // We are supposed to use JSClassRetain/Release but since we know that we currently have
130 // the only reference to this class object we cheat and use a RefPtr instead.
131 RefPtr<OpaqueJSClass> protoClass = adoptRef(new OpaqueJSClass(&protoDefinition, 0));
132
133 // remove functions from the original class
134 JSClassDefinition objectDefinition = *definition;
135 objectDefinition.staticFunctions = 0;
136
137 return adoptRef(new OpaqueJSClass(&objectDefinition, protoClass.get()));
138 }
139
140 return adoptRef(new OpaqueJSClass(definition, 0));
141 }
142
143 OpaqueJSClassContextData::OpaqueJSClassContextData(OpaqueJSClass* jsClass)
144 : m_class(jsClass)
145 , cachedPrototype(0)
146 {
147 if (jsClass->m_staticValues) {
148 staticValues = new OpaqueJSClassStaticValuesTable;
149 OpaqueJSClassStaticValuesTable::const_iterator end = jsClass->m_staticValues->end();
150 for (OpaqueJSClassStaticValuesTable::const_iterator it = jsClass->m_staticValues->begin(); it != end; ++it) {
151 ASSERT(!it->first->identifierTable());
152 staticValues->add(UString::Rep::createCopying(it->first->data(), it->first->size()),
153 new StaticValueEntry(it->second->getProperty, it->second->setProperty, it->second->attributes));
154 }
155
156 } else
157 staticValues = 0;
158
159
160 if (jsClass->m_staticFunctions) {
161 staticFunctions = new OpaqueJSClassStaticFunctionsTable;
162 OpaqueJSClassStaticFunctionsTable::const_iterator end = jsClass->m_staticFunctions->end();
163 for (OpaqueJSClassStaticFunctionsTable::const_iterator it = jsClass->m_staticFunctions->begin(); it != end; ++it) {
164 ASSERT(!it->first->identifierTable());
165 staticFunctions->add(UString::Rep::createCopying(it->first->data(), it->first->size()),
166 new StaticFunctionEntry(it->second->callAsFunction, it->second->attributes));
167 }
168
169 } else
170 staticFunctions = 0;
171 }
172
173 OpaqueJSClassContextData::~OpaqueJSClassContextData()
174 {
175 if (staticValues) {
176 deleteAllValues(*staticValues);
177 delete staticValues;
178 }
179
180 if (staticFunctions) {
181 deleteAllValues(*staticFunctions);
182 delete staticFunctions;
183 }
184 }
185
186 OpaqueJSClassContextData& OpaqueJSClass::contextData(ExecState* exec)
187 {
188 OpaqueJSClassContextData*& contextData = exec->globalData().opaqueJSClassData.add(this, 0).first->second;
189 if (!contextData)
190 contextData = new OpaqueJSClassContextData(this);
191 return *contextData;
192 }
193
194 UString OpaqueJSClass::className()
195 {
196 // Make a deep copy, so that the caller has no chance to put the original into IdentifierTable.
197 return UString(m_className.data(), m_className.size());
198 }
199
200 OpaqueJSClassStaticValuesTable* OpaqueJSClass::staticValues(JSC::ExecState* exec)
201 {
202 OpaqueJSClassContextData& jsClassData = contextData(exec);
203 return jsClassData.staticValues;
204 }
205
206 OpaqueJSClassStaticFunctionsTable* OpaqueJSClass::staticFunctions(JSC::ExecState* exec)
207 {
208 OpaqueJSClassContextData& jsClassData = contextData(exec);
209 return jsClassData.staticFunctions;
210 }
211
212 /*!
213 // Doc here in case we make this public. (Hopefully we won't.)
214 @function
215 @abstract Returns the prototype that will be used when constructing an object with a given class.
216 @param ctx The execution context to use.
217 @param jsClass A JSClass whose prototype you want to get.
218 @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.
219 */
220 JSObject* OpaqueJSClass::prototype(ExecState* exec)
221 {
222 /* Class (C++) and prototype (JS) inheritance are parallel, so:
223 * (C++) | (JS)
224 * ParentClass | ParentClassPrototype
225 * ^ | ^
226 * | | |
227 * DerivedClass | DerivedClassPrototype
228 */
229
230 if (!prototypeClass)
231 return 0;
232
233 OpaqueJSClassContextData& jsClassData = contextData(exec);
234
235 if (!jsClassData.cachedPrototype) {
236 // Recursive, but should be good enough for our purposes
237 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
238 if (parentClass) {
239 if (JSObject* prototype = parentClass->prototype(exec))
240 jsClassData.cachedPrototype->setPrototype(prototype);
241 }
242 }
243 return jsClassData.cachedPrototype;
244 }