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 "JSAPIWrapperObject.h"
31 #include "JSCJSValue.h"
32 #include "JSCallbackObject.h"
33 #include "JSGlobalObject.h"
34 #include "JSONObject.h"
36 #include "LiteralParser.h"
37 #include "JSCInlines.h"
40 #include <wtf/Assertions.h>
41 #include <wtf/text/StringHash.h>
42 #include <wtf/text/WTFString.h>
44 #include <algorithm> // for std::min
47 #include <mach-o/dyld.h>
50 #if ENABLE(REMOTE_INSPECTOR)
51 #include "JSGlobalObjectInspectorController.h"
57 static bool evernoteHackNeeded()
59 static const int32_t webkitLastVersionWithEvernoteHack
= 35133959;
60 static bool hackNeeded
= CFEqual(CFBundleGetIdentifier(CFBundleGetMainBundle()), CFSTR("com.evernote.Evernote"))
61 && NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitLastVersionWithEvernoteHack
;
67 ::JSType
JSValueGetType(JSContextRef ctx
, JSValueRef value
)
71 return kJSTypeUndefined
;
73 ExecState
* exec
= toJS(ctx
);
74 JSLockHolder
locker(exec
);
76 JSValue jsValue
= toJS(exec
, value
);
78 if (jsValue
.isUndefined())
79 return kJSTypeUndefined
;
82 if (jsValue
.isBoolean())
83 return kJSTypeBoolean
;
84 if (jsValue
.isNumber())
86 if (jsValue
.isString())
88 ASSERT(jsValue
.isObject());
92 bool JSValueIsUndefined(JSContextRef ctx
, JSValueRef value
)
98 ExecState
* exec
= toJS(ctx
);
99 JSLockHolder
locker(exec
);
101 JSValue jsValue
= toJS(exec
, value
);
102 return jsValue
.isUndefined();
105 bool JSValueIsNull(JSContextRef ctx
, JSValueRef value
)
108 ASSERT_NOT_REACHED();
111 ExecState
* exec
= toJS(ctx
);
112 JSLockHolder
locker(exec
);
114 JSValue jsValue
= toJS(exec
, value
);
115 return jsValue
.isNull();
118 bool JSValueIsBoolean(JSContextRef ctx
, JSValueRef value
)
121 ASSERT_NOT_REACHED();
124 ExecState
* exec
= toJS(ctx
);
125 JSLockHolder
locker(exec
);
127 JSValue jsValue
= toJS(exec
, value
);
128 return jsValue
.isBoolean();
131 bool JSValueIsNumber(JSContextRef ctx
, JSValueRef value
)
134 ASSERT_NOT_REACHED();
137 ExecState
* exec
= toJS(ctx
);
138 JSLockHolder
locker(exec
);
140 JSValue jsValue
= toJS(exec
, value
);
141 return jsValue
.isNumber();
144 bool JSValueIsString(JSContextRef ctx
, JSValueRef value
)
147 ASSERT_NOT_REACHED();
150 ExecState
* exec
= toJS(ctx
);
151 JSLockHolder
locker(exec
);
153 JSValue jsValue
= toJS(exec
, value
);
154 return jsValue
.isString();
157 bool JSValueIsObject(JSContextRef ctx
, JSValueRef value
)
160 ASSERT_NOT_REACHED();
163 ExecState
* exec
= toJS(ctx
);
164 JSLockHolder
locker(exec
);
166 JSValue jsValue
= toJS(exec
, value
);
167 return jsValue
.isObject();
170 bool JSValueIsObjectOfClass(JSContextRef ctx
, JSValueRef value
, JSClassRef jsClass
)
172 if (!ctx
|| !jsClass
) {
173 ASSERT_NOT_REACHED();
176 ExecState
* exec
= toJS(ctx
);
177 JSLockHolder
locker(exec
);
179 JSValue jsValue
= toJS(exec
, value
);
181 if (JSObject
* o
= jsValue
.getObject()) {
182 if (o
->inherits(JSProxy::info()))
183 o
= jsCast
<JSProxy
*>(o
)->target();
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
);
197 bool JSValueIsEqual(JSContextRef ctx
, JSValueRef a
, JSValueRef b
, JSValueRef
* exception
)
200 ASSERT_NOT_REACHED();
203 ExecState
* exec
= toJS(ctx
);
204 JSLockHolder
locker(exec
);
206 JSValue jsA
= toJS(exec
, a
);
207 JSValue jsB
= toJS(exec
, b
);
209 bool result
= JSValue::equal(exec
, jsA
, jsB
); // false if an exception is thrown
210 if (exec
->hadException()) {
211 JSValue exceptionValue
= exec
->exception();
213 *exception
= toRef(exec
, exceptionValue
);
214 exec
->clearException();
215 #if ENABLE(REMOTE_INSPECTOR)
216 exec
->vmEntryGlobalObject()->inspectorController().reportAPIException(exec
, exceptionValue
);
222 bool JSValueIsStrictEqual(JSContextRef ctx
, JSValueRef a
, JSValueRef b
)
225 ASSERT_NOT_REACHED();
228 ExecState
* exec
= toJS(ctx
);
229 JSLockHolder
locker(exec
);
231 JSValue jsA
= toJS(exec
, a
);
232 JSValue jsB
= toJS(exec
, b
);
234 return JSValue::strictEqual(exec
, jsA
, jsB
);
237 bool JSValueIsInstanceOfConstructor(JSContextRef ctx
, JSValueRef value
, JSObjectRef constructor
, JSValueRef
* exception
)
240 ASSERT_NOT_REACHED();
243 ExecState
* exec
= toJS(ctx
);
244 JSLockHolder
locker(exec
);
246 JSValue jsValue
= toJS(exec
, value
);
248 JSObject
* jsConstructor
= toJS(constructor
);
249 if (!jsConstructor
->structure()->typeInfo().implementsHasInstance())
251 bool result
= jsConstructor
->hasInstance(exec
, jsValue
); // false if an exception is thrown
252 if (exec
->hadException()) {
253 JSValue exceptionValue
= exec
->exception();
255 *exception
= toRef(exec
, exceptionValue
);
256 exec
->clearException();
257 #if ENABLE(REMOTE_INSPECTOR)
258 exec
->vmEntryGlobalObject()->inspectorController().reportAPIException(exec
, exceptionValue
);
264 JSValueRef
JSValueMakeUndefined(JSContextRef ctx
)
267 ASSERT_NOT_REACHED();
270 ExecState
* exec
= toJS(ctx
);
271 JSLockHolder
locker(exec
);
273 return toRef(exec
, jsUndefined());
276 JSValueRef
JSValueMakeNull(JSContextRef ctx
)
279 ASSERT_NOT_REACHED();
282 ExecState
* exec
= toJS(ctx
);
283 JSLockHolder
locker(exec
);
285 return toRef(exec
, jsNull());
288 JSValueRef
JSValueMakeBoolean(JSContextRef ctx
, bool value
)
291 ASSERT_NOT_REACHED();
294 ExecState
* exec
= toJS(ctx
);
295 JSLockHolder
locker(exec
);
297 return toRef(exec
, jsBoolean(value
));
300 JSValueRef
JSValueMakeNumber(JSContextRef ctx
, double value
)
303 ASSERT_NOT_REACHED();
306 ExecState
* exec
= toJS(ctx
);
307 JSLockHolder
locker(exec
);
309 return toRef(exec
, jsNumber(purifyNaN(value
)));
312 JSValueRef
JSValueMakeString(JSContextRef ctx
, JSStringRef string
)
315 ASSERT_NOT_REACHED();
318 ExecState
* exec
= toJS(ctx
);
319 JSLockHolder
locker(exec
);
321 return toRef(exec
, jsString(exec
, string
->string()));
324 JSValueRef
JSValueMakeFromJSONString(JSContextRef ctx
, JSStringRef string
)
327 ASSERT_NOT_REACHED();
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());
338 LiteralParser
<UChar
> parser(exec
, str
.characters16(), length
, StrictJSON
);
339 return toRef(exec
, parser
.tryLiteralParse());
342 JSStringRef
JSValueCreateJSONString(JSContextRef ctx
, JSValueRef apiValue
, unsigned indent
, JSValueRef
* exception
)
345 ASSERT_NOT_REACHED();
348 ExecState
* exec
= toJS(ctx
);
349 JSLockHolder
locker(exec
);
350 JSValue value
= toJS(exec
, apiValue
);
351 String result
= JSONStringify(exec
, value
, indent
);
354 if (exec
->hadException()) {
355 JSValue exceptionValue
= exec
->exception();
357 *exception
= toRef(exec
, exceptionValue
);
358 exec
->clearException();
359 #if ENABLE(REMOTE_INSPECTOR)
360 exec
->vmEntryGlobalObject()->inspectorController().reportAPIException(exec
, exceptionValue
);
364 return OpaqueJSString::create(result
).leakRef();
367 bool JSValueToBoolean(JSContextRef ctx
, JSValueRef value
)
370 ASSERT_NOT_REACHED();
373 ExecState
* exec
= toJS(ctx
);
374 JSLockHolder
locker(exec
);
376 JSValue jsValue
= toJS(exec
, value
);
377 return jsValue
.toBoolean(exec
);
380 double JSValueToNumber(JSContextRef ctx
, JSValueRef value
, JSValueRef
* exception
)
383 ASSERT_NOT_REACHED();
386 ExecState
* exec
= toJS(ctx
);
387 JSLockHolder
locker(exec
);
389 JSValue jsValue
= toJS(exec
, value
);
391 double number
= jsValue
.toNumber(exec
);
392 if (exec
->hadException()) {
393 JSValue exceptionValue
= exec
->exception();
395 *exception
= toRef(exec
, exceptionValue
);
396 exec
->clearException();
397 #if ENABLE(REMOTE_INSPECTOR)
398 exec
->vmEntryGlobalObject()->inspectorController().reportAPIException(exec
, exceptionValue
);
405 JSStringRef
JSValueToStringCopy(JSContextRef ctx
, JSValueRef value
, JSValueRef
* exception
)
408 ASSERT_NOT_REACHED();
411 ExecState
* exec
= toJS(ctx
);
412 JSLockHolder
locker(exec
);
414 JSValue jsValue
= toJS(exec
, value
);
416 RefPtr
<OpaqueJSString
> stringRef(OpaqueJSString::create(jsValue
.toString(exec
)->value(exec
)));
417 if (exec
->hadException()) {
418 JSValue exceptionValue
= exec
->exception();
420 *exception
= toRef(exec
, exceptionValue
);
421 exec
->clearException();
422 #if ENABLE(REMOTE_INSPECTOR)
423 exec
->vmEntryGlobalObject()->inspectorController().reportAPIException(exec
, exceptionValue
);
427 return stringRef
.release().leakRef();
430 JSObjectRef
JSValueToObject(JSContextRef ctx
, JSValueRef value
, JSValueRef
* exception
)
433 ASSERT_NOT_REACHED();
436 ExecState
* exec
= toJS(ctx
);
437 JSLockHolder
locker(exec
);
439 JSValue jsValue
= toJS(exec
, value
);
441 JSObjectRef objectRef
= toRef(jsValue
.toObject(exec
));
442 if (exec
->hadException()) {
443 JSValue exceptionValue
= exec
->exception();
445 *exception
= toRef(exec
, exceptionValue
);
446 exec
->clearException();
447 #if ENABLE(REMOTE_INSPECTOR)
448 exec
->vmEntryGlobalObject()->inspectorController().reportAPIException(exec
, exceptionValue
);
455 void JSValueProtect(JSContextRef ctx
, JSValueRef value
)
458 ASSERT_NOT_REACHED();
461 ExecState
* exec
= toJS(ctx
);
462 JSLockHolder
locker(exec
);
464 JSValue jsValue
= toJSForGC(exec
, value
);
468 void JSValueUnprotect(JSContextRef ctx
, JSValueRef value
)
471 if ((!value
|| !ctx
) && evernoteHackNeeded())
475 ExecState
* exec
= toJS(ctx
);
476 JSLockHolder
locker(exec
);
478 JSValue jsValue
= toJSForGC(exec
, value
);
479 gcUnprotect(jsValue
);