From 99594f518a5fb657b75f68bba73537c4e9208e46 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 3 May 2017 08:45:28 +0200 Subject: Re-add some inline property storage It turns out that not using any inline property storage comes at a relatively high price in terms of memory consumption, as we always need to also create a memberData for any object. This avoids the memberData creation in quite a few cases, as we use the additional padding we have up to the 32 byte boundary given by the memory manager to store some property data. This complicates property access somewhat. To avoid performance regressions because of this, add specialized QV4::Lookup functions that optimize for properties that are inline or in the memberData struct. Change seems to be performance neutral on v8-bench on x86_64, but reduces peak memory usage when running the benchmark by around 20%. Change-Id: I0127d31a2d6038aaa540c4c4a1156f45ca3b7464 Reviewed-by: Simon Hausmann Reviewed-by: Robin Burchell --- src/qml/jsruntime/qv4object_p.h | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'src/qml/jsruntime/qv4object_p.h') diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 6a543ae1a8..c1d5fd66b2 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -71,8 +71,25 @@ struct Object : Base { void init() { Base::init(); } void destroy() { Base::destroy(); } - const Value *propertyData(uint index) const { return memberData->data + index; } - Value *propertyData(uint index) { return memberData->data + index; } + const Value *inlinePropertyData(uint index) const { + Q_ASSERT(index < vt->nInlineProperties); + return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + } + + const Value *propertyData(uint index) const { + uint nInline = vt->nInlineProperties; + if (index < nInline) + return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + index -= nInline; + return memberData->data + index; + } + Value *propertyData(uint index) { + uint nInline = vt->nInlineProperties; + if (index < nInline) + return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + index -= nInline; + return memberData->data + index; + } InternalClass *internalClass; Pointer prototype; -- cgit v1.2.3 From 799f4a526375701d2b68d2ca1c85648994468394 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 3 May 2017 15:11:55 +0200 Subject: Optimize other lookups Add some more optimized lookups for accessing properties stored inline or in the memberData. Change-Id: Id74901d1dd91fd60933bf164c2bf90fed86232e3 Reviewed-by: Simon Hausmann Reviewed-by: Robin Burchell --- src/qml/jsruntime/qv4object_p.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/qml/jsruntime/qv4object_p.h') diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index c1d5fd66b2..45392c0486 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -75,6 +75,10 @@ struct Object : Base { Q_ASSERT(index < vt->nInlineProperties); return reinterpret_cast(this) + vt->inlinePropertyOffset + index; } + Value *inlinePropertyData(uint index) { + Q_ASSERT(index < vt->nInlineProperties); + return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + } const Value *propertyData(uint index) const { uint nInline = vt->nInlineProperties; -- cgit v1.2.3 From 931239579d60eff13ef4f7674cc10f27d7bbdf71 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 May 2017 10:16:51 +0200 Subject: Move the list of default internal classes into EngineBase And store them in an enumerated array. This will simplify upcoming changes. Change-Id: I82eac03b9f6264843ae625e36e150464fe08be9d Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4object_p.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/qml/jsruntime/qv4object_p.h') diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 45392c0486..80bfbe941a 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -138,8 +138,8 @@ struct Object : Base { V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); #define V4_INTERNALCLASS(c) \ - static QV4::InternalClass *defaultInternalClass(QV4::ExecutionEngine *e) \ - { return e->c; } + static QV4::InternalClass *defaultInternalClass(QV4::EngineBase *e) \ +{ return e->internalClasses[QV4::EngineBase::Class_##c]; } #define V4_PROTOTYPE(p) \ static QV4::Object *defaultPrototype(QV4::ExecutionEngine *e) \ { return e->p(); } @@ -198,7 +198,7 @@ QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF struct Q_QML_EXPORT Object: Managed { V4_OBJECT2(Object, Object) Q_MANAGED_TYPE(Object) - V4_INTERNALCLASS(emptyClass) + V4_INTERNALCLASS(Object) V4_PROTOTYPE(objectPrototype) enum { @@ -472,7 +472,7 @@ struct NumberObject: Object { struct ArrayObject: Object { V4_OBJECT2(ArrayObject, Object) Q_MANAGED_TYPE(ArrayObject) - V4_INTERNALCLASS(arrayClass) + V4_INTERNALCLASS(ArrayObject) V4_PROTOTYPE(arrayPrototype) void init(ExecutionEngine *engine); -- cgit v1.2.3 From 70a49fe042dd244926cc4a9cb6affb8b4f3d9b7f Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 May 2017 10:29:23 +0200 Subject: Add ICs for String, MemberData and ArrayData Change-Id: I43ddcb4842e501cbea8a950ab6ffa2d906014efd Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4object_p.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/qml/jsruntime/qv4object_p.h') diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 80bfbe941a..e1b2a40b94 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -137,9 +137,6 @@ struct Object : Base { } \ V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); -#define V4_INTERNALCLASS(c) \ - static QV4::InternalClass *defaultInternalClass(QV4::EngineBase *e) \ -{ return e->internalClasses[QV4::EngineBase::Class_##c]; } #define V4_PROTOTYPE(p) \ static QV4::Object *defaultPrototype(QV4::ExecutionEngine *e) \ { return e->p(); } -- cgit v1.2.3 From cdbc4b83d59e08189d6ece9ccd88a646be155c08 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 May 2017 15:01:07 +0200 Subject: Properly encapsulate all accesses to the vtable Change-Id: I3f6ae59d01c7b6c898e98d3b6f65b84a19b8851a Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4object_p.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/qml/jsruntime/qv4object_p.h') diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index e1b2a40b94..78ee263c80 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -72,25 +72,25 @@ struct Object : Base { void destroy() { Base::destroy(); } const Value *inlinePropertyData(uint index) const { - Q_ASSERT(index < vt->nInlineProperties); - return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + Q_ASSERT(index < vtable()->nInlineProperties); + return reinterpret_cast(this) + vtable()->inlinePropertyOffset + index; } Value *inlinePropertyData(uint index) { - Q_ASSERT(index < vt->nInlineProperties); - return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + Q_ASSERT(index < vtable()->nInlineProperties); + return reinterpret_cast(this) + vtable()->inlinePropertyOffset + index; } const Value *propertyData(uint index) const { - uint nInline = vt->nInlineProperties; + uint nInline = vtable()->nInlineProperties; if (index < nInline) - return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + return reinterpret_cast(this) + vtable()->inlinePropertyOffset + index; index -= nInline; return memberData->data + index; } Value *propertyData(uint index) { - uint nInline = vt->nInlineProperties; + uint nInline = vtable()->nInlineProperties; if (index < nInline) - return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + return reinterpret_cast(this) + vtable()->inlinePropertyOffset + index; index -= nInline; return memberData->data + index; } -- cgit v1.2.3 From cae7975a036352ca4bbcf1381a445362f8e01367 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 May 2017 15:12:45 +0200 Subject: Move the internalClass field from Heap::Object to Heap::Base And do not store the vtable in Heap::Base anymore. This change makes the internal class the main distinguishing feature of all garbage collected objects. It also saves one pointer on all Objects. No measurable impact on runtime performance. Change-Id: I040a28b7581b993f1886b5219e279173dfa567e8 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4object_p.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/qml/jsruntime/qv4object_p.h') diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 78ee263c80..951659a4bc 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -95,7 +95,6 @@ struct Object : Base { return memberData->data + index; } - InternalClass *internalClass; Pointer prototype; Pointer memberData; Pointer arrayData; @@ -204,7 +203,6 @@ struct Q_QML_EXPORT Object: Managed { SetterOffset = 1 }; - InternalClass *internalClass() const { return d()->internalClass; } void setInternalClass(InternalClass *ic); const Value *propertyData(uint index) const { return d()->propertyData(index); } -- cgit v1.2.3 From afbb57ae84ecbee5fab9eb6e58356b19d7995ea5 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 15 May 2017 09:56:05 +0200 Subject: Move the prototype into the internal class This saves another pointer on all Objects. Currently introduces a slight performance regression on some of the v8 benchmarks, that needs addressing. Change-Id: I87de8e1d198d2683f4e903c467ce2a60ba542243 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4object_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/qml/jsruntime/qv4object_p.h') diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 951659a4bc..cf04a84175 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -95,7 +95,7 @@ struct Object : Base { return memberData->data + index; } - Pointer prototype; + Heap::Object *prototype() const { return internalClass->prototype; } Pointer memberData; Pointer arrayData; }; @@ -215,7 +215,7 @@ struct Q_QML_EXPORT Object: Managed { void setProperty(uint index, const Property *p); const ObjectVTable *vtable() const { return reinterpret_cast(d()->vtable()); } - Heap::Object *prototype() const { return d()->prototype; } + Heap::Object *prototype() const { return d()->prototype(); } bool setPrototype(Object *proto); void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0); -- cgit v1.2.3 From 5bc38a50308665bdc185eb96dbcc9ba7948ab4e0 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 19 May 2017 12:39:52 +0200 Subject: Get rid of the old way of defining builtin functions The old calling convention used for builtin functions is very inefficient. It was still being used in a few places. Clean those up and convert them to the new and much more effiecient calling convention. Change-Id: I6b769c6185df7e9be1e80709330fc1ca868576c1 Reviewed-by: Robin Burchell --- src/qml/jsruntime/qv4object_p.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/qml/jsruntime/qv4object_p.h') diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index cf04a84175..a9afe14129 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -255,12 +255,8 @@ struct Q_QML_EXPORT Object: Managed { insertMember(name, value, Attr_Data|Attr_NotEnumerable); } void defineDefaultProperty(const QString &name, const Value &value); - void defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount = 0); void defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0); - void defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount = 0); void defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0); - void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)); - void defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)); void defineAccessorProperty(const QString &name, void (*getter)(const BuiltinFunction *, Scope &, CallData *), void (*setter)(const BuiltinFunction *, Scope &, CallData *)); void defineAccessorProperty(String *name, void (*getter)(const BuiltinFunction *, Scope &, CallData *), -- cgit v1.2.3 From 8bc243f569e3feb1005fbca426bf24f59c38af2e Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 19 May 2017 15:50:22 +0200 Subject: Move the engine() accessor from Object to Managed We can easily do this now that Managed has a pointer to an internal class (which always has a back pointer to the ExecutionEngine). Remove the extra engine pointer from ExecutionContext, and clean up tow methods in String. Change-Id: I98d750b1afbdeadf42e66ae0c92c48db1a7adc31 Reviewed-by: Robin Burchell --- src/qml/jsruntime/qv4object_p.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/qml/jsruntime/qv4object_p.h') diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index a9afe14129..9592ff5d1b 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -273,8 +273,6 @@ struct Q_QML_EXPORT Object: Managed { } void insertMember(String *s, const Property *p, PropertyAttributes attributes); - inline ExecutionEngine *engine() const { return internalClass()->engine; } - bool isExtensible() const { return d()->internalClass->extensible; } // Array handling -- cgit v1.2.3