De-virtualize JSVariableObject::isDynamicScope
[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 namespace JSC {
37
38 ASSERT_CLASS_FITS_IN_CELL(JSActivation);
39
40 const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSActivation) };
41
42 JSActivation::JSActivation(CallFrame* callFrame, FunctionExecutable* functionExecutable)
43     : Base(callFrame->globalData(), callFrame->globalData().activationStructure.get(), functionExecutable->symbolTable(), callFrame->registers())
44     , m_numParametersMinusThis(static_cast<int>(functionExecutable->parameterCount()))
45     , m_numCapturedVars(functionExecutable->capturedVariableCount())
46     , m_requiresDynamicChecks(functionExecutable->usesEval())
47     , m_argumentsRegister(functionExecutable->generatedBytecode().argumentsRegister())
48 {
49 }
50
51 void JSActivation::finishCreation(CallFrame* callFrame)
52 {
53     Base::finishCreation(callFrame->globalData());
54     ASSERT(inherits(&s_info));
55
56     // We have to manually ref and deref the symbol table as JSVariableObject
57     // doesn't know about SharedSymbolTable
58     static_cast<SharedSymbolTable*>(m_symbolTable)->ref();
59 }
60
61 JSActivation::~JSActivation()
62 {
63     static_cast<SharedSymbolTable*>(m_symbolTable)->deref();
64 }
65
66 void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor)
67 {
68     JSActivation* thisObject = static_cast<JSActivation*>(cell);
69     ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
70     COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
71     ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
72     Base::visitChildren(thisObject, visitor);
73
74     // No need to mark our registers if they're still in the RegisterFile.
75     WriteBarrier<Unknown>* registerArray = thisObject->m_registerArray.get();
76     if (!registerArray)
77         return;
78
79     visitor.appendValues(registerArray, thisObject->m_numParametersMinusThis);
80
81     // Skip the call frame, which sits between the parameters and vars.
82     visitor.appendValues(registerArray + thisObject->m_numParametersMinusThis + RegisterFile::CallFrameHeaderSize, thisObject->m_numCapturedVars);
83 }
84
85 inline bool JSActivation::symbolTableGet(const Identifier& propertyName, PropertySlot& slot)
86 {
87     SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
88     if (entry.isNull())
89         return false;
90     if (entry.getIndex() >= m_numCapturedVars)
91         return false;
92
93     slot.setValue(registerAt(entry.getIndex()).get());
94     return true;
95 }
96
97 inline bool JSActivation::symbolTablePut(JSGlobalData& globalData, const Identifier& propertyName, JSValue value)
98 {
99     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
100     
101     SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
102     if (entry.isNull())
103         return false;
104     if (entry.isReadOnly())
105         return true;
106     if (entry.getIndex() >= m_numCapturedVars)
107         return false;
108
109     registerAt(entry.getIndex()).set(globalData, this, value);
110     return true;
111 }
112
113 void JSActivation::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
114 {
115     JSActivation* thisObject = static_cast<JSActivation*>(object);
116     SymbolTable::const_iterator end = thisObject->symbolTable().end();
117     for (SymbolTable::const_iterator it = thisObject->symbolTable().begin(); it != end; ++it) {
118         if (it->second.getAttributes() & DontEnum && mode != IncludeDontEnumProperties)
119             continue;
120         if (it->second.getIndex() >= thisObject->m_numCapturedVars)
121             continue;
122         propertyNames.add(Identifier(exec, it->first.get()));
123     }
124     // Skip the JSVariableObject implementation of getOwnPropertyNames
125     JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
126 }
127
128 inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData, const Identifier& 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.impl());
133     if (iter == symbolTable().end())
134         return false;
135     SymbolTableEntry& entry = iter->second;
136     ASSERT(!entry.isNull());
137     if (entry.getIndex() >= m_numCapturedVars)
138         return false;
139
140     entry.setAttributes(attributes);
141     registerAt(entry.getIndex()).set(globalData, this, value);
142     return true;
143 }
144
145 bool JSActivation::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
146 {
147     JSActivation* thisObject = static_cast<JSActivation*>(cell);
148     if (propertyName == exec->propertyNames().arguments) {
149         slot.setCustom(thisObject, thisObject->getArgumentsGetter());
150         return true;
151     }
152
153     if (thisObject->symbolTableGet(propertyName, slot))
154         return true;
155
156     if (WriteBarrierBase<Unknown>* location = thisObject->getDirectLocation(exec->globalData(), propertyName)) {
157         slot.setValue(location->get());
158         return true;
159     }
160
161     // We don't call through to JSObject because there's no way to give an 
162     // activation object getter properties or a prototype.
163     ASSERT(!thisObject->hasGetterSetterProperties());
164     ASSERT(thisObject->prototype().isNull());
165     return false;
166 }
167
168 void JSActivation::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
169 {
170     JSActivation* thisObject = static_cast<JSActivation*>(cell);
171     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
172
173     if (thisObject->symbolTablePut(exec->globalData(), propertyName, value))
174         return;
175
176     // We don't call through to JSObject because __proto__ and getter/setter 
177     // properties are non-standard extensions that other implementations do not
178     // expose in the activation object.
179     ASSERT(!thisObject->hasGetterSetterProperties());
180     thisObject->putDirect(exec->globalData(), propertyName, value, 0, true, slot);
181 }
182
183 // FIXME: Make this function honor ReadOnly (const) and DontEnum
184 void JSActivation::putWithAttributes(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes)
185 {
186     JSActivation* thisObject = static_cast<JSActivation*>(object);
187     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
188
189     if (thisObject->symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes))
190         return;
191
192     // We don't call through to JSObject because __proto__ and getter/setter 
193     // properties are non-standard extensions that other implementations do not
194     // expose in the activation object.
195     ASSERT(!thisObject->hasGetterSetterProperties());
196     JSObject::putWithAttributes(thisObject, exec, propertyName, value, attributes);
197 }
198
199 bool JSActivation::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
200 {
201     if (propertyName == exec->propertyNames().arguments)
202         return false;
203
204     return Base::deleteProperty(cell, exec, propertyName);
205 }
206
207 JSObject* JSActivation::toThisObject(JSCell*, ExecState* exec)
208 {
209     return exec->globalThisValue();
210 }
211
212 JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, const Identifier&)
213 {
214     JSActivation* activation = asActivation(slotBase);
215     CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers));
216     int argumentsRegister = activation->m_argumentsRegister;
217     if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue())
218         return arguments;
219     int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister);
220
221     JSValue arguments = JSValue(Arguments::create(callFrame->globalData(), callFrame));
222     callFrame->uncheckedR(argumentsRegister) = arguments;
223     callFrame->uncheckedR(realArgumentsRegister) = arguments;
224     
225     ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(&Arguments::s_info));
226     return callFrame->uncheckedR(realArgumentsRegister).jsValue();
227 }
228
229 // These two functions serve the purpose of isolating the common case from a
230 // PIC branch.
231
232 PropertySlot::GetValueFunc JSActivation::getArgumentsGetter()
233 {
234     return argumentsGetter;
235 }
236
237 } // namespace JSC