2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "JSClassRef.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>
39 const JSClassDefinition kJSClassDefinitionEmpty
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
41 OpaqueJSClass::OpaqueJSClass(const JSClassDefinition
* definition
, OpaqueJSClass
* protoClass
)
42 : parentClass(definition
->parentClass
)
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
))
57 , m_staticFunctions(0)
59 initializeThreading();
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
));
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
));
80 prototypeClass
= JSClassRetain(protoClass
);
83 OpaqueJSClass::~OpaqueJSClass()
85 ASSERT(!m_className
.rep()->identifierTable());
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());
93 delete m_staticValues
;
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());
102 delete m_staticFunctions
;
106 JSClassRelease(prototypeClass
);
109 PassRefPtr
<OpaqueJSClass
> OpaqueJSClass::createNoAutomaticPrototype(const JSClassDefinition
* definition
)
111 return adoptRef(new OpaqueJSClass(definition
, 0));
114 static void clearReferenceToPrototype(JSObjectRef prototype
)
116 OpaqueJSClassContextData
* jsClassData
= static_cast<OpaqueJSClassContextData
*>(JSObjectGetPrivate(prototype
));
118 jsClassData
->cachedPrototype
= 0;
121 PassRefPtr
<OpaqueJSClass
> OpaqueJSClass::create(const JSClassDefinition
* definition
)
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
;
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));
133 // remove functions from the original class
134 JSClassDefinition objectDefinition
= *definition
;
135 objectDefinition
.staticFunctions
= 0;
137 return adoptRef(new OpaqueJSClass(&objectDefinition
, protoClass
.get()));
140 return adoptRef(new OpaqueJSClass(definition
, 0));
143 OpaqueJSClassContextData::OpaqueJSClassContextData(OpaqueJSClass
* jsClass
)
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
));
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
));
173 OpaqueJSClassContextData::~OpaqueJSClassContextData()
176 deleteAllValues(*staticValues
);
180 if (staticFunctions
) {
181 deleteAllValues(*staticFunctions
);
182 delete staticFunctions
;
186 OpaqueJSClassContextData
& OpaqueJSClass::contextData(ExecState
* exec
)
188 OpaqueJSClassContextData
*& contextData
= exec
->globalData().opaqueJSClassData
.add(this, 0).first
->second
;
190 contextData
= new OpaqueJSClassContextData(this);
194 UString
OpaqueJSClass::className()
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());
200 OpaqueJSClassStaticValuesTable
* OpaqueJSClass::staticValues(JSC::ExecState
* exec
)
202 OpaqueJSClassContextData
& jsClassData
= contextData(exec
);
203 return jsClassData
.staticValues
;
206 OpaqueJSClassStaticFunctionsTable
* OpaqueJSClass::staticFunctions(JSC::ExecState
* exec
)
208 OpaqueJSClassContextData
& jsClassData
= contextData(exec
);
209 return jsClassData
.staticFunctions
;
213 // Doc here in case we make this public. (Hopefully we won't.)
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.
220 JSObject
* OpaqueJSClass::prototype(ExecState
* exec
)
222 /* Class (C++) and prototype (JS) inheritance are parallel, so:
224 * ParentClass | ParentClassPrototype
227 * DerivedClass | DerivedClassPrototype
233 OpaqueJSClassContextData
& jsClassData
= contextData(exec
);
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
239 if (JSObject
* prototype
= parentClass
->prototype(exec
))
240 jsClassData
.cachedPrototype
->setPrototype(prototype
);
243 return jsClassData
.cachedPrototype
;