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