1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:18:11 +00:00

LibJS: Stop making shapes unique

We previously had a concept of unique shapes, which meant that they
couldn't be shared between multiple objects.

Object shapes became unique in three situations:

- They were the shape of the global object.
- They had more than 100 properties added to them.
- They had one or more properties deleted from them.

Unfortunately, unique shapes presented an annoying problem for inline
caches, and we added a "unique shape serial number" for being able to
tell that a unique shape had been mutated.

This patch gets rid of the concept of unique shapes, simplifying all
the caching code, since inline caches can now simply perform a shape
check and then we're good.

To make this possible, we now have the concept of delete transitions,
which occur when a property is deleted from a shape.

Note that this patch by itself introduces a performance regression in
some situtations, since we now create a lot more shapes, and marking
their property keys can be very heavy. This will be addressed in a
subsequent patch.
This commit is contained in:
Andreas Kling 2023-12-11 14:29:40 +01:00
parent ef86cf4646
commit 3d92c26445
8 changed files with 63 additions and 214 deletions

View file

@ -1665,39 +1665,6 @@ void Compiler::compile_get_by_id(Bytecode::Op::GetById const& op)
Assembler::Operand::Register(GPR1),
slow_case);
// (!object->shape().is_unique() || object->shape().unique_shape_serial_number() == cache.unique_shape_serial_number)) {
Assembler::Label fast_case;
// GPR1 = object->shape().is_unique()
m_assembler.mov8(
Assembler::Operand::Register(GPR1),
Assembler::Operand::Mem64BaseAndOffset(GPR2, Shape::is_unique_offset()));
m_assembler.jump_if(
Assembler::Operand::Register(GPR1),
Assembler::Condition::EqualTo,
Assembler::Operand::Imm(0),
fast_case);
// GPR1 = object->shape().unique_shape_serial_number()
m_assembler.mov(
Assembler::Operand::Register(GPR1),
Assembler::Operand::Mem64BaseAndOffset(GPR2, Shape::unique_shape_serial_number_offset()));
// GPR2 = cache.unique_shape_serial_number
m_assembler.mov(
Assembler::Operand::Register(GPR2),
Assembler::Operand::Mem64BaseAndOffset(ARG5, Bytecode::PropertyLookupCache::unique_shape_serial_number_offset()));
// if (GPR1 != GPR2) goto slow_case;
m_assembler.jump_if(
Assembler::Operand::Register(GPR1),
Assembler::Condition::NotEqualTo,
Assembler::Operand::Register(GPR2),
slow_case);
fast_case.link(m_assembler);
// return object->get_direct(*cache.property_offset);
// GPR0 = object
// GPR1 = *cache.property_offset * sizeof(Value)
@ -1953,38 +1920,6 @@ void Compiler::compile_get_global(Bytecode::Op::GetGlobal const& op)
Assembler::Operand::Register(GPR0),
slow_case);
Assembler::Label fast_case {};
// GPR2 = shape->unique()
m_assembler.mov8(
Assembler::Operand::Register(GPR2),
Assembler::Operand::Mem64BaseAndOffset(GPR0, Shape::is_unique_offset()));
// if (!GPR2) goto fast_case;
m_assembler.jump_if(
Assembler::Operand::Register(GPR2),
Assembler::Condition::EqualTo,
Assembler::Operand::Imm(0),
fast_case);
// GPR2 = shape->unique_shape_serial_number()
m_assembler.mov(
Assembler::Operand::Register(GPR2),
Assembler::Operand::Mem64BaseAndOffset(GPR0, Shape::unique_shape_serial_number_offset()));
// GPR0 = cache.unique_shape_serial_number
m_assembler.mov(
Assembler::Operand::Register(GPR0),
Assembler::Operand::Mem64BaseAndOffset(ARG2, Bytecode::PropertyLookupCache::unique_shape_serial_number_offset()));
// if (GPR2 != GPR0) goto slow_case;
m_assembler.jump_if(
Assembler::Operand::Register(GPR2),
Assembler::Condition::NotEqualTo,
Assembler::Operand::Register(GPR0),
slow_case);
fast_case.link(m_assembler);
// accumulator = GPR1->get_direct(*cache.property_offset);
// GPR0 = GPR1
// GPR1 = *cache.property_offset * sizeof(Value)
@ -2295,39 +2230,6 @@ void Compiler::compile_put_by_id(Bytecode::Op::PutById const& op)
Assembler::Operand::Register(GPR1),
slow_case);
// (!object->shape().is_unique() || object->shape().unique_shape_serial_number() == cache.unique_shape_serial_number)) {
Assembler::Label fast_case;
// GPR1 = object->shape().is_unique()
m_assembler.mov8(
Assembler::Operand::Register(GPR1),
Assembler::Operand::Mem64BaseAndOffset(GPR2, Shape::is_unique_offset()));
m_assembler.jump_if(
Assembler::Operand::Register(GPR1),
Assembler::Condition::EqualTo,
Assembler::Operand::Imm(0),
fast_case);
// GPR1 = object->shape().unique_shape_serial_number()
m_assembler.mov(
Assembler::Operand::Register(GPR1),
Assembler::Operand::Mem64BaseAndOffset(GPR2, Shape::unique_shape_serial_number_offset()));
// GPR2 = cache.unique_shape_serial_number
m_assembler.mov(
Assembler::Operand::Register(GPR2),
Assembler::Operand::Mem64BaseAndOffset(ARG5, Bytecode::PropertyLookupCache::unique_shape_serial_number_offset()));
// if (GPR1 != GPR2) goto slow_case;
m_assembler.jump_if(
Assembler::Operand::Register(GPR1),
Assembler::Condition::NotEqualTo,
Assembler::Operand::Register(GPR2),
slow_case);
fast_case.link(m_assembler);
// object->put_direct(*cache.property_offset, value);
// GPR0 = object
// GPR1 = *cache.property_offset * sizeof(Value)