1/* 2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) 3 * Copyright (C) 2008, 2011 Apple Inc. All rights reserved. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 * 19 */ 20 21#include "config.h" 22#include "ObjectPrototype.h" 23 24#include "Error.h" 25#include "GetterSetter.h" 26#include "JSFunction.h" 27#include "JSString.h" 28#include "JSCInlines.h" 29#include "StructureRareDataInlines.h" 30 31namespace JSC { 32 33static EncodedJSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState*); 34static EncodedJSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState*); 35static EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState*); 36static EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState*); 37static EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState*); 38static EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState*); 39static EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState*); 40static EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState*); 41static EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*); 42 43STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ObjectPrototype); 44 45const ClassInfo ObjectPrototype::s_info = { "Object", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(ObjectPrototype) }; 46 47ObjectPrototype::ObjectPrototype(VM& vm, Structure* stucture) 48 : JSNonFinalObject(vm, stucture) 49{ 50} 51 52void ObjectPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) 53{ 54 Base::finishCreation(vm); 55 ASSERT(inherits(info())); 56 vm.prototypeMap.addPrototype(this); 57 58 JSC_NATIVE_FUNCTION(vm.propertyNames->toString, objectProtoFuncToString, DontEnum, 0); 59 JSC_NATIVE_FUNCTION(vm.propertyNames->toLocaleString, objectProtoFuncToLocaleString, DontEnum, 0); 60 JSC_NATIVE_FUNCTION(vm.propertyNames->valueOf, objectProtoFuncValueOf, DontEnum, 0); 61 JSC_NATIVE_FUNCTION(vm.propertyNames->hasOwnProperty, objectProtoFuncHasOwnProperty, DontEnum, 1); 62 JSC_NATIVE_FUNCTION(vm.propertyNames->propertyIsEnumerable, objectProtoFuncPropertyIsEnumerable, DontEnum, 1); 63 JSC_NATIVE_FUNCTION(vm.propertyNames->isPrototypeOf, objectProtoFuncIsPrototypeOf, DontEnum, 1); 64 JSC_NATIVE_FUNCTION(vm.propertyNames->__defineGetter__, objectProtoFuncDefineGetter, DontEnum, 2); 65 JSC_NATIVE_FUNCTION(vm.propertyNames->__defineSetter__, objectProtoFuncDefineSetter, DontEnum, 2); 66 JSC_NATIVE_FUNCTION(vm.propertyNames->__lookupGetter__, objectProtoFuncLookupGetter, DontEnum, 1); 67 JSC_NATIVE_FUNCTION(vm.propertyNames->__lookupSetter__, objectProtoFuncLookupSetter, DontEnum, 1); 68} 69 70ObjectPrototype* ObjectPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure) 71{ 72 ObjectPrototype* prototype = new (NotNull, allocateCell<ObjectPrototype>(vm.heap)) ObjectPrototype(vm, structure); 73 prototype->finishCreation(vm, globalObject); 74 return prototype; 75} 76 77// ------------------------------ Functions -------------------------------- 78 79EncodedJSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState* exec) 80{ 81 JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); 82 return JSValue::encode(thisValue.toObject(exec)); 83} 84 85EncodedJSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState* exec) 86{ 87 JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); 88 return JSValue::encode(jsBoolean(thisValue.toObject(exec)->hasOwnProperty(exec, exec->argument(0).toString(exec)->toIdentifier(exec)))); 89} 90 91EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec) 92{ 93 JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); 94 JSObject* thisObj = thisValue.toObject(exec); 95 96 if (!exec->argument(0).isObject()) 97 return JSValue::encode(jsBoolean(false)); 98 99 JSValue v = asObject(exec->argument(0))->prototype(); 100 101 while (true) { 102 if (!v.isObject()) 103 return JSValue::encode(jsBoolean(false)); 104 if (v == thisObj) 105 return JSValue::encode(jsBoolean(true)); 106 v = asObject(v)->prototype(); 107 } 108} 109 110EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState* exec) 111{ 112 JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); 113 if (exec->hadException()) 114 return JSValue::encode(jsUndefined()); 115 116 JSValue get = exec->argument(1); 117 CallData callData; 118 if (getCallData(get, callData) == CallTypeNone) 119 return throwVMError(exec, createTypeError(exec, ASCIILiteral("invalid getter usage"))); 120 121 PropertyDescriptor descriptor; 122 descriptor.setGetter(get); 123 descriptor.setEnumerable(true); 124 descriptor.setConfigurable(true); 125 thisObject->methodTable(exec->vm())->defineOwnProperty(thisObject, exec, exec->argument(0).toString(exec)->toIdentifier(exec), descriptor, false); 126 127 return JSValue::encode(jsUndefined()); 128} 129 130EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec) 131{ 132 JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); 133 if (exec->hadException()) 134 return JSValue::encode(jsUndefined()); 135 136 JSValue set = exec->argument(1); 137 CallData callData; 138 if (getCallData(set, callData) == CallTypeNone) 139 return throwVMError(exec, createTypeError(exec, ASCIILiteral("invalid setter usage"))); 140 141 PropertyDescriptor descriptor; 142 descriptor.setSetter(set); 143 descriptor.setEnumerable(true); 144 descriptor.setConfigurable(true); 145 thisObject->methodTable(exec->vm())->defineOwnProperty(thisObject, exec, exec->argument(0).toString(exec)->toIdentifier(exec), descriptor, false); 146 147 return JSValue::encode(jsUndefined()); 148} 149 150EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState* exec) 151{ 152 JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); 153 if (exec->hadException()) 154 return JSValue::encode(jsUndefined()); 155 156 PropertySlot slot(thisObject); 157 if (thisObject->getPropertySlot(exec, exec->argument(0).toString(exec)->toIdentifier(exec), slot) 158 && slot.isAccessor()) { 159 JSObject* getter = slot.getterSetter()->getter(); 160 return getter ? JSValue::encode(getter) : JSValue::encode(jsUndefined()); 161 } 162 163 return JSValue::encode(jsUndefined()); 164} 165 166EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState* exec) 167{ 168 JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); 169 if (exec->hadException()) 170 return JSValue::encode(jsUndefined()); 171 172 PropertySlot slot(thisObject); 173 if (thisObject->getPropertySlot(exec, exec->argument(0).toString(exec)->toIdentifier(exec), slot) 174 && slot.isAccessor()) { 175 JSObject* setter = slot.getterSetter()->setter(); 176 return setter ? JSValue::encode(setter) : JSValue::encode(jsUndefined()); 177 } 178 179 return JSValue::encode(jsUndefined()); 180} 181 182EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState* exec) 183{ 184 JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); 185 Identifier propertyName(exec, exec->argument(0).toString(exec)->value(exec)); 186 187 PropertyDescriptor descriptor; 188 bool enumerable = thisObject->getOwnPropertyDescriptor(exec, propertyName, descriptor) && descriptor.enumerable(); 189 return JSValue::encode(jsBoolean(enumerable)); 190} 191 192// 15.2.4.3 Object.prototype.toLocaleString() 193EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec) 194{ 195 // 1. Let O be the result of calling ToObject passing the this value as the argument. 196 JSObject* object = exec->thisValue().toThis(exec, StrictMode).toObject(exec); 197 if (exec->hadException()) 198 return JSValue::encode(jsUndefined()); 199 200 // 2. Let toString be the result of calling the [[Get]] internal method of O passing "toString" as the argument. 201 JSValue toString = object->get(exec, exec->propertyNames().toString); 202 203 // 3. If IsCallable(toString) is false, throw a TypeError exception. 204 CallData callData; 205 CallType callType = getCallData(toString, callData); 206 if (callType == CallTypeNone) 207 return JSValue::encode(jsUndefined()); 208 209 // 4. Return the result of calling the [[Call]] internal method of toString passing O as the this value and no arguments. 210 return JSValue::encode(call(exec, toString, callType, callData, object, exec->emptyList())); 211} 212 213EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec) 214{ 215 VM& vm = exec->vm(); 216 JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); 217 if (thisValue.isUndefinedOrNull()) 218 return JSValue::encode(thisValue.isUndefined() ? vm.smallStrings.undefinedObjectString() : vm.smallStrings.nullObjectString()); 219 JSObject* thisObject = thisValue.toObject(exec); 220 221 JSString* result = thisObject->structure(vm)->objectToStringValue(); 222 if (!result) { 223 RefPtr<StringImpl> newString = WTF::tryMakeString("[object ", thisObject->methodTable(exec->vm())->className(thisObject), "]"); 224 if (!newString) 225 return JSValue::encode(throwOutOfMemoryError(exec)); 226 227 result = jsNontrivialString(&vm, newString.release()); 228 thisObject->structure(vm)->setObjectToStringValue(vm, result); 229 } 230 return JSValue::encode(result); 231} 232 233} // namespace JSC 234