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