Removed ASSERT_CLASS_FITS_IN_CELL
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSActivation.cpp
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
36 using namespace std;
37
38 namespace JSC {
39
40 const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSActivation) };
41
42 void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor)
43 {
44     JSActivation* thisObject = jsCast<JSActivation*>(cell);
45     ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
46     COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
47     ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
48     Base::visitChildren(thisObject, visitor);
49
50     // No need to mark our registers if they're still in the JSStack.
51     if (!thisObject->isTornOff())
52         return;
53
54     for (int i = 0; i < thisObject->symbolTable()->captureCount(); ++i)
55         visitor.append(&thisObject->storage()[i]);
56 }
57
58 inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertySlot& slot)
59 {
60     SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName());
61     if (entry.isNull())
62         return false;
63
64     // Defend against the inspector asking for a var after it has been optimized out.
65     if (isTornOff() && !isValid(entry))
66         return false;
67
68     slot.setValue(registerAt(entry.getIndex()).get());
69     return true;
70 }
71
72 inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertyDescriptor& descriptor)
73 {
74     SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName());
75     if (entry.isNull())
76         return false;
77
78     // Defend against the inspector asking for a var after it has been optimized out.
79     if (isTornOff() && !isValid(entry))
80         return false;
81
82     descriptor.setDescriptor(registerAt(entry.getIndex()).get(), entry.getAttributes());
83     return true;
84 }
85
86 inline bool JSActivation::symbolTablePut(ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrow)
87 {
88     JSGlobalData& globalData = exec->globalData();
89     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
90     
91     SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName());
92     if (entry.isNull())
93         return false;
94     if (entry.isReadOnly()) {
95         if (shouldThrow)
96             throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
97         return true;
98     }
99
100     // Defend against the inspector asking for a var after it has been optimized out.
101     if (isTornOff() && !isValid(entry))
102         return false;
103
104     registerAt(entry.getIndex()).set(globalData, this, value);
105     return true;
106 }
107
108 void JSActivation::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
109 {
110     JSActivation* thisObject = jsCast<JSActivation*>(object);
111
112     if (mode == IncludeDontEnumProperties && !thisObject->isTornOff())
113         propertyNames.add(exec->propertyNames().arguments);
114
115     SymbolTable::const_iterator end = thisObject->symbolTable()->end();
116     for (SymbolTable::const_iterator it = thisObject->symbolTable()->begin(); it != end; ++it) {
117         if (it->value.getAttributes() & DontEnum && mode != IncludeDontEnumProperties)
118             continue;
119         if (!thisObject->isValid(it->value))
120             continue;
121         propertyNames.add(Identifier(exec, it->key.get()));
122     }
123     // Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames
124     JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
125 }
126
127 inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes)
128 {
129     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
130     
131     SymbolTable::iterator iter = symbolTable()->find(propertyName.publicName());
132     if (iter == symbolTable()->end())
133         return false;
134     SymbolTableEntry& entry = iter->value;
135     ASSERT(!entry.isNull());
136     if (!isValid(entry))
137         return false;
138
139     entry.setAttributes(attributes);
140     registerAt(entry.getIndex()).set(globalData, this, value);
141     return true;
142 }
143
144 bool JSActivation::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
145 {
146     JSActivation* thisObject = jsCast<JSActivation*>(cell);
147
148     if (propertyName == exec->propertyNames().arguments) {
149         // Defend against the inspector asking for the arguments object after it has been optimized out.
150         if (!thisObject->isTornOff()) {
151             slot.setCustom(thisObject, thisObject->getArgumentsGetter());
152             return true;
153         }
154     }
155
156     if (thisObject->symbolTableGet(propertyName, slot))
157         return true;
158
159     if (WriteBarrierBase<Unknown>* location = thisObject->getDirectLocation(exec->globalData(), propertyName)) {
160         slot.setValue(location->get());
161         return true;
162     }
163
164     // We don't call through to JSObject because there's no way to give an 
165     // activation object getter properties or a prototype.
166     ASSERT(!thisObject->hasGetterSetterProperties());
167     ASSERT(thisObject->prototype().isNull());
168     return false;
169 }
170
171 bool JSActivation::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
172 {
173     JSActivation* thisObject = jsCast<JSActivation*>(object);
174
175     if (propertyName == exec->propertyNames().arguments) {
176         // Defend against the inspector asking for the arguments object after it has been optimized out.
177         if (!thisObject->isTornOff()) {
178             PropertySlot slot;
179             JSActivation::getOwnPropertySlot(thisObject, exec, propertyName, slot);
180             descriptor.setDescriptor(slot.getValue(exec, propertyName), DontEnum);
181             return true;
182         }
183     }
184
185     if (thisObject->symbolTableGet(propertyName, descriptor))
186         return true;
187
188     return Base::getOwnPropertyDescriptor(object, exec, propertyName, descriptor);
189 }
190
191 void JSActivation::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
192 {
193     JSActivation* thisObject = jsCast<JSActivation*>(cell);
194     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
195
196     if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode()))
197         return;
198
199     // We don't call through to JSObject because __proto__ and getter/setter 
200     // properties are non-standard extensions that other implementations do not
201     // expose in the activation object.
202     ASSERT(!thisObject->hasGetterSetterProperties());
203     thisObject->putOwnDataProperty(exec->globalData(), propertyName, value, slot);
204 }
205
206 // FIXME: Make this function honor ReadOnly (const) and DontEnum
207 void JSActivation::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
208 {
209     JSActivation* thisObject = jsCast<JSActivation*>(object);
210     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
211
212     if (thisObject->symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes))
213         return;
214
215     // We don't call through to JSObject because __proto__ and getter/setter 
216     // properties are non-standard extensions that other implementations do not
217     // expose in the activation object.
218     ASSERT(!thisObject->hasGetterSetterProperties());
219     JSObject::putDirectVirtual(thisObject, exec, propertyName, value, attributes);
220 }
221
222 bool JSActivation::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
223 {
224     if (propertyName == exec->propertyNames().arguments)
225         return false;
226
227     return Base::deleteProperty(cell, exec, propertyName);
228 }
229
230 JSObject* JSActivation::toThisObject(JSCell*, ExecState* exec)
231 {
232     return exec->globalThisValue();
233 }
234
235 JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, PropertyName)
236 {
237     JSActivation* activation = jsCast<JSActivation*>(slotBase);
238     if (activation->isTornOff())
239         return jsUndefined();
240
241     CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers));
242     int argumentsRegister = callFrame->codeBlock()->argumentsRegister();
243     if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue())
244         return arguments;
245     int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister);
246
247     JSValue arguments = JSValue(Arguments::create(callFrame->globalData(), callFrame));
248     callFrame->uncheckedR(argumentsRegister) = arguments;
249     callFrame->uncheckedR(realArgumentsRegister) = arguments;
250     
251     ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(&Arguments::s_info));
252     return callFrame->uncheckedR(realArgumentsRegister).jsValue();
253 }
254
255 // These two functions serve the purpose of isolating the common case from a
256 // PIC branch.
257
258 PropertySlot::GetValueFunc JSActivation::getArgumentsGetter()
259 {
260     return argumentsGetter;
261 }
262
263 } // namespace JSC