]> git.saurik.com Git - apple/javascriptcore.git/blob - API/JSValueRef.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / API / JSValueRef.cpp
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 "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"
38 #include "JSString.h"
39 #include "LiteralParser.h"
40 #include "Protect.h"
41 #include <algorithm>
42 #include <wtf/Assertions.h>
43 #include <wtf/text/StringHash.h>
44 #include <wtf/text/WTFString.h>
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
54 using namespace JSC;
55
56 enum class ExceptionStatus {
57 DidThrow,
58 DidNotThrow
59 };
60
61 static 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
76 #if PLATFORM(MAC)
77 static 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
87 ::JSType JSValueGetType(JSContextRef ctx, JSValueRef value)
88 {
89 if (!ctx) {
90 ASSERT_NOT_REACHED();
91 return kJSTypeUndefined;
92 }
93 ExecState* exec = toJS(ctx);
94 JSLockHolder locker(exec);
95
96 JSValue jsValue = toJS(exec, value);
97
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;
110 }
111
112 bool JSValueIsUndefined(JSContextRef ctx, JSValueRef value)
113 {
114 if (!ctx) {
115 ASSERT_NOT_REACHED();
116 return false;
117 }
118 ExecState* exec = toJS(ctx);
119 JSLockHolder locker(exec);
120
121 return toJS(exec, value).isUndefined();
122 }
123
124 bool JSValueIsNull(JSContextRef ctx, JSValueRef value)
125 {
126 if (!ctx) {
127 ASSERT_NOT_REACHED();
128 return false;
129 }
130 ExecState* exec = toJS(ctx);
131 JSLockHolder locker(exec);
132
133 return toJS(exec, value).isNull();
134 }
135
136 bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value)
137 {
138 if (!ctx) {
139 ASSERT_NOT_REACHED();
140 return false;
141 }
142 ExecState* exec = toJS(ctx);
143 JSLockHolder locker(exec);
144
145 return toJS(exec, value).isBoolean();
146 }
147
148 bool JSValueIsNumber(JSContextRef ctx, JSValueRef value)
149 {
150 if (!ctx) {
151 ASSERT_NOT_REACHED();
152 return false;
153 }
154 ExecState* exec = toJS(ctx);
155 JSLockHolder locker(exec);
156
157 return toJS(exec, value).isNumber();
158 }
159
160 bool JSValueIsString(JSContextRef ctx, JSValueRef value)
161 {
162 if (!ctx) {
163 ASSERT_NOT_REACHED();
164 return false;
165 }
166 ExecState* exec = toJS(ctx);
167 JSLockHolder locker(exec);
168
169 return toJS(exec, value).isString();
170 }
171
172 bool JSValueIsObject(JSContextRef ctx, JSValueRef value)
173 {
174 if (!ctx) {
175 ASSERT_NOT_REACHED();
176 return false;
177 }
178 ExecState* exec = toJS(ctx);
179 JSLockHolder locker(exec);
180
181 return toJS(exec, value).isObject();
182 }
183
184 bool 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
196 bool 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());
206 }
207
208 bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass)
209 {
210 if (!ctx || !jsClass) {
211 ASSERT_NOT_REACHED();
212 return false;
213 }
214 ExecState* exec = toJS(ctx);
215 JSLockHolder locker(exec);
216
217 JSValue jsValue = toJS(exec, value);
218
219 if (JSObject* o = jsValue.getObject()) {
220 if (o->inherits(JSProxy::info()))
221 o = jsCast<JSProxy*>(o)->target();
222
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);
230 #endif
231 }
232 return false;
233 }
234
235 bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* exception)
236 {
237 if (!ctx) {
238 ASSERT_NOT_REACHED();
239 return false;
240 }
241 ExecState* exec = toJS(ctx);
242 JSLockHolder locker(exec);
243
244 JSValue jsA = toJS(exec, a);
245 JSValue jsB = toJS(exec, b);
246
247 bool result = JSValue::equal(exec, jsA, jsB); // false if an exception is thrown
248 handleExceptionIfNeeded(exec, exception);
249
250 return result;
251 }
252
253 bool JSValueIsStrictEqual(JSContextRef ctx, JSValueRef a, JSValueRef b)
254 {
255 if (!ctx) {
256 ASSERT_NOT_REACHED();
257 return false;
258 }
259 ExecState* exec = toJS(ctx);
260 JSLockHolder locker(exec);
261
262 JSValue jsA = toJS(exec, a);
263 JSValue jsB = toJS(exec, b);
264
265 return JSValue::strictEqual(exec, jsA, jsB);
266 }
267
268 bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObjectRef constructor, JSValueRef* exception)
269 {
270 if (!ctx) {
271 ASSERT_NOT_REACHED();
272 return false;
273 }
274 ExecState* exec = toJS(ctx);
275 JSLockHolder locker(exec);
276
277 JSValue jsValue = toJS(exec, value);
278
279 JSObject* jsConstructor = toJS(constructor);
280 if (!jsConstructor->structure()->typeInfo().implementsHasInstance())
281 return false;
282 bool result = jsConstructor->hasInstance(exec, jsValue); // false if an exception is thrown
283 handleExceptionIfNeeded(exec, exception);
284 return result;
285 }
286
287 JSValueRef JSValueMakeUndefined(JSContextRef ctx)
288 {
289 if (!ctx) {
290 ASSERT_NOT_REACHED();
291 return 0;
292 }
293 ExecState* exec = toJS(ctx);
294 JSLockHolder locker(exec);
295
296 return toRef(exec, jsUndefined());
297 }
298
299 JSValueRef JSValueMakeNull(JSContextRef ctx)
300 {
301 if (!ctx) {
302 ASSERT_NOT_REACHED();
303 return 0;
304 }
305 ExecState* exec = toJS(ctx);
306 JSLockHolder locker(exec);
307
308 return toRef(exec, jsNull());
309 }
310
311 JSValueRef JSValueMakeBoolean(JSContextRef ctx, bool value)
312 {
313 if (!ctx) {
314 ASSERT_NOT_REACHED();
315 return 0;
316 }
317 ExecState* exec = toJS(ctx);
318 JSLockHolder locker(exec);
319
320 return toRef(exec, jsBoolean(value));
321 }
322
323 JSValueRef JSValueMakeNumber(JSContextRef ctx, double value)
324 {
325 if (!ctx) {
326 ASSERT_NOT_REACHED();
327 return 0;
328 }
329 ExecState* exec = toJS(ctx);
330 JSLockHolder locker(exec);
331
332 return toRef(exec, jsNumber(purifyNaN(value)));
333 }
334
335 JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string)
336 {
337 if (!ctx) {
338 ASSERT_NOT_REACHED();
339 return 0;
340 }
341 ExecState* exec = toJS(ctx);
342 JSLockHolder locker(exec);
343
344 return toRef(exec, jsString(exec, string ? string->string() : String()));
345 }
346
347 JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string)
348 {
349 if (!ctx) {
350 ASSERT_NOT_REACHED();
351 return 0;
352 }
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());
360 }
361 LiteralParser<UChar> parser(exec, str.characters16(), length, StrictJSON);
362 return toRef(exec, parser.tryLiteralParse());
363 }
364
365 JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef apiValue, unsigned indent, JSValueRef* exception)
366 {
367 if (!ctx) {
368 ASSERT_NOT_REACHED();
369 return 0;
370 }
371 ExecState* exec = toJS(ctx);
372 JSLockHolder locker(exec);
373 JSValue value = toJS(exec, apiValue);
374 String result = JSONStringify(exec, value, indent);
375 if (exception)
376 *exception = 0;
377 if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
378 return 0;
379 return OpaqueJSString::create(result).leakRef();
380 }
381
382 bool JSValueToBoolean(JSContextRef ctx, JSValueRef value)
383 {
384 if (!ctx) {
385 ASSERT_NOT_REACHED();
386 return false;
387 }
388 ExecState* exec = toJS(ctx);
389 JSLockHolder locker(exec);
390
391 JSValue jsValue = toJS(exec, value);
392 return jsValue.toBoolean(exec);
393 }
394
395 double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
396 {
397 if (!ctx) {
398 ASSERT_NOT_REACHED();
399 return PNaN;
400 }
401 ExecState* exec = toJS(ctx);
402 JSLockHolder locker(exec);
403
404 JSValue jsValue = toJS(exec, value);
405
406 double number = jsValue.toNumber(exec);
407 if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
408 number = PNaN;
409 return number;
410 }
411
412 JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
413 {
414 if (!ctx) {
415 ASSERT_NOT_REACHED();
416 return 0;
417 }
418 ExecState* exec = toJS(ctx);
419 JSLockHolder locker(exec);
420
421 JSValue jsValue = toJS(exec, value);
422
423 RefPtr<OpaqueJSString> stringRef(OpaqueJSString::create(jsValue.toString(exec)->value(exec)));
424 if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
425 stringRef = nullptr;
426 return stringRef.release().leakRef();
427 }
428
429 JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
430 {
431 if (!ctx) {
432 ASSERT_NOT_REACHED();
433 return 0;
434 }
435 ExecState* exec = toJS(ctx);
436 JSLockHolder locker(exec);
437
438 JSValue jsValue = toJS(exec, value);
439
440 JSObjectRef objectRef = toRef(jsValue.toObject(exec));
441 if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
442 objectRef = 0;
443 return objectRef;
444 }
445
446 void JSValueProtect(JSContextRef ctx, JSValueRef value)
447 {
448 if (!ctx) {
449 ASSERT_NOT_REACHED();
450 return;
451 }
452 ExecState* exec = toJS(ctx);
453 JSLockHolder locker(exec);
454
455 JSValue jsValue = toJSForGC(exec, value);
456 gcProtect(jsValue);
457 }
458
459 void JSValueUnprotect(JSContextRef ctx, JSValueRef value)
460 {
461 #if PLATFORM(MAC)
462 if ((!value || !ctx) && evernoteHackNeeded())
463 return;
464 #endif
465
466 ExecState* exec = toJS(ctx);
467 JSLockHolder locker(exec);
468
469 JSValue jsValue = toJSForGC(exec, value);
470 gcUnprotect(jsValue);
471 }