2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "JSValueRef.h"
30 #include "DateInstance.h"
31 #include "Exception.h"
32 #include "JSAPIWrapperObject.h"
33 #include "JSCInlines.h"
34 #include "JSCJSValue.h"
35 #include "JSCallbackObject.h"
36 #include "JSGlobalObject.h"
37 #include "JSONObject.h"
39 #include "LiteralParser.h"
42 #include <wtf/Assertions.h>
43 #include <wtf/text/StringHash.h>
44 #include <wtf/text/WTFString.h>
47 #include <mach-o/dyld.h>
50 #if ENABLE(REMOTE_INSPECTOR)
51 #include "JSGlobalObjectInspectorController.h"
56 enum class ExceptionStatus
{
61 static ExceptionStatus
handleExceptionIfNeeded(ExecState
* exec
, JSValueRef
* returnedExceptionRef
)
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
);
71 return ExceptionStatus::DidThrow
;
73 return ExceptionStatus::DidNotThrow
;
77 static bool evernoteHackNeeded()
79 static const int32_t webkitLastVersionWithEvernoteHack
= 35133959;
80 static bool hackNeeded
= CFEqual(CFBundleGetIdentifier(CFBundleGetMainBundle()), CFSTR("com.evernote.Evernote"))
81 && NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitLastVersionWithEvernoteHack
;
87 ::JSType
JSValueGetType(JSContextRef ctx
, JSValueRef value
)
91 return kJSTypeUndefined
;
93 ExecState
* exec
= toJS(ctx
);
94 JSLockHolder
locker(exec
);
96 JSValue jsValue
= toJS(exec
, value
);
98 if (jsValue
.isUndefined())
99 return kJSTypeUndefined
;
100 if (jsValue
.isNull())
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
;
112 bool JSValueIsUndefined(JSContextRef ctx
, JSValueRef value
)
115 ASSERT_NOT_REACHED();
118 ExecState
* exec
= toJS(ctx
);
119 JSLockHolder
locker(exec
);
121 return toJS(exec
, value
).isUndefined();
124 bool JSValueIsNull(JSContextRef ctx
, JSValueRef value
)
127 ASSERT_NOT_REACHED();
130 ExecState
* exec
= toJS(ctx
);
131 JSLockHolder
locker(exec
);
133 return toJS(exec
, value
).isNull();
136 bool JSValueIsBoolean(JSContextRef ctx
, JSValueRef value
)
139 ASSERT_NOT_REACHED();
142 ExecState
* exec
= toJS(ctx
);
143 JSLockHolder
locker(exec
);
145 return toJS(exec
, value
).isBoolean();
148 bool JSValueIsNumber(JSContextRef ctx
, JSValueRef value
)
151 ASSERT_NOT_REACHED();
154 ExecState
* exec
= toJS(ctx
);
155 JSLockHolder
locker(exec
);
157 return toJS(exec
, value
).isNumber();
160 bool JSValueIsString(JSContextRef ctx
, JSValueRef value
)
163 ASSERT_NOT_REACHED();
166 ExecState
* exec
= toJS(ctx
);
167 JSLockHolder
locker(exec
);
169 return toJS(exec
, value
).isString();
172 bool JSValueIsObject(JSContextRef ctx
, JSValueRef value
)
175 ASSERT_NOT_REACHED();
178 ExecState
* exec
= toJS(ctx
);
179 JSLockHolder
locker(exec
);
181 return toJS(exec
, value
).isObject();
184 bool JSValueIsArray(JSContextRef ctx
, JSValueRef value
)
187 ASSERT_NOT_REACHED();
190 ExecState
* exec
= toJS(ctx
);
191 JSLockHolder
locker(exec
);
193 return toJS(exec
, value
).inherits(JSArray::info());
196 bool JSValueIsDate(JSContextRef ctx
, JSValueRef value
)
199 ASSERT_NOT_REACHED();
202 ExecState
* exec
= toJS(ctx
);
203 JSLockHolder
locker(exec
);
205 return toJS(exec
, value
).inherits(DateInstance::info());
208 bool JSValueIsObjectOfClass(JSContextRef ctx
, JSValueRef value
, JSClassRef jsClass
)
210 if (!ctx
|| !jsClass
) {
211 ASSERT_NOT_REACHED();
214 ExecState
* exec
= toJS(ctx
);
215 JSLockHolder
locker(exec
);
217 JSValue jsValue
= toJS(exec
, value
);
219 if (JSObject
* o
= jsValue
.getObject()) {
220 if (o
->inherits(JSProxy::info()))
221 o
= jsCast
<JSProxy
*>(o
)->target();
223 if (o
->inherits(JSCallbackObject
<JSGlobalObject
>::info()))
224 return jsCast
<JSCallbackObject
<JSGlobalObject
>*>(o
)->inherits(jsClass
);
225 if (o
->inherits(JSCallbackObject
<JSDestructibleObject
>::info()))
226 return jsCast
<JSCallbackObject
<JSDestructibleObject
>*>(o
)->inherits(jsClass
);
227 #if JSC_OBJC_API_ENABLED
228 if (o
->inherits(JSCallbackObject
<JSAPIWrapperObject
>::info()))
229 return jsCast
<JSCallbackObject
<JSAPIWrapperObject
>*>(o
)->inherits(jsClass
);
235 bool JSValueIsEqual(JSContextRef ctx
, JSValueRef a
, JSValueRef b
, JSValueRef
* exception
)
238 ASSERT_NOT_REACHED();
241 ExecState
* exec
= toJS(ctx
);
242 JSLockHolder
locker(exec
);
244 JSValue jsA
= toJS(exec
, a
);
245 JSValue jsB
= toJS(exec
, b
);
247 bool result
= JSValue::equal(exec
, jsA
, jsB
); // false if an exception is thrown
248 handleExceptionIfNeeded(exec
, exception
);
253 bool JSValueIsStrictEqual(JSContextRef ctx
, JSValueRef a
, JSValueRef b
)
256 ASSERT_NOT_REACHED();
259 ExecState
* exec
= toJS(ctx
);
260 JSLockHolder
locker(exec
);
262 JSValue jsA
= toJS(exec
, a
);
263 JSValue jsB
= toJS(exec
, b
);
265 return JSValue::strictEqual(exec
, jsA
, jsB
);
268 bool JSValueIsInstanceOfConstructor(JSContextRef ctx
, JSValueRef value
, JSObjectRef constructor
, JSValueRef
* exception
)
271 ASSERT_NOT_REACHED();
274 ExecState
* exec
= toJS(ctx
);
275 JSLockHolder
locker(exec
);
277 JSValue jsValue
= toJS(exec
, value
);
279 JSObject
* jsConstructor
= toJS(constructor
);
280 if (!jsConstructor
->structure()->typeInfo().implementsHasInstance())
282 bool result
= jsConstructor
->hasInstance(exec
, jsValue
); // false if an exception is thrown
283 handleExceptionIfNeeded(exec
, exception
);
287 JSValueRef
JSValueMakeUndefined(JSContextRef ctx
)
290 ASSERT_NOT_REACHED();
293 ExecState
* exec
= toJS(ctx
);
294 JSLockHolder
locker(exec
);
296 return toRef(exec
, jsUndefined());
299 JSValueRef
JSValueMakeNull(JSContextRef ctx
)
302 ASSERT_NOT_REACHED();
305 ExecState
* exec
= toJS(ctx
);
306 JSLockHolder
locker(exec
);
308 return toRef(exec
, jsNull());
311 JSValueRef
JSValueMakeBoolean(JSContextRef ctx
, bool value
)
314 ASSERT_NOT_REACHED();
317 ExecState
* exec
= toJS(ctx
);
318 JSLockHolder
locker(exec
);
320 return toRef(exec
, jsBoolean(value
));
323 JSValueRef
JSValueMakeNumber(JSContextRef ctx
, double value
)
326 ASSERT_NOT_REACHED();
329 ExecState
* exec
= toJS(ctx
);
330 JSLockHolder
locker(exec
);
332 return toRef(exec
, jsNumber(purifyNaN(value
)));
335 JSValueRef
JSValueMakeString(JSContextRef ctx
, JSStringRef string
)
338 ASSERT_NOT_REACHED();
341 ExecState
* exec
= toJS(ctx
);
342 JSLockHolder
locker(exec
);
344 return toRef(exec
, jsString(exec
, string
? string
->string() : String()));
347 JSValueRef
JSValueMakeFromJSONString(JSContextRef ctx
, JSStringRef string
)
350 ASSERT_NOT_REACHED();
353 ExecState
* exec
= toJS(ctx
);
354 JSLockHolder
locker(exec
);
355 String str
= string
->string();
356 unsigned length
= str
.length();
357 if (!length
|| str
.is8Bit()) {
358 LiteralParser
<LChar
> parser(exec
, str
.characters8(), length
, StrictJSON
);
359 return toRef(exec
, parser
.tryLiteralParse());
361 LiteralParser
<UChar
> parser(exec
, str
.characters16(), length
, StrictJSON
);
362 return toRef(exec
, parser
.tryLiteralParse());
365 JSStringRef
JSValueCreateJSONString(JSContextRef ctx
, JSValueRef apiValue
, unsigned indent
, JSValueRef
* exception
)
368 ASSERT_NOT_REACHED();
371 ExecState
* exec
= toJS(ctx
);
372 JSLockHolder
locker(exec
);
373 JSValue value
= toJS(exec
, apiValue
);
374 String result
= JSONStringify(exec
, value
, indent
);
377 if (handleExceptionIfNeeded(exec
, exception
) == ExceptionStatus::DidThrow
)
379 return OpaqueJSString::create(result
).leakRef();
382 bool JSValueToBoolean(JSContextRef ctx
, JSValueRef value
)
385 ASSERT_NOT_REACHED();
388 ExecState
* exec
= toJS(ctx
);
389 JSLockHolder
locker(exec
);
391 JSValue jsValue
= toJS(exec
, value
);
392 return jsValue
.toBoolean(exec
);
395 double JSValueToNumber(JSContextRef ctx
, JSValueRef value
, JSValueRef
* exception
)
398 ASSERT_NOT_REACHED();
401 ExecState
* exec
= toJS(ctx
);
402 JSLockHolder
locker(exec
);
404 JSValue jsValue
= toJS(exec
, value
);
406 double number
= jsValue
.toNumber(exec
);
407 if (handleExceptionIfNeeded(exec
, exception
) == ExceptionStatus::DidThrow
)
412 JSStringRef
JSValueToStringCopy(JSContextRef ctx
, JSValueRef value
, JSValueRef
* exception
)
415 ASSERT_NOT_REACHED();
418 ExecState
* exec
= toJS(ctx
);
419 JSLockHolder
locker(exec
);
421 JSValue jsValue
= toJS(exec
, value
);
423 RefPtr
<OpaqueJSString
> stringRef(OpaqueJSString::create(jsValue
.toString(exec
)->value(exec
)));
424 if (handleExceptionIfNeeded(exec
, exception
) == ExceptionStatus::DidThrow
)
426 return stringRef
.release().leakRef();
429 JSObjectRef
JSValueToObject(JSContextRef ctx
, JSValueRef value
, JSValueRef
* exception
)
432 ASSERT_NOT_REACHED();
435 ExecState
* exec
= toJS(ctx
);
436 JSLockHolder
locker(exec
);
438 JSValue jsValue
= toJS(exec
, value
);
440 JSObjectRef objectRef
= toRef(jsValue
.toObject(exec
));
441 if (handleExceptionIfNeeded(exec
, exception
) == ExceptionStatus::DidThrow
)
446 void JSValueProtect(JSContextRef ctx
, JSValueRef value
)
449 ASSERT_NOT_REACHED();
452 ExecState
* exec
= toJS(ctx
);
453 JSLockHolder
locker(exec
);
455 JSValue jsValue
= toJSForGC(exec
, value
);
459 void JSValueUnprotect(JSContextRef ctx
, JSValueRef value
)
462 if ((!value
|| !ctx
) && evernoteHackNeeded())
466 ExecState
* exec
= toJS(ctx
);
467 JSLockHolder
locker(exec
);
469 JSValue jsValue
= toJSForGC(exec
, value
);
470 gcUnprotect(jsValue
);