]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - API/JSValueRef.cpp
JavaScriptCore-7600.1.4.11.8.tar.gz
[apple/javascriptcore.git] / API / JSValueRef.cpp
... / ...
CommitLineData
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
54using namespace JSC;
55
56#if PLATFORM(MAC)
57static 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
92bool 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
105bool 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
118bool 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
131bool 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
144bool 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
157bool 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
170bool 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
197bool 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
222bool 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
237bool 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
264JSValueRef 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
276JSValueRef 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
288JSValueRef 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
300JSValueRef 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
312JSValueRef 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
324JSValueRef 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
342JSStringRef 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
367bool 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
380double 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
405JSStringRef 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
430JSObjectRef 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
455void 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
468void 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}