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