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 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 "JSCInlines.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
, 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
.uid());
65 // Defend against the inspector asking for a var after it has been optimized out.
66 if (isTornOff() && !isValid(entry
))
69 slot
.setValue(this, DontEnum
, registerAt(entry
.getIndex()).get());
73 inline bool JSActivation::symbolTableGet(PropertyName propertyName
, PropertyDescriptor
& descriptor
)
75 SymbolTableEntry entry
= symbolTable()->inlineGet(propertyName
.uid());
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 WriteBarrierBase
<Unknown
>* reg
;
94 GCSafeConcurrentJITLocker
locker(symbolTable()->m_lock
, exec
->vm().heap
);
95 SymbolTable::Map::iterator iter
= symbolTable()->find(locker
, propertyName
.uid());
96 if (iter
== symbolTable()->end(locker
))
98 ASSERT(!iter
->value
.isNull());
99 if (iter
->value
.isReadOnly()) {
101 throwTypeError(exec
, StrictModeReadonlyPropertyWriteError
);
104 // Defend against the inspector asking for a var after it has been optimized out.
105 if (isTornOff() && !isValid(iter
->value
))
107 if (VariableWatchpointSet
* set
= iter
->value
.watchpointSet())
108 set
->invalidate(); // Don't mess around - if we had found this statically, we would have invcalidated it.
109 reg
= ®isterAt(iter
->value
.getIndex());
111 reg
->set(vm
, this, value
);
115 void JSActivation::getOwnNonIndexPropertyNames(JSObject
* object
, ExecState
* exec
, PropertyNameArray
& propertyNames
, EnumerationMode mode
)
117 JSActivation
* thisObject
= jsCast
<JSActivation
*>(object
);
119 CallFrame
* callFrame
= CallFrame::create(reinterpret_cast<Register
*>(thisObject
->m_registers
));
120 if (mode
== IncludeDontEnumProperties
&& !thisObject
->isTornOff() && (callFrame
->codeBlock()->usesArguments() || callFrame
->codeBlock()->usesEval()))
121 propertyNames
.add(exec
->propertyNames().arguments
);
124 ConcurrentJITLocker
locker(thisObject
->symbolTable()->m_lock
);
125 SymbolTable::Map::iterator end
= thisObject
->symbolTable()->end(locker
);
126 for (SymbolTable::Map::iterator it
= thisObject
->symbolTable()->begin(locker
); it
!= end
; ++it
) {
127 if (it
->value
.getAttributes() & DontEnum
&& mode
!= IncludeDontEnumProperties
)
129 if (!thisObject
->isValid(it
->value
))
131 propertyNames
.add(Identifier(exec
, it
->key
.get()));
134 // Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames
135 JSObject::getOwnNonIndexPropertyNames(thisObject
, exec
, propertyNames
, mode
);
138 inline bool JSActivation::symbolTablePutWithAttributes(VM
& vm
, PropertyName propertyName
, JSValue value
, unsigned attributes
)
140 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
142 WriteBarrierBase
<Unknown
>* reg
;
144 ConcurrentJITLocker
locker(symbolTable()->m_lock
);
145 SymbolTable::Map::iterator iter
= symbolTable()->find(locker
, propertyName
.uid());
146 if (iter
== symbolTable()->end(locker
))
148 SymbolTableEntry
& entry
= iter
->value
;
149 ASSERT(!entry
.isNull());
153 entry
.setAttributes(attributes
);
154 reg
= ®isterAt(entry
.getIndex());
156 reg
->set(vm
, this, value
);
160 bool JSActivation::getOwnPropertySlot(JSObject
* object
, ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
162 JSActivation
* thisObject
= jsCast
<JSActivation
*>(object
);
164 if (propertyName
== exec
->propertyNames().arguments
) {
165 // Defend against the inspector asking for the arguments object after it has been optimized out.
166 CallFrame
* callFrame
= CallFrame::create(reinterpret_cast<Register
*>(thisObject
->m_registers
));
167 if (!thisObject
->isTornOff() && (callFrame
->codeBlock()->usesArguments() || callFrame
->codeBlock()->usesEval())) {
168 slot
.setCustom(thisObject
, DontEnum
, argumentsGetter
);
173 if (thisObject
->symbolTableGet(propertyName
, slot
))
177 if (JSValue value
= thisObject
->getDirect(exec
->vm(), propertyName
, attributes
)) {
178 slot
.setValue(thisObject
, attributes
, value
);
182 // We don't call through to JSObject because there's no way to give an
183 // activation object getter properties or a prototype.
184 ASSERT(!thisObject
->hasGetterSetterProperties());
185 ASSERT(thisObject
->prototype().isNull());
189 void JSActivation::put(JSCell
* cell
, ExecState
* exec
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
)
191 JSActivation
* thisObject
= jsCast
<JSActivation
*>(cell
);
192 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(thisObject
));
194 if (thisObject
->symbolTablePut(exec
, propertyName
, value
, slot
.isStrictMode()))
197 // We don't call through to JSObject because __proto__ and getter/setter
198 // properties are non-standard extensions that other implementations do not
199 // expose in the activation object.
200 ASSERT(!thisObject
->hasGetterSetterProperties());
201 thisObject
->putOwnDataProperty(exec
->vm(), propertyName
, value
, slot
);
204 bool JSActivation::deleteProperty(JSCell
* cell
, ExecState
* exec
, PropertyName propertyName
)
206 if (propertyName
== exec
->propertyNames().arguments
)
209 return Base::deleteProperty(cell
, exec
, propertyName
);
212 JSValue
JSActivation::toThis(JSCell
*, ExecState
* exec
, ECMAMode ecmaMode
)
214 if (ecmaMode
== StrictMode
)
215 return jsUndefined();
216 return exec
->globalThisValue();
219 EncodedJSValue
JSActivation::argumentsGetter(ExecState
*, JSObject
* slotBase
, EncodedJSValue
, PropertyName
)
221 JSActivation
* activation
= jsCast
<JSActivation
*>(slotBase
);
222 CallFrame
* callFrame
= CallFrame::create(reinterpret_cast<Register
*>(activation
->m_registers
));
223 ASSERT(!activation
->isTornOff() && (callFrame
->codeBlock()->usesArguments() || callFrame
->codeBlock()->usesEval()));
224 if (activation
->isTornOff() || !(callFrame
->codeBlock()->usesArguments() || callFrame
->codeBlock()->usesEval()))
225 return JSValue::encode(jsUndefined());
227 VirtualRegister argumentsRegister
= callFrame
->codeBlock()->argumentsRegister();
228 if (JSValue arguments
= callFrame
->uncheckedR(argumentsRegister
.offset()).jsValue())
229 return JSValue::encode(arguments
);
230 int realArgumentsRegister
= unmodifiedArgumentsRegister(argumentsRegister
).offset();
232 JSValue arguments
= JSValue(Arguments::create(callFrame
->vm(), callFrame
));
233 callFrame
->uncheckedR(argumentsRegister
.offset()) = arguments
;
234 callFrame
->uncheckedR(realArgumentsRegister
) = arguments
;
236 ASSERT(callFrame
->uncheckedR(realArgumentsRegister
).jsValue().inherits(Arguments::info()));
237 return JSValue::encode(callFrame
->uncheckedR(realArgumentsRegister
).jsValue());