Skip to content

Commit

Permalink
Implement more things for CreateObjectPrepare operation
Browse files Browse the repository at this point in the history
* It should support methods

Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
  • Loading branch information
ksh8281 committed Jan 17, 2024
1 parent 121f4bd commit ac3194f
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 64 deletions.
37 changes: 26 additions & 11 deletions src/interpreter/ByteCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -958,20 +958,17 @@ class CreateObjectPrepare : public ByteCode {
public:
enum Stage ENSURE_ENUM_UNSIGNED {
Init,
FillKeyValue
FillKeyValue,
DefineGetterSetter,
};

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_fillIndex(0)
, m_target(target)
{
m_properties.resizeWithUninitializedValues(propertyCount);
Expand All @@ -982,25 +979,43 @@ class CreateObjectPrepare : public ByteCode {
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_hasPreComputedKey(false)
, m_needsToUpdateFunctionName(false)
, m_isGetter(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)
CreateObjectPrepare(const ByteCodeLOC& loc, const bool hasPreComputedKey, const size_t dataRegisterIndex, const size_t keyIndex, const size_t valueIndex, const bool needsToUpdateFunctionName)
: ByteCode(Opcode::CreateObjectPrepareOpcode, loc)
, m_stage(Stage::FillKeyValue)
, m_hasAtomicString(hasAtomicString)
, m_hasPreComputedKey(hasPreComputedKey)
, m_needsToUpdateFunctionName(needsToUpdateFunctionName)
, m_isGetter(false)
, m_dataRegisterIndex(dataRegisterIndex)
, m_keyIndex(keyIndex)
, m_valueIndex(valueIndex)
{
}

Stage m_stage : 1;
bool m_hasAtomicString : 1;
CreateObjectPrepare(const ByteCodeLOC& loc, const bool hasPreComputedKey, const bool isGetter, const size_t dataRegisterIndex, const size_t keyIndex, const size_t valueIndex)
: ByteCode(Opcode::CreateObjectPrepareOpcode, loc)
, m_stage(Stage::DefineGetterSetter)
, m_hasPreComputedKey(hasPreComputedKey)
, m_needsToUpdateFunctionName(false)
, m_isGetter(isGetter)
, m_dataRegisterIndex(dataRegisterIndex)
, m_keyIndex(keyIndex)
, m_valueIndex(valueIndex)
{
}

Stage m_stage : 2;
bool m_hasPreComputedKey : 1;
bool m_needsToUpdateFunctionName : 1;
bool m_isGetter : 1; // other case, this is setter
ByteCodeRegisterIndex m_dataRegisterIndex : REGISTER_INDEX_IN_BIT;

union {
Expand Down
2 changes: 1 addition & 1 deletion src/interpreter/ByteCodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ void ByteCodeGenerator::relocateByteCode(ByteCodeBlock* block)
case CreateObjectPrepareOpcode: {
CreateObjectPrepare* cd = (CreateObjectPrepare*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_dataRegisterIndex, stackBase, stackBaseWillBe, stackVariableSize);
if (cd->m_stage == CreateObjectPrepare::FillKeyValue) {
if (cd->m_stage == CreateObjectPrepare::FillKeyValue || cd->m_stage == CreateObjectPrepare::DefineGetterSetter) {
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_keyIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_valueIndex, stackBase, stackBaseWillBe, stackVariableSize);
}
Expand Down
144 changes: 107 additions & 37 deletions src/interpreter/ByteCodeInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class InterpreterSlowPath {
static bool setObjectPreComputedCaseOperationSlowCase(ExecutionState& state, Object* obj, const Value& willBeObject, const Value& value, SetObjectPreComputedCase* code, ByteCodeBlock* block);
static void setObjectPreComputedCaseOperationCacheMiss(ExecutionState& state, Object* obj, const Value& willBeObject, const Value& value, SetObjectPreComputedCase* code, ByteCodeBlock* block);
static void defineObjectGetterSetterOperation(ExecutionState& state, ObjectDefineGetterSetter* code, ByteCodeBlock* byteCodeBlock, Value* registerFile, Object* object);
static void updateObjectGetterSetterFunctionName(ExecutionState& state, FunctionObject* fn, Value propertyName, bool isGetter);
static Value incrementOperationSlowCase(ExecutionState& state, const Value& value);
static Value decrementOperationSlowCase(ExecutionState& state, const Value& value);
};
Expand Down Expand Up @@ -2974,7 +2975,7 @@ NEVER_INLINE void InterpreterSlowPath::createObjectOperation(ExecutionState& sta
{
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());
data->m_properties.reset(data->m_properties.data(), data->m_fillIndex);
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));
Expand All @@ -2986,28 +2987,107 @@ NEVER_INLINE void InterpreterSlowPath::createObjectOperation(ExecutionState& sta
#endif
}

static Value createObjectPropertyFunctionName(ExecutionState& state, const Value& name, const char* prefix)
{
StringBuilder builder;
if (name.isSymbol()) {
builder.appendString(prefix);
if (name.asSymbol()->descriptionString()->length()) {
// add symbol name if it is not an empty symbol
builder.appendString("[");
builder.appendString(name.asSymbol()->descriptionString());
builder.appendString("]");
}
} else {
builder.appendString(prefix);
builder.appendString(name.toString(state));
}
return builder.finalize(&state);
}

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);
ASSERT(code->m_stage == CreateObjectPrepare::FillKeyValue || code->m_stage == CreateObjectPrepare::DefineGetterSetter);
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));
ObjectStructurePropertyName propertyName;
if (code->m_hasPreComputedKey) {
propertyName = ObjectStructurePropertyName(AtomicString::fromPayload(registerFile[code->m_keyIndex].asString()));
// http://www.ecma-international.org/ecma-262/6.0/#sec-__proto__-property-names-in-object-initializers
if (UNLIKELY(propertyName.asAtomicString() == state.context()->staticStrings().__proto__ && code->m_stage == CreateObjectPrepare::FillKeyValue)) {
const Value& v = registerFile[code->m_valueIndex];
if (v.isObject() || v.isNull()) {
data->m_target->setPrototype(state, v);
}
return;
}
} else {
data->m_properties[data->m_fillIndex] = ObjectStructureItem(ObjectStructurePropertyName(state,
registerFile[code->m_keyIndex]),
ObjectStructurePropertyDescriptor::createDataDescriptor(ObjectStructurePropertyDescriptor::AllPresent));
data->m_hasNonAtomicPropertyName = true;
propertyName = ObjectStructurePropertyName(state, registerFile[code->m_keyIndex]);
}

data->m_values[data->m_fillIndex] = registerFile[code->m_valueIndex];
data->m_fillIndex++;
size_t lastPropertyCount = data->m_fillIndex;
size_t targetIndex = data->m_fillIndex;
bool updateProperty = false;
for (size_t i = 0; i < lastPropertyCount; i++) {
if (data->m_properties[i].m_propertyName == propertyName) {
targetIndex = i;
updateProperty = true;
break;
}
}
if (code->m_stage == CreateObjectPrepare::FillKeyValue) {
Value& value = registerFile[code->m_valueIndex];
if (code->m_needsToUpdateFunctionName) {
Value propertyStringOrSymbol(propertyName.isSymbol() ? Value(propertyName.symbol()) : Value(propertyName.toValue().toString(state)));
ASSERT(value.isFunction());
Value fnName = createObjectPropertyFunctionName(state, propertyStringOrSymbol, "");
value.asFunction()->defineOwnProperty(state, state.context()->staticStrings().name, ObjectPropertyDescriptor(fnName));
}
data->m_properties[targetIndex] = ObjectStructureItem(propertyName,
ObjectStructurePropertyDescriptor::createDataDescriptor(ObjectStructurePropertyDescriptor::AllPresent));
data->m_values[targetIndex] = value;
} else {
FunctionObject* fn = registerFile[code->m_valueIndex].asFunction();
updateObjectGetterSetterFunctionName(state, fn, registerFile[code->m_keyIndex], code->m_isGetter);
int flag = ObjectStructurePropertyDescriptor::ConfigurablePresent | ObjectStructurePropertyDescriptor::EnumerablePresent;
if (code->m_isGetter) {
flag = flag | ObjectStructurePropertyDescriptor::HasJSGetter;
} else {
flag = flag | ObjectStructurePropertyDescriptor::HasJSSetter;
}
JSGetterSetter* gs;
if (updateProperty) {
const auto& oldDesc = data->m_properties[targetIndex].m_descriptor;
if (oldDesc.isDataProperty()) {
gs = new JSGetterSetter(Value(Value::EmptyValue), Value(Value::EmptyValue));
} else {
if (oldDesc.hasJSGetter()) {
flag = flag | ObjectStructurePropertyDescriptor::HasJSGetter;
} else {
flag = flag | ObjectStructurePropertyDescriptor::HasJSSetter;
}
gs = Value(data->m_values[targetIndex]).asPointerValue()->asJSGetterSetter();
}
} else {
gs = new JSGetterSetter(Value(Value::EmptyValue), Value(Value::EmptyValue));
}

if (code->m_isGetter) {
gs->setGetter(fn);
} else {
gs->setSetter(fn);
}
data->m_values[targetIndex] = gs;
data->m_properties[targetIndex] = ObjectStructureItem(propertyName, ObjectStructurePropertyDescriptor::createAccessorDescriptor((ObjectStructurePropertyDescriptor::PresentAttribute)flag));
}
if (!updateProperty) {
data->m_fillIndex++;
}
}
}

Expand Down Expand Up @@ -4215,24 +4295,6 @@ NEVER_INLINE void InterpreterSlowPath::metaPropertyOperation(ExecutionState& sta
}
}

static Value createObjectPropertyFunctionName(ExecutionState& state, const Value& name, const char* prefix)
{
StringBuilder builder;
if (name.isSymbol()) {
builder.appendString(prefix);
if (name.asSymbol()->descriptionString()->length()) {
// add symbol name if it is not an empty symbol
builder.appendString("[");
builder.appendString(name.asSymbol()->descriptionString());
builder.appendString("]");
}
} else {
builder.appendString(prefix);
builder.appendString(name.toString(state));
}
return builder.finalize(&state);
}

NEVER_INLINE void InterpreterSlowPath::objectDefineOwnPropertyOperation(ExecutionState& state, ObjectDefineOwnPropertyOperation* code, Value* registerFile)
{
const Value& willBeObject = registerFile[code->m_objectRegisterIndex];
Expand Down Expand Up @@ -4404,17 +4466,22 @@ NEVER_INLINE void InterpreterSlowPath::createSpreadArrayObject(ExecutionState& s
registerFile[code->m_registerIndex] = spreadArray;
}

NEVER_INLINE void InterpreterSlowPath::defineObjectGetterSetterOperation(ExecutionState& state, ObjectDefineGetterSetter* code, ByteCodeBlock* byteCodeBlock, Value* registerFile, Object* object)
NEVER_INLINE void InterpreterSlowPath::updateObjectGetterSetterFunctionName(ExecutionState& state, FunctionObject* fn, Value propertyName, bool isGetter)
{
FunctionObject* fn = registerFile[code->m_objectPropertyValueRegisterIndex].asFunction();
Value pName = code->m_objectPropertyNameRegisterIndex == REGISTER_LIMIT ? fn->codeBlock()->functionName().string() : registerFile[code->m_objectPropertyNameRegisterIndex];
Value fnName;
if (code->m_isGetter) {
fnName = createObjectPropertyFunctionName(state, pName, "get ");
if (isGetter) {
fnName = createObjectPropertyFunctionName(state, propertyName, "get ");
} else {
fnName = createObjectPropertyFunctionName(state, pName, "set ");
fnName = createObjectPropertyFunctionName(state, propertyName, "set ");
}
fn->defineOwnProperty(state, state.context()->staticStrings().name, ObjectPropertyDescriptor(fnName));
}

NEVER_INLINE void InterpreterSlowPath::defineObjectGetterSetterOperation(ExecutionState& state, ObjectDefineGetterSetter* code, ByteCodeBlock* byteCodeBlock, Value* registerFile, Object* object)
{
FunctionObject* fn = registerFile[code->m_objectPropertyValueRegisterIndex].asFunction();
Value pName = code->m_objectPropertyNameRegisterIndex == REGISTER_LIMIT ? fn->codeBlock()->functionName().string() : registerFile[code->m_objectPropertyNameRegisterIndex];
updateObjectGetterSetterFunctionName(state, fn, pName, code->m_isGetter);
JSGetterSetter* gs;
if (code->m_isGetter) {
gs = new (alloca(sizeof(JSGetterSetter))) JSGetterSetter(registerFile[code->m_objectPropertyValueRegisterIndex].asFunction(), Value(Value::EmptyValue));
Expand All @@ -4430,11 +4497,14 @@ NEVER_INLINE void InterpreterSlowPath::defineObjectGetterSetter(ExecutionState&
Object* object = registerFile[code->m_objectRegisterIndex].toObject(state);
const size_t minCacheFillCount = 2;
if (object->structure() == code->m_inlineCachedStructureBefore) {
FunctionObject* fn = registerFile[code->m_objectPropertyValueRegisterIndex].asFunction();
updateObjectGetterSetterFunctionName(state, fn,
code->m_objectPropertyNameRegisterIndex == REGISTER_LIMIT ? fn->codeBlock()->functionName().string() : registerFile[code->m_objectPropertyNameRegisterIndex], code->m_isGetter);
JSGetterSetter* gs;
if (code->m_isGetter) {
gs = new JSGetterSetter(registerFile[code->m_objectPropertyValueRegisterIndex].asFunction(), Value(Value::EmptyValue));
gs = new JSGetterSetter(fn, Value(Value::EmptyValue));
} else {
gs = new JSGetterSetter(Value(Value::EmptyValue), registerFile[code->m_objectPropertyValueRegisterIndex].asFunction());
gs = new JSGetterSetter(Value(Value::EmptyValue), fn);
}
object->m_values.push_back(Value(gs), code->m_inlineCachedStructureAfter->propertyCount());
object->m_structure = code->m_inlineCachedStructureAfter;
Expand Down
24 changes: 12 additions & 12 deletions src/parser/ast/ObjectExpressionNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,7 @@ class ObjectExpressionNode : public ExpressionNode {
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 {
if (!property->astNode()->isProperty()) {
allSimpleCase = false;
break;
}
Expand All @@ -79,8 +73,6 @@ class ObjectExpressionNode : public ExpressionNode {
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()) {
Expand All @@ -93,9 +85,17 @@ class ObjectExpressionNode : public ExpressionNode {
}

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();
if (p->kind() == PropertyNode::Kind::Init) {
bool hasFunctionOnRightSide = p->value()->type() == ASTNodeType::FunctionExpression || p->value()->type() == ASTNodeType::ArrowFunctionExpression;
bool hasClassOnRightSide = p->value()->type() == ASTNodeType::ClassExpression && !p->value()->asClassExpression()->classNode().classBody()->hasStaticMemberName(codeBlock->m_codeBlock->context()->staticStrings().name);
codeBlock->pushCode(CreateObjectPrepare(ByteCodeLOC(m_loc.index), hasKeyName, dataIndex, propertyIndex, valueIndex, !hasKeyName && (hasFunctionOnRightSide | hasClassOnRightSide)), context, this->m_loc.index);
} else {
ASSERT(p->kind() == PropertyNode::Kind::Get || p->kind() == PropertyNode::Kind::Set);
codeBlock->pushCode(CreateObjectPrepare(ByteCodeLOC(m_loc.index), hasKeyName, p->kind() == PropertyNode::Kind::Get, dataIndex, propertyIndex, valueIndex), context, this->m_loc.index);
}

context->giveUpRegister(); // value
context->giveUpRegister(); // key
}

codeBlock->pushCode(CreateObject(ByteCodeLOC(m_loc.index), dstRegister, dataIndex), context, this->m_loc.index);
Expand Down
2 changes: 2 additions & 0 deletions src/runtime/ObjectStructure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ ObjectStructure* ObjectStructure::create(Context* ctx, ObjectStructureItemTightV
bool hasSymbol = false;
bool hasNonAtomicPropertyName = false;
bool hasEnumerableProperty = true;
bool isInlineCacheable = true;

for (size_t i = 0; i < properties.size(); i++) {
const ObjectStructurePropertyName& propertyName = properties[i].m_propertyName;
if (propertyName.isSymbol()) {
Expand Down
Loading

0 comments on commit ac3194f

Please sign in to comment.