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 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. 24 */ 25 26 #include "config.h" 27 #include "JSValueRef.h" 28 29 #include "APICast.h" 30 #include "APIShims.h" 31 #include "JSCallbackObject.h" 32 33 #include <runtime/JSGlobalObject.h> 34 #include <runtime/JSONObject.h> 35 #include <runtime/JSString.h> 36 #include <runtime/LiteralParser.h> 37 #include <runtime/Operations.h> 38 #include <runtime/Protect.h> 39 #include <runtime/UString.h> 40 #include <runtime/JSValue.h> 41 42 #include <wtf/Assertions.h> 43 #include <wtf/text/StringHash.h> 44 45 #include <algorithm> // for std::min 46 47 using namespace JSC; 48 49 ::JSType JSValueGetType(JSContextRef ctx, JSValueRef value) 50 { 51 ExecState* exec = toJS(ctx); 52 APIEntryShim entryShim(exec); 53 54 JSValue jsValue = toJS(exec, value); 55 56 if (jsValue.isUndefined()) 57 return kJSTypeUndefined; 58 if (jsValue.isNull()) 59 return kJSTypeNull; 60 if (jsValue.isBoolean()) 61 return kJSTypeBoolean; 62 if (jsValue.isNumber()) 63 return kJSTypeNumber; 64 if (jsValue.isString()) 65 return kJSTypeString; 66 ASSERT(jsValue.isObject()); 67 return kJSTypeObject; 68 } 69 70 bool JSValueIsUndefined(JSContextRef ctx, JSValueRef value) 71 { 72 ExecState* exec = toJS(ctx); 73 APIEntryShim entryShim(exec); 74 75 JSValue jsValue = toJS(exec, value); 76 return jsValue.isUndefined(); 77 } 78 79 bool JSValueIsNull(JSContextRef ctx, JSValueRef value) 80 { 81 ExecState* exec = toJS(ctx); 82 APIEntryShim entryShim(exec); 83 84 JSValue jsValue = toJS(exec, value); 85 return jsValue.isNull(); 86 } 87 88 bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value) 89 { 90 ExecState* exec = toJS(ctx); 91 APIEntryShim entryShim(exec); 92 93 JSValue jsValue = toJS(exec, value); 94 return jsValue.isBoolean(); 95 } 96 97 bool JSValueIsNumber(JSContextRef ctx, JSValueRef value) 98 { 99 ExecState* exec = toJS(ctx); 100 APIEntryShim entryShim(exec); 101 102 JSValue jsValue = toJS(exec, value); 103 return jsValue.isNumber(); 104 } 105 106 bool JSValueIsString(JSContextRef ctx, JSValueRef value) 107 { 108 ExecState* exec = toJS(ctx); 109 APIEntryShim entryShim(exec); 110 111 JSValue jsValue = toJS(exec, value); 112 return jsValue.isString(); 113 } 114 115 bool JSValueIsObject(JSContextRef ctx, JSValueRef value) 116 { 117 ExecState* exec = toJS(ctx); 118 APIEntryShim entryShim(exec); 119 120 JSValue jsValue = toJS(exec, value); 121 return jsValue.isObject(); 122 } 123 124 bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass) 125 { 126 ExecState* exec = toJS(ctx); 127 APIEntryShim entryShim(exec); 128 129 JSValue jsValue = toJS(exec, value); 130 131 if (JSObject* o = jsValue.getObject()) { 132 if (o->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) 133 return static_cast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass); 134 if (o->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info)) 135 return static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(o)->inherits(jsClass); 136 } 137 return false; 138 } 139 140 bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* exception) 141 { 142 ExecState* exec = toJS(ctx); 143 APIEntryShim entryShim(exec); 144 145 JSValue jsA = toJS(exec, a); 146 JSValue jsB = toJS(exec, b); 147 148 bool result = JSValue::equal(exec, jsA, jsB); // false if an exception is thrown 149 if (exec->hadException()) { 150 if (exception) 151 *exception = toRef(exec, exec->exception()); 152 exec->clearException(); 153 } 154 return result; 155 } 156 157 bool JSValueIsStrictEqual(JSContextRef ctx, JSValueRef a, JSValueRef b) 158 { 159 ExecState* exec = toJS(ctx); 160 APIEntryShim entryShim(exec); 161 162 JSValue jsA = toJS(exec, a); 163 JSValue jsB = toJS(exec, b); 164 165 return JSValue::strictEqual(exec, jsA, jsB); 166 } 167 168 bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObjectRef constructor, JSValueRef* exception) 169 { 170 ExecState* exec = toJS(ctx); 171 APIEntryShim entryShim(exec); 172 173 JSValue jsValue = toJS(exec, value); 174 175 JSObject* jsConstructor = toJS(constructor); 176 if (!jsConstructor->structure()->typeInfo().implementsHasInstance()) 177 return false; 178 bool result = jsConstructor->hasInstance(exec, jsValue, jsConstructor->get(exec, exec->propertyNames().prototype)); // false if an exception is thrown 179 if (exec->hadException()) { 180 if (exception) 181 *exception = toRef(exec, exec->exception()); 182 exec->clearException(); 183 } 184 return result; 185 } 186 187 JSValueRef JSValueMakeUndefined(JSContextRef ctx) 188 { 189 ExecState* exec = toJS(ctx); 190 APIEntryShim entryShim(exec); 191 192 return toRef(exec, jsUndefined()); 193 } 194 195 JSValueRef JSValueMakeNull(JSContextRef ctx) 196 { 197 ExecState* exec = toJS(ctx); 198 APIEntryShim entryShim(exec); 199 200 return toRef(exec, jsNull()); 201 } 202 203 JSValueRef JSValueMakeBoolean(JSContextRef ctx, bool value) 204 { 205 ExecState* exec = toJS(ctx); 206 APIEntryShim entryShim(exec); 207 208 return toRef(exec, jsBoolean(value)); 209 } 210 211 JSValueRef JSValueMakeNumber(JSContextRef ctx, double value) 212 { 213 ExecState* exec = toJS(ctx); 214 APIEntryShim entryShim(exec); 215 216 // Our JSValue representation relies on a standard bit pattern for NaN. NaNs 217 // generated internally to JavaScriptCore naturally have that representation, 218 // but an external NaN might not. 219 if (isnan(value)) 220 value = NaN; 221 222 return toRef(exec, jsNumber(value)); 223 } 224 225 JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string) 226 { 227 ExecState* exec = toJS(ctx); 228 APIEntryShim entryShim(exec); 229 230 return toRef(exec, jsString(exec, string->ustring())); 231 } 232 233 JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) 234 { 235 ExecState* exec = toJS(ctx); 236 APIEntryShim entryShim(exec); 237 LiteralParser parser(exec, string->ustring(), LiteralParser::StrictJSON); 238 return toRef(exec, parser.tryLiteralParse()); 239 } 240 241 JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef apiValue, unsigned indent, JSValueRef* exception) 242 { 243 ExecState* exec = toJS(ctx); 244 APIEntryShim entryShim(exec); 245 JSValue value = toJS(exec, apiValue); 246 UString result = JSONStringify(exec, value, indent); 247 if (exception) 248 *exception = 0; 249 if (exec->hadException()) { 250 if (exception) 251 *exception = toRef(exec, exec->exception()); 252 exec->clearException(); 253 return 0; 254 } 255 return OpaqueJSString::create(result).leakRef(); 256 } 257 258 bool JSValueToBoolean(JSContextRef ctx, JSValueRef value) 259 { 260 ExecState* exec = toJS(ctx); 261 APIEntryShim entryShim(exec); 262 263 JSValue jsValue = toJS(exec, value); 264 return jsValue.toBoolean(exec); 265 } 266 267 double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception) 268 { 269 ExecState* exec = toJS(ctx); 270 APIEntryShim entryShim(exec); 271 272 JSValue jsValue = toJS(exec, value); 273 274 double number = jsValue.toNumber(exec); 275 if (exec->hadException()) { 276 if (exception) 277 *exception = toRef(exec, exec->exception()); 278 exec->clearException(); 279 number = NaN; 280 } 281 return number; 282 } 283 284 JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* exception) 285 { 286 ExecState* exec = toJS(ctx); 287 APIEntryShim entryShim(exec); 288 289 JSValue jsValue = toJS(exec, value); 290 291 RefPtr<OpaqueJSString> stringRef(OpaqueJSString::create(jsValue.toString(exec))); 292 if (exec->hadException()) { 293 if (exception) 294 *exception = toRef(exec, exec->exception()); 295 exec->clearException(); 296 stringRef.clear(); 297 } 298 return stringRef.release().leakRef(); 299 } 300 301 JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exception) 302 { 303 ExecState* exec = toJS(ctx); 304 APIEntryShim entryShim(exec); 305 306 JSValue jsValue = toJS(exec, value); 307 308 JSObjectRef objectRef = toRef(jsValue.toObject(exec)); 309 if (exec->hadException()) { 310 if (exception) 311 *exception = toRef(exec, exec->exception()); 312 exec->clearException(); 313 objectRef = 0; 314 } 315 return objectRef; 316 } 317 318 void JSValueProtect(JSContextRef ctx, JSValueRef value) 319 { 320 ExecState* exec = toJS(ctx); 321 APIEntryShim entryShim(exec); 322 323 JSValue jsValue = toJSForGC(exec, value); 324 gcProtect(jsValue); 325 } 326 327 void JSValueUnprotect(JSContextRef ctx, JSValueRef value) 328 { 329 ExecState* exec = toJS(ctx); 330 APIEntryShim entryShim(exec); 331 332 JSValue jsValue = toJSForGC(exec, value); 333 gcUnprotect(jsValue); 334 } 335