Skip to content

Commit 069fba1

Browse files
committed
Optimize big object expression through bloom filter
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
1 parent 9819a8d commit 069fba1

File tree

4 files changed

+65
-12
lines changed

4 files changed

+65
-12
lines changed

src/interpreter/ByteCode.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "interpreter/ByteCodeBlockData.h"
2424
#include "interpreter/ByteCodeGenerator.h"
2525
#include "runtime/ExecutionPauser.h"
26+
#include "util/BloomFilter.h"
2627

2728
#ifndef NDEBUG
2829
#include "parser/CodeBlock.h"
@@ -964,19 +965,25 @@ class CreateObjectPrepare : public ByteCode {
964965
DefineGetterSetter,
965966
};
966967

968+
typedef BloomFilter<1024> CreateObjectPropertyFilter;
969+
967970
struct CreateObjectData : public gc {
968971
bool m_allPrecomputed;
969972
bool m_wasStructureComputed;
970973
bool m_canStoreStructureOnCode;
974+
bool m_needsToUsePropertyFilterOnIntepreter;
971975
VectorWithInlineStorage<6, ObjectStructureItem, GCUtil::gc_malloc_allocator<ObjectStructureItem>> m_properties;
972976
EncodedValueVector m_values;
973977
Object* m_target;
974978
CreateObjectPrepare* m_initCode;
979+
Optional<CreateObjectPropertyFilter*> m_filter;
975980
CreateObjectData(bool allPrecomputed, bool wasStructureComputed, bool canStoreStructureOnCode,
981+
bool needsToUsePropertyFilterOnIntepreter,
976982
size_t reserveSize, Object* target, CreateObjectPrepare* initCode)
977983
: m_allPrecomputed(allPrecomputed)
978984
, m_wasStructureComputed(wasStructureComputed)
979985
, m_canStoreStructureOnCode(canStoreStructureOnCode)
986+
, m_needsToUsePropertyFilterOnIntepreter(needsToUsePropertyFilterOnIntepreter)
980987
, m_target(target)
981988
, m_initCode(initCode)
982989
{
@@ -987,10 +994,11 @@ class CreateObjectPrepare : public ByteCode {
987994
}
988995
};
989996

990-
CreateObjectPrepare(const ByteCodeLOC& loc, const size_t dataRegisterIndex, const size_t objectIndex)
997+
CreateObjectPrepare(const ByteCodeLOC& loc, const size_t dataRegisterIndex, const size_t objectIndex, bool needsToUseNameFilterOnIntepreter)
991998
: ByteCode(Opcode::CreateObjectPrepareOpcode, loc)
992999
, m_stage(Stage::Init)
9931000
, m_allPrecomputed(false)
1001+
, m_needsToUsePropertyFilterOnIntepreter(needsToUseNameFilterOnIntepreter)
9941002
, m_hasPrecomputedKey(false)
9951003
, m_needsToUpdateFunctionName(false)
9961004
, m_isGetter(false)
@@ -1004,6 +1012,7 @@ class CreateObjectPrepare : public ByteCode {
10041012
: ByteCode(Opcode::CreateObjectPrepareOpcode, loc)
10051013
, m_stage(Stage::FillKeyValue)
10061014
, m_allPrecomputed(false)
1015+
, m_needsToUsePropertyFilterOnIntepreter(false)
10071016
, m_hasPrecomputedKey(hasPreComputedKey)
10081017
, m_needsToUpdateFunctionName(needsToUpdateFunctionName)
10091018
, m_isGetter(false)
@@ -1017,6 +1026,7 @@ class CreateObjectPrepare : public ByteCode {
10171026
: ByteCode(Opcode::CreateObjectPrepareOpcode, loc)
10181027
, m_stage(Stage::DefineGetterSetter)
10191028
, m_allPrecomputed(false)
1029+
, m_needsToUsePropertyFilterOnIntepreter(false)
10201030
, m_hasPrecomputedKey(hasPreComputedKey)
10211031
, m_needsToUpdateFunctionName(false)
10221032
, m_isGetter(isGetter)
@@ -1028,6 +1038,7 @@ class CreateObjectPrepare : public ByteCode {
10281038

10291039
Stage m_stage : 2;
10301040
bool m_allPrecomputed : 1;
1041+
bool m_needsToUsePropertyFilterOnIntepreter : 1;
10311042
bool m_hasPrecomputedKey : 1;
10321043
bool m_needsToUpdateFunctionName : 1;
10331044
bool m_isGetter : 1; // other case, this is setter

src/interpreter/ByteCodeInterpreter.cpp

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3094,22 +3094,35 @@ static Value createObjectPropertyFunctionName(ExecutionState& state, const Value
30943094
NEVER_INLINE void InterpreterSlowPath::createObjectPrepareOperation(ExecutionState& state, CreateObjectPrepare* code, ByteCodeBlock* byteCodeBlock, Value* registerFile)
30953095
{
30963096
if (code->m_stage == CreateObjectPrepare::Init) {
3097-
void* ptr;
3097+
uint8_t* ptr;
30983098
if (byteCodeBlock->codeBlock()->isAsyncOrGenerator()) {
30993099
// async or generator uses ValueVector alloctor for allocating registerFile
31003100
// ValueVector allocator cannot track CreateObjectData if there is CreateObjectData on registerFile
3101-
ptr = GC_MALLOC(sizeof(CreateObjectPrepare::CreateObjectData));
3101+
ptr = reinterpret_cast<uint8_t*>(GC_MALLOC(sizeof(CreateObjectPrepare::CreateObjectData)));
31023102
registerFile[code->m_dataRegisterIndex] = Value(Value::FromPayload, reinterpret_cast<intptr_t>(ptr));
31033103
} else {
3104-
ptr = &registerFile[code->m_dataRegisterIndex];
3104+
ptr = reinterpret_cast<uint8_t*>(&registerFile[code->m_dataRegisterIndex]);
31053105
}
31063106
CreateObjectPrepare::CreateObjectData* data = new (ptr) CreateObjectPrepare::CreateObjectData(
31073107
code->m_allPrecomputed, code->m_cachedObjectStructure.hasValue(), code->m_allPrecomputed,
3108+
code->m_needsToUsePropertyFilterOnIntepreter,
31083109
code->m_propertyReserveSize, new Object(state), code);
31093110
registerFile[code->m_objectIndex] = data->m_target;
31103111
if (data->m_wasStructureComputed) {
31113112
data->m_target->m_structure = code->m_cachedObjectStructure.value();
31123113
}
3114+
if (UNLIKELY(data->m_needsToUsePropertyFilterOnIntepreter)) {
3115+
if (byteCodeBlock->codeBlock()->isAsyncOrGenerator()) {
3116+
data->m_filter = new (PointerFreeGC) CreateObjectPrepare::CreateObjectPropertyFilter();
3117+
} else {
3118+
size_t diff = sizeof(CreateObjectPrepare::CreateObjectData);
3119+
if (diff % sizeof(Value)) {
3120+
diff += (sizeof(Value) - (diff % sizeof(Value)));
3121+
}
3122+
data->m_filter = reinterpret_cast<CreateObjectPrepare::CreateObjectPropertyFilter*>(ptr + diff);
3123+
}
3124+
data->m_filter->clear();
3125+
}
31133126
} else {
31143127
ASSERT(code->m_stage == CreateObjectPrepare::FillKeyValue || code->m_stage == CreateObjectPrepare::DefineGetterSetter);
31153128
CreateObjectPrepare::CreateObjectData* data;
@@ -3146,15 +3159,29 @@ NEVER_INLINE void InterpreterSlowPath::createObjectPrepareOperation(ExecutionSta
31463159
return;
31473160
}
31483161

3162+
bool needsPropertySearch = true;
3163+
if (UNLIKELY(data->m_needsToUsePropertyFilterOnIntepreter)) {
3164+
auto newPropertyNameHash = (propertyName.isSymbol() ?
3165+
propertyName.symbol()->descriptionString()->hashValue() : propertyName.plainString()->hashValue());
3166+
if (data->m_filter->mayContain(newPropertyNameHash)) {
3167+
} else {
3168+
data->m_filter->add(newPropertyNameHash);
3169+
needsPropertySearch = false;
3170+
}
3171+
}
3172+
31493173
size_t lastPropertyCount = data->m_properties.size();
31503174
size_t targetIndex = lastPropertyCount;
31513175
bool updateProperty = false;
3152-
for (size_t i = 0; i < lastPropertyCount; i++) {
3153-
if (data->m_properties[i].m_propertyName == propertyName) {
3154-
targetIndex = i;
3155-
updateProperty = true;
3156-
data->m_canStoreStructureOnCode = false;
3157-
break;
3176+
3177+
if (LIKELY(needsPropertySearch)) {
3178+
for (size_t i = 0; i < lastPropertyCount; i++) {
3179+
if (data->m_properties[i].m_propertyName == propertyName) {
3180+
targetIndex = i;
3181+
updateProperty = true;
3182+
data->m_canStoreStructureOnCode = false;
3183+
break;
3184+
}
31583185
}
31593186
}
31603187

src/parser/ast/ObjectExpressionNode.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ class ObjectExpressionNode : public ExpressionNode {
6060
size_t objectCreationDataRegisterSize = 0;
6161
size_t initCodePosition = codeBlock->currentCodeSize();
6262

63+
bool needsToUseNameFilterOnIntepreter = m_properties.size() >= 6;
64+
if (needsToUseNameFilterOnIntepreter) {
65+
for (SentinelNode* property = m_properties.begin(); property != m_properties.end(); property = property->next()) {
66+
if (!property->astNode()->isProperty()) {
67+
needsToUseNameFilterOnIntepreter = false;
68+
}
69+
}
70+
}
71+
6372
if (m_properties.size()) {
6473
objectCreationDataIndex = context->getRegister();
6574
objectCreationDataRegisterSize = 1;
@@ -70,9 +79,15 @@ class ObjectExpressionNode : public ExpressionNode {
7079
objectCreationDataRegisterSize++;
7180
context->getRegister();
7281
}
82+
if (needsToUseNameFilterOnIntepreter) {
83+
for (size_t i = 0; i < sizeof(CreateObjectPrepare::CreateObjectPropertyFilter); i += sizeof(Value)) {
84+
objectCreationDataRegisterSize++;
85+
context->getRegister();
86+
}
87+
}
7388
}
7489

75-
codeBlock->pushCode(CreateObjectPrepare(ByteCodeLOC(m_loc.index), objectCreationDataIndex, dstRegister), context, this->m_loc.index);
90+
codeBlock->pushCode(CreateObjectPrepare(ByteCodeLOC(m_loc.index), objectCreationDataIndex, dstRegister, needsToUseNameFilterOnIntepreter), context, this->m_loc.index);
7691
}
7792

7893
bool allPrecomputed = true;

src/runtime/ObjectStructurePropertyName.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class ObjectStructurePropertyName {
4848
// same as `ToPropertyKey` https://262.ecma-international.org/#sec-topropertykey
4949
ObjectStructurePropertyName(ExecutionState& state, const Value& value);
5050

51-
size_t hashValue() const
51+
ALWAYS_INLINE size_t hashValue() const
5252
{
5353
if (LIKELY(hasAtomicString())) {
5454
std::hash<Escargot::AtomicString> hasher;

0 commit comments

Comments
 (0)