v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
contexts.cc
Go to the documentation of this file.
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
6
7#include <bit>
8#include <limits>
9#include <optional>
10
11#include "src/ast/modules.h"
12#include "src/common/globals.h"
13#include "src/debug/debug.h"
15#include "src/flags/flags.h"
24
25namespace v8::internal {
26
27// static
29 int capacity,
30 AllocationType allocation) {
31 DCHECK_GE(capacity, 0);
32 DCHECK_LE(capacity, kMaxCapacity);
33
34 auto names = NameToIndexHashTable::New(isolate, 16);
35
36 std::optional<DisallowGarbageCollection> no_gc;
38 Allocate(isolate, capacity, &no_gc, allocation);
39 result->set_length(0, kReleaseStore);
40 result->set_names_to_context_index(*names);
41 ReadOnlyRoots roots{isolate};
42 MemsetTagged(result->RawFieldOfFirstElement(), roots.undefined_value(),
43 capacity);
44 return result;
45}
46
47namespace {
48
49// Adds local names from `script_context` to the hash table.
50Handle<NameToIndexHashTable> AddLocalNamesFromContext(
51 Isolate* isolate, Handle<NameToIndexHashTable> names_table,
52 DirectHandle<Context> script_context, bool ignore_duplicates,
53 int script_context_index) {
54 ReadOnlyRoots roots(isolate);
55 DirectHandle<ScopeInfo> scope_info(script_context->scope_info(), isolate);
56 int local_count = scope_info->ContextLocalCount();
57 names_table = names_table->EnsureCapacity(isolate, names_table, local_count);
58
59 for (auto it : ScopeInfo::IterateLocalNames(scope_info)) {
60 DirectHandle<Name> name(it->name(), isolate);
61 if (ignore_duplicates) {
62 int32_t hash = NameToIndexShape::Hash(roots, name);
63 if (names_table->FindEntry(isolate, roots, name, hash).is_found()) {
64 continue;
65 }
66 }
67 names_table = NameToIndexHashTable::Add(isolate, names_table, name,
68 script_context_index);
69 }
70
71 return names_table;
72}
73
74} // namespace
75
77 Isolate* isolate, Handle<ScriptContextTable> table,
78 DirectHandle<Context> script_context, bool ignore_duplicates) {
79 DCHECK(script_context->IsScriptContext());
80
81 int old_length = table->length(kAcquireLoad);
82 int new_length = old_length + 1;
83 DCHECK_LE(0, old_length);
84
86 int old_capacity = table->capacity();
87 DCHECK_LE(old_length, old_capacity);
88 if (old_length == old_capacity) {
89 int new_capacity = NewCapacityForIndex(old_length, old_capacity);
90 auto new_table = New(isolate, new_capacity);
91 new_table->set_length(old_length, kReleaseStore);
92 new_table->set_names_to_context_index(table->names_to_context_index());
93 CopyElements(isolate, *new_table, 0, *table, 0, old_length);
94 result = new_table;
95 }
96
97 Handle<NameToIndexHashTable> names_table(result->names_to_context_index(),
98 isolate);
99 names_table = AddLocalNamesFromContext(isolate, names_table, script_context,
100 ignore_duplicates, old_length);
101 result->set_names_to_context_index(*names_table);
102
103 result->set(old_length, *script_context, kReleaseStore);
104 result->set_length(new_length, kReleaseStore);
105 return result;
106}
107
109 Tagged<ScopeInfo> scope_info = this->scope_info();
110 int header = scope_info->ContextHeaderLength();
111 for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
112 if (scope_info->ContextLocalInitFlag(var) == kNeedsInitialization) {
113 set(header + var, ReadOnlyRoots(isolate).the_hole_value());
114 }
115 }
116}
117
121 int index = names_to_context_index()->Lookup(name);
122 if (index == -1) return false;
123 DCHECK_LE(0, index);
125 Tagged<Context> context = get(index);
126 DCHECK(context->IsScriptContext());
127 int slot_index = context->scope_info()->ContextSlotIndex(name, result);
128 if (slot_index < 0) return false;
129 result->context_index = index;
130 result->slot_index = slot_index;
131 return true;
132}
133
135 if (IsFunctionContext() || IsNativeContext(*this) || IsScriptContext() ||
136 IsModuleContext()) {
137 return true;
138 }
139 if (IsEvalContext()) {
140 return scope_info()->language_mode() == LanguageMode::kStrict;
141 }
142 if (!IsBlockContext()) return false;
143 return scope_info()->is_declaration_scope();
144}
145
147 Tagged<Context> current = *this;
148 while (!current->is_declaration_context()) {
149 current = current->previous();
150 }
151 return current;
152}
153
155 Tagged<Context> current = *this;
156 while (!current->IsFunctionContext() && !current->IsScriptContext() &&
157 !current->IsModuleContext() && !IsNativeContext(current) &&
158 !current->IsEvalContext()) {
159 current = current->previous();
160 }
161 return current;
162}
163
165 DCHECK(IsNativeContext(*this) || IsFunctionContext() || IsBlockContext() ||
167 Tagged<HeapObject> object = extension();
168 if (IsUndefined(object)) return JSObject();
169 DCHECK(IsJSContextExtensionObject(object) ||
170 (IsNativeContext(*this) && IsJSGlobalObject(object)));
171 return Cast<JSObject>(object);
172}
173
179
181 Tagged<Context> current = *this;
182 while (!current->IsModuleContext()) {
183 current = current->previous();
184 }
185 return Cast<SourceTextModule>(current->extension());
186}
187
191
193 Tagged<Context> current = *this;
194 while (!current->IsScriptContext()) {
195 current = current->previous();
196 }
197 return current;
198}
199
201 return native_context()->global_proxy_object();
202}
203
208static Maybe<bool> UnscopableLookup(LookupIterator* it, bool is_with_context) {
209 Isolate* isolate = it->isolate();
210
212 if (!is_with_context || found.IsNothing() || !found.FromJust()) return found;
213
214 DirectHandle<Object> unscopables;
216 isolate, unscopables,
217 JSReceiver::GetProperty(isolate, Cast<JSReceiver>(it->GetReceiver()),
218 isolate->factory()->unscopables_symbol()),
219 Nothing<bool>());
220 if (!IsJSReceiver(*unscopables)) return Just(true);
221 DirectHandle<Object> blocklist;
223 isolate, blocklist,
224 JSReceiver::GetProperty(isolate, Cast<JSReceiver>(unscopables),
225 it->name()),
226 Nothing<bool>());
227 return Just(!Object::BooleanValue(*blocklist, isolate));
228}
229
234
235// static
237 ContextLookupFlags flags, int* index,
238 PropertyAttributes* attributes,
239 InitializationFlag* init_flag,
240 VariableMode* variable_mode,
241 bool* is_sloppy_function_name) {
242 Isolate* isolate = context->GetIsolate();
243
244 bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
245 bool has_seen_debug_evaluate_context = false;
246 *index = kNotFound;
247 *attributes = ABSENT;
248 *init_flag = kCreatedInitialized;
249 *variable_mode = VariableMode::kVar;
250 if (is_sloppy_function_name != nullptr) {
251 *is_sloppy_function_name = false;
252 }
253
254 if (v8_flags.trace_contexts) {
255 PrintF("Context::Lookup(");
256 ShortPrint(*name);
257 PrintF(")\n");
258 }
259
260 do {
261 if (v8_flags.trace_contexts) {
262 PrintF(" - looking in context %p",
263 reinterpret_cast<void*>(context->ptr()));
264 if (context->IsScriptContext()) PrintF(" (script context)");
265 if (IsNativeContext(*context)) PrintF(" (native context)");
266 if (context->IsDebugEvaluateContext()) PrintF(" (debug context)");
267 PrintF("\n");
268 }
269
270 // 1. Check global objects, subjects of with, and extension objects.
271 DCHECK_IMPLIES(context->IsEvalContext() && context->has_extension(),
272 IsTheHole(context->extension(), isolate));
273 if ((IsNativeContext(*context) || context->IsWithContext() ||
274 context->IsFunctionContext() || context->IsBlockContext()) &&
275 context->has_extension() && !context->extension_receiver().is_null()) {
276 Handle<JSReceiver> object(context->extension_receiver(), isolate);
277
278 if (IsNativeContext(*context)) {
280 if (v8_flags.trace_contexts) {
281 PrintF(" - trying other script contexts\n");
282 }
283 // Try other script contexts.
284 Tagged<ScriptContextTable> script_contexts =
285 context->native_context()->script_context_table();
287 if (script_contexts->Lookup(name, &r)) {
289 script_contexts->get(r.context_index);
290 if (v8_flags.trace_contexts) {
291 PrintF("=> found property in script context %d: %p\n",
292 r.context_index,
293 reinterpret_cast<void*>(script_context.ptr()));
294 }
295 *index = r.slot_index;
296 *variable_mode = r.mode;
297 *init_flag = r.init_flag;
298 *attributes = GetAttributesForMode(r.mode);
299 return handle(script_context, isolate);
300 }
301 }
302
303 // Context extension objects needs to behave as if they have no
304 // prototype. So even if we want to follow prototype chains, we need
305 // to only do a local lookup for context extension objects.
307 if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
308 IsJSContextExtensionObject(*object)) {
309 maybe = JSReceiver::GetOwnPropertyAttributes(isolate, object, name);
310 } else {
311 // A with context will never bind "this", but debug-eval may look into
312 // a with context when resolving "this". Other synthetic variables such
313 // as new.target may be resolved as VariableMode::kDynamicLocal due to
314 // bug v8:5405 , skipping them here serves as a workaround until a more
315 // thorough fix can be applied.
316 // TODO(v8:5405): Replace this check with a DCHECK when resolution of
317 // of synthetic variables does not go through this code path.
319 maybe = Just(ABSENT);
320 } else {
321 LookupIterator it(isolate, object, name, object);
322 Maybe<bool> found = UnscopableLookup(&it, context->IsWithContext());
323 if (found.IsNothing()) {
325 } else {
326 // Luckily, consumers of |maybe| only care whether the property
327 // was absent or not, so we can return a dummy |NONE| value
328 // for its attributes when it was present.
329 maybe = Just(found.FromJust() ? NONE : ABSENT);
330 }
331 }
332 }
333
334 if (maybe.IsNothing()) return Handle<Object>();
335 DCHECK(!isolate->has_exception());
336 *attributes = maybe.FromJust();
337
338 if (maybe.FromJust() != ABSENT) {
339 if (v8_flags.trace_contexts) {
340 PrintF("=> found property in context object %p\n",
341 reinterpret_cast<void*>(object->ptr()));
342 }
343 return object;
344 }
345 }
346
347 // 2. Check the context proper if it has slots.
348 if (context->IsFunctionContext() || context->IsBlockContext() ||
349 context->IsScriptContext() || context->IsEvalContext() ||
350 context->IsModuleContext() || context->IsCatchContext()) {
352 // Use serialized scope information of functions and blocks to search
353 // for the context index.
354 Tagged<ScopeInfo> scope_info = context->scope_info();
355 VariableLookupResult lookup_result;
356 int slot_index = scope_info->ContextSlotIndex(name, &lookup_result);
357 DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
358 if (slot_index >= 0) {
359 // Re-direct lookup to the ScriptContextTable in case we find a hole in
360 // a REPL script context. REPL scripts allow re-declaration of
361 // script-level let bindings. The value itself is stored in the script
362 // context of the first script that declared a variable, all other
363 // script contexts will contain 'the hole' for that particular name.
364 if (scope_info->IsReplModeScope() &&
365 IsTheHole(context->get(slot_index), isolate)) {
366 context = Handle<Context>(context->previous(), isolate);
367 continue;
368 }
369
370 if (v8_flags.trace_contexts) {
371 PrintF("=> found local in context slot %d (mode = %hhu)\n",
372 slot_index, static_cast<uint8_t>(lookup_result.mode));
373 }
374 *index = slot_index;
375 *variable_mode = lookup_result.mode;
376 *init_flag = lookup_result.init_flag;
377 *attributes = GetAttributesForMode(lookup_result.mode);
378 return context;
379 }
380
381 // Check the slot corresponding to the intermediate context holding
382 // only the function name variable. It's conceptually (and spec-wise)
383 // in an outer scope of the function's declaration scope.
384 if (follow_context_chain && context->IsFunctionContext()) {
385 int function_index = scope_info->FunctionContextSlotIndex(*name);
386 if (function_index >= 0) {
387 if (v8_flags.trace_contexts) {
388 PrintF("=> found intermediate function in context slot %d\n",
389 function_index);
390 }
391 *index = function_index;
392 *attributes = READ_ONLY;
393 *init_flag = kCreatedInitialized;
394 *variable_mode = VariableMode::kConst;
395 if (is_sloppy_function_name != nullptr &&
396 is_sloppy(scope_info->language_mode())) {
397 *is_sloppy_function_name = true;
398 }
399 return context;
400 }
401 }
402
403 // Lookup variable in module imports and exports.
404 if (context->IsModuleContext()) {
407 MaybeAssignedFlag maybe_assigned_flag;
408 int cell_index =
409 scope_info->ModuleIndex(*name, &mode, &flag, &maybe_assigned_flag);
410 if (cell_index != 0) {
411 if (v8_flags.trace_contexts) {
412 PrintF("=> found in module imports or exports\n");
413 }
414 *index = cell_index;
415 *variable_mode = mode;
416 *init_flag = flag;
420 : READ_ONLY;
421 return handle(context->module(), isolate);
422 }
423 }
424 } else if (context->IsDebugEvaluateContext()) {
425 has_seen_debug_evaluate_context = true;
426
427 // Check materialized locals.
428 Tagged<Object> ext = context->get(EXTENSION_INDEX);
429 if (IsJSReceiver(ext)) {
431 LookupIterator it(isolate, extension, name, extension);
433 if (found.FromMaybe(false)) {
434 *attributes = NONE;
435 return extension;
436 }
437 }
438
439 // Check the original context, but do not follow its context chain.
440 Tagged<Object> obj = context->get(WRAPPED_CONTEXT_INDEX);
441 if (IsContext(obj)) {
442 Handle<Context> wrapped_context(Cast<Context>(obj), isolate);
444 Context::Lookup(wrapped_context, name, DONT_FOLLOW_CHAINS, index,
445 attributes, init_flag, variable_mode);
446 if (!result.is_null()) return result;
447 }
448 }
449
450 // 3. Prepare to continue with the previous (next outermost) context.
451 if (IsNativeContext(*context)) break;
452
453 // In case we saw any DebugEvaluateContext, we'll need to check the block
454 // list before we can advance to properly "shadow" stack-allocated
455 // variables.
456 // Note that this implicitly skips the block list check for the
457 // "wrapped" context lookup for DebugEvaluateContexts. In that case
458 // `has_seen_debug_evaluate_context` will always be false.
459 if (has_seen_debug_evaluate_context &&
460 IsEphemeronHashTable(isolate->heap()->locals_block_list_cache())) {
461 DirectHandle<ScopeInfo> scope_info =
462 direct_handle(context->scope_info(), isolate);
463 Tagged<Object> maybe_outer_block_list =
464 isolate->LocalsBlockListCacheGet(scope_info);
465 if (IsStringSet(maybe_outer_block_list) &&
466 Cast<StringSet>(maybe_outer_block_list)->Has(isolate, name)) {
467 if (v8_flags.trace_contexts) {
468 PrintF(" - name is blocklisted. Aborting.\n");
469 }
470 break;
471 }
472 }
473
474 context = Handle<Context>(context->previous(), isolate);
475 } while (follow_context_chain);
476
477 if (v8_flags.trace_contexts) {
478 PrintF("=> no property/slot found\n");
479 }
480 return Handle<Object>::null();
481}
482
484 DirectHandle<Context> script_context, size_t index,
485 ContextSidePropertyCell::Property property, Isolate* isolate) {
486 DCHECK(v8_flags.script_context_mutable_heap_number ||
487 v8_flags.const_tracking_let);
488 DCHECK(script_context->IsScriptContext());
490 int side_data_index =
491 static_cast<int>(index - Context::MIN_CONTEXT_EXTENDED_SLOTS);
492 DirectHandle<FixedArray> side_data(
494 isolate);
495 Tagged<Object> object = side_data->get(side_data_index);
496 if (!IsContextSidePropertyCell(object)) {
497 // If these CHECKs fail, there's a code path which initializes or assigns a
498 // top-level `let` variable but doesn't update the side data.
499 object = *isolate->factory()->NewContextSidePropertyCell(property);
500 side_data->set(side_data_index, object);
501 }
502 return Cast<ContextSidePropertyCell>(object);
503}
504
505std::optional<ContextSidePropertyCell::Property>
507 DCHECK(v8_flags.script_context_mutable_heap_number ||
508 v8_flags.const_tracking_let);
510 int side_data_index =
511 static_cast<int>(index - Context::MIN_CONTEXT_EXTENDED_SLOTS);
512 Tagged<FixedArray> side_data =
514 Tagged<Object> object = side_data->get(side_data_index);
515 if (IsUndefined(object)) return {};
516 if (IsContextSidePropertyCell(object)) {
517 return Cast<ContextSidePropertyCell>(object)->context_side_property();
518 }
519 CHECK(IsSmi(object));
520 return ContextSidePropertyCell::FromSmi(object.ToSmi());
521}
522
523namespace {
524std::optional<int32_t> DoubleFitsInInt32(double value) {
525 constexpr double int32_min = std::numeric_limits<int32_t>::min();
526 constexpr double int32_max = std::numeric_limits<int32_t>::max();
527 // Check -0.0 first.
528 if (value == 0.0 && std::signbit(value)) return {};
529 double trunc_value = std::trunc(value);
530 if (int32_min <= value && value <= int32_max && value == trunc_value) {
531 return static_cast<int32_t>(trunc_value);
532 }
533 return {};
534}
535
536DirectHandle<Object> TryLoadMutableHeapNumber(
537 DirectHandle<Context> script_context, int index, DirectHandle<Object> value,
538 Isolate* isolate) {
539 DCHECK(v8_flags.script_context_mutable_heap_number);
540 DCHECK(script_context->IsScriptContext());
541 if (!IsHeapNumber(*value)) return value;
542 const int side_data_index = index - Context::MIN_CONTEXT_EXTENDED_SLOTS;
543 Tagged<FixedArray> side_data_table = Cast<FixedArray>(
544 script_context->get(Context::CONTEXT_SIDE_TABLE_PROPERTY_INDEX));
545 if (side_data_table == ReadOnlyRoots(isolate).empty_fixed_array()) {
546 // No side data (maybe the context was created while the side data
547 // collection was disabled).
548 return value;
549 }
550
551 Tagged<Object> data = side_data_table->get(side_data_index);
553 if (IsSmi(data)) {
554 property =
555 static_cast<ContextSidePropertyCell::Property>(data.ToSmi().value());
556 } else if (Is<ContextSidePropertyCell>(data)) {
557 property = Cast<ContextSidePropertyCell>(data)->context_side_property();
558 } else {
559 // We should not reach this point. The debugger has updated the value
560 // without updating the side data table. Fall back to other. There is also
561 // no dependent code to this cell, since this is not a
562 // ContextSidePropertyCell.
564 side_data_table->set(side_data_index, Smi::FromInt(property));
565 }
567 int32_t int32_value =
568 static_cast<int32_t>(Cast<HeapNumber>(*value)->value_as_bits());
569 return isolate->factory()->NewHeapNumber(static_cast<double>(int32_value));
570 } else if (property == ContextSidePropertyCell::kMutableHeapNumber) {
571 return isolate->factory()->NewHeapNumber(Cast<HeapNumber>(*value)->value());
572 } else {
573 return value;
574 }
575}
576} // namespace
577
579 DirectHandle<Context> script_context, int index, DirectHandle<Object> value,
580 Isolate* isolate) {
581 DCHECK(v8_flags.script_context_mutable_heap_number);
582 DCHECK(script_context->IsScriptContext());
583 return TryLoadMutableHeapNumber(script_context, index, value, isolate);
584}
585
587 DirectHandle<Context> script_context, int index,
588 DirectHandle<Object> new_value, Isolate* isolate) {
589 DCHECK(v8_flags.script_context_mutable_heap_number ||
590 v8_flags.const_tracking_let);
591 DCHECK(script_context->IsScriptContext());
592
593 const int side_data_index = index - Context::MIN_CONTEXT_EXTENDED_SLOTS;
594 DirectHandle<FixedArray> side_data(
597 isolate);
598 if (*side_data == ReadOnlyRoots(isolate).empty_fixed_array()) {
599 // No side data (maybe the context was created while the side data
600 // collection was disabled).
601 script_context->set(index, *new_value);
602 return;
603 }
604
605 DirectHandle<Object> old_value(script_context->get(index), isolate);
606 if (IsTheHole(*old_value)) {
607 // Setting the initial value. Here we cannot assert the corresponding side
608 // data is `undefined` - that won't hold w/ variable redefinitions in REPL.
609 script_context->set(index, *new_value);
610 side_data->set(side_data_index, ContextSidePropertyCell::Const());
611 return;
612 }
613
614 // If we are assigning the same value, the property won't change.
615 if (*old_value == *new_value) {
616 return;
617 }
618 // If both values are HeapNumbers with the same double value, the property
619 // won't change either.
620 if (Is<HeapNumber>(*old_value) && Is<HeapNumber>(*new_value)) {
621 double old_number = Cast<HeapNumber>(*old_value)->value();
622 double new_number = Cast<HeapNumber>(*new_value)->value();
623 if (old_number == new_number && old_number != 0) {
624 return;
625 }
626 }
627
628 // From now on, we know the value is no longer a constant.
629
630 Tagged<Object> data = side_data->get(side_data_index);
631 std::optional<Tagged<ContextSidePropertyCell>> maybe_cell;
633
634 if (IsSmi(data)) {
635 property = ContextSidePropertyCell::FromSmi(data.ToSmi());
636 } else {
638 maybe_cell = Cast<ContextSidePropertyCell>(data);
639 property = maybe_cell.value()->context_side_property();
640 }
641
642 switch (property) {
644 if (maybe_cell) {
646 isolate, maybe_cell.value(),
648 }
649 if (v8_flags.script_context_mutable_heap_number) {
650 // It can transition to Smi, MutableInt32, MutableHeapNumber or Other.
651 if (IsHeapNumber(*new_value)) {
652 double double_value = Cast<HeapNumber>(*new_value)->value();
653 auto maybe_int32_value = DoubleFitsInInt32(double_value);
654 if (v8_flags.script_context_mutable_heap_int32 && maybe_int32_value) {
655 auto new_number =
656 isolate->factory()->NewHeapInt32(*maybe_int32_value);
657 script_context->set(index, *new_number);
658 side_data->set(side_data_index,
660 } else {
661 auto new_number = isolate->factory()->NewHeapNumber(double_value);
662 script_context->set(index, *new_number);
663 side_data->set(side_data_index,
665 }
666 } else {
667 script_context->set(index, *new_value);
668 side_data->set(side_data_index,
669 IsSmi(*new_value)
672 }
673 } else {
674 // MutableHeapNumber is not supported, just transition the property to
675 // kOther.
676 script_context->set(index, *new_value);
677 side_data->set(side_data_index, ContextSidePropertyCell::Other());
678 }
679
680 break;
682 if (IsSmi(*new_value)) {
683 script_context->set(index, *new_value);
684 } else {
685 if (maybe_cell) {
687 isolate, maybe_cell.value(),
689 }
690 // It can transition to MutableInt32, MutableHeapNumber or Other.
691 if (IsHeapNumber(*new_value)) {
692 double double_value = Cast<HeapNumber>(*new_value)->value();
693 auto maybe_int32_value = DoubleFitsInInt32(double_value);
694 if (v8_flags.script_context_mutable_heap_int32 && maybe_int32_value) {
695 auto new_number =
696 isolate->factory()->NewHeapInt32(*maybe_int32_value);
697 script_context->set(index, *new_number);
698 side_data->set(side_data_index,
700 } else {
701 auto new_number = isolate->factory()->NewHeapNumber(double_value);
702 script_context->set(index, *new_number);
703 side_data->set(side_data_index,
705 }
706 } else {
707 script_context->set(index, *new_value);
708 side_data->set(side_data_index, ContextSidePropertyCell::Other());
709 }
710 }
711 break;
713 CHECK(IsHeapNumber(*old_value));
714 DirectHandle<HeapNumber> old_number = Cast<HeapNumber>(old_value);
715 if (IsSmi(*new_value)) {
716 old_number->set_value_as_bits(
717 (static_cast<uint64_t>(kHoleNanUpper32) << 32) |
718 Cast<Smi>(*new_value).value());
719 } else if (IsHeapNumber(*new_value)) {
720 double double_value = Cast<HeapNumber>(*new_value)->value();
721 auto maybe_int32_value = DoubleFitsInInt32(double_value);
722 if (v8_flags.script_context_mutable_heap_int32 && maybe_int32_value) {
723 old_number->set_value_as_bits(
724 (static_cast<uint64_t>(kHoleNanUpper32) << 32) |
725 *maybe_int32_value);
726 } else {
727 if (maybe_cell) {
729 isolate, maybe_cell.value(),
731 }
732 old_number->set_value(double_value);
733 side_data->set(side_data_index,
735 }
736 } else {
737 if (maybe_cell) {
739 isolate, maybe_cell.value(),
741 }
742 // It can only transition to Other.
743 script_context->set(index, *new_value);
744 side_data->set(side_data_index, ContextSidePropertyCell::Other());
745 }
746 break;
747 }
749 CHECK(IsHeapNumber(*old_value));
750 if (IsSmi(*new_value)) {
751 Cast<HeapNumber>(old_value)->set_value(
752 static_cast<double>(Cast<Smi>(*new_value).value()));
753 } else if (IsHeapNumber(*new_value)) {
754 Cast<HeapNumber>(old_value)->set_value(
755 Cast<HeapNumber>(*new_value)->value());
756 } else {
757 if (maybe_cell) {
759 isolate, maybe_cell.value(),
761 }
762 // It can only transition to Other.
763 script_context->set(index, *new_value);
764 side_data->set(side_data_index, ContextSidePropertyCell::Other());
765 }
766 break;
768 // We should not have a code depending on Other.
769 DCHECK(!maybe_cell.has_value());
770 // No need to update side data, this is a sink state...
771 script_context->set(index, *new_value);
772 break;
773 default:
774 UNREACHABLE();
775 }
776}
777
779 return array->map() == js_array_template_literal_object_map();
780}
781
783 Isolate* isolate = GetIsolate();
784 Handle<Object> result(error_message_for_code_gen_from_strings(), isolate);
785 if (!IsUndefined(*result, isolate)) return result;
786 return isolate->factory()->NewStringFromStaticChars(
787 "Code generation from strings disallowed for this context");
788}
789
791 Isolate* isolate = GetIsolate();
792 DirectHandle<Object> result(error_message_for_wasm_code_gen(), isolate);
793 if (!IsUndefined(*result, isolate)) return result;
794 return isolate->factory()->NewStringFromStaticChars(
795 "Wasm code generation disallowed by embedder");
796}
797
798#ifdef VERIFY_HEAP
799namespace {
800// TODO(v8:12298): Fix js-context-specialization cctests to set up full
801// native contexts instead of using dummy internalized strings as
802// extensions.
803bool IsContexExtensionTestObject(Tagged<HeapObject> extension) {
804 return IsInternalizedString(extension) &&
805 Cast<String>(extension)->length() == 1;
806}
807} // namespace
808
809void Context::VerifyExtensionSlot(Tagged<HeapObject> extension) {
810 CHECK(scope_info()->HasContextExtensionSlot());
811 // Early exit for potentially uninitialized contexfts.
812 if (IsUndefined(extension)) return;
813 if (IsJSContextExtensionObject(extension)) {
814 CHECK((IsBlockContext() && scope_info()->is_declaration_scope()) ||
816 } else if (IsModuleContext()) {
817 CHECK(IsSourceTextModule(extension));
818 } else if (IsDebugEvaluateContext() || IsWithContext()) {
819 CHECK(IsJSReceiver(extension) ||
820 (IsWithContext() && IsContexExtensionTestObject(extension)));
821 } else if (IsNativeContext(*this)) {
822 CHECK(IsJSGlobalObject(extension) ||
823 IsContexExtensionTestObject(extension));
824 } else if (IsScriptContext()) {
825 // Host-defined options can be stored on the context for classic scripts.
826 CHECK(IsFixedArray(extension));
827 }
828}
829#endif // VERIFY_HEAP
830
832 DCHECK(scope_info()->HasContextExtensionSlot());
833#ifdef VERIFY_HEAP
834 if (v8_flags.verify_heap) VerifyExtensionSlot(object);
835#endif
836 set(EXTENSION_INDEX, object, mode);
837}
838
839#ifdef DEBUG
840
841bool Context::IsBootstrappingOrValidParentContext(Tagged<Object> object,
842 Tagged<Context> child) {
843 // During bootstrapping we allow all objects to pass as
844 // contexts. This is necessary to fix circular dependencies.
845 if (child->GetIsolate()->bootstrapper()->IsActive()) return true;
846 if (!IsContext(object)) return false;
847 Tagged<Context> context = Cast<Context>(object);
848 return IsNativeContext(context) || context->IsScriptContext() ||
849 context->IsModuleContext() || !child->IsModuleContext();
850}
851
852#endif
853
854void NativeContext::ResetErrorsThrown() { set_errors_thrown(Smi::FromInt(0)); }
855
857 int previous_value = errors_thrown().value();
858 set_errors_thrown(Smi::FromInt(previous_value + 1));
859}
860
861int NativeContext::GetErrorsThrown() { return errors_thrown().value(); }
862
863static_assert(Context::MIN_CONTEXT_SLOTS == 2);
864static_assert(Context::MIN_CONTEXT_EXTENDED_SLOTS == 3);
865static_assert(NativeContext::kScopeInfoOffset ==
867static_assert(NativeContext::kPreviousOffset ==
869static_assert(NativeContext::kExtensionOffset ==
871
872static_assert(NativeContext::kStartOfStrongFieldsOffset ==
874static_assert(NativeContext::kStartOfWeakFieldsOffset ==
876static_assert(NativeContext::kMicrotaskQueueOffset ==
878static_assert(NativeContext::kSize ==
881
882#ifdef V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS
883void NativeContext::RunPromiseHook(PromiseHookType type,
885 DirectHandle<Object> parent) {
886 Isolate* isolate = promise->GetIsolate();
887 DCHECK(isolate->HasContextPromiseHooks());
888 int contextSlot;
889
890 switch (type) {
892 contextSlot = PROMISE_HOOK_INIT_FUNCTION_INDEX;
893 break;
895 contextSlot = PROMISE_HOOK_RESOLVE_FUNCTION_INDEX;
896 break;
898 contextSlot = PROMISE_HOOK_BEFORE_FUNCTION_INDEX;
899 break;
901 contextSlot = PROMISE_HOOK_AFTER_FUNCTION_INDEX;
902 break;
903 default:
904 UNREACHABLE();
905 }
906
907 DirectHandle<Object> hook(isolate->native_context()->get(contextSlot),
908 isolate);
909 if (IsUndefined(*hook)) return;
910
911 size_t argc = type == PromiseHookType::kInit ? 2 : 1;
912 DirectHandle<Object> argv[2] = {Cast<Object>(promise), parent};
913
914 DirectHandle<Object> receiver = isolate->global_proxy();
915
916 StackLimitCheck check(isolate);
917 bool failed = false;
918 if (check.HasOverflowed()) {
919 isolate->StackOverflow();
920 failed = true;
921 } else {
922 failed = Execution::Call(isolate, hook, receiver, {argv, argc}).is_null();
923 }
924 if (failed) {
925 DCHECK(isolate->has_exception());
926 DirectHandle<Object> exception(isolate->exception(), isolate);
927
928 MessageLocation* no_location = nullptr;
929 DirectHandle<JSMessageObject> message =
930 isolate->CreateMessageOrAbort(exception, no_location);
931 MessageHandler::ReportMessage(isolate, no_location, message);
932
933 isolate->clear_exception();
934 }
935}
936#endif // V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS
937
938} // namespace v8::internal
V8_INLINE T FromMaybe(const T &default_value) const
Definition v8-maybe.h:82
V8_INLINE T FromJust() const &
Definition v8-maybe.h:64
V8_INLINE bool IsNothing() const
Definition v8-maybe.h:35
static Property FromSmi(Tagged< Smi > smi)
static Tagged< Smi > MutableHeapNumber()
static Tagged< ContextSidePropertyCell > GetOrCreateContextSidePropertyCell(DirectHandle< Context > context, size_t index, ContextSidePropertyCell::Property property, Isolate *isolate)
Definition contexts.cc:483
bool IsModuleContext() const
std::optional< ContextSidePropertyCell::Property > GetScriptContextSideProperty(size_t index) const
Definition contexts.cc:506
bool IsDebugEvaluateContext() const
static Handle< Object > Lookup(Handle< Context > context, Handle< String > name, ContextLookupFlags flags, int *index, PropertyAttributes *attributes, InitializationFlag *init_flag, VariableMode *variable_mode, bool *is_sloppy_function_name=nullptr)
Definition contexts.cc:236
Tagged< Context > declaration_context() const
Definition contexts.cc:146
void Initialize(Isolate *isolate)
Definition contexts.cc:108
bool IsWithContext() const
static const int kExtensionOffset
Definition contexts.h:500
static DirectHandle< Object > LoadScriptContextElement(DirectHandle< Context > script_context, int index, DirectHandle< Object > new_value, Isolate *isolate)
Definition contexts.cc:578
V8_INLINE void set(int index, Tagged< Object > value, WriteBarrierMode mode=UPDATE_WRITE_BARRIER)
V8_EXPORT_PRIVATE Tagged< JSGlobalObject > global_object() const
Definition contexts.cc:188
bool IsBlockContext() const
Tagged< Context > closure_context() const
Definition contexts.cc:154
static V8_INLINE constexpr int OffsetOfElementAt(int index)
Definition contexts.h:512
bool IsScriptContext() const
bool IsEvalContext() const
V8_EXPORT_PRIVATE void set_extension(Tagged< HeapObject > object, WriteBarrierMode mode=UPDATE_WRITE_BARRIER)
Definition contexts.cc:831
bool IsCatchContext() const
static V8_INLINE constexpr int SizeFor(int length)
Definition contexts.h:503
bool is_declaration_context() const
Definition contexts.cc:134
Handle< Object > ErrorMessageForCodeGenerationFromStrings()
Definition contexts.cc:782
bool IsFunctionContext() const
DirectHandle< Object > ErrorMessageForWasmCodeGeneration()
Definition contexts.cc:790
static const int kScopeInfoOffset
Definition contexts.h:491
static void StoreScriptContextAndUpdateSlotProperty(DirectHandle< Context > script_context, int index, DirectHandle< Object > new_value, Isolate *isolate)
Definition contexts.cc:586
Tagged< HeapObject > extension() const
Tagged< JSObject > extension_object() const
Definition contexts.cc:164
V8_EXPORT_PRIVATE Tagged< JSGlobalProxy > global_proxy() const
Definition contexts.cc:200
static const int kNotFound
Definition contexts.h:698
V8_INLINE Tagged< Object > get(int index) const
Tagged< JSReceiver > extension_receiver() const
Definition contexts.cc:174
Tagged< Context > script_context() const
Definition contexts.cc:192
static const int kPreviousOffset
Definition contexts.h:492
Tagged< NativeContext > native_context() const
Tagged< SourceTextModule > module() const
Definition contexts.cc:180
static void DeoptimizeDependencyGroups(Isolate *isolate, ObjectT object, DependencyGroups groups)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > Call(Isolate *isolate, DirectHandle< Object > callable, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args)
Definition execution.cc:523
Isolate * isolate() const
Definition factory.h:1281
static V8_WARN_UNUSED_RESULT Maybe< PropertyAttributes > GetOwnPropertyAttributes(Isolate *isolate, DirectHandle< JSReceiver > object, DirectHandle< Name > name)
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetProperty(Isolate *isolate, DirectHandle< JSReceiver > receiver, const char *key)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Maybe< bool > HasProperty(LookupIterator *it)
Definition js-objects.cc:98
static V8_EXPORT_PRIVATE void ReportMessage(Isolate *isolate, const MessageLocation *loc, DirectHandle< JSMessageObject > message)
Definition messages.cc:98
static Handle< NameToIndexHashTable > Add(IsolateT *isolate, Handle< NameToIndexHashTable > table, DirectHandle< Name > key, int32_t value)
static uint32_t Hash(ReadOnlyRoots roots, DirectHandle< Name > key)
bool HasTemplateLiteralObject(Tagged< JSArray > array)
Definition contexts.cc:778
static V8_EXPORT_PRIVATE bool BooleanValue(Tagged< Object > obj, IsolateT *isolate)
static LocalNamesRange< DirectHandle< ScopeInfo > > IterateLocalNames(DirectHandle< ScopeInfo > scope_info)
static bool VariableIsSynthetic(Tagged< String > name)
Tagged< NameToIndexHashTable > names_to_context_index() const
static Handle< ScriptContextTable > New(Isolate *isolate, int capacity, AllocationType allocation=AllocationType::kYoung)
Definition contexts.cc:28
V8_WARN_UNUSED_RESULT static V8_EXPORT_PRIVATE Handle< ScriptContextTable > Add(Isolate *isolate, Handle< ScriptContextTable > table, DirectHandle< Context > script_context, bool ignore_duplicates)
Definition contexts.cc:76
Tagged< Context > get(int index) const
V8_WARN_UNUSED_RESULT V8_EXPORT_PRIVATE bool Lookup(DirectHandle< String > name, VariableLookupResult *result)
Definition contexts.cc:118
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static CellIndexKind GetCellIndexKind(int cell_index)
Definition modules.cc:279
static Handle< ScriptContextTable > Allocate(IsolateT *isolate, int capacity, std::optional< DisallowGarbageCollection > *no_gc_out, AllocationType allocation=AllocationType::kYoung)
static void CopyElements(Isolate *isolate, Tagged< ScriptContextTable > dst, int dst_index, Tagged< ScriptContextTable > src, int src_index, int len, WriteBarrierMode mode=kDefaultMode)
static constexpr int NewCapacityForIndex(int index, int old_capacity)
LineAndColumn current
#define ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, value)
Definition isolate.h:276
std::string extension
TNode< Context > context
TNode< Object > receiver
const std::string property
ZoneVector< RpoNumber > & result
int r
Definition mul-fft.cc:298
int int32_t
Definition unicode.cc:40
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
@ kNeedsInitialization
Definition globals.h:2225
@ kCreatedInitialized
Definition globals.h:2225
bool is_sloppy(LanguageMode language_mode)
Definition globals.h:773
bool Is(IndirectHandle< U > value)
Definition handles-inl.h:51
static PropertyAttributes GetAttributesForMode(VariableMode mode)
Definition contexts.cc:230
void PrintF(const char *format,...)
Definition utils.cc:39
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
kInterpreterTrampolineOffset Tagged< HeapObject >
kStaticElementsTemplateOffset kInstancePropertiesTemplateOffset Tagged< FixedArray >
void MemsetTagged(Tagged_t *start, Tagged< MaybeObject > value, size_t counter)
Definition slots-inl.h:486
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and force scavenge at random points between and reclaim otherwise unreachable unmodified wrapper objects when possible less compaction in non memory reducing mode use high priority threads for concurrent Marking Test mode only flag It allows an unit test to select evacuation candidates use incremental marking for CppHeap cppheap_concurrent_marking c value for membalancer A special constant to balance between memory and space tradeoff The smaller the more memory it uses enable use of SSE4 instructions if available enable use of AVX VNNI instructions if available enable use of POPCNT instruction if available force all emitted branches to be in long mode(MIPS/PPC only)") DEFINE_BOOL(partial_constant_pool
constexpr int kSystemPointerSize
Definition globals.h:410
void ShortPrint(Tagged< Object > obj, FILE *out)
Definition objects.cc:1865
V8_EXPORT_PRIVATE FlagValues v8_flags
static Maybe< bool > UnscopableLookup(LookupIterator *it, bool is_with_context)
Definition contexts.cc:208
constexpr uint32_t kHoleNanUpper32
Definition globals.h:1952
bool IsSerializableVariableMode(VariableMode mode)
Definition globals.h:2140
return value
Definition map-inl.h:893
bool IsImmutableLexicalOrPrivateVariableMode(VariableMode mode)
Definition globals.h:2150
@ FOLLOW_CONTEXT_CHAIN
Definition contexts.h:30
@ DONT_FOLLOW_CHAINS
Definition contexts.h:33
@ FOLLOW_PROTOTYPE_CHAIN
Definition contexts.h:31
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
static constexpr ReleaseStoreTag kReleaseStore
Definition globals.h:2910
Local< T > Handle
Maybe< T > Nothing()
Definition v8-maybe.h:112
static constexpr AcquireLoadTag kAcquireLoad
Definition globals.h:2908
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
PromiseHookType
Definition v8-promise.h:141
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489