Rename AtomicString to AtomString
[WebKit.git] / Source / JavaScriptCore / 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 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 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 "Identifier.h"
31 #include "InitializeThreading.h"
32 #include "JSCallbackObject.h"
33 #include "JSGlobalObject.h"
34 #include "JSObjectRef.h"
35 #include "ObjectPrototype.h"
36 #include "JSCInlines.h"
37 #include <wtf/text/StringHash.h>
38
39 using namespace JSC;
40
41 const JSClassDefinition kJSClassDefinitionEmpty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
42
43 OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* protoClass) 
44     : parentClass(definition->parentClass)
45     , prototypeClass(0)
46     , initialize(definition->initialize)
47     , finalize(definition->finalize)
48     , hasProperty(definition->hasProperty)
49     , getProperty(definition->getProperty)
50     , setProperty(definition->setProperty)
51     , deleteProperty(definition->deleteProperty)
52     , getPropertyNames(definition->getPropertyNames)
53     , callAsFunction(definition->callAsFunction)
54     , callAsConstructor(definition->callAsConstructor)
55     , hasInstance(definition->hasInstance)
56     , convertToType(definition->convertToType)
57     , m_className(String::fromUTF8(definition->className))
58 {
59     initializeThreading();
60
61     if (const JSStaticValue* staticValue = definition->staticValues) {
62         m_staticValues = std::make_unique<OpaqueJSClassStaticValuesTable>();
63         while (staticValue->name) {
64             String valueName = String::fromUTF8(staticValue->name);
65             if (!valueName.isNull())
66                 m_staticValues->set(valueName.impl(), std::make_unique<StaticValueEntry>(staticValue->getProperty, staticValue->setProperty, staticValue->attributes, valueName));
67             ++staticValue;
68         }
69     }
70
71     if (const JSStaticFunction* staticFunction = definition->staticFunctions) {
72         m_staticFunctions = std::make_unique<OpaqueJSClassStaticFunctionsTable>();
73         while (staticFunction->name) {
74             String functionName = String::fromUTF8(staticFunction->name);
75             if (!functionName.isNull())
76                 m_staticFunctions->set(functionName.impl(), std::make_unique<StaticFunctionEntry>(staticFunction->callAsFunction, staticFunction->attributes));
77             ++staticFunction;
78         }
79     }
80         
81     if (protoClass)
82         prototypeClass = JSClassRetain(protoClass);
83 }
84
85 OpaqueJSClass::~OpaqueJSClass()
86 {
87     // The empty string is shared across threads & is an identifier, in all other cases we should have done a deep copy in className(), below. 
88     ASSERT(!m_className.length() || !m_className.impl()->isAtom());
89
90 #ifndef NDEBUG
91     if (m_staticValues) {
92         OpaqueJSClassStaticValuesTable::const_iterator end = m_staticValues->end();
93         for (OpaqueJSClassStaticValuesTable::const_iterator it = m_staticValues->begin(); it != end; ++it)
94             ASSERT(!it->key->isAtom());
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->key->isAtom());
101     }
102 #endif
103     
104     if (prototypeClass)
105         JSClassRelease(prototypeClass);
106 }
107
108 Ref<OpaqueJSClass> OpaqueJSClass::createNoAutomaticPrototype(const JSClassDefinition* definition)
109 {
110     return adoptRef(*new OpaqueJSClass(definition, 0));
111 }
112
113 Ref<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* clientDefinition)
114 {
115     JSClassDefinition definition = *clientDefinition; // Avoid modifying client copy.
116
117     JSClassDefinition protoDefinition = kJSClassDefinitionEmpty;
118     protoDefinition.finalize = 0;
119     std::swap(definition.staticFunctions, protoDefinition.staticFunctions); // Move static functions to the prototype.
120     
121     // We are supposed to use JSClassRetain/Release but since we know that we currently have
122     // the only reference to this class object we cheat and use a RefPtr instead.
123     RefPtr<OpaqueJSClass> protoClass = adoptRef(new OpaqueJSClass(&protoDefinition, 0));
124     return adoptRef(*new OpaqueJSClass(&definition, protoClass.get()));
125 }
126
127 OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::VM&, OpaqueJSClass* jsClass)
128     : m_class(jsClass)
129 {
130     if (jsClass->m_staticValues) {
131         staticValues = std::make_unique<OpaqueJSClassStaticValuesTable>();
132         OpaqueJSClassStaticValuesTable::const_iterator end = jsClass->m_staticValues->end();
133         for (OpaqueJSClassStaticValuesTable::const_iterator it = jsClass->m_staticValues->begin(); it != end; ++it) {
134             ASSERT(!it->key->isAtom());
135             String valueName = it->key->isolatedCopy();
136             staticValues->add(valueName.impl(), std::make_unique<StaticValueEntry>(it->value->getProperty, it->value->setProperty, it->value->attributes, valueName));
137         }
138     }
139
140     if (jsClass->m_staticFunctions) {
141         staticFunctions = std::make_unique<OpaqueJSClassStaticFunctionsTable>();
142         OpaqueJSClassStaticFunctionsTable::const_iterator end = jsClass->m_staticFunctions->end();
143         for (OpaqueJSClassStaticFunctionsTable::const_iterator it = jsClass->m_staticFunctions->begin(); it != end; ++it) {
144             ASSERT(!it->key->isAtom());
145             staticFunctions->add(it->key->isolatedCopy(), std::make_unique<StaticFunctionEntry>(it->value->callAsFunction, it->value->attributes));
146         }
147     }
148 }
149
150 OpaqueJSClassContextData& OpaqueJSClass::contextData(ExecState* exec)
151 {
152     std::unique_ptr<OpaqueJSClassContextData>& contextData = exec->lexicalGlobalObject()->opaqueJSClassData().add(this, nullptr).iterator->value;
153     if (!contextData)
154         contextData = std::make_unique<OpaqueJSClassContextData>(exec->vm(), this);
155     return *contextData;
156 }
157
158 String OpaqueJSClass::className()
159 {
160     // Make a deep copy, so that the caller has no chance to put the original into AtomStringTable.
161     return m_className.isolatedCopy();
162 }
163
164 OpaqueJSClassStaticValuesTable* OpaqueJSClass::staticValues(JSC::ExecState* exec)
165 {
166     return contextData(exec).staticValues.get();
167 }
168
169 OpaqueJSClassStaticFunctionsTable* OpaqueJSClass::staticFunctions(JSC::ExecState* exec)
170 {
171     return contextData(exec).staticFunctions.get();
172 }
173
174 JSObject* OpaqueJSClass::prototype(ExecState* exec)
175 {
176     /* Class (C++) and prototype (JS) inheritance are parallel, so:
177      *     (C++)      |        (JS)
178      *   ParentClass  |   ParentClassPrototype
179      *       ^        |          ^
180      *       |        |          |
181      *  DerivedClass  |  DerivedClassPrototype
182      */
183
184     if (!prototypeClass)
185         return 0;
186
187     OpaqueJSClassContextData& jsClassData = contextData(exec);
188
189     if (JSObject* prototype = jsClassData.cachedPrototype.get())
190         return prototype;
191
192     // Recursive, but should be good enough for our purposes
193     JSObject* prototype = JSCallbackObject<JSDestructibleObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData); // set jsClassData as the object's private data, so it can clear our reference on destruction
194     if (parentClass) {
195         if (JSObject* parentPrototype = parentClass->prototype(exec))
196             prototype->setPrototypeDirect(exec->vm(), parentPrototype);
197     }
198
199     jsClassData.cachedPrototype = Weak<JSObject>(prototype);
200     return prototype;
201 }