aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2017-05-15 09:56:05 +0200
committerLars Knoll <lars.knoll@qt.io>2017-05-19 06:23:29 +0000
commitafbb57ae84ecbee5fab9eb6e58356b19d7995ea5 (patch)
tree33418ab6f9507c238998c61fdd818cb8823db71a
parentcae7975a036352ca4bbcf1381a445362f8e01367 (diff)
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 <simon.hausmann@qt.io>
-rw-r--r--src/qml/jsruntime/qv4context_p.h1
-rw-r--r--src/qml/jsruntime/qv4engine.cpp106
-rw-r--r--src/qml/jsruntime/qv4engine_p.h2
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h2
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp3
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h18
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp17
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h5
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp53
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h26
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp60
-rw-r--r--src/qml/jsruntime/qv4object.cpp15
-rw-r--r--src/qml/jsruntime/qv4object_p.h4
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp1
-rw-r--r--src/qml/memory/qv4mm_p.h19
-rw-r--r--tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp2
17 files changed, 216 insertions, 119 deletions
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index c742df7b97..89ff6dc957 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -272,6 +272,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
struct Q_QML_EXPORT CallContext : public ExecutionContext
{
V4_MANAGED(CallContext, ExecutionContext)
+ V4_INTERNALCLASS(CallContext)
// formals are in reverse order
Identifier * const *formals() const;
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 6b05d9a05c..daab7ad279 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -213,12 +213,12 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
classPool = new InternalClassPool;
internalClasses[Class_Empty] = new (classPool) InternalClass(this);
- internalClasses[Class_Object] = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable());
internalClasses[Class_String] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::String::staticVTable());
internalClasses[Class_MemberData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::MemberData::staticVTable());
internalClasses[Class_SimpleArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable());
internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable());
internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable());
+ internalClasses[Class_CallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
jsStrings[String_Empty] = newIdentifier(QString());
jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined"));
@@ -257,15 +257,20 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer"));
jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex"));
- jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(internalClasses[Class_Object]);
+ InternalClass *ic = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable());
+ jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic);
+ internalClasses[Class_Object] = ic->changePrototype(objectPrototype()->d());
- internalClasses[Class_ArrayObject] = internalClasses[Class_Empty]->changeVTable(QV4::ArrayObject::staticVTable());
- internalClasses[Class_ArrayObject] = internalClasses[Class_ArrayObject]->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable);
- jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(internalClasses[Class_ArrayObject], objectPrototype());
+ ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype());
+ Q_ASSERT(ic->prototype);
+ ic = ic->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable);
+ Q_ASSERT(ic->prototype);
+ jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(ic, objectPrototype());
+ internalClasses[Class_ArrayObject] = ic->changePrototype(arrayPrototype()->d());
jsObjects[PropertyListProto] = memoryManager->allocObject<PropertyListPrototype>();
- InternalClass *argsClass = internalClasses[Class_Empty]->changeVTable(QV4::ArgumentsObject::staticVTable())
- ->addMember(id_length(), Attr_NotEnumerable);
+ InternalClass *argsClass = newInternalClass(ArgumentsObject::staticVTable(), objectPrototype());
+ argsClass = argsClass->addMember(id_length(), Attr_NotEnumerable);
internalClasses[EngineBase::Class_ArgumentsObject] = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable);
argsClass = argsClass->addMember(id_callee(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
internalClasses[EngineBase::Class_StrictArgumentsObject] = argsClass->addMember(id_caller(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
@@ -274,25 +279,31 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
Q_ASSERT(globalObject->d()->vtable());
initRootContext();
- internalClasses[Class_StringObject] = internalClasses[Class_Empty]->changeVTable(QV4::StringObject::staticVTable());
- internalClasses[EngineBase::Class_StringObject] = internalClasses[Class_StringObject]->addMember(id_length(), Attr_ReadOnly);
+ ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype());
+ ic = ic->addMember(id_length(), Attr_ReadOnly);
+ jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(ic);
+ internalClasses[Class_StringObject] = ic->changePrototype(stringPrototype()->d());
Q_ASSERT(internalClasses[EngineBase::Class_StringObject]->find(id_length()) == Heap::StringObject::LengthPropertyIndex);
- jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(internalClasses[EngineBase::Class_StringObject], objectPrototype());
+
jsObjects[NumberProto] = memoryManager->allocObject<NumberPrototype>();
jsObjects[BooleanProto] = memoryManager->allocObject<BooleanPrototype>();
jsObjects[DateProto] = memoryManager->allocObject<DatePrototype>();
uint index;
- InternalClass *functionProtoClass =
- internalClasses[Class_Empty]->changeVTable(QV4::FunctionPrototype::staticVTable())
- ->addMember(id_prototype(), Attr_NotEnumerable, &index);
+ ic = newInternalClass(QV4::FunctionPrototype::staticVTable(), objectPrototype());
+ ic = ic->addMember(id_prototype(), Attr_NotEnumerable, &index);
Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
- jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(functionProtoClass, objectPrototype());
- internalClasses[EngineBase::Class_FunctionObject] = internalClasses[Class_Object]->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
+ jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(ic, objectPrototype());
+ ic = newInternalClass(FunctionObject::staticVTable(), functionPrototype());
+ ic = ic->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
- internalClasses[EngineBase::Class_ScriptFunction] = internalClasses[EngineBase::Class_FunctionObject]->addMember(id_name(), Attr_ReadOnly, &index);
+ internalClasses[EngineBase::Class_FunctionObject] = ic;
+ ic = ic->addMember(id_name(), Attr_ReadOnly, &index);
Q_ASSERT(index == Heap::ScriptFunction::Index_Name);
- internalClasses[EngineBase::Class_ScriptFunction] = internalClasses[EngineBase::Class_ScriptFunction]->addMember(id_length(), Attr_ReadOnly, &index);
+ ic = ic->changeVTable(ScriptFunction::staticVTable());
+ internalClasses[EngineBase::Class_ScriptFunction] = ic->addMember(id_length(), Attr_ReadOnly, &index);
+ Q_ASSERT(index == Heap::ScriptFunction::Index_Length);
+ internalClasses[EngineBase::Class_BuiltinFunction] = ic->changeVTable(BuiltinFunction::staticVTable());
Q_ASSERT(index == Heap::ScriptFunction::Index_Length);
internalClasses[EngineBase::Class_ObjectProto] = internalClasses[Class_Object]->addMember(id_constructor(), Attr_NotEnumerable, &index);
Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor);
@@ -300,59 +311,59 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
Scope scope(this);
ScopedString str(scope);
internalClasses[Class_RegExp] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::RegExp::staticVTable());
- internalClasses[EngineBase::Class_RegExpObject] =
- internalClasses[Class_Empty]->changeVTable(QV4::RegExpObject::staticVTable())
- ->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
+ ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype());
+ ic = ic->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
Q_ASSERT(index == RegExpObject::Index_LastIndex);
- internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index);
Q_ASSERT(index == RegExpObject::Index_Source);
- internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index);
Q_ASSERT(index == RegExpObject::Index_Global);
- internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index);
Q_ASSERT(index == RegExpObject::Index_IgnoreCase);
- internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index);
Q_ASSERT(index == RegExpObject::Index_Multiline);
+ jsObjects[RegExpProto] = memoryManager->allocObject<RegExpPrototype>(ic, objectPrototype());
+ internalClasses[Class_RegExpObject] = ic->changePrototype(regExpPrototype()->d());
- jsObjects[RegExpProto] = memoryManager->allocObject<RegExpPrototype>(internalClasses[EngineBase::Class_RegExpObject], objectPrototype());
- internalClasses[EngineBase::Class_RegExpExecArray] = internalClasses[Class_ArrayObject]->addMember(id_index(), Attr_Data, &index);
+ ic = internalClasses[Class_ArrayObject]->addMember(id_index(), Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayIndex);
- internalClasses[EngineBase::Class_RegExpExecArray] = internalClasses[EngineBase::Class_RegExpExecArray]->addMember(id_input(), Attr_Data, &index);
+ internalClasses[EngineBase::Class_RegExpExecArray] = ic->addMember(id_input(), Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayInput);
- internalClasses[EngineBase::Class_ErrorObject] =
- internalClasses[Class_Empty]->changeVTable(QV4::ErrorObject::staticVTable())
- ->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index);
+ ic = newInternalClass(ErrorObject::staticVTable(), 0);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index);
Q_ASSERT(index == ErrorObject::Index_Stack);
- internalClasses[EngineBase::Class_ErrorObject] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index);
Q_ASSERT(index == ErrorObject::Index_FileName);
- internalClasses[EngineBase::Class_ErrorObject] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index);
+ internalClasses[EngineBase::Class_ErrorObject] = ic;
Q_ASSERT(index == ErrorObject::Index_LineNumber);
- internalClasses[EngineBase::Class_ErrorObjectWithMessage] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index);
+ internalClasses[EngineBase::Class_ErrorObjectWithMessage] = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index);
Q_ASSERT(index == ErrorObject::Index_Message);
- internalClasses[EngineBase::Class_ErrorProto] =
- internalClasses[Class_Empty]->changeVTable(QV4::ErrorPrototype::staticVTable())
- ->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index);
+ ic = newInternalClass(ErrorObject::staticVTable(), objectPrototype());
+ ic = ic->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index);
Q_ASSERT(index == ErrorPrototype::Index_Constructor);
- internalClasses[EngineBase::Class_ErrorProto] = internalClasses[EngineBase::Class_ErrorProto]->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index);
Q_ASSERT(index == ErrorPrototype::Index_Message);
- internalClasses[EngineBase::Class_ErrorProto] = internalClasses[EngineBase::Class_ErrorProto]->addMember(id_name(), Attr_Data|Attr_NotEnumerable, &index);
+ internalClasses[EngineBase::Class_ErrorProto] = ic->addMember(id_name(), Attr_Data|Attr_NotEnumerable, &index);
Q_ASSERT(index == ErrorPrototype::Index_Name);
jsObjects[GetStack_Function] = BuiltinFunction::create(rootContext(), str = newIdentifier(QStringLiteral("stack")), ErrorObject::method_get_stack);
getStackFunction()->defineReadonlyProperty(id_length(), Primitive::fromInt32(0));
jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto], objectPrototype());
- jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto], errorPrototype());
- jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto], errorPrototype());
- jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto], errorPrototype());
- jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto], errorPrototype());
- jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto], errorPrototype());
- jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto], errorPrototype());
+ jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
+ jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
+ jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
+ jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
+ jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
+ jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
jsObjects[VariantProto] = memoryManager->allocObject<VariantPrototype>();
Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d());
- jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>());
+ ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this));
+ jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(ic, SequencePrototype::defaultPrototype(this)));
ExecutionContext *global = rootContext();
jsObjects[Object_Ctor] = memoryManager->allocObject<ObjectCtor>(global);
@@ -538,6 +549,11 @@ ExecutionContext *ExecutionEngine::pushGlobalContext()
return currentContext;
}
+InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype)
+{
+ return internalClasses[EngineBase::Class_Empty]->changeVTable(vtable)->changePrototype(prototype ? prototype->d() : 0);
+}
+
Heap::Object *ExecutionEngine::newObject()
{
return memoryManager->allocObject<Object>();
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 1d07196c28..a569b8ddf9 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -366,6 +366,8 @@ public:
void popContext();
ExecutionContext *parentContext(ExecutionContext *context) const;
+ InternalClass *newInternalClass(const VTable *vtable, Object *prototype);
+
Heap::Object *newObject();
Heap::Object *newObject(InternalClass *internalClass, Object *prototype);
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index e124adb810..06c346b3c0 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -88,11 +88,13 @@ struct EngineBase {
Class_SimpleArrayData,
Class_SparseArrayData,
Class_ExecutionContext,
+ Class_CallContext,
Class_Object,
Class_ArrayObject,
Class_FunctionObject,
Class_StringObject,
Class_ScriptFunction,
+ Class_BuiltinFunction,
Class_ObjectProto,
Class_RegExp,
Class_RegExpObject,
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 65507e2251..6811438915 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -328,8 +328,7 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He
*obj->propertyData(Index_Constructor) = ctor;
*obj->propertyData(Index_Message) = engine->id_empty();
*obj->propertyData(Index_Name) = engine->newString(QString::fromLatin1(ErrorObject::className(t)));
- if (t == Heap::ErrorObject::Error)
- obj->defineDefaultProperty(engine->id_toString(), method_toString, 0);
+ obj->defineDefaultProperty(engine->id_toString(), method_toString, 0);
}
void ErrorPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 34e4b4a682..12531c9309 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -326,25 +326,25 @@ inline SyntaxErrorObject *ErrorObject::asSyntaxError()
template <typename T>
Heap::Object *ErrorObject::create(ExecutionEngine *e, const Value &message) {
- return e->memoryManager->allocObject<T>(
- e->internalClasses[message.isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage],
- T::defaultPrototype(e), message);
+ InternalClass *ic = e->internalClasses[message.isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage];
+ ic = ic->changePrototype(T::defaultPrototype(e)->d());
+ return e->memoryManager->allocObject<T>(ic, T::defaultPrototype(e), message);
}
template <typename T>
Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message) {
Scope scope(e);
ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue());
- return e->memoryManager->allocObject<T>(
- e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage],
- T::defaultPrototype(e), v);
+ InternalClass *ic = e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage];
+ ic = ic->changePrototype(T::defaultPrototype(e)->d());
+ return e->memoryManager->allocObject<T>(ic, T::defaultPrototype(e), v);
}
template <typename T>
Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message, const QString &filename, int line, int column) {
Scope scope(e);
ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue());
- return e->memoryManager->allocObject<T>(
- e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage],
- T::defaultPrototype(e), v, filename, line, column);
+ InternalClass *ic = e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage];
+ ic = ic->changePrototype(T::defaultPrototype(e)->d());
+ return e->memoryManager->allocObject<T>(ic, T::defaultPrototype(e), v, filename, line, column);
}
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 86362fa0cb..4be14c09ba 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -375,8 +375,8 @@ void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *call
Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that));
- InternalClass *ic = v4->internalClasses[EngineBase::Class_Object];
- ScopedObject proto(scope, f->protoForConstructor());
+ InternalClass *ic = f->classForConstructor();
+ ScopedObject proto(scope, ic->prototype);
ScopedObject obj(scope, v4->newObject(ic, proto));
callData->thisObject = obj.asReturnedValue();
@@ -444,12 +444,19 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function
}
}
-Heap::Object *ScriptFunction::protoForConstructor() const
+InternalClass *ScriptFunction::classForConstructor() const
{
const Object *o = d()->protoProperty();
+ InternalClass *ic = d()->cachedClassForConstructor;
+ if (ic && ic->prototype == o->d())
+ return ic;
+
+ ic = engine()->internalClasses[EngineBase::Class_Object];
if (o)
- return o->d();
- return engine()->objectPrototype()->d();
+ ic = ic->changePrototype(o->d());
+ d()->cachedClassForConstructor = ic;
+
+ return ic;
}
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index bfaa1ae056..354f6b2e3f 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -117,6 +117,8 @@ struct ScriptFunction : FunctionObject {
Index_Length
};
void init(QV4::ExecutionContext *scope, Function *function);
+
+ QV4::InternalClass *cachedClassForConstructor;
};
struct BoundFunction : FunctionObject {
@@ -199,6 +201,7 @@ struct Q_QML_EXPORT OldBuiltinFunction : FunctionObject {
struct Q_QML_EXPORT BuiltinFunction : FunctionObject {
V4_OBJECT2(BuiltinFunction, FunctionObject)
+ V4_INTERNALCLASS(BuiltinFunction)
static Heap::OldBuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *))
{
@@ -241,7 +244,7 @@ struct ScriptFunction : FunctionObject {
static void construct(const Managed *, Scope &scope, CallData *callData);
static void call(const Managed *that, Scope &scope, CallData *callData);
- Heap::Object *protoForConstructor() const;
+ InternalClass *classForConstructor() const;
};
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 9a4087485f..600198567a 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -106,6 +106,7 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
InternalClass::InternalClass(ExecutionEngine *engine)
: engine(engine)
, vtable(0)
+ , prototype(0)
, m_sealed(0)
, m_frozen(0)
, size(0)
@@ -118,6 +119,7 @@ InternalClass::InternalClass(const QV4::InternalClass &other)
: QQmlJS::Managed()
, engine(other.engine)
, vtable(other.vtable)
+ , prototype(other.prototype)
, propertyTable(other.propertyTable)
, nameMap(other.nameMap)
, propertyData(other.propertyData)
@@ -223,6 +225,7 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri
// create a new class and add it to the tree
InternalClass *newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable);
+ newClass = newClass->changePrototype(prototype);
for (uint i = 0; i < size; ++i) {
if (i == idx) {
newClass = newClass->addMember(nameMap.at(i), data);
@@ -236,6 +239,35 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri
return newClass;
}
+InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
+{
+ Q_ASSERT(prototype != proto);
+
+ Transition temp = { { nullptr }, 0, Transition::PrototypeChange };
+ temp.prototype = proto;
+
+ Transition &t = lookupOrInsertTransition(temp);
+ if (t.lookup)
+ return t.lookup;
+
+ // create a new class and add it to the tree
+ InternalClass *newClass;
+ if (!size && !prototype) {
+ newClass = engine->newClass(*this);
+ newClass->prototype = proto;
+ } else {
+ newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable);
+ newClass = newClass->changePrototype(proto);
+ for (uint i = 0; i < size; ++i) {
+ if (!propertyData.at(i).isEmpty())
+ newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
+ }
+ }
+
+ t.lookup = newClass;
+ return newClass;
+}
+
InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
{
Q_ASSERT(vtable != vt);
@@ -366,6 +398,7 @@ void InternalClass::removeMember(Object *object, Identifier *id)
} else {
// create a new class and add it to the tree
InternalClass *newClass = oldClass->engine->internalClasses[EngineBase::Class_Empty]->changeVTable(oldClass->vtable);
+ newClass = newClass->changePrototype(oldClass->prototype);
for (uint i = 0; i < oldClass->size; ++i) {
if (i == propIdx)
continue;
@@ -411,6 +444,7 @@ InternalClass *InternalClass::sealed()
return m_sealed;
m_sealed = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable);
+ m_sealed = m_sealed->changePrototype(prototype);
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
if (attrs.isEmpty())
@@ -440,6 +474,7 @@ InternalClass *InternalClass::frozen()
InternalClass *InternalClass::propertiesFrozen() const
{
InternalClass *frozen = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable);
+ frozen = frozen->changePrototype(prototype);
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
if (attrs.isEmpty())
@@ -480,9 +515,25 @@ void InternalClass::destroy()
}
}
+void InternalClass::mark(ExecutionEngine *e)
+{
+ if (m_sealed)
+ m_sealed->mark(e);
+ if (m_frozen)
+ m_frozen->mark(e);
+
+ for (size_t i = 0; i < transitions.size(); ++i) {
+ Q_ASSERT(transitions.at(i).lookup);
+ transitions.at(i).lookup->mark(e);
+ }
+ if (prototype)
+ prototype->mark(engine);
+}
+
void InternalClassPool::markObjects(ExecutionEngine *engine)
{
- Q_UNUSED(engine);
+ InternalClass *ic = engine->internalClasses[EngineBase::Class_Empty];
+ ic->mark(engine);
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 3c4e0838d9..031f66793b 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -223,6 +223,7 @@ struct InternalClassTransition
union {
Identifier *id;
const VTable *vtable;
+ Heap::Object *prototype;
};
InternalClass *lookup;
int flags;
@@ -230,6 +231,7 @@ struct InternalClassTransition
// range 0-0xff is reserved for attribute changes
NotExtensible = 0x100,
VTableChange = 0x200,
+ PrototypeChange = 0x201
};
bool operator==(const InternalClassTransition &other) const
@@ -242,6 +244,7 @@ struct InternalClassTransition
struct InternalClass : public QQmlJS::Managed {
ExecutionEngine *engine;
const VTable *vtable;
+ Heap::Object *prototype;
PropertyHash propertyTable; // id to valueIndex
SharedInternalClassData<Identifier *> nameMap;
@@ -257,30 +260,37 @@ struct InternalClass : public QQmlJS::Managed {
uint size;
bool extensible;
- InternalClass *nonExtensible();
- InternalClass *changeVTable(const VTable *vt) {
+ Q_REQUIRED_RESULT InternalClass *nonExtensible();
+ Q_REQUIRED_RESULT InternalClass *changeVTable(const VTable *vt) {
if (vtable == vt)
return this;
return changeVTableImpl(vt);
}
+ Q_REQUIRED_RESULT InternalClass *changePrototype(Heap::Object *proto) {
+ if (prototype == proto)
+ return this;
+ return changePrototypeImpl(proto);
+ }
static void addMember(Object *object, String *string, PropertyAttributes data, uint *index);
- InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0);
- InternalClass *addMember(Identifier *identifier, PropertyAttributes data, uint *index = 0);
- InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = 0);
+ Q_REQUIRED_RESULT InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0);
+ Q_REQUIRED_RESULT InternalClass *addMember(Identifier *identifier, PropertyAttributes data, uint *index = 0);
+ Q_REQUIRED_RESULT InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = 0);
static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = 0);
static void removeMember(Object *object, Identifier *id);
uint find(const String *string);
uint find(const Identifier *id);
- InternalClass *sealed();
- InternalClass *frozen();
- InternalClass *propertiesFrozen() const;
+ Q_REQUIRED_RESULT InternalClass *sealed();
+ Q_REQUIRED_RESULT InternalClass *frozen();
+ Q_REQUIRED_RESULT InternalClass *propertiesFrozen() const;
void destroy();
+ void mark(ExecutionEngine *e);
private:
Q_QML_EXPORT InternalClass *changeVTableImpl(const VTable *vt);
+ Q_QML_EXPORT InternalClass *changePrototypeImpl(Heap::Object *proto);
InternalClass *addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index);
friend struct ExecutionEngine;
InternalClass(ExecutionEngine *engine);
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index f8ac0cb650..25fa670115 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -63,7 +63,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu
return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs);
}
- obj = obj->prototype;
+ obj = obj->prototype();
++i;
}
level = Size;
@@ -76,7 +76,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu
return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs);
}
- obj = obj->prototype;
+ obj = obj->prototype();
}
return Primitive::emptyValue().asReturnedValue();
}
@@ -98,7 +98,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs);
}
- obj = obj->prototype;
+ obj = obj->prototype();
++i;
}
level = Size;
@@ -111,7 +111,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs);
}
- obj = obj->prototype;
+ obj = obj->prototype();
}
return Primitive::emptyValue().asReturnedValue();
}
@@ -402,8 +402,8 @@ ReturnedValue Lookup::getter1(Lookup *l, ExecutionEngine *engine, const Value &o
// 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[0] == o->internalClass && l->classList[1] == o->prototype()->internalClass)
+ return o->prototype()->propertyData(l->index)->asReturnedValue();
}
return getterTwoClasses(l, engine, object);
}
@@ -415,9 +415,9 @@ ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &o
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass) {
- Heap::Object *p = o->prototype;
+ Heap::Object *p = o->prototype();
if (l->classList[1] == p->internalClass) {
- p = p->prototype;
+ p = p->prototype();
if (l->classList[2] == p->internalClass)
return p->propertyData(l->index)->asReturnedValue();
}
@@ -480,8 +480,8 @@ ReturnedValue Lookup::getter0Inlinegetter1(Lookup *l, ExecutionEngine *engine, c
if (o) {
if (l->classList[0] == o->internalClass)
return o->inlinePropertyData(l->index)->asReturnedValue();
- if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass)
- return o->prototype->propertyData(l->index2)->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);
@@ -495,8 +495,8 @@ ReturnedValue Lookup::getter0MemberDatagetter1(Lookup *l, ExecutionEngine *engin
if (o) {
if (l->classList[0] == o->internalClass)
return o->memberData->data[l->index].asReturnedValue();
- if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass)
- return o->prototype->propertyData(l->index2)->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);
@@ -509,11 +509,11 @@ ReturnedValue Lookup::getter1getter1(Lookup *l, ExecutionEngine *engine, const V
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();
+ 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();
+ l->classList[3] == o->prototype()->internalClass)
+ return o->prototype()->propertyData(l->index2)->asReturnedValue();
return getterFallback(l, engine, object);
}
l->getter = getterFallback;
@@ -550,9 +550,9 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass &&
- l->classList[1] == o->prototype->internalClass) {
+ l->classList[1] == o->prototype()->internalClass) {
Scope scope(o->internalClass->engine);
- ScopedFunctionObject getter(scope, o->prototype->propertyData(l->index + Object::GetterOffset));
+ ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset));
if (!getter)
return Encode::undefined();
@@ -573,9 +573,9 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass) {
- o = o->prototype;
+ o = o->prototype();
if (l->classList[1] == o->internalClass) {
- o = o->prototype;
+ o = o->prototype();
if (l->classList[2] == o->internalClass) {
Scope scope(o->internalClass->engine);
ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset));
@@ -621,8 +621,8 @@ ReturnedValue Lookup::primitiveGetter1(Lookup *l, ExecutionEngine *engine, const
if (object.type() == l->type) {
Heap::Object *o = l->proto;
if (l->classList[0] == o->internalClass &&
- l->classList[1] == o->prototype->internalClass)
- return o->prototype->propertyData(l->index)->asReturnedValue();
+ l->classList[1] == o->prototype()->internalClass)
+ return o->prototype()->propertyData(l->index)->asReturnedValue();
}
l->getter = getterGeneric;
return getterGeneric(l, engine, object);
@@ -653,9 +653,9 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engin
if (object.type() == l->type) {
Heap::Object *o = l->proto;
if (l->classList[0] == o->internalClass &&
- l->classList[1] == o->prototype->internalClass) {
+ l->classList[1] == o->prototype()->internalClass) {
Scope scope(o->internalClass->engine);
- ScopedFunctionObject getter(scope, o->prototype->propertyData(l->index + Object::GetterOffset));
+ ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset));
if (!getter)
return Encode::undefined();
@@ -758,11 +758,11 @@ ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionEngine *engine)
{
Heap::Object *o = engine->globalObject->d();
if (l->classList[0] == o->internalClass) {
- o = o->prototype;
+ o = o->prototype();
if (l->classList[1] == o->internalClass) {
- o = o->prototype;
+ o = o->prototype();
if (l->classList[2] == o->internalClass) {
- return o->prototype->propertyData(l->index)->asReturnedValue();
+ return o->prototype()->propertyData(l->index)->asReturnedValue();
}
}
}
@@ -811,9 +811,9 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine)
{
Heap::Object *o = engine->globalObject->d();
if (l->classList[0] == o->internalClass) {
- o = o->prototype;
+ o = o->prototype();
if (l->classList[1] == o->internalClass) {
- o = o->prototype;
+ o = o->prototype();
if (l->classList[2] == o->internalClass) {
Scope scope(o->internalClass->engine);
ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset));
@@ -934,7 +934,7 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co
if (o && o->internalClass() == l->classList[0]) {
Heap::Object *p = o->prototype();
if (p && p->internalClass == l->classList[1]) {
- p = p->prototype;
+ p = p->prototype();
if (p && p->internalClass == l->classList[2]) {
o->setInternalClass(l->classList[3]);
*o->propertyData(l->index) = value;
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 838ae96c59..4abe508e10 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -88,13 +88,14 @@ void Object::setProperty(uint index, const Property *p)
bool Object::setPrototype(Object *proto)
{
- Heap::Object *pp = proto ? proto->d() : 0;
+ Heap::Object *p = proto ? proto->d() : 0;
+ Heap::Object *pp = p;
while (pp) {
if (pp == d())
return false;
- pp = pp->prototype;
+ pp = pp->prototype();
}
- d()->prototype = proto ? proto->d() : 0;
+ setInternalClass(internalClass()->changePrototype(p));
return true;
}
@@ -264,8 +265,6 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e)
o->memberData->mark(e);
if (o->arrayData)
o->arrayData->mark(e);
- if (o->prototype)
- o->prototype->mark(e);
uint nInline = o->vtable()->nInlineProperties;
Value *v = reinterpret_cast<Value *>(o) + o->vtable()->inlinePropertyOffset;
const Value *end = v + nInline;
@@ -345,7 +344,7 @@ Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs)
return o->propertyData(attrs->isAccessor() ? idx + SetterOffset : idx);
}
- o = o->prototype;
+ o = o->prototype();
}
*attrs = Attr_Invalid;
return 0;
@@ -368,7 +367,7 @@ Value *Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
return reinterpret_cast<Value *>(0x1);
}
}
- o = o->prototype;
+ o = o->prototype();
}
*attrs = Attr_Invalid;
return 0;
@@ -1204,7 +1203,7 @@ ReturnedValue Object::instanceOf(const Object *typeObject, const Value &var)
// 15.3.5.3, 4
while (v) {
// 15.3.5.3, 4, a
- v = v->prototype;
+ v = v->prototype();
// 15.3.5.3, 4, b
if (!v)
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<Object> prototype;
+ Heap::Object *prototype() const { return internalClass->prototype; }
Pointer<MemberData> memberData;
Pointer<ArrayData> 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<const ObjectVTable *>(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);
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index b8fb80546f..2e64364f9f 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -109,6 +109,7 @@ struct StringCtor: FunctionObject
struct StringPrototype: StringObject
{
+ V4_PROTOTYPE(objectPrototype)
void init(ExecutionEngine *engine, Object *ctor);
static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index bb28a7683c..80655aded6 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -373,6 +373,7 @@ void Heap::TypedArray::init(Type t)
Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t)
{
QV4::InternalClass *ic = e->internalClasses[EngineBase::Class_Empty]->changeVTable(staticVTable());
+ ic = ic->changePrototype(e->typedArrayPrototype[t].d());
return e->memoryManager->allocObject<TypedArray>(ic, e->typedArrayPrototype + t, t);
}
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 8f12fa7cbd..69d3eeb93c 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -247,11 +247,11 @@ public:
{
InternalClass *ic = ObjectType::defaultInternalClass(engine);
ic = ic->changeVTable(ObjectType::staticVTable());
+ ic = ic->changePrototype(ObjectType::defaultPrototype(engine)->d());
Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size);
- Object *prototype = ObjectType::defaultPrototype(engine);
o->internalClass = ic;
Q_ASSERT(o->internalClass && o->internalClass->vtable);
- o->prototype = prototype->d();
+ Q_ASSERT(o->internalClass->prototype == ObjectType::defaultPrototype(engine)->d());
return static_cast<typename ObjectType::Data *>(o);
}
@@ -279,7 +279,8 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype = prototype->d();
+ Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0));
+ Q_UNUSED(prototype);
t->d_unchecked()->init();
return t->d();
}
@@ -289,7 +290,8 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype = prototype->d();
+ Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0));
+ Q_UNUSED(prototype);
t->d_unchecked()->init(arg1);
return t->d();
}
@@ -299,7 +301,8 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype = prototype->d();
+ Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0));
+ Q_UNUSED(prototype);
t->d_unchecked()->init(arg1, arg2);
return t->d();
}
@@ -309,7 +312,8 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype = prototype->d();
+ Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0));
+ Q_UNUSED(prototype);
t->d_unchecked()->init(arg1, arg2, arg3);
return t->d();
}
@@ -319,7 +323,8 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype = prototype->d();
+ Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0));
+ Q_UNUSED(prototype);
t->d_unchecked()->init(arg1, arg2, arg3, arg4);
return t->d();
}
diff --git a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
index 63da28b7ba..49135ca920 100644
--- a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
+++ b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
@@ -250,7 +250,7 @@ void tst_QQuickWorkerScript::scriptError_onLoad()
QVERIFY(worker != 0);
QTRY_COMPARE(qquickworkerscript_lastWarning,
- testFileUrl("script_error_onLoad.js").toString() + QLatin1String(":3:10: Expected token `,'"));
+ testFileUrl("script_error_onLoad.js").toString() + QLatin1String(":3:10: SyntaxError: Expected token `,'"));
qInstallMessageHandler(previousMsgHandler);
qApp->processEvents();