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

Last change on this file since 35807 was 35418, checked in by [email protected], 17 years ago

Reviewed by Oliver Hunt.

Store UString::Rep::isStatic bit in identifierTable pointer instead of reportedCost for
slightly nicer code and a 0.5% SunSpider improvement.

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