Line data Source code
1 : // Copyright 2011 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 : #include "src/contexts.h"
6 :
7 : #include "src/ast/modules.h"
8 : #include "src/bootstrapper.h"
9 : #include "src/debug/debug.h"
10 : #include "src/isolate-inl.h"
11 : #include "src/objects/module-inl.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 :
16 :
17 18128 : Handle<ScriptContextTable> ScriptContextTable::Extend(
18 : Handle<ScriptContextTable> table, Handle<Context> script_context) {
19 : Handle<ScriptContextTable> result;
20 18128 : int used = table->used();
21 : int length = table->length();
22 18128 : CHECK(used >= 0 && length > 0 && used < length);
23 18128 : if (used + kFirstContextSlotIndex == length) {
24 14193 : CHECK(length < Smi::kMaxValue / 2);
25 : Isolate* isolate = script_context->GetIsolate();
26 : Handle<FixedArray> copy =
27 14193 : isolate->factory()->CopyFixedArrayAndGrow(table, length);
28 14193 : copy->set_map(ReadOnlyRoots(isolate).script_context_table_map());
29 14193 : result = Handle<ScriptContextTable>::cast(copy);
30 : } else {
31 : result = table;
32 : }
33 : result->set_used(used + 1);
34 :
35 : DCHECK(script_context->IsScriptContext());
36 36256 : result->set(used + kFirstContextSlotIndex, *script_context);
37 18128 : return result;
38 : }
39 :
40 12045442 : bool ScriptContextTable::Lookup(Isolate* isolate,
41 : Handle<ScriptContextTable> table,
42 : Handle<String> name, LookupResult* result) {
43 51400599 : for (int i = 0; i < table->used(); i++) {
44 13748186 : Handle<Context> context = GetContext(isolate, table, i);
45 : DCHECK(context->IsScriptContext());
46 27496376 : Handle<ScopeInfo> scope_info(context->scope_info(), context->GetIsolate());
47 : int slot_index = ScopeInfo::ContextSlotIndex(
48 : scope_info, name, &result->mode, &result->init_flag,
49 13748190 : &result->maybe_assigned_flag);
50 :
51 13748191 : if (slot_index >= 0) {
52 93333 : result->context_index = i;
53 93333 : result->slot_index = slot_index;
54 93333 : return true;
55 : }
56 : }
57 : return false;
58 : }
59 :
60 :
61 412741 : bool Context::is_declaration_context() {
62 533757 : if (IsFunctionContext() || IsNativeContext() || IsScriptContext() ||
63 1459 : IsModuleContext()) {
64 : return true;
65 : }
66 1459 : if (IsEvalContext()) {
67 133 : return scope_info()->language_mode() == LanguageMode::kStrict;
68 : }
69 1326 : if (!IsBlockContext()) return false;
70 966 : return scope_info()->is_declaration_scope();
71 : }
72 :
73 410149 : Context Context::declaration_context() {
74 410149 : Context current = *this;
75 820845 : while (!current->is_declaration_context()) {
76 547 : current = current->previous();
77 : }
78 410149 : return current;
79 : }
80 :
81 54630 : Context Context::closure_context() {
82 54630 : Context current = *this;
83 208166 : while (!current->IsFunctionContext() && !current->IsScriptContext() &&
84 75323 : !current->IsModuleContext() && !current->IsNativeContext() &&
85 4161 : !current->IsEvalContext()) {
86 4131 : current = current->previous();
87 : }
88 54630 : return current;
89 : }
90 :
91 12773998 : JSObject Context::extension_object() {
92 : DCHECK(IsNativeContext() || IsFunctionContext() || IsBlockContext() ||
93 : IsEvalContext() || IsCatchContext());
94 12773998 : HeapObject object = extension();
95 12773998 : if (object->IsTheHole()) return JSObject();
96 : DCHECK(object->IsJSContextExtensionObject() ||
97 : (IsNativeContext() && object->IsJSGlobalObject()));
98 : return JSObject::cast(object);
99 : }
100 :
101 16988792 : JSReceiver Context::extension_receiver() {
102 : DCHECK(IsNativeContext() || IsWithContext() || IsEvalContext() ||
103 : IsFunctionContext() || IsBlockContext());
104 29488598 : return IsWithContext() ? JSReceiver::cast(extension()) : extension_object();
105 : }
106 :
107 23142019 : ScopeInfo Context::scope_info() {
108 23142025 : return ScopeInfo::cast(get(SCOPE_INFO_INDEX));
109 : }
110 :
111 1980 : Module Context::module() {
112 1980 : Context current = *this;
113 3962 : while (!current->IsModuleContext()) {
114 2 : current = current->previous();
115 : }
116 3960 : return Module::cast(current->extension());
117 : }
118 :
119 20884195 : JSGlobalObject Context::global_object() {
120 41768387 : return JSGlobalObject::cast(native_context()->extension());
121 : }
122 :
123 0 : Context Context::script_context() {
124 0 : Context current = *this;
125 0 : while (!current->IsScriptContext()) {
126 0 : current = current->previous();
127 : }
128 0 : return current;
129 : }
130 :
131 2658535 : JSGlobalProxy Context::global_proxy() {
132 2658535 : return native_context()->global_proxy_object();
133 : }
134 :
135 91851 : void Context::set_global_proxy(JSGlobalProxy object) {
136 91851 : native_context()->set_global_proxy_object(object);
137 91851 : }
138 :
139 : /**
140 : * Lookups a property in an object environment, taking the unscopables into
141 : * account. This is used For HasBinding spec algorithms for ObjectEnvironment.
142 : */
143 2241673 : static Maybe<bool> UnscopableLookup(LookupIterator* it) {
144 : Isolate* isolate = it->isolate();
145 :
146 2241673 : Maybe<bool> found = JSReceiver::HasProperty(it);
147 4483310 : if (found.IsNothing() || !found.FromJust()) return found;
148 :
149 : Handle<Object> unscopables;
150 879226 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
151 : isolate, unscopables,
152 : JSReceiver::GetProperty(isolate,
153 : Handle<JSReceiver>::cast(it->GetReceiver()),
154 : isolate->factory()->unscopables_symbol()),
155 : Nothing<bool>());
156 879166 : if (!unscopables->IsJSReceiver()) return Just(true);
157 : Handle<Object> blacklist;
158 248152 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
159 : isolate, blacklist,
160 : JSReceiver::GetProperty(isolate, Handle<JSReceiver>::cast(unscopables),
161 : it->name()),
162 : Nothing<bool>());
163 248134 : return Just(!blacklist->BooleanValue(isolate));
164 : }
165 :
166 : static PropertyAttributes GetAttributesForMode(VariableMode mode) {
167 : DCHECK(IsDeclaredVariableMode(mode));
168 1689999 : return mode == VariableMode::kConst ? READ_ONLY : NONE;
169 : }
170 :
171 : // static
172 6536634 : Handle<Object> Context::Lookup(Handle<Context> context, Handle<String> name,
173 : ContextLookupFlags flags, int* index,
174 : PropertyAttributes* attributes,
175 : InitializationFlag* init_flag,
176 : VariableMode* variable_mode,
177 : bool* is_sloppy_function_name) {
178 : Isolate* isolate = context->GetIsolate();
179 :
180 6536634 : bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
181 : bool failed_whitelist = false;
182 6536634 : *index = kNotFound;
183 6536634 : *attributes = ABSENT;
184 6536634 : *init_flag = kCreatedInitialized;
185 6536634 : *variable_mode = VariableMode::kVar;
186 6536634 : if (is_sloppy_function_name != nullptr) {
187 2669759 : *is_sloppy_function_name = false;
188 : }
189 :
190 : if (FLAG_trace_contexts) {
191 : PrintF("Context::Lookup(");
192 : name->ShortPrint();
193 : PrintF(")\n");
194 : }
195 :
196 3985817 : do {
197 : if (FLAG_trace_contexts) {
198 : PrintF(" - looking in context %p",
199 : reinterpret_cast<void*>(context->ptr()));
200 : if (context->IsScriptContext()) PrintF(" (script context)");
201 : if (context->IsNativeContext()) PrintF(" (native context)");
202 : PrintF("\n");
203 : }
204 :
205 : // 1. Check global objects, subjects of with, and extension objects.
206 : DCHECK_IMPLIES(context->IsEvalContext(),
207 : context->extension()->IsTheHole(isolate));
208 30655972 : if ((context->IsNativeContext() || context->IsWithContext() ||
209 34678352 : context->IsFunctionContext() || context->IsBlockContext()) &&
210 20452033 : !context->extension_receiver().is_null()) {
211 13532122 : Handle<JSReceiver> object(context->extension_receiver(), isolate);
212 :
213 13532122 : if (context->IsNativeContext()) {
214 : if (FLAG_trace_contexts) {
215 : PrintF(" - trying other script contexts\n");
216 : }
217 : // Try other script contexts.
218 : Handle<ScriptContextTable> script_contexts(
219 8039360 : context->global_object()->native_context()->script_context_table(),
220 8039360 : isolate);
221 : ScriptContextTable::LookupResult r;
222 4019680 : if (ScriptContextTable::Lookup(isolate, script_contexts, name, &r)) {
223 : if (FLAG_trace_contexts) {
224 : Handle<Context> c = ScriptContextTable::GetContext(
225 : isolate, script_contexts, r.context_index);
226 : PrintF("=> found property in script context %d: %p\n",
227 : r.context_index, reinterpret_cast<void*>(c->ptr()));
228 : }
229 74 : *index = r.slot_index;
230 74 : *variable_mode = r.mode;
231 74 : *init_flag = r.init_flag;
232 74 : *attributes = GetAttributesForMode(r.mode);
233 : return ScriptContextTable::GetContext(isolate, script_contexts,
234 74 : r.context_index);
235 : }
236 : }
237 :
238 : // Context extension objects needs to behave as if they have no
239 : // prototype. So even if we want to follow prototype chains, we need
240 : // to only do a local lookup for context extension objects.
241 : Maybe<PropertyAttributes> maybe = Nothing<PropertyAttributes>();
242 20297961 : if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
243 19521621 : object->IsJSContextExtensionObject()) {
244 622167 : maybe = JSReceiver::GetOwnPropertyAttributes(object, name);
245 6143820 : } else if (context->IsWithContext()) {
246 : // A with context will never bind "this", but debug-eval may look into
247 : // a with context when resolving "this". Other synthetic variables such
248 : // as new.target may be resolved as VariableMode::kDynamicLocal due to
249 : // bug v8:5405 , skipping them here serves as a workaround until a more
250 : // thorough fix can be applied.
251 : // TODO(v8:5405): Replace this check with a DCHECK when resolution of
252 : // of synthetic variables does not go through this code path.
253 2241817 : if (ScopeInfo::VariableIsSynthetic(*name)) {
254 : maybe = Just(ABSENT);
255 : } else {
256 2241673 : LookupIterator it(object, name, object);
257 2241673 : Maybe<bool> found = UnscopableLookup(&it);
258 2241673 : if (found.IsNothing()) {
259 : maybe = Nothing<PropertyAttributes>();
260 : } else {
261 : // Luckily, consumers of |maybe| only care whether the property
262 : // was absent or not, so we can return a dummy |NONE| value
263 : // for its attributes when it was present.
264 2241598 : maybe = Just(found.FromJust() ? NONE : ABSENT);
265 : }
266 : }
267 : } else {
268 3902003 : maybe = JSReceiver::GetPropertyAttributes(object, name);
269 : }
270 :
271 6765987 : if (maybe.IsNothing()) return Handle<Object>();
272 : DCHECK(!isolate->has_pending_exception());
273 6765912 : *attributes = maybe.FromJust();
274 :
275 6765912 : if (maybe.FromJust() != ABSENT) {
276 : if (FLAG_trace_contexts) {
277 : PrintF("=> found property in context object %p\n",
278 : reinterpret_cast<void*>(object->ptr()));
279 : }
280 3649425 : return object;
281 : }
282 : }
283 :
284 : // 2. Check the context proper if it has slots.
285 18736678 : if (context->IsFunctionContext() || context->IsBlockContext() ||
286 14928697 : context->IsScriptContext() || context->IsEvalContext() ||
287 12145357 : context->IsModuleContext() || context->IsCatchContext()) {
288 : // Use serialized scope information of functions and blocks to search
289 : // for the context index.
290 7613664 : Handle<ScopeInfo> scope_info(context->scope_info(), isolate);
291 : VariableMode mode;
292 : InitializationFlag flag;
293 : MaybeAssignedFlag maybe_assigned_flag;
294 : int slot_index = ScopeInfo::ContextSlotIndex(scope_info, name, &mode,
295 3806832 : &flag, &maybe_assigned_flag);
296 : DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
297 3806832 : if (slot_index >= 0) {
298 : if (FLAG_trace_contexts) {
299 : PrintF("=> found local in context slot %d (mode = %hhu)\n",
300 : slot_index, static_cast<uint8_t>(mode));
301 : }
302 1689735 : *index = slot_index;
303 1689735 : *variable_mode = mode;
304 1689735 : *init_flag = flag;
305 1689735 : *attributes = GetAttributesForMode(mode);
306 1689735 : return context;
307 : }
308 :
309 : // Check the slot corresponding to the intermediate context holding
310 : // only the function name variable. It's conceptually (and spec-wise)
311 : // in an outer scope of the function's declaration scope.
312 3946008 : if (follow_context_chain && context->IsFunctionContext()) {
313 1824857 : int function_index = scope_info->FunctionContextSlotIndex(*name);
314 1824857 : if (function_index >= 0) {
315 : if (FLAG_trace_contexts) {
316 : PrintF("=> found intermediate function in context slot %d\n",
317 : function_index);
318 : }
319 162 : *index = function_index;
320 162 : *attributes = READ_ONLY;
321 162 : *init_flag = kCreatedInitialized;
322 162 : *variable_mode = VariableMode::kConst;
323 486 : if (is_sloppy_function_name != nullptr &&
324 306 : is_sloppy(scope_info->language_mode())) {
325 72 : *is_sloppy_function_name = true;
326 : }
327 162 : return context;
328 : }
329 : }
330 :
331 : // Lookup variable in module imports and exports.
332 2116935 : if (context->IsModuleContext()) {
333 : VariableMode mode;
334 : InitializationFlag flag;
335 : MaybeAssignedFlag maybe_assigned_flag;
336 : int cell_index =
337 285 : scope_info->ModuleIndex(name, &mode, &flag, &maybe_assigned_flag);
338 285 : if (cell_index != 0) {
339 : if (FLAG_trace_contexts) {
340 : PrintF("=> found in module imports or exports\n");
341 : }
342 235 : *index = cell_index;
343 235 : *variable_mode = mode;
344 235 : *init_flag = flag;
345 235 : *attributes = ModuleDescriptor::GetCellIndexKind(cell_index) ==
346 : ModuleDescriptor::kExport
347 190 : ? GetAttributesForMode(mode)
348 470 : : READ_ONLY;
349 470 : return handle(context->module(), isolate);
350 : }
351 : }
352 2777922 : } else if (context->IsDebugEvaluateContext()) {
353 : // Check materialized locals.
354 23666 : Object ext = context->get(EXTENSION_INDEX);
355 11833 : if (ext->IsJSReceiver()) {
356 : Handle<JSReceiver> extension(JSReceiver::cast(ext), isolate);
357 11521 : LookupIterator it(extension, name, extension);
358 11521 : Maybe<bool> found = JSReceiver::HasProperty(&it);
359 11521 : if (found.FromMaybe(false)) {
360 6185 : *attributes = NONE;
361 6185 : return extension;
362 : }
363 : }
364 : // Check the original context, but do not follow its context chain.
365 11296 : Object obj = context->get(WRAPPED_CONTEXT_INDEX);
366 5648 : if (obj->IsContext()) {
367 : Handle<Context> context(Context::cast(obj), isolate);
368 : Handle<Object> result =
369 : Context::Lookup(context, name, DONT_FOLLOW_CHAINS, index,
370 892 : attributes, init_flag, variable_mode);
371 892 : if (!result.is_null()) return result;
372 : }
373 : // Check whitelist. Names that do not pass whitelist shall only resolve
374 : // to with, script or native contexts up the context chain.
375 9950 : obj = context->get(WHITE_LIST_INDEX);
376 4975 : if (obj->IsStringSet()) {
377 : failed_whitelist =
378 9308 : failed_whitelist || !StringSet::cast(obj)->Has(isolate, name);
379 : }
380 : }
381 :
382 : // 3. Prepare to continue with the previous (next outermost) context.
383 9775528 : if (context->IsNativeContext()) break;
384 :
385 7967314 : do {
386 7971844 : context = Handle<Context>(context->previous(), isolate);
387 : // If we come across a whitelist context, and the name is not
388 : // whitelisted, then only consider with, script, module or native
389 : // contexts.
390 3999103 : } while (failed_whitelist && !context->IsScriptContext() &&
391 7976245 : !context->IsNativeContext() && !context->IsWithContext() &&
392 3986062 : !context->IsModuleContext());
393 : } while (follow_context_chain);
394 :
395 : if (FLAG_trace_contexts) {
396 : PrintF("=> no property/slot found\n");
397 : }
398 : return Handle<Object>::null();
399 : }
400 :
401 453664 : void Context::AddOptimizedCode(Code code) {
402 : DCHECK(IsNativeContext());
403 : DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
404 : DCHECK(code->next_code_link()->IsUndefined());
405 453665 : code->set_next_code_link(get(OPTIMIZED_CODE_LIST));
406 : set(OPTIMIZED_CODE_LIST, code, UPDATE_WEAK_WRITE_BARRIER);
407 453665 : }
408 :
409 323437 : void Context::SetOptimizedCodeListHead(Object head) {
410 : DCHECK(IsNativeContext());
411 : set(OPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
412 323437 : }
413 :
414 108816 : Object Context::OptimizedCodeListHead() {
415 : DCHECK(IsNativeContext());
416 108816 : return get(OPTIMIZED_CODE_LIST);
417 : }
418 :
419 327589 : void Context::SetDeoptimizedCodeListHead(Object head) {
420 : DCHECK(IsNativeContext());
421 : set(DEOPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
422 327589 : }
423 :
424 468905 : Object Context::DeoptimizedCodeListHead() {
425 : DCHECK(IsNativeContext());
426 468905 : return get(DEOPTIMIZED_CODE_LIST);
427 : }
428 :
429 73 : Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() {
430 : Isolate* isolate = GetIsolate();
431 73 : Handle<Object> result(error_message_for_code_gen_from_strings(), isolate);
432 146 : if (!result->IsUndefined(isolate)) return result;
433 : return isolate->factory()->NewStringFromStaticChars(
434 68 : "Code generation from strings disallowed for this context");
435 : }
436 :
437 : #define COMPARE_NAME(index, type, name) \
438 : if (string->IsOneByteEqualTo(StaticCharVector(#name))) return index;
439 :
440 0 : int Context::IntrinsicIndexForName(Handle<String> string) {
441 0 : NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME);
442 0 : return kNotFound;
443 : }
444 :
445 : #undef COMPARE_NAME
446 :
447 : #define COMPARE_NAME(index, type, name) \
448 : if (strncmp(string, #name, length) == 0) return index;
449 :
450 50 : int Context::IntrinsicIndexForName(const unsigned char* unsigned_string,
451 : int length) {
452 : const char* string = reinterpret_cast<const char*>(unsigned_string);
453 50 : NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME);
454 45 : return kNotFound;
455 : }
456 :
457 : #undef COMPARE_NAME
458 :
459 : #ifdef DEBUG
460 :
461 : bool Context::IsBootstrappingOrNativeContext(Isolate* isolate, Object object) {
462 : // During bootstrapping we allow all objects to pass as global
463 : // objects. This is necessary to fix circular dependencies.
464 : return isolate->heap()->gc_state() != Heap::NOT_IN_GC ||
465 : isolate->bootstrapper()->IsActive() || object->IsNativeContext();
466 : }
467 :
468 : bool Context::IsBootstrappingOrValidParentContext(Object object,
469 : Context child) {
470 : // During bootstrapping we allow all objects to pass as
471 : // contexts. This is necessary to fix circular dependencies.
472 : if (child->GetIsolate()->bootstrapper()->IsActive()) return true;
473 : if (!object->IsContext()) return false;
474 : Context context = Context::cast(object);
475 : return context->IsNativeContext() || context->IsScriptContext() ||
476 : context->IsModuleContext() || !child->IsModuleContext();
477 : }
478 :
479 : #endif
480 :
481 91891 : void Context::ResetErrorsThrown() {
482 : DCHECK(IsNativeContext());
483 91891 : set_errors_thrown(Smi::FromInt(0));
484 91891 : }
485 :
486 1158981 : void Context::IncrementErrorsThrown() {
487 : DCHECK(IsNativeContext());
488 :
489 2317962 : int previous_value = errors_thrown()->value();
490 2317962 : set_errors_thrown(Smi::FromInt(previous_value + 1));
491 1158981 : }
492 :
493 214 : int Context::GetErrorsThrown() { return errors_thrown()->value(); }
494 :
495 : STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4);
496 : STATIC_ASSERT(NativeContext::kScopeInfoOffset ==
497 : Context::OffsetOfElementAt(NativeContext::SCOPE_INFO_INDEX));
498 : STATIC_ASSERT(NativeContext::kPreviousOffset ==
499 : Context::OffsetOfElementAt(NativeContext::PREVIOUS_INDEX));
500 : STATIC_ASSERT(NativeContext::kExtensionOffset ==
501 : Context::OffsetOfElementAt(NativeContext::EXTENSION_INDEX));
502 : STATIC_ASSERT(NativeContext::kNativeContextOffset ==
503 : Context::OffsetOfElementAt(NativeContext::NATIVE_CONTEXT_INDEX));
504 :
505 : STATIC_ASSERT(NativeContext::kStartOfStrongFieldsOffset ==
506 : Context::OffsetOfElementAt(0));
507 : STATIC_ASSERT(NativeContext::kStartOfWeakFieldsOffset ==
508 : Context::OffsetOfElementAt(NativeContext::FIRST_WEAK_SLOT));
509 : STATIC_ASSERT(NativeContext::kMicrotaskQueueOffset ==
510 : Context::SizeFor(NativeContext::NATIVE_CONTEXT_SLOTS));
511 : STATIC_ASSERT(NativeContext::kSize ==
512 : (Context::SizeFor(NativeContext::NATIVE_CONTEXT_SLOTS) +
513 : kSystemPointerSize));
514 :
515 : } // namespace internal
516 183867 : } // namespace v8
|