aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2017-05-29 10:30:39 +0200
committerLars Knoll <lars.knoll@qt.io>2017-06-06 15:59:38 +0200
commitc254cec22a2352a3fcab60244a6ab74f95d45ace (patch)
treed8456def48b09bd3914eb87c57ab53376f92c14f /src/qml
parentc158ca8be49a75026e83751dfd825c5bdd63189a (diff)
parent3f9367cb32533b691cb8c761213f21a524e3d1cb (diff)
Merge remote-tracking branch 'origin/5.9' into dev
Conflicts: .qmake.conf src/qml/jsruntime/qv4argumentsobject.cpp src/qml/jsruntime/qv4arraydata.cpp src/qml/jsruntime/qv4context.cpp src/qml/jsruntime/qv4context_p.h src/qml/jsruntime/qv4errorobject.cpp src/qml/jsruntime/qv4functionobject.cpp src/qml/jsruntime/qv4internalclass.cpp src/qml/jsruntime/qv4lookup.cpp src/qml/jsruntime/qv4managed.cpp src/qml/jsruntime/qv4managed_p.h src/qml/jsruntime/qv4object.cpp src/qml/jsruntime/qv4object_p.h src/qml/jsruntime/qv4qmlcontext.cpp src/qml/jsruntime/qv4runtime.cpp src/qml/jsruntime/qv4vme_moth.cpp src/qml/memory/qv4heap_p.h src/qml/memory/qv4mm.cpp src/qml/memory/qv4mm_p.h src/qml/memory/qv4mmdefs_p.h src/quick/scenegraph/util/qsgdistancefieldutil.cpp src/quick/scenegraph/util/qsgdistancefieldutil_p.h tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp Change-Id: I7ed925d4f5d308f872a58ddf51fdce0c8494ec9c
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/compiler.pri2
-rw-r--r--src/qml/compiler/qv4compileddata.cpp4
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h10
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp59
-rw-r--r--src/qml/compiler/qv4ssa.cpp6
-rw-r--r--src/qml/jit/qv4isel_masm.cpp12
-rw-r--r--src/qml/jsapi/qjsvalue.cpp4
-rw-r--r--src/qml/jsruntime/jsruntime.pri2
-rw-r--r--src/qml/jsruntime/qv4alloca_p.h53
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp21
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp2
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h2
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4context.cpp65
-rw-r--r--src/qml/jsruntime/qv4context_p.h15
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp136
-rw-r--r--src/qml/jsruntime/qv4engine_p.h33
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h128
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp7
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h18
-rw-r--r--src/qml/jsruntime/qv4executableallocator_p.h2
-rw-r--r--src/qml/jsruntime/qv4function.cpp8
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp66
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h20
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp132
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h65
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp272
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h22
-rw-r--r--src/qml/jsruntime/qv4managed.cpp2
-rw-r--r--src/qml/jsruntime/qv4managed_p.h11
-rw-r--r--src/qml/jsruntime/qv4memberdata_p.h15
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4object.cpp133
-rw-r--r--src/qml/jsruntime/qv4object_p.h74
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp12
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp5
-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.cpp110
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h2
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4string.cpp14
-rw-r--r--src/qml/jsruntime/qv4string_p.h17
-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.cpp74
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h10
-rw-r--r--src/qml/memory/qv4heap_p.h12
-rw-r--r--src/qml/memory/qv4mm.cpp45
-rw-r--r--src/qml/memory/qv4mm_p.h48
-rw-r--r--src/qml/memory/qv4mmdefs_p.h33
-rw-r--r--src/qml/memory/qv4writebarrier_p.h3
-rw-r--r--src/qml/parser/qqmljslexer.cpp5
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp5
-rw-r--r--src/qml/qml/qqmltypeloader.cpp41
-rw-r--r--src/qml/qml/qqmltypeloader_p.h12
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp4
-rw-r--r--src/qml/qtqmlglobal_p.h42
-rw-r--r--src/qml/types/qqmlconnections.cpp1
-rw-r--r--src/qml/types/qqmllistmodel.cpp1
-rw-r--r--src/qml/util/qqmladaptormodel.cpp44
68 files changed, 1202 insertions, 764 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 31ee917b39..60f548a2b0 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -41,7 +41,7 @@ SOURCES += \
unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-qtConfig(private_tests):unix: QMAKE_USE_PRIVATE += libdl
+qtConfig(private_tests):qtConfig(dlopen): QMAKE_USE_PRIVATE += libdl
}
qmldevtools_build|qtConfig(qml-interpreter) {
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 9832e1c49b..a0dd4c426c 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -176,7 +176,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);
@@ -733,7 +733,7 @@ static QByteArray ownLibraryChecksum()
if (checksumInitialized)
return libraryChecksum;
checksumInitialized = true;
-#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST) && !defined(Q_OS_INTEGRITY)
+#if !defined(QT_NO_DYNAMIC_CAST) && QT_CONFIG(dlopen)
Dl_info libInfo;
if (dladdr(reinterpret_cast<const void *>(&ownLibraryChecksum), &libInfo) != 0) {
QFile library(QFile::decodeName(libInfo.dli_fname));
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 aefb084971..fb805dce02 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -638,7 +638,7 @@ void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex,
void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
{
- if (useFastLookups) {
+ if (0 && useFastLookups) {
Instruction::LoadElementLookup load;
load.lookup = registerIndexedGetterLookup();
load.base = getParam(base);
@@ -657,7 +657,7 @@ void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr
void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase,
IR::Expr *targetIndex)
{
- if (useFastLookups) {
+ if (0 && useFastLookups) {
Instruction::StoreElementLookup store;
store.lookup = registerIndexedSetterLookup();
store.base = getParam(targetBase);
@@ -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/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 731c6ad38f..fc136b09ff 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -5417,7 +5417,11 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
showMeTheCode(function, "After loop detection");
// cfg2dot(function, loopDetection.allLoops());
- if (peelLoops) {
+ // ### disable loop peeling for now. It doesn't give any measurable performance
+ // improvements at this time, but significantly increases the size of the
+ // JIT generated code
+ Q_UNUSED(peelLoops);
+ if (0 && peelLoops) {
QVector<LoopDetection::LoopInfo *> innerLoops = loopDetection.innermostLoops();
LoopPeeling(df).run(innerLoops);
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index c2853a39d2..7784eb364e 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -621,7 +621,7 @@ void InstructionSelection<JITAssembler>::setQObjectProperty(IR::Expr *source, IR
template <typename JITAssembler>
void InstructionSelection<JITAssembler>::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
{
- if (useFastLookups) {
+ if (0 && useFastLookups) {
uint lookup = registerIndexedGetterLookup();
generateLookupCall(target, lookup, offsetof(QV4::Lookup, indexedGetter),
JITTargetPlatform::EngineRegister,
@@ -637,7 +637,7 @@ void InstructionSelection<JITAssembler>::getElement(IR::Expr *base, IR::Expr *in
template <typename JITAssembler>
void InstructionSelection<JITAssembler>::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex)
{
- if (useFastLookups) {
+ if (0 && useFastLookups) {
uint lookup = registerIndexedSetterLookup();
generateLookupCall(JITAssembler::Void, lookup, offsetof(QV4::Lookup, indexedSetter),
JITTargetPlatform::EngineRegister,
@@ -1639,14 +1639,20 @@ QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory<JITAssembler>::createU
return result;
}
+#endif // ENABLE(ASSEMBLER)
+
QT_BEGIN_NAMESPACE
namespace QV4 { namespace JIT {
+#if ENABLE(ASSEMBLER)
template class Q_QML_EXPORT InstructionSelection<>;
template class Q_QML_EXPORT ISelFactory<>;
+#endif
+
#if defined(V4_BOOTSTRAP)
Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &architecture)
{
+#if ENABLE(ASSEMBLER)
using ARMv7CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
using ARM64CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>;
@@ -1667,6 +1673,7 @@ Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &arch
#endif
if (!hostArch.isEmpty() && architecture == hostArch)
return new ISelFactory<>;
+#endif // ENABLE(ASSEMBLER)
return nullptr;
}
@@ -1675,4 +1682,3 @@ Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &arch
} }
QT_END_NAMESPACE
-#endif // ENABLE(ASSEMBLER)
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index bab2e633a7..3a3cf46ddb 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -1019,7 +1019,7 @@ QJSValue QJSValue::property(const QString& name) const
if (idx < UINT_MAX)
return property(idx);
- s->makeIdentifier(engine);
+ s->makeIdentifier();
QV4::ScopedValue result(scope, o->get(s));
if (engine->hasException)
result = engine->catchException();
@@ -1090,7 +1090,7 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value)
return;
}
- s->makeIdentifier(scope.engine);
+ s->makeIdentifier();
QV4::ScopedValue v(scope, QJSValuePrivate::convertedToValue(engine, value));
o->put(s, v);
if (engine->hasException)
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 955cf585e4..9938f60aea 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -46,7 +46,9 @@ SOURCES += \
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/qv4alloca_p.h b/src/qml/jsruntime/qv4alloca_p.h
index 2f486988c1..c21878fa42 100644
--- a/src/qml/jsruntime/qv4alloca_p.h
+++ b/src/qml/jsruntime/qv4alloca_p.h
@@ -51,15 +51,58 @@
// We mean it.
//
-#include <qglobal.h>
+#include <QtCore/private/qglobal_p.h>
-#if defined(Q_OS_WIN)
+#if QT_CONFIG(alloca_h)
+# include <alloca.h>
+#elif QT_CONFIG(alloca_malloc_h)
# include <malloc.h>
-# ifndef __GNUC__
+// This does not matter unless compiling in strict standard mode.
+# ifdef Q_OS_WIN
# define alloca _alloca
# endif
-#elif !defined(Q_OS_BSD4) || defined(Q_OS_DARWIN)
-# include <alloca.h>
+#else
+# include <stdlib.h>
+#endif
+
+// Define Q_ALLOCA_VAR macro to be used instead of #ifdeffing
+// the occurrences of alloca() in case it's not supported.
+// Q_ALLOCA_DECLARE and Q_ALLOCA_ASSIGN macros separate
+// memory allocation from the declaration and RAII.
+#define Q_ALLOCA_VAR(type, name, size) \
+ Q_ALLOCA_DECLARE(type, name); \
+ Q_ALLOCA_ASSIGN(type, name, size)
+
+#if QT_CONFIG(alloca)
+
+#define Q_ALLOCA_DECLARE(type, name) \
+ type *name = 0
+
+#define Q_ALLOCA_ASSIGN(type, name, size) \
+ name = static_cast<type*>(alloca(size))
+
+#else
+QT_BEGIN_NAMESPACE
+class Qt_AllocaWrapper
+{
+public:
+ Qt_AllocaWrapper() { m_data = 0; }
+ ~Qt_AllocaWrapper() { free(m_data); }
+ void *data() { return m_data; }
+ void allocate(int size) { m_data = malloc(size); }
+private:
+ void *m_data;
+};
+QT_END_NAMESPACE
+
+#define Q_ALLOCA_DECLARE(type, name) \
+ Qt_AllocaWrapper _qt_alloca_##name; \
+ type *name = nullptr
+
+#define Q_ALLOCA_ASSIGN(type, name, size) \
+ _qt_alloca_##name.allocate(size); \
+ name = static_cast<type*>(_qt_alloca_##name.data())
+
#endif
#endif
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 318db4f904..0905c2828a 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -48,7 +48,7 @@ DEFINE_OBJECT_VTABLE(ArgumentsObject);
void Heap::ArgumentsObject::init(QV4::CallContext *context)
{
- ExecutionEngine *v4 = context->d()->engine;
+ ExecutionEngine *v4 = internalClass->engine;
Object::init();
fullyCreated = false;
@@ -59,8 +59,8 @@ void Heap::ArgumentsObject::init(QV4::CallContext *context)
Scoped<QV4::ArgumentsObject> args(scope, this);
if (context->d()->strictMode) {
- Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee()));
- Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller()));
+ Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(v4->id_callee()));
+ Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(v4->id_caller()));
args->setProperty(CalleePropertyIndex + QV4::Object::GetterOffset, *v4->thrower());
args->setProperty(CalleePropertyIndex + QV4::Object::SetterOffset, *v4->thrower());
args->setProperty(CallerPropertyIndex + QV4::Object::GetterOffset, *v4->thrower());
@@ -70,10 +70,10 @@ void Heap::ArgumentsObject::init(QV4::CallContext *context)
args->arrayPut(0, context->args(), context->argc());
args->d()->fullyCreated = true;
} else {
- Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee()));
+ Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(v4->id_callee()));
args->setProperty(CalleePropertyIndex, context->d()->function);
}
- Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length()));
+ Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(v4->id_length()));
args->setProperty(LengthPropertyIndex, Primitive::fromInt32(context->d()->callData->argc));
}
@@ -82,18 +82,19 @@ void ArgumentsObject::fullyCreate()
if (fullyCreated())
return;
+ Scope scope(engine());
+
uint argCount = context()->callData->argc;
uint numAccessors = qMin(context()->formalParameterCount(), argCount);
ArrayData::realloc(this, Heap::ArrayData::Sparse, argCount, true);
- context()->engine->requireArgumentsAccessors(numAccessors);
+ scope.engine->requireArgumentsAccessors(numAccessors);
- Scope scope(engine());
Scoped<MemberData> md(scope, d()->mappedArguments);
if (numAccessors) {
- d()->mappedArguments.set(scope.engine, md->allocate(engine(), numAccessors));
+ d()->mappedArguments.set(scope.engine, md->allocate(scope.engine, numAccessors));
for (uint i = 0; i < numAccessors; ++i) {
d()->mappedArguments->values.set(scope.engine, i, context()->callData->args[i]);
- arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor);
+ arraySet(i, scope.engine->argumentsAccessors + i, Attr_Accessor);
}
}
arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors);
@@ -114,7 +115,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
bool isMapped = false;
if (arrayData() && index < numAccessors &&
arrayData()->attributes(index).isAccessor() &&
- arrayData()->get(index) == context()->engine->argumentsAccessors[index].getter()->asReturnedValue())
+ arrayData()->get(index) == scope.engine->argumentsAccessors[index].getter()->asReturnedValue())
isMapped = true;
if (isMapped) {
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 4a619858b4..df9884d84a 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -51,6 +51,8 @@ QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON
const QV4::VTable QV4::ArrayData::static_vtbl = {
0,
0,
+ 0,
+ 0,
QV4::ArrayData::IsExecutionContext,
QV4::ArrayData::IsString,
QV4::ArrayData::IsObject,
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index c2c81e886b..1d895c90c5 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -234,6 +234,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); }
@@ -257,6 +258,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.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index 601066110f..c8e9ebb2dd 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -85,7 +85,7 @@ void BooleanPrototype::method_toString(const BuiltinFunction *, Scope &scope, Ca
result = thisObject->value();
}
- scope.result = scope.engine->newString(QLatin1String(result ? "true" : "false"));
+ scope.result = result ? scope.engine->id_true() : scope.engine->id_false();
}
void BooleanPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
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 02d3af619e..ba72a9e43b 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -65,13 +65,14 @@ Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData
uint localsAndFormals = function->compiledFunction->nLocals + sizeof(CallData)/sizeof(Value) - 1 + qMax(static_cast<uint>(callData->argc), function->nFormals);
size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * (localsAndFormals);
- Heap::CallContext *c = d()->engine->memoryManager->allocManaged<CallContext>(requiredMemory);
- c->init(d()->engine, Heap::ExecutionContext::Type_CallContext);
+ ExecutionEngine *v4 = engine();
+ Heap::CallContext *c = v4->memoryManager->allocManaged<CallContext>(requiredMemory);
+ c->init(Heap::ExecutionContext::Type_CallContext);
c->v4Function = function;
c->strictMode = function->isStrict();
- c->outer.set(d()->engine, this->d());
+ c->outer.set(v4, this->d());
c->compilationUnit = function->compilationUnit;
c->lookups = function->compilationUnit->runtimeLookups;
@@ -99,14 +100,14 @@ Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData
Heap::WithContext *ExecutionContext::newWithContext(Heap::Object *with)
{
- return d()->engine->memoryManager->alloc<WithContext>(d(), with);
+ return engine()->memoryManager->alloc<WithContext>(d(), with);
}
Heap::CatchContext *ExecutionContext::newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue)
{
Scope scope(this);
ScopedValue e(scope, exceptionValue);
- return d()->engine->memoryManager->alloc<CatchContext>(d(), exceptionVarName, e);
+ return engine()->memoryManager->alloc<CatchContext>(d(), exceptionVarName, e);
}
void ExecutionContext::createMutableBinding(String *name, bool deletable)
@@ -156,35 +157,35 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
void Heap::GlobalContext::init(ExecutionEngine *eng)
{
- Heap::ExecutionContext::init(eng, Heap::ExecutionContext::Type_GlobalContext);
+ Heap::ExecutionContext::init(Heap::ExecutionContext::Type_GlobalContext);
global.set(eng, eng->globalObject->d());
}
void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionVarName,
const Value &exceptionValue)
{
- Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_CatchContext);
- outer.set(engine, outerContext);
+ Heap::ExecutionContext::init(Heap::ExecutionContext::Type_CatchContext);
+ outer.set(internalClass->engine, outerContext);
strictMode = outer->strictMode;
callData = outer->callData;
lookups = outer->lookups;
constantTable = outer->constantTable;
compilationUnit = outer->compilationUnit;
- this->exceptionVarName.set(engine, exceptionVarName);
- this->exceptionValue.set(engine, exceptionValue);
+ this->exceptionVarName.set(internalClass->engine, exceptionVarName);
+ this->exceptionValue.set(internalClass->engine, exceptionValue);
}
void Heap::WithContext::init(ExecutionContext *outerContext, Object *with)
{
- Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_WithContext);
- outer.set(engine, outerContext);
+ Heap::ExecutionContext::init(Heap::ExecutionContext::Type_WithContext);
+ outer.set(internalClass->engine, outerContext);
callData = outer->callData;
lookups = outer->lookups;
constantTable = outer->constantTable;
compilationUnit = outer->compilationUnit;
- withObject.set(engine, with);
+ withObject.set(internalClass->engine, with);
}
Identifier * const *SimpleCallContext::formals() const
@@ -211,6 +212,9 @@ unsigned int SimpleCallContext::variableCount() const
bool ExecutionContext::deleteProperty(String *name)
{
+ name->makeIdentifier();
+ Identifier *id = name->identifier();
+
Scope scope(this);
ScopedContext ctx(scope, this);
for (; ctx; ctx = ctx->d()->outer) {
@@ -235,7 +239,7 @@ bool ExecutionContext::deleteProperty(String *name)
}
case Heap::ExecutionContext::Type_CallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- uint index = c->v4Function->internalClass->find(name);
+ uint index = c->v4Function->internalClass->find(id);
if (index < UINT_MAX)
// ### throw in strict mode?
return false;
@@ -282,7 +286,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio
ExecutionContextSaver ctxSaver(scope);
- SimpleCallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(scope.engine);
+ SimpleCallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext();
ctx->strictMode = function->isStrict();
ctx->callData = callData;
@@ -306,6 +310,9 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio
void ExecutionContext::setProperty(String *name, const Value &value)
{
+ name->makeIdentifier();
+ Identifier *id = name->identifier();
+
Scope scope(this);
ScopedContext ctx(scope, this);
ScopedObject activation(scope);
@@ -337,7 +344,7 @@ void ExecutionContext::setProperty(String *name, const Value &value)
case Heap::ExecutionContext::Type_SimpleCallContext: {
Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(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;
@@ -360,7 +367,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;
@@ -368,21 +375,21 @@ void ExecutionContext::setProperty(String *name, const Value &value)
}
}
- if (d()->strictMode || name->equals(d()->engine->id_this())) {
+ if (d()->strictMode || name->equals(engine()->id_this())) {
ScopedValue n(scope, name->asReturnedValue());
engine()->throwReferenceError(n);
return;
}
- d()->engine->globalObject->put(name, value);
+ engine()->globalObject->put(name, value);
}
ReturnedValue ExecutionContext::getProperty(String *name)
{
Scope scope(this);
ScopedValue v(scope);
- name->makeIdentifier(scope.engine);
+ name->makeIdentifier();
- if (name->equals(d()->engine->id_this()))
+ if (name->equals(engine()->id_this()))
return thisObject().asReturnedValue();
ScopedContext ctx(scope, this);
@@ -413,7 +420,10 @@ ReturnedValue ExecutionContext::getProperty(String *name)
}
case Heap::ExecutionContext::Type_CallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- uint index = c->v4Function->internalClass->find(name);
+ name->makeIdentifier();
+ 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();
@@ -456,9 +466,9 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
Scope scope(this);
ScopedValue v(scope);
base->setM(0);
- name->makeIdentifier(scope.engine);
+ name->makeIdentifier();
- if (name->equals(d()->engine->id_this()))
+ if (name->equals(engine()->id_this()))
return thisObject().asReturnedValue();
ScopedContext ctx(scope, this);
@@ -490,7 +500,10 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
}
case Heap::ExecutionContext::Type_CallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- uint index = c->v4Function->internalClass->find(name);
+ name->makeIdentifier();
+ 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();
@@ -531,7 +544,7 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
Function *ExecutionContext::getFunction() const
{
- Scope scope(d()->engine);
+ Scope scope(engine());
ScopedContext it(scope, this->d());
for (; it; it = it->d()->outer) {
if (const SimpleCallContext *callCtx = it->asSimpleCallContext())
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 625d9ed424..a854c324d0 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -104,7 +104,6 @@ struct QmlContext;
#define ExecutionContextMembers(class, Member) \
Member(class, NoMark, CallData *, callData) \
- Member(class, NoMark, ExecutionEngine *, engine) \
Member(class, Pointer, ExecutionContext *, outer) \
Member(class, NoMark, Lookup *, lookups) \
Member(class, NoMark, const QV4::Value *, constantTable) \
@@ -124,11 +123,10 @@ DECLARE_HEAP_OBJECT(ExecutionContext, Base) {
Type_CallContext = 0x6
};
- void init(ExecutionEngine *engine, ContextType t)
+ void init(ContextType t)
{
Base::init();
- this->engine = engine;
type = t;
lineNumber = -1;
}
@@ -146,8 +144,7 @@ Q_STATIC_ASSERT(sizeof(ExecutionContext) == sizeof(Base) + sizeof(ExecutionConte
Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::value);
Q_STATIC_ASSERT(offsetof(ExecutionContextData, callData) == 0);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, engine) == offsetof(ExecutionContextData, callData) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == offsetof(ExecutionContextData, engine) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == offsetof(ExecutionContextData, callData) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(ExecutionContextData, lookups) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(ExecutionContextData, constantTable) == offsetof(ExecutionContextData, lookups) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(ExecutionContextData, compilationUnit) == offsetof(ExecutionContextData, constantTable) + QT_POINTER_SIZE);
@@ -160,9 +157,9 @@ Q_STATIC_ASSERT(offsetof(ExecutionContextData, lineNumber) == offsetof(Execution
DECLARE_HEAP_OBJECT(SimpleCallContext, ExecutionContext) {
DECLARE_MARK_TABLE(SimpleCallContext);
- void init(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext)
+ void init(ContextType t = Type_SimpleCallContext)
{
- ExecutionContext::init(engine, t);
+ ExecutionContext::init(t);
}
inline unsigned int formalParameterCount() const;
@@ -240,8 +237,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
V4_MANAGED(ExecutionContext, Managed)
Q_MANAGED_TYPE(ExecutionContext)
-
- ExecutionEngine *engine() const { return d()->engine; }
+ V4_INTERNALCLASS(ExecutionContext)
Heap::CallContext *newCallContext(Function *f, CallData *callData);
Heap::WithContext *newWithContext(Heap::Object *with);
@@ -281,6 +277,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
struct Q_QML_EXPORT SimpleCallContext : public ExecutionContext
{
V4_MANAGED(SimpleCallContext, ExecutionContext)
+ V4_INTERNALCLASS(SimpleCallContext)
// 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 b32b2c3f66..b0373884dd 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -114,6 +114,8 @@ struct DateCtor: FunctionObject
struct DatePrototype: Object
{
+ 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 6465b15d5a..019936767a 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -109,9 +109,9 @@ using namespace QV4;
static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
-static ReturnedValue throwTypeError(CallContext *ctx)
+void throwTypeError(const BuiltinFunction *, Scope &scope, CallData *)
{
- return ctx->engine()->throwTypeError();
+ scope.result = scope.engine->throwTypeError();
}
@@ -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)
, gcStack(new WTF::PageAllocation)
@@ -219,7 +217,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_SimpleCallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
jsStrings[String_Empty] = newIdentifier(QString());
jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined"));
@@ -258,90 +262,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);
@@ -490,7 +517,7 @@ ExecutionEngine::~ExecutionEngine()
for (QV4::CompiledData::CompilationUnit *unit : qAsConst(remainingUnits))
unit->unlink();
- emptyClass->destroy();
+ internalClasses[Class_Empty]->destroy();
delete classPool;
delete bumperPointerAllocator;
delete regExpCache;
@@ -548,6 +575,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>();
@@ -864,8 +896,8 @@ static inline char *v4StackTrace(const ExecutionContext *context)
QString result;
QTextStream str(&result);
str << "stack=[";
- if (context && context->d()->engine) {
- const QVector<StackFrame> stackTrace = context->d()->engine->stackTrace(20);
+ if (context && context->engine()) {
+ const QVector<StackFrame> stackTrace = context->engine()->stackTrace(20);
for (int i = 0; i < stackTrace.size(); ++i) {
if (i)
str << ',';
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index a2c774c295..16a043dda5 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,16 +97,10 @@ 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 {
@@ -113,7 +108,6 @@ public:
GCStackLimit = 2*1024*1024
};
WTF::PageAllocation *jsStack;
- Value *jsStackBase;
WTF::PageAllocation *gcStack;
@@ -125,10 +119,6 @@ public:
return ptr;
}
- IdentifierTable *identifierTable;
-
- Object *globalObject;
-
Function *globalCode;
#ifdef V4_BOOTSTRAP
@@ -239,25 +229,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); }
@@ -391,6 +362,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..88f9dfd85c
--- /dev/null
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** 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;
+ quint8 hasException = false;
+ quint8 writeBarrierActive = false;
+ quint16 unused = 0;
+#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_SimpleCallContext,
+ 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 58742a0b84..b3bd28e18b 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;
setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
@@ -175,8 +175,6 @@ void ErrorObject::method_get_stack(const BuiltinFunction *, Scope &scope, CallDa
DEFINE_OBJECT_VTABLE(ErrorObject);
-DEFINE_OBJECT_VTABLE(SyntaxErrorObject);
-
void Heap::SyntaxErrorObject::init(const Value &msg)
{
Heap::ErrorObject::init(msg, SyntaxError);
@@ -322,8 +320,7 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He
obj->setProperty(Index_Constructor, ctor->d());
obj->setProperty(Index_Message, engine->id_empty()->d());
obj->setProperty(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 5afd9efcba..d556617b48 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -160,7 +160,7 @@ struct ErrorObject: Object {
V4_OBJECT2(ErrorObject, Object)
Q_MANAGED_TYPE(ErrorObject)
- V4_INTERNALCLASS(errorClass)
+ V4_INTERNALCLASS(ErrorObject)
V4_PROTOTYPE(errorPrototype)
V4_NEEDS_DESTROY
@@ -205,8 +205,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 {
@@ -326,19 +328,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/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h
index f13f70e01a..353a6eacff 100644
--- a/src/qml/jsruntime/qv4executableallocator_p.h
+++ b/src/qml/jsruntime/qv4executableallocator_p.h
@@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-class Q_AUTOTEST_EXPORT ExecutableAllocator
+class Q_QML_AUTOTEST_EXPORT ExecutableAllocator
{
public:
struct ChunkOfPages;
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index ed9e3699f2..4c8117527c 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);
@@ -74,7 +74,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
}
// duplicate arguments, need some trick to store them
MemoryManager *mm = engine->memoryManager;
- arg = mm->alloc<String>(mm, arg->d(), engine->newString(QString(0xfffe)));
+ arg = mm->alloc<String>(arg->d(), engine->newString(QString(0xfffe)));
}
}
nFormals = compiledFunction->nFormals;
@@ -92,7 +92,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);
@@ -106,7 +106,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
break;
}
// duplicate arguments, need some trick to store them
- arg = engine->memoryManager->alloc<String>(engine->memoryManager, arg->d(), engine->newString(QString(0xfffe)));
+ arg = engine->memoryManager->alloc<String>(arg->d(), engine->newString(QString(0xfffe)));
}
}
nFormals = parameters.size();
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 5c8f03dc72..45fdde98f7 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -124,8 +124,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, s.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->setProperty(Heap::FunctionObject::Index_ProtoConstructor, d());
setProperty(Heap::FunctionObject::Index_Prototype, proto);
} else {
@@ -138,7 +138,7 @@ void FunctionObject::init(String *n, bool createProto)
ReturnedValue FunctionObject::name() const
{
- return get(scope()->engine->id_name());
+ return get(scope()->internalClass->engine->id_name());
}
void FunctionObject::construct(const Managed *that, Scope &scope, CallData *)
@@ -153,7 +153,7 @@ void FunctionObject::call(const Managed *, Scope &scope, CallData *)
Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function)
{
- return scope->d()->engine->memoryManager->allocObject<ScriptFunction>(scope, function);
+ return scope->engine()->memoryManager->allocObject<ScriptFunction>(scope, function);
}
bool FunctionObject::isBinding() const
@@ -369,8 +369,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();
@@ -433,54 +433,24 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function
ScopedProperty pd(s);
pd->value = s.engine->thrower();
pd->set = s.engine->thrower();
- f->insertMember(scope->d()->engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
- f->insertMember(scope->d()->engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ f->insertMember(s.engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
}
}
-Heap::Object *ScriptFunction::protoForConstructor() const
+InternalClass *ScriptFunction::classForConstructor() const
{
const Object *o = d()->protoProperty();
- if (o)
- return o->d();
- return engine()->objectPrototype()->d();
-}
-
-
+ InternalClass *ic = d()->cachedClassForConstructor;
+ if (ic && ic->prototype == o->d())
+ return ic;
-DEFINE_OBJECT_VTABLE(OldBuiltinFunction);
-
-void Heap::OldBuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *))
-{
- Heap::FunctionObject::init(scope, name);
- this->code = code;
-}
-
-void OldBuiltinFunction::construct(const Managed *f, Scope &scope, CallData *)
-{
- scope.result = static_cast<const OldBuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
-}
-
-void OldBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
-{
- const OldBuiltinFunction *f = static_cast<const OldBuiltinFunction *>(that);
- ExecutionEngine *v4 = scope.engine;
- if (v4->hasException) {
- scope.result = Encode::undefined();
- return;
- }
- CHECK_STACK_LIMITS(v4, scope);
-
- ExecutionContextSaver ctxSaver(scope);
-
- SimpleCallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4);
- ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
- ctx->callData = callData;
- v4->pushContext(ctx);
- Q_ASSERT(v4->current == ctx);
+ ic = engine()->internalClasses[EngineBase::Class_Object];
+ if (o)
+ ic = ic->changePrototype(o->d());
+ d()->cachedClassForConstructor = ic;
- scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext));
- v4->memoryManager->freeSimpleCallContext();
+ return ic;
}
DEFINE_OBJECT_VTABLE(BuiltinFunction);
@@ -520,7 +490,7 @@ void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *c
ExecutionContextSaver ctxSaver(scope);
- SimpleCallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4);
+ SimpleCallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext();
ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
ctx->callData = callData;
v4->pushContext(ctx);
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index d8929026ca..6ce5734b6d 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -118,6 +118,8 @@ struct ScriptFunction : FunctionObject {
Index_Length
};
void init(QV4::ExecutionContext *scope, Function *function);
+
+ QV4::InternalClass *cachedClassForConstructor;
};
#define BoundFunctionMembers(class, Member) \
@@ -139,7 +141,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
@@ -192,20 +194,10 @@ struct FunctionPrototype: FunctionObject
static void method_bind(const BuiltinFunction *, Scope &scope, CallData *callData);
};
-struct Q_QML_EXPORT OldBuiltinFunction : FunctionObject {
- V4_OBJECT2(OldBuiltinFunction, FunctionObject)
-
- static void construct(const Managed *, Scope &scope, CallData *);
- static void call(const Managed *that, Scope &scope, CallData *callData);
-};
-
struct Q_QML_EXPORT BuiltinFunction : FunctionObject {
V4_OBJECT2(BuiltinFunction, FunctionObject)
+ V4_INTERNALCLASS(BuiltinFunction)
- static Heap::OldBuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *))
- {
- return scope->engine()->memoryManager->allocObject<OldBuiltinFunction>(scope, name, code);
- }
static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *))
{
return scope->engine()->memoryManager->allocObject<BuiltinFunction>(scope, name, code);
@@ -238,12 +230,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/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index f0630660d4..0916e8e110 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -332,8 +332,8 @@ DEFINE_OBJECT_VTABLE(EvalFunction);
void Heap::EvalFunction::init(QV4::ExecutionContext *scope)
{
- Heap::FunctionObject::init(scope, scope->d()->engine->id_eval());
Scope s(scope);
+ Heap::FunctionObject::init(scope, s.engine->id_eval());
ScopedFunctionObject f(s, this);
f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(1));
}
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 3d9a672f2f..603da1df7b 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -43,6 +43,7 @@
#include <qv4identifier_p.h>
#include "qv4object_p.h"
#include "qv4identifiertable_p.h"
+#include "qv4value_p.h"
QT_BEGIN_NAMESPACE
@@ -104,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)
@@ -115,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)
@@ -126,6 +131,24 @@ InternalClass::InternalClass(const QV4::InternalClass &other)
Q_ASSERT(extensible);
}
+static void insertHoleIntoPropertyData(Object *object, int idx)
+{
+ Heap::Object *o = object->d();
+ ExecutionEngine *v4 = o->internalClass->engine;
+ int size = o->internalClass->size;
+ for (int i = size - 1; i > idx; --i)
+ o->setProperty(v4, i, *o->propertyData(i - 1));
+}
+
+static void removeFromPropertyData(Object *object, int idx, bool accessor = false)
+{
+ Heap::Object *o = object->d();
+ ExecutionEngine *v4 = o->internalClass->engine;
+ int size = o->internalClass->size;
+ for (int i = idx; i < size; ++i)
+ o->setProperty(v4, i, *o->propertyData(i + (accessor ? 2 : 1)));
+}
+
void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index)
{
uint idx;
@@ -137,10 +160,10 @@ void InternalClass::changeMember(Object *object, String *string, PropertyAttribu
object->setInternalClass(newClass);
if (newClass->size > oldClass->size) {
Q_ASSERT(newClass->size == oldClass->size + 1);
- object->d()->memberData->values.insertData(newClass->engine, idx + 1, Primitive::emptyValue());
+ insertHoleIntoPropertyData(object, idx);
} else if (newClass->size < oldClass->size) {
Q_ASSERT(newClass->size == oldClass->size - 1);
- object->d()->memberData->values.removeData(newClass->engine, idx + 1);
+ removeFromPropertyData(object, idx + 1);
}
}
@@ -167,13 +190,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);
@@ -187,12 +211,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;
@@ -240,7 +324,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)
@@ -276,7 +360,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();
@@ -285,7 +369,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;
@@ -298,14 +383,17 @@ void InternalClass::removeMember(Object *object, Identifier *id)
Q_ASSERT(object->internalClass()->size == oldClass->size - (accessor ? 2 : 1));
// remove the entry in the property data
- object->d()->memberData->values.removeData(oldClass->engine, propIdx, accessor ? 2 : 1);
+ removeFromPropertyData(object, propIdx, accessor);
t.lookup = object->internalClass();
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;
@@ -318,7 +406,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())
@@ -347,7 +436,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())
@@ -390,7 +480,23 @@ void InternalClass::destroy()
void InternalClassPool::markObjects(MarkStack *markStack)
{
- Q_UNUSED(markStack);
+ InternalClass *ic = markStack->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(markStack);
+ }
+ } else if (t.flags == InternalClassTransition::PrototypeChange) {
+ t.lookup->prototype->mark(markStack);
+ }
+ }
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index a29ce5b5ff..df17074e72 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -54,18 +54,17 @@
#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;
+struct MarkStack;
struct PropertyHashData;
struct PropertyHash
@@ -222,12 +221,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 +244,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 +261,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(MarkStack *markStack);
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 11d7767e05..d943ae1340 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();
}
@@ -284,11 +284,17 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va
ReturnedValue v = l->lookup(object, proto, &attrs);
if (v != Primitive::emptyValue().asReturnedValue()) {
l->type = object.type();
- l->proto = proto;
+ l->proto = proto->d();
if (attrs.isData()) {
- if (l->level == 0)
- l->getter = Lookup::primitiveGetter0;
- else if (l->level == 1)
+ if (l->level == 0) {
+ uint nInline = l->proto->vtable()->nInlineProperties;
+ if (l->index < nInline)
+ l->getter = Lookup::primitiveGetter0Inline;
+ else {
+ l->index -= nInline;
+ l->getter = Lookup::primitiveGetter0MemberData;
+ }
+ } else if (l->level == 1)
l->getter = Lookup::primitiveGetter1;
return v;
} else {
@@ -307,15 +313,18 @@ ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const
{
Lookup l1 = *l;
- if (l1.getter == Lookup::getter0 || l1.getter == Lookup::getter1) {
+ if (l1.getter == Lookup::getter0MemberData || l1.getter == Lookup::getter0Inline || l1.getter == Lookup::getter1) {
if (const Object *o = object.as<Object>()) {
ReturnedValue v = o->getLookup(l);
Lookup l2 = *l;
- if (l->index != UINT_MAX && (l2.getter == Lookup::getter0 || l2.getter == Lookup::getter1)) {
- // if we have a getter0, make sure it comes first
- if (l2.getter == Lookup::getter0)
- qSwap(l1, l2);
+ if (l2.index != UINT_MAX) {
+ if (l1.getter != Lookup::getter0Inline) {
+ if (l2.getter == Lookup::getter0Inline ||
+ (l1.getter != Lookup::getter0MemberData && l2.getter == Lookup::getter0MemberData))
+ // sort the better getter first
+ qSwap(l1, l2);
+ }
l->classList[0] = l1.classList[0];
l->classList[1] = l1.classList[1];
@@ -324,8 +333,22 @@ ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const
l->index = l1.index;
l->index2 = l2.index;
- if (l1.getter == Lookup::getter0) {
- l->getter = (l2.getter == Lookup::getter0) ? Lookup::getter0getter0 : Lookup::getter0getter1;
+ if (l1.getter == Lookup::getter0Inline) {
+ if (l2.getter == Lookup::getter0Inline)
+ l->getter = Lookup::getter0Inlinegetter0Inline;
+ else if (l2.getter == Lookup::getter0MemberData)
+ l->getter = Lookup::getter0Inlinegetter0MemberData;
+ else if (l2.getter == Lookup::getter1)
+ l->getter = Lookup::getter0Inlinegetter1;
+ else
+ Q_UNREACHABLE();
+ } else if (l1.getter == Lookup::getter0MemberData) {
+ if (l2.getter == Lookup::getter0MemberData)
+ l->getter = Lookup::getter0MemberDatagetter0MemberData;
+ else if (l2.getter == Lookup::getter1)
+ l->getter = Lookup::getter0MemberDatagetter1;
+ else
+ Q_UNREACHABLE();
} else {
Q_ASSERT(l1.getter == Lookup::getter1 && l2.getter == Lookup::getter1);
l->getter = Lookup::getter1getter1;
@@ -349,14 +372,26 @@ ReturnedValue Lookup::getterFallback(Lookup *l, ExecutionEngine *engine, const V
return o->get(name);
}
-ReturnedValue Lookup::getter0(Lookup *l, ExecutionEngine *engine, const Value &object)
+ReturnedValue Lookup::getter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
{
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass)
- return o->propertyData(l->index)->asReturnedValue();
+ return o->memberData->values.data()[l->index].asReturnedValue();
+ }
+ return getterTwoClasses(l, engine, object);
+}
+
+ReturnedValue Lookup::getter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ // we can safely cast to a QV4::Object here. If object is actually a string,
+ // the internal class won't match
+ Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+ if (o) {
+ if (l->classList[0] == o->internalClass)
+ return o->inlinePropertyData(l->index)->asReturnedValue();
}
return getterTwoClasses(l, engine, object);
}
@@ -367,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);
}
@@ -380,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();
}
@@ -392,31 +427,76 @@ ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &o
return getterFallback(l, engine, object);
}
-ReturnedValue Lookup::getter0getter0(Lookup *l, ExecutionEngine *engine, const Value &object)
+ReturnedValue Lookup::getter0Inlinegetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object)
{
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass)
- return o->propertyData(l->index)->asReturnedValue();
+ return o->inlinePropertyData(l->index)->asReturnedValue();
if (l->classList[2] == o->internalClass)
- return o->propertyData(l->index2)->asReturnedValue();
+ return o->inlinePropertyData(l->index2)->asReturnedValue();
+ }
+ l->getter = getterFallback;
+ return getterFallback(l, engine, object);
+}
+
+ReturnedValue Lookup::getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ // we can safely cast to a QV4::Object here. If object is actually a string,
+ // the internal class won't match
+ Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+ if (o) {
+ if (l->classList[0] == o->internalClass)
+ return o->inlinePropertyData(l->index)->asReturnedValue();
+ if (l->classList[2] == o->internalClass)
+ return o->memberData->values.data()[l->index2].asReturnedValue();
+ }
+ l->getter = getterFallback;
+ return getterFallback(l, engine, object);
+}
+
+ReturnedValue Lookup::getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ // we can safely cast to a QV4::Object here. If object is actually a string,
+ // the internal class won't match
+ Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+ if (o) {
+ if (l->classList[0] == o->internalClass)
+ return o->memberData->values.data()[l->index].asReturnedValue();
+ if (l->classList[2] == o->internalClass)
+ return o->memberData->values.data()[l->index2].asReturnedValue();
+ }
+ l->getter = getterFallback;
+ return getterFallback(l, engine, object);
+}
+
+ReturnedValue Lookup::getter0Inlinegetter1(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ // we can safely cast to a QV4::Object here. If object is actually a string,
+ // the internal class won't match
+ Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+ if (o) {
+ if (l->classList[0] == o->internalClass)
+ return o->inlinePropertyData(l->index)->asReturnedValue();
+ if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype()->internalClass)
+ return o->prototype()->propertyData(l->index2)->asReturnedValue();
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
}
-ReturnedValue Lookup::getter0getter1(Lookup *l, ExecutionEngine *engine, const Value &object)
+ReturnedValue Lookup::getter0MemberDatagetter1(Lookup *l, ExecutionEngine *engine, const Value &object)
{
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass)
- return o->propertyData(l->index)->asReturnedValue();
- if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass)
- return o->prototype->propertyData(l->index2)->asReturnedValue();
+ return o->memberData->values.data()[l->index].asReturnedValue();
+ if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype()->internalClass)
+ return o->prototype()->propertyData(l->index2)->asReturnedValue();
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
@@ -429,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;
@@ -470,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();
@@ -493,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));
@@ -514,12 +594,23 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const
return getterFallback(l, engine, object);
}
-ReturnedValue Lookup::primitiveGetter0(Lookup *l, ExecutionEngine *engine, const Value &object)
+ReturnedValue Lookup::primitiveGetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (object.type() == l->type) {
- Object *o = l->proto;
- if (l->classList[0] == o->internalClass())
- return o->propertyData(l->index)->asReturnedValue();
+ Heap::Object *o = l->proto;
+ if (l->classList[0] == o->internalClass)
+ return o->inlinePropertyData(l->index)->asReturnedValue();
+ }
+ l->getter = getterGeneric;
+ return getterGeneric(l, engine, object);
+}
+
+ReturnedValue Lookup::primitiveGetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ if (object.type() == l->type) {
+ Heap::Object *o = l->proto;
+ if (l->classList[0] == o->internalClass)
+ return o->memberData->values.data()[l->index].asReturnedValue();
}
l->getter = getterGeneric;
return getterGeneric(l, engine, object);
@@ -528,8 +619,8 @@ ReturnedValue Lookup::primitiveGetter0(Lookup *l, ExecutionEngine *engine, const
ReturnedValue Lookup::primitiveGetter1(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (object.type() == l->type) {
- Object *o = l->proto;
- if (l->classList[0] == o->internalClass() &&
+ Heap::Object *o = l->proto;
+ if (l->classList[0] == o->internalClass &&
l->classList[1] == o->prototype()->internalClass)
return o->prototype()->propertyData(l->index)->asReturnedValue();
}
@@ -540,9 +631,9 @@ ReturnedValue Lookup::primitiveGetter1(Lookup *l, ExecutionEngine *engine, const
ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (object.type() == l->type) {
- Object *o = l->proto;
- if (l->classList[0] == o->internalClass()) {
- Scope scope(o->engine());
+ Heap::Object *o = l->proto;
+ if (l->classList[0] == o->internalClass) {
+ Scope scope(o->internalClass->engine);
ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset));
if (!getter)
return Encode::undefined();
@@ -560,10 +651,10 @@ ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engin
ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (object.type() == l->type) {
- Object *o = l->proto;
- if (l->classList[0] == o->internalClass() &&
+ Heap::Object *o = l->proto;
+ if (l->classList[0] == o->internalClass &&
l->classList[1] == o->prototype()->internalClass) {
- Scope scope(o->engine());
+ Scope scope(o->internalClass->engine);
ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset));
if (!getter)
return Encode::undefined();
@@ -604,9 +695,15 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine)
ReturnedValue v = l->lookup(o, &attrs);
if (v != Primitive::emptyValue().asReturnedValue()) {
if (attrs.isData()) {
- if (l->level == 0)
- l->globalGetter = globalGetter0;
- else if (l->level == 1)
+ if (l->level == 0) {
+ uint nInline = o->d()->vtable()->nInlineProperties;
+ if (l->index < nInline)
+ l->globalGetter = globalGetter0Inline;
+ else {
+ l->index -= nInline;
+ l->globalGetter = globalGetter0MemberData;
+ }
+ } else if (l->level == 1)
l->globalGetter = globalGetter1;
else if (l->level == 2)
l->globalGetter = globalGetter2;
@@ -626,11 +723,21 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine)
return engine->throwReferenceError(n);
}
-ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionEngine *engine)
+ReturnedValue Lookup::globalGetter0Inline(Lookup *l, ExecutionEngine *engine)
{
Object *o = engine->globalObject;
if (l->classList[0] == o->internalClass())
- return o->propertyData(l->index)->asReturnedValue();
+ return o->d()->inlinePropertyData(l->index)->asReturnedValue();
+
+ l->globalGetter = globalGetterGeneric;
+ return globalGetterGeneric(l, engine);
+}
+
+ReturnedValue Lookup::globalGetter0MemberData(Lookup *l, ExecutionEngine *engine)
+{
+ Object *o = engine->globalObject;
+ if (l->classList[0] == o->internalClass())
+ return o->d()->memberData->values.data()[l->index].asReturnedValue();
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
@@ -651,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();
}
}
}
@@ -704,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));
@@ -746,7 +853,7 @@ void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object,
if (Object *o = object.as<Object>()) {
o->setLookup(l, value);
- if (l->setter == Lookup::setter0) {
+ if (l->setter == Lookup::setter0 || l->setter == Lookup::setter0Inline) {
l->setter = setter0setter0;
l->classList[1] = l1.classList[0];
l->index2 = l1.index;
@@ -770,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->setProperty(engine, l->index, value);
return;
@@ -779,15 +886,25 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va
setterTwoClasses(l, engine, object, value);
}
+void Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+{
+ Object *o = static_cast<Object *>(object.managed());
+ if (o && o->internalClass() == l->classList[0]) {
+ o->d()->setInlineProperty(engine, l->index, value);
+ return;
+ }
+
+ setterTwoClasses(l, engine, object, value);
+}
+
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->setProperty(l->index, value);
- return;
- }
+ Q_ASSERT(!o->prototype());
+ o->setInternalClass(l->classList[3]);
+ o->setProperty(l->index, value);
+ return;
}
l->setter = setterFallback;
@@ -796,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->setProperty(l->index, value);
return;
@@ -812,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->setProperty(l->index, value);
return;
@@ -831,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->setProperty(l->index, value);
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index daf3c71e27..ce5189a780 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -78,13 +78,14 @@ struct Lookup {
struct {
void *dummy0;
void *dummy1;
- Object *proto;
- unsigned type;
+ void *dummy2;
+ Heap::Object *proto;
};
};
union {
int level;
uint index2;
+ unsigned type;
};
uint index;
uint nameIndex;
@@ -101,17 +102,22 @@ struct Lookup {
static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterFallback(Lookup *l, ExecutionEngine *engine, const Value &object);
- static ReturnedValue getter0(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getter1(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getter2(Lookup *l, ExecutionEngine *engine, const Value &object);
- static ReturnedValue getter0getter0(Lookup *l, ExecutionEngine *engine, const Value &object);
- static ReturnedValue getter0getter1(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0Inlinegetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0Inlinegetter1(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0MemberDatagetter1(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getter1getter1(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterAccessor0(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterAccessor2(Lookup *l, ExecutionEngine *engine, const Value &object);
- static ReturnedValue primitiveGetter0(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue primitiveGetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue primitiveGetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetter1(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -119,7 +125,8 @@ struct Lookup {
static ReturnedValue arrayLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue globalGetterGeneric(Lookup *l, ExecutionEngine *engine);
- static ReturnedValue globalGetter0(Lookup *l, ExecutionEngine *engine);
+ static ReturnedValue globalGetter0Inline(Lookup *l, ExecutionEngine *engine);
+ static ReturnedValue globalGetter0MemberData(Lookup *l, ExecutionEngine *engine);
static ReturnedValue globalGetter1(Lookup *l, ExecutionEngine *engine);
static ReturnedValue globalGetter2(Lookup *l, ExecutionEngine *engine);
static ReturnedValue globalGetterAccessor0(Lookup *l, ExecutionEngine *engine);
@@ -130,6 +137,7 @@ struct Lookup {
static void setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static void setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static void setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static void setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static void setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static void setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static void setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 1b43fd86e8..e00eaa0d9b 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -48,6 +48,8 @@ const VTable Managed::static_vtbl =
{
0,
0,
+ 0,
+ 0,
Managed::IsExecutionContext,
Managed::IsString,
Managed::IsObject,
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index f97771831c..40dfc244ea 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>
#include <private/qv4writebarrier_p.h>
@@ -132,6 +133,9 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
{ \
parentVTable, \
markTable, \
+ (sizeof(classname::Data) + sizeof(QV4::Value) - 1)/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, \
classname::IsObject, \
@@ -151,6 +155,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 +201,9 @@ public:
};
Q_MANAGED_TYPE(Invalid)
+ InternalClass *internalClass() const { return d()->internalClass; }
+ inline ExecutionEngine *engine() const { return internalClass()->engine; }
+
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 fbe66757e0..9d333011fc 100644
--- a/src/qml/jsruntime/qv4memberdata_p.h
+++ b/src/qml/jsruntime/qv4memberdata_p.h
@@ -72,17 +72,18 @@ V4_ASSERT_IS_TRIVIAL(MemberData)
struct MemberData : Managed
{
V4_MANAGED(MemberData, Managed)
+ V4_INTERNALCLASS(MemberData)
struct Index {
- Heap::MemberData *memberData;
- uint index;
+ Heap::Base *base;
+ Value *slot;
- void set(ExecutionEngine *e, Value newVal) {
- memberData->values.set(e, index, newVal);
+ void set(EngineBase *e, Value newVal) {
+ WriteBarrier::write(e, base, slot, newVal);
}
- const Value *operator->() const { return &memberData->values[index]; }
- const Value &operator*() const { return memberData->values[index]; }
- bool isNull() const { return !memberData; }
+ const Value *operator->() const { return slot; }
+ const Value &operator*() const { return *slot; }
+ bool isNull() const { return !slot; }
};
const Value &operator[] (uint idx) const { return d()->values[idx]; }
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index e18267c50c..0bc2cd8c65 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 d400c2ae64..94d5a74fe5 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -61,9 +61,14 @@ 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;
bool hasMD = d()->memberData != nullptr;
- if ((!hasMD && ic->size) || (hasMD && d()->memberData->values.size < ic->size))
- d()->memberData.set(engine(), MemberData::allocate(ic->engine, ic->size, d()->memberData));
+ uint requiredSize = ic->size - nInline;
+ if (!(hasMD && requiredSize) || (hasMD && d()->memberData->values.size < requiredSize))
+ d()->memberData.set(ic->engine, MemberData::allocate(ic->engine, requiredSize, d()->memberData));
}
void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const
@@ -83,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.set(engine(), proto ? proto->d() : 0);
+ setInternalClass(internalClass()->changePrototype(p));
return true;
}
@@ -150,17 +156,6 @@ void Object::defineDefaultProperty(const QString &name, const Value &value)
defineDefaultProperty(s, value);
}
-void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount)
-{
- ExecutionEngine *e = engine();
- Scope scope(e);
- ScopedString s(scope, e->newIdentifier(name));
- ExecutionContext *global = e->rootContext();
- ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code));
- function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
- defineDefaultProperty(s, function);
-}
-
void Object::defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount)
{
ExecutionEngine *e = engine();
@@ -172,16 +167,6 @@ void Object::defineDefaultProperty(const QString &name, void (*code)(const Built
defineDefaultProperty(s, function);
}
-void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount)
-{
- ExecutionEngine *e = engine();
- Scope scope(e);
- ExecutionContext *global = e->rootContext();
- ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code));
- function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
- defineDefaultProperty(name, function);
-}
-
void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount)
{
ExecutionEngine *e = engine();
@@ -192,25 +177,6 @@ void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunct
defineDefaultProperty(name, function);
}
-void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *))
-{
- ExecutionEngine *e = engine();
- Scope scope(e);
- ScopedString s(scope, e->newIdentifier(name));
- defineAccessorProperty(s, getter, setter);
-}
-
-void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *))
-{
- ExecutionEngine *v4 = engine();
- QV4::Scope scope(v4);
- ScopedProperty p(scope);
- ExecutionContext *global = v4->rootContext();
- p->setGetter(ScopedFunctionObject(scope, (getter ? BuiltinFunction::create(global, name, getter) : 0)));
- p->setSetter(ScopedFunctionObject(scope, (setter ? BuiltinFunction::create(global, name, setter) : 0)));
- insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
-}
-
void Object::defineAccessorProperty(const QString &name, void (*getter)(const BuiltinFunction *, Scope &, CallData *),
void (*setter)(const BuiltinFunction *, Scope &, CallData *))
{
@@ -258,6 +224,18 @@ void Object::defineReadonlyConfigurableProperty(String *name, const Value &value
insertMember(name, value, Attr_ReadOnly_ButConfigurable);
}
+void Object::markObjects(Heap::Base *b, MarkStack *stack)
+{
+ Heap::Object *o = static_cast<Heap::Object *>(b);
+ uint nInline = o->vtable()->nInlineProperties;
+ Value *v = reinterpret_cast<Value *>(o) + o->vtable()->inlinePropertyOffset;
+ const Value *end = v + nInline;
+ while (v < end) {
+ v->mark(stack);
+ ++v;
+ }
+}
+
void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes)
{
uint idx;
@@ -278,7 +256,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();
+ Identifier *id = name->identifier();
+
+ uint member = internalClass()->find(id);
if (member < UINT_MAX) {
*attrs = internalClass()->propertyData[member];
if (p) {
@@ -317,15 +298,18 @@ MemberData::Index Object::getValueOrSetter(String *name, PropertyAttributes *att
{
Q_ASSERT(name->asArrayIndex() == UINT_MAX);
+ name->makeIdentifier();
+ 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 MemberData::Index{ o->memberData, attrs->isAccessor() ? idx + SetterOffset : idx };
+ return o->writablePropertyData(attrs->isAccessor() ? idx + SetterOffset : idx );
}
- o = o->prototype;
+ o = o->prototype();
}
*attrs = Attr_Invalid;
return { 0, 0 };
@@ -350,7 +334,7 @@ ArrayData::Index Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
return { reinterpret_cast<Heap::ArrayData *>(0x1), 0 };
}
}
- o = o->prototype;
+ o = o->prototype();
}
*attrs = Attr_Invalid;
return { 0, 0 };
@@ -394,7 +378,10 @@ bool Object::hasOwnProperty(String *name) const
if (idx != UINT_MAX)
return hasOwnProperty(idx);
- if (internalClass()->find(name) < UINT_MAX)
+ name->makeIdentifier();
+ Identifier *id = name->identifier();
+
+ if (internalClass()->find(id) < UINT_MAX)
return true;
if (!query(name).isEmpty())
return true;
@@ -451,8 +438,11 @@ PropertyAttributes Object::query(const Managed *m, String *name)
if (idx != UINT_MAX)
return queryIndexed(m, idx);
+ name->makeIdentifier();
+ 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];
@@ -488,9 +478,18 @@ 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()) {
- if (l->level == 0)
- l->getter = Lookup::getter0;
+ Q_ASSERT(l->classList[0] == o->internalClass());
+ if (l->level == 0) {
+ uint nInline = o->d()->vtable()->nInlineProperties;
+ if (l->index < nInline)
+ l->getter = Lookup::getter0Inline;
+ else {
+ l->index -= nInline;
+ l->getter = Lookup::getter0MemberData;
+ }
+ }
else if (l->level == 1)
l->getter = Lookup::getter1;
else if (l->level == 2)
@@ -525,7 +524,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 = Lookup::setter0;
+ l->setter = idx < o->d()->vtable()->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0;
o->setProperty(idx, value);
return;
}
@@ -642,12 +641,13 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) const
if (idx != UINT_MAX)
return getIndexed(idx, hasProperty);
- Scope scope(engine());
- name->makeIdentifier(scope.engine);
+ name->makeIdentifier();
+ Identifier *id = name->identifier();
+ Scope scope(engine());
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;
@@ -709,14 +709,15 @@ bool Object::internalPut(String *name, const Value &value)
if (idx != UINT_MAX)
return putIndexed(idx, value);
- name->makeIdentifier(engine);
+ name->makeIdentifier();
+ Identifier *id = name->identifier();
MemberData::Index memberIndex{0, 0};
- uint member = internalClass()->find(name);
+ uint member = internalClass()->find(id);
PropertyAttributes attrs;
if (member < UINT_MAX) {
attrs = internalClass()->propertyData[member];
- memberIndex = { d()->memberData, (attrs.isAccessor() ? member + SetterOffset : member) };
+ memberIndex = d()->writablePropertyData(attrs.isAccessor() ? member + SetterOffset : member);
}
// clause 1
@@ -869,9 +870,9 @@ bool Object::internalDeleteProperty(String *name)
if (idx != UINT_MAX)
return deleteIndexedProperty(idx);
- name->makeIdentifier(engine());
+ name->makeIdentifier();
- 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());
@@ -908,7 +909,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const
return __defineOwnProperty__(engine, idx, p, attrs);
Scope scope(engine);
- name->makeIdentifier(scope.engine);
+ name->makeIdentifier();
uint memberIndex;
@@ -942,7 +943,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
@@ -1188,7 +1189,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 df9d68525d..066a93cc61 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -68,8 +68,6 @@ struct BuiltinFunction;
namespace Heap {
#define ObjectMembers(class, Member) \
- Member(class, NoMark, InternalClass *, internalClass) \
- Member(class, Pointer, Object *, prototype) \
Member(class, Pointer, MemberData *, memberData) \
Member(class, Pointer, ArrayData *, arrayData)
@@ -78,12 +76,59 @@ DECLARE_HEAP_OBJECT(Object, Base) {
void init() { Base::init(); }
void destroy() { Base::destroy(); }
- const Value *propertyData(uint index) const { return memberData->values.data() + index; }
- void setProperty(ExecutionEngine *e, uint index, Value v) const { memberData->values.set(e, index, v); }
- void setProperty(ExecutionEngine *e, uint index, Heap::Base *b) const { memberData->values.set(e, index, b); }
+ const Value *inlinePropertyData(uint index) const {
+ Q_ASSERT(index < vtable()->nInlineProperties);
+ return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index;
+ }
+ void setInlineProperty(ExecutionEngine *e, uint index, Value v) {
+ Q_ASSERT(index < vtable()->nInlineProperties);
+ Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
+ WriteBarrier::write(e, this, prop, v);
+ }
+ void setInlineProperty(ExecutionEngine *e, uint index, Heap::Base *b) {
+ Q_ASSERT(index < vtable()->nInlineProperties);
+ Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
+ WriteBarrier::write(e, this, prop, b);
+ }
+
+ QV4::MemberData::Index writablePropertyData(uint index) {
+ uint nInline = vtable()->nInlineProperties;
+ if (index < nInline)
+ return { this, reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index};
+ index -= nInline;
+ return { memberData, memberData->values.values + index };
+ }
+
+ const Value *propertyData(uint index) const {
+ uint nInline = vtable()->nInlineProperties;
+ if (index < nInline)
+ return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index;
+ index -= nInline;
+ return memberData->values.data() + index;
+ }
+ void setProperty(ExecutionEngine *e, uint index, Value v) {
+ uint nInline = vtable()->nInlineProperties;
+ if (index < nInline) {
+ setInlineProperty(e, index, v);
+ return;
+ }
+ index -= nInline;
+ memberData->values.set(e, index, v);
+ }
+ void setProperty(ExecutionEngine *e, uint index, Heap::Base *b) {
+ uint nInline = vtable()->nInlineProperties;
+ if (index < nInline) {
+ setInlineProperty(e, index, b);
+ return;
+ }
+ index -= nInline;
+ memberData->values.set(e, index, b);
+ }
+
+ Heap::Object *prototype() const { return internalClass->prototype; }
};
-Q_STATIC_ASSERT(Object::markTable == ((2 << 4) | (2 << 6) | (2 << 8)));
+Q_STATIC_ASSERT(Object::markTable == ((2 << 2) | (2 << 4)));
}
@@ -122,9 +167,6 @@ Q_STATIC_ASSERT(Object::markTable == ((2 << 4) | (2 << 6) | (2 << 8)));
V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); \
static Q_CONSTEXPR quint64 markTable = QV4::Heap::DataClass::markTable;
-#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(); }
@@ -183,7 +225,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 {
@@ -192,7 +234,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); }
@@ -208,7 +249,7 @@ struct Q_QML_EXPORT Object: Managed {
void setProperty(ExecutionEngine *engine, uint index, Heap::Base *b) const { d()->setProperty(engine, index, b); }
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);
@@ -246,12 +287,8 @@ struct Q_QML_EXPORT Object: Managed {
insertMember(name, value, Attr_Data|Attr_NotEnumerable);
}
void defineDefaultProperty(const QString &name, const Value &value);
- void defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
void defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0);
- void defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
void defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0);
- void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *));
- void defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *));
void defineAccessorProperty(const QString &name, void (*getter)(const BuiltinFunction *, Scope &, CallData *),
void (*setter)(const BuiltinFunction *, Scope &, CallData *));
void defineAccessorProperty(String *name, void (*getter)(const BuiltinFunction *, Scope &, CallData *),
@@ -272,8 +309,6 @@ struct Q_QML_EXPORT Object: Managed {
}
void insertMember(String *s, const Property *p, PropertyAttributes attributes);
- inline ExecutionEngine *engine() const { return internalClass()->engine; }
-
bool isExtensible() const { return d()->internalClass->extensible; }
// Array handling
@@ -424,6 +459,7 @@ protected:
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static uint getLength(const Managed *m);
static ReturnedValue instanceOf(const Object *typeObject, const Value &var);
+ static void markObjects(Heap::Base *, MarkStack *);
private:
ReturnedValue internalGet(String *name, bool *hasProperty) const;
@@ -498,7 +534,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 c08dd7baa3..61d785066f 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -297,15 +297,15 @@ bool QQmlContextWrapper::put(Managed *m, String *name, const Value &value)
void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml)
{
- Heap::ExecutionContext::init(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext);
- outer.set(engine, outerContext->d());
+ Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext);
+ outer.set(internalClass->engine, outerContext->d());
strictMode = false;
callData = outer->callData;
lookups = outer->lookups;
constantTable = outer->constantTable;
compilationUnit = outer->compilationUnit;
- this->qml.set(engine, qml->d());
+ this->qml.set(internalClass->engine, qml->d());
}
Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, const QUrl &source, Value *sendFunction)
@@ -327,7 +327,8 @@ Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, cons
qml->QV4::Object::put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("WorkerScript"))), api);
qml->setReadOnly(true);
- Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc<QmlContext>(parent, qml);
+ Heap::QmlContext *c = scope.engine->memoryManager->alloc<QmlContext>(parent, qml);
+ Q_ASSERT(c->vtable() == staticVTable());
return c;
}
@@ -336,7 +337,8 @@ Heap::QmlContext *QmlContext::create(ExecutionContext *parent, QQmlContextData *
Scope scope(parent);
Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, scopeObject));
- Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc<QmlContext>(parent, qml);
+ Heap::QmlContext *c = scope.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 83730d632a..91650f16e2 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1060,7 +1060,6 @@ void QObjectWrapper::destroyObject(bool lastCall)
}
}
- h->internalClass = 0;
h->~Data();
}
@@ -1813,7 +1812,7 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine)
ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, int index)
{
Scope valueScope(scope);
- Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->allocObject<QObjectMethod>(scope));
+ Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocObject<QObjectMethod>(scope));
method->d()->setObject(object);
if (QQmlData *ddata = QQmlData::get(object))
@@ -1864,7 +1863,7 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) co
result = QLatin1String("null");
}
- return ctx->d()->engine->newString(result)->asReturnedValue();
+ return ctx->engine()->newString(result)->asReturnedValue();
}
QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const
diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h
index 348af0fb14..7ab12fe245 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 85e37ebe82..735951e085 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -356,7 +356,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 0fcfe93135..6f54a4ab92 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -103,7 +103,7 @@ DECLARE_HEAP_OBJECT(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 610db8ec00..df2af9de40 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -554,7 +554,7 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu
if (!sright->d()->length())
return sleft->asReturnedValue();
MemoryManager *mm = engine->memoryManager;
- return (mm->alloc<String>(mm, sleft->d(), sright->d()))->asReturnedValue();
+ return (mm->alloc<String>(sleft->d(), sright->d()))->asReturnedValue();
}
double x = RuntimeHelpers::toNumber(pleft);
double y = RuntimeHelpers::toNumber(pright);
@@ -586,7 +586,7 @@ QV4::ReturnedValue Runtime::method_addString(ExecutionEngine *engine, const Valu
if (!sright->d()->length())
return pleft->asReturnedValue();
MemoryManager *mm = engine->memoryManager;
- return (mm->alloc<String>(mm, sleft->d(), sright->d()))->asReturnedValue();
+ return (mm->alloc<String>(sleft->d(), sright->d()))->asReturnedValue();
}
void Runtime::method_setProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)
@@ -599,41 +599,53 @@ void Runtime::method_setProperty(ExecutionEngine *engine, const Value &object, i
o->put(name, value);
}
-ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &object, const Value &index)
+static Q_NEVER_INLINE ReturnedValue getElementIntFallback(ExecutionEngine *engine, const Value &object, uint idx)
{
+ Q_ASSERT(idx < UINT_MAX);
Scope scope(engine);
- uint idx = index.asArrayIndex();
ScopedObject o(scope, object);
if (!o) {
- if (idx < UINT_MAX) {
- if (const String *str = object.as<String>()) {
- if (idx >= (uint)str->toQString().length()) {
- return Encode::undefined();
- }
- const QString s = str->toQString().mid(idx, 1);
- return scope.engine->newString(s)->asReturnedValue();
+ if (const String *str = object.as<String>()) {
+ if (idx >= (uint)str->toQString().length()) {
+ return Encode::undefined();
}
+ const QString s = str->toQString().mid(idx, 1);
+ return scope.engine->newString(s)->asReturnedValue();
}
if (object.isNullOrUndefined()) {
- QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow());
+ QString message = QStringLiteral("Cannot read property '%1' of %2").arg(idx).arg(object.toQStringNoThrow());
return engine->throwTypeError(message);
}
o = RuntimeHelpers::convertToObject(scope.engine, object);
- if (!o) // type error
- return Encode::undefined();
+ Q_ASSERT(!!o); // can't fail as null/undefined is covered above
+ }
+
+ if (o->arrayData() && !o->arrayData()->attrs) {
+ ScopedValue v(scope, o->arrayData()->get(idx));
+ if (!v->isEmpty())
+ return v->asReturnedValue();
}
- if (idx < UINT_MAX) {
- if (o->arrayData() && !o->arrayData()->attrs) {
- ScopedValue v(scope, o->arrayData()->get(idx));
- if (!v->isEmpty())
- return v->asReturnedValue();
+ return o->getIndexed(idx);
+}
+
+static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine, const Value &object, const Value &index)
+{
+ Q_ASSERT(index.asArrayIndex() == UINT_MAX);
+ Scope scope(engine);
+
+ ScopedObject o(scope, object);
+ if (!o) {
+ if (object.isNullOrUndefined()) {
+ QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow());
+ return engine->throwTypeError(message);
}
- return o->getIndexed(idx);
+ o = RuntimeHelpers::convertToObject(scope.engine, object);
+ Q_ASSERT(!!o); // can't fail as null/undefined is covered above
}
ScopedString name(scope, index.toString(engine));
@@ -642,18 +654,39 @@ ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &o
return o->get(name);
}
-void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
+ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &object, const Value &index)
+{
+ uint idx;
+ if (index.asArrayIndex(idx)) {
+ if (Heap::Base *b = object.heapObject()) {
+ if (b->vtable()->isObject) {
+ Heap::Object *o = static_cast<Heap::Object *>(b);
+ if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
+ Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
+ if (idx < s->values.size)
+ if (!s->data(idx).isEmpty())
+ return s->data(idx).asReturnedValue();
+ }
+ }
+ }
+ return getElementIntFallback(engine, object, idx);
+ }
+
+ return getElementFallback(engine, object, index);
+}
+
+static Q_NEVER_INLINE void setElementFallback(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
Scope scope(engine);
ScopedObject o(scope, object.toObject(engine));
- if (scope.engine->hasException)
+ if (engine->hasException)
return;
- uint idx = index.asArrayIndex();
- if (idx < UINT_MAX) {
- if (o->arrayType() == Heap::ArrayData::Simple) {
- Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->arrayData());
- if (s && idx < s->values.size && !s->data(idx).isEmpty()) {
+ uint idx;
+ if (index.asArrayIndex(idx)) {
+ if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) {
+ Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>();
+ if (idx < s->values.size) {
s->setData(engine, idx, value);
return;
}
@@ -666,6 +699,27 @@ void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, co
o->put(name, value);
}
+void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
+{
+ uint idx;
+ if (index.asArrayIndex(idx)) {
+ if (Heap::Base *b = object.heapObject()) {
+ if (b->vtable()->isObject) {
+ Heap::Object *o = static_cast<Heap::Object *>(b);
+ if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
+ Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
+ if (idx < s->values.size) {
+ s->setData(engine, idx, value);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ return setElementFallback(engine, object, index, value);
+}
+
ReturnedValue Runtime::method_foreachIterator(ExecutionEngine *engine, const Value &in)
{
Scope scope(engine);
@@ -1354,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/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index bc882bbd95..04a0c74133 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -102,7 +102,7 @@ struct ScopedValue;
struct Scope {
inline Scope(ExecutionContext *ctx)
- : engine(ctx->d()->engine)
+ : engine(ctx->engine())
, mark(engine->jsStackTop)
, result(*engine->jsAlloca(1))
{
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index dcab34d092..2b8d1ea716 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.cpp b/src/qml/jsruntime/qv4string.cpp
index 71f85c2d71..c0183a46a7 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -75,10 +75,9 @@ bool String::isEqualTo(Managed *t, Managed *o)
}
-void Heap::String::init(MemoryManager *mm, const QString &t)
+void Heap::String::init(const QString &t)
{
Base::init();
- this->mm = mm;
subtype = String::StringType_Unknown;
@@ -90,10 +89,9 @@ void Heap::String::init(MemoryManager *mm, const QString &t)
len = text->size;
}
-void Heap::String::init(MemoryManager *mm, String *l, String *r)
+void Heap::String::init(String *l, String *r)
{
Base::init();
- this->mm = mm;
subtype = String::StringType_Unknown;
@@ -116,7 +114,7 @@ void Heap::String::init(MemoryManager *mm, String *l, String *r)
void Heap::String::destroy() {
if (!largestSubLength) {
- mm->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar));
+ internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar));
if (!text->ref.deref())
QStringData::deallocate(text);
}
@@ -141,12 +139,12 @@ uint String::toUInt(bool *ok) const
return UINT_MAX;
}
-void String::makeIdentifierImpl(ExecutionEngine *e) const
+void String::makeIdentifierImpl() const
{
if (d()->largestSubLength)
d()->simplifyString();
Q_ASSERT(!d()->largestSubLength);
- e->identifierTable->identifier(this);
+ engine()->identifierTable->identifier(this);
}
void Heap::String::simplifyString() const
@@ -161,7 +159,7 @@ void Heap::String::simplifyString() const
text->ref.ref();
identifier = 0;
largestSubLength = 0;
- mm->changeUnmanagedHeapSizeUsage(qptrdiff(text->size) * (qptrdiff)sizeof(QChar));
+ internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(text->size) * (qptrdiff)sizeof(QChar));
}
void Heap::String::append(const String *data, QChar *ch)
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index 71e55cbcd4..df0394d4cb 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
@@ -71,8 +72,8 @@ struct Q_QML_PRIVATE_EXPORT String : Base {
};
#ifndef V4_BOOTSTRAP
- void init(MemoryManager *mm, const QString &text);
- void init(MemoryManager *mm, String *l, String *n);
+ void init(const QString &text);
+ void init(String *l, String *n);
void destroy();
void simplifyString() const;
int length() const {
@@ -125,7 +126,6 @@ struct Q_QML_PRIVATE_EXPORT String : Base {
mutable uint stringHash;
mutable uint largestSubLength;
uint len;
- MemoryManager *mm;
private:
static void append(const String *data, QChar *ch);
#endif
@@ -138,6 +138,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
@@ -174,13 +175,17 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
}
uint toUInt(bool *ok) const;
- void makeIdentifier(ExecutionEngine *e) const {
+ Q_DECL_DEPRECATED void makeIdentifier(ExecutionEngine *) {
+ makeIdentifier();
+ }
+
+ void makeIdentifier() const {
if (d()->identifier)
return;
- makeIdentifierImpl(e);
+ makeIdentifierImpl();
}
- void makeIdentifierImpl(ExecutionEngine *e) const;
+ void makeIdentifierImpl() const;
static uint createHashValue(const QChar *ch, int length, uint *subtype)
{
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 5ccee3335e..ce046f4844 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -86,7 +86,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 {
@@ -112,6 +112,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 a34a8922e1..fe27d7c2d2 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);
}
ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty)
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 96786c8231..a472dfa607 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -149,6 +149,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 e281602bb5..a7c6fa320c 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 e16df8dc60..7293630924 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -172,7 +172,7 @@ static QV4::Function *qt_v4ExtractFunction(QV4::ExecutionContext *context)
if (QV4::Function *function = context->getFunction())
return function;
else
- return context->d()->engine->globalCode;
+ return context->engine()->globalCode;
}
static void qt_v4TriggerBreakpoint(const Breakpoint &bp, QV4::Function *function)
@@ -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
@@ -362,11 +362,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);
@@ -375,15 +371,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;
@@ -392,7 +384,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
@@ -402,7 +393,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;
@@ -415,10 +406,10 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
};
Q_ALLOCA_VAR(Scopes, scopes, sizeof(Scopes)*(2 + 2*scopeDepth));
{
- scopes[0] = { const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(context->d()->compilationUnit)->constants), 0 };
+ scopes[0] = { const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->constants), 0 };
// stack gets setup in push instruction
scopes[1] = { 0, 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) {
@@ -442,7 +433,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
@@ -461,12 +452,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)
@@ -479,7 +470,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)
@@ -494,7 +485,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, engine, VALUE(instr.base), VALUE(instr.index)));
MOTH_END_INSTR(LoadElementLookup)
@@ -504,7 +495,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, engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElementLookup)
@@ -514,7 +505,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)
@@ -524,7 +515,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)
@@ -595,7 +586,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);
@@ -614,7 +605,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);
@@ -624,7 +615,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);
@@ -675,18 +666,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)
@@ -926,22 +914,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)
@@ -967,25 +955,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 a38a938588..f00ce4283c 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,10 +70,14 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+struct InternalClass;
+
struct VTable
{
const VTable * const parent;
const quint64 markTable;
+ uint inlinePropertyOffset : 16;
+ uint nInlineProperties : 16;
uint isExecutionContext : 1;
uint isString : 1;
uint isObject : 1;
@@ -94,13 +99,12 @@ struct Q_QML_EXPORT Base {
static Q_CONSTEXPR quint64 markTable = 0;
- const VTable *vt;
+ InternalClass *internalClass;
inline ReturnedValue asReturnedValue() const;
inline void mark(QV4::MarkStack *markStack);
- 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();
@@ -175,7 +179,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);
}
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 64b07153cc..de97918fb0 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -348,8 +348,9 @@ static void increaseFreedCountForClass(const char *className)
(*freedObjectStatsGlobal())[className]++;
}
-void Chunk::sweep(ClassDestroyStatsCallback classCountPtr)
+bool Chunk::sweep(ClassDestroyStatsCallback classCountPtr)
{
+ bool hasUsedSlots = false;
SDUMP() << "sweeping chunk" << this;
HeapItem *o = realBase();
bool lastSlotFree = false;
@@ -395,6 +396,7 @@ void Chunk::sweep(ClassDestroyStatsCallback classCountPtr)
}
objectBitmap[i] = blackBitmap[i];
grayBitmap[i] = 0;
+ hasUsedSlots |= (blackBitmap[i] != 0);
extendsBitmap[i] = e;
lastSlotFree = !((objectBitmap[i]|extendsBitmap[i]) >> (sizeof(quintptr)*8 - 1));
SDUMP() << " new extends =" << binary(e);
@@ -403,6 +405,7 @@ void Chunk::sweep(ClassDestroyStatsCallback classCountPtr)
o += Chunk::Bits;
}
// DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots.";
+ return hasUsedSlots;
}
void Chunk::freeAll()
@@ -700,12 +703,21 @@ void BlockAllocator::sweep(ClassDestroyStatsCallback classCountPtr)
// qDebug() << "BlockAlloc: sweep";
usedSlotsAfterLastSweep = 0;
- for (auto c : chunks) {
- c->sweep(classCountPtr);
- c->sortIntoBins(freeBins, NumBins);
-// qDebug() << "used slots in chunk" << c << ":" << c->nUsedSlots();
- usedSlotsAfterLastSweep += c->nUsedSlots();
- }
+
+ auto isFree = [this, classCountPtr] (Chunk *c) {
+ bool isUsed = c->sweep(classCountPtr);
+
+ 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()
@@ -922,13 +934,17 @@ Heap::Base *MemoryManager::allocData(std::size_t size)
return *m;
}
-Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nMembers)
+Heap::Object *MemoryManager::allocObjectWithMemberData(const QV4::VTable *vtable, uint nMembers)
{
+ uint size = (vtable->nInlineProperties + vtable->inlinePropertyOffset)*sizeof(Value);
+ Q_ASSERT(!(size % sizeof(HeapItem)));
+
Heap::Object *o;
- if (!nMembers) {
+ if (nMembers <= vtable->nInlineProperties) {
o = static_cast<Heap::Object *>(allocData(size));
} else {
// Allocate both in one go through the block allocator
+ nMembers -= vtable->nInlineProperties;
std::size_t memberSize = align(sizeof(Heap::MemberData) + (nMembers - 1)*sizeof(Value));
size_t totalSize = size + memberSize;
Heap::MemberData *m;
@@ -947,7 +963,8 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nM
Chunk::clearBit(c->extendsBitmap, index);
}
o->memberData.set(engine, m);
- m->setVtable(MemberData::staticVTable());
+ m->internalClass = engine->internalClasses[EngineBase::Class_MemberData];
+ Q_ASSERT(o->memberData->internalClass);
m->values.alloc = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
m->values.size = o->memberData->values.alloc;
m->init();
@@ -1147,7 +1164,8 @@ void MemoryManager::runGC()
qDebug() << " Allocations since last GC" << allocationCount;
allocationCount = 0;
#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);
@@ -1190,8 +1208,9 @@ void MemoryManager::runGC()
});
qDebug() << "Used memory before GC:" << usedBefore;
- qDebug() << "Used memory after GC :" << usedAfter;
- qDebug() << "Freed up bytes :" << (usedBefore - usedAfter);
+ 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 df7d09dce0..17957d0cd6 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -211,12 +211,13 @@ public:
Q_DECL_CONSTEXPR static inline std::size_t align(std::size_t size)
{ return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); }
- QV4::Heap::SimpleCallContext *allocSimpleCallContext(QV4::ExecutionEngine *v4)
+ QV4::Heap::CallContext *allocSimpleCallContext()
{
Heap::CallContext *ctxt = stackAllocator.allocate();
memset(ctxt, 0, sizeof(Heap::SimpleCallContext));
- ctxt->setVtable(QV4::SimpleCallContext::staticVTable());
- ctxt->init(v4);
+ ctxt->internalClass = SimpleCallContext::defaultInternalClass(engine);
+ Q_ASSERT(ctxt->internalClass && ctxt->internalClass->vtable);
+ ctxt->init();
return ctxt;
}
@@ -229,16 +230,20 @@ 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);
}
template <typename ObjectType>
typename ObjectType::Data *allocateObject(InternalClass *ic)
{
- Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size);
- o->setVtable(ObjectType::staticVTable());
+ Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size);
o->internalClass = ic;
+ Q_ASSERT(o->internalClass && o->internalClass->vtable);
+ Q_ASSERT(ic->vtable == ObjectType::staticVTable());
return static_cast<typename ObjectType::Data *>(o);
}
@@ -246,11 +251,12 @@ public:
typename ObjectType::Data *allocateObject()
{
InternalClass *ic = ObjectType::defaultInternalClass(engine);
- Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size);
- o->setVtable(ObjectType::staticVTable());
- Object *prototype = ObjectType::defaultPrototype(engine);
+ ic = ic->changeVTable(ObjectType::staticVTable());
+ ic = ic->changePrototype(ObjectType::defaultPrototype(engine)->d());
+ Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size);
o->internalClass = ic;
- o->prototype.set(engine, 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);
}
@@ -258,8 +264,9 @@ 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->init(this, arg1);
+ o->internalClass = ManagedType::defaultInternalClass(engine);
+ Q_ASSERT(o->internalClass && o->internalClass->vtable);
+ o->init(arg1);
return o;
}
@@ -277,7 +284,8 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype.set(engine, prototype->d());
+ Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0));
+ Q_UNUSED(prototype);
t->d_unchecked()->init();
return t->d();
}
@@ -287,7 +295,8 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype.set(engine, prototype->d());
+ Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0));
+ Q_UNUSED(prototype);
t->d_unchecked()->init(arg1);
return t->d();
}
@@ -297,7 +306,8 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype.set(engine, prototype->d());
+ Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0));
+ Q_UNUSED(prototype);
t->d_unchecked()->init(arg1, arg2);
return t->d();
}
@@ -307,7 +317,8 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype.set(engine, prototype->d());
+ Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0));
+ Q_UNUSED(prototype);
t->d_unchecked()->init(arg1, arg2, arg3);
return t->d();
}
@@ -317,7 +328,8 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype.set(engine, 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();
}
@@ -437,7 +449,7 @@ protected:
/// expects size to be aligned
Heap::Base *allocString(std::size_t unmanagedSize);
Heap::Base *allocData(std::size_t size);
- Heap::Object *allocObjectWithMemberData(std::size_t size, uint nMembers);
+ Heap::Object *allocObjectWithMemberData(const QV4::VTable *vtable, uint nMembers);
#ifdef DETAILED_MM_STATS
void willAllocate(std::size_t size);
diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
index bf29b44a2c..328797fb5e 100644
--- a/src/qml/memory/qv4mmdefs_p.h
+++ b/src/qml/memory/qv4mmdefs_p.h
@@ -186,7 +186,7 @@ struct Chunk {
return usedSlots;
}
- void sweep(ClassDestroyStatsCallback classCountPtr);
+ bool sweep(ClassDestroyStatsCallback classCountPtr);
void freeAll();
void resetBlackBits();
void collectGrayItems(QV4::MarkStack *markStack);
@@ -269,7 +269,7 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize);
Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits);
Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits);
-struct MarkStack {\
+struct MarkStack {
MarkStack(ExecutionEngine *engine);
Heap::Base **top = 0;
Heap::Base **base = 0;
@@ -287,35 +287,6 @@ struct MarkStack {\
};
-// 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;
- quint8 hasException = false;
- quint8 writeBarrierActive = false;
- quint16 unused = 0;
-#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);
-
// Some helper classes and macros to automate the generation of our
// tables used for marking objects
diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h
index e36ea0749a..3182fd2aa9 100644
--- a/src/qml/memory/qv4writebarrier_p.h
+++ b/src/qml/memory/qv4writebarrier_p.h
@@ -149,6 +149,9 @@ struct HeapValue : Value {
void set(ExecutionEngine *e, const Value &newVal) {
WriteBarrier::write(e, base(), this, newVal);
}
+ void set(ExecutionEngine *e, Heap::Base *b) {
+ WriteBarrier::write(e, base(), this, b);
+ }
};
template <size_t offset>
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index 66f9eac126..53e67fde03 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -724,6 +724,11 @@ again:
return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL;
} else if (_char == QLatin1Char('\\')) {
scanChar();
+ if (_codePtr > _endPtr) {
+ _errorCode = IllegalEscapeSequence;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "End of file reached at escape sequence");
+ return T_ERROR;
+ }
QChar u;
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 88ce2fa1b9..d18159841c 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -970,8 +970,11 @@ int QQmlPropertyCache::originalClone(QObject *object, int index)
QQmlData *data = QQmlData::get(object, false);
if (data && data->propertyCache) {
QQmlPropertyCache *cache = data->propertyCache;
- while (cache->signal(index)->isCloned())
+ QQmlPropertyData *sig = cache->signal(index);
+ while (sig && sig->isCloned()) {
--index;
+ sig = cache->signal(index);
+ }
} else {
while (QMetaObjectPrivate::signal(object->metaObject(), index).attributes() & QMetaMethod::Cloned)
--index;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 40bd2e5020..e4293596d8 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1320,8 +1320,8 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData:
{
QQmlQmldirData *data = typeLoader()->getQmldir(url);
- data->setImport(import);
- data->setPriority(priority);
+ data->setImport(this, import);
+ data->setPriority(this, priority);
if (data->status() == Error) {
// This qmldir must not exist - which is not an error
@@ -1349,7 +1349,7 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::Compile
QHash<const QV4::CompiledData::Import *, int>::iterator it = m_unresolvedImports.find(import);
if (it != m_unresolvedImports.end()) {
- *it = data->priority();
+ *it = data->priority(this);
}
// Release this reference at destruction
@@ -1482,7 +1482,7 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
if (blob->type() == QQmlDataBlob::QmldirFile) {
QQmlQmldirData *data = static_cast<QQmlQmldirData *>(blob);
- const QV4::CompiledData::Import *import = data->import();
+ const QV4::CompiledData::Import *import = data->import(this);
QList<QQmlError> errors;
if (!qmldirDataAvailable(data, &errors)) {
@@ -1506,11 +1506,11 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlE
{
bool resolve = true;
- const QV4::CompiledData::Import *import = data->import();
- data->setImport(0);
+ const QV4::CompiledData::Import *import = data->import(this);
+ data->setImport(this, 0);
- int priority = data->priority();
- data->setPriority(0);
+ int priority = data->priority(this);
+ data->setPriority(this, 0);
if (import) {
// Do we need to resolve this import?
@@ -3069,7 +3069,7 @@ void QQmlScriptBlob::initializeFromCompilationUnit(QV4::CompiledData::Compilatio
}
QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader)
-: QQmlTypeLoader::Blob(url, QmldirFile, loader), m_import(0), m_priority(0)
+: QQmlTypeLoader::Blob(url, QmldirFile, loader)
{
}
@@ -3078,24 +3078,31 @@ const QString &QQmlQmldirData::content() const
return m_content;
}
-const QV4::CompiledData::Import *QQmlQmldirData::import() const
+const QV4::CompiledData::Import *QQmlQmldirData::import(QQmlTypeLoader::Blob *blob) const
{
- return m_import;
+ QHash<QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *>::const_iterator it =
+ m_imports.find(blob);
+ if (it == m_imports.end())
+ return 0;
+ return *it;
}
-void QQmlQmldirData::setImport(const QV4::CompiledData::Import *import)
+void QQmlQmldirData::setImport(QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import)
{
- m_import = import;
+ m_imports[blob] = import;
}
-int QQmlQmldirData::priority() const
+int QQmlQmldirData::priority(QQmlTypeLoader::Blob *blob) const
{
- return m_priority;
+ QHash<QQmlTypeLoader::Blob *, int>::const_iterator it = m_priorities.find(blob);
+ if (it == m_priorities.end())
+ return 0;
+ return *it;
}
-void QQmlQmldirData::setPriority(int priority)
+void QQmlQmldirData::setPriority(QQmlTypeLoader::Blob *blob, int priority)
{
- m_priority = priority;
+ m_priorities[blob] = priority;
}
void QQmlQmldirData::dataReceived(const SourceCodeData &data)
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 48e7d5cba4..f367fa6f58 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -572,11 +572,11 @@ private:
public:
const QString &content() const;
- const QV4::CompiledData::Import *import() const;
- void setImport(const QV4::CompiledData::Import *);
+ const QV4::CompiledData::Import *import(QQmlTypeLoader::Blob *) const;
+ void setImport(QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *);
- int priority() const;
- void setPriority(int);
+ int priority(QQmlTypeLoader::Blob *) const;
+ void setPriority(QQmlTypeLoader::Blob *, int);
protected:
void dataReceived(const SourceCodeData &) override;
@@ -584,8 +584,8 @@ protected:
private:
QString m_content;
- const QV4::CompiledData::Import *m_import;
- int m_priority;
+ QHash<QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *> m_imports;
+ QHash<QQmlTypeLoader::Blob *, int> m_priorities;
};
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 9f86d1cae9..a2ab9bdfed 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -105,7 +105,7 @@ void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
QV4::Scope scope(v4);
QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value());
if (sp) {
- QV4::MemberData::Index index{ sp->d(), static_cast<uint>(m_index) };
+ QV4::MemberData::Index index{ sp->d(), sp->d()->values.values + m_index };
index.set(v4, QV4::Primitive::nullValue());
}
}
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index b18904fc73..9e8735cbc6 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -895,7 +895,7 @@ ReturnedValue NamedNodeMap::get(const Managed *m, String *name, bool *hasPropert
const NamedNodeMap *r = static_cast<const NamedNodeMap *>(m);
QV4::ExecutionEngine *v4 = r->engine();
- name->makeIdentifier(v4);
+ name->makeIdentifier();
if (name->equals(v4->id_length()))
return Primitive::fromInt32(r->d()->list().count()).asReturnedValue();
@@ -940,7 +940,7 @@ ReturnedValue NodeList::get(const Managed *m, String *name, bool *hasProperty)
const NodeList *r = static_cast<const NodeList *>(m);
QV4::ExecutionEngine *v4 = r->engine();
- name->makeIdentifier(v4);
+ name->makeIdentifier();
if (name->equals(v4->id_length()))
return Primitive::fromInt32(r->d()->d->children.count()).asReturnedValue();
diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h
index 6547274d09..3314e73d19 100644
--- a/src/qml/qtqmlglobal_p.h
+++ b/src/qml/qtqmlglobal_p.h
@@ -55,46 +55,12 @@
#include <QtQml/private/qtqml-config_p.h>
#include <QtQml/qtqmlglobal.h>
-// Define Q_ALLOCA_VAR macro to be used instead of #ifdeffing
-// the occurrences of alloca() in case it's not supported.
-// Q_ALLOCA_DECLARE and Q_ALLOCA_ASSIGN macros separate
-// memory allocation from the declaration and RAII.
-#define Q_ALLOCA_VAR(type, name, size) \
- Q_ALLOCA_DECLARE(type, name); \
- Q_ALLOCA_ASSIGN(type, name, size)
-
-#if defined(QT_BOOTSTRAPPED) || QT_CONFIG(alloca)
-
-#define Q_ALLOCA_DECLARE(type, name) \
- type *name = 0
-
-#define Q_ALLOCA_ASSIGN(type, name, size) \
- name = static_cast<type*>(alloca(size))
+#define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT
+#if !defined(QT_QMLDEVTOOLS_LIB) && !defined(QT_BUILD_QMLDEVTOOLS_LIB)
+# define Q_QML_AUTOTEST_EXPORT Q_AUTOTEST_EXPORT
#else
-QT_BEGIN_NAMESPACE
-class Qt_AllocaWrapper
-{
-public:
- Qt_AllocaWrapper() { m_data = 0; }
- ~Qt_AllocaWrapper() { free(m_data); }
- void *data() { return m_data; }
- void allocate(int size) { m_data = malloc(size); }
-private:
- void *m_data;
-};
-QT_END_NAMESPACE
-
-#define Q_ALLOCA_DECLARE(type, name) \
- Qt_AllocaWrapper _qt_alloca_##name; \
- type *name = 0
-
-#define Q_ALLOCA_ASSIGN(type, name, size) \
- _qt_alloca_##name.allocate(size); \
- name = static_cast<type*>(_qt_alloca_##name.data())
-
+# define Q_QML_AUTOTEST_EXPORT
#endif
-#define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT
-
#endif // QTQMLGLOBAL_P_H
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 6e9cb5f1fe..e218cdcfe4 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -286,6 +286,7 @@ void QQmlConnections::connectSignals()
int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex();
QQmlBoundSignal *signal =
new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
+ signal->setEnabled(d->enabled);
QQmlBoundSignalExpression *expression = ctxtdata ?
new QQmlBoundSignalExpression(target, signalIndex,
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 44d968fd46..517411fa47 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -1076,6 +1076,7 @@ void ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *tar
QVariant v = src->getProperty(srcRole, 0, 0);
target->setVariantProperty(targetRole, v);
}
+ break;
case ListLayout::Role::VariantMap:
{
QVariantMap *map = src->getVariantMapProperty(srcRole);
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index c77495a1a7..b9f6ea461a 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -61,14 +61,13 @@ public:
V4_DEFINE_EXTENSION(QQmlAdaptorModelEngineData, engineData)
-static QV4::ReturnedValue get_index(QV4::CallContext *ctx)
+static void get_index(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object")));
- return QV4::Encode(o->d()->item->index);
+ RETURN_RESULT(QV4::Encode(o->d()->item->index));
}
template <typename T, typename M> static void setModelDataType(QMetaObjectBuilder *builder, M *metaType)
@@ -195,19 +194,18 @@ public:
dataType->watchedRoles += newRoles;
}
- static QV4::ReturnedValue get_hasModelChildren(QV4::CallContext *ctx)
+ static void get_hasModelChildren(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object")));
const QQmlAdaptorModel *const model = static_cast<QQmlDMCachedModelData *>(o->d()->item)->type->model;
if (o->d()->item->index >= 0 && *model) {
const QAbstractItemModel * const aim = model->aim();
- return QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex)));
+ RETURN_RESULT(QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex))));
} else {
- return QV4::Encode(false);
+ RETURN_RESULT(QV4::Encode(false));
}
}
@@ -583,27 +581,25 @@ public:
}
}
- static QV4::ReturnedValue get_modelData(QV4::CallContext *ctx)
+ static void get_modelData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object")));
- return scope.engine->fromVariant(static_cast<QQmlDMListAccessorData *>(o->d()->item)->cachedData);
+ RETURN_RESULT(scope.engine->fromVariant(static_cast<QQmlDMListAccessorData *>(o->d()->item)->cachedData));
}
- static QV4::ReturnedValue set_modelData(QV4::CallContext *ctx)
+ static void set_modelData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
- return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
- if (!ctx->argc())
- return ctx->engine()->throwTypeError();
+ RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object")));
+ if (!callData->argc)
+ RETURN_RESULT(scope.engine->throwTypeError());
- static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(scope.engine->toVariant(ctx->args()[0], QVariant::Invalid));
- return QV4::Encode::undefined();
+ static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(scope.engine->toVariant(callData->args[0], QVariant::Invalid));
+ RETURN_RESULT(QV4::Encode::undefined());
}
QV4::ReturnedValue get() override