]> git.saurik.com Git - apple/javascriptcore.git/blob - API/JSValueRef.cpp
JavaScriptCore-1218.33.tar.gz
[apple/javascriptcore.git] / API / JSValueRef.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 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 "APICast.h"
30 #include "APIShims.h"
31 #include "JSAPIWrapperObject.h"
32 #include "JSCallbackObject.h"
33
34 #include <runtime/JSCJSValue.h>
35 #include <runtime/JSGlobalObject.h>
36 #include <runtime/JSONObject.h>
37 #include <runtime/JSString.h>
38 #include <runtime/LiteralParser.h>
39 #include <runtime/Operations.h>
40 #include <runtime/Protect.h>
41
42 #include <wtf/Assertions.h>
43 #include <wtf/text/StringHash.h>
44 #include <wtf/text/WTFString.h>
45
46 #include <algorithm> // for std::min
47
48 #if PLATFORM(MAC)
49 #include <mach-o/dyld.h>
50 #endif
51
52 using namespace JSC;
53
54 #if PLATFORM(MAC)
55 static bool evernoteHackNeeded()
56 {
57 static const int32_t webkitLastVersionWithEvernoteHack = 35133959;
58 static bool hackNeeded = CFEqual(CFBundleGetIdentifier(CFBundleGetMainBundle()), CFSTR("com.evernote.Evernote"))
59 && NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitLastVersionWithEvernoteHack;
60
61 return hackNeeded;
62 }
63 #endif
64
65 ::JSType JSValueGetType(JSContextRef ctx, JSValueRef value)
66 {
67 if (!ctx) {
68 ASSERT_NOT_REACHED();
69 return kJSTypeUndefined;
70 }
71 ExecState* exec = toJS(ctx);
72 APIEntryShim entryShim(exec);
73
74 JSValue jsValue = toJS(exec, value);
75
76 if (jsValue.isUndefined())
77 return kJSTypeUndefined;
78 if (jsValue.isNull())
79 return kJSTypeNull;
80 if (jsValue.isBoolean())
81 return kJSTypeBoolean;
82 if (jsValue.isNumber())
83 return kJSTypeNumber;
84 if (jsValue.isString())
85 return kJSTypeString;
86 ASSERT(jsValue.isObject());
87 return kJSTypeObject;
88 }
89
90 bool JSValueIsUndefined(JSContextRef ctx, JSValueRef value)
91 {
92 if (!ctx) {
93 ASSERT_NOT_REACHED();
94 return false;
95 }
96 ExecState* exec = toJS(ctx);
97 APIEntryShim entryShim(exec);
98
99 JSValue jsValue = toJS(exec, value);
100 return jsValue.isUndefined();
101 }
102
103 bool JSValueIsNull(JSContextRef ctx, JSValueRef value)
104 {
105 if (!ctx) {
106 ASSERT_NOT_REACHED();
107 return false;
108 }
109 ExecState* exec = toJS(ctx);
110 APIEntryShim entryShim(exec);
111
112 JSValue jsValue = toJS(exec, value);
113 return jsValue.isNull();
114 }
115
116 bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value)
117 {
118 if (!ctx) {
119 ASSERT_NOT_REACHED();
120 return false;
121 }
122 ExecState* exec = toJS(ctx);
123 APIEntryShim entryShim(exec);
124
125 JSValue jsValue = toJS(exec, value);
126 return jsValue.isBoolean();
127 }
128
129 bool JSValueIsNumber(JSContextRef ctx, JSValueRef value)
130 {
131 if (!ctx) {
132 ASSERT_NOT_REACHED();
133 return false;
134 }
135 ExecState* exec = toJS(ctx);
136 APIEntryShim entryShim(exec);
137
138 JSValue jsValue = toJS(exec, value);
139 return jsValue.isNumber();
140 }
141
142 bool JSValueIsString(JSContextRef ctx, JSValueRef value)
143 {
144 if (!ctx) {
145 ASSERT_NOT_REACHED();
146 return false;
147 }
148 ExecState* exec = toJS(ctx);
149 APIEntryShim entryShim(exec);
150
151 JSValue jsValue = toJS(exec, value);
152 return jsValue.isString();
153 }
154
155 bool JSValueIsObject(JSContextRef ctx, JSValueRef value)
156 {
157 if (!ctx) {
158 ASSERT_NOT_REACHED();
159 return false;
160 }
161 ExecState* exec = toJS(ctx);
162 APIEntryShim entryShim(exec);
163
164 JSValue jsValue = toJS(exec, value);
165 return jsValue.isObject();
166 }
167
168 bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass)
169 {
170 if (!ctx || !jsClass) {
171 ASSERT_NOT_REACHED();
172 return false;
173 }
174 ExecState* exec = toJS(ctx);
175 APIEntryShim entryShim(exec);
176
177 JSValue jsValue = toJS(exec, value);
178
179 if (JSObject* o = jsValue.getObject()) {
180 if (o->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
181 return jsCast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass);
182 if (o->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
183 return jsCast<JSCallbackObject<JSDestructibleObject>*>(o)->inherits(jsClass);
184 #if JSC_OBJC_API_ENABLED
185 if (o->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info))
186 return jsCast<JSCallbackObject<JSAPIWrapperObject>*>(o)->inherits(jsClass);
187 #endif
188 }
189 return false;
190 }
191
192 bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* exception)
193 {
194 if (!ctx) {
195 ASSERT_NOT_REACHED();
196 return false;
197 }
198 ExecState* exec = toJS(ctx);
199 APIEntryShim entryShim(exec);
200
201 JSValue jsA = toJS(exec, a);
202 JSValue jsB = toJS(exec, b);
203
204 bool result = JSValue::equal(exec, jsA, jsB); // false if an exception is thrown
205 if (exec->hadException()) {
206 if (exception)
207 *exception = toRef(exec, exec->exception());
208 exec->clearException();
209 }
210 return result;
211 }
212
213 bool JSValueIsStrictEqual(JSContextRef ctx, JSValueRef a, JSValueRef b)
214 {
215 if (!ctx) {
216 ASSERT_NOT_REACHED();
217 return false;
218 }
219 ExecState* exec = toJS(ctx);
220 APIEntryShim entryShim(exec);
221
222 JSValue jsA = toJS(exec, a);
223 JSValue jsB = toJS(exec, b);
224
225 return JSValue::strictEqual(exec, jsA, jsB);
226 }
227
228 bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObjectRef constructor, JSValueRef* exception)
229 {
230 if (!ctx) {
231 ASSERT_NOT_REACHED();
232 return false;
233 }
234 ExecState* exec = toJS(ctx);
235 APIEntryShim entryShim(exec);
236
237 JSValue jsValue = toJS(exec, value);
238
239 JSObject* jsConstructor = toJS(constructor);
240 if (!jsConstructor->structure()->typeInfo().implementsHasInstance())
241 return false;
242 bool result = jsConstructor->hasInstance(exec, jsValue); // false if an exception is thrown
243 if (exec->hadException()) {
244 if (exception)
245 *exception = toRef(exec, exec->exception());
246 exec->clearException();
247 }
248 return result;
249 }
250
251 JSValueRef JSValueMakeUndefined(JSContextRef ctx)
252 {
253 if (!ctx) {
254 ASSERT_NOT_REACHED();
255 return 0;
256 }
257 ExecState* exec = toJS(ctx);
258 APIEntryShim entryShim(exec);
259
260 return toRef(exec, jsUndefined());
261 }
262
263 JSValueRef JSValueMakeNull(JSContextRef ctx)
264 {
265 if (!ctx) {
266 ASSERT_NOT_REACHED();
267 return 0;
268 }
269 ExecState* exec = toJS(ctx);
270 APIEntryShim entryShim(exec);
271
272 return toRef(exec, jsNull());
273 }
274
275 JSValueRef JSValueMakeBoolean(JSContextRef ctx, bool value)
276 {
277 if (!ctx) {
278 ASSERT_NOT_REACHED();
279 return 0;
280 }
281 ExecState* exec = toJS(ctx);
282 APIEntryShim entryShim(exec);
283
284 return toRef(exec, jsBoolean(value));
285 }
286
287 JSValueRef JSValueMakeNumber(JSContextRef ctx, double value)
288 {
289 if (!ctx) {
290 ASSERT_NOT_REACHED();
291 return 0;
292 }
293 ExecState* exec = toJS(ctx);
294 APIEntryShim entryShim(exec);
295
296 // Our JSValue representation relies on a standard bit pattern for NaN. NaNs
297 // generated internally to JavaScriptCore naturally have that representation,
298 // but an external NaN might not.
299 if (std::isnan(value))
300 value = QNaN;
301
302 return toRef(exec, jsNumber(value));
303 }
304
305 JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string)
306 {
307 if (!ctx) {
308 ASSERT_NOT_REACHED();
309 return 0;
310 }
311 ExecState* exec = toJS(ctx);
312 APIEntryShim entryShim(exec);
313
314 return toRef(exec, jsString(exec, string->string()));
315 }
316
317 JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string)
318 {
319 if (!ctx) {
320 ASSERT_NOT_REACHED();
321 return 0;
322 }
323 ExecState* exec = toJS(ctx);
324 APIEntryShim entryShim(exec);
325 String str = string->string();
326 unsigned length = str.length();
327 if (length && str.is8Bit()) {
328 LiteralParser<LChar> parser(exec, str.characters8(), length, StrictJSON);
329 return toRef(exec, parser.tryLiteralParse());
330 }
331 LiteralParser<UChar> parser(exec, str.characters(), length, StrictJSON);
332 return toRef(exec, parser.tryLiteralParse());
333 }
334
335 JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef apiValue, unsigned indent, JSValueRef* exception)
336 {
337 if (!ctx) {
338 ASSERT_NOT_REACHED();
339 return 0;
340 }
341 ExecState* exec = toJS(ctx);
342 APIEntryShim entryShim(exec);
343 JSValue value = toJS(exec, apiValue);
344 String result = JSONStringify(exec, value, indent);
345 if (exception)
346 *exception = 0;
347 if (exec->hadException()) {
348 if (exception)
349 *exception = toRef(exec, exec->exception());
350 exec->clearException();
351 return 0;
352 }
353 return OpaqueJSString::create(result).leakRef();
354 }
355
356 bool JSValueToBoolean(JSContextRef ctx, JSValueRef value)
357 {
358 if (!ctx) {
359 ASSERT_NOT_REACHED();
360 return false;
361 }
362 ExecState* exec = toJS(ctx);
363 APIEntryShim entryShim(exec);
364
365 JSValue jsValue = toJS(exec, value);
366 return jsValue.toBoolean(exec);
367 }
368
369 double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
370 {
371 if (!ctx) {
372 ASSERT_NOT_REACHED();
373 return QNaN;
374 }
375 ExecState* exec = toJS(ctx);
376 APIEntryShim entryShim(exec);
377
378 JSValue jsValue = toJS(exec, value);
379
380 double number = jsValue.toNumber(exec);
381 if (exec->hadException()) {
382 if (exception)
383 *exception = toRef(exec, exec->exception());
384 exec->clearException();
385 number = QNaN;
386 }
387 return number;
388 }
389
390 JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
391 {
392 if (!ctx) {
393 ASSERT_NOT_REACHED();
394 return 0;
395 }
396 ExecState* exec = toJS(ctx);
397 APIEntryShim entryShim(exec);
398
399 JSValue jsValue = toJS(exec, value);
400
401 RefPtr<OpaqueJSString> stringRef(OpaqueJSString::create(jsValue.toString(exec)->value(exec)));
402 if (exec->hadException()) {
403 if (exception)
404 *exception = toRef(exec, exec->exception());
405 exec->clearException();
406 stringRef.clear();
407 }
408 return stringRef.release().leakRef();
409 }
410
411 JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
412 {
413 if (!ctx) {
414 ASSERT_NOT_REACHED();
415 return 0;
416 }
417 ExecState* exec = toJS(ctx);
418 APIEntryShim entryShim(exec);
419
420 JSValue jsValue = toJS(exec, value);
421
422 JSObjectRef objectRef = toRef(jsValue.toObject(exec));
423 if (exec->hadException()) {
424 if (exception)
425 *exception = toRef(exec, exec->exception());
426 exec->clearException();
427 objectRef = 0;
428 }
429 return objectRef;
430 }
431
432 void JSValueProtect(JSContextRef ctx, JSValueRef value)
433 {
434 if (!ctx) {
435 ASSERT_NOT_REACHED();
436 return;
437 }
438 ExecState* exec = toJS(ctx);
439 APIEntryShim entryShim(exec);
440
441 JSValue jsValue = toJSForGC(exec, value);
442 gcProtect(jsValue);
443 }
444
445 void JSValueUnprotect(JSContextRef ctx, JSValueRef value)
446 {
447 #if PLATFORM(MAC)
448 if ((!value || !ctx) && evernoteHackNeeded())
449 return;
450 #endif
451
452 ExecState* exec = toJS(ctx);
453 APIEntryShim entryShim(exec);
454
455 JSValue jsValue = toJSForGC(exec, value);
456 gcUnprotect(jsValue);
457 }