]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/JSLexicalEnvironment.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / JSLexicalEnvironment.cpp
1 /*
2 * Copyright (C) 2008, 2009, 2014, 2015 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 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 "JSLexicalEnvironment.h"
31
32 #include "Interpreter.h"
33 #include "JSFunction.h"
34 #include "JSCInlines.h"
35
36 using namespace std;
37
38 namespace JSC {
39
40 const ClassInfo JSLexicalEnvironment::s_info = { "JSLexicalEnvironment", &Base::s_info, 0, CREATE_METHOD_TABLE(JSLexicalEnvironment) };
41
42 inline bool JSLexicalEnvironment::symbolTableGet(PropertyName propertyName, PropertySlot& slot)
43 {
44 SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.uid());
45 if (entry.isNull())
46 return false;
47
48 ScopeOffset offset = entry.scopeOffset();
49
50 // Defend against the inspector asking for a var after it has been optimized out.
51 if (!isValid(offset))
52 return false;
53
54 slot.setValue(this, DontEnum, variableAt(offset).get());
55 return true;
56 }
57
58 inline bool JSLexicalEnvironment::symbolTableGet(PropertyName propertyName, PropertyDescriptor& descriptor)
59 {
60 SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.uid());
61 if (entry.isNull())
62 return false;
63
64 ScopeOffset offset = entry.scopeOffset();
65
66 // Defend against the inspector asking for a var after it has been optimized out.
67 if (!isValid(offset))
68 return false;
69
70 descriptor.setDescriptor(variableAt(offset).get(), entry.getAttributes());
71 return true;
72 }
73
74 inline bool JSLexicalEnvironment::symbolTablePut(ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrow)
75 {
76 VM& vm = exec->vm();
77 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
78
79 WriteBarrierBase<Unknown>* reg;
80 WatchpointSet* set;
81 {
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))
85 return false;
86 ASSERT(!iter->value.isNull());
87 if (iter->value.isReadOnly()) {
88 if (shouldThrow)
89 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
90 return true;
91 }
92 ScopeOffset offset = iter->value.scopeOffset();
93 // Defend against the inspector asking for a var after it has been optimized out.
94 if (!isValid(offset))
95 return false;
96 set = iter->value.watchpointSet();
97 reg = &variableAt(offset);
98 }
99 reg->set(vm, this, value);
100 if (set)
101 set->invalidate(VariableWriteFireDetail(this, propertyName)); // Don't mess around - if we had found this statically, we would have invalidated it.
102 return true;
103 }
104
105 void JSLexicalEnvironment::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
106 {
107 JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(object);
108
109 {
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())
114 continue;
115 if (!thisObject->isValid(it->value.scopeOffset()))
116 continue;
117 if (it->key->isSymbol() && !mode.includeSymbolProperties())
118 continue;
119 propertyNames.add(Identifier::fromUid(exec, it->key.get()));
120 }
121 }
122 // Skip the JSEnvironmentRecord implementation of getOwnNonIndexPropertyNames
123 JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
124 }
125
126 inline bool JSLexicalEnvironment::symbolTablePutWithAttributes(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
127 {
128 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
129
130 WriteBarrierBase<Unknown>* reg;
131 {
132 ConcurrentJITLocker locker(symbolTable()->m_lock);
133 SymbolTable::Map::iterator iter = symbolTable()->find(locker, propertyName.uid());
134 if (iter == symbolTable()->end(locker))
135 return false;
136 SymbolTableEntry& entry = iter->value;
137 ASSERT(!entry.isNull());
138
139 ScopeOffset offset = entry.scopeOffset();
140 if (!isValid(offset))
141 return false;
142
143 entry.setAttributes(attributes);
144 reg = &variableAt(offset);
145 }
146 reg->set(vm, this, value);
147 return true;
148 }
149
150 bool JSLexicalEnvironment::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
151 {
152 JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(object);
153
154 if (thisObject->symbolTableGet(propertyName, slot))
155 return true;
156
157 unsigned attributes;
158 if (JSValue value = thisObject->getDirect(exec->vm(), propertyName, attributes)) {
159 slot.setValue(thisObject, attributes, value);
160 return true;
161 }
162
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());
167 return false;
168 }
169
170 void JSLexicalEnvironment::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
171 {
172 JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(cell);
173 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
174
175 if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode()))
176 return;
177
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);
183 }
184
185 bool JSLexicalEnvironment::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
186 {
187 if (propertyName == exec->propertyNames().arguments)
188 return false;
189
190 return Base::deleteProperty(cell, exec, propertyName);
191 }
192
193 JSValue JSLexicalEnvironment::toThis(JSCell*, ExecState* exec, ECMAMode ecmaMode)
194 {
195 if (ecmaMode == StrictMode)
196 return jsUndefined();
197 return exec->globalThisValue();
198 }
199
200 } // namespace JSC