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 "JSValueRef.h"
28
29 #include <wtf/Platform.h>
30 #include "APICast.h"
31 #include "APIShims.h"
32 #include "JSCallbackObject.h"
33
34 #include <runtime/JSGlobalObject.h>
35 #include <runtime/JSString.h>
36 #include <runtime/Operations.h>
37 #include <runtime/Protect.h>
38 #include <runtime/UString.h>
39 #include <runtime/JSValue.h>
40
41 #include <wtf/Assertions.h>
42
43 #include <algorithm> // for std::min
44
45 using namespace JSC;
46
JSValueGetType(JSContextRef ctx,JSValueRef value)47 ::JSType JSValueGetType(JSContextRef ctx, JSValueRef value)
48 {
49 ExecState* exec = toJS(ctx);
50 APIEntryShim entryShim(exec);
51
52 JSValue jsValue = toJS(exec, value);
53
54 if (jsValue.isUndefined())
55 return kJSTypeUndefined;
56 if (jsValue.isNull())
57 return kJSTypeNull;
58 if (jsValue.isBoolean())
59 return kJSTypeBoolean;
60 if (jsValue.isNumber())
61 return kJSTypeNumber;
62 if (jsValue.isString())
63 return kJSTypeString;
64 ASSERT(jsValue.isObject());
65 return kJSTypeObject;
66 }
67
JSValueIsUndefined(JSContextRef ctx,JSValueRef value)68 bool JSValueIsUndefined(JSContextRef ctx, JSValueRef value)
69 {
70 ExecState* exec = toJS(ctx);
71 APIEntryShim entryShim(exec);
72
73 JSValue jsValue = toJS(exec, value);
74 return jsValue.isUndefined();
75 }
76
JSValueIsNull(JSContextRef ctx,JSValueRef value)77 bool JSValueIsNull(JSContextRef ctx, JSValueRef value)
78 {
79 ExecState* exec = toJS(ctx);
80 APIEntryShim entryShim(exec);
81
82 JSValue jsValue = toJS(exec, value);
83 return jsValue.isNull();
84 }
85
JSValueIsBoolean(JSContextRef ctx,JSValueRef value)86 bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value)
87 {
88 ExecState* exec = toJS(ctx);
89 APIEntryShim entryShim(exec);
90
91 JSValue jsValue = toJS(exec, value);
92 return jsValue.isBoolean();
93 }
94
JSValueIsNumber(JSContextRef ctx,JSValueRef value)95 bool JSValueIsNumber(JSContextRef ctx, JSValueRef value)
96 {
97 ExecState* exec = toJS(ctx);
98 APIEntryShim entryShim(exec);
99
100 JSValue jsValue = toJS(exec, value);
101 return jsValue.isNumber();
102 }
103
JSValueIsString(JSContextRef ctx,JSValueRef value)104 bool JSValueIsString(JSContextRef ctx, JSValueRef value)
105 {
106 ExecState* exec = toJS(ctx);
107 APIEntryShim entryShim(exec);
108
109 JSValue jsValue = toJS(exec, value);
110 return jsValue.isString();
111 }
112
JSValueIsObject(JSContextRef ctx,JSValueRef value)113 bool JSValueIsObject(JSContextRef ctx, JSValueRef value)
114 {
115 ExecState* exec = toJS(ctx);
116 APIEntryShim entryShim(exec);
117
118 JSValue jsValue = toJS(exec, value);
119 return jsValue.isObject();
120 }
121
JSValueIsObjectOfClass(JSContextRef ctx,JSValueRef value,JSClassRef jsClass)122 bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass)
123 {
124 ExecState* exec = toJS(ctx);
125 APIEntryShim entryShim(exec);
126
127 JSValue jsValue = toJS(exec, value);
128
129 if (JSObject* o = jsValue.getObject()) {
130 if (o->inherits(&JSCallbackObject<JSGlobalObject>::info))
131 return static_cast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass);
132 else if (o->inherits(&JSCallbackObject<JSObject>::info))
133 return static_cast<JSCallbackObject<JSObject>*>(o)->inherits(jsClass);
134 }
135 return false;
136 }
137
JSValueIsEqual(JSContextRef ctx,JSValueRef a,JSValueRef b,JSValueRef * exception)138 bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* exception)
139 {
140 ExecState* exec = toJS(ctx);
141 APIEntryShim entryShim(exec);
142
143 JSValue jsA = toJS(exec, a);
144 JSValue jsB = toJS(exec, b);
145
146 bool result = JSValue::equal(exec, jsA, jsB); // false if an exception is thrown
147 if (exec->hadException()) {
148 if (exception)
149 *exception = toRef(exec, exec->exception());
150 exec->clearException();
151 }
152 return result;
153 }
154
JSValueIsStrictEqual(JSContextRef ctx,JSValueRef a,JSValueRef b)155 bool JSValueIsStrictEqual(JSContextRef ctx, JSValueRef a, JSValueRef b)
156 {
157 ExecState* exec = toJS(ctx);
158 APIEntryShim entryShim(exec);
159
160 JSValue jsA = toJS(exec, a);
161 JSValue jsB = toJS(exec, b);
162
163 return JSValue::strictEqual(exec, jsA, jsB);
164 }
165
JSValueIsInstanceOfConstructor(JSContextRef ctx,JSValueRef value,JSObjectRef constructor,JSValueRef * exception)166 bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObjectRef constructor, JSValueRef* exception)
167 {
168 ExecState* exec = toJS(ctx);
169 APIEntryShim entryShim(exec);
170
171 JSValue jsValue = toJS(exec, value);
172
173 JSObject* jsConstructor = toJS(constructor);
174 if (!jsConstructor->structure()->typeInfo().implementsHasInstance())
175 return false;
176 bool result = jsConstructor->hasInstance(exec, jsValue, jsConstructor->get(exec, exec->propertyNames().prototype)); // false if an exception is thrown
177 if (exec->hadException()) {
178 if (exception)
179 *exception = toRef(exec, exec->exception());
180 exec->clearException();
181 }
182 return result;
183 }
184
JSValueMakeUndefined(JSContextRef ctx)185 JSValueRef JSValueMakeUndefined(JSContextRef ctx)
186 {
187 ExecState* exec = toJS(ctx);
188 APIEntryShim entryShim(exec);
189
190 return toRef(exec, jsUndefined());
191 }
192
JSValueMakeNull(JSContextRef ctx)193 JSValueRef JSValueMakeNull(JSContextRef ctx)
194 {
195 ExecState* exec = toJS(ctx);
196 APIEntryShim entryShim(exec);
197
198 return toRef(exec, jsNull());
199 }
200
JSValueMakeBoolean(JSContextRef ctx,bool value)201 JSValueRef JSValueMakeBoolean(JSContextRef ctx, bool value)
202 {
203 ExecState* exec = toJS(ctx);
204 APIEntryShim entryShim(exec);
205
206 return toRef(exec, jsBoolean(value));
207 }
208
JSValueMakeNumber(JSContextRef ctx,double value)209 JSValueRef JSValueMakeNumber(JSContextRef ctx, double value)
210 {
211 ExecState* exec = toJS(ctx);
212 APIEntryShim entryShim(exec);
213
214 // Our JSValue representation relies on a standard bit pattern for NaN. NaNs
215 // generated internally to JavaScriptCore naturally have that representation,
216 // but an external NaN might not.
217 if (isnan(value))
218 value = NaN;
219
220 return toRef(exec, jsNumber(exec, value));
221 }
222
JSValueMakeString(JSContextRef ctx,JSStringRef string)223 JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string)
224 {
225 ExecState* exec = toJS(ctx);
226 APIEntryShim entryShim(exec);
227
228 return toRef(exec, jsString(exec, string->ustring()));
229 }
230
JSValueToBoolean(JSContextRef ctx,JSValueRef value)231 bool JSValueToBoolean(JSContextRef ctx, JSValueRef value)
232 {
233 ExecState* exec = toJS(ctx);
234 APIEntryShim entryShim(exec);
235
236 JSValue jsValue = toJS(exec, value);
237 return jsValue.toBoolean(exec);
238 }
239
JSValueToNumber(JSContextRef ctx,JSValueRef value,JSValueRef * exception)240 double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
241 {
242 ExecState* exec = toJS(ctx);
243 APIEntryShim entryShim(exec);
244
245 JSValue jsValue = toJS(exec, value);
246
247 double number = jsValue.toNumber(exec);
248 if (exec->hadException()) {
249 if (exception)
250 *exception = toRef(exec, exec->exception());
251 exec->clearException();
252 number = NaN;
253 }
254 return number;
255 }
256
JSValueToStringCopy(JSContextRef ctx,JSValueRef value,JSValueRef * exception)257 JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
258 {
259 ExecState* exec = toJS(ctx);
260 APIEntryShim entryShim(exec);
261
262 JSValue jsValue = toJS(exec, value);
263
264 RefPtr<OpaqueJSString> stringRef(OpaqueJSString::create(jsValue.toString(exec)));
265 if (exec->hadException()) {
266 if (exception)
267 *exception = toRef(exec, exec->exception());
268 exec->clearException();
269 stringRef.clear();
270 }
271 return stringRef.release().releaseRef();
272 }
273
JSValueToObject(JSContextRef ctx,JSValueRef value,JSValueRef * exception)274 JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
275 {
276 ExecState* exec = toJS(ctx);
277 APIEntryShim entryShim(exec);
278
279 JSValue jsValue = toJS(exec, value);
280
281 JSObjectRef objectRef = toRef(jsValue.toObject(exec));
282 if (exec->hadException()) {
283 if (exception)
284 *exception = toRef(exec, exec->exception());
285 exec->clearException();
286 objectRef = 0;
287 }
288 return objectRef;
289 }
290
JSValueProtect(JSContextRef ctx,JSValueRef value)291 void JSValueProtect(JSContextRef ctx, JSValueRef value)
292 {
293 ExecState* exec = toJS(ctx);
294 APIEntryShim entryShim(exec);
295
296 JSValue jsValue = toJSForGC(exec, value);
297 gcProtect(jsValue);
298 }
299
JSValueUnprotect(JSContextRef ctx,JSValueRef value)300 void JSValueUnprotect(JSContextRef ctx, JSValueRef value)
301 {
302 ExecState* exec = toJS(ctx);
303 APIEntryShim entryShim(exec);
304
305 JSValue jsValue = toJSForGC(exec, value);
306 gcUnprotect(jsValue);
307 }
308