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