diff options
author | Lars Knoll <[email protected]> | 2017-11-13 15:00:20 +0100 |
---|---|---|
committer | Lars Knoll <[email protected]> | 2017-11-27 11:09:53 +0000 |
commit | d31304eab9e7424edc20fb83a8a19cd979458029 (patch) | |
tree | 027bdee6f8a64ff59def96a52a88bdeff9053ca5 /src/qml/jsruntime/qv4lookup.cpp | |
parent | 71f0bc8ce6244d4544dcd35a62ed8f163bb5b092 (diff) |
Refactor getter lookups
Use the new id of InternalClass to simplify out lookup code
for getters. Now all lookups in the prototype chain can be
done at the same speed independent of the depth within the
prototype chain with only two checks.
Change-Id: I7d8451cc54c0ac50c1bcb4ae3bf386fd5f2a84aa
Reviewed-by: Erik Verbruggen <[email protected]>
Diffstat (limited to 'src/qml/jsruntime/qv4lookup.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4lookup.cpp | 292 |
1 files changed, 134 insertions, 158 deletions
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index c603d424ed..bbc33def10 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -87,6 +87,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs Heap::Object *obj = thisObject->d(); ExecutionEngine *engine = thisObject->engine(); Identifier *name = engine->identifierTable->identifier(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); + int i = 0; while (i < Size && obj) { classList[i] = obj->internalClass; @@ -117,10 +118,57 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs return Primitive::emptyValue().asReturnedValue(); } +ReturnedValue Lookup::resolveGetter(ExecutionEngine *engine, const Object *object) +{ + Heap::Object *obj = object->d(); + Identifier *name = engine->identifierTable->identifier(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); + + uint index = obj->internalClass->find(name); + if (index != UINT_MAX) { + PropertyAttributes attrs = obj->internalClass->propertyData.at(index); + uint nInline = obj->vtable()->nInlineProperties; + if (attrs.isData()) { + if (index < obj->vtable()->nInlineProperties) { + index += obj->vtable()->inlinePropertyOffset; + getter = getter0Inline; + } else { + index -= nInline; + getter = getter0MemberData; + } + } else { + getter = getterAccessor; + } + objectLookup.ic = obj->internalClass; + objectLookup.offset = index; + return getter(this, engine, *object); + } + + protoLookup.icIdentifier = obj->internalClass->id; + obj = obj->prototype(); + while (obj) { + uint index = obj->internalClass->find(name); + if (index != UINT_MAX) { + PropertyAttributes attrs = obj->internalClass->propertyData.at(index); + protoLookup.data = obj->propertyData(index); + if (attrs.isData()) { + getter = getterProto; + } else { + getter = getterProtoAccessor; + } + return getter(this, engine, *object); + } + obj = obj->prototype(); + } + // ### put in a getterNotFound! + getter = getterFallback; + return getter(this, engine, *object); +} + ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (const Object *o = object.as<Object>()) - return o->getLookup(l); + if (const Object *o = object.as<Object>()) { + return l->resolveGetter(engine, o); + } Object *proto; switch (object.type()) { @@ -179,51 +227,45 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object) { - Lookup l1 = *l; + if (const Object *o = object.as<Object>()) { + Lookup first = *l; + Lookup second = *l; - if (l1.getter == Lookup::getter0MemberData || l1.getter == Lookup::getter0Inline || l1.getter == Lookup::getter1) { - if (const Object *o = object.as<Object>()) { - ReturnedValue v = o->getLookup(l); - Lookup l2 = *l; - - if (l2.index != UINT_MAX) { - if (l1.getter != Lookup::getter0Inline) { - if (l2.getter == Lookup::getter0Inline || - (l1.getter != Lookup::getter0MemberData && l2.getter == Lookup::getter0MemberData)) - // sort the better getter first - qSwap(l1, l2); - } + ReturnedValue result = second.resolveGetter(engine, o); - l->classList[0] = l1.classList[0]; - l->classList[1] = l1.classList[1]; - l->classList[2] = l2.classList[0]; - l->classList[3] = l2.classList[1]; - l->index = l1.index; - l->index2 = l2.index; - - if (l1.getter == Lookup::getter0Inline) { - if (l2.getter == Lookup::getter0Inline) - l->getter = Lookup::getter0Inlinegetter0Inline; - else if (l2.getter == Lookup::getter0MemberData) - l->getter = Lookup::getter0Inlinegetter0MemberData; - else if (l2.getter == Lookup::getter1) - l->getter = Lookup::getter0Inlinegetter1; - else - Q_UNREACHABLE(); - } else if (l1.getter == Lookup::getter0MemberData) { - if (l2.getter == Lookup::getter0MemberData) - l->getter = Lookup::getter0MemberDatagetter0MemberData; - else if (l2.getter == Lookup::getter1) - l->getter = Lookup::getter0MemberDatagetter1; - else - Q_UNREACHABLE(); - } else { - Q_ASSERT(l1.getter == Lookup::getter1 && l2.getter == Lookup::getter1); - l->getter = Lookup::getter1getter1; - } - return v; - } + if (first.getter == getter0Inline && (second.getter == getter0Inline || second.getter == getter0MemberData)) { + l->objectLookupTwoClasses.ic = first.objectLookup.ic; + l->objectLookupTwoClasses.ic2 = second.objectLookup.ic; + l->objectLookupTwoClasses.offset = first.objectLookup.offset; + l->objectLookupTwoClasses.offset2 = second.objectLookup.offset; + l->getter = second.getter == getter0Inline ? getter0Inlinegetter0Inline : getter0Inlinegetter0MemberData; + return result; + } + if (first.getter == getter0MemberData && (second.getter == getter0Inline || second.getter == getter0MemberData)) { + l->objectLookupTwoClasses.ic = second.objectLookup.ic; + l->objectLookupTwoClasses.ic2 = first.objectLookup.ic; + l->objectLookupTwoClasses.offset = second.objectLookup.offset; + l->objectLookupTwoClasses.offset2 = first.objectLookup.offset; + l->getter = second.getter == getter0Inline ? getter0Inlinegetter0MemberData : getter0MemberDatagetter0MemberData; + return result; + } + if (first.getter == getterProto && second.getter == getterProto) { + l->protoLookupTwoClasses.icIdentifier = first.protoLookup.icIdentifier; + l->protoLookupTwoClasses.icIdentifier2 = second.protoLookup.icIdentifier; + l->protoLookupTwoClasses.data = first.protoLookup.data; + l->protoLookupTwoClasses.data2 = second.protoLookup.data; + l->getter = getterProtoTwoClasses; + return result; + } + if (first.getter == getterProtoAccessor && second.getter == getterProtoAccessor) { + l->protoLookupTwoClasses.icIdentifier = first.protoLookup.icIdentifier; + l->protoLookupTwoClasses.icIdentifier2 = second.protoLookup.icIdentifier; + l->protoLookupTwoClasses.data = first.protoLookup.data; + l->protoLookupTwoClasses.data2 = second.protoLookup.data; + l->getter = getterProtoAccessorTwoClasses; + return result; } + } l->getter = getterFallback; @@ -246,8 +288,8 @@ ReturnedValue Lookup::getter0MemberData(Lookup *l, ExecutionEngine *engine, cons // the internal class won't match Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); if (o) { - if (l->classList[0] == o->internalClass) - return o->memberData->values.data()[l->index].asReturnedValue(); + if (l->objectLookup.ic == o->internalClass) + return o->memberData->values.data()[l->objectLookup.offset].asReturnedValue(); } return getterTwoClasses(l, engine, object); } @@ -258,53 +300,34 @@ ReturnedValue Lookup::getter0Inline(Lookup *l, ExecutionEngine *engine, const Va // the internal class won't match Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); if (o) { - if (l->classList[0] == o->internalClass) - return o->inlinePropertyDataWithOffset(l->index)->asReturnedValue(); + if (l->objectLookup.ic == o->internalClass) + return o->inlinePropertyDataWithOffset(l->objectLookup.offset)->asReturnedValue(); } return getterTwoClasses(l, engine, object); } -ReturnedValue Lookup::getter1(Lookup *l, ExecutionEngine *engine, const Value &object) +ReturnedValue Lookup::getterProto(Lookup *l, ExecutionEngine *engine, const Value &object) { // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); if (o) { - if (l->classList[0] == o->internalClass && l->classList[1] == l->proto->internalClass) - return l->proto->propertyData(l->index)->asReturnedValue(); + if (l->protoLookup.icIdentifier == o->internalClass->id) + return l->protoLookup.data->asReturnedValue(); } return getterTwoClasses(l, engine, object); } -ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &object) -{ - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); - if (o) { - if (l->classList[0] == o->internalClass) { - Q_ASSERT(l->proto == o->prototype()); - if (l->classList[1] == l->proto->internalClass) { - Heap::Object *p = l->proto->prototype(); - if (l->classList[2] == p->internalClass) - return p->propertyData(l->index)->asReturnedValue(); - } - } - } - l->getter = getterFallback; - return getterFallback(l, engine, object); -} - ReturnedValue Lookup::getter0Inlinegetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object) { // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); if (o) { - if (l->classList[0] == o->internalClass) - return o->inlinePropertyDataWithOffset(l->index)->asReturnedValue(); - if (l->classList[2] == o->internalClass) - return o->inlinePropertyDataWithOffset(l->index2)->asReturnedValue(); + if (l->objectLookupTwoClasses.ic == o->internalClass) + return o->inlinePropertyDataWithOffset(l->objectLookupTwoClasses.offset)->asReturnedValue(); + if (l->objectLookupTwoClasses.ic2 == o->internalClass) + return o->inlinePropertyDataWithOffset(l->objectLookupTwoClasses.offset2)->asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); @@ -316,10 +339,10 @@ ReturnedValue Lookup::getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine // the internal class won't match Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); if (o) { - if (l->classList[0] == o->internalClass) - return o->inlinePropertyDataWithOffset(l->index)->asReturnedValue(); - if (l->classList[2] == o->internalClass) - return o->memberData->values.data()[l->index2].asReturnedValue(); + if (l->objectLookupTwoClasses.ic == o->internalClass) + return o->inlinePropertyDataWithOffset(l->objectLookupTwoClasses.offset)->asReturnedValue(); + if (l->objectLookupTwoClasses.ic2 == o->internalClass) + return o->memberData->values.data()[l->objectLookupTwoClasses.offset2].asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); @@ -331,128 +354,81 @@ ReturnedValue Lookup::getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEng // the internal class won't match Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); if (o) { - if (l->classList[0] == o->internalClass) - return o->memberData->values.data()[l->index].asReturnedValue(); - if (l->classList[2] == o->internalClass) - return o->memberData->values.data()[l->index2].asReturnedValue(); + if (l->objectLookupTwoClasses.ic == o->internalClass) + return o->memberData->values.data()[l->objectLookupTwoClasses.offset].asReturnedValue(); + if (l->objectLookupTwoClasses.ic2 == o->internalClass) + return o->memberData->values.data()[l->objectLookupTwoClasses.offset2].asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); } -ReturnedValue Lookup::getter0Inlinegetter1(Lookup *l, ExecutionEngine *engine, const Value &object) +ReturnedValue Lookup::getterProtoTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object) { // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); if (o) { - if (l->classList[0] == o->internalClass) - return o->inlinePropertyDataWithOffset(l->index)->asReturnedValue(); - if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index2)->asReturnedValue(); - } - l->getter = getterFallback; - return getterFallback(l, engine, object); -} - -ReturnedValue Lookup::getter0MemberDatagetter1(Lookup *l, ExecutionEngine *engine, const Value &object) -{ - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); - if (o) { - if (l->classList[0] == o->internalClass) - return o->memberData->values.data()[l->index].asReturnedValue(); - if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index2)->asReturnedValue(); - } - l->getter = getterFallback; - return getterFallback(l, engine, object); -} - -ReturnedValue Lookup::getter1getter1(Lookup *l, ExecutionEngine *engine, const Value &object) -{ - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); - if (o) { - if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index)->asReturnedValue(); - if (l->classList[2] == o->internalClass && - l->classList[3] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index2)->asReturnedValue(); + if (l->protoLookupTwoClasses.icIdentifier == o->internalClass->id) + return l->protoLookupTwoClasses.data->asReturnedValue(); + if (l->protoLookupTwoClasses.icIdentifier2 == o->internalClass->id) + return l->protoLookupTwoClasses.data2->asReturnedValue(); return getterFallback(l, engine, object); } l->getter = getterFallback; return getterFallback(l, engine, object); } - -ReturnedValue Lookup::getterAccessor0(Lookup *l, ExecutionEngine *engine, const Value &object) +ReturnedValue Lookup::getterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object) { // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); if (o) { - if (l->classList[0] == o->internalClass) { - Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); - if (!getter) + if (l->objectLookup.ic == o->internalClass) { + const Value *getter = o->propertyData(l->objectLookup.offset); + if (!getter->isFunctionObject()) // ### catch at resolve time return Encode::undefined(); - JSCallData jsCallData(scope); - *jsCallData->thisObject = object; - return getter->call(jsCallData); + return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0); } } l->getter = getterFallback; return getterFallback(l, engine, object); } -ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object) +ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, const Value &object) { // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); - if (o) { - if (l->classList[0] == o->internalClass && - l->classList[1] == l->proto->internalClass) { - Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset)); - if (!getter) - return Encode::undefined(); + if (o && l->protoLookup.icIdentifier == o->internalClass->id) { + const Value *getter = l->protoLookup.data; + if (!getter->isFunctionObject()) // ### catch at resolve time + return Encode::undefined(); - JSCallData jsCallData(scope); - *jsCallData->thisObject = object; - return getter->call(jsCallData); - } + return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0); } - l->getter = getterFallback; - return getterFallback(l, engine, object); + l->getter = getterTwoClasses; + return getterTwoClasses(l, engine, object); } -ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const Value &object) +ReturnedValue Lookup::getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object) { // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); if (o) { - if (l->classList[0] == o->internalClass) { - Q_ASSERT(o->prototype() == l->proto); - if (l->classList[1] == l->proto->internalClass) { - o = l->proto->prototype(); - if (l->classList[2] == o->internalClass) { - Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); - if (!getter) - return Encode::undefined(); - - JSCallData jsCallData(scope); - *jsCallData->thisObject = object; - return getter->call(jsCallData); - } - } + const Value *getter = nullptr; + if (l->protoLookupTwoClasses.icIdentifier == o->internalClass->id) + getter = l->protoLookupTwoClasses.data; + else if (l->protoLookupTwoClasses.icIdentifier2 == o->internalClass->id) + getter = l->protoLookupTwoClasses.data2; + if (getter) { + if (!getter->isFunctionObject()) // ### catch at resolve time + return Encode::undefined(); + + return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0); } } l->getter = getterFallback; |