]> git.saurik.com Git - apple/javascriptcore.git/blame - API/JSClassRef.cpp
JavaScriptCore-525.tar.gz
[apple/javascriptcore.git] / API / JSClassRef.cpp
CommitLineData
b37bf2e1
A
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"
9dae56ea
A
32#include <runtime/InitializeThreading.h>
33#include <runtime/JSGlobalObject.h>
34#include <runtime/ObjectPrototype.h>
35#include <runtime/Identifier.h>
b37bf2e1 36
9dae56ea 37using namespace JSC;
b37bf2e1
A
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)
9dae56ea 42 : parentClass(definition->parentClass)
b37bf2e1 43 , prototypeClass(0)
b37bf2e1
A
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)
9dae56ea
A
55 , m_className(UString::Rep::createFromUTF8(definition->className))
56 , m_staticValues(0)
57 , m_staticFunctions(0)
b37bf2e1 58{
9dae56ea
A
59 initializeThreading();
60
b37bf2e1 61 if (const JSStaticValue* staticValue = definition->staticValues) {
9dae56ea 62 m_staticValues = new OpaqueJSClassStaticValuesTable();
b37bf2e1 63 while (staticValue->name) {
9dae56ea 64 m_staticValues->add(UString::Rep::createFromUTF8(staticValue->name),
b37bf2e1
A
65 new StaticValueEntry(staticValue->getProperty, staticValue->setProperty, staticValue->attributes));
66 ++staticValue;
67 }
68 }
9dae56ea 69
b37bf2e1 70 if (const JSStaticFunction* staticFunction = definition->staticFunctions) {
9dae56ea 71 m_staticFunctions = new OpaqueJSClassStaticFunctionsTable();
b37bf2e1 72 while (staticFunction->name) {
9dae56ea 73 m_staticFunctions->add(UString::Rep::createFromUTF8(staticFunction->name),
b37bf2e1
A
74 new StaticFunctionEntry(staticFunction->callAsFunction, staticFunction->attributes));
75 ++staticFunction;
76 }
77 }
78
79 if (protoClass)
80 prototypeClass = JSClassRetain(protoClass);
81}
82
83OpaqueJSClass::~OpaqueJSClass()
84{
9dae56ea
A
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;
b37bf2e1
A
94 }
95
9dae56ea
A
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;
b37bf2e1
A
103 }
104
105 if (prototypeClass)
106 JSClassRelease(prototypeClass);
107}
108
9dae56ea 109PassRefPtr<OpaqueJSClass> OpaqueJSClass::createNoAutomaticPrototype(const JSClassDefinition* definition)
b37bf2e1 110{
9dae56ea 111 return adoptRef(new OpaqueJSClass(definition, 0));
b37bf2e1
A
112}
113
9dae56ea 114static void clearReferenceToPrototype(JSObjectRef prototype)
b37bf2e1 115{
9dae56ea
A
116 OpaqueJSClassContextData* jsClassData = static_cast<OpaqueJSClassContextData*>(JSObjectGetPrivate(prototype));
117 ASSERT(jsClassData);
118 jsClassData->cachedPrototype = 0;
b37bf2e1
A
119}
120
9dae56ea 121PassRefPtr<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* definition)
b37bf2e1
A
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;
9dae56ea
A
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));
b37bf2e1
A
132
133 // remove functions from the original class
134 JSClassDefinition objectDefinition = *definition;
135 objectDefinition.staticFunctions = 0;
9dae56ea
A
136
137 return adoptRef(new OpaqueJSClass(&objectDefinition, protoClass.get()));
138 }
139
140 return adoptRef(new OpaqueJSClass(definition, 0));
141}
142
143OpaqueJSClassContextData::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
173OpaqueJSClassContextData::~OpaqueJSClassContextData()
174{
175 if (staticValues) {
176 deleteAllValues(*staticValues);
177 delete staticValues;
b37bf2e1
A
178 }
179
9dae56ea
A
180 if (staticFunctions) {
181 deleteAllValues(*staticFunctions);
182 delete staticFunctions;
183 }
184}
185
186OpaqueJSClassContextData& 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
194UString 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
200OpaqueJSClassStaticValuesTable* OpaqueJSClass::staticValues(JSC::ExecState* exec)
201{
202 OpaqueJSClassContextData& jsClassData = contextData(exec);
203 return jsClassData.staticValues;
204}
205
206OpaqueJSClassStaticFunctionsTable* OpaqueJSClass::staticFunctions(JSC::ExecState* exec)
207{
208 OpaqueJSClassContextData& jsClassData = contextData(exec);
209 return jsClassData.staticFunctions;
b37bf2e1
A
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*/
9dae56ea 220JSObject* OpaqueJSClass::prototype(ExecState* exec)
b37bf2e1
A
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;
9dae56ea
A
232
233 OpaqueJSClassContextData& jsClassData = contextData(exec);
234
235 if (!jsClassData.cachedPrototype) {
b37bf2e1 236 // Recursive, but should be good enough for our purposes
9dae56ea
A
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 }
b37bf2e1 242 }
9dae56ea 243 return jsClassData.cachedPrototype;
b37bf2e1 244}