1/* 2 * Copyright (C) 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 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "JSActivation.h" 31 32#include "Arguments.h" 33#include "Interpreter.h" 34#include "JSFunction.h" 35#include "Operations.h" 36 37using namespace std; 38 39namespace JSC { 40 41const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSActivation) }; 42 43void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor) 44{ 45 JSActivation* thisObject = jsCast<JSActivation*>(cell); 46 ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); 47 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); 48 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); 49 Base::visitChildren(thisObject, visitor); 50 51 // No need to mark our registers if they're still in the JSStack. 52 if (!thisObject->isTornOff()) 53 return; 54 55 for (int i = 0; i < thisObject->symbolTable()->captureCount(); ++i) 56 visitor.append(&thisObject->storage()[i]); 57} 58 59inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertySlot& slot) 60{ 61 SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName()); 62 if (entry.isNull()) 63 return false; 64 65 // Defend against the inspector asking for a var after it has been optimized out. 66 if (isTornOff() && !isValid(entry)) 67 return false; 68 69 slot.setValue(registerAt(entry.getIndex()).get()); 70 return true; 71} 72 73inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertyDescriptor& descriptor) 74{ 75 SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName()); 76 if (entry.isNull()) 77 return false; 78 79 // Defend against the inspector asking for a var after it has been optimized out. 80 if (isTornOff() && !isValid(entry)) 81 return false; 82 83 descriptor.setDescriptor(registerAt(entry.getIndex()).get(), entry.getAttributes()); 84 return true; 85} 86 87inline bool JSActivation::symbolTablePut(ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrow) 88{ 89 VM& vm = exec->vm(); 90 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); 91 92 SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName()); 93 if (entry.isNull()) 94 return false; 95 if (entry.isReadOnly()) { 96 if (shouldThrow) 97 throwTypeError(exec, StrictModeReadonlyPropertyWriteError); 98 return true; 99 } 100 101 // Defend against the inspector asking for a var after it has been optimized out. 102 if (isTornOff() && !isValid(entry)) 103 return false; 104 105 registerAt(entry.getIndex()).set(vm, this, value); 106 return true; 107} 108 109void JSActivation::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) 110{ 111 JSActivation* thisObject = jsCast<JSActivation*>(object); 112 113 if (mode == IncludeDontEnumProperties && !thisObject->isTornOff()) 114 propertyNames.add(exec->propertyNames().arguments); 115 116 SymbolTable::const_iterator end = thisObject->symbolTable()->end(); 117 for (SymbolTable::const_iterator it = thisObject->symbolTable()->begin(); it != end; ++it) { 118 if (it->value.getAttributes() & DontEnum && mode != IncludeDontEnumProperties) 119 continue; 120 if (!thisObject->isValid(it->value)) 121 continue; 122 propertyNames.add(Identifier(exec, it->key.get())); 123 } 124 // Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames 125 JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); 126} 127 128inline bool JSActivation::symbolTablePutWithAttributes(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) 129{ 130 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); 131 132 SymbolTable::iterator iter = symbolTable()->find(propertyName.publicName()); 133 if (iter == symbolTable()->end()) 134 return false; 135 SymbolTableEntry& entry = iter->value; 136 ASSERT(!entry.isNull()); 137 if (!isValid(entry)) 138 return false; 139 140 entry.setAttributes(attributes); 141 registerAt(entry.getIndex()).set(vm, this, value); 142 return true; 143} 144 145bool JSActivation::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) 146{ 147 JSActivation* thisObject = jsCast<JSActivation*>(cell); 148 149 if (propertyName == exec->propertyNames().arguments) { 150 // Defend against the inspector asking for the arguments object after it has been optimized out. 151 if (!thisObject->isTornOff()) { 152 slot.setCustom(thisObject, thisObject->getArgumentsGetter()); 153 return true; 154 } 155 } 156 157 if (thisObject->symbolTableGet(propertyName, slot)) 158 return true; 159 160 if (JSValue value = thisObject->getDirect(exec->vm(), propertyName)) { 161 slot.setValue(value); 162 return true; 163 } 164 165 // We don't call through to JSObject because there's no way to give an 166 // activation object getter properties or a prototype. 167 ASSERT(!thisObject->hasGetterSetterProperties()); 168 ASSERT(thisObject->prototype().isNull()); 169 return false; 170} 171 172bool JSActivation::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) 173{ 174 JSActivation* thisObject = jsCast<JSActivation*>(object); 175 176 if (propertyName == exec->propertyNames().arguments) { 177 // Defend against the inspector asking for the arguments object after it has been optimized out. 178 if (!thisObject->isTornOff()) { 179 PropertySlot slot; 180 JSActivation::getOwnPropertySlot(thisObject, exec, propertyName, slot); 181 descriptor.setDescriptor(slot.getValue(exec, propertyName), DontEnum); 182 return true; 183 } 184 } 185 186 if (thisObject->symbolTableGet(propertyName, descriptor)) 187 return true; 188 189 return Base::getOwnPropertyDescriptor(object, exec, propertyName, descriptor); 190} 191 192void JSActivation::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) 193{ 194 JSActivation* thisObject = jsCast<JSActivation*>(cell); 195 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); 196 197 if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode())) 198 return; 199 200 // We don't call through to JSObject because __proto__ and getter/setter 201 // properties are non-standard extensions that other implementations do not 202 // expose in the activation object. 203 ASSERT(!thisObject->hasGetterSetterProperties()); 204 thisObject->putOwnDataProperty(exec->vm(), propertyName, value, slot); 205} 206 207// FIXME: Make this function honor ReadOnly (const) and DontEnum 208void JSActivation::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes) 209{ 210 JSActivation* thisObject = jsCast<JSActivation*>(object); 211 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); 212 213 if (thisObject->symbolTablePutWithAttributes(exec->vm(), propertyName, value, attributes)) 214 return; 215 216 // We don't call through to JSObject because __proto__ and getter/setter 217 // properties are non-standard extensions that other implementations do not 218 // expose in the activation object. 219 ASSERT(!thisObject->hasGetterSetterProperties()); 220 JSObject::putDirectVirtual(thisObject, exec, propertyName, value, attributes); 221} 222 223bool JSActivation::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) 224{ 225 if (propertyName == exec->propertyNames().arguments) 226 return false; 227 228 return Base::deleteProperty(cell, exec, propertyName); 229} 230 231JSObject* JSActivation::toThisObject(JSCell*, ExecState* exec) 232{ 233 return exec->globalThisValue(); 234} 235 236JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, PropertyName) 237{ 238 JSActivation* activation = jsCast<JSActivation*>(slotBase); 239 if (activation->isTornOff()) 240 return jsUndefined(); 241 242 CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers)); 243 int argumentsRegister = callFrame->codeBlock()->argumentsRegister(); 244 if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue()) 245 return arguments; 246 int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister); 247 248 JSValue arguments = JSValue(Arguments::create(callFrame->vm(), callFrame)); 249 callFrame->uncheckedR(argumentsRegister) = arguments; 250 callFrame->uncheckedR(realArgumentsRegister) = arguments; 251 252 ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(&Arguments::s_info)); 253 return callFrame->uncheckedR(realArgumentsRegister).jsValue(); 254} 255 256// These two functions serve the purpose of isolating the common case from a 257// PIC branch. 258 259PropertySlot::GetValueFunc JSActivation::getArgumentsGetter() 260{ 261 return argumentsGetter; 262} 263 264} // namespace JSC 265