Commit be116477 authored by Victor Gomes's avatar Victor Gomes Committed by Commit Bot

Reland "[Context] Add a bit flag to indicate if extension might exist"

This is a reland of d7b67ce2

Original change's description:
> [Context] Add a bit flag to indicate if extension might exist
> 
> Checking the bit flag instead of comparing pointers should improve performance.
> This will also allow us to remove the extension slot in Context and save memory.
> 
> Bug: v8:9744
> Change-Id: I7ab9feeadfb934955798d877d13bc0e1d78a191c
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1814918
> Commit-Queue: Victor Gomes <victorgomes@google.com>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#63906}

Bug: v8:9744
Change-Id: Ic4725ad5730a8f8fff6288d6af2205c230aff79d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1815256Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@google.com>
Cr-Commit-Position: refs/heads/master@{#63993}
parent 66129430
......@@ -2717,6 +2717,13 @@ TNode<Float64T> CodeStubAssembler::LoadDoubleWithHoleCheck(
return UncheckedCast<Float64T>(Load(machine_type, base, offset));
}
TNode<BoolT> CodeStubAssembler::LoadContextHasExtensionField(
SloppyTNode<Context> context) {
TNode<IntPtrT> value =
LoadAndUntagObjectField(context, Context::kLengthOffset);
return IsSetWord<Context::HasExtensionField>(value);
}
TNode<Object> CodeStubAssembler::LoadContextElement(
SloppyTNode<Context> context, int slot_index) {
int offset = Context::SlotOffset(slot_index);
......
......@@ -1433,6 +1433,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BigInt> BigIntFromUint32Pair(TNode<UintPtrT> low, TNode<UintPtrT> high);
// Context manipulation
TNode<BoolT> LoadContextHasExtensionField(SloppyTNode<Context> context);
TNode<Object> LoadContextElement(SloppyTNode<Context> context,
int slot_index);
TNode<Object> LoadContextElement(SloppyTNode<Context> context,
......
......@@ -1422,7 +1422,7 @@ Handle<Context> Factory::NewContext(RootIndex map_root_index, int size,
Map map = Map::cast(isolate()->root(map_root_index));
HeapObject result = AllocateRawWithImmortalMap(size, allocation, map);
Handle<Context> context(Context::cast(result), isolate());
context->set_length(variadic_part_length);
context->initialize_length_and_extension_bit(variadic_part_length);
DCHECK_EQ(context->SizeFromMap(map), size);
if (size > Context::kTodoHeaderSize) {
ObjectSlot start = context->RawField(Context::kTodoHeaderSize);
......
......@@ -205,27 +205,32 @@ void InterpreterAssembler::GotoIfHasContextExtensionUpToDepth(
TVARIABLE(Uint32T, cur_depth, depth);
Label context_search(this, {&cur_depth, &cur_context});
Label no_extension(this);
// Loop until the depth is 0.
Goto(&context_search);
BIND(&context_search);
{
// TODO(leszeks): We only need to do this check if the context had a sloppy
// eval, we could pass in a context chain bitmask to figure out which
// contexts actually need to be checked.
// Check if context has an extension slot
TNode<BoolT> has_extension =
LoadContextHasExtensionField(cur_context.value());
GotoIfNot(has_extension, &no_extension);
// Jump to the target if the extension slot is not a hole.
TNode<Object> extension_slot =
LoadContextElement(cur_context.value(), Context::EXTENSION_INDEX);
Branch(TaggedNotEqual(extension_slot, TheHoleConstant()), target,
&no_extension);
// Jump to the target if the extension slot is not a hole.
GotoIf(TaggedNotEqual(extension_slot, TheHoleConstant()), target);
cur_depth = Unsigned(Int32Sub(cur_depth.value(), Int32Constant(1)));
cur_context =
CAST(LoadContextElement(cur_context.value(), Context::PREVIOUS_INDEX));
BIND(&no_extension);
{
cur_depth = Unsigned(Int32Sub(cur_depth.value(), Int32Constant(1)));
cur_context = CAST(
LoadContextElement(cur_context.value(), Context::PREVIOUS_INDEX));
GotoIf(Word32NotEqual(cur_depth.value(), Int32Constant(0)),
&context_search);
GotoIf(Word32NotEqual(cur_depth.value(), Int32Constant(0)),
&context_search);
}
}
}
......
......@@ -47,10 +47,29 @@ Context ScriptContextTable::get_context(int i) const {
OBJECT_CONSTRUCTORS_IMPL(Context, HeapObject)
NEVER_READ_ONLY_SPACE_IMPL(Context)
CAST_ACCESSOR(Context)
SMI_ACCESSORS(Context, length, kLengthOffset)
SMI_ACCESSORS(Context, length_and_extension_flag, kLengthOffset)
SYNCHRONIZED_SMI_ACCESSORS(Context, length_and_extension_flag, kLengthOffset)
CAST_ACCESSOR(NativeContext)
int Context::length() const {
return LengthField::decode(length_and_extension_flag());
}
int Context::synchronized_length() const {
return LengthField::decode(synchronized_length_and_extension_flag());
}
void Context::initialize_length_and_extension_bit(int len,
Context::HasExtension flag) {
DCHECK(LengthField::is_valid(len));
int value = 0;
value = LengthField::update(value, len);
value = HasExtensionField::update(value, flag == Context::HasExtension::kYes);
set_length_and_extension_flag(value);
}
Object Context::get(int index) const {
Isolate* isolate = GetIsolateForPtrCompr(*this);
return get(isolate, index);
......@@ -94,11 +113,20 @@ void Context::set_previous(Context context) { set(PREVIOUS_INDEX, context); }
Object Context::next_context_link() { return get(Context::NEXT_CONTEXT_LINK); }
bool Context::has_extension() { return !extension().IsTheHole(); }
bool Context::has_extension() {
return static_cast<bool>(
HasExtensionField::decode(length_and_extension_flag())) &&
!extension().IsTheHole();
}
HeapObject Context::extension() {
return HeapObject::cast(get(EXTENSION_INDEX));
}
void Context::set_extension(HeapObject object) { set(EXTENSION_INDEX, object); }
void Context::set_extension(HeapObject object) {
set(EXTENSION_INDEX, object);
synchronized_set_length_and_extension_flag(
HasExtensionField::update(length_and_extension_flag(), true));
}
NativeContext Context::native_context() const {
Object result = get(NATIVE_CONTEXT_INDEX);
......
......@@ -453,9 +453,19 @@ class Context : public HeapObject {
DECL_CAST(Context)
enum class HasExtension { kYes, kNo };
// [length]: length of the context.
V8_INLINE int length() const;
V8_INLINE void set_length(int value);
V8_INLINE int synchronized_length() const;
V8_INLINE void initialize_length_and_extension_bit(
int len, HasExtension flag = HasExtension::kNo);
// We use the 30th bit. Otherwise if we set the 31st bit,
// the number would be pottentially bigger than an SMI.
// Any DCHECK(Smi::IsValue(...)) would fail.
using LengthField = BitField<int, 0, kSmiValueSize - 2>;
using HasExtensionField = BitField<int, kSmiValueSize - 2, 1>;
// Setter and getter for elements.
V8_INLINE Object get(int index) const;
......@@ -662,6 +672,8 @@ class Context : public HeapObject {
#endif
OBJECT_CONSTRUCTORS(Context, HeapObject);
DECL_INT_ACCESSORS(length_and_extension_flag)
DECL_SYNCHRONIZED_INT_ACCESSORS(length_and_extension_flag)
};
class NativeContext : public Context {
......
......@@ -2188,7 +2188,8 @@ int HeapObject::SizeFromMap(Map map) const {
}
if (IsInRange(instance_type, FIRST_CONTEXT_TYPE, LAST_CONTEXT_TYPE)) {
if (instance_type == NATIVE_CONTEXT_TYPE) return NativeContext::kSize;
return Context::SizeFor(Context::unchecked_cast(*this).length());
return Context::SizeFor(
Context::unchecked_cast(*this).synchronized_length());
}
if (instance_type == ONE_BYTE_STRING_TYPE ||
instance_type == ONE_BYTE_INTERNALIZED_STRING_TYPE) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment