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 COMPUTER, 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 COMPUTER, 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"
31 #include "JSAPIWrapperObject.h"
32 #include "JSCallbackObject.h"
34 #include <runtime/JSCJSValue.h>
35 #include <runtime/JSGlobalObject.h>
36 #include <runtime/JSONObject.h>
37 #include <runtime/JSString.h>
38 #include <runtime/LiteralParser.h>
39 #include <runtime/Operations.h>
40 #include <runtime/Protect.h>
42 #include <wtf/Assertions.h>
43 #include <wtf/text/StringHash.h>
44 #include <wtf/text/WTFString.h>
46 #include <algorithm> // for std::min
49 #include <mach-o/dyld.h>
55 static bool evernoteHackNeeded()
57 static const int32_t webkitLastVersionWithEvernoteHack
= 35133959;
58 static bool hackNeeded
= CFEqual(CFBundleGetIdentifier(CFBundleGetMainBundle()), CFSTR("com.evernote.Evernote"))
59 && NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitLastVersionWithEvernoteHack
;
65 ::JSType
JSValueGetType(JSContextRef ctx
, JSValueRef value
)
69 return kJSTypeUndefined
;
71 ExecState
* exec
= toJS(ctx
);
72 APIEntryShim
entryShim(exec
);
74 JSValue jsValue
= toJS(exec
, value
);
76 if (jsValue
.isUndefined())
77 return kJSTypeUndefined
;
80 if (jsValue
.isBoolean())
81 return kJSTypeBoolean
;
82 if (jsValue
.isNumber())
84 if (jsValue
.isString())
86 ASSERT(jsValue
.isObject());
90 bool JSValueIsUndefined(JSContextRef ctx
, JSValueRef value
)
96 ExecState
* exec
= toJS(ctx
);
97 APIEntryShim
entryShim(exec
);
99 JSValue jsValue
= toJS(exec
, value
);
100 return jsValue
.isUndefined();
103 bool JSValueIsNull(JSContextRef ctx
, JSValueRef value
)
106 ASSERT_NOT_REACHED();
109 ExecState
* exec
= toJS(ctx
);
110 APIEntryShim
entryShim(exec
);
112 JSValue jsValue
= toJS(exec
, value
);
113 return jsValue
.isNull();
116 bool JSValueIsBoolean(JSContextRef ctx
, JSValueRef value
)
119 ASSERT_NOT_REACHED();
122 ExecState
* exec
= toJS(ctx
);
123 APIEntryShim
entryShim(exec
);
125 JSValue jsValue
= toJS(exec
, value
);
126 return jsValue
.isBoolean();
129 bool JSValueIsNumber(JSContextRef ctx
, JSValueRef value
)
132 ASSERT_NOT_REACHED();
135 ExecState
* exec
= toJS(ctx
);
136 APIEntryShim
entryShim(exec
);
138 JSValue jsValue
= toJS(exec
, value
);
139 return jsValue
.isNumber();
142 bool JSValueIsString(JSContextRef ctx
, JSValueRef value
)
145 ASSERT_NOT_REACHED();
148 ExecState
* exec
= toJS(ctx
);
149 APIEntryShim
entryShim(exec
);
151 JSValue jsValue
= toJS(exec
, value
);
152 return jsValue
.isString();
155 bool JSValueIsObject(JSContextRef ctx
, JSValueRef value
)
158 ASSERT_NOT_REACHED();
161 ExecState
* exec
= toJS(ctx
);
162 APIEntryShim
entryShim(exec
);
164 JSValue jsValue
= toJS(exec
, value
);
165 return jsValue
.isObject();
168 bool JSValueIsObjectOfClass(JSContextRef ctx
, JSValueRef value
, JSClassRef jsClass
)
170 if (!ctx
|| !jsClass
) {
171 ASSERT_NOT_REACHED();
174 ExecState
* exec
= toJS(ctx
);
175 APIEntryShim
entryShim(exec
);
177 JSValue jsValue
= toJS(exec
, value
);
179 if (JSObject
* o
= jsValue
.getObject()) {
180 if (o
->inherits(&JSCallbackObject
<JSGlobalObject
>::s_info
))
181 return jsCast
<JSCallbackObject
<JSGlobalObject
>*>(o
)->inherits(jsClass
);
182 if (o
->inherits(&JSCallbackObject
<JSDestructibleObject
>::s_info
))
183 return jsCast
<JSCallbackObject
<JSDestructibleObject
>*>(o
)->inherits(jsClass
);
184 #if JSC_OBJC_API_ENABLED
185 if (o
->inherits(&JSCallbackObject
<JSAPIWrapperObject
>::s_info
))
186 return jsCast
<JSCallbackObject
<JSAPIWrapperObject
>*>(o
)->inherits(jsClass
);
192 bool JSValueIsEqual(JSContextRef ctx
, JSValueRef a
, JSValueRef b
, JSValueRef
* exception
)
195 ASSERT_NOT_REACHED();
198 ExecState
* exec
= toJS(ctx
);
199 APIEntryShim
entryShim(exec
);
201 JSValue jsA
= toJS(exec
, a
);
202 JSValue jsB
= toJS(exec
, b
);
204 bool result
= JSValue::equal(exec
, jsA
, jsB
); // false if an exception is thrown
205 if (exec
->hadException()) {
207 *exception
= toRef(exec
, exec
->exception());
208 exec
->clearException();
213 bool JSValueIsStrictEqual(JSContextRef ctx
, JSValueRef a
, JSValueRef b
)
216 ASSERT_NOT_REACHED();
219 ExecState
* exec
= toJS(ctx
);
220 APIEntryShim
entryShim(exec
);
222 JSValue jsA
= toJS(exec
, a
);
223 JSValue jsB
= toJS(exec
, b
);
225 return JSValue::strictEqual(exec
, jsA
, jsB
);
228 bool JSValueIsInstanceOfConstructor(JSContextRef ctx
, JSValueRef value
, JSObjectRef constructor
, JSValueRef
* exception
)
231 ASSERT_NOT_REACHED();
234 ExecState
* exec
= toJS(ctx
);
235 APIEntryShim
entryShim(exec
);
237 JSValue jsValue
= toJS(exec
, value
);
239 JSObject
* jsConstructor
= toJS(constructor
);
240 if (!jsConstructor
->structure()->typeInfo().implementsHasInstance())
242 bool result
= jsConstructor
->hasInstance(exec
, jsValue
); // false if an exception is thrown
243 if (exec
->hadException()) {
245 *exception
= toRef(exec
, exec
->exception());
246 exec
->clearException();
251 JSValueRef
JSValueMakeUndefined(JSContextRef ctx
)
254 ASSERT_NOT_REACHED();
257 ExecState
* exec
= toJS(ctx
);
258 APIEntryShim
entryShim(exec
);
260 return toRef(exec
, jsUndefined());
263 JSValueRef
JSValueMakeNull(JSContextRef ctx
)
266 ASSERT_NOT_REACHED();
269 ExecState
* exec
= toJS(ctx
);
270 APIEntryShim
entryShim(exec
);
272 return toRef(exec
, jsNull());
275 JSValueRef
JSValueMakeBoolean(JSContextRef ctx
, bool value
)
278 ASSERT_NOT_REACHED();
281 ExecState
* exec
= toJS(ctx
);
282 APIEntryShim
entryShim(exec
);
284 return toRef(exec
, jsBoolean(value
));
287 JSValueRef
JSValueMakeNumber(JSContextRef ctx
, double value
)
290 ASSERT_NOT_REACHED();
293 ExecState
* exec
= toJS(ctx
);
294 APIEntryShim
entryShim(exec
);
296 // Our JSValue representation relies on a standard bit pattern for NaN. NaNs
297 // generated internally to JavaScriptCore naturally have that representation,
298 // but an external NaN might not.
299 if (std::isnan(value
))
302 return toRef(exec
, jsNumber(value
));
305 JSValueRef
JSValueMakeString(JSContextRef ctx
, JSStringRef string
)
308 ASSERT_NOT_REACHED();
311 ExecState
* exec
= toJS(ctx
);
312 APIEntryShim
entryShim(exec
);
314 return toRef(exec
, jsString(exec
, string
->string()));
317 JSValueRef
JSValueMakeFromJSONString(JSContextRef ctx
, JSStringRef string
)
320 ASSERT_NOT_REACHED();
323 ExecState
* exec
= toJS(ctx
);
324 APIEntryShim
entryShim(exec
);
325 String str
= string
->string();
326 unsigned length
= str
.length();
327 if (length
&& str
.is8Bit()) {
328 LiteralParser
<LChar
> parser(exec
, str
.characters8(), length
, StrictJSON
);
329 return toRef(exec
, parser
.tryLiteralParse());
331 LiteralParser
<UChar
> parser(exec
, str
.characters(), length
, StrictJSON
);
332 return toRef(exec
, parser
.tryLiteralParse());
335 JSStringRef
JSValueCreateJSONString(JSContextRef ctx
, JSValueRef apiValue
, unsigned indent
, JSValueRef
* exception
)
338 ASSERT_NOT_REACHED();
341 ExecState
* exec
= toJS(ctx
);
342 APIEntryShim
entryShim(exec
);
343 JSValue value
= toJS(exec
, apiValue
);
344 String result
= JSONStringify(exec
, value
, indent
);
347 if (exec
->hadException()) {
349 *exception
= toRef(exec
, exec
->exception());
350 exec
->clearException();
353 return OpaqueJSString::create(result
).leakRef();
356 bool JSValueToBoolean(JSContextRef ctx
, JSValueRef value
)
359 ASSERT_NOT_REACHED();
362 ExecState
* exec
= toJS(ctx
);
363 APIEntryShim
entryShim(exec
);
365 JSValue jsValue
= toJS(exec
, value
);
366 return jsValue
.toBoolean(exec
);
369 double JSValueToNumber(JSContextRef ctx
, JSValueRef value
, JSValueRef
* exception
)
372 ASSERT_NOT_REACHED();
375 ExecState
* exec
= toJS(ctx
);
376 APIEntryShim
entryShim(exec
);
378 JSValue jsValue
= toJS(exec
, value
);
380 double number
= jsValue
.toNumber(exec
);
381 if (exec
->hadException()) {
383 *exception
= toRef(exec
, exec
->exception());
384 exec
->clearException();
390 JSStringRef
JSValueToStringCopy(JSContextRef ctx
, JSValueRef value
, JSValueRef
* exception
)
393 ASSERT_NOT_REACHED();
396 ExecState
* exec
= toJS(ctx
);
397 APIEntryShim
entryShim(exec
);
399 JSValue jsValue
= toJS(exec
, value
);
401 RefPtr
<OpaqueJSString
> stringRef(OpaqueJSString::create(jsValue
.toString(exec
)->value(exec
)));
402 if (exec
->hadException()) {
404 *exception
= toRef(exec
, exec
->exception());
405 exec
->clearException();
408 return stringRef
.release().leakRef();
411 JSObjectRef
JSValueToObject(JSContextRef ctx
, JSValueRef value
, JSValueRef
* exception
)
414 ASSERT_NOT_REACHED();
417 ExecState
* exec
= toJS(ctx
);
418 APIEntryShim
entryShim(exec
);
420 JSValue jsValue
= toJS(exec
, value
);
422 JSObjectRef objectRef
= toRef(jsValue
.toObject(exec
));
423 if (exec
->hadException()) {
425 *exception
= toRef(exec
, exec
->exception());
426 exec
->clearException();
432 void JSValueProtect(JSContextRef ctx
, JSValueRef value
)
435 ASSERT_NOT_REACHED();
438 ExecState
* exec
= toJS(ctx
);
439 APIEntryShim
entryShim(exec
);
441 JSValue jsValue
= toJSForGC(exec
, value
);
445 void JSValueUnprotect(JSContextRef ctx
, JSValueRef value
)
448 if ((!value
|| !ctx
) && evernoteHackNeeded())
452 ExecState
* exec
= toJS(ctx
);
453 APIEntryShim
entryShim(exec
);
455 JSValue jsValue
= toJSForGC(exec
, value
);
456 gcUnprotect(jsValue
);