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 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 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(VM& vm, Structure* structure, PassRefPtr<Instance> instance) 41 : JSDestructibleObject(vm, structure) 42 , m_instance(instance) 43{ 44} 45 46void RuntimeObject::finishCreation(VM& vm) 47{ 48 Base::finishCreation(vm); 49 ASSERT(inherits(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 65EncodedJSValue RuntimeObject::fallbackObjectGetter(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName propertyName) 66{ 67 RuntimeObject* thisObj = jsCast<RuntimeObject*>(slotBase); 68 RefPtr<Instance> instance = thisObj->m_instance; 69 70 if (!instance) 71 return JSValue::encode(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 JSValue::encode(result); 81} 82 83EncodedJSValue RuntimeObject::fieldGetter(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName propertyName) 84{ 85 RuntimeObject* thisObj = jsCast<RuntimeObject*>(slotBase); 86 RefPtr<Instance> instance = thisObj->m_instance; 87 88 if (!instance) 89 return JSValue::encode(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 JSValue::encode(result); 100} 101 102EncodedJSValue RuntimeObject::methodGetter(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName propertyName) 103{ 104 RuntimeObject* thisObj = jsCast<RuntimeObject*>(slotBase); 105 RefPtr<Instance> instance = thisObj->m_instance; 106 107 if (!instance) 108 return JSValue::encode(throwInvalidAccessError(exec)); 109 110 instance->begin(); 111 112 JSValue method = instance->getMethod(exec, propertyName); 113 114 instance->end(); 115 116 return JSValue::encode(method); 117} 118 119bool RuntimeObject::getOwnPropertySlot(JSObject* object, ExecState *exec, PropertyName propertyName, PropertySlot& slot) 120{ 121 RuntimeObject* thisObject = jsCast<RuntimeObject*>(object); 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, DontDelete, 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, DontDelete | ReadOnly, 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, DontDelete | ReadOnly | DontEnum, 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 164void RuntimeObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) 165{ 166 RuntimeObject* thisObject = jsCast<RuntimeObject*>(cell); 167 if (!thisObject->m_instance) { 168 throwInvalidAccessError(exec); 169 return; 170 } 171 172 RefPtr<Instance> instance = thisObject->m_instance; 173 instance->begin(); 174 175 // Set the value of the property. 176 Field *aField = instance->getClass()->fieldNamed(propertyName, instance.get()); 177 if (aField) 178 aField->setValueToInstance(exec, instance.get(), value); 179 else if (!instance->setValueOfUndefinedField(exec, propertyName, value)) 180 instance->put(thisObject, exec, propertyName, value, slot); 181 182 instance->end(); 183} 184 185bool RuntimeObject::deleteProperty(JSCell*, ExecState*, PropertyName) 186{ 187 // Can never remove a property of a RuntimeObject. 188 return false; 189} 190 191JSValue RuntimeObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint) 192{ 193 const RuntimeObject* thisObject = jsCast<const RuntimeObject*>(object); 194 if (!thisObject->m_instance) 195 return throwInvalidAccessError(exec); 196 197 RefPtr<Instance> instance = thisObject->m_instance; 198 199 instance->begin(); 200 JSValue result = instance->defaultValue(exec, hint); 201 instance->end(); 202 return result; 203} 204 205static EncodedJSValue JSC_HOST_CALL callRuntimeObject(ExecState* exec) 206{ 207 ASSERT(exec->callee()->inherits(RuntimeObject::info())); 208 RefPtr<Instance> instance(static_cast<RuntimeObject*>(exec->callee())->getInternalInstance()); 209 instance->begin(); 210 JSValue result = instance->invokeDefaultMethod(exec); 211 instance->end(); 212 return JSValue::encode(result); 213} 214 215CallType RuntimeObject::getCallData(JSCell* cell, CallData& callData) 216{ 217 RuntimeObject* thisObject = jsCast<RuntimeObject*>(cell); 218 if (!thisObject->m_instance) 219 return CallTypeNone; 220 221 RefPtr<Instance> instance = thisObject->m_instance; 222 if (!instance->supportsInvokeDefaultMethod()) 223 return CallTypeNone; 224 225 callData.native.function = callRuntimeObject; 226 return CallTypeHost; 227} 228 229static EncodedJSValue JSC_HOST_CALL callRuntimeConstructor(ExecState* exec) 230{ 231 JSObject* constructor = exec->callee(); 232 ASSERT(constructor->inherits(RuntimeObject::info())); 233 RefPtr<Instance> instance(static_cast<RuntimeObject*>(exec->callee())->getInternalInstance()); 234 instance->begin(); 235 ArgList args(exec); 236 JSValue result = instance->invokeConstruct(exec, args); 237 instance->end(); 238 239 ASSERT(result); 240 return JSValue::encode(result.isObject() ? jsCast<JSObject*>(result.asCell()) : constructor); 241} 242 243ConstructType RuntimeObject::getConstructData(JSCell* cell, ConstructData& constructData) 244{ 245 RuntimeObject* thisObject = jsCast<RuntimeObject*>(cell); 246 if (!thisObject->m_instance) 247 return ConstructTypeNone; 248 249 RefPtr<Instance> instance = thisObject->m_instance; 250 if (!instance->supportsConstruct()) 251 return ConstructTypeNone; 252 253 constructData.native.function = callRuntimeConstructor; 254 return ConstructTypeHost; 255} 256 257void RuntimeObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode) 258{ 259 RuntimeObject* thisObject = jsCast<RuntimeObject*>(object); 260 if (!thisObject->m_instance) { 261 throwInvalidAccessError(exec); 262 return; 263 } 264 265 RefPtr<Instance> instance = thisObject->m_instance; 266 267 instance->begin(); 268 instance->getPropertyNames(exec, propertyNames); 269 instance->end(); 270} 271 272JSObject* RuntimeObject::throwInvalidAccessError(ExecState* exec) 273{ 274 return exec->vm().throwException(exec, createReferenceError(exec, "Trying to access object from destroyed plug-in.")); 275} 276 277} 278} 279