]>
Commit | Line | Data |
---|---|---|
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 |
54 | using namespace JSC; |
55 | ||
ed1e77d3 A |
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 | ||
93a37866 A |
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 | ||
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 | 112 | bool 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 | 124 | bool 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 | 136 | bool 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 | 148 | bool 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 | 160 | bool 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 | 172 | bool 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 | ||
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()); | |
b37bf2e1 A |
206 | } |
207 | ||
ba379fdc | 208 | bool 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 | ||
235 | bool 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 | 253 | bool 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 | ||
268 | bool 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 | 287 | JSValueRef 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 | 299 | JSValueRef 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 | 311 | JSValueRef 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 | 323 | JSValueRef 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 | 335 | JSValueRef 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 |
347 | JSValueRef 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 | ||
365 | JSStringRef 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 |
382 | bool 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 | ||
395 | double 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 | ||
412 | JSStringRef 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 | ||
429 | JSObjectRef 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 | 446 | void 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 | 459 | void 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 | } |