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