1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef V8_OBJECTS_CONTEXTS_INL_H_
6 #define V8_OBJECTS_CONTEXTS_INL_H_
7
8 #include "src/heap/heap-write-barrier.h"
9 #include "src/objects/contexts.h"
10 #include "src/objects/dictionary-inl.h"
11 #include "src/objects/fixed-array-inl.h"
12 #include "src/objects/js-function-inl.h"
13 #include "src/objects/js-objects-inl.h"
14 #include "src/objects/map-inl.h"
15 #include "src/objects/objects-inl.h"
16 #include "src/objects/ordered-hash-table-inl.h"
17 #include "src/objects/osr-optimized-code-cache-inl.h"
18 #include "src/objects/regexp-match-info.h"
19 #include "src/objects/scope-info.h"
20 #include "src/objects/shared-function-info.h"
21
22 // Has to be the last include (doesn't have include guards):
23 #include "src/objects/object-macros.h"
24
25 namespace v8 {
26 namespace internal {
27
OBJECT_CONSTRUCTORS_IMPL(ScriptContextTable,FixedArray)28 OBJECT_CONSTRUCTORS_IMPL(ScriptContextTable, FixedArray)
29 CAST_ACCESSOR(ScriptContextTable)
30
31 int ScriptContextTable::synchronized_used() const {
32 return Smi::ToInt(synchronized_get(kUsedSlotIndex));
33 }
34
synchronized_set_used(int used)35 void ScriptContextTable::synchronized_set_used(int used) {
36 synchronized_set(kUsedSlotIndex, Smi::FromInt(used));
37 }
38
39 // static
GetContext(Isolate * isolate,Handle<ScriptContextTable> table,int i)40 Handle<Context> ScriptContextTable::GetContext(Isolate* isolate,
41 Handle<ScriptContextTable> table,
42 int i) {
43 return handle(table->get_context(i), isolate);
44 }
45
get_context(int i)46 Context ScriptContextTable::get_context(int i) const {
47 DCHECK_LT(i, synchronized_used());
48 return Context::cast(this->get(i + kFirstContextSlotIndex));
49 }
50
OBJECT_CONSTRUCTORS_IMPL(Context,HeapObject)51 OBJECT_CONSTRUCTORS_IMPL(Context, HeapObject)
52 NEVER_READ_ONLY_SPACE_IMPL(Context)
53 CAST_ACCESSOR(Context)
54
55 SMI_ACCESSORS(Context, length, kLengthOffset)
56 CAST_ACCESSOR(NativeContext)
57
58 Object Context::get(int index) const {
59 IsolateRoot isolate = GetIsolateForPtrCompr(*this);
60 return get(isolate, index);
61 }
62
get(IsolateRoot isolate,int index)63 Object Context::get(IsolateRoot isolate, int index) const {
64 DCHECK_LT(static_cast<unsigned>(index),
65 static_cast<unsigned>(this->length()));
66 return TaggedField<Object>::Relaxed_Load(isolate, *this,
67 OffsetOfElementAt(index));
68 }
69
set(int index,Object value)70 void Context::set(int index, Object value) {
71 DCHECK_LT(static_cast<unsigned>(index),
72 static_cast<unsigned>(this->length()));
73 int offset = OffsetOfElementAt(index);
74 RELAXED_WRITE_FIELD(*this, offset, value);
75 WRITE_BARRIER(*this, offset, value);
76 }
77
set(int index,Object value,WriteBarrierMode mode)78 void Context::set(int index, Object value, WriteBarrierMode mode) {
79 DCHECK_LT(static_cast<unsigned>(index),
80 static_cast<unsigned>(this->length()));
81 int offset = OffsetOfElementAt(index);
82 RELAXED_WRITE_FIELD(*this, offset, value);
83 CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode);
84 }
85
set_scope_info(ScopeInfo scope_info)86 void Context::set_scope_info(ScopeInfo scope_info) {
87 set(SCOPE_INFO_INDEX, scope_info);
88 }
89
synchronized_get(int index)90 Object Context::synchronized_get(int index) const {
91 IsolateRoot isolate = GetIsolateForPtrCompr(*this);
92 return synchronized_get(isolate, index);
93 }
94
synchronized_get(IsolateRoot isolate,int index)95 Object Context::synchronized_get(IsolateRoot isolate, int index) const {
96 DCHECK_LT(static_cast<unsigned int>(index),
97 static_cast<unsigned int>(this->length()));
98 return ACQUIRE_READ_FIELD(*this, OffsetOfElementAt(index));
99 }
100
synchronized_set(int index,Object value)101 void Context::synchronized_set(int index, Object value) {
102 DCHECK_LT(static_cast<unsigned int>(index),
103 static_cast<unsigned int>(this->length()));
104 const int offset = OffsetOfElementAt(index);
105 RELEASE_WRITE_FIELD(*this, offset, value);
106 WRITE_BARRIER(*this, offset, value);
107 }
108
unchecked_previous()109 Object Context::unchecked_previous() { return get(PREVIOUS_INDEX); }
110
previous()111 Context Context::previous() {
112 Object result = get(PREVIOUS_INDEX);
113 DCHECK(IsBootstrappingOrValidParentContext(result, *this));
114 return Context::unchecked_cast(result);
115 }
set_previous(Context context)116 void Context::set_previous(Context context) { set(PREVIOUS_INDEX, context); }
117
next_context_link()118 Object Context::next_context_link() { return get(Context::NEXT_CONTEXT_LINK); }
119
has_extension()120 bool Context::has_extension() {
121 return scope_info().HasContextExtensionSlot() && !extension().IsUndefined();
122 }
123
extension()124 HeapObject Context::extension() {
125 DCHECK(scope_info().HasContextExtensionSlot());
126 return HeapObject::cast(get(EXTENSION_INDEX));
127 }
128
set_extension(HeapObject object)129 void Context::set_extension(HeapObject object) {
130 DCHECK(scope_info().HasContextExtensionSlot());
131 set(EXTENSION_INDEX, object);
132 }
133
native_context()134 NativeContext Context::native_context() const {
135 return this->map().native_context();
136 }
137
IsFunctionContext()138 bool Context::IsFunctionContext() const {
139 return map().instance_type() == FUNCTION_CONTEXT_TYPE;
140 }
141
IsCatchContext()142 bool Context::IsCatchContext() const {
143 return map().instance_type() == CATCH_CONTEXT_TYPE;
144 }
145
IsWithContext()146 bool Context::IsWithContext() const {
147 return map().instance_type() == WITH_CONTEXT_TYPE;
148 }
149
IsDebugEvaluateContext()150 bool Context::IsDebugEvaluateContext() const {
151 return map().instance_type() == DEBUG_EVALUATE_CONTEXT_TYPE;
152 }
153
IsAwaitContext()154 bool Context::IsAwaitContext() const {
155 return map().instance_type() == AWAIT_CONTEXT_TYPE;
156 }
157
IsBlockContext()158 bool Context::IsBlockContext() const {
159 return map().instance_type() == BLOCK_CONTEXT_TYPE;
160 }
161
IsModuleContext()162 bool Context::IsModuleContext() const {
163 return map().instance_type() == MODULE_CONTEXT_TYPE;
164 }
165
IsEvalContext()166 bool Context::IsEvalContext() const {
167 return map().instance_type() == EVAL_CONTEXT_TYPE;
168 }
169
IsScriptContext()170 bool Context::IsScriptContext() const {
171 return map().instance_type() == SCRIPT_CONTEXT_TYPE;
172 }
173
HasSameSecurityTokenAs(Context that)174 bool Context::HasSameSecurityTokenAs(Context that) const {
175 return this->native_context().security_token() ==
176 that.native_context().security_token();
177 }
178
179 #define NATIVE_CONTEXT_FIELD_ACCESSORS(index, type, name) \
180 void Context::set_##name(type value) { \
181 DCHECK(IsNativeContext()); \
182 set(index, value); \
183 } \
184 bool Context::is_##name(type value) const { \
185 DCHECK(IsNativeContext()); \
186 return type::cast(get(index)) == value; \
187 } \
188 type Context::name() const { \
189 DCHECK(IsNativeContext()); \
190 return type::cast(get(index)); \
191 }
NATIVE_CONTEXT_FIELDS(NATIVE_CONTEXT_FIELD_ACCESSORS)192 NATIVE_CONTEXT_FIELDS(NATIVE_CONTEXT_FIELD_ACCESSORS)
193 #undef NATIVE_CONTEXT_FIELD_ACCESSORS
194
195 #define CHECK_FOLLOWS2(v1, v2) STATIC_ASSERT((v1 + 1) == (v2))
196 #define CHECK_FOLLOWS4(v1, v2, v3, v4) \
197 CHECK_FOLLOWS2(v1, v2); \
198 CHECK_FOLLOWS2(v2, v3); \
199 CHECK_FOLLOWS2(v3, v4)
200
201 int Context::FunctionMapIndex(LanguageMode language_mode, FunctionKind kind,
202 bool has_shared_name, bool needs_home_object) {
203 if (IsClassConstructor(kind)) {
204 // Like the strict function map, but with no 'name' accessor. 'name'
205 // needs to be the last property and it is added during instantiation,
206 // in case a static property with the same name exists"
207 return CLASS_FUNCTION_MAP_INDEX;
208 }
209
210 int base = 0;
211 if (IsGeneratorFunction(kind)) {
212 CHECK_FOLLOWS4(GENERATOR_FUNCTION_MAP_INDEX,
213 GENERATOR_FUNCTION_WITH_NAME_MAP_INDEX,
214 GENERATOR_FUNCTION_WITH_HOME_OBJECT_MAP_INDEX,
215 GENERATOR_FUNCTION_WITH_NAME_AND_HOME_OBJECT_MAP_INDEX);
216 CHECK_FOLLOWS4(
217 ASYNC_GENERATOR_FUNCTION_MAP_INDEX,
218 ASYNC_GENERATOR_FUNCTION_WITH_NAME_MAP_INDEX,
219 ASYNC_GENERATOR_FUNCTION_WITH_HOME_OBJECT_MAP_INDEX,
220 ASYNC_GENERATOR_FUNCTION_WITH_NAME_AND_HOME_OBJECT_MAP_INDEX);
221
222 base = IsAsyncFunction(kind) ? ASYNC_GENERATOR_FUNCTION_MAP_INDEX
223 : GENERATOR_FUNCTION_MAP_INDEX;
224
225 } else if (IsAsyncFunction(kind) || IsAsyncModule(kind)) {
226 CHECK_FOLLOWS4(ASYNC_FUNCTION_MAP_INDEX, ASYNC_FUNCTION_WITH_NAME_MAP_INDEX,
227 ASYNC_FUNCTION_WITH_HOME_OBJECT_MAP_INDEX,
228 ASYNC_FUNCTION_WITH_NAME_AND_HOME_OBJECT_MAP_INDEX);
229
230 base = ASYNC_FUNCTION_MAP_INDEX;
231
232 } else if (IsStrictFunctionWithoutPrototype(kind)) {
233 DCHECK_IMPLIES(IsArrowFunction(kind), !needs_home_object);
234 CHECK_FOLLOWS4(STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
235 METHOD_WITH_NAME_MAP_INDEX,
236 METHOD_WITH_HOME_OBJECT_MAP_INDEX,
237 METHOD_WITH_NAME_AND_HOME_OBJECT_MAP_INDEX);
238
239 base = STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX;
240
241 } else {
242 DCHECK(!needs_home_object);
243 CHECK_FOLLOWS2(SLOPPY_FUNCTION_MAP_INDEX,
244 SLOPPY_FUNCTION_WITH_NAME_MAP_INDEX);
245 CHECK_FOLLOWS2(STRICT_FUNCTION_MAP_INDEX,
246 STRICT_FUNCTION_WITH_NAME_MAP_INDEX);
247
248 base = is_strict(language_mode) ? STRICT_FUNCTION_MAP_INDEX
249 : SLOPPY_FUNCTION_MAP_INDEX;
250 }
251 int offset = static_cast<int>(!has_shared_name) |
252 (static_cast<int>(needs_home_object) << 1);
253 DCHECK_EQ(0, offset & ~3);
254
255 return base + offset;
256 }
257
258 #undef CHECK_FOLLOWS2
259 #undef CHECK_FOLLOWS4
260
GetInitialJSArrayMap(ElementsKind kind)261 Map Context::GetInitialJSArrayMap(ElementsKind kind) const {
262 DCHECK(IsNativeContext());
263 if (!IsFastElementsKind(kind)) return Map();
264 DisallowHeapAllocation no_gc;
265 Object const initial_js_array_map = get(Context::ArrayMapIndex(kind));
266 DCHECK(!initial_js_array_map.IsUndefined());
267 return Map::cast(initial_js_array_map);
268 }
269
DEF_GETTER(NativeContext,microtask_queue,MicrotaskQueue *)270 DEF_GETTER(NativeContext, microtask_queue, MicrotaskQueue*) {
271 return reinterpret_cast<MicrotaskQueue*>(ReadExternalPointerField(
272 kMicrotaskQueueOffset, isolate, kNativeContextMicrotaskQueueTag));
273 }
274
AllocateExternalPointerEntries(Isolate * isolate)275 void NativeContext::AllocateExternalPointerEntries(Isolate* isolate) {
276 InitExternalPointerField(kMicrotaskQueueOffset, isolate);
277 }
278
set_microtask_queue(Isolate * isolate,MicrotaskQueue * microtask_queue)279 void NativeContext::set_microtask_queue(Isolate* isolate,
280 MicrotaskQueue* microtask_queue) {
281 WriteExternalPointerField(kMicrotaskQueueOffset, isolate,
282 reinterpret_cast<Address>(microtask_queue),
283 kNativeContextMicrotaskQueueTag);
284 }
285
synchronized_set_script_context_table(ScriptContextTable script_context_table)286 void NativeContext::synchronized_set_script_context_table(
287 ScriptContextTable script_context_table) {
288 synchronized_set(SCRIPT_CONTEXT_TABLE_INDEX, script_context_table);
289 }
290
synchronized_script_context_table()291 ScriptContextTable NativeContext::synchronized_script_context_table() const {
292 return ScriptContextTable::cast(synchronized_get(SCRIPT_CONTEXT_TABLE_INDEX));
293 }
294
GetOSROptimizedCodeCache()295 OSROptimizedCodeCache NativeContext::GetOSROptimizedCodeCache() {
296 return OSROptimizedCodeCache::cast(osr_code_cache());
297 }
298
299 OBJECT_CONSTRUCTORS_IMPL(NativeContext, Context)
300
301 } // namespace internal
302 } // namespace v8
303
304 #include "src/objects/object-macros-undef.h"
305
306 #endif // V8_OBJECTS_CONTEXTS_INL_H_
307