]> git.saurik.com Git - apple/javascriptcore.git/blame - API/JSClassRef.cpp
JavaScriptCore-1097.3.3.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>
4e4e5a6f
A
36#include <wtf/text/StringHash.h>
37#include <wtf/unicode/UTF8.h>
b37bf2e1 38
f9bf01c6 39using namespace std;
9dae56ea 40using namespace JSC;
4e4e5a6f 41using namespace WTF::Unicode;
b37bf2e1
A
42
43const JSClassDefinition kJSClassDefinitionEmpty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
44
4e4e5a6f
A
45static inline UString tryCreateStringFromUTF8(const char* string)
46{
47 if (!string)
14957cd0 48 return UString();
4e4e5a6f
A
49
50 size_t length = strlen(string);
51 Vector<UChar, 1024> buffer(length);
52 UChar* p = buffer.data();
53 if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length))
14957cd0 54 return UString();
4e4e5a6f
A
55
56 return UString(buffer.data(), p - buffer.data());
57}
58
b37bf2e1 59OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* protoClass)
9dae56ea 60 : parentClass(definition->parentClass)
b37bf2e1 61 , prototypeClass(0)
b37bf2e1
A
62 , initialize(definition->initialize)
63 , finalize(definition->finalize)
64 , hasProperty(definition->hasProperty)
65 , getProperty(definition->getProperty)
66 , setProperty(definition->setProperty)
67 , deleteProperty(definition->deleteProperty)
68 , getPropertyNames(definition->getPropertyNames)
69 , callAsFunction(definition->callAsFunction)
70 , callAsConstructor(definition->callAsConstructor)
71 , hasInstance(definition->hasInstance)
72 , convertToType(definition->convertToType)
4e4e5a6f 73 , m_className(tryCreateStringFromUTF8(definition->className))
b37bf2e1 74{
9dae56ea
A
75 initializeThreading();
76
b37bf2e1 77 if (const JSStaticValue* staticValue = definition->staticValues) {
6fe7ccc8 78 m_staticValues = adoptPtr(new OpaqueJSClassStaticValuesTable);
b37bf2e1 79 while (staticValue->name) {
4e4e5a6f 80 UString valueName = tryCreateStringFromUTF8(staticValue->name);
6fe7ccc8
A
81 if (!valueName.isNull())
82 m_staticValues->set(valueName.impl(), adoptPtr(new StaticValueEntry(staticValue->getProperty, staticValue->setProperty, staticValue->attributes)));
b37bf2e1
A
83 ++staticValue;
84 }
85 }
9dae56ea 86
b37bf2e1 87 if (const JSStaticFunction* staticFunction = definition->staticFunctions) {
6fe7ccc8 88 m_staticFunctions = adoptPtr(new OpaqueJSClassStaticFunctionsTable);
b37bf2e1 89 while (staticFunction->name) {
4e4e5a6f 90 UString functionName = tryCreateStringFromUTF8(staticFunction->name);
6fe7ccc8
A
91 if (!functionName.isNull())
92 m_staticFunctions->set(functionName.impl(), adoptPtr(new StaticFunctionEntry(staticFunction->callAsFunction, staticFunction->attributes)));
b37bf2e1
A
93 ++staticFunction;
94 }
95 }
96
97 if (protoClass)
98 prototypeClass = JSClassRetain(protoClass);
99}
100
101OpaqueJSClass::~OpaqueJSClass()
102{
4e4e5a6f 103 // The empty string is shared across threads & is an identifier, in all other cases we should have done a deep copy in className(), below.
14957cd0 104 ASSERT(!m_className.length() || !m_className.impl()->isIdentifier());
9dae56ea 105
6fe7ccc8 106#ifndef NDEBUG
9dae56ea
A
107 if (m_staticValues) {
108 OpaqueJSClassStaticValuesTable::const_iterator end = m_staticValues->end();
6fe7ccc8 109 for (OpaqueJSClassStaticValuesTable::const_iterator it = m_staticValues->begin(); it != end; ++it)
f9bf01c6 110 ASSERT(!it->first->isIdentifier());
b37bf2e1
A
111 }
112
9dae56ea
A
113 if (m_staticFunctions) {
114 OpaqueJSClassStaticFunctionsTable::const_iterator end = m_staticFunctions->end();
6fe7ccc8 115 for (OpaqueJSClassStaticFunctionsTable::const_iterator it = m_staticFunctions->begin(); it != end; ++it)
f9bf01c6 116 ASSERT(!it->first->isIdentifier());
b37bf2e1 117 }
6fe7ccc8 118#endif
b37bf2e1
A
119
120 if (prototypeClass)
121 JSClassRelease(prototypeClass);
122}
123
9dae56ea 124PassRefPtr<OpaqueJSClass> OpaqueJSClass::createNoAutomaticPrototype(const JSClassDefinition* definition)
b37bf2e1 125{
9dae56ea 126 return adoptRef(new OpaqueJSClass(definition, 0));
b37bf2e1
A
127}
128
f9bf01c6 129PassRefPtr<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* clientDefinition)
b37bf2e1 130{
f9bf01c6 131 JSClassDefinition definition = *clientDefinition; // Avoid modifying client copy.
9dae56ea 132
f9bf01c6 133 JSClassDefinition protoDefinition = kJSClassDefinitionEmpty;
14957cd0 134 protoDefinition.finalize = 0;
f9bf01c6
A
135 swap(definition.staticFunctions, protoDefinition.staticFunctions); // Move static functions to the prototype.
136
137 // We are supposed to use JSClassRetain/Release but since we know that we currently have
138 // the only reference to this class object we cheat and use a RefPtr instead.
139 RefPtr<OpaqueJSClass> protoClass = adoptRef(new OpaqueJSClass(&protoDefinition, 0));
140 return adoptRef(new OpaqueJSClass(&definition, protoClass.get()));
9dae56ea
A
141}
142
14957cd0 143OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::JSGlobalData&, OpaqueJSClass* jsClass)
9dae56ea 144 : m_class(jsClass)
9dae56ea
A
145{
146 if (jsClass->m_staticValues) {
6fe7ccc8 147 staticValues = adoptPtr(new OpaqueJSClassStaticValuesTable);
9dae56ea
A
148 OpaqueJSClassStaticValuesTable::const_iterator end = jsClass->m_staticValues->end();
149 for (OpaqueJSClassStaticValuesTable::const_iterator it = jsClass->m_staticValues->begin(); it != end; ++it) {
f9bf01c6 150 ASSERT(!it->first->isIdentifier());
6fe7ccc8 151 staticValues->add(StringImpl::create(it->first->characters(), it->first->length()), adoptPtr(new StaticValueEntry(it->second->getProperty, it->second->setProperty, it->second->attributes)));
9dae56ea 152 }
6fe7ccc8 153 }
9dae56ea
A
154
155 if (jsClass->m_staticFunctions) {
6fe7ccc8 156 staticFunctions = adoptPtr(new OpaqueJSClassStaticFunctionsTable);
9dae56ea
A
157 OpaqueJSClassStaticFunctionsTable::const_iterator end = jsClass->m_staticFunctions->end();
158 for (OpaqueJSClassStaticFunctionsTable::const_iterator it = jsClass->m_staticFunctions->begin(); it != end; ++it) {
f9bf01c6 159 ASSERT(!it->first->isIdentifier());
6fe7ccc8 160 staticFunctions->add(StringImpl::create(it->first->characters(), it->first->length()), adoptPtr(new StaticFunctionEntry(it->second->callAsFunction, it->second->attributes)));
9dae56ea 161 }
9dae56ea
A
162 }
163}
164
165OpaqueJSClassContextData& OpaqueJSClass::contextData(ExecState* exec)
166{
6fe7ccc8 167 OwnPtr<OpaqueJSClassContextData>& contextData = exec->globalData().opaqueJSClassData.add(this, nullptr).iterator->second;
9dae56ea 168 if (!contextData)
6fe7ccc8 169 contextData = adoptPtr(new OpaqueJSClassContextData(exec->globalData(), this));
9dae56ea
A
170 return *contextData;
171}
172
173UString OpaqueJSClass::className()
174{
175 // Make a deep copy, so that the caller has no chance to put the original into IdentifierTable.
14957cd0 176 return UString(m_className.characters(), m_className.length());
9dae56ea
A
177}
178
179OpaqueJSClassStaticValuesTable* OpaqueJSClass::staticValues(JSC::ExecState* exec)
180{
6fe7ccc8 181 return contextData(exec).staticValues.get();
9dae56ea
A
182}
183
184OpaqueJSClassStaticFunctionsTable* OpaqueJSClass::staticFunctions(JSC::ExecState* exec)
185{
6fe7ccc8 186 return contextData(exec).staticFunctions.get();
b37bf2e1
A
187}
188
189/*!
190// Doc here in case we make this public. (Hopefully we won't.)
191@function
192 @abstract Returns the prototype that will be used when constructing an object with a given class.
193 @param ctx The execution context to use.
194 @param jsClass A JSClass whose prototype you want to get.
195 @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.
196*/
9dae56ea 197JSObject* OpaqueJSClass::prototype(ExecState* exec)
b37bf2e1
A
198{
199 /* Class (C++) and prototype (JS) inheritance are parallel, so:
200 * (C++) | (JS)
201 * ParentClass | ParentClassPrototype
202 * ^ | ^
203 * | | |
204 * DerivedClass | DerivedClassPrototype
205 */
6fe7ccc8 206
b37bf2e1
A
207 if (!prototypeClass)
208 return 0;
9dae56ea
A
209
210 OpaqueJSClassContextData& jsClassData = contextData(exec);
211
212 if (!jsClassData.cachedPrototype) {
b37bf2e1 213 // Recursive, but should be good enough for our purposes
6fe7ccc8 214 jsClassData.cachedPrototype = PassWeak<JSObject>(JSCallbackObject<JSNonFinalObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData), 0); // set jsClassData as the object's private data, so it can clear our reference on destruction
9dae56ea
A
215 if (parentClass) {
216 if (JSObject* prototype = parentClass->prototype(exec))
14957cd0 217 jsClassData.cachedPrototype->setPrototype(exec->globalData(), prototype);
9dae56ea 218 }
b37bf2e1 219 }
f9bf01c6 220 return jsClassData.cachedPrototype.get();
b37bf2e1 221}