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"
40 ASSERT_CLASS_FITS_IN_CELL(JSActivation
);
42 const ClassInfo
JSActivation::s_info
= { "JSActivation", &Base::s_info
, 0, 0, CREATE_METHOD_TABLE(JSActivation
) };
44 JSActivation::JSActivation(CallFrame
* callFrame
, FunctionExecutable
* functionExecutable
)
45 : Base(callFrame
->globalData(), callFrame
->globalData().activationStructure
.get(), functionExecutable
->symbolTable(), callFrame
->registers())
46 , m_numCapturedArgs(max(callFrame
->argumentCount(), functionExecutable
->parameterCount()))
47 , m_numCapturedVars(functionExecutable
->capturedVariableCount())
49 , m_requiresDynamicChecks(functionExecutable
->usesEval() && !functionExecutable
->isStrictMode())
50 , m_argumentsRegister(functionExecutable
->generatedBytecode().argumentsRegister())
54 void JSActivation::finishCreation(CallFrame
* callFrame
)
56 Base::finishCreation(callFrame
->globalData());
57 ASSERT(inherits(&s_info
));
59 // We have to manually ref and deref the symbol table as JSVariableObject
60 // doesn't know about SharedSymbolTable
61 static_cast<SharedSymbolTable
*>(m_symbolTable
)->ref();
62 callFrame
->globalData().heap
.addFinalizer(this, &finalize
);
65 void JSActivation::finalize(JSCell
* cell
)
67 static_cast<SharedSymbolTable
*>(jsCast
<JSActivation
*>(cell
)->m_symbolTable
)->deref();
70 void JSActivation::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
72 JSActivation
* thisObject
= jsCast
<JSActivation
*>(cell
);
73 ASSERT_GC_OBJECT_INHERITS(thisObject
, &s_info
);
74 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
75 ASSERT(thisObject
->structure()->typeInfo().overridesVisitChildren());
76 Base::visitChildren(thisObject
, visitor
);
78 // No need to mark our registers if they're still in the RegisterFile.
79 WriteBarrier
<Unknown
>* registerArray
= thisObject
->m_registerArray
.get();
83 visitor
.appendValues(registerArray
, thisObject
->m_numCapturedArgs
);
85 // Skip 'this' and call frame, except for callee and scope chain.
86 int offset
= CallFrame::offsetFor(thisObject
->m_numCapturedArgs
+ 1);
87 visitor
.append(registerArray
+ offset
+ RegisterFile::ScopeChain
);
88 visitor
.append(registerArray
+ offset
+ RegisterFile::Callee
);
90 visitor
.appendValues(registerArray
+ offset
, thisObject
->m_numCapturedVars
);
93 inline bool JSActivation::symbolTableGet(const Identifier
& propertyName
, PropertySlot
& slot
)
95 SymbolTableEntry entry
= symbolTable().inlineGet(propertyName
.impl());
98 if (m_isTornOff
&& entry
.getIndex() >= m_numCapturedVars
)
101 slot
.setValue(registerAt(entry
.getIndex()).get());
105 inline bool JSActivation::symbolTablePut(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, bool shouldThrow
)
107 JSGlobalData
& globalData
= exec
->globalData();
108 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
110 SymbolTableEntry entry
= symbolTable().inlineGet(propertyName
.impl());
113 if (entry
.isReadOnly()) {
115 throwTypeError(exec
, StrictModeReadonlyPropertyWriteError
);
118 if (m_isTornOff
&& entry
.getIndex() >= m_numCapturedVars
)
121 registerAt(entry
.getIndex()).set(globalData
, this, value
);
125 void JSActivation::getOwnPropertyNames(JSObject
* object
, ExecState
* exec
, PropertyNameArray
& propertyNames
, EnumerationMode mode
)
127 JSActivation
* thisObject
= jsCast
<JSActivation
*>(object
);
128 SymbolTable::const_iterator end
= thisObject
->symbolTable().end();
129 for (SymbolTable::const_iterator it
= thisObject
->symbolTable().begin(); it
!= end
; ++it
) {
130 if (it
->second
.getAttributes() & DontEnum
&& mode
!= IncludeDontEnumProperties
)
132 if (it
->second
.getIndex() >= thisObject
->m_numCapturedVars
)
134 propertyNames
.add(Identifier(exec
, it
->first
.get()));
136 // Skip the JSVariableObject implementation of getOwnPropertyNames
137 JSObject::getOwnPropertyNames(thisObject
, exec
, propertyNames
, mode
);
140 inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData
& globalData
, const Identifier
& propertyName
, JSValue value
, unsigned attributes
)
142 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
144 SymbolTable::iterator iter
= symbolTable().find(propertyName
.impl());
145 if (iter
== symbolTable().end())
147 SymbolTableEntry
& entry
= iter
->second
;
148 ASSERT(!entry
.isNull());
149 if (entry
.getIndex() >= m_numCapturedVars
)
152 entry
.setAttributes(attributes
);
153 registerAt(entry
.getIndex()).set(globalData
, this, value
);
157 bool JSActivation::getOwnPropertySlot(JSCell
* cell
, ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
159 JSActivation
* thisObject
= jsCast
<JSActivation
*>(cell
);
160 if (propertyName
== exec
->propertyNames().arguments
) {
161 slot
.setCustom(thisObject
, thisObject
->getArgumentsGetter());
165 if (thisObject
->symbolTableGet(propertyName
, slot
))
168 if (WriteBarrierBase
<Unknown
>* location
= thisObject
->getDirectLocation(exec
->globalData(), propertyName
)) {
169 slot
.setValue(location
->get());
173 // We don't call through to JSObject because there's no way to give an
174 // activation object getter properties or a prototype.
175 ASSERT(!thisObject
->hasGetterSetterProperties());
176 ASSERT(thisObject
->prototype().isNull());
180 void JSActivation::put(JSCell
* cell
, ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
)
182 JSActivation
* thisObject
= jsCast
<JSActivation
*>(cell
);
183 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(thisObject
));
185 if (thisObject
->symbolTablePut(exec
, propertyName
, value
, slot
.isStrictMode()))
188 // We don't call through to JSObject because __proto__ and getter/setter
189 // properties are non-standard extensions that other implementations do not
190 // expose in the activation object.
191 ASSERT(!thisObject
->hasGetterSetterProperties());
192 thisObject
->putOwnDataProperty(exec
->globalData(), propertyName
, value
, slot
);
195 // FIXME: Make this function honor ReadOnly (const) and DontEnum
196 void JSActivation::putDirectVirtual(JSObject
* object
, ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, unsigned attributes
)
198 JSActivation
* thisObject
= jsCast
<JSActivation
*>(object
);
199 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(thisObject
));
201 if (thisObject
->symbolTablePutWithAttributes(exec
->globalData(), propertyName
, value
, attributes
))
204 // We don't call through to JSObject because __proto__ and getter/setter
205 // properties are non-standard extensions that other implementations do not
206 // expose in the activation object.
207 ASSERT(!thisObject
->hasGetterSetterProperties());
208 JSObject::putDirectVirtual(thisObject
, exec
, propertyName
, value
, attributes
);
211 bool JSActivation::deleteProperty(JSCell
* cell
, ExecState
* exec
, const Identifier
& propertyName
)
213 if (propertyName
== exec
->propertyNames().arguments
)
216 return Base::deleteProperty(cell
, exec
, propertyName
);
219 JSObject
* JSActivation::toThisObject(JSCell
*, ExecState
* exec
)
221 return exec
->globalThisValue();
224 JSValue
JSActivation::argumentsGetter(ExecState
*, JSValue slotBase
, const Identifier
&)
226 JSActivation
* activation
= asActivation(slotBase
);
227 CallFrame
* callFrame
= CallFrame::create(reinterpret_cast<Register
*>(activation
->m_registers
));
228 int argumentsRegister
= activation
->m_argumentsRegister
;
229 if (JSValue arguments
= callFrame
->uncheckedR(argumentsRegister
).jsValue())
231 int realArgumentsRegister
= unmodifiedArgumentsRegister(argumentsRegister
);
233 JSValue arguments
= JSValue(Arguments::create(callFrame
->globalData(), callFrame
));
234 callFrame
->uncheckedR(argumentsRegister
) = arguments
;
235 callFrame
->uncheckedR(realArgumentsRegister
) = arguments
;
237 ASSERT(callFrame
->uncheckedR(realArgumentsRegister
).jsValue().inherits(&Arguments::s_info
));
238 return callFrame
->uncheckedR(realArgumentsRegister
).jsValue();
241 // These two functions serve the purpose of isolating the common case from a
244 PropertySlot::GetValueFunc
JSActivation::getArgumentsGetter()
246 return argumentsGetter
;