1/* 2 * Copyright (C) 2003, 2008, 2009 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 "runtime_object.h" 28 29#include "JSDOMBinding.h" 30#include "runtime_method.h" 31#include <runtime/Error.h> 32 33using namespace WebCore; 34 35namespace JSC { 36namespace Bindings { 37 38const ClassInfo RuntimeObject::s_info = { "RuntimeObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(RuntimeObject) }; 39 40RuntimeObject::RuntimeObject(ExecState*, JSGlobalObject* globalObject, Structure* structure, PassRefPtr<Instance> instance) 41 : JSDestructibleObject(globalObject->vm(), structure) 42 , m_instance(instance) 43{ 44} 45 46void RuntimeObject::finishCreation(JSGlobalObject* globalObject) 47{ 48 Base::finishCreation(globalObject->vm()); 49 ASSERT(inherits(&s_info)); 50} 51 52void RuntimeObject::destroy(JSCell* cell) 53{ 54 static_cast<RuntimeObject*>(cell)->RuntimeObject::~RuntimeObject(); 55} 56 57void RuntimeObject::invalidate() 58{ 59 ASSERT(m_instance); 60 if (m_instance) 61 m_instance->willInvalidateRuntimeObject(); 62 m_instance = 0; 63} 64 65JSValue RuntimeObject::fallbackObjectGetter(ExecState* exec, JSValue slotBase, PropertyName propertyName) 66{ 67 RuntimeObject* thisObj = static_cast<RuntimeObject*>(asObject(slotBase)); 68 RefPtr<Instance> instance = thisObj->m_instance; 69 70 if (!instance) 71 return throwInvalidAccessError(exec); 72 73 instance->begin(); 74 75 Class *aClass = instance->getClass(); 76 JSValue result = aClass->fallbackObject(exec, instance.get(), propertyName); 77 78 instance->end(); 79 80 return result; 81} 82 83JSValue RuntimeObject::fieldGetter(ExecState* exec, JSValue slotBase, PropertyName propertyName) 84{ 85 RuntimeObject* thisObj = static_cast<RuntimeObject*>(asObject(slotBase)); 86 RefPtr<Instance> instance = thisObj->m_instance; 87 88 if (!instance) 89 return throwInvalidAccessError(exec); 90 91 instance->begin(); 92 93 Class *aClass = instance->getClass(); 94 Field* aField = aClass->fieldNamed(propertyName, instance.get()); 95 JSValue result = aField->valueFromInstance(exec, instance.get()); 96 97 instance->end(); 98 99 return result; 100} 101 102JSValue RuntimeObject::methodGetter(ExecState* exec, JSValue slotBase, PropertyName propertyName) 103{ 104 RuntimeObject* thisObj = static_cast<RuntimeObject*>(asObject(slotBase)); 105 RefPtr<Instance> instance = thisObj->m_instance; 106 107 if (!instance) 108 return throwInvalidAccessError(exec); 109 110 instance->begin(); 111 112 JSValue method = instance->getMethod(exec, propertyName); 113 114 instance->end(); 115 116 return method; 117} 118 119bool RuntimeObject::getOwnPropertySlot(JSCell* cell, ExecState *exec, PropertyName propertyName, PropertySlot& slot) 120{ 121 RuntimeObject* thisObject = jsCast<RuntimeObject*>(cell); 122 if (!thisObject->m_instance) { 123 throwInvalidAccessError(exec); 124 return false; 125 } 126 127 RefPtr<Instance> instance = thisObject->m_instance; 128 129 instance->begin(); 130 131 Class *aClass = instance->getClass(); 132 133 if (aClass) { 134 // See if the instance has a field with the specified name. 135 Field *aField = aClass->fieldNamed(propertyName, instance.get()); 136 if (aField) { 137 slot.setCustom(thisObject, thisObject->fieldGetter); 138 instance->end(); 139 return true; 140 } else { 141 // Now check if a method with specified name exists, if so return a function object for 142 // that method. 143 if (aClass->methodNamed(propertyName, instance.get())) { 144 slot.setCustom(thisObject, thisObject->methodGetter); 145 146 instance->end(); 147 return true; 148 } 149 } 150 151 // Try a fallback object. 152 if (!aClass->fallbackObject(exec, instance.get(), propertyName).isUndefined()) { 153 slot.setCustom(thisObject, thisObject->fallbackObjectGetter); 154 instance->end(); 155 return true; 156 } 157 } 158 159 instance->end(); 160 161 return instance->getOwnPropertySlot(thisObject, exec, propertyName, slot); 162} 163 164bool RuntimeObject::getOwnPropertyDescriptor(JSObject* object, ExecState *exec, PropertyName propertyName, PropertyDescriptor& descriptor) 165{ 166 RuntimeObject* thisObject = jsCast<RuntimeObject*>(object); 167 if (!thisObject->m_instance) { 168 throwInvalidAccessError(exec); 169 return false; 170 } 171 172 RefPtr<Instance> instance = thisObject->m_instance; 173 instance->begin(); 174 175 Class *aClass = instance->getClass(); 176 177 if (aClass) { 178 // See if the instance has a field with the specified name. 179 Field *aField = aClass->fieldNamed(propertyName, instance.get()); 180 if (aField) { 181 PropertySlot slot; 182 slot.setCustom(thisObject, fieldGetter); 183 instance->end(); 184 descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete); 185 return true; 186 } else { 187 // Now check if a method with specified name exists, if so return a function object for 188 // that method. 189 if (aClass->methodNamed(propertyName, instance.get())) { 190 PropertySlot slot; 191 slot.setCustom(thisObject, methodGetter); 192 instance->end(); 193 descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly); 194 return true; 195 } 196 } 197 198 // Try a fallback object. 199 if (!aClass->fallbackObject(exec, instance.get(), propertyName).isUndefined()) { 200 PropertySlot slot; 201 slot.setCustom(thisObject, fallbackObjectGetter); 202 instance->end(); 203 descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum); 204 return true; 205 } 206 } 207 208 instance->end(); 209 210 return instance->getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); 211} 212 213void RuntimeObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) 214{ 215 RuntimeObject* thisObject = jsCast<RuntimeObject*>(cell); 216 if (!thisObject->m_instance) { 217 throwInvalidAccessError(exec); 218 return; 219 } 220 221 RefPtr<Instance> instance = thisObject->m_instance; 222 instance->begin(); 223 224 // Set the value of the property. 225 Field *aField = instance->getClass()->fieldNamed(propertyName, instance.get()); 226 if (aField) 227 aField->setValueToInstance(exec, instance.get(), value); 228 else if (!instance->setValueOfUndefinedField(exec, propertyName, value)) 229 instance->put(thisObject, exec, propertyName, value, slot); 230 231 instance->end(); 232} 233 234bool RuntimeObject::deleteProperty(JSCell*, ExecState*, PropertyName) 235{ 236 // Can never remove a property of a RuntimeObject. 237 return false; 238} 239 240JSValue RuntimeObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint) 241{ 242 const RuntimeObject* thisObject = jsCast<const RuntimeObject*>(object); 243 if (!thisObject->m_instance) 244 return throwInvalidAccessError(exec); 245 246 RefPtr<Instance> instance = thisObject->m_instance; 247 248 instance->begin(); 249 JSValue result = instance->defaultValue(exec, hint); 250 instance->end(); 251 return result; 252} 253 254static EncodedJSValue JSC_HOST_CALL callRuntimeObject(ExecState* exec) 255{ 256 ASSERT(exec->callee()->inherits(&RuntimeObject::s_info)); 257 RefPtr<Instance> instance(static_cast<RuntimeObject*>(exec->callee())->getInternalInstance()); 258 instance->begin(); 259 JSValue result = instance->invokeDefaultMethod(exec); 260 instance->end(); 261 return JSValue::encode(result); 262} 263 264CallType RuntimeObject::getCallData(JSCell* cell, CallData& callData) 265{ 266 RuntimeObject* thisObject = jsCast<RuntimeObject*>(cell); 267 if (!thisObject->m_instance) 268 return CallTypeNone; 269 270 RefPtr<Instance> instance = thisObject->m_instance; 271 if (!instance->supportsInvokeDefaultMethod()) 272 return CallTypeNone; 273 274 callData.native.function = callRuntimeObject; 275 return CallTypeHost; 276} 277 278static EncodedJSValue JSC_HOST_CALL callRuntimeConstructor(ExecState* exec) 279{ 280 JSObject* constructor = exec->callee(); 281 ASSERT(constructor->inherits(&RuntimeObject::s_info)); 282 RefPtr<Instance> instance(static_cast<RuntimeObject*>(exec->callee())->getInternalInstance()); 283 instance->begin(); 284 ArgList args(exec); 285 JSValue result = instance->invokeConstruct(exec, args); 286 instance->end(); 287 288 ASSERT(result); 289 return JSValue::encode(result.isObject() ? jsCast<JSObject*>(result.asCell()) : constructor); 290} 291 292ConstructType RuntimeObject::getConstructData(JSCell* cell, ConstructData& constructData) 293{ 294 RuntimeObject* thisObject = jsCast<RuntimeObject*>(cell); 295 if (!thisObject->m_instance) 296 return ConstructTypeNone; 297 298 RefPtr<Instance> instance = thisObject->m_instance; 299 if (!instance->supportsConstruct()) 300 return ConstructTypeNone; 301 302 constructData.native.function = callRuntimeConstructor; 303 return ConstructTypeHost; 304} 305 306void RuntimeObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode) 307{ 308 RuntimeObject* thisObject = jsCast<RuntimeObject*>(object); 309 if (!thisObject->m_instance) { 310 throwInvalidAccessError(exec); 311 return; 312 } 313 314 RefPtr<Instance> instance = thisObject->m_instance; 315 316 instance->begin(); 317 instance->getPropertyNames(exec, propertyNames); 318 instance->end(); 319} 320 321JSObject* RuntimeObject::throwInvalidAccessError(ExecState* exec) 322{ 323 return throwError(exec, createReferenceError(exec, "Trying to access object from destroyed plug-in.")); 324} 325 326} 327} 328