Skip to content

Commit

Permalink
Introduce new way of create object in script
Browse files Browse the repository at this point in the history
* Prepare the property and key list before object creation
* The new way reduce size of object structure with transition

Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
  • Loading branch information
ksh8281 committed Jan 16, 2024
1 parent e593555 commit 121f4bd
Show file tree
Hide file tree
Showing 8 changed files with 251 additions and 35 deletions.
76 changes: 74 additions & 2 deletions src/interpreter/ByteCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ struct GlobalVariableAccessCacheItem;
F(BinaryUnsignedRightShift) \
F(BinaryInOperation) \
F(BinaryInstanceOfOperation) \
F(CreateObjectPrepare) \
F(CreateObject) \
F(CreateArray) \
F(CreateSpreadArrayObject) \
Expand Down Expand Up @@ -953,20 +954,91 @@ class BreakpointEnabled : public ByteCode {
COMPILE_ASSERT(sizeof(BreakpointDisabled) == sizeof(BreakpointEnabled), "");
#endif /* ESCARGOT_DEBUGGER */

class CreateObjectPrepare : public ByteCode {
public:
enum Stage ENSURE_ENUM_UNSIGNED {
Init,
FillKeyValue
};

struct CreateObjectData : public gc {
bool m_hasSymbol;
bool m_hasNonAtomicPropertyName;
size_t m_fillIndex;
ObjectStructureItemTightVector m_properties;
ObjectPropertyValueVector m_values;
Object* m_target;
CreateObjectData(size_t propertyCount, Object* target)
: m_hasSymbol(false)
, m_hasNonAtomicPropertyName(false)
, m_fillIndex(0)
, m_target(target)
{
m_properties.resizeWithUninitializedValues(propertyCount);
m_values.resizeWithUninitializedValues(0, propertyCount);
}
};

CreateObjectPrepare(const ByteCodeLOC& loc, const size_t dataRegisterIndex, const size_t propertyCount, const size_t objectIndex)
: ByteCode(Opcode::CreateObjectPrepareOpcode, loc)
, m_stage(Stage::Init)
, m_hasAtomicString(false)
, m_dataRegisterIndex(dataRegisterIndex)
, m_propertyCount(propertyCount)
, m_objectIndex(objectIndex)
{
}

CreateObjectPrepare(const ByteCodeLOC& loc, const bool hasAtomicString, const size_t dataRegisterIndex, const size_t keyIndex, const size_t valueIndex)
: ByteCode(Opcode::CreateObjectPrepareOpcode, loc)
, m_stage(Stage::FillKeyValue)
, m_hasAtomicString(hasAtomicString)
, m_dataRegisterIndex(dataRegisterIndex)
, m_keyIndex(keyIndex)
, m_valueIndex(valueIndex)
{
}

Stage m_stage : 1;
bool m_hasAtomicString : 1;
ByteCodeRegisterIndex m_dataRegisterIndex : REGISTER_INDEX_IN_BIT;

union {
struct {
ByteCodeRegisterIndex m_propertyCount : REGISTER_INDEX_IN_BIT;
ByteCodeRegisterIndex m_objectIndex : REGISTER_INDEX_IN_BIT;
};

struct {
ByteCodeRegisterIndex m_keyIndex : REGISTER_INDEX_IN_BIT;
ByteCodeRegisterIndex m_valueIndex : REGISTER_INDEX_IN_BIT;
};
};

#ifndef NDEBUG
void dump()
{
printf("createobjectprepare -> r%u stage: %d", m_dataRegisterIndex, m_stage);
}
#endif
};

class CreateObject : public ByteCode {
public:
CreateObject(const ByteCodeLOC& loc, const size_t registerIndex)
CreateObject(const ByteCodeLOC& loc, const size_t registerIndex, const size_t dataRegisterIndex = SIZE_MAX)
: ByteCode(Opcode::CreateObjectOpcode, loc)
, m_registerIndex(registerIndex)
, m_dataRegisterIndex(dataRegisterIndex)
{
}

ByteCodeRegisterIndex m_registerIndex;
ByteCodeRegisterIndex m_dataRegisterIndex;

#ifndef NDEBUG
void dump()
{
printf("createobject -> r%u", m_registerIndex);
printf("createobject -> r%u r%u", m_registerIndex, m_dataRegisterIndex);
}
#endif
};
Expand Down
10 changes: 10 additions & 0 deletions src/interpreter/ByteCodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,16 @@ void ByteCodeGenerator::relocateByteCode(ByteCodeBlock* block)
case CreateObjectOpcode: {
CreateObject* cd = (CreateObject*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_registerIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dataRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case CreateObjectPrepareOpcode: {
CreateObjectPrepare* cd = (CreateObjectPrepare*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dataRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
if (cd->m_stage == CreateObjectPrepare::FillKeyValue) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_keyIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_valueIndex, stackBase, stackBaseWillBe, stackVariableSize);
}
break;
}
case CreateArrayOpcode: {
Expand Down
65 changes: 60 additions & 5 deletions src/interpreter/ByteCodeInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ class InterpreterSlowPath {

static Value tryOperation(ExecutionState*& state, size_t& programCounter, ByteCodeBlock* byteCodeBlock, Value* registerFile);

static void createObjectOperation(ExecutionState& state, CreateObject* createObject, ByteCodeBlock* byteCodeBlock, Value* registerFile);
static void createObjectPrepareOperation(ExecutionState& state, CreateObjectPrepare* createObject, ByteCodeBlock* byteCodeBlock, Value* registerFile);
static void createArrayOperation(ExecutionState& state, CreateArray* createArray, ByteCodeBlock* byteCodeBlock, Value* registerFile);
static void createFunctionOperation(ExecutionState& state, CreateFunction* createFunction, ByteCodeBlock* byteCodeBlock, Value* registerFile);
static ArrayObject* createRestElementOperation(ExecutionState& state, ByteCodeBlock* byteCodeBlock);
static void initializeClassOperation(ExecutionState& state, InitializeClass* code, Value* registerFile);
Expand Down Expand Up @@ -1157,19 +1160,25 @@ Value Interpreter::interpret(ExecutionState* state, ByteCodeBlock* byteCodeBlock
:
{
CreateObject* code = (CreateObject*)programCounter;
registerFile[code->m_registerIndex] = new Object(*state);
#if defined(ESCARGOT_SMALL_CONFIG)
registerFile[code->m_registerIndex].asObject()->markThisObjectDontNeedStructureTransitionTable();
#endif
InterpreterSlowPath::createObjectOperation(*state, code, byteCodeBlock, registerFile);
ADD_PROGRAM_COUNTER(CreateObject);
NEXT_INSTRUCTION();
}

DEFINE_OPCODE(CreateObjectPrepare)
:
{
CreateObjectPrepare* code = (CreateObjectPrepare*)programCounter;
InterpreterSlowPath::createObjectPrepareOperation(*state, code, byteCodeBlock, registerFile);
ADD_PROGRAM_COUNTER(CreateObjectPrepare);
NEXT_INSTRUCTION();
}

DEFINE_OPCODE(CreateArray)
:
{
CreateArray* code = (CreateArray*)programCounter;
registerFile[code->m_registerIndex] = new ArrayObject(*state, (uint64_t)code->m_length);
InterpreterSlowPath::createArrayOperation(*state, code, byteCodeBlock, registerFile);
ADD_PROGRAM_COUNTER(CreateArray);
NEXT_INSTRUCTION();
}
Expand Down Expand Up @@ -2961,6 +2970,52 @@ NEVER_INLINE void InterpreterSlowPath::initializeGlobalVariable(ExecutionState&
ASSERT_NOT_REACHED();
}

NEVER_INLINE void InterpreterSlowPath::createObjectOperation(ExecutionState& state, CreateObject* code, ByteCodeBlock* byteCodeBlock, Value* registerFile)
{
if (code->m_dataRegisterIndex != REGISTER_LIMIT) {
CreateObjectPrepare::CreateObjectData* data = reinterpret_cast<CreateObjectPrepare::CreateObjectData*>(registerFile[code->m_dataRegisterIndex].payload());
ASSERT(data->m_fillIndex == data->m_properties.size());
Object* obj = registerFile[code->m_registerIndex].asObject();
obj->m_values = std::move(data->m_values);
obj->m_structure = ObjectStructure::create(state.context(), std::move(data->m_properties));
} else {
registerFile[code->m_registerIndex] = new Object(state);
}
#if defined(ESCARGOT_SMALL_CONFIG)
registerFile[code->m_registerIndex].asObject()->markThisObjectDontNeedStructureTransitionTable();
#endif
}

NEVER_INLINE void InterpreterSlowPath::createObjectPrepareOperation(ExecutionState& state, CreateObjectPrepare* code, ByteCodeBlock* byteCodeBlock, Value* registerFile)
{
if (code->m_stage == CreateObjectPrepare::Init) {
CreateObjectPrepare::CreateObjectData* data = new CreateObjectPrepare::CreateObjectData(code->m_propertyCount, new Object(state));
registerFile[code->m_dataRegisterIndex] = Value(Value::FromPayload, reinterpret_cast<intptr_t>(data));
registerFile[code->m_objectIndex] = data->m_target;
} else {
ASSERT(code->m_stage == CreateObjectPrepare::FillKeyValue);
CreateObjectPrepare::CreateObjectData* data = reinterpret_cast<CreateObjectPrepare::CreateObjectData*>(registerFile[code->m_dataRegisterIndex].payload());

if (code->m_hasAtomicString) {
data->m_properties[data->m_fillIndex] = ObjectStructureItem(ObjectStructurePropertyName(AtomicString::fromPayload(registerFile[code->m_keyIndex].asString())),
ObjectStructurePropertyDescriptor::createDataDescriptor(ObjectStructurePropertyDescriptor::AllPresent));
} else {
data->m_properties[data->m_fillIndex] = ObjectStructureItem(ObjectStructurePropertyName(state,
registerFile[code->m_keyIndex]),
ObjectStructurePropertyDescriptor::createDataDescriptor(ObjectStructurePropertyDescriptor::AllPresent));
data->m_hasNonAtomicPropertyName = true;
}

data->m_values[data->m_fillIndex] = registerFile[code->m_valueIndex];
data->m_fillIndex++;
}
}

NEVER_INLINE void InterpreterSlowPath::createArrayOperation(ExecutionState& state, CreateArray* code, ByteCodeBlock* byteCodeBlock, Value* registerFile)
{
registerFile[code->m_registerIndex] = new ArrayObject(state, (uint64_t)code->m_length);
}

NEVER_INLINE void InterpreterSlowPath::createFunctionOperation(ExecutionState& state, CreateFunction* code, ByteCodeBlock* byteCodeBlock, Value* registerFile)
{
InterpretedCodeBlock* cb = code->m_codeBlock;
Expand Down
67 changes: 60 additions & 7 deletions src/parser/ast/ObjectExpressionNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,68 @@ class ObjectExpressionNode : public ExpressionNode {
return m_properties;
}

size_t generateInitValueByteCode(ByteCodeBlock* codeBlock, ByteCodeGenerateContext* context, PropertyNode* p, ByteCodeRegisterIndex dstRegister)
{
size_t valueIndex = p->value()->getRegister(codeBlock, context);
const ClassContextInformation classInfoBefore = context->m_classInfo;
context->m_classInfo.m_prototypeIndex = dstRegister;
context->m_classInfo.m_constructorIndex = SIZE_MAX;
context->m_classInfo.m_superIndex = SIZE_MAX;
p->value()->generateExpressionByteCode(codeBlock, context, valueIndex);
context->m_classInfo = classInfoBefore;
return valueIndex;
}

virtual ASTNodeType type() override { return ASTNodeType::ObjectExpression; }
virtual void generateExpressionByteCode(ByteCodeBlock* codeBlock, ByteCodeGenerateContext* context, ByteCodeRegisterIndex dstRegister) override
{
size_t initPropertyCount = 0;
bool allSimpleCase = true;
for (SentinelNode* property = m_properties.begin(); property != m_properties.end(); property = property->next()) {
initPropertyCount++;
if (property->astNode()->isProperty()) {
PropertyNode* p = property->astNode()->asProperty();
if (p->kind() != PropertyNode::Kind::Init) {
allSimpleCase = false;
break;
}
} else {
allSimpleCase = false;
break;
}
}

if (allSimpleCase && initPropertyCount >= ESCARGOT_OBJECT_STRUCTURE_TRANSITION_MODE_MAX_SIZE && initPropertyCount <= REGISTER_LIMIT) {
size_t dataIndex = context->getRegister();
codeBlock->pushCode(CreateObjectPrepare(ByteCodeLOC(m_loc.index), dataIndex, initPropertyCount, dstRegister), context, this->m_loc.index);

size_t propertyIndex = 0;
for (SentinelNode* property = m_properties.begin(); property != m_properties.end(); propertyIndex++, property = property->next()) {
PropertyNode* p = property->astNode()->asProperty();
ASSERT(p->kind() == PropertyNode::Kind::Init);

bool hasKeyName = false;
size_t propertyIndex = SIZE_MAX;
if (p->key()->isIdentifier() && !p->computed()) {
hasKeyName = true;
propertyIndex = context->getRegister();
codeBlock->pushCode(LoadLiteral(ByteCodeLOC(m_loc.index), propertyIndex, Value(p->key()->asIdentifier()->name().string())), context, this->m_loc.index);
} else {
propertyIndex = p->key()->getRegister(codeBlock, context);
p->key()->generateExpressionByteCode(codeBlock, context, propertyIndex);
}

size_t valueIndex = generateInitValueByteCode(codeBlock, context, p, dstRegister);
codeBlock->pushCode(CreateObjectPrepare(ByteCodeLOC(m_loc.index), hasKeyName, dataIndex, propertyIndex, valueIndex), context, this->m_loc.index);
context->giveUpRegister();
context->giveUpRegister();
}

codeBlock->pushCode(CreateObject(ByteCodeLOC(m_loc.index), dstRegister, dataIndex), context, this->m_loc.index);
context->giveUpRegister();
return;
}

codeBlock->pushCode(CreateObject(ByteCodeLOC(m_loc.index), dstRegister), context, this->m_loc.index);
size_t objIndex = dstRegister;
for (SentinelNode* property = m_properties.begin(); property != m_properties.end(); property = property->next()) {
Expand All @@ -58,13 +117,7 @@ class ObjectExpressionNode : public ExpressionNode {
p->key()->generateExpressionByteCode(codeBlock, context, propertyIndex);
}

size_t valueIndex = p->value()->getRegister(codeBlock, context);
const ClassContextInformation classInfoBefore = context->m_classInfo;
context->m_classInfo.m_prototypeIndex = dstRegister;
context->m_classInfo.m_constructorIndex = SIZE_MAX;
context->m_classInfo.m_superIndex = SIZE_MAX;
p->value()->generateExpressionByteCode(codeBlock, context, valueIndex);
context->m_classInfo = classInfoBefore;
size_t valueIndex = generateInitValueByteCode(codeBlock, context, p, dstRegister);

if (p->kind() == PropertyNode::Kind::Init) {
if (hasKeyName) {
Expand Down
27 changes: 27 additions & 0 deletions src/runtime/ObjectStructure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,33 @@ void* ObjectStructureWithoutTransition::operator new(size_t size)
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
}

ObjectStructure* ObjectStructure::create(Context* ctx, ObjectStructureItemTightVector&& properties)
{
bool hasIndexStringAsPropertyName = false;
bool hasSymbol = false;
bool hasNonAtomicPropertyName = false;
bool hasEnumerableProperty = true;
for (size_t i = 0; i < properties.size(); i++) {
const ObjectStructurePropertyName& propertyName = properties[i].m_propertyName;
if (propertyName.isSymbol()) {
hasSymbol = true;
}
if (!hasIndexStringAsPropertyName) {
hasIndexStringAsPropertyName |= propertyName.isIndexString();
}

hasNonAtomicPropertyName |= !propertyName.hasAtomicString();
hasEnumerableProperty |= properties[i].m_descriptor.isEnumerable();
}

ObjectStructure* newObjectStructure;
if (properties.size() > ESCARGOT_OBJECT_STRUCTURE_ACCESS_CACHE_BUILD_MIN_SIZE) {
return new ObjectStructureWithMap(hasIndexStringAsPropertyName, hasSymbol, hasEnumerableProperty, std::move(properties));
} else {
return new ObjectStructureWithoutTransition(new ObjectStructureItemVector(std::move(properties)), hasIndexStringAsPropertyName, hasSymbol, hasNonAtomicPropertyName, hasEnumerableProperty);
}
}

std::pair<size_t, Optional<const ObjectStructureItem*>> ObjectStructureWithoutTransition::findProperty(const ObjectStructurePropertyName& s)
{
if (m_properties->size() && m_lastFoundPropertyName == s) {
Expand Down
3 changes: 3 additions & 0 deletions src/runtime/ObjectStructure.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ COMPILE_ASSERT(ESCARGOT_OBJECT_STRUCTURE_ACCESS_CACHE_BUILD_MIN_SIZE < 65536, ""
class ObjectStructure : public gc {
public:
virtual ~ObjectStructure() {}

static ObjectStructure* create(Context* ctx, ObjectStructureItemTightVector&& properties);

std::pair<size_t, Optional<const ObjectStructureItem*>> findProperty(ExecutionState& state, String* propertyName)
{
ObjectStructurePropertyName name(state, propertyName);
Expand Down
22 changes: 1 addition & 21 deletions src/runtime/Template.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,6 @@ Template::CachedObjectStructure Template::constructObjectStructure(Context* ctx,
structureItemVector[i] = baseItems[i];
}

bool hasIndexStringAsPropertyName = false;
bool hasSymbol = false;
bool hasNonAtomicPropertyName = false;
bool hasEnumerableProperty = false;
bool isInlineNonCacheable = false;
for (size_t i = baseItemCount; i < propertyCount; i++) {
auto propertyIndex = i - baseItemCount;
Expand All @@ -109,15 +105,8 @@ Template::CachedObjectStructure Template::constructObjectStructure(Context* ctx,
} else {
ASSERT(propertyNameValue.isSymbol());
propertyName = ObjectStructurePropertyName(propertyNameValue.asSymbol());
hasSymbol = true;
}

if (!hasIndexStringAsPropertyName) {
hasIndexStringAsPropertyName |= propertyName.isIndexString();
}

hasNonAtomicPropertyName |= !propertyName.hasAtomicString();

auto type = m_properties[propertyIndex].second.propertyType();
ObjectStructurePropertyDescriptor desc;
if (type == Template::TemplatePropertyData::PropertyType::PropertyValueData || type == Template::TemplatePropertyData::PropertyType::PropertyTemplateData) {
Expand All @@ -130,20 +119,11 @@ Template::CachedObjectStructure Template::constructObjectStructure(Context* ctx,
desc = ObjectStructurePropertyDescriptor::createAccessorDescriptor(m_properties[propertyIndex].second.presentAttributes());
}

hasEnumerableProperty |= desc.isEnumerable();

structureItemVector[i] = ObjectStructureItem(propertyName, desc);
}

ObjectStructure* newObjectStructure;
if (propertyCount > ESCARGOT_OBJECT_STRUCTURE_ACCESS_CACHE_BUILD_MIN_SIZE) {
newObjectStructure = new ObjectStructureWithMap(hasIndexStringAsPropertyName, hasSymbol, hasEnumerableProperty, std::move(structureItemVector));
} else {
newObjectStructure = new ObjectStructureWithTransition(std::move(structureItemVector), hasIndexStringAsPropertyName, hasSymbol, hasNonAtomicPropertyName, hasEnumerableProperty);
}

CachedObjectStructure s;
s.m_objectStructure = newObjectStructure;
s.m_objectStructure = ObjectStructure::create(ctx, std::move(structureItemVector));
s.m_inlineCacheable = !isInlineNonCacheable;
return s;
}
Expand Down
Loading

0 comments on commit 121f4bd

Please sign in to comment.