From b8ca4132433c2d1eef0a6cda8be8a1754786702b Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 5 Mar 2014 08:40:11 +0100 Subject: [PATCH] Better way of retrieving the prototype property for FunctionObjects Make sure FunctionObjects always have the prototype property at index 0. This way we can speed up the instanceOf operator even more, and at the same time save 16-28 bytes of memory per FunctionObject. Change-Id: I8527bc8f9dc7b04a9db8395b5f05bab47ddc21ce Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4engine.cpp | 2 +- src/qml/jsruntime/qv4engine_p.h | 1 - src/qml/jsruntime/qv4functionobject.cpp | 75 ++++++++++----------------------- src/qml/jsruntime/qv4functionobject_p.h | 18 ++++---- 4 files changed, 31 insertions(+), 65 deletions(-) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 6b2d1e6..1807513 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -283,7 +283,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(InternalClass::create(this, FunctionPrototype::staticVTable(), objectPrototype)); functionClass = InternalClass::create(this, FunctionObject::staticVTable(), functionPrototype); uint index; - functionWithProtoClass = functionClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index); + functionClass = functionClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == FunctionObject::Index_Prototype); protoClass = objectClass->addMember(id_constructor, Attr_NotEnumerable, &index); Q_ASSERT(index == FunctionObject::Index_ProtoConstructor); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index cbe9815..14358c1 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -210,7 +210,6 @@ public: InternalClass *dateClass; InternalClass *functionClass; - InternalClass *functionWithProtoClass; InternalClass *protoClass; InternalClass *regExpClass; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index f096649..9a3aa33 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -75,21 +75,17 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(FunctionObject); FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto) - : Object(createProto ? scope->engine->functionWithProtoClass : scope->engine->functionClass) + : Object(scope->engine->functionClass) , scope(scope) , function(0) - , protoCacheClass(0) - , protoCacheIndex(UINT_MAX) { init(name, createProto); } FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto) - : Object(createProto ? scope->engine->functionWithProtoClass : scope->engine->functionClass) + : Object(scope->engine->functionClass) , scope(scope) , function(0) - , protoCacheClass(0) - , protoCacheIndex(UINT_MAX) { Scope s(scope); ScopedValue protectThis(s, this); @@ -101,8 +97,6 @@ FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValue name : Object(scope->engine->functionClass) , scope(scope) , function(0) - , protoCacheClass(0) - , protoCacheIndex(UINT_MAX) { Scope s(scope); ScopedValue protectThis(s, this); @@ -117,6 +111,7 @@ FunctionObject::FunctionObject(InternalClass *ic) { needsActivation = false; strictMode = false; + memberData[Index_Prototype].value = Encode::undefined(); } FunctionObject::~FunctionObject() @@ -137,6 +132,9 @@ void FunctionObject::init(const StringRef n, bool createProto) Scoped proto(s, scope->engine->newObject(scope->engine->protoClass)); proto->memberData[Index_ProtoConstructor].value = this->asReturnedValue(); memberData[Index_Prototype].value = proto.asReturnedValue(); + } else { + // ### Empty or undefined? + memberData[Index_Prototype].value = Encode::undefined(); } ScopedValue v(s, n.asReturnedValue()); @@ -158,13 +156,8 @@ ReturnedValue FunctionObject::newInstance() ReturnedValue FunctionObject::construct(Managed *that, CallData *) { - ExecutionEngine *v4 = that->internalClass->engine; - Scope scope(v4); - Scoped f(scope, that, Scoped::Cast); - - InternalClass *ic = f->internalClassForConstructor(); - Scoped obj(scope, v4->newObject(ic)); - return obj.asReturnedValue(); + that->internalClass->engine->currentContext()->throwTypeError(); + return Encode::undefined(); } ReturnedValue FunctionObject::call(Managed *, CallData *) @@ -190,43 +183,6 @@ FunctionObject *FunctionObject::creatScriptFunction(ExecutionContext *scope, Fun return new (scope->engine->memoryManager) SimpleScriptFunction(scope, function, createProto); } -ReturnedValue FunctionObject::protoProperty() -{ - if (protoCacheClass != internalClass) { - protoCacheClass = internalClass; - protoCacheIndex = internalClass->find(internalClass->engine->id_prototype); - } - if (protoCacheIndex < UINT_MAX) { - if (internalClass->propertyData.at(protoCacheIndex).isData()) { - ReturnedValue v = memberData[protoCacheIndex].value.asReturnedValue(); - if (v != protoValue) { - classForConstructor = 0; - protoValue = v; - } - return v; - } - } - classForConstructor = 0; - return get(internalClass->engine->id_prototype); -} - -InternalClass *FunctionObject::internalClassForConstructor() -{ - // need to call this first to ensure we don't use a wrong class - ReturnedValue proto = protoProperty(); - if (classForConstructor) - return classForConstructor; - - Scope scope(internalClass->engine); - ScopedObject p(scope, proto); - if (p) - classForConstructor = InternalClass::create(scope.engine, Object::staticVTable(), p.getPointer()); - else - classForConstructor = scope.engine->objectClass; - - return classForConstructor; -} - DEFINE_OBJECT_VTABLE(FunctionCtor); FunctionCtor::FunctionCtor(ExecutionContext *scope) @@ -395,7 +351,7 @@ ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) DEFINE_OBJECT_VTABLE(ScriptFunction); ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function) - : FunctionObject(scope, function->name(), true) + : SimpleScriptFunction(scope, function, true) { setVTable(staticVTable()); @@ -583,6 +539,19 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData) return result.asReturnedValue(); } +InternalClass *SimpleScriptFunction::internalClassForConstructor() +{ + ReturnedValue proto = protoProperty(); + InternalClass *classForConstructor; + Scope scope(internalClass->engine); + ScopedObject p(scope, proto); + if (p) + classForConstructor = InternalClass::create(scope.engine, Object::staticVTable(), p.getPointer()); + else + classForConstructor = scope.engine->objectClass; + + return classForConstructor; +} diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 3f432c2..a08dc60 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -116,10 +116,6 @@ struct Q_QML_EXPORT FunctionObject: Object { unsigned int formalParameterCount() { return function ? function->compiledFunction->nFormals : 0; } unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } Function *function; - InternalClass *protoCacheClass; - uint protoCacheIndex; - ReturnedValue protoValue; - InternalClass *classForConstructor; FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto = false); FunctionObject(ExecutionContext *scope, const QString &name = QString(), bool createProto = false); @@ -141,8 +137,7 @@ struct Q_QML_EXPORT FunctionObject: Object { static FunctionObject *creatScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true); - ReturnedValue protoProperty(); - InternalClass *internalClassForConstructor(); + ReturnedValue protoProperty() { return memberData[Index_Prototype].value.asReturnedValue(); } protected: FunctionObject(InternalClass *ic); @@ -213,22 +208,25 @@ struct IndexedBuiltinFunction: FunctionObject }; -struct ScriptFunction: FunctionObject { +struct SimpleScriptFunction: FunctionObject { V4_OBJECT - ScriptFunction(ExecutionContext *scope, Function *function); + SimpleScriptFunction(ExecutionContext *scope, Function *function, bool createProto); static ReturnedValue construct(Managed *, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); + + InternalClass *internalClassForConstructor(); }; -struct SimpleScriptFunction: FunctionObject { +struct ScriptFunction: SimpleScriptFunction { V4_OBJECT - SimpleScriptFunction(ExecutionContext *scope, Function *function, bool createProto); + ScriptFunction(ExecutionContext *scope, Function *function); static ReturnedValue construct(Managed *, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); }; + struct BoundFunction: FunctionObject { V4_OBJECT FunctionObject *target; -- 2.7.4