2 * Copyright (C) 2008, 2009, 2014, 2015 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 "JSLexicalEnvironment.h"
32 #include "Interpreter.h"
33 #include "JSFunction.h"
34 #include "JSCInlines.h"
40 const ClassInfo
JSLexicalEnvironment::s_info
= { "JSLexicalEnvironment", &Base::s_info
, 0, CREATE_METHOD_TABLE(JSLexicalEnvironment
) };
42 inline bool JSLexicalEnvironment::symbolTableGet(PropertyName propertyName
, PropertySlot
& slot
)
44 SymbolTableEntry entry
= symbolTable()->inlineGet(propertyName
.uid());
48 ScopeOffset offset
= entry
.scopeOffset();
50 // Defend against the inspector asking for a var after it has been optimized out.
54 slot
.setValue(this, DontEnum
, variableAt(offset
).get());
58 inline bool JSLexicalEnvironment::symbolTableGet(PropertyName propertyName
, PropertyDescriptor
& descriptor
)
60 SymbolTableEntry entry
= symbolTable()->inlineGet(propertyName
.uid());
64 ScopeOffset offset
= entry
.scopeOffset();
66 // Defend against the inspector asking for a var after it has been optimized out.
70 descriptor
.setDescriptor(variableAt(offset
).get(), entry
.getAttributes());
74 inline bool JSLexicalEnvironment::symbolTablePut(ExecState
* exec
, PropertyName propertyName
, JSValue value
, bool shouldThrow
)
77 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
79 WriteBarrierBase
<Unknown
>* reg
;
82 GCSafeConcurrentJITLocker
locker(symbolTable()->m_lock
, exec
->vm().heap
);
83 SymbolTable::Map::iterator iter
= symbolTable()->find(locker
, propertyName
.uid());
84 if (iter
== symbolTable()->end(locker
))
86 ASSERT(!iter
->value
.isNull());
87 if (iter
->value
.isReadOnly()) {
89 throwTypeError(exec
, StrictModeReadonlyPropertyWriteError
);
92 ScopeOffset offset
= iter
->value
.scopeOffset();
93 // Defend against the inspector asking for a var after it has been optimized out.
96 set
= iter
->value
.watchpointSet();
97 reg
= &variableAt(offset
);
99 reg
->set(vm
, this, value
);
101 set
->invalidate(VariableWriteFireDetail(this, propertyName
)); // Don't mess around - if we had found this statically, we would have invalidated it.
105 void JSLexicalEnvironment::getOwnNonIndexPropertyNames(JSObject
* object
, ExecState
* exec
, PropertyNameArray
& propertyNames
, EnumerationMode mode
)
107 JSLexicalEnvironment
* thisObject
= jsCast
<JSLexicalEnvironment
*>(object
);
110 ConcurrentJITLocker
locker(thisObject
->symbolTable()->m_lock
);
111 SymbolTable::Map::iterator end
= thisObject
->symbolTable()->end(locker
);
112 for (SymbolTable::Map::iterator it
= thisObject
->symbolTable()->begin(locker
); it
!= end
; ++it
) {
113 if (it
->value
.getAttributes() & DontEnum
&& !mode
.includeDontEnumProperties())
115 if (!thisObject
->isValid(it
->value
.scopeOffset()))
117 if (it
->key
->isSymbol() && !mode
.includeSymbolProperties())
119 propertyNames
.add(Identifier::fromUid(exec
, it
->key
.get()));
122 // Skip the JSEnvironmentRecord implementation of getOwnNonIndexPropertyNames
123 JSObject::getOwnNonIndexPropertyNames(thisObject
, exec
, propertyNames
, mode
);
126 inline bool JSLexicalEnvironment::symbolTablePutWithAttributes(VM
& vm
, PropertyName propertyName
, JSValue value
, unsigned attributes
)
128 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
130 WriteBarrierBase
<Unknown
>* reg
;
132 ConcurrentJITLocker
locker(symbolTable()->m_lock
);
133 SymbolTable::Map::iterator iter
= symbolTable()->find(locker
, propertyName
.uid());
134 if (iter
== symbolTable()->end(locker
))
136 SymbolTableEntry
& entry
= iter
->value
;
137 ASSERT(!entry
.isNull());
139 ScopeOffset offset
= entry
.scopeOffset();
140 if (!isValid(offset
))
143 entry
.setAttributes(attributes
);
144 reg
= &variableAt(offset
);
146 reg
->set(vm
, this, value
);
150 bool JSLexicalEnvironment::getOwnPropertySlot(JSObject
* object
, ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
152 JSLexicalEnvironment
* thisObject
= jsCast
<JSLexicalEnvironment
*>(object
);
154 if (thisObject
->symbolTableGet(propertyName
, slot
))
158 if (JSValue value
= thisObject
->getDirect(exec
->vm(), propertyName
, attributes
)) {
159 slot
.setValue(thisObject
, attributes
, value
);
163 // We don't call through to JSObject because there's no way to give a
164 // lexical environment object getter properties or a prototype.
165 ASSERT(!thisObject
->hasGetterSetterProperties());
166 ASSERT(thisObject
->prototype().isNull());
170 void JSLexicalEnvironment::put(JSCell
* cell
, ExecState
* exec
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
)
172 JSLexicalEnvironment
* thisObject
= jsCast
<JSLexicalEnvironment
*>(cell
);
173 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(thisObject
));
175 if (thisObject
->symbolTablePut(exec
, propertyName
, value
, slot
.isStrictMode()))
178 // We don't call through to JSObject because __proto__ and getter/setter
179 // properties are non-standard extensions that other implementations do not
180 // expose in the lexicalEnvironment object.
181 ASSERT(!thisObject
->hasGetterSetterProperties());
182 thisObject
->putOwnDataProperty(exec
->vm(), propertyName
, value
, slot
);
185 bool JSLexicalEnvironment::deleteProperty(JSCell
* cell
, ExecState
* exec
, PropertyName propertyName
)
187 if (propertyName
== exec
->propertyNames().arguments
)
190 return Base::deleteProperty(cell
, exec
, propertyName
);
193 JSValue
JSLexicalEnvironment::toThis(JSCell
*, ExecState
* exec
, ECMAMode ecmaMode
)
195 if (ecmaMode
== StrictMode
)
196 return jsUndefined();
197 return exec
->globalThisValue();