Exception is a JSCell, not a JSObject.
[WebKit-https.git] / Source / WebCore / bridge / objc / objc_utility.mm
1 /*
2  * Copyright (C) 2004-2019 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 #import "config.h"
27 #import "objc_utility.h"
28
29 #import "WebScriptObjectProtocol.h"
30 #import "objc_instance.h"
31 #import "runtime_array.h"
32 #import "runtime_object.h"
33 #import <JavaScriptCore/JSGlobalObject.h>
34 #import <JavaScriptCore/JSLock.h>
35 #import <wtf/Assertions.h>
36
37 #if !defined(_C_LNG_LNG)
38 #define _C_LNG_LNG 'q'
39 #endif
40
41 #if !defined(_C_ULNG_LNG)
42 #define _C_ULNG_LNG 'Q'
43 #endif
44
45 #if !defined(_C_CONST)
46 #define _C_CONST 'r'
47 #endif
48
49 #if !defined(_C_BYCOPY)
50 #define _C_BYCOPY 'O'
51 #endif
52
53 #if !defined(_C_BYREF)
54 #define _C_BYREF 'R'
55 #endif
56
57 #if !defined(_C_ONEWAY)
58 #define _C_ONEWAY 'V'
59 #endif
60
61 #if !defined(_C_GCINVISIBLE)
62 #define _C_GCINVISIBLE '!'
63 #endif
64
65 namespace JSC {
66 namespace Bindings {
67
68 /*
69
70     JavaScript to   ObjC
71     Number          coerced to char, short, int, long, float, double, or NSNumber, as appropriate
72     String          NSString
73     wrapper         id
74     Object          WebScriptObject
75     null            NSNull
76     [], other       exception
77
78 */
79 ObjcValue convertValueToObjcValue(ExecState* exec, JSValue value, ObjcValueType type)
80 {
81     ObjcValue result;
82     double d = 0;
83
84     if (value.isNumber() || value.isString() || value.isBoolean()) {
85         JSLockHolder lock(exec);
86         d = value.toNumber(exec);
87     }
88
89     switch (type) {
90         case ObjcObjectType: {
91             VM& vm = exec->vm();
92             JSLockHolder lock(vm);
93             
94             JSGlobalObject *originGlobalObject = vm.vmEntryGlobalObject(exec);
95             RootObject* originRootObject = findRootObject(originGlobalObject);
96
97             JSGlobalObject* globalObject = 0;
98             if (value.isObject() && asObject(value)->isGlobalObject())
99                 globalObject = jsCast<JSGlobalObject*>(asObject(value));
100
101             if (!globalObject)
102                 globalObject = originGlobalObject;
103                 
104             RootObject* rootObject = findRootObject(globalObject);
105             result.objectValue = rootObject
106                 ? (__bridge CFTypeRef)[webScriptObjectClass() _convertValueToObjcValue:value originRootObject:originRootObject rootObject:rootObject]
107                 : nil;
108         }
109         break;
110
111         case ObjcCharType:
112         case ObjcUnsignedCharType:
113             result.charValue = (char)d;
114             break;
115         case ObjcShortType:
116         case ObjcUnsignedShortType:
117             result.shortValue = (short)d;
118             break;
119         case ObjcBoolType:
120             result.booleanValue = (bool)d;
121             break;
122         case ObjcIntType:
123         case ObjcUnsignedIntType:
124             result.intValue = (int)d;
125             break;
126         case ObjcLongType:
127         case ObjcUnsignedLongType:
128             result.longValue = (long)d;
129             break;
130         case ObjcLongLongType:
131         case ObjcUnsignedLongLongType:
132             result.longLongValue = (long long)d;
133             break;
134         case ObjcFloatType:
135             result.floatValue = (float)d;
136             break;
137         case ObjcDoubleType:
138             result.doubleValue = (double)d;
139             break;
140         case ObjcVoidType:
141             bzero(&result, sizeof(ObjcValue));
142             break;
143
144         case ObjcInvalidType:
145         default:
146             // FIXME: throw an exception?
147             break;
148     }
149
150     return result;
151 }
152
153 JSValue convertNSStringToString(ExecState* exec, NSString *nsstring)
154 {
155     JSLockHolder lock(exec);
156     JSValue aValue = jsString(exec, String(nsstring));
157     return aValue;
158 }
159
160 /*
161     ObjC      to    JavaScript
162     ----            ----------
163     char            number
164     short           number
165     int             number
166     long            number
167     float           number
168     double          number
169     NSNumber        boolean or number
170     NSString        string
171     NSArray         array
172     NSNull          null
173     WebScriptObject underlying JavaScript object
174     WebUndefined    undefined
175     id              object wrapper
176     other           should not happen
177 */
178 JSValue convertObjcValueToValue(ExecState* exec, void* buffer, ObjcValueType type, RootObject* rootObject)
179 {
180     JSLockHolder lock(exec);
181     
182     switch (type) {
183         case ObjcObjectType: {
184             id obj = *(const id*)buffer;
185             if ([obj isKindOfClass:[NSString class]])
186                 return convertNSStringToString(exec, (NSString *)obj);
187             if ([obj isKindOfClass:webUndefinedClass()])
188                 return jsUndefined();
189             if ((__bridge CFBooleanRef)obj == kCFBooleanTrue)
190                 return jsBoolean(true);
191             if ((__bridge CFBooleanRef)obj == kCFBooleanFalse)
192                 return jsBoolean(false);
193             if ([obj isKindOfClass:[NSNumber class]])
194                 return jsNumber([obj doubleValue]);
195             if ([obj isKindOfClass:[NSArray class]])
196                 return RuntimeArray::create(exec, new ObjcArray(obj, rootObject));
197             if ([obj isKindOfClass:webScriptObjectClass()]) {
198                 JSObject* imp = [obj _imp];
199                 return imp ? imp : jsUndefined();
200             }
201             if ([obj isKindOfClass:[NSNull class]])
202                 return jsNull();
203             if (obj == 0)
204                 return jsUndefined();
205             return ObjcInstance::create(obj, rootObject)->createRuntimeObject(exec);
206         }
207         case ObjcCharType:
208             return jsNumber(*(char*)buffer);
209         case ObjcUnsignedCharType:
210             return jsNumber(*(unsigned char*)buffer);
211         case ObjcShortType:
212             return jsNumber(*(short*)buffer);
213         case ObjcUnsignedShortType:
214             return jsNumber(*(unsigned short*)buffer);
215         case ObjcBoolType:
216             return jsBoolean(*(bool*)buffer);
217         case ObjcIntType:
218             return jsNumber(*(int*)buffer);
219         case ObjcUnsignedIntType:
220             return jsNumber(*(unsigned int*)buffer);
221         case ObjcLongType:
222             return jsNumber(*(long*)buffer);
223         case ObjcUnsignedLongType:
224             return jsNumber(*(unsigned long*)buffer);
225         case ObjcLongLongType:
226             return jsNumber(*(long long*)buffer);
227         case ObjcUnsignedLongLongType:
228             return jsNumber(*(unsigned long long*)buffer);
229         case ObjcFloatType:
230             return jsNumber(*(float*)buffer);
231         case ObjcDoubleType:
232             return jsNumber(*(double*)buffer);
233         default:
234             // Should never get here. Argument types are filtered.
235             fprintf(stderr, "%s: invalid type (%d)\n", __PRETTY_FUNCTION__, (int)type);
236             ASSERT_NOT_REACHED();
237     }
238     
239     return jsUndefined();
240 }
241
242 ObjcValueType objcValueTypeForType(const char *type)
243 {
244     int typeLength = strlen(type);
245     ObjcValueType objcValueType = ObjcInvalidType;
246
247     for (int i = 0; i < typeLength; ++i) {
248         char typeChar = type[i];
249         switch (typeChar) {
250             case _C_CONST:
251             case _C_BYCOPY:
252             case _C_BYREF:
253             case _C_ONEWAY:
254             case _C_GCINVISIBLE:
255                 // skip these type modifiers
256                 break;
257             case _C_ID:
258                 objcValueType = ObjcObjectType;
259                 break;
260             case _C_CHR:
261                 objcValueType = ObjcCharType;
262                 break;
263             case _C_UCHR:
264                 objcValueType = ObjcUnsignedCharType;
265                 break;
266             case _C_SHT:
267                 objcValueType = ObjcShortType;
268                 break;
269             case _C_USHT:
270                 objcValueType = ObjcUnsignedShortType;
271                 break;
272             case _C_BOOL:
273                 objcValueType = ObjcBoolType;
274                 break;
275             case _C_INT:
276                 objcValueType = ObjcIntType;
277                 break;
278             case _C_UINT:
279                 objcValueType = ObjcUnsignedIntType;
280                 break;
281             case _C_LNG:
282                 objcValueType = ObjcLongType;
283                 break;
284             case _C_ULNG:
285                 objcValueType = ObjcUnsignedLongType;
286                 break;
287             case _C_LNG_LNG:
288                 objcValueType = ObjcLongLongType;
289                 break;
290             case _C_ULNG_LNG:
291                 objcValueType = ObjcUnsignedLongLongType;
292                 break;
293             case _C_FLT:
294                 objcValueType = ObjcFloatType;
295                 break;
296             case _C_DBL:
297                 objcValueType = ObjcDoubleType;
298                 break;
299             case _C_VOID:
300                 objcValueType = ObjcVoidType;
301                 break;
302             default:
303                 // Unhandled type. We don't handle C structs, unions, etc.
304                 // FIXME: throw an exception?
305                 WTFLogAlways("Unhandled ObjC type specifier: \"%c\" used in ObjC bridge.", typeChar);
306                 RELEASE_ASSERT_NOT_REACHED();
307         }
308
309         if (objcValueType != ObjcInvalidType)
310             break;
311     }
312
313     return objcValueType;
314 }
315
316 Exception *throwError(ExecState *exec, ThrowScope& scope, NSString *message)
317 {
318     ASSERT(message);
319     return throwException(exec, scope, JSC::createError(exec, String(message)));
320 }
321
322 }
323 }