aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qv4compileddata.cpp2
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h10
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp55
-rw-r--r--src/qml/jsruntime/jsruntime.pri1
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h2
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4context.cpp22
-rw-r--r--src/qml/jsruntime/qv4context_p.h2
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp128
-rw-r--r--src/qml/jsruntime/qv4engine_p.h33
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h126
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp7
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h18
-rw-r--r--src/qml/jsruntime/qv4function.cpp4
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp21
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h9
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp111
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h64
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp100
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h3
-rw-r--r--src/qml/jsruntime/qv4managed_p.h9
-rw-r--r--src/qml/jsruntime/qv4memberdata_p.h1
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4object.cpp54
-rw-r--r--src/qml/jsruntime/qv4object_p.h29
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp2
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp1
-rw-r--r--src/qml/jsruntime/qv4regexp_p.h1
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp2
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4string_p.h2
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h3
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp4
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h1
-rw-r--r--src/qml/jsruntime/qv4variantobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp72
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h10
-rw-r--r--src/qml/memory/qv4heap_p.h10
-rw-r--r--src/qml/memory/qv4mm.cpp33
-rw-r--r--src/qml/memory/qv4mm_p.h36
-rw-r--r--src/qml/memory/qv4mmdefs_p.h33
-rw-r--r--tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp2
-rw-r--r--tests/manual/v4/v8-bench.js3
46 files changed, 628 insertions, 408 deletions
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index d59a72cde2..ac4192bc12 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -177,7 +177,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
for (uint i = 0; i < data->jsClassTableSize; ++i) {
int memberCount = 0;
const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount);
- QV4::InternalClass *klass = engine->emptyClass;
+ QV4::InternalClass *klass = engine->internalClasses[QV4::ExecutionEngine::Class_Object];
for (int j = 0; j < memberCount; ++j, ++member)
klass = klass->addMember(runtimeStrings[member->nameOffset]->identifier, member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data);
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index fbd6ac8f99..dabda7bae8 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -170,11 +170,7 @@ QT_BEGIN_NAMESPACE
#define MOTH_INSTR_ALIGN_MASK (Q_ALIGNOF(QV4::Moth::Instr) - 1)
-#ifdef MOTH_THREADED_INTERPRETER
-# define MOTH_INSTR_HEADER union { quint32 instructionType; void *code; };
-#else
-# define MOTH_INSTR_HEADER quint32 instructionType;
-#endif
+#define MOTH_INSTR_HEADER quint32 instructionType;
#define MOTH_INSTR_ENUM(I, FMT) I,
#define MOTH_INSTR_SIZE(I, FMT) ((sizeof(QV4::Moth::Instr::instr_##FMT) + MOTH_INSTR_ALIGN_MASK) & ~MOTH_INSTR_ALIGN_MASK)
@@ -194,8 +190,8 @@ struct Param {
// Arg(outer): 4
// Local(outer): 5
// ...
- unsigned scope;
- unsigned index;
+ unsigned scope : 12;
+ unsigned index : 20;
bool isConstant() const { return !scope; }
bool isArgument() const { return scope >= 2 && !(scope &1); }
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index dc6fe317e5..fb805dce02 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -1436,29 +1436,6 @@ CompilationUnit::~CompilationUnit()
void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine)
{
-#ifdef MOTH_THREADED_INTERPRETER
- // link byte code against addresses of instructions
- for (int i = 0; i < codeRefs.count(); ++i) {
- QByteArray &codeRef = codeRefs[i];
- char *code = codeRef.data();
- int index = 0;
- while (index < codeRef.size()) {
- Instr *genericInstr = reinterpret_cast<Instr *>(code + index);
-
- switch (genericInstr->common.instructionType) {
-#define LINK_INSTRUCTION(InstructionType, Member) \
- case Instr::InstructionType: \
- genericInstr->common.code = VME::instructionJumpTable()[static_cast<int>(genericInstr->common.instructionType)]; \
- index += InstrMeta<(int)Instr::InstructionType>::Size; \
- break;
-
- FOR_EACH_MOTH_INSTR(LINK_INSTRUCTION)
-
- }
- }
- }
-#endif
-
runtimeFunctions.resize(data->functionTableSize);
runtimeFunctions.fill(0);
for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
@@ -1516,17 +1493,6 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
QByteArray padding;
-#if defined(MOTH_THREADED_INTERPRETER) && !defined(V4_BOOTSTRAP)
- // Map from instruction label back to instruction type. Only needed when persisting
- // already linked compilation units;
- QHash<void*, int> reverseInstructionMapping;
- if (engine) {
- void **instructions = VME::instructionJumpTable();
- for (int i = 0; i < Instr::LastInstruction; ++i)
- reverseInstructionMapping.insert(instructions[i], i);
- }
-#endif
-
for (int i = 0; i < codeRefs.size(); ++i) {
const CompiledData::Function *compiledFunction = unit->functionAt(i);
@@ -1545,27 +1511,6 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
QByteArray code = codeRefs.at(i);
-#if defined(MOTH_THREADED_INTERPRETER) && !defined(V4_BOOTSTRAP)
- if (!reverseInstructionMapping.isEmpty()) {
- char *codePtr = code.data(); // detaches
- int index = 0;
- while (index < code.size()) {
- Instr *genericInstr = reinterpret_cast<Instr *>(codePtr + index);
-
- genericInstr->common.instructionType = reverseInstructionMapping.value(genericInstr->common.code);
-
- switch (genericInstr->common.instructionType) {
- #define REVERSE_INSTRUCTION(InstructionType, Member) \
- case Instr::InstructionType: \
- index += InstrMeta<(int)Instr::InstructionType>::Size; \
- break;
-
- FOR_EACH_MOTH_INSTR(REVERSE_INSTRUCTION)
- }
- }
- }
-#endif
-
written = device->write(code.constData(), compiledFunction->codeSize);
if (written != qint64(compiledFunction->codeSize)) {
*errorString = device->errorString();
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 76ac8d4a91..9938f60aea 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -48,6 +48,7 @@ HEADERS += \
$$PWD/qv4global_p.h \
$$PWD/qv4alloca_p.h \
$$PWD/qv4engine_p.h \
+ $$PWD/qv4enginebase_p.h \
$$PWD/qv4context_p.h \
$$PWD/qv4math_p.h \
$$PWD/qv4persistent_p.h \
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index 24b948f01e..daf8c36814 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -236,6 +236,7 @@ struct Q_QML_EXPORT ArrayData : public Managed
struct Q_QML_EXPORT SimpleArrayData : public ArrayData
{
V4_ARRAYDATA(SimpleArrayData)
+ V4_INTERNALCLASS(SimpleArrayData)
uint mappedIndex(uint index) const { return d()->mappedIndex(index); }
Value data(uint index) const { return d()->data(index); }
@@ -262,6 +263,7 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData
struct Q_QML_EXPORT SparseArrayData : public ArrayData
{
V4_ARRAYDATA(SparseArrayData)
+ V4_INTERNALCLASS(SparseArrayData)
V4_NEEDS_DESTROY
ReturnedValue &freeList() { return d()->freeList; }
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index 9c8b1d67f1..ca2cf7d17a 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -76,6 +76,7 @@ struct BooleanCtor: FunctionObject
struct BooleanPrototype: BooleanObject
{
+ 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/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index c4a0539750..03595aa59d 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -209,6 +209,9 @@ unsigned int CallContext::variableCount() const
bool ExecutionContext::deleteProperty(String *name)
{
+ name->makeIdentifier(engine());
+ Identifier *id = name->identifier();
+
Scope scope(this);
bool hasWith = false;
ScopedContext ctx(scope, this);
@@ -237,7 +240,7 @@ bool ExecutionContext::deleteProperty(String *name)
case Heap::ExecutionContext::Type_SimpleCallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
if (c->v4Function && (c->v4Function->needsActivation() || hasWith)) {
- uint index = c->v4Function->internalClass->find(name);
+ uint index = c->v4Function->internalClass->find(id);
if (index < UINT_MAX)
// ### throw in strict mode?
return false;
@@ -361,6 +364,9 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio
void ExecutionContext::setProperty(String *name, const Value &value)
{
+ name->makeIdentifier(engine());
+ Identifier *id = name->identifier();
+
Scope scope(this);
ScopedContext ctx(scope, this);
ScopedObject activation(scope);
@@ -392,7 +398,7 @@ void ExecutionContext::setProperty(String *name, const Value &value)
case Heap::ExecutionContext::Type_SimpleCallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
if (c->v4Function) {
- uint index = c->v4Function->internalClass->find(name);
+ uint index = c->v4Function->internalClass->find(id);
if (index < UINT_MAX) {
if (index < c->v4Function->nFormals) {
c->callData->args[c->v4Function->nFormals - index - 1] = value;
@@ -414,7 +420,7 @@ void ExecutionContext::setProperty(String *name, const Value &value)
}
if (activation) {
- uint member = activation->internalClass()->find(name);
+ uint member = activation->internalClass()->find(id);
if (member < UINT_MAX) {
activation->putValue(member, value);
return;
@@ -473,7 +479,10 @@ ReturnedValue ExecutionContext::getProperty(String *name)
case Heap::ExecutionContext::Type_SimpleCallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) {
- uint index = c->v4Function->internalClass->find(name);
+ name->makeIdentifier(engine());
+ Identifier *id = name->identifier();
+
+ uint index = c->v4Function->internalClass->find(id);
if (index < UINT_MAX) {
if (index < c->v4Function->nFormals)
return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
@@ -551,7 +560,10 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
case Heap::ExecutionContext::Type_SimpleCallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) {
- uint index = c->v4Function->internalClass->find(name);
+ name->makeIdentifier(engine());
+ Identifier *id = name->identifier();
+
+ uint index = c->v4Function->internalClass->find(id);
if (index < UINT_MAX) {
if (index < c->v4Function->nFormals)
return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index c769dcd142..89ff6dc957 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -228,6 +228,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
V4_MANAGED(ExecutionContext, Managed)
Q_MANAGED_TYPE(ExecutionContext)
+ V4_INTERNALCLASS(ExecutionContext)
ExecutionEngine *engine() const { return d()->engine; }
@@ -271,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/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index a56d17f9b1..ecd57bcd8d 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -114,6 +114,8 @@ struct DateCtor: FunctionObject
struct DatePrototype: DateObject
{
+ V4_PROTOTYPE(objectPrototype)
+
void init(ExecutionEngine *engine, Object *ctor);
static double getThisDate(Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 0b61c6e7e6..daab7ad279 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -130,10 +130,8 @@ QQmlEngine *ExecutionEngine::qmlEngine() const
qint32 ExecutionEngine::maxCallDepth = -1;
ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
- : callDepth(0)
- , executableAllocator(new QV4::ExecutableAllocator)
+ : executableAllocator(new QV4::ExecutableAllocator)
, regExpAllocator(new QV4::ExecutableAllocator)
- , currentContext(0)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
, jsStack(new WTF::PageAllocation)
, globalCode(0)
@@ -214,7 +212,13 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
classPool = new InternalClassPool;
- emptyClass = new (classPool) InternalClass(this);
+ internalClasses[Class_Empty] = new (classPool) InternalClass(this);
+ 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"));
@@ -253,90 +257,113 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer"));
jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex"));
- jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(emptyClass);
+ InternalClass *ic = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable());
+ jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic);
+ internalClasses[Class_Object] = ic->changePrototype(objectPrototype()->d());
- arrayClass = emptyClass->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable);
- jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(arrayClass, 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 = emptyClass->addMember(id_length(), Attr_NotEnumerable);
- argumentsObjectClass = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable);
- strictArgumentsObjectClass = argsClass->addMember(id_callee(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
- strictArgumentsObjectClass = strictArgumentsObjectClass->addMember(id_caller(), Attr_Accessor|Attr_NotConfigurable|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);
*static_cast<Value *>(globalObject) = newObject();
Q_ASSERT(globalObject->d()->vtable());
initRootContext();
- stringClass = emptyClass->addMember(id_length(), Attr_ReadOnly);
- Q_ASSERT(stringClass->find(id_length()) == Heap::StringObject::LengthPropertyIndex);
- jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(stringClass, objectPrototype());
- jsObjects[NumberProto] = memoryManager->allocObject<NumberPrototype>(emptyClass, objectPrototype());
- jsObjects[BooleanProto] = memoryManager->allocObject<BooleanPrototype>(emptyClass, objectPrototype());
- jsObjects[DateProto] = memoryManager->allocObject<DatePrototype>(emptyClass, objectPrototype());
+ 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[NumberProto] = memoryManager->allocObject<NumberPrototype>();
+ jsObjects[BooleanProto] = memoryManager->allocObject<BooleanPrototype>();
+ jsObjects[DateProto] = memoryManager->allocObject<DatePrototype>();
uint index;
- InternalClass *functionProtoClass = emptyClass->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());
- functionClass = emptyClass->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);
- scriptFunctionClass = functionClass->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);
- scriptFunctionClass = scriptFunctionClass->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);
- protoClass = emptyClass->addMember(id_constructor(), Attr_NotEnumerable, &index);
+ internalClasses[EngineBase::Class_ObjectProto] = internalClasses[Class_Object]->addMember(id_constructor(), Attr_NotEnumerable, &index);
Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor);
Scope scope(this);
ScopedString str(scope);
- regExpObjectClass = emptyClass->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
+ internalClasses[Class_RegExp] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::RegExp::staticVTable());
+ ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype());
+ ic = ic->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
Q_ASSERT(index == RegExpObject::Index_LastIndex);
- regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index);
Q_ASSERT(index == RegExpObject::Index_Source);
- regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index);
Q_ASSERT(index == RegExpObject::Index_Global);
- regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index);
Q_ASSERT(index == RegExpObject::Index_IgnoreCase);
- regExpObjectClass = regExpObjectClass->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>(regExpObjectClass, objectPrototype());
- regExpExecArrayClass = arrayClass->addMember(id_index(), Attr_Data, &index);
+ ic = internalClasses[Class_ArrayObject]->addMember(id_index(), Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayIndex);
- regExpExecArrayClass = regExpExecArrayClass->addMember(id_input(), Attr_Data, &index);
+ internalClasses[EngineBase::Class_RegExpExecArray] = ic->addMember(id_input(), Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayInput);
- errorClass = emptyClass->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);
- errorClass = errorClass->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);
- errorClass = errorClass->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);
- errorClassWithMessage = errorClass->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);
- errorProtoClass = emptyClass->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);
- errorProtoClass = errorProtoClass->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);
- errorProtoClass = errorProtoClass->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>(errorProtoClass, objectPrototype());
- jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(errorProtoClass, errorPrototype());
- jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(errorProtoClass, errorPrototype());
- jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(errorProtoClass, errorPrototype());
- jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(errorProtoClass, errorPrototype());
- jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(errorProtoClass, errorPrototype());
- jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(errorProtoClass, errorPrototype());
+ jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto], objectPrototype());
+ 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>(emptyClass, objectPrototype());
+ jsObjects[VariantProto] = memoryManager->allocObject<VariantPrototype>();
Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d());
- jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(arrayClass, arrayPrototype()));
+ 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);
@@ -466,7 +493,7 @@ ExecutionEngine::~ExecutionEngine()
for (QV4::CompiledData::CompilationUnit *unit : qAsConst(remainingUnits))
unit->unlink();
- emptyClass->destroy();
+ internalClasses[Class_Empty]->destroy();
delete classPool;
delete bumperPointerAllocator;
delete regExpCache;
@@ -522,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 5182f24235..a569b8ddf9 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -55,6 +55,7 @@
#include "qv4managed_p.h"
#include "qv4context_p.h"
#include <private/qintrusivelist_p.h>
+#include "qv4enginebase_p.h"
#ifndef V4_BOOTSTRAP
# include <private/qv8engine_p.h>
@@ -96,21 +97,14 @@ private:
friend struct ExecutionContext;
friend struct Heap::ExecutionContext;
public:
- qint32 callDepth;
-
ExecutableAllocator *executableAllocator;
ExecutableAllocator *regExpAllocator;
QScopedPointer<EvalISelFactory> iselFactory;
- ExecutionContext *currentContext;
-
- Value *jsStackLimit;
-
WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
enum { JSStackLimit = 4*1024*1024 };
WTF::PageAllocation *jsStack;
- Value *jsStackBase;
void pushForGC(Heap::Base *m) {
*jsStackTop = m;
@@ -129,10 +123,6 @@ public:
return ptr;
}
- IdentifierTable *identifierTable;
-
- Object *globalObject;
-
Function *globalCode;
#ifdef V4_BOOTSTRAP
@@ -243,25 +233,6 @@ public:
Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); }
InternalClassPool *classPool;
- InternalClass *emptyClass;
-
- InternalClass *arrayClass;
- InternalClass *stringClass;
-
- InternalClass *functionClass;
- InternalClass *scriptFunctionClass;
- InternalClass *protoClass;
-
- InternalClass *regExpExecArrayClass;
- InternalClass *regExpObjectClass;
-
- InternalClass *argumentsObjectClass;
- InternalClass *strictArgumentsObjectClass;
-
- InternalClass *errorClass;
- InternalClass *errorClassWithMessage;
- InternalClass *errorProtoClass;
-
EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); }
FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); }
FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); }
@@ -395,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
new file mode 100644
index 0000000000..06c346b3c0
--- /dev/null
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4ENGINEBASE_P_H
+#define QV4ENGINEBASE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qv4global_p.h>
+#include <private/qv4runtimeapi_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+// Base class for the execution engine
+
+#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
+#pragma pack(push, 1)
+#endif
+struct EngineBase {
+ Heap::ExecutionContext *current = 0;
+
+ Value *jsStackTop = 0;
+ quint32 hasException = false;
+#if QT_POINTER_SIZE == 8
+ quint8 padding[4];
+#endif
+ MemoryManager *memoryManager = 0;
+ Runtime runtime;
+
+ qint32 callDepth = 0;
+ Value *jsStackLimit = 0;
+ Value *jsStackBase = 0;
+
+ ExecutionContext *currentContext = 0;
+ IdentifierTable *identifierTable = 0;
+ Object *globalObject = 0;
+
+ enum {
+ Class_Empty,
+ Class_String,
+ Class_MemberData,
+ 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,
+ Class_RegExpExecArray,
+ Class_ArgumentsObject,
+ Class_StrictArgumentsObject,
+ Class_ErrorObject,
+ Class_ErrorObjectWithMessage,
+ Class_ErrorProto,
+ NClasses
+ };
+ InternalClass *internalClasses[NClasses];
+};
+#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
+#pragma pack(pop)
+#endif
+
+Q_STATIC_ASSERT(std::is_standard_layout<EngineBase>::value);
+Q_STATIC_ASSERT(offsetof(EngineBase, current) == 0);
+Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, current) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE);
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index f290bc5136..6811438915 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -75,7 +75,7 @@ void Heap::ErrorObject::init()
Scope scope(internalClass->engine);
Scoped<QV4::ErrorObject> e(scope, this);
- if (internalClass == scope.engine->errorProtoClass)
+ if (internalClass == scope.engine->internalClasses[EngineBase::Class_ErrorProto])
return;
*propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction();
@@ -183,8 +183,6 @@ void ErrorObject::markObjects(Heap::Base *that, ExecutionEngine *e)
DEFINE_OBJECT_VTABLE(ErrorObject);
-DEFINE_OBJECT_VTABLE(SyntaxErrorObject);
-
void Heap::SyntaxErrorObject::init(const Value &msg)
{
Heap::ErrorObject::init(msg, SyntaxError);
@@ -330,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 9ba9f05234..12531c9309 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -157,7 +157,7 @@ struct ErrorObject: Object {
V4_OBJECT2(ErrorObject, Object)
Q_MANAGED_TYPE(ErrorObject)
- V4_INTERNALCLASS(errorClass)
+ V4_INTERNALCLASS(ErrorObject)
V4_PROTOTYPE(errorPrototype)
V4_NEEDS_DESTROY
@@ -203,8 +203,10 @@ struct ReferenceErrorObject: ErrorObject {
};
struct SyntaxErrorObject: ErrorObject {
- V4_OBJECT2(SyntaxErrorObject, ErrorObject)
+ typedef Heap::SyntaxErrorObject Data;
V4_PROTOTYPE(syntaxErrorPrototype)
+ const Data *d() const { return static_cast<const Data *>(ErrorObject::d()); }
+ Data *d() { return static_cast<Data *>(ErrorObject::d()); }
};
struct TypeErrorObject: ErrorObject {
@@ -324,19 +326,25 @@ inline SyntaxErrorObject *ErrorObject::asSyntaxError()
template <typename T>
Heap::Object *ErrorObject::create(ExecutionEngine *e, const Value &message) {
- return e->memoryManager->allocObject<T>(message.isUndefined() ? e->errorClass : e->errorClassWithMessage, 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>(v->isUndefined() ? e->errorClass : e->errorClassWithMessage, 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>(v->isUndefined() ? e->errorClass : e->errorClassWithMessage, 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/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 358c2d079c..994dede26d 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -59,7 +59,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
{
Q_UNUSED(engine);
- internalClass = engine->emptyClass;
+ internalClass = engine->internalClasses[EngineBase::Class_Empty];
const CompiledData::LEUInt32 *formalsIndices = compiledFunction->formalsTable();
// iterate backwards, so we get the right ordering for duplicate names
Scope scope(engine);
@@ -95,7 +95,7 @@ Function::~Function()
void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters)
{
- internalClass = engine->emptyClass;
+ internalClass = engine->internalClasses[EngineBase::Class_Empty];
// iterate backwards, so we get the right ordering for duplicate names
Scope scope(engine);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index b2d89220ea..4be14c09ba 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -122,8 +122,8 @@ void FunctionObject::init(String *n, bool createProto)
Q_ASSERT(internalClass() && internalClass()->find(s.engine->id_prototype()) == Heap::FunctionObject::Index_Prototype);
if (createProto) {
- ScopedObject proto(s, scope()->engine->newObject(s.engine->protoClass, s.engine->objectPrototype()));
- Q_ASSERT(s.engine->protoClass->find(s.engine->id_constructor()) == Heap::FunctionObject::Index_ProtoConstructor);
+ ScopedObject proto(s, scope()->engine->newObject(s.engine->internalClasses[EngineBase::Class_ObjectProto], s.engine->objectPrototype()));
+ Q_ASSERT(s.engine->internalClasses[EngineBase::Class_ObjectProto]->find(s.engine->id_constructor()) == Heap::FunctionObject::Index_ProtoConstructor);
*proto->propertyData(Heap::FunctionObject::Index_ProtoConstructor) = this->asReturnedValue();
*propertyData(Heap::FunctionObject::Index_Prototype) = proto.asReturnedValue();
} else {
@@ -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->emptyClass;
- 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 f4ac37219c..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 {
@@ -134,7 +136,7 @@ struct Q_QML_EXPORT FunctionObject: Object {
};
V4_OBJECT2(FunctionObject, Object)
Q_MANAGED_TYPE(FunctionObject)
- V4_INTERNALCLASS(functionClass)
+ V4_INTERNALCLASS(FunctionObject)
V4_PROTOTYPE(functionPrototype)
V4_NEEDS_DESTROY
@@ -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 *))
{
@@ -236,12 +239,12 @@ void Heap::IndexedBuiltinFunction::init(QV4::ExecutionContext *scope, uint index
struct ScriptFunction : FunctionObject {
V4_OBJECT2(ScriptFunction, FunctionObject)
- V4_INTERNALCLASS(scriptFunctionClass)
+ V4_INTERNALCLASS(ScriptFunction)
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 7e3fd7dc12..0bcd510541 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -105,6 +105,8 @@ 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)
@@ -116,6 +118,8 @@ InternalClass::InternalClass(ExecutionEngine *engine)
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)
@@ -129,7 +133,7 @@ InternalClass::InternalClass(const QV4::InternalClass &other)
static void insertHoleIntoPropertyData(Object *object, int idx)
{
- int inlineSize = object->d()->vt->nInlineProperties;
+ int inlineSize = object->d()->vtable()->nInlineProperties;
int icSize = object->internalClass()->size;
int from = qMax(idx, inlineSize);
int to = from + 1;
@@ -151,7 +155,7 @@ static void insertHoleIntoPropertyData(Object *object, int idx)
static void removeFromPropertyData(Object *object, int idx, bool accessor = false)
{
- int inlineSize = object->d()->vt->nInlineProperties;
+ int inlineSize = object->d()->vtable()->nInlineProperties;
int delta = (accessor ? 2 : 1);
int oldSize = object->internalClass()->size + delta;
int to = idx;
@@ -214,13 +218,14 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri
if (data == propertyData.at(idx))
return this;
- Transition temp = { identifier, 0, (int)data.flags() };
+ Transition temp = { { identifier }, nullptr, (int)data.flags() };
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup)
return t.lookup;
// create a new class and add it to the tree
- InternalClass *newClass = engine->emptyClass;
+ 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);
@@ -234,12 +239,72 @@ 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);
+
+ Transition temp = { { nullptr }, nullptr, Transition::VTableChange };
+ temp.vtable = vt;
+
+ Transition &t = lookupOrInsertTransition(temp);
+ if (t.lookup)
+ return t.lookup;
+
+ // create a new class and add it to the tree
+ InternalClass *newClass;
+ if (this == engine->internalClasses[EngineBase::Class_Empty]) {
+ newClass = engine->newClass(*this);
+ newClass->vtable = vt;
+ } else {
+ newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vt);
+ newClass = newClass->changePrototype(prototype);
+ for (uint i = 0; i < size; ++i) {
+ if (!propertyData.at(i).isEmpty())
+ newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
+ }
+ }
+
+ t.lookup = newClass;
+ Q_ASSERT(t.lookup);
+ Q_ASSERT(newClass->vtable);
+ return newClass;
+}
+
InternalClass *InternalClass::nonExtensible()
{
if (!extensible)
return this;
- Transition temp = { Q_NULLPTR, Q_NULLPTR, Transition::NotExtensible};
+ Transition temp = { { nullptr }, nullptr, Transition::NotExtensible};
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup)
return t.lookup;
@@ -287,7 +352,7 @@ InternalClass *InternalClass::addMember(Identifier *identifier, PropertyAttribut
InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index)
{
- Transition temp = { identifier, 0, (int)data.flags() };
+ Transition temp = { { identifier }, nullptr, (int)data.flags() };
Transition &t = lookupOrInsertTransition(temp);
if (index)
@@ -323,7 +388,7 @@ void InternalClass::removeMember(Object *object, Identifier *id)
uint propIdx = oldClass->propertyTable.lookup(id);
Q_ASSERT(propIdx < oldClass->size);
- Transition temp = { id, 0, -1 };
+ Transition temp = { { id }, nullptr, -1 };
Transition &t = object->internalClass()->lookupOrInsertTransition(temp);
bool accessor = oldClass->propertyData.at(propIdx).isAccessor();
@@ -332,7 +397,8 @@ void InternalClass::removeMember(Object *object, Identifier *id)
object->setInternalClass(t.lookup);
} else {
// create a new class and add it to the tree
- InternalClass *newClass = oldClass->engine->emptyClass;
+ 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;
@@ -351,8 +417,11 @@ void InternalClass::removeMember(Object *object, Identifier *id)
Q_ASSERT(t.lookup);
}
-uint InternalClass::find(const Identifier *id)
+uint QV4::InternalClass::find(const String *string)
{
+ engine->identifierTable->identifier(string);
+ const Identifier *id = string->d()->identifier;
+
uint index = propertyTable.lookup(id);
if (index < size)
return index;
@@ -365,7 +434,8 @@ InternalClass *InternalClass::sealed()
if (m_sealed)
return m_sealed;
- m_sealed = engine->emptyClass;
+ 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())
@@ -394,7 +464,8 @@ InternalClass *InternalClass::frozen()
InternalClass *InternalClass::propertiesFrozen() const
{
- InternalClass *frozen = engine->emptyClass;
+ 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())
@@ -437,7 +508,23 @@ void InternalClass::destroy()
void InternalClassPool::markObjects(ExecutionEngine *engine)
{
- Q_UNUSED(engine);
+ InternalClass *ic = engine->internalClasses[EngineBase::Class_Empty];
+ Q_ASSERT(!ic->prototype);
+
+ // only need to go two levels into the IC hierarchy, as prototype changes
+ // can only happen there
+ for (auto &t : ic->transitions) {
+ Q_ASSERT(t.lookup);
+ if (t.flags == InternalClassTransition::VTableChange) {
+ InternalClass *ic2 = t.lookup;
+ for (auto &t2 : ic2->transitions) {
+ if (t2.flags == InternalClassTransition::PrototypeChange)
+ t2.lookup->prototype->mark(engine);
+ }
+ } else if (t.flags == InternalClassTransition::PrototypeChange) {
+ t.lookup->prototype->mark(engine);
+ }
+ }
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 1d8ef4b0fb..9e8ab9e73e 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -54,15 +54,13 @@
#include <QHash>
#include <private/qqmljsmemorypool_p.h>
-#include <private/qv4engine_p.h>
-#include <private/qv4identifiertable_p.h>
+#include <private/qv4identifier_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
struct String;
-struct ExecutionEngine;
struct Object;
struct Identifier;
struct VTable;
@@ -222,12 +220,18 @@ private:
struct InternalClassTransition
{
- Identifier *id;
+ union {
+ Identifier *id;
+ const VTable *vtable;
+ Heap::Object *prototype;
+ };
InternalClass *lookup;
int flags;
enum {
// range 0-0xff is reserved for attribute changes
- NotExtensible = 0x100
+ NotExtensible = 0x100,
+ VTableChange = 0x200,
+ PrototypeChange = 0x201
};
bool operator==(const InternalClassTransition &other) const
@@ -239,6 +243,8 @@ struct InternalClassTransition
struct InternalClass : public QQmlJS::Managed {
ExecutionEngine *engine;
+ const VTable *vtable;
+ Heap::Object *prototype;
PropertyHash propertyTable; // id to valueIndex
SharedInternalClassData<Identifier *> nameMap;
@@ -254,41 +260,49 @@ struct InternalClass : public QQmlJS::Managed {
uint size;
bool extensible;
- InternalClass *nonExtensible();
+ 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);
+ uint find(const Identifier *id)
+ {
+ uint index = propertyTable.lookup(id);
+ if (index < size)
+ return index;
+
+ return UINT_MAX;
+ }
- 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();
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);
InternalClass(const InternalClass &other);
};
-inline uint InternalClass::find(const String *string)
-{
- engine->identifierTable->identifier(string);
- const Identifier *id = string->d()->identifier;
-
- uint index = propertyTable.lookup(id);
- if (index < size)
- return index;
-
- return UINT_MAX;
-}
-
struct InternalClassPool : public QQmlJS::MemoryPool
{
void markObjects(ExecutionEngine *engine);
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 0d467098fe..faaa5539ab 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();
}
@@ -287,7 +287,7 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va
l->proto = proto->d();
if (attrs.isData()) {
if (l->level == 0) {
- uint nInline = l->proto->vt->nInlineProperties;
+ uint nInline = l->proto->vtable()->nInlineProperties;
if (l->index < nInline)
l->getter = Lookup::primitiveGetter0Inline;
else {
@@ -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] == l->proto->internalClass)
+ return l->proto->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;
- if (l->classList[1] == p->internalClass) {
- p = p->prototype;
+ 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();
}
@@ -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] == l->proto->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;
- if (l->classList[1] == o->internalClass) {
- o = o->prototype;
+ 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));
@@ -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();
@@ -696,7 +696,7 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine)
if (v != Primitive::emptyValue().asReturnedValue()) {
if (attrs.isData()) {
if (l->level == 0) {
- uint nInline = o->d()->vt->nInlineProperties;
+ uint nInline = o->d()->vtable()->nInlineProperties;
if (l->index < nInline)
l->globalGetter = globalGetter0Inline;
else {
@@ -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));
@@ -877,7 +877,7 @@ void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, c
void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
- Object *o = object.as<Object>();
+ Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
*o->propertyData(l->index) = value;
return;
@@ -888,7 +888,7 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va
void Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
- Object *o = object.as<Object>();
+ Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
*o->d()->inlinePropertyData(l->index) = value;
return;
@@ -899,13 +899,12 @@ void Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, co
void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
- Object *o = object.as<Object>();
+ Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
- if (!o->prototype()) {
- o->setInternalClass(l->classList[3]);
- *o->propertyData(l->index) = value;
- return;
- }
+ Q_ASSERT(!o->prototype());
+ o->setInternalClass(l->classList[3]);
+ *o->propertyData(l->index) = value;
+ return;
}
l->setter = setterFallback;
@@ -914,10 +913,12 @@ void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, co
void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
- Object *o = object.as<Object>();
+ Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
Heap::Object *p = o->prototype();
- if (p && p->internalClass == l->classList[1]) {
+ Q_ASSERT(p);
+ if (p->internalClass == l->classList[1]) {
+ Q_ASSERT(!p->prototype());
o->setInternalClass(l->classList[3]);
*o->propertyData(l->index) = value;
return;
@@ -930,12 +931,15 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, co
void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
- Object *o = object.as<Object>();
+ Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
Heap::Object *p = o->prototype();
- if (p && p->internalClass == l->classList[1]) {
- p = p->prototype;
- if (p && p->internalClass == l->classList[2]) {
+ Q_ASSERT(p);
+ if (p->internalClass == l->classList[1]) {
+ p = p->prototype();
+ Q_ASSERT(p);
+ if (p->internalClass == l->classList[2]) {
+ Q_ASSERT(!p->prototype());
o->setInternalClass(l->classList[3]);
*o->propertyData(l->index) = value;
return;
@@ -949,7 +953,7 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co
void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
- Object *o = object.as<Object>();
+ Object *o = static_cast<Object *>(object.managed());
if (o) {
if (o->internalClass() == l->classList[0]) {
*o->propertyData(l->index) = value;
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 9e50235b73..151231991f 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -79,13 +79,14 @@ struct Lookup {
struct {
void *dummy0;
void *dummy1;
+ void *dummy2;
Heap::Object *proto;
- unsigned type;
};
};
union {
int level;
uint index2;
+ unsigned type;
};
uint index;
uint nameIndex;
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 7e674c6ec7..4c387a7fe7 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -52,6 +52,7 @@
#include "qv4global_p.h"
#include "qv4value_p.h"
+#include "qv4enginebase_p.h"
#include <private/qv4heap_p.h>
QT_BEGIN_NAMESPACE
@@ -130,7 +131,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
{ \
parentVTable, \
(sizeof(classname::Data) + sizeof(QV4::Value) - 1)/sizeof(QV4::Value), \
- (sizeof(classname::Data) + QV4::Chunk::SlotSize - 1)/QV4::Chunk::SlotSize*QV4::Chunk::SlotSize/sizeof(QV4::Value) \
+ (sizeof(classname::Data) + (std::is_same<classname, Object>::value ? 2*sizeof(QV4::Value) : 0) + QV4::Chunk::SlotSize - 1)/QV4::Chunk::SlotSize*QV4::Chunk::SlotSize/sizeof(QV4::Value) \
- (sizeof(classname::Data) + sizeof(QV4::Value) - 1)/sizeof(QV4::Value), \
classname::IsExecutionContext, \
classname::IsString, \
@@ -151,6 +152,10 @@ QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON \
const QV4::VTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, 0) \
QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF
+#define V4_INTERNALCLASS(c) \
+ static QV4::InternalClass *defaultInternalClass(QV4::EngineBase *e) \
+ { return e->internalClasses[QV4::EngineBase::Class_##c]; }
+
struct Q_QML_PRIVATE_EXPORT Managed : Value
{
V4_MANAGED_ITSELF(Base, Managed)
@@ -193,6 +198,8 @@ public:
};
Q_MANAGED_TYPE(Invalid)
+ InternalClass *internalClass() const { return d()->internalClass; }
+
bool isListType() const { return d()->vtable()->type == Type_QmlSequence; }
bool isArrayObject() const { return d()->vtable()->type == Type_ArrayObject; }
diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h
index 5c89dfe8ec..e239458849 100644
--- a/src/qml/jsruntime/qv4memberdata_p.h
+++ b/src/qml/jsruntime/qv4memberdata_p.h
@@ -73,6 +73,7 @@ V4_ASSERT_IS_TRIVIAL(MemberData)
struct MemberData : Managed
{
V4_MANAGED(MemberData, Managed)
+ V4_INTERNALCLASS(MemberData)
Value &operator[] (uint idx) { return d()->data[idx]; }
const Value *data() const { return d()->data; }
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index 364b866a16..85d306020c 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -85,6 +85,7 @@ struct NumberCtor: FunctionObject
struct NumberPrototype: NumberObject
{
+ V4_PROTOTYPE(objectPrototype)
void init(ExecutionEngine *engine, Object *ctor);
static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 3d8e8f3ddf..cac9d8ad7d 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -61,6 +61,7 @@ DEFINE_OBJECT_VTABLE(Object);
void Object::setInternalClass(InternalClass *ic)
{
d()->internalClass = ic;
+ Q_ASSERT(ic && ic->vtable);
uint nInline = d()->vtable()->nInlineProperties;
if (ic->size <= nInline)
return;
@@ -87,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;
}
@@ -263,10 +265,8 @@ 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->vt->inlinePropertyOffset;
+ Value *v = reinterpret_cast<Value *>(o) + o->vtable()->inlinePropertyOffset;
const Value *end = v + nInline;
while (v < end) {
v->mark(e);
@@ -294,7 +294,10 @@ void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p
if (idx != UINT_MAX)
return getOwnProperty(idx, attrs, p);
- uint member = internalClass()->find(name);
+ name->makeIdentifier(engine());
+ Identifier *id = name->identifier();
+
+ uint member = internalClass()->find(id);
if (member < UINT_MAX) {
*attrs = internalClass()->propertyData[member];
if (p) {
@@ -336,15 +339,18 @@ Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs)
{
Q_ASSERT(name->asArrayIndex() == UINT_MAX);
+ name->makeIdentifier(engine());
+ Identifier *id = name->identifier();
+
Heap::Object *o = d();
while (o) {
- uint idx = o->internalClass->find(name);
+ uint idx = o->internalClass->find(id);
if (idx < UINT_MAX) {
*attrs = o->internalClass->propertyData[idx];
return o->propertyData(attrs->isAccessor() ? idx + SetterOffset : idx);
}
- o = o->prototype;
+ o = o->prototype();
}
*attrs = Attr_Invalid;
return 0;
@@ -367,7 +373,7 @@ Value *Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
return reinterpret_cast<Value *>(0x1);
}
}
- o = o->prototype;
+ o = o->prototype();
}
*attrs = Attr_Invalid;
return 0;
@@ -411,7 +417,10 @@ bool Object::hasOwnProperty(String *name) const
if (idx != UINT_MAX)
return hasOwnProperty(idx);
- if (internalClass()->find(name) < UINT_MAX)
+ name->makeIdentifier(engine());
+ Identifier *id = name->identifier();
+
+ if (internalClass()->find(id) < UINT_MAX)
return true;
if (!query(name).isEmpty())
return true;
@@ -468,8 +477,11 @@ PropertyAttributes Object::query(const Managed *m, String *name)
if (idx != UINT_MAX)
return queryIndexed(m, idx);
+ name->makeIdentifier(m->internalClass()->engine);
+ Identifier *id = name->identifier();
+
const Object *o = static_cast<const Object *>(m);
- idx = o->internalClass()->find(name);
+ idx = o->internalClass()->find(id);
if (idx < UINT_MAX)
return o->internalClass()->propertyData[idx];
@@ -505,9 +517,11 @@ ReturnedValue Object::getLookup(const Managed *m, Lookup *l)
PropertyAttributes attrs;
ReturnedValue v = l->lookup(o, &attrs);
if (v != Primitive::emptyValue().asReturnedValue()) {
+ l->proto = l->classList[0]->prototype;
if (attrs.isData()) {
+ Q_ASSERT(l->classList[0] == o->internalClass());
if (l->level == 0) {
- uint nInline = o->d()->vt->nInlineProperties;
+ uint nInline = o->d()->vtable()->nInlineProperties;
if (l->index < nInline)
l->getter = Lookup::getter0Inline;
else {
@@ -549,7 +563,7 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value)
if (idx != UINT_MAX && o->internalClass()->propertyData[idx].isData() && o->internalClass()->propertyData[idx].isWritable()) {
l->classList[0] = o->internalClass();
l->index = idx;
- l->setter = idx < o->d()->vt->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0;
+ l->setter = idx < o->d()->vtable()->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0;
*o->propertyData(idx) = value;
return;
}
@@ -668,10 +682,11 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) const
Scope scope(engine());
name->makeIdentifier(scope.engine);
+ Identifier *id = name->identifier();
ScopedObject o(scope, this);
while (o) {
- uint idx = o->internalClass()->find(name);
+ uint idx = o->internalClass()->find(id);
if (idx < UINT_MAX) {
if (hasProperty)
*hasProperty = true;
@@ -734,8 +749,9 @@ void Object::internalPut(String *name, const Value &value)
return putIndexed(idx, value);
name->makeIdentifier(engine());
+ Identifier *id = name->identifier();
- uint member = internalClass()->find(name);
+ uint member = internalClass()->find(id);
Value *v = 0;
PropertyAttributes attrs;
if (member < UINT_MAX) {
@@ -888,7 +904,7 @@ bool Object::internalDeleteProperty(String *name)
name->makeIdentifier(engine());
- uint memberIdx = internalClass()->find(name);
+ uint memberIdx = internalClass()->find(name->identifier());
if (memberIdx != UINT_MAX) {
if (internalClass()->propertyData[memberIdx].isConfigurable()) {
InternalClass::removeMember(this, name->identifier());
@@ -959,7 +975,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const
}
// Clause 1
- memberIndex = internalClass()->find(name);
+ memberIndex = internalClass()->find(name->identifier());
if (memberIndex == UINT_MAX) {
// clause 3
@@ -1203,7 +1219,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 45392c0486..cf04a84175 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -72,31 +72,30 @@ struct Object : Base {
void destroy() { Base::destroy(); }
const Value *inlinePropertyData(uint index) const {
- Q_ASSERT(index < vt->nInlineProperties);
- return reinterpret_cast<const Value *>(this) + vt->inlinePropertyOffset + index;
+ Q_ASSERT(index < vtable()->nInlineProperties);
+ return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index;
}
Value *inlinePropertyData(uint index) {
- Q_ASSERT(index < vt->nInlineProperties);
- return reinterpret_cast<Value *>(this) + vt->inlinePropertyOffset + index;
+ Q_ASSERT(index < vtable()->nInlineProperties);
+ return reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
}
const Value *propertyData(uint index) const {
- uint nInline = vt->nInlineProperties;
+ uint nInline = vtable()->nInlineProperties;
if (index < nInline)
- return reinterpret_cast<const Value *>(this) + vt->inlinePropertyOffset + index;
+ return reinterpret_cast<const Value *>(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<Value *>(this) + vt->inlinePropertyOffset + index;
+ return reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
index -= nInline;
return memberData->data + index;
}
- InternalClass *internalClass;
- Pointer<Object> prototype;
+ Heap::Object *prototype() const { return internalClass->prototype; }
Pointer<MemberData> memberData;
Pointer<ArrayData> arrayData;
};
@@ -137,9 +136,6 @@ struct Object : Base {
} \
V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass);
-#define V4_INTERNALCLASS(c) \
- static QV4::InternalClass *defaultInternalClass(QV4::ExecutionEngine *e) \
- { return e->c; }
#define V4_PROTOTYPE(p) \
static QV4::Object *defaultPrototype(QV4::ExecutionEngine *e) \
{ return e->p(); }
@@ -198,7 +194,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 {
@@ -207,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); }
@@ -220,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);
@@ -472,7 +467,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);
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index 889f4ea288..ef1a1c11ed 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -331,6 +331,7 @@ Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, cons
qml->setReadOnly(true);
Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc<QmlContext>(parent, qml);
+ Q_ASSERT(c->vtable() == staticVTable());
return c;
}
@@ -340,6 +341,7 @@ Heap::QmlContext *QmlContext::create(ExecutionContext *parent, QQmlContextData *
Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, scopeObject));
Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc<QmlContext>(parent, qml);
+ Q_ASSERT(c->vtable() == staticVTable());
return c;
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 67b1356e65..f484d56040 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -997,7 +997,6 @@ void QObjectWrapper::destroyObject(bool lastCall)
}
}
- h->internalClass = 0;
h->~Data();
}
diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h
index d3e63375a5..04cdb468bf 100644
--- a/src/qml/jsruntime/qv4regexp_p.h
+++ b/src/qml/jsruntime/qv4regexp_p.h
@@ -100,6 +100,7 @@ struct RegExp : public Managed
V4_MANAGED(RegExp, Managed)
Q_MANAGED_TYPE(RegExp)
V4_NEEDS_DESTROY
+ V4_INTERNALCLASS(RegExp)
QString pattern() const { return *d()->pattern; }
JSC::Yarr::BytecodePattern *byteCode() { return d()->byteCode; }
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 0894d0c25b..1f758e36f6 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -379,7 +379,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
}
// fill in result data
- ScopedArrayObject array(scope, scope.engine->newArrayObject(scope.engine->regExpExecArrayClass, scope.engine->arrayPrototype()));
+ ScopedArrayObject array(scope, scope.engine->newArrayObject(scope.engine->internalClasses[EngineBase::Class_RegExpExecArray], scope.engine->arrayPrototype()));
int len = r->value()->captureCount();
array->arrayReserve(len);
ScopedValue v(scope);
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index c0c7dfa78a..54731cef14 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -96,7 +96,7 @@ struct RegExpCtor : FunctionObject {
struct RegExpObject: Object {
V4_OBJECT2(RegExpObject, Object)
Q_MANAGED_TYPE(RegExpObject)
- V4_INTERNALCLASS(regExpObjectClass)
+ V4_INTERNALCLASS(RegExpObject)
V4_PROTOTYPE(regExpPrototype)
// needs to be compatible with the flags in qv4jsir_p.h
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 4b440f5335..a79eab3778 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1408,7 +1408,7 @@ QV4::ReturnedValue Runtime::method_setupArgumentsObject(ExecutionEngine *engine)
{
Q_ASSERT(engine->current->type == Heap::ExecutionContext::Type_CallContext);
QV4::CallContext *c = static_cast<QV4::CallContext *>(engine->currentContext);
- QV4::InternalClass *ic = c->d()->strictMode ? engine->strictArgumentsObjectClass : engine->argumentsObjectClass;
+ QV4::InternalClass *ic = engine->internalClasses[c->d()->strictMode ? EngineBase::Class_StrictArgumentsObject : EngineBase::Class_ArgumentsObject];
return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->objectPrototype(), c)->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 6f96b9f760..0879f149fa 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -65,6 +65,7 @@ namespace QV4 {
struct SequencePrototype : public QV4::Object
{
+ V4_PROTOTYPE(arrayPrototype)
void init();
static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index 5b0fd292d6..ad30165ce5 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -53,6 +53,7 @@
#include <QtCore/qstring.h>
#include "qv4managed_p.h"
#include <QtCore/private/qnumeric_p.h>
+#include "qv4enginebase_p.h"
QT_BEGIN_NAMESPACE
@@ -138,6 +139,7 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
#ifndef V4_BOOTSTRAP
V4_MANAGED(String, Managed)
Q_MANAGED_TYPE(String)
+ V4_INTERNALCLASS(String)
V4_NEEDS_DESTROY
enum {
IsString = true
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 0ee7a6ece9..2e64364f9f 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -82,7 +82,7 @@ struct StringCtor : FunctionObject {
struct StringObject: Object {
V4_OBJECT2(StringObject, Object)
Q_MANAGED_TYPE(StringObject)
- V4_INTERNALCLASS(stringClass)
+ V4_INTERNALCLASS(StringObject)
V4_PROTOTYPE(stringPrototype)
Heap::String *getIndex(uint index) const {
@@ -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 cecd1e6958..80655aded6 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -372,7 +372,9 @@ void Heap::TypedArray::init(Type t)
Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t)
{
- return e->memoryManager->allocObject<TypedArray>(e->emptyClass, e->typedArrayPrototype + t, 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);
}
void TypedArray::markObjects(Heap::Base *that, ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index eefed2db4b..a6a74e4b9b 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -148,6 +148,7 @@ struct TypedArrayCtor: FunctionObject
struct TypedArrayPrototype : Object
{
V4_OBJECT2(TypedArrayPrototype, Object)
+ V4_PROTOTYPE(objectPrototype)
void init(ExecutionEngine *engine, TypedArrayCtor *ctor);
diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h
index ef51b6632d..dba14b13fb 100644
--- a/src/qml/jsruntime/qv4variantobject_p.h
+++ b/src/qml/jsruntime/qv4variantobject_p.h
@@ -105,6 +105,7 @@ struct VariantObject : Object
struct VariantPrototype : VariantObject
{
public:
+ V4_PROTOTYPE(objectPrototype)
void init();
static void method_preserve(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index a74016ab0c..d662b1738d 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -304,7 +304,7 @@ using namespace QV4::Moth;
# define MOTH_END_INSTR(I) } \
genericInstr = reinterpret_cast<const Instr *>(code); \
- goto *genericInstr->common.code; \
+ goto *jumpTable[genericInstr->common.instructionType]; \
#else
@@ -356,11 +356,7 @@ Param traceParam(const Param &param)
if (engine->hasException) \
goto catchException
-QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
-#ifdef MOTH_THREADED_INTERPRETER
- , void ***storeJumpTable
-#endif
- )
+QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
{
#ifdef DO_TRACE_INSTR
qDebug("Starting VME with context=%p and code=%p", context, code);
@@ -369,15 +365,11 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
qt_v4ResolvePendingBreakpointsHook();
#ifdef MOTH_THREADED_INTERPRETER
- if (storeJumpTable) {
#define MOTH_INSTR_ADDR(I, FMT) &&op_##I,
- static void *jumpTable[] = {
- FOR_EACH_MOTH_INSTR(MOTH_INSTR_ADDR)
- };
+ static void *jumpTable[] = {
+ FOR_EACH_MOTH_INSTR(MOTH_INSTR_ADDR)
+ };
#undef MOTH_INSTR_ADDR
- *storeJumpTable = jumpTable;
- return QV4::Primitive::undefinedValue().asReturnedValue();
- }
#endif
QV4::Value *stack = 0;
@@ -386,7 +378,6 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
const uchar *exceptionHandler = 0;
QV4::Scope scope(engine);
- QV4::ExecutionContext *context = engine->currentContext;
engine->current->lineNumber = -1;
#ifdef DO_TRACE_INSTR
@@ -396,7 +387,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
// setup lookup scopes
int scopeDepth = 0;
{
- QV4::Heap::ExecutionContext *scope = context->d();
+ QV4::Heap::ExecutionContext *scope = engine->current;
while (scope) {
++scopeDepth;
scope = scope->outer;
@@ -405,10 +396,10 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
Q_ALLOCA_VAR(QV4::Value*, scopes, sizeof(QV4::Value *)*(2 + 2*scopeDepth));
{
- scopes[0] = const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(context->d()->compilationUnit)->constants);
+ scopes[0] = const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->constants);
// stack gets setup in push instruction
scopes[1] = 0;
- QV4::Heap::ExecutionContext *scope = context->d();
+ QV4::Heap::ExecutionContext *scope = engine->current;
int i = 0;
while (scope) {
if (scope->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext) {
@@ -428,7 +419,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
for (;;) {
const Instr *genericInstr = reinterpret_cast<const Instr *>(code);
#ifdef MOTH_THREADED_INTERPRETER
- goto *genericInstr->common.code;
+ goto *jumpTable[genericInstr->common.instructionType];
#else
switch (genericInstr->common.instructionType) {
#endif
@@ -447,12 +438,12 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(LoadRuntimeString)
// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData());
- VALUE(instr.result) = context->d()->compilationUnit->runtimeStrings[instr.stringId];
+ VALUE(instr.result) = engine->current->compilationUnit->runtimeStrings[instr.stringId];
MOTH_END_INSTR(LoadRuntimeString)
MOTH_BEGIN_INSTR(LoadRegExp)
// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData());
- VALUE(instr.result) = static_cast<CompiledData::CompilationUnit*>(context->d()->compilationUnit)->runtimeRegularExpressions[instr.regExpId];
+ VALUE(instr.result) = static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->runtimeRegularExpressions[instr.regExpId];
MOTH_END_INSTR(LoadRegExp)
MOTH_BEGIN_INSTR(LoadClosure)
@@ -465,7 +456,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(GetGlobalLookup)
- QV4::Lookup *l = context->d()->lookups + instr.index;
+ QV4::Lookup *l = engine->current->lookups + instr.index;
STOREVALUE(instr.result, l->globalGetter(l, engine));
MOTH_END_INSTR(GetGlobalLookup)
@@ -480,7 +471,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(LoadElementLookup)
- QV4::Lookup *l = context->d()->lookups + instr.lookup;
+ QV4::Lookup *l = engine->current->lookups + instr.lookup;
STOREVALUE(instr.result, l->indexedGetter(l, VALUE(instr.base), VALUE(instr.index)));
MOTH_END_INSTR(LoadElementLookup)
@@ -490,7 +481,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(StoreElementLookup)
- QV4::Lookup *l = context->d()->lookups + instr.lookup;
+ QV4::Lookup *l = engine->current->lookups + instr.lookup;
l->indexedSetter(l, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElementLookup)
@@ -500,7 +491,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
- QV4::Lookup *l = context->d()->lookups + instr.index;
+ QV4::Lookup *l = engine->current->lookups + instr.index;
STOREVALUE(instr.result, l->getter(l, engine, VALUE(instr.base)));
MOTH_END_INSTR(GetLookup)
@@ -510,7 +501,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(StoreProperty)
MOTH_BEGIN_INSTR(SetLookup)
- QV4::Lookup *l = context->d()->lookups + instr.index;
+ QV4::Lookup *l = engine->current->lookups + instr.index;
l->setter(l, engine, VALUE(instr.base), VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(SetLookup)
@@ -581,7 +572,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallProperty)
- TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
+ TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData());
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = quint32(Value::ValueTypeInternal::Integer);
@@ -600,7 +591,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallScopeObjectProperty)
- TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
+ TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData());
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = quint32(Value::ValueTypeInternal::Integer);
@@ -610,7 +601,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(CallScopeObjectProperty)
MOTH_BEGIN_INSTR(CallContextObjectProperty)
- TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
+ TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData());
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = quint32(Value::ValueTypeInternal::Integer);
@@ -661,18 +652,15 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope)
Runtime::method_pushCatchScope(static_cast<QV4::NoThrowEngine*>(engine), instr.name);
- context = engine->currentContext;
MOTH_END_INSTR(CallBuiltinPushCatchScope)
MOTH_BEGIN_INSTR(CallBuiltinPushScope)
Runtime::method_pushWithScope(VALUE(instr.arg), static_cast<QV4::NoThrowEngine*>(engine));
- context = engine->currentContext;
CHECK_EXCEPTION;
MOTH_END_INSTR(CallBuiltinPushScope)
MOTH_BEGIN_INSTR(CallBuiltinPopScope)
Runtime::method_popScope(static_cast<QV4::NoThrowEngine*>(engine));
- context = engine->currentContext;
MOTH_END_INSTR(CallBuiltinPopScope)
MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject)
@@ -912,22 +900,22 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
#ifndef QT_NO_QML_DEBUGGER
MOTH_BEGIN_INSTR(Debug)
engine->current->lineNumber = instr.lineNumber;
- QV4::Debugging::Debugger *debugger = context->engine()->debugger();
+ QV4::Debugging::Debugger *debugger = engine->debugger();
if (debugger && debugger->pauseAtNextOpportunity())
debugger->maybeBreakAtInstruction();
if (qt_v4IsDebugging)
- qt_v4CheckForBreak(context);
+ qt_v4CheckForBreak(engine->currentContext);
MOTH_END_INSTR(Debug)
MOTH_BEGIN_INSTR(Line)
engine->current->lineNumber = instr.lineNumber;
if (qt_v4IsDebugging)
- qt_v4CheckForBreak(context);
+ qt_v4CheckForBreak(engine->currentContext);
MOTH_END_INSTR(Line)
#endif // QT_NO_QML_DEBUGGER
MOTH_BEGIN_INSTR(LoadThis)
- VALUE(instr.result) = context->thisObject();
+ VALUE(instr.result) = engine->currentContext->thisObject();
MOTH_END_INSTR(LoadThis)
MOTH_BEGIN_INSTR(LoadQmlContext)
@@ -953,25 +941,13 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
Q_ASSERT(false);
catchException:
- Q_ASSERT(context->engine()->hasException);
+ Q_ASSERT(engine->hasException);
if (!exceptionHandler)
return QV4::Encode::undefined();
code = exceptionHandler;
}
}
-#ifdef MOTH_THREADED_INTERPRETER
-void **VME::instructionJumpTable()
-{
- static void **jumpTable = 0;
- if (!jumpTable) {
- const uchar *code = 0;
- VME().run(0, code, &jumpTable);
- }
- return jumpTable;
-}
-#endif
-
QV4::ReturnedValue VME::exec(ExecutionEngine *engine, const uchar *code)
{
VME vme;
diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h
index f8893509d9..8d46207f2b 100644
--- a/src/qml/jsruntime/qv4vme_moth_p.h
+++ b/src/qml/jsruntime/qv4vme_moth_p.h
@@ -67,16 +67,8 @@ class VME
public:
static QV4::ReturnedValue exec(QV4::ExecutionEngine *, const uchar *);
-#ifdef MOTH_THREADED_INTERPRETER
- static void **instructionJumpTable();
-#endif
-
private:
- QV4::ReturnedValue run(QV4::ExecutionEngine *, const uchar *code
-#ifdef MOTH_THREADED_INTERPRETER
- , void ***storeJumpTable = 0
-#endif
- );
+ QV4::ReturnedValue run(QV4::ExecutionEngine *, const uchar *code);
};
} // namespace Moth
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index cd0a6d9a81..a4e96b4c84 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -53,6 +53,7 @@
#include <QtCore/QString>
#include <private/qv4global_p.h>
#include <private/qv4mmdefs_p.h>
+#include <private/qv4internalclass_p.h>
#include <QSharedPointer>
// To check if Heap::Base::init is called (meaning, all subclasses did their init and called their
@@ -69,6 +70,8 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+struct InternalClass;
+
struct VTable
{
const VTable * const parent;
@@ -93,13 +96,12 @@ namespace Heap {
struct Q_QML_EXPORT Base {
void *operator new(size_t) = delete;
- const VTable *vt;
+ InternalClass *internalClass;
inline ReturnedValue asReturnedValue() const;
inline void mark(QV4::ExecutionEngine *engine);
- void setVtable(const VTable *v) { vt = v; }
- const VTable *vtable() const { return vt; }
+ const VTable *vtable() const { return internalClass->vtable; }
inline bool isMarked() const {
const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
Chunk *c = h->chunk();
@@ -166,7 +168,7 @@ V4_ASSERT_IS_TRIVIAL(Base)
// for a size/offset translation when cross-compiling between 32- and
// 64-bit.
Q_STATIC_ASSERT(std::is_standard_layout<Base>::value);
-Q_STATIC_ASSERT(offsetof(Base, vt) == 0);
+Q_STATIC_ASSERT(offsetof(Base, internalClass) == 0);
Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE);
template <typename T>
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 0a6dfb9170..56f1254421 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -275,8 +275,9 @@ QString binary(quintptr) { return QString(); }
#define SDUMP if (1) ; else qDebug
#endif
-void Chunk::sweep()
+bool Chunk::sweep()
{
+ bool hasUsedSlots = false;
SDUMP() << "sweeping chunk" << this;
HeapItem *o = realBase();
bool lastSlotFree = false;
@@ -316,6 +317,7 @@ void Chunk::sweep()
}
}
objectBitmap[i] = blackBitmap[i];
+ hasUsedSlots |= (blackBitmap[i] != 0);
blackBitmap[i] = 0;
extendsBitmap[i] = e;
lastSlotFree = !((objectBitmap[i]|extendsBitmap[i]) >> (sizeof(quintptr)*8 - 1));
@@ -325,6 +327,7 @@ void Chunk::sweep()
o += Chunk::Bits;
}
// DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots.";
+ return hasUsedSlots;
}
void Chunk::freeAll()
@@ -579,12 +582,21 @@ void BlockAllocator::sweep()
// qDebug() << "BlockAlloc: sweep";
usedSlotsAfterLastSweep = 0;
- for (auto c : chunks) {
- c->sweep();
- c->sortIntoBins(freeBins, NumBins);
-// qDebug() << "used slots in chunk" << c << ":" << c->nUsedSlots();
- usedSlotsAfterLastSweep += c->nUsedSlots();
- }
+
+ auto isFree = [this] (Chunk *c) {
+ bool isUsed = c->sweep();
+
+ if (isUsed) {
+ c->sortIntoBins(freeBins, NumBins);
+ usedSlotsAfterLastSweep += c->nUsedSlots();
+ } else {
+ chunkAllocator->free(c);
+ }
+ return !isUsed;
+ };
+
+ auto newEnd = std::remove_if(chunks.begin(), chunks.end(), isFree);
+ chunks.erase(newEnd, chunks.end());
}
void BlockAllocator::freeAll()
@@ -775,7 +787,8 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(const QV4::VTable *vtable
m = *blockAllocator.allocate(memberSize, true);
memset(m, 0, memberSize);
o->memberData = static_cast<Heap::MemberData *>(m);
- o->memberData->setVtable(MemberData::staticVTable());
+ o->memberData->internalClass = engine->internalClasses[EngineBase::Class_MemberData];
+ Q_ASSERT(o->memberData->internalClass);
o->memberData->size = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
o->memberData->init();
// qDebug() << " got" << o->memberData << o->memberData->size;
@@ -950,7 +963,8 @@ void MemoryManager::runGC()
#ifndef QT_NO_DEBUG
qDebug() << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots.";
#endif
- qDebug() << "Allocated" << totalMem << "bytes in" << blockAllocator.chunks.size() << "chunks";
+ size_t oldChunks = blockAllocator.chunks.size();
+ qDebug() << "Allocated" << totalMem << "bytes in" << oldChunks << "chunks";
qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore);
dumpBins(&blockAllocator);
@@ -975,6 +989,7 @@ void MemoryManager::runGC()
qDebug() << "Used memory before GC:" << usedBefore;
qDebug() << "Used memory after GC:" << usedAfter;
qDebug() << "Freed up bytes:" << (usedBefore - usedAfter);
+ qDebug() << "Freed up chunks:" << (oldChunks - blockAllocator.chunks.size());
size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter;
if (lost)
qDebug() << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 9b4c2cd8df..69d3eeb93c 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -210,7 +210,8 @@ public:
{
Heap::CallContext *ctxt = stackAllocator.allocate();
memset(ctxt, 0, sizeof(Heap::CallContext));
- ctxt->setVtable(QV4::CallContext::staticVTable());
+ ctxt->internalClass = CallContext::defaultInternalClass(engine);
+ Q_ASSERT(ctxt->internalClass && ctxt->internalClass->vtable);
ctxt->init(v4);
return ctxt;
@@ -224,7 +225,10 @@ public:
V4_ASSERT_IS_TRIVIAL(typename ManagedType::Data)
size = align(size);
Heap::Base *o = allocData(size);
- o->setVtable(ManagedType::staticVTable());
+ InternalClass *ic = ManagedType::defaultInternalClass(engine);
+ ic = ic->changeVTable(ManagedType::staticVTable());
+ o->internalClass = ic;
+ Q_ASSERT(o->internalClass && o->internalClass->vtable);
return static_cast<typename ManagedType::Data *>(o);
}
@@ -232,8 +236,9 @@ public:
typename ObjectType::Data *allocateObject(InternalClass *ic)
{
Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size);
- o->setVtable(ObjectType::staticVTable());
o->internalClass = ic;
+ Q_ASSERT(o->internalClass && o->internalClass->vtable);
+ Q_ASSERT(ic->vtable == ObjectType::staticVTable());
return static_cast<typename ObjectType::Data *>(o);
}
@@ -241,11 +246,12 @@ public:
typename ObjectType::Data *allocateObject()
{
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);
- o->setVtable(ObjectType::staticVTable());
- Object *prototype = ObjectType::defaultPrototype(engine);
o->internalClass = ic;
- o->prototype = prototype->d();
+ Q_ASSERT(o->internalClass && o->internalClass->vtable);
+ Q_ASSERT(o->internalClass->prototype == ObjectType::defaultPrototype(engine)->d());
return static_cast<typename ObjectType::Data *>(o);
}
@@ -253,7 +259,8 @@ public:
typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1)
{
typename ManagedType::Data *o = reinterpret_cast<typename ManagedType::Data *>(allocString(unmanagedSize));
- o->setVtable(ManagedType::staticVTable());
+ o->internalClass = ManagedType::defaultInternalClass(engine);
+ Q_ASSERT(o->internalClass && o->internalClass->vtable);
o->init(this, arg1);
return o;
}
@@ -272,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();
}
@@ -282,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();
}
@@ -292,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();
}
@@ -302,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();
}
@@ -312,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/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
index db0ffe11a2..ef93971ab8 100644
--- a/src/qml/memory/qv4mmdefs_p.h
+++ b/src/qml/memory/qv4mmdefs_p.h
@@ -59,6 +59,10 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+struct MarkStack;
+
+typedef void(*ClassDestroyStatsCallback)(const char *);
+
/*
* Chunks are the basic structure containing GC managed objects.
*
@@ -175,7 +179,7 @@ struct Chunk {
return usedSlots;
}
- void sweep();
+ bool sweep();
void freeAll();
void sortIntoBins(HeapItem **bins, uint nBins);
@@ -256,33 +260,6 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize);
Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits);
Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits);
-// Base class for the execution engine
-
-#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
-#pragma pack(push, 1)
-#endif
-struct EngineBase {
- Heap::ExecutionContext *current = 0;
-
- Value *jsStackTop = 0;
- quint32 hasException = false;
-#if QT_POINTER_SIZE == 8
- quint8 padding[4];
-#endif
- MemoryManager *memoryManager = 0;
- Runtime runtime;
-};
-#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
-#pragma pack(pop)
-#endif
-
-Q_STATIC_ASSERT(std::is_standard_layout<EngineBase>::value);
-Q_STATIC_ASSERT(offsetof(EngineBase, current) == 0);
-Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, current) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE);
-
}
QT_END_NAMESPACE
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();
diff --git a/tests/manual/v4/v8-bench.js b/tests/manual/v4/v8-bench.js
index 41a04fa29a..bfce6231e4 100644
--- a/tests/manual/v4/v8-bench.js
+++ b/tests/manual/v4/v8-bench.js
@@ -202,6 +202,9 @@ BenchmarkSuite.prototype.NotifyError = function(error) {
// Runs a single benchmark for at least a second and computes the
// average time it takes to run a single iteration.
BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark, data) {
+ // run the garbage collector, to give more reproducible conditions to each test
+ gc()
+
function Measure(data) {
var elapsed = 0;
var start = new Date();