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 47using 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 70bool 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 79bool 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 88bool 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 97bool 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 106bool 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 115bool 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 124bool 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 140bool 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 157bool 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 168bool 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 187JSValueRef JSValueMakeUndefined(JSContextRef ctx) 188{ 189 ExecState* exec = toJS(ctx); 190 APIEntryShim entryShim(exec); 191 192 return toRef(exec, jsUndefined()); 193} 194 195JSValueRef JSValueMakeNull(JSContextRef ctx) 196{ 197 ExecState* exec = toJS(ctx); 198 APIEntryShim entryShim(exec); 199 200 return toRef(exec, jsNull()); 201} 202 203JSValueRef JSValueMakeBoolean(JSContextRef ctx, bool value) 204{ 205 ExecState* exec = toJS(ctx); 206 APIEntryShim entryShim(exec); 207 208 return toRef(exec, jsBoolean(value)); 209} 210 211JSValueRef 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 225JSValueRef 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 233JSValueRef 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 241JSStringRef 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 258bool 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 267double 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 284JSStringRef 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 301JSObjectRef 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 318void 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 327void 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