Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce new way of create object in script #1303

Merged
merged 3 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/builtins/BuiltinTemporal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,10 @@ static Value builtinTemporalPlainDateTimeConstructor(ExecutionState& state, Valu

ASSERT(argc > 2);

if (!(argv[0].isInteger(state) || argv[1].isInteger(state) || argv[2].isInteger(state)) || !(argc > 3 && argv[3].isInteger(state)) || !(argc > 4 && argv[4].isInteger(state)) || !(argc > 5 && argv[5].isInteger(state)) || !(argc > 6 && argv[6].isInteger(state)) || !(argc > 7 && argv[7].isInteger(state)) || !(argc > 8 && argv[8].isInteger(state))) {
if (!argv[0].isInteger(state) || !argv[1].isInteger(state) || !argv[2].isInteger(state)
|| (argc > 3 && !argv[3].isInteger(state)) || (argc > 4 && !argv[4].isInteger(state))
|| (argc > 5 && !argv[5].isInteger(state)) || (argc > 6 && !argv[6].isInteger(state))
|| (argc > 7 && !argv[7].isInteger(state)) || (argc > 8 && !argv[8].isInteger(state))) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type");
}

Expand Down Expand Up @@ -802,14 +805,14 @@ static Value builtinTemporalDurationConstructor(ExecutionState& state, Value thi
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
}

int values[10];
double values[10];
memset(values, 0, sizeof(values));

for (unsigned int i = 0; i < argc && i < 10; ++i) {
if (!argv[i].isInteger(state)) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type");
}
values[i] = argv[i].asInt32();
values[i] = argv[i].toInteger(state);
}

return TemporalDurationObject::createTemporalDuration(state, values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8], values[9], newTarget);
Expand Down
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);
}
Comment on lines +3102 to +3105
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you add a function for creating Array object here?
This method seems quite simple, so it might be better to embed this function body into the interpreter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, calling GC_MALLOC is quite complicated, so inlining the new expression into the interpreter is not very efficient.
It's only a small effort to reduce the size of the interpreter function.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh,, I see


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
Loading