Fix REGRESSION(r27885): Installer hits assertion failure in JavaScriptGlue.
[WebKit-https.git] / JavaScriptGlue / JSValueWrapper.cpp
1 /*
2  * Copyright (C) 2005 Apple Computer, 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  *
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  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "JSValueWrapper.h"
31 #include <JavaScriptCore/PropertyNameArray.h>
32 #include <pthread.h>
33
34 JSValueWrapper::JSValueWrapper(JSValue *inValue)
35     : fValue(inValue)
36 {
37 }
38
39 JSValueWrapper::~JSValueWrapper()
40 {
41 }
42
43 JSValue *JSValueWrapper::GetValue()
44 {
45     return fValue;
46 }
47
48 /*
49  * This is a slight hack. The JSGlue API has no concept of execution state.
50  * However, execution state is an inherent part of JS, and JSCore requires it.
51  * So, we keep a single execution state for the whole thread and supply it
52  * where necessary.
53
54  * The execution state holds two things: (1) exceptions; (2) the global object. 
55  * JSGlue has no API for accessing exceptions, so we just discard them. As for
56  * the global object, JSGlue includes no calls that depend on it. Its property
57  * getters and setters are per-object; they don't walk up the enclosing scope. 
58  * Functions called by JSObjectCallFunction may reference values in the enclosing 
59  * scope, but they do so through an internally stored scope chain, so we don't 
60  * need to supply the global scope.
61  */      
62
63 pthread_key_t interpreterKey;
64 pthread_once_t interpreterKeyOnce = PTHREAD_ONCE_INIT;
65
66 static void derefInterpreter(void* data) 
67 {
68     static_cast<Interpreter*>(data)->deref();
69 }
70
71 static void initializeInterpreterKey()
72 {
73     pthread_key_create(&interpreterKey, derefInterpreter);
74 }
75
76 static ExecState* getThreadGlobalExecState()
77 {
78     pthread_once(&interpreterKeyOnce, initializeInterpreterKey);
79     Interpreter* interpreter = static_cast<Interpreter*>(pthread_getspecific(interpreterKey));
80     if (!interpreter) {
81         interpreter = new Interpreter();
82         interpreter->setGlobalObject(new JSGlobalObject());
83         interpreter->ref();
84         pthread_setspecific(interpreterKey, interpreter);
85     }
86
87     // Discard exceptions -- otherwise an exception would forestall JS 
88     // evaluation throughout the thread
89     interpreter->globalExec()->clearException();
90
91     return interpreter->globalExec();
92 }
93
94 void JSValueWrapper::GetJSObectCallBacks(JSObjectCallBacks& callBacks)
95 {
96     callBacks.dispose = (JSObjectDisposeProcPtr)JSValueWrapper::JSObjectDispose;
97     callBacks.equal = (JSObjectEqualProcPtr)0;
98     callBacks.copyPropertyNames = (JSObjectCopyPropertyNamesProcPtr)JSValueWrapper::JSObjectCopyPropertyNames;
99     callBacks.copyCFValue = (JSObjectCopyCFValueProcPtr)JSValueWrapper::JSObjectCopyCFValue;
100     callBacks.copyProperty = (JSObjectCopyPropertyProcPtr)JSValueWrapper::JSObjectCopyProperty;
101     callBacks.setProperty = (JSObjectSetPropertyProcPtr)JSValueWrapper::JSObjectSetProperty;
102     callBacks.callFunction = (JSObjectCallFunctionProcPtr)JSValueWrapper::JSObjectCallFunction;
103 }
104
105 void JSValueWrapper::JSObjectDispose(void *data)
106 {
107     JSValueWrapper* ptr = (JSValueWrapper*)data;
108     delete ptr;
109 }
110
111
112 CFArrayRef JSValueWrapper::JSObjectCopyPropertyNames(void *data)
113 {
114     JSLock lock;
115
116     CFMutableArrayRef result = 0;
117     JSValueWrapper* ptr = (JSValueWrapper*)data;
118     if (ptr)
119     {
120         ExecState* exec = getThreadGlobalExecState();
121         JSObject *object = ptr->GetValue()->toObject(exec);
122         PropertyNameArray propNames;
123         object->getPropertyNames(exec, propNames);
124         PropertyNameArray::const_iterator iterator = propNames.begin();
125
126         while (iterator != propNames.end()) {
127             Identifier name = *iterator;
128             CFStringRef nameStr = IdentifierToCFString(name);
129
130             if (!result)
131             {
132                 result = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
133             }
134             if (result && nameStr)
135             {
136                 CFArrayAppendValue(result, nameStr);
137             }
138             ReleaseCFType(nameStr);
139             iterator++;
140         }
141
142     }
143     return result;
144 }
145
146
147 JSObjectRef JSValueWrapper::JSObjectCopyProperty(void *data, CFStringRef propertyName)
148 {
149     JSLock lock;
150
151     JSObjectRef result = 0;
152     JSValueWrapper* ptr = (JSValueWrapper*)data;
153     if (ptr)
154     {
155         ExecState* exec = getThreadGlobalExecState();
156         JSValue *propValue = ptr->GetValue()->toObject(exec)->get(exec, CFStringToIdentifier(propertyName));
157         JSValueWrapper* wrapperValue = new JSValueWrapper(propValue);
158
159         JSObjectCallBacks callBacks;
160         GetJSObectCallBacks(callBacks);
161         result = JSObjectCreateInternal(wrapperValue, &callBacks, JSValueWrapper::JSObjectMark, kJSUserObjectDataTypeJSValueWrapper);
162
163         if (!result)
164         {
165             delete wrapperValue;
166         }
167     }
168     return result;
169 }
170
171 void JSValueWrapper::JSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue)
172 {
173     JSLock lock;
174
175     JSValueWrapper* ptr = (JSValueWrapper*)data;
176     if (ptr)
177     {
178         ExecState* exec = getThreadGlobalExecState();
179         JSValue *value = JSObjectKJSValue((JSUserObject*)jsValue);
180         JSObject *objValue = ptr->GetValue()->toObject(exec);
181         objValue->put(exec, CFStringToIdentifier(propertyName), value);
182     }
183 }
184
185 JSObjectRef JSValueWrapper::JSObjectCallFunction(void *data, JSObjectRef thisObj, CFArrayRef args)
186 {
187     JSLock lock;
188
189     JSObjectRef result = 0;
190     JSValueWrapper* ptr = (JSValueWrapper*)data;
191     if (ptr)
192     {
193         ExecState* exec = getThreadGlobalExecState();
194
195         JSValue *value = JSObjectKJSValue((JSUserObject*)thisObj);
196         JSObject *ksjThisObj = value->toObject(exec);
197         JSObject *objValue = ptr->GetValue()->toObject(exec);
198
199         List listArgs;
200         CFIndex argCount = args ? CFArrayGetCount(args) : 0;
201         for (CFIndex i = 0; i < argCount; i++)
202         {
203             JSObjectRef jsArg = (JSObjectRef)CFArrayGetValueAtIndex(args, i);
204             JSValue *kgsArg = JSObjectKJSValue((JSUserObject*)jsArg);
205             listArgs.append(kgsArg);
206         }
207
208         JSValue *resultValue = objValue->call(exec, ksjThisObj, listArgs);
209         JSValueWrapper* wrapperValue = new JSValueWrapper(resultValue);
210         JSObjectCallBacks callBacks;
211         GetJSObectCallBacks(callBacks);
212         result = JSObjectCreate(wrapperValue, &callBacks);
213         if (!result)
214         {
215             delete wrapperValue;
216         }
217     }
218     return result;
219 }
220
221 CFTypeRef JSValueWrapper::JSObjectCopyCFValue(void *data)
222 {
223     JSLock lock;
224
225     CFTypeRef result = 0;
226     JSValueWrapper* ptr = (JSValueWrapper*)data;
227     if (ptr)
228     {
229         result = KJSValueToCFType(ptr->GetValue(), getThreadGlobalExecState());
230     }
231     return result;
232 }
233
234 void JSValueWrapper::JSObjectMark(void *data)
235 {
236     JSValueWrapper* ptr = (JSValueWrapper*)data;
237     if (ptr)
238     {
239         ptr->fValue->mark();
240     }
241 }