2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "JSActivation.h"
32 #include "Arguments.h"
33 #include "Interpreter.h"
34 #include "JSFunction.h"
35 #include "Operations.h"
41 const ClassInfo
JSActivation::s_info
= { "JSActivation", &Base::s_info
, 0, 0, CREATE_METHOD_TABLE(JSActivation
) };
43 void JSActivation::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
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
);
51 // No need to mark our registers if they're still in the JSStack.
52 if (!thisObject
->isTornOff())
55 for (int i
= 0; i
< thisObject
->symbolTable()->captureCount(); ++i
)
56 visitor
.append(&thisObject
->storage()[i
]);
59 inline bool JSActivation::symbolTableGet(PropertyName propertyName
, PropertySlot
& slot
)
61 SymbolTableEntry entry
= symbolTable()->inlineGet(propertyName
.publicName());
65 // Defend against the inspector asking for a var after it has been optimized out.
66 if (isTornOff() && !isValid(entry
))
69 slot
.setValue(registerAt(entry
.getIndex()).get());
73 inline bool JSActivation::symbolTableGet(PropertyName propertyName
, PropertyDescriptor
& descriptor
)
75 SymbolTableEntry entry
= symbolTable()->inlineGet(propertyName
.publicName());
79 // Defend against the inspector asking for a var after it has been optimized out.
80 if (isTornOff() && !isValid(entry
))
83 descriptor
.setDescriptor(registerAt(entry
.getIndex()).get(), entry
.getAttributes());
87 inline bool JSActivation::symbolTablePut(ExecState
* exec
, PropertyName propertyName
, JSValue value
, bool shouldThrow
)
90 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
92 SymbolTableEntry entry
= symbolTable()->inlineGet(propertyName
.publicName());
95 if (entry
.isReadOnly()) {
97 throwTypeError(exec
, StrictModeReadonlyPropertyWriteError
);
101 // Defend against the inspector asking for a var after it has been optimized out.
102 if (isTornOff() && !isValid(entry
))
105 registerAt(entry
.getIndex()).set(vm
, this, value
);
109 void JSActivation::getOwnNonIndexPropertyNames(JSObject
* object
, ExecState
* exec
, PropertyNameArray
& propertyNames
, EnumerationMode mode
)
111 JSActivation
* thisObject
= jsCast
<JSActivation
*>(object
);
113 if (mode
== IncludeDontEnumProperties
&& !thisObject
->isTornOff())
114 propertyNames
.add(exec
->propertyNames().arguments
);
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
)
120 if (!thisObject
->isValid(it
->value
))
122 propertyNames
.add(Identifier(exec
, it
->key
.get()));
124 // Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames
125 JSObject::getOwnNonIndexPropertyNames(thisObject
, exec
, propertyNames
, mode
);
128 inline bool JSActivation::symbolTablePutWithAttributes(VM
& vm
, PropertyName propertyName
, JSValue value
, unsigned attributes
)
130 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
132 SymbolTable::iterator iter
= symbolTable()->find(propertyName
.publicName());
133 if (iter
== symbolTable()->end())
135 SymbolTableEntry
& entry
= iter
->value
;
136 ASSERT(!entry
.isNull());
140 entry
.setAttributes(attributes
);
141 registerAt(entry
.getIndex()).set(vm
, this, value
);
145 bool JSActivation::getOwnPropertySlot(JSCell
* cell
, ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
147 JSActivation
* thisObject
= jsCast
<JSActivation
*>(cell
);
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());
157 if (thisObject
->symbolTableGet(propertyName
, slot
))
160 if (JSValue value
= thisObject
->getDirect(exec
->vm(), propertyName
)) {
161 slot
.setValue(value
);
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());
172 bool JSActivation::getOwnPropertyDescriptor(JSObject
* object
, ExecState
* exec
, PropertyName propertyName
, PropertyDescriptor
& descriptor
)
174 JSActivation
* thisObject
= jsCast
<JSActivation
*>(object
);
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()) {
180 JSActivation::getOwnPropertySlot(thisObject
, exec
, propertyName
, slot
);
181 descriptor
.setDescriptor(slot
.getValue(exec
, propertyName
), DontEnum
);
186 if (thisObject
->symbolTableGet(propertyName
, descriptor
))
189 return Base::getOwnPropertyDescriptor(object
, exec
, propertyName
, descriptor
);
192 void JSActivation::put(JSCell
* cell
, ExecState
* exec
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
)
194 JSActivation
* thisObject
= jsCast
<JSActivation
*>(cell
);
195 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(thisObject
));
197 if (thisObject
->symbolTablePut(exec
, propertyName
, value
, slot
.isStrictMode()))
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
);
207 // FIXME: Make this function honor ReadOnly (const) and DontEnum
208 void JSActivation::putDirectVirtual(JSObject
* object
, ExecState
* exec
, PropertyName propertyName
, JSValue value
, unsigned attributes
)
210 JSActivation
* thisObject
= jsCast
<JSActivation
*>(object
);
211 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(thisObject
));
213 if (thisObject
->symbolTablePutWithAttributes(exec
->vm(), propertyName
, value
, attributes
))
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
);
223 bool JSActivation::deleteProperty(JSCell
* cell
, ExecState
* exec
, PropertyName propertyName
)
225 if (propertyName
== exec
->propertyNames().arguments
)
228 return Base::deleteProperty(cell
, exec
, propertyName
);
231 JSObject
* JSActivation::toThisObject(JSCell
*, ExecState
* exec
)
233 return exec
->globalThisValue();
236 JSValue
JSActivation::argumentsGetter(ExecState
*, JSValue slotBase
, PropertyName
)
238 JSActivation
* activation
= jsCast
<JSActivation
*>(slotBase
);
239 if (activation
->isTornOff())
240 return jsUndefined();
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())
246 int realArgumentsRegister
= unmodifiedArgumentsRegister(argumentsRegister
);
248 JSValue arguments
= JSValue(Arguments::create(callFrame
->vm(), callFrame
));
249 callFrame
->uncheckedR(argumentsRegister
) = arguments
;
250 callFrame
->uncheckedR(realArgumentsRegister
) = arguments
;
252 ASSERT(callFrame
->uncheckedR(realArgumentsRegister
).jsValue().inherits(&Arguments::s_info
));
253 return callFrame
->uncheckedR(realArgumentsRegister
).jsValue();
256 // These two functions serve the purpose of isolating the common case from a
259 PropertySlot::GetValueFunc
JSActivation::getArgumentsGetter()
261 return argumentsGetter
;