Reland "[Context] Add a bit flag to indicate if extension might exist"
This is a reland of d7b67ce206
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/+/1815256
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@google.com>
Cr-Commit-Position: refs/heads/master@{#63993}
This commit is contained in:
parent
6612943010
commit
be1164775f
@ -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.
|
||||
|
||||
TNode<Object> extension_slot =
|
||||
LoadContextElement(cur_context.value(), Context::EXTENSION_INDEX);
|
||||
// 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.
|
||||
GotoIf(TaggedNotEqual(extension_slot, TheHoleConstant()), target);
|
||||
TNode<Object> extension_slot =
|
||||
LoadContextElement(cur_context.value(), Context::EXTENSION_INDEX);
|
||||
Branch(TaggedNotEqual(extension_slot, TheHoleConstant()), target,
|
||||
&no_extension);
|
||||
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user