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