aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-02-01 20:43:29 +0100
committerOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-02-01 20:43:30 +0100
commit6ba26317d0fc0573aca7638eda8bdb91e52d1ab3 (patch)
tree061ddc3d0977fc6364eb3275a3da4287fd1a7869 /src/qml
parentcd39a62bbd5c6e725547a696c297c46f929b3439 (diff)
parent835f8a90387c8d62e7ab262d23e3ab103aa6d133 (diff)
Merge dev into 5.9
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/compiler.pri8
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp152
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h15
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp8
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h4
-rw-r--r--src/qml/compiler/qv4codegen.cpp31
-rw-r--r--src/qml/compiler/qv4compileddata.cpp236
-rw-r--r--src/qml/compiler/qv4compileddata_p.h87
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h3
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp70
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h6
-rw-r--r--src/qml/compiler/qv4jsir_p.h62
-rw-r--r--src/qml/compiler/qv4ssa.cpp14
-rw-r--r--src/qml/compiler/qv4ssa_p.h35
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h2
-rw-r--r--src/qml/doc/src/qmltypereference.qdoc4
-rw-r--r--src/qml/jit/qv4assembler.cpp213
-rw-r--r--src/qml/jit/qv4assembler_p.h890
-rw-r--r--src/qml/jit/qv4binop.cpp116
-rw-r--r--src/qml/jit/qv4binop_p.h67
-rw-r--r--src/qml/jit/qv4isel_masm.cpp1195
-rw-r--r--src/qml/jit/qv4isel_masm_p.h73
-rw-r--r--src/qml/jit/qv4regalloc.cpp16
-rw-r--r--src/qml/jit/qv4targetplatform_p.h269
-rw-r--r--src/qml/jit/qv4unop.cpp55
-rw-r--r--src/qml/jit/qv4unop_p.h12
-rw-r--r--src/qml/jsruntime/jsruntime.pri4
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp10
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp69
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h8
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp10
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp675
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h48
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp26
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4context.cpp34
-rw-r--r--src/qml/jsruntime/qv4context_p.h24
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp133
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h18
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp475
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h102
-rw-r--r--src/qml/jsruntime/qv4engine.cpp10
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp25
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp134
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h32
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp146
-rw-r--r--src/qml/jsruntime/qv4globalobject_p.h20
-rw-r--r--src/qml/jsruntime/qv4include.cpp19
-rw-r--r--src/qml/jsruntime/qv4include_p.h2
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp32
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h2
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp23
-rw-r--r--src/qml/jsruntime/qv4jsonobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h3
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp186
-rw-r--r--src/qml/jsruntime/qv4mathobject_p.h38
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp7
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp160
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h16
-rw-r--r--src/qml/jsruntime/qv4object.cpp96
-rw-r--r--src/qml/jsruntime/qv4object_p.h21
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp412
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h52
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp65
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h4
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp94
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h18
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp34
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h32
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp64
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h6
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp395
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h46
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp101
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h12
-rw-r--r--src/qml/jsruntime/qv4value_p.h47
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp47
-rw-r--r--src/qml/jsruntime/qv4variantobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp4
-rw-r--r--src/qml/memory/memory.pri4
-rw-r--r--src/qml/memory/qv4heap_p.h43
-rw-r--r--src/qml/memory/qv4mm.cpp929
-rw-r--r--src/qml/memory/qv4mm_p.h196
-rw-r--r--src/qml/memory/qv4mmdefs_p.h262
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp2
-rw-r--r--src/qml/qml/qqmlcomponent.cpp59
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp10
-rw-r--r--src/qml/qml/qqmldelayedcallqueue_p.h2
-rw-r--r--src/qml/qml/qqmlimport.cpp276
-rw-r--r--src/qml/qml/qqmlimport_p.h42
-rw-r--r--src/qml/qml/qqmllocale.cpp485
-rw-r--r--src/qml/qml/qqmllocale_p.h82
-rw-r--r--src/qml/qml/qqmlmetatype.cpp2
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp4
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp5
-rw-r--r--src/qml/qml/qqmltypeloader.cpp104
-rw-r--r--src/qml/qml/qqmltypeloader_p.h69
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp57
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h8
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp12
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h2
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp9
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp496
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp865
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h118
-rw-r--r--src/qml/qml/v8/qv4domerrors_p.h5
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp79
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h6
-rw-r--r--src/qml/types/qquickworkerscript.cpp13
111 files changed, 6826 insertions, 5125 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 1de5dfa6fa..fa66d3a6e3 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -39,7 +39,10 @@ SOURCES += \
unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-qtConfig(qml-interpreter) {
+qtConfig(private_tests): LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
+}
+
+qmldevtools_build|qtConfig(qml-interpreter) {
HEADERS += \
$$PWD/qv4instr_moth_p.h \
$$PWD/qv4isel_moth_p.h
@@ -48,6 +51,3 @@ qtConfig(qml-interpreter) {
$$PWD/qv4isel_moth.cpp
}
-
-qtConfig(private_tests): LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
-}
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 54d0cb4f46..8a7507c92e 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -2061,4 +2061,156 @@ QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevis
return 0;
}
+IRLoader::IRLoader(const QV4::CompiledData::Unit *qmlData, QmlIR::Document *output)
+ : unit(qmlData)
+ , output(output)
+{
+ pool = output->jsParserEngine.pool();
+}
+
+void IRLoader::load()
+{
+ output->jsGenerator.stringTable.clear();
+ for (uint i = 0; i < unit->stringTableSize; ++i)
+ output->jsGenerator.stringTable.registerString(unit->stringAt(i));
+
+ for (quint32 i = 0; i < unit->nImports; ++i)
+ output->imports << unit->importAt(i);
+
+ if (unit->flags & QV4::CompiledData::Unit::IsSingleton) {
+ QmlIR::Pragma *p = New<QmlIR::Pragma>();
+ p->location = QV4::CompiledData::Location();
+ p->type = QmlIR::Pragma::PragmaSingleton;
+ output->pragmas << p;
+ }
+
+ output->indexOfRootObject = unit->indexOfRootObject;
+
+ for (uint i = 0; i < unit->nObjects; ++i) {
+ const QV4::CompiledData::Object *serializedObject = unit->objectAt(i);
+ QmlIR::Object *object = loadObject(serializedObject);
+ output->objects.append(object);
+ }
+}
+
+struct FakeExpression : public QQmlJS::AST::NullExpression
+{
+ FakeExpression(int start, int length)
+ : location(start, length)
+ {}
+
+ virtual QQmlJS::AST::SourceLocation firstSourceLocation() const
+ { return location; }
+
+ virtual QQmlJS::AST::SourceLocation lastSourceLocation() const
+ { return location; }
+
+private:
+ QQmlJS::AST::SourceLocation location;
+};
+
+QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedObject)
+{
+ QmlIR::Object *object = pool->New<QmlIR::Object>();
+ object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex);
+
+ object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
+ object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
+
+ object->location = serializedObject->location;
+ object->locationOfIdProperty = serializedObject->locationOfIdProperty;
+
+ QVector<int> functionIndices;
+ functionIndices.reserve(serializedObject->nFunctions + serializedObject->nBindings / 2);
+
+ for (uint i = 0; i < serializedObject->nBindings; ++i) {
+ QmlIR::Binding *b = pool->New<QmlIR::Binding>();
+ *static_cast<QV4::CompiledData::Binding*>(b) = serializedObject->bindingTable()[i];
+ object->bindings->append(b);
+ if (b->type == QV4::CompiledData::Binding::Type_Script) {
+ functionIndices.append(b->value.compiledScriptIndex);
+ b->value.compiledScriptIndex = functionIndices.count() - 1;
+
+ QmlIR::CompiledFunctionOrExpression *foe = pool->New<QmlIR::CompiledFunctionOrExpression>();
+ foe->disableAcceleratedLookups = true;
+ foe->nameIndex = 0;
+
+ QQmlJS::AST::ExpressionNode *expr;
+
+ if (b->stringIndex != quint32(0)) {
+ const int start = output->code.length();
+ const QString script = output->stringAt(b->stringIndex);
+ const int length = script.length();
+ output->code.append(script);
+ expr = new (pool) FakeExpression(start, length);
+ } else
+ expr = new (pool) QQmlJS::AST::NullExpression();
+ foe->node = new (pool) QQmlJS::AST::ExpressionStatement(expr); // dummy
+ object->functionsAndExpressions->append(foe);
+ }
+ }
+
+ Q_ASSERT(object->functionsAndExpressions->count == functionIndices.count());
+
+ for (uint i = 0; i < serializedObject->nSignals; ++i) {
+ const QV4::CompiledData::Signal *serializedSignal = serializedObject->signalAt(i);
+ QmlIR::Signal *s = pool->New<QmlIR::Signal>();
+ s->nameIndex = serializedSignal->nameIndex;
+ s->location = serializedSignal->location;
+ s->parameters = pool->New<QmlIR::PoolList<QmlIR::SignalParameter> >();
+
+ for (uint i = 0; i < serializedSignal->nParameters; ++i) {
+ QmlIR::SignalParameter *p = pool->New<QmlIR::SignalParameter>();
+ *static_cast<QV4::CompiledData::Parameter*>(p) = *serializedSignal->parameterAt(i);
+ s->parameters->append(p);
+ }
+
+ object->qmlSignals->append(s);
+ }
+
+ const QV4::CompiledData::Property *serializedProperty = serializedObject->propertyTable();
+ for (uint i = 0; i < serializedObject->nProperties; ++i, ++serializedProperty) {
+ QmlIR::Property *p = pool->New<QmlIR::Property>();
+ *static_cast<QV4::CompiledData::Property*>(p) = *serializedProperty;
+ object->properties->append(p);
+ }
+
+ QQmlJS::Engine *jsParserEngine = &output->jsParserEngine;
+
+ const QV4::CompiledData::LEUInt32 *functionIdx = serializedObject->functionOffsetTable();
+ for (uint i = 0; i < serializedObject->nFunctions; ++i, ++functionIdx) {
+ QmlIR::Function *f = pool->New<QmlIR::Function>();
+ const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx);
+
+ functionIndices.append(*functionIdx);
+ f->index = functionIndices.count() - 1;
+ f->location = compiledFunction->location;
+ f->nameIndex = compiledFunction->nameIndex;
+
+ QQmlJS::AST::FormalParameterList *paramList = 0;
+ const QV4::CompiledData::LEUInt32 *formalNameIdx = compiledFunction->formalsTable();
+ for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx) {
+ const QString formal = unit->stringAt(*formalNameIdx);
+ QStringRef paramNameRef = jsParserEngine->newStringRef(formal);
+
+ if (paramList)
+ paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, paramNameRef);
+ else
+ paramList = new (pool) QQmlJS::AST::FormalParameterList(paramNameRef);
+ }
+
+ if (paramList)
+ paramList = paramList->finish();
+
+ const QString name = unit->stringAt(compiledFunction->nameIndex);
+ f->functionDeclaration = new(pool) QQmlJS::AST::FunctionDeclaration(jsParserEngine->newStringRef(name), paramList, /*body*/0);
+
+ object->functions->append(f);
+ }
+
+ object->runtimeFunctionIndices.allocate(pool, functionIndices);
+
+ return object;
+}
+
#endif // V4_BOOTSTRAP
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 95756845c3..2022112e07 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -622,6 +622,21 @@ private:
int _importedScriptsTemp;
};
+struct IRLoader {
+ IRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output);
+
+ void load();
+
+private:
+ QmlIR::Object *loadObject(const QV4::CompiledData::Object *serializedObject);
+
+ template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
+
+ const QV4::CompiledData::Unit *unit;
+ QmlIR::Document *output;
+ QQmlJS::MemoryPool *pool;
+};
+
} // namespace QmlIR
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index ab2b0553a9..85267225be 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -57,12 +57,12 @@
QT_BEGIN_NAMESPACE
QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData,
- QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
: resolvedTypes(resolvedTypeCache)
, engine(engine)
, typeData(typeData)
- , importCache(importCache)
+ , typeNameCache(typeNameCache)
, document(parsedQML)
{
}
@@ -138,7 +138,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
sss.scan();
}
- QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, importCache, &document->jsGenerator.stringTable);
+ QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, typeNameCache, &document->jsGenerator.stringTable);
QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
if (!jsCodeGen.generateCodeForComponents())
return nullptr;
@@ -164,7 +164,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
QV4::CompiledData::CompilationUnit *compilationUnit = document->javaScriptCompilationUnit;
compilationUnit = document->javaScriptCompilationUnit;
- compilationUnit->importCache = importCache;
+ compilationUnit->typeNameCache = typeNameCache;
compilationUnit->resolvedTypes = resolvedTypes;
compilationUnit->propertyCaches = std::move(m_propertyCaches);
Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->data->nObjects));
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index de6abb4ced..2b59e7e42f 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -89,7 +89,7 @@ struct QQmlTypeCompiler
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler)
public:
- QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
+ QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
// --- interface used by QQmlPropertyCacheCreator
typedef QmlIR::Object CompiledObject;
@@ -139,7 +139,7 @@ private:
QList<QQmlError> errors;
QQmlEnginePrivate *engine;
QQmlTypeData *typeData;
- QQmlRefPointer<QQmlTypeNameCache> importCache;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QmlIR::Document *document;
// index is string index of type name (use obj->inheritedTypeNameIndex)
QHash<int, QQmlCustomParser*> customParsers;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index e0def1021b..7d3ad38f97 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -526,21 +526,21 @@ IR::Expr *Codegen::subscript(IR::Expr *base, IR::Expr *index)
if (hasError)
return 0;
- if (! base->asTemp() || base->asArgLocal()) {
+ if (! base->asTemp() && !base->asArgLocal()) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), base);
base = _block->TEMP(t);
}
- if (! index->asTemp() || index->asArgLocal()) {
+ if (! index->asTemp() && !index->asArgLocal() && !index->asConst()) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), index);
index = _block->TEMP(t);
}
Q_ASSERT(base->asTemp() || base->asArgLocal());
- Q_ASSERT(index->asTemp() || index->asArgLocal());
- return _block->SUBSCRIPT(base->asTemp(), index->asTemp());
+ Q_ASSERT(index->asTemp() || index->asArgLocal() || index->asConst());
+ return _block->SUBSCRIPT(base, index);
}
IR::Expr *Codegen::argument(IR::Expr *expr)
@@ -611,7 +611,7 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right, const AS
if (IR::Const *c1 = left->asConst()) {
if (IR::Const *c2 = right->asConst()) {
- if (c1->type == IR::NumberType && c2->type == IR::NumberType) {
+ if ((c1->type & IR::NumberType) && (c2->type & IR::NumberType)) {
switch (op) {
case IR::OpAdd: return _block->CONST(IR::NumberType, c1->value + c2->value);
case IR::OpAnd: return _block->CONST(IR::BoolType, c1->value ? c2->value : 0);
@@ -659,20 +659,20 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right, const AS
}
}
- if (!left->asTemp() && !left->asArgLocal()) {
+ if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) {
const unsigned t = _block->newTemp();
setLocation(move(_block->TEMP(t), left), loc);
left = _block->TEMP(t);
}
- if (!right->asTemp() && !right->asArgLocal()) {
+ if (!right->asTemp() && !right->asArgLocal() && !right->asConst()) {
const unsigned t = _block->newTemp();
setLocation(move(_block->TEMP(t), right), loc);
right = _block->TEMP(t);
}
- Q_ASSERT(left->asTemp() || left->asArgLocal());
- Q_ASSERT(right->asTemp() || right->asArgLocal());
+ Q_ASSERT(left->asTemp() || left->asArgLocal() || left->asConst());
+ Q_ASSERT(right->asTemp() || right->asArgLocal() || right->asConst());
return _block->BINOP(op, left, right);
}
@@ -842,9 +842,16 @@ void Codegen::variableDeclaration(VariableDeclaration *ast)
Q_ASSERT(expr.code);
initializer = *expr;
- int initialized = _block->newTemp();
- move(_block->TEMP(initialized), initializer);
- move(identifier(ast->name.toString(), ast->identifierToken.startLine, ast->identifierToken.startColumn), _block->TEMP(initialized));
+ IR::Expr *lhs = identifier(ast->name.toString(), ast->identifierToken.startLine,
+ ast->identifierToken.startColumn);
+
+ if (lhs->asArgLocal()) {
+ move(lhs, initializer);
+ } else {
+ int initialized = _block->newTemp();
+ move(_block->TEMP(initialized), initializer);
+ move(lhs, _block->TEMP(initialized));
+ }
}
void Codegen::variableDeclarationList(VariableDeclarationList *ast)
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 6aac111897..8f8d374e24 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -52,7 +52,6 @@
#include "qv4compilationunitmapper_p.h"
#include <QQmlPropertyMap>
#include <QDateTime>
-#include <QSaveFile>
#include <QFile>
#include <QFileInfo>
#include <QScopedValueRollback>
@@ -62,6 +61,7 @@
#include <private/qqmlirbuilder_p.h>
#include <QCoreApplication>
#include <QCryptographicHash>
+#include <QSaveFile>
#include <algorithm>
@@ -77,6 +77,27 @@ namespace QV4 {
namespace CompiledData {
+#ifdef V4_BOOTSTRAP
+static QString cacheFilePath(const QString &localSourcePath)
+{
+ const QString localCachePath = localSourcePath + QLatin1Char('c');
+ return localCachePath;
+}
+#else
+static QString cacheFilePath(const QUrl &url)
+{
+ const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
+ const QString localCachePath = localSourcePath + QLatin1Char('c');
+ if (QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
+ return localCachePath;
+ QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
+ fileNameHash.addData(localSourcePath.toUtf8());
+ QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
+ QDir::root().mkpath(directory);
+ return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + QFileInfo(localCachePath).completeSuffix();
+}
+#endif
+
#ifndef V4_BOOTSTRAP
CompilationUnit::CompilationUnit()
: data(0)
@@ -207,7 +228,7 @@ void CompilationUnit::unlink()
dependentScripts.at(ii)->release();
dependentScripts.clear();
- importCache = nullptr;
+ typeNameCache = nullptr;
qDeleteAll(resolvedTypes);
resolvedTypes.clear();
@@ -329,20 +350,68 @@ bool CompilationUnit::verifyChecksum(QQmlEngine *engine,
sizeof(data->dependencyMD5Checksum)) == 0;
}
-static QString cacheFilePath(const QUrl &url)
+bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString)
{
- const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- const QString localCachePath = localSourcePath + QLatin1Char('c');
- if (QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
- return localCachePath;
- QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
- fileNameHash.addData(localSourcePath.toUtf8());
- QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
- QDir::root().mkpath(directory);
- return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + QFileInfo(localCachePath).completeSuffix();
+ if (!QQmlFile::isLocalFile(url)) {
+ *errorString = QStringLiteral("File has to be a local file.");
+ return false;
+ }
+
+ const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
+ QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
+
+ CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString);
+ if (!mappedUnit)
+ return false;
+
+ const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
+ QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit);
+
+ if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
+ *errorString = QStringLiteral("QML source file has moved to a different location.");
+ return false;
+ }
+
+ {
+ const QString foundArchitecture = stringAt(data->architectureIndex);
+ const QString expectedArchitecture = QSysInfo::buildAbi();
+ if (foundArchitecture != expectedArchitecture) {
+ *errorString = QString::fromUtf8("Architecture mismatch. Found %1 expected %2").arg(foundArchitecture).arg(expectedArchitecture);
+ return false;
+ }
+ }
+
+ {
+ const QString foundCodeGenerator = stringAt(data->codeGeneratorIndex);
+ const QString expectedCodeGenerator = iselFactory->codeGeneratorName;
+ if (foundCodeGenerator != expectedCodeGenerator) {
+ *errorString = QString::fromUtf8("Code generator mismatch. Found code generated by %1 but expected %2").arg(foundCodeGenerator).arg(expectedCodeGenerator);
+ return false;
+ }
+ }
+
+ if (!memoryMapCode(errorString))
+ return false;
+
+ dataPtrChange.commit();
+ free(const_cast<Unit*>(oldDataPtr));
+ backingFile.reset(cacheFile.take());
+ return true;
+}
+
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ *errorString = QStringLiteral("Missing code mapping backend");
+ return false;
}
+#endif // V4_BOOTSTRAP
+
+#if defined(V4_BOOTSTRAP)
+bool CompilationUnit::saveToDisk(const QString &unitUrl, QString *errorString)
+#else
bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
+#endif
{
errorString->clear();
@@ -351,10 +420,12 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
return false;
}
+#if !defined(V4_BOOTSTRAP)
if (!QQmlFile::isLocalFile(unitUrl)) {
*errorString = QStringLiteral("File has to be a local file.");
return false;
}
+#endif
// Foo.qml -> Foo.qmlc
QSaveFile cacheFile(cacheFilePath(unitUrl));
@@ -390,78 +461,105 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
return true;
}
-bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString)
+void CompilationUnit::prepareCodeOffsetsForDiskStorage(Unit *unit)
{
- if (!QQmlFile::isLocalFile(url)) {
- *errorString = QStringLiteral("File has to be a local file.");
- return false;
- }
+ Q_UNUSED(unit);
+}
- const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
+bool CompilationUnit::saveCodeToDisk(QIODevice *device, const Unit *unit, QString *errorString)
+{
+ Q_UNUSED(device);
+ Q_UNUSED(unit);
+ *errorString = QStringLiteral("Saving code to disk is not supported in this configuration");
+ return false;
+}
- CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString);
- if (!mappedUnit)
- return false;
+Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
+{
+ if (!irDocument->javaScriptCompilationUnit->data)
+ return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable);
- const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
- QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit);
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = irDocument->javaScriptCompilationUnit;
+ QV4::CompiledData::Unit *jsUnit = const_cast<QV4::CompiledData::Unit*>(irDocument->javaScriptCompilationUnit->data);
- if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
- *errorString = QStringLiteral("QML source file has moved to a different location.");
- return false;
- }
+ QV4::Compiler::StringTableGenerator &stringTable = irDocument->jsGenerator.stringTable;
- {
- const QString foundArchitecture = stringAt(data->architectureIndex);
- const QString expectedArchitecture = QSysInfo::buildAbi();
- if (foundArchitecture != expectedArchitecture) {
- *errorString = QString::fromUtf8("Architecture mismatch. Found %1 expected %2").arg(foundArchitecture).arg(expectedArchitecture);
- return false;
+ // Collect signals that have had a change in signature (from onClicked to onClicked(mouse) for example)
+ // and now need fixing in the QV4::CompiledData. Also register strings at the same time, to finalize
+ // the string table.
+ QVector<quint32> changedSignals;
+ QVector<QQmlJS::AST::FormalParameterList*> changedSignalParameters;
+ for (QmlIR::Object *o: qAsConst(irDocument->objects)) {
+ for (QmlIR::Binding *binding = o->firstBinding(); binding; binding = binding->next) {
+ if (!(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression))
+ continue;
+
+ quint32 functionIndex = binding->value.compiledScriptIndex;
+ QmlIR::CompiledFunctionOrExpression *foe = o->functionsAndExpressions->slowAt(functionIndex);
+ if (!foe)
+ continue;
+
+ // save absolute index
+ changedSignals << o->runtimeFunctionIndices.at(functionIndex);
+
+ Q_ASSERT(foe->node);
+ Q_ASSERT(QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(foe->node));
+
+ QQmlJS::AST::FormalParameterList *parameters = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(foe->node)->formals;
+ changedSignalParameters << parameters;
+
+ for (; parameters; parameters = parameters->next)
+ stringTable.registerString(parameters->name.toString());
}
}
- {
- const QString foundCodeGenerator = stringAt(data->codeGeneratorIndex);
- const QString expectedCodeGenerator = iselFactory->codeGeneratorName;
- if (foundCodeGenerator != expectedCodeGenerator) {
- *errorString = QString::fromUtf8("Code generator mismatch. Found code generated by %1 but expected %2").arg(foundCodeGenerator).arg(expectedCodeGenerator);
- return false;
+ QVector<quint32> signalParameterNameTable;
+ quint32 signalParameterNameTableOffset = jsUnit->unitSize;
+
+ // Update signal signatures
+ if (!changedSignals.isEmpty()) {
+ if (jsUnit == compilationUnit->data) {
+ char *unitCopy = (char*)malloc(jsUnit->unitSize);
+ memcpy(unitCopy, jsUnit, jsUnit->unitSize);
+ jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitCopy);
}
- }
- if (!memoryMapCode(errorString))
- return false;
+ for (int i = 0; i < changedSignals.count(); ++i) {
+ const uint functionIndex = changedSignals.at(i);
+ // The data is now read-write due to the copy above, so the const_cast is ok.
+ QV4::CompiledData::Function *function = const_cast<QV4::CompiledData::Function *>(jsUnit->functionAt(functionIndex));
+ Q_ASSERT(function->nFormals == quint32(0));
- dataPtrChange.commit();
- free(const_cast<Unit*>(oldDataPtr));
- backingFile.reset(cacheFile.take());
- return true;
-}
+ function->formalsOffset = signalParameterNameTableOffset - jsUnit->functionOffsetTable()[functionIndex];
-void CompilationUnit::prepareCodeOffsetsForDiskStorage(Unit *unit)
-{
- Q_UNUSED(unit);
-}
+ for (QQmlJS::AST::FormalParameterList *parameters = changedSignalParameters.at(i);
+ parameters; parameters = parameters->next) {
+ signalParameterNameTable.append(stringTable.getStringId(parameters->name.toString()));
+ function->nFormals = function->nFormals + 1;
+ }
-bool CompilationUnit::saveCodeToDisk(QIODevice *device, const Unit *unit, QString *errorString)
-{
- Q_UNUSED(device);
- Q_UNUSED(unit);
- *errorString = QStringLiteral("Saving code to disk is not supported in this configuration");
- return false;
-}
+ // Hack to ensure an activation is created.
+ function->flags |= QV4::CompiledData::Function::HasCatchOrWith | QV4::CompiledData::Function::HasDirectEval;
-bool CompilationUnit::memoryMapCode(QString *errorString)
-{
- *errorString = QStringLiteral("Missing code mapping backend");
- return false;
-}
-#endif // V4_BOOTSTRAP
+ signalParameterNameTableOffset += function->nFormals * sizeof(quint32);
+ }
+ }
-Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
-{
- return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable);
+ if (!signalParameterNameTable.isEmpty()) {
+ Q_ASSERT(jsUnit != compilationUnit->data);
+ const uint signalParameterTableSize = signalParameterNameTable.count() * sizeof(quint32);
+ uint newSize = jsUnit->unitSize + signalParameterTableSize;
+ const uint oldSize = jsUnit->unitSize;
+ char *unitWithSignalParameters = (char*)realloc(jsUnit, newSize);
+ memcpy(unitWithSignalParameters + oldSize, signalParameterNameTable.constData(), signalParameterTableSize);
+ jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitWithSignalParameters);
+ jsUnit->unitSize = newSize;
+ }
+
+ if (jsUnit != compilationUnit->data)
+ jsUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
+
+ return jsUnit;
}
QString Binding::valueAsString(const Unit *unit) const
@@ -624,7 +722,7 @@ static QByteArray ownLibraryChecksum()
if (checksumInitialized)
return libraryChecksum;
checksumInitialized = true;
-#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST)
+#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST) && !defined(Q_OS_INTEGRITY)
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/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 2682365182..13a0c4b075 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -71,7 +71,7 @@
QT_BEGIN_NAMESPACE
// Bump this whenever the compiler data structures change in an incompatible way.
-#define QV4_DATA_STRUCTURE_VERSION 0x08
+#define QV4_DATA_STRUCTURE_VERSION 0x09
class QIODevice;
class QQmlPropertyCache;
@@ -133,7 +133,7 @@ struct Location
QJsonPrivate::qle_bitfield<20, 12> column;
};
- Location() { line = 0; column = 0; }
+ Location() { line.val = 0; column.val = 0; }
inline bool operator<(const Location &other) const {
return line < other.line ||
@@ -153,7 +153,7 @@ struct RegExp
QJsonPrivate::qle_bitfield<4, 28> stringIndex;
};
- RegExp() { flags = 0; stringIndex = 0; }
+ RegExp() { flags.val = 0; stringIndex.val = 0; }
};
struct Lookup
@@ -171,7 +171,7 @@ struct Lookup
QJsonPrivate::qle_bitfield<4, 28> nameIndex;
};
- Lookup() { type_and_flags = 0; nameIndex = 0; }
+ Lookup() { type_and_flags.val = 0; nameIndex.val = 0; }
};
struct JSClassMember
@@ -625,7 +625,8 @@ struct Unit
StaticData = 0x4, // Unit data persistent in memory?
IsSingleton = 0x8,
IsSharedLibrary = 0x10, // .pragma shared?
- ContainsMachineCode = 0x20 // used to determine if we need to mmap with execute permissions
+ ContainsMachineCode = 0x20, // used to determine if we need to mmap with execute permissions
+ PendingTypeCompilation = 0x40 // the QML data structures present are incomplete and require type compilation
};
LEUInt32 flags;
LEUInt32 stringTableSize;
@@ -777,31 +778,7 @@ struct TypeReferenceMap : QHash<int, TypeReference>
};
#ifndef V4_BOOTSTRAP
-struct ResolvedTypeReference
-{
- ResolvedTypeReference()
- : type(0)
- , majorVersion(0)
- , minorVersion(0)
- , isFullyDynamicType(false)
- {}
-
- QQmlType *type;
- QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
-
- int majorVersion;
- int minorVersion;
- // Types such as QQmlPropertyMap can add properties dynamically at run-time and
- // therefore cannot have a property cache installed when instantiated.
- bool isFullyDynamicType;
-
- QQmlPropertyCache *propertyCache() const;
- QQmlPropertyCache *createPropertyCache(QQmlEngine *);
- bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
-
- void doDynamicTypeCheck();
-};
+struct ResolvedTypeReference;
// map from name index
// While this could be a hash, a map is chosen here to provide a stable
// order, which is used to calculating a check-sum on dependent meta-objects.
@@ -841,10 +818,14 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
#ifndef V4_BOOTSTRAP
ExecutionEngine *engine;
+#endif
+
+ QV4::Heap::String **runtimeStrings; // Array
+
+#ifndef V4_BOOTSTRAP
QString fileName() const { return data->stringAt(data->sourceFileIndex); }
QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
- QV4::Heap::String **runtimeStrings; // Array
QV4::Lookup *runtimeLookups;
QV4::Value *runtimeRegularExpressions;
QV4::InternalClass **runtimeClasses;
@@ -855,7 +836,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
QQmlPropertyCacheVector propertyCaches;
QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(data->indexOfRootObject); }
- QQmlRefPointer<QQmlTypeNameCache> importCache;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
// index is object index. This allows fast access to the
// property data when initializing bindings, avoiding expensive
@@ -918,17 +899,53 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
void destroy() Q_DECL_OVERRIDE;
- bool saveToDisk(const QUrl &unitUrl, QString *errorString);
bool loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString);
protected:
virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0;
- virtual void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit);
- virtual bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString);
virtual bool memoryMapCode(QString *errorString);
#endif // V4_BOOTSTRAP
+
+public:
+#if defined(V4_BOOTSTRAP)
+ bool saveToDisk(const QString &unitUrl, QString *errorString);
+#else
+ bool saveToDisk(const QUrl &unitUrl, QString *errorString);
+#endif
+
+protected:
+ virtual void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit);
+ virtual bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString);
};
+#ifndef V4_BOOTSTRAP
+struct ResolvedTypeReference
+{
+ ResolvedTypeReference()
+ : type(0)
+ , majorVersion(0)
+ , minorVersion(0)
+ , isFullyDynamicType(false)
+ {}
+
+ QQmlType *type;
+ QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+
+ int majorVersion;
+ int minorVersion;
+ // Types such as QQmlPropertyMap can add properties dynamically at run-time and
+ // therefore cannot have a property cache installed when instantiated.
+ bool isFullyDynamicType;
+
+ QQmlPropertyCache *propertyCache() const;
+ QQmlPropertyCache *createPropertyCache(QQmlEngine *);
+ bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
+
+ void doDynamicTypeCheck();
+};
+#endif
+
}
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index ca4e0b73d4..53d9956315 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -52,10 +52,11 @@
//
#include <private/qv4global_p.h>
#include <private/qv4value_p.h>
-#include <private/qv4function_p.h>
#include <private/qv4runtime_p.h>
+#if !defined(V4_BOOTSTRAP)
QT_REQUIRE_CONFIG(qml_interpreter);
+#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index 9dbebd1128..04844302d9 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -39,15 +39,15 @@
#include "qv4isel_util_p.h"
#include "qv4isel_moth_p.h"
-#include "qv4vme_moth_p.h"
#include "qv4ssa_p.h"
-#include <private/qv4debugging_p.h>
-#include <private/qv4function_p.h>
-#include <private/qv4regexpobject_p.h>
#include <private/qv4compileddata_p.h>
-#include <private/qqmlengine_p.h>
#include <wtf/MathExtras.h>
+#if !defined(V4_BOOTSTRAP)
+#include "qv4vme_moth_p.h"
+#include <private/qv4function_p.h>
+#endif
+
#undef USE_TYPE_INFO
using namespace QV4;
@@ -1185,8 +1185,11 @@ void InstructionSelection::callBuiltinPushWithScope(IR::Expr *arg)
void InstructionSelection::callBuiltinPopScope()
{
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_GCC("-Wuninitialized")
Instruction::CallBuiltinPopScope call;
addInstruction(call);
+ QT_WARNING_POP
}
void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &name)
@@ -1335,8 +1338,11 @@ void InstructionSelection::callBuiltinSetupArgumentObject(IR::Expr *result)
void QV4::Moth::InstructionSelection::callBuiltinConvertThisToObject()
{
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_GCC("-Wuninitialized")
Instruction::CallBuiltinConvertThisToObject call;
addInstruction(call);
+ QT_WARNING_POP
}
ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr)
@@ -1425,6 +1431,8 @@ CompilationUnit::~CompilationUnit()
{
}
+#if !defined(V4_BOOTSTRAP)
+
void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine)
{
#ifdef MOTH_THREADED_INTERPRETER
@@ -1461,6 +1469,31 @@ void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine)
}
}
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ Q_UNUSED(errorString);
+ codeRefs.resize(data->functionTableSize);
+
+ const char *basePtr = reinterpret_cast<const char *>(data);
+
+ for (uint i = 0; i < data->functionTableSize; ++i) {
+ const CompiledData::Function *compiledFunction = data->functionAt(i);
+ const char *codePtr = const_cast<const char *>(reinterpret_cast<const char *>(basePtr + compiledFunction->codeOffset));
+#ifdef MOTH_THREADED_INTERPRETER
+ // for the threaded interpreter we need to make a copy of the data because it needs to be
+ // modified for the instruction handler addresses.
+ QByteArray code(codePtr, compiledFunction->codeSize);
+#else
+ QByteArray code = QByteArray::fromRawData(codePtr, compiledFunction->codeSize);
+#endif
+ codeRefs[i] = code;
+ }
+
+ return true;
+}
+
+#endif // V4_BOOTSTRAP
+
void CompilationUnit::prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit)
{
const int codeAlignment = 16;
@@ -1482,7 +1515,7 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
QByteArray padding;
-#ifdef MOTH_THREADED_INTERPRETER
+#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;
@@ -1511,7 +1544,7 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
QByteArray code = codeRefs.at(i);
-#ifdef MOTH_THREADED_INTERPRETER
+#if defined(MOTH_THREADED_INTERPRETER) && !defined(V4_BOOTSTRAP)
if (!reverseInstructionMapping.isEmpty()) {
char *codePtr = code.data(); // detaches
int index = 0;
@@ -1541,29 +1574,6 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
return true;
}
-bool CompilationUnit::memoryMapCode(QString *errorString)
-{
- Q_UNUSED(errorString);
- codeRefs.resize(data->functionTableSize);
-
- const char *basePtr = reinterpret_cast<const char *>(data);
-
- for (uint i = 0; i < data->functionTableSize; ++i) {
- const CompiledData::Function *compiledFunction = data->functionAt(i);
- const char *codePtr = const_cast<const char *>(reinterpret_cast<const char *>(basePtr + compiledFunction->codeOffset));
-#ifdef MOTH_THREADED_INTERPRETER
- // for the threaded interpreter we need to make a copy of the data because it needs to be
- // modified for the instruction handler addresses.
- QByteArray code(codePtr, compiledFunction->codeSize);
-#else
- QByteArray code = QByteArray::fromRawData(codePtr, compiledFunction->codeSize);
-#endif
- codeRefs[i] = code;
- }
-
- return true;
-}
-
QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory::createUnitForLoading()
{
QQmlRefPointer<CompiledData::CompilationUnit> result;
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index afe5fe342e..41469f1985 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -59,7 +59,9 @@
#include <private/qv4value_p.h>
#include "qv4instr_moth_p.h"
+#if !defined(V4_BOOTSTRAP)
QT_REQUIRE_CONFIG(qml_interpreter);
+#endif
QT_BEGIN_NAMESPACE
@@ -69,10 +71,12 @@ namespace Moth {
struct CompilationUnit : public QV4::CompiledData::CompilationUnit
{
virtual ~CompilationUnit();
+#if !defined(V4_BOOTSTRAP)
void linkBackendToEngine(QV4::ExecutionEngine *engine) Q_DECL_OVERRIDE;
+ bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
+#endif
void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit) Q_DECL_OVERRIDE;
bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString) Q_DECL_OVERRIDE;
- bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
QVector<QByteArray> codeRefs;
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 73aa6c4975..04bc3d86e5 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -315,20 +315,20 @@ struct Q_AUTOTEST_EXPORT Expr {
Expr(ExprKind exprKind): type(UnknownType), exprKind(exprKind) {}
bool isLValue() const;
- Const *asConst() { return as<Const>(); }
- String *asString() { return as<String>(); }
- RegExp *asRegExp() { return as<RegExp>(); }
- Name *asName() { return as<Name>(); }
- Temp *asTemp() { return as<Temp>(); }
- ArgLocal *asArgLocal() { return as<ArgLocal>(); }
- Closure *asClosure() { return as<Closure>(); }
- Convert *asConvert() { return as<Convert>(); }
- Unop *asUnop() { return as<Unop>(); }
- Binop *asBinop() { return as<Binop>(); }
- Call *asCall() { return as<Call>(); }
- New *asNew() { return as<New>(); }
- Subscript *asSubscript() { return as<Subscript>(); }
- Member *asMember() { return as<Member>(); }
+ Const *asConst();
+ String *asString();
+ RegExp *asRegExp();
+ Name *asName();
+ Temp *asTemp();
+ ArgLocal *asArgLocal();
+ Closure *asClosure();
+ Convert *asConvert();
+ Unop *asUnop();
+ Binop *asBinop();
+ Call *asCall();
+ New *asNew();
+ Subscript *asSubscript();
+ Member *asMember();
};
#define EXPR_VISIT_ALL_KINDS(e) \
@@ -773,12 +773,12 @@ struct Stmt {
Stmt *asTerminator();
- Exp *asExp() { return as<Exp>(); }
- Move *asMove() { return as<Move>(); }
- Jump *asJump() { return as<Jump>(); }
- CJump *asCJump() { return as<CJump>(); }
- Ret *asRet() { return as<Ret>(); }
- Phi *asPhi() { return as<Phi>(); }
+ Exp *asExp();
+ Move *asMove();
+ Jump *asJump();
+ CJump *asCJump();
+ Ret *asRet();
+ Phi *asPhi();
int id() const { return _id; }
@@ -1720,6 +1720,28 @@ inline Stmt *BasicBlock::RET(Expr *expr)
return s;
}
+inline Const *Expr::asConst() { return as<Const>(); }
+inline String *Expr::asString() { return as<String>(); }
+inline RegExp *Expr::asRegExp() { return as<RegExp>(); }
+inline Name *Expr::asName() { return as<Name>(); }
+inline Temp *Expr::asTemp() { return as<Temp>(); }
+inline ArgLocal *Expr::asArgLocal() { return as<ArgLocal>(); }
+inline Closure *Expr::asClosure() { return as<Closure>(); }
+inline Convert *Expr::asConvert() { return as<Convert>(); }
+inline Unop *Expr::asUnop() { return as<Unop>(); }
+inline Binop *Expr::asBinop() { return as<Binop>(); }
+inline Call *Expr::asCall() { return as<Call>(); }
+inline New *Expr::asNew() { return as<New>(); }
+inline Subscript *Expr::asSubscript() { return as<Subscript>(); }
+inline Member *Expr::asMember() { return as<Member>(); }
+
+inline Exp *Stmt::asExp() { return as<Exp>(); }
+inline Move *Stmt::asMove() { return as<Move>(); }
+inline Jump *Stmt::asJump() { return as<Jump>(); }
+inline CJump *Stmt::asCJump() { return as<CJump>(); }
+inline Ret *Stmt::asRet() { return as<Ret>(); }
+inline Phi *Stmt::asPhi() { return as<Phi>(); }
+
} // end of namespace IR
} // end of namespace QV4
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 1d512711b8..10f0bbcf8f 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -5123,7 +5123,7 @@ void LifeTimeInterval::setFrom(int from) {
Q_ASSERT(from > 0);
if (_ranges.isEmpty()) { // this is the case where there is no use, only a define
- _ranges.prepend(Range(from, from));
+ _ranges.prepend(LifeTimeIntervalRange(from, from));
if (_end == InvalidPosition)
_end = from;
} else {
@@ -5137,17 +5137,17 @@ void LifeTimeInterval::addRange(int from, int to) {
Q_ASSERT(to >= from);
if (_ranges.isEmpty()) {
- _ranges.prepend(Range(from, to));
+ _ranges.prepend(LifeTimeIntervalRange(from, to));
_end = to;
return;
}
- Range *p = &_ranges.first();
+ LifeTimeIntervalRange *p = &_ranges.first();
if (to + 1 >= p->start && p->end + 1 >= from) {
p->start = qMin(p->start, from);
p->end = qMax(p->end, to);
while (_ranges.count() > 1) {
- Range *p1 = p + 1;
+ LifeTimeIntervalRange *p1 = p + 1;
if (p->end + 1 < p1->start || p1->end + 1 < p->start)
break;
p1->start = qMin(p->start, p1->start);
@@ -5157,10 +5157,10 @@ void LifeTimeInterval::addRange(int from, int to) {
}
} else {
if (to < p->start) {
- _ranges.prepend(Range(from, to));
+ _ranges.prepend(LifeTimeIntervalRange(from, to));
} else {
Q_ASSERT(from > _ranges.last().end);
- _ranges.push_back(Range(from, to));
+ _ranges.push_back(LifeTimeIntervalRange(from, to));
}
}
@@ -5206,7 +5206,7 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart)
} else {
// find the first range where the temp will get active again:
while (!newInterval._ranges.isEmpty()) {
- const Range &range = newInterval._ranges.first();
+ const LifeTimeIntervalRange &range = newInterval._ranges.first();
if (range.start > newStart) {
// The split position is before the start of the range. Either we managed to skip
// over the correct range, or we got an invalid split request. Either way, this
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index db8b6edd1a..c07abd04c4 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -63,20 +63,28 @@ class QQmlEnginePrivate;
namespace QV4 {
namespace IR {
-class Q_AUTOTEST_EXPORT LifeTimeInterval {
-public:
- struct Range {
- int start;
- int end;
+struct LifeTimeIntervalRange {
+ int start;
+ int end;
- Range(int start = InvalidPosition, int end = InvalidPosition)
- : start(start)
- , end(end)
- {}
+ LifeTimeIntervalRange(int start = -1, int end = -1)
+ : start(start)
+ , end(end)
+ {}
- bool covers(int position) const { return start <= position && position <= end; }
- };
- typedef QVarLengthArray<Range, 4> Ranges;
+ bool covers(int position) const { return start <= position && position <= end; }
+};
+} // IR namespace
+} // QV4 namespace
+
+Q_DECLARE_TYPEINFO(QV4::IR::LifeTimeIntervalRange, Q_PRIMITIVE_TYPE);
+
+namespace QV4 {
+namespace IR {
+
+class Q_AUTOTEST_EXPORT LifeTimeInterval {
+public:
+ typedef QVarLengthArray<LifeTimeIntervalRange, 4> Ranges;
private:
Temp _temp;
@@ -137,7 +145,7 @@ public:
// Validate the new range
if (_end != InvalidPosition) {
Q_ASSERT(!_ranges.isEmpty());
- for (const Range &range : qAsConst(_ranges)) {
+ for (const LifeTimeIntervalRange &range : qAsConst(_ranges)) {
Q_ASSERT(range.start >= 0);
Q_ASSERT(range.end >= 0);
Q_ASSERT(range.start <= range.end);
@@ -457,7 +465,6 @@ protected:
Q_DECLARE_TYPEINFO(QV4::IR::LifeTimeInterval, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(QV4::IR::LifeTimeInterval::Range, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index 3a507bef74..41fb2c5b7b 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -73,7 +73,7 @@ struct QQmlProfiler {};
struct QQmlBindingProfiler
{
- QQmlBindingProfiler(quintptr, QQmlBinding *, QV4::FunctionObject *) {}
+ QQmlBindingProfiler(quintptr, QV4::Function *) {}
};
struct QQmlHandlingSignalProfiler
diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc
index f32574fcc1..b2bb9ebd18 100644
--- a/src/qml/doc/src/qmltypereference.qdoc
+++ b/src/qml/doc/src/qmltypereference.qdoc
@@ -89,7 +89,7 @@ provided:
\ingroup qtquickbasictypes
\brief a date value.
-The \c date type refers to a date value.
+The \c date type refers to a date value, including the time of the day.
To create a \c date value, specify it as a "YYYY-MM-DD" string:
@@ -100,7 +100,7 @@ MyDatePicker { minDate: "2000-01-01"; maxDate: "2020-12-31" }
To read a date value returned from a C++ extension class, use
\l{QtQml::Qt::formatDate()}{Qt.formatDate()} and \l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}.
-When integrating with C++, note that any QDate value
+When integrating with C++, note that any QDate or QDateTime value
\l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
converted into a \c date value, and vice-versa.
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index 018396318e..646d9a8871 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -39,11 +39,6 @@
#include "qv4isel_masm_p.h"
#include "qv4runtime_p.h"
-#include "qv4object_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4regexpobject_p.h"
-#include "qv4lookup_p.h"
-#include "qv4function_p.h"
#include "qv4ssa_p.h"
#include "qv4regalloc_p.h"
#include "qv4assembler_p.h"
@@ -51,6 +46,10 @@
#include <assembler/LinkBuffer.h>
#include <WTFStubs.h>
+#if !defined(V4_BOOTSTRAP)
+#include "qv4function_p.h"
+#endif
+
#include <iostream>
#include <QBuffer>
#include <QCoreApplication>
@@ -68,6 +67,8 @@ CompilationUnit::~CompilationUnit()
{
}
+#if !defined(V4_BOOTSTRAP)
+
void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
{
runtimeFunctions.resize(data->functionTableSize);
@@ -81,6 +82,26 @@ void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
}
}
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ Q_UNUSED(errorString);
+ codeRefs.resize(data->functionTableSize);
+
+ const char *basePtr = reinterpret_cast<const char *>(data);
+
+ for (uint i = 0; i < data->functionTableSize; ++i) {
+ const CompiledData::Function *compiledFunction = data->functionAt(i);
+ void *codePtr = const_cast<void *>(reinterpret_cast<const void *>(basePtr + compiledFunction->codeOffset));
+ JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
+ JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
+ codeRefs[i] = codeRef;
+ }
+
+ return true;
+}
+
+#endif // !defined(V4_BOOTSTRAP)
+
void CompilationUnit::prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit)
{
const int codeAlignment = 16;
@@ -128,27 +149,11 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
return true;
}
-bool CompilationUnit::memoryMapCode(QString *errorString)
-{
- Q_UNUSED(errorString);
- codeRefs.resize(data->functionTableSize);
-
- const char *basePtr = reinterpret_cast<const char *>(data);
-
- for (uint i = 0; i < data->functionTableSize; ++i) {
- const CompiledData::Function *compiledFunction = data->functionAt(i);
- void *codePtr = const_cast<void *>(reinterpret_cast<const void *>(basePtr + compiledFunction->codeOffset));
- JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
- JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
- codeRefs[i] = codeRef;
- }
-
- return true;
-}
-
-const Assembler::VoidType Assembler::Void;
+template <typename TargetConfiguration>
+const typename Assembler<TargetConfiguration>::VoidType Assembler<TargetConfiguration>::Void;
-Assembler::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
+template <typename TargetConfiguration>
+Assembler<TargetConfiguration>::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
: _function(function)
, _nextBlock(0)
, _executableAllocator(executableAllocator)
@@ -159,14 +164,16 @@ Assembler::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function*
_labelPatches.resize(_function->basicBlockCount());
}
-void Assembler::registerBlock(IR::BasicBlock* block, IR::BasicBlock *nextBlock)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::registerBlock(IR::BasicBlock* block, IR::BasicBlock *nextBlock)
{
_addrs[block->index()] = label();
catchBlock = block->catchBlock;
_nextBlock = nextBlock;
}
-void Assembler::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target)
{
Q_UNUSED(current);
@@ -174,12 +181,14 @@ void Assembler::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target)
_patches[target->index()].push_back(jump());
}
-void Assembler::addPatch(IR::BasicBlock* targetBlock, Jump targetJump)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::addPatch(IR::BasicBlock* targetBlock, Jump targetJump)
{
_patches[targetBlock->index()].push_back(targetJump);
}
-void Assembler::addPatch(DataLabelPtr patch, Label target)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::addPatch(DataLabelPtr patch, Label target)
{
DataLabelPatch p;
p.dataLabel = patch;
@@ -187,37 +196,21 @@ void Assembler::addPatch(DataLabelPtr patch, Label target)
_dataLabelPatches.push_back(p);
}
-void Assembler::addPatch(DataLabelPtr patch, IR::BasicBlock *target)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::addPatch(DataLabelPtr patch, IR::BasicBlock *target)
{
_labelPatches[target->index()].push_back(patch);
}
-void Assembler::generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
{
- generateCJumpOnCompare(NotEqual, reg, TrustedImm32(0), currentBlock, trueBlock, falseBlock);
-}
-
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
-void Assembler::generateCJumpOnCompare(RelationalCondition cond,
- RegisterID left,
- TrustedImm64 right,
- IR::BasicBlock *currentBlock,
- IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
-{
- if (trueBlock == _nextBlock) {
- Jump target = branch64(invert(cond), left, right);
- addPatch(falseBlock, target);
- } else {
- Jump target = branch64(cond, left, right);
- addPatch(trueBlock, target);
- jumpToBlock(currentBlock, falseBlock);
- }
+ generateCJumpOnCompare(RelationalCondition::NotEqual, reg, TrustedImm32(0), currentBlock, trueBlock, falseBlock);
}
-#endif
-void Assembler::generateCJumpOnCompare(RelationalCondition cond,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::generateCJumpOnCompare(RelationalCondition cond,
RegisterID left,
TrustedImm32 right,
IR::BasicBlock *currentBlock,
@@ -234,7 +227,8 @@ void Assembler::generateCJumpOnCompare(RelationalCondition cond,
}
}
-void Assembler::generateCJumpOnCompare(RelationalCondition cond,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::generateCJumpOnCompare(RelationalCondition cond,
RegisterID left,
RegisterID right,
IR::BasicBlock *currentBlock,
@@ -251,7 +245,8 @@ void Assembler::generateCJumpOnCompare(RelationalCondition cond,
}
}
-Assembler::Pointer Assembler::loadAddress(RegisterID tmp, IR::Expr *e)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadAddress(RegisterID tmp, IR::Expr *e)
{
IR::Temp *t = e->asTemp();
if (t)
@@ -260,7 +255,8 @@ Assembler::Pointer Assembler::loadAddress(RegisterID tmp, IR::Expr *e)
return loadArgLocalAddress(tmp, e->asArgLocal());
}
-Assembler::Pointer Assembler::loadTempAddress(IR::Temp *t)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadTempAddress(IR::Temp *t)
{
if (t->kind == IR::Temp::StackSlot)
return stackSlotPointer(t);
@@ -268,7 +264,8 @@ Assembler::Pointer Assembler::loadTempAddress(IR::Temp *t)
Q_UNREACHABLE();
}
-Assembler::Pointer Assembler::loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al)
{
int32_t offset = 0;
int scope = al->scope;
@@ -298,7 +295,8 @@ Assembler::Pointer Assembler::loadArgLocalAddress(RegisterID baseReg, IR::ArgLoc
return Pointer(baseReg, offset);
}
-Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &string)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadStringAddress(RegisterID reg, const QString &string)
{
loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, compilationUnit)), Assembler::ScratchRegister);
@@ -307,12 +305,14 @@ Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &s
return Pointer(reg, id * sizeof(QV4::String*));
}
-Assembler::Address Assembler::loadConstant(IR::Const *c, RegisterID baseReg)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(IR::Const *c, RegisterID baseReg)
{
return loadConstant(convertToValue(c), baseReg);
}
-Assembler::Address Assembler::loadConstant(const Primitive &v, RegisterID baseReg)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const Primitive &v, RegisterID baseReg)
{
loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), baseReg);
loadPtr(Address(baseReg, qOffsetOf(QV4::Heap::ExecutionContext, constantTable)), baseReg);
@@ -320,33 +320,36 @@ Assembler::Address Assembler::loadConstant(const Primitive &v, RegisterID baseRe
return Address(baseReg, index * sizeof(QV4::Value));
}
-void Assembler::loadStringRef(RegisterID reg, const QString &string)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::loadStringRef(RegisterID reg, const QString &string)
{
const int id = _jsGenerator->registerString(string);
move(TrustedImm32(id), reg);
}
-void Assembler::storeValue(QV4::Primitive value, IR::Expr *destination)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::storeValue(QV4::Primitive value, IR::Expr *destination)
{
Address addr = loadAddress(ScratchRegister, destination);
storeValue(value, addr);
}
-void Assembler::enterStandardStackFrame(const RegisterInformation &regularRegistersToSave,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::enterStandardStackFrame(const RegisterInformation &regularRegistersToSave,
const RegisterInformation &fpRegistersToSave)
{
platformEnterStandardStackFrame(this);
- move(StackPointerRegister, FramePointerRegister);
+ move(StackPointerRegister, JITTargetPlatform::FramePointerRegister);
const int frameSize = _stackLayout->calculateStackFrameSize();
subPtr(TrustedImm32(frameSize), StackPointerRegister);
- Address slotAddr(FramePointerRegister, 0);
+ Address slotAddr(JITTargetPlatform::FramePointerRegister, 0);
for (int i = 0, ei = fpRegistersToSave.size(); i < ei; ++i) {
Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint());
slotAddr.offset -= sizeof(double);
- JSC::MacroAssembler::storeDouble(fpRegistersToSave.at(i).reg<FPRegisterID>(), slotAddr);
+ TargetConfiguration::MacroAssembler::storeDouble(fpRegistersToSave.at(i).reg<FPRegisterID>(), slotAddr);
}
for (int i = 0, ei = regularRegistersToSave.size(); i < ei; ++i) {
Q_ASSERT(regularRegistersToSave.at(i).isRegularRegister());
@@ -355,10 +358,11 @@ void Assembler::enterStandardStackFrame(const RegisterInformation &regularRegist
}
}
-void Assembler::leaveStandardStackFrame(const RegisterInformation &regularRegistersToSave,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::leaveStandardStackFrame(const RegisterInformation &regularRegistersToSave,
const RegisterInformation &fpRegistersToSave)
{
- Address slotAddr(FramePointerRegister, -regularRegistersToSave.size() * RegisterSize - fpRegistersToSave.size() * sizeof(double));
+ Address slotAddr(JITTargetPlatform::FramePointerRegister, -regularRegistersToSave.size() * RegisterSize - fpRegistersToSave.size() * sizeof(double));
// restore the callee saved registers
for (int i = regularRegistersToSave.size() - 1; i >= 0; --i) {
@@ -368,7 +372,7 @@ void Assembler::leaveStandardStackFrame(const RegisterInformation &regularRegist
}
for (int i = fpRegistersToSave.size() - 1; i >= 0; --i) {
Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint());
- JSC::MacroAssembler::loadDouble(slotAddr, fpRegistersToSave.at(i).reg<FPRegisterID>());
+ TargetConfiguration::MacroAssembler::loadDouble(slotAddr, fpRegistersToSave.at(i).reg<FPRegisterID>());
slotAddr.offset += sizeof(double);
}
@@ -393,7 +397,8 @@ void Assembler::leaveStandardStackFrame(const RegisterInformation &regularRegist
// Try to load the source expression into the destination FP register. This assumes that two
// general purpose (integer) registers are available: the ScratchRegister and the
// ReturnValueRegister. It returns a Jump if no conversion can be performed.
-Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRegisterID dest)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::genTryDoubleConversion(IR::Expr *src, FPRegisterID dest)
{
switch (src->type) {
case IR::DoubleType:
@@ -436,11 +441,10 @@ Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRe
isNoInt.link(this);
#ifdef QV4_USE_64_BIT_VALUE_ENCODING
rshift32(TrustedImm32(Value::IsDoubleTag_Shift), ScratchRegister);
- Assembler::Jump isNoDbl = branch32(Equal, ScratchRegister, TrustedImm32(0));
+ Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(0));
#else
and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister);
- Assembler::Jump isNoDbl = branch32(Assembler::Equal, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::NotDouble_Mask));
+ Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(Value::NotDouble_Mask));
#endif
toDoubleRegister(src, dest);
intDone.link(this);
@@ -448,10 +452,11 @@ Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRe
return isNoDbl;
}
-Assembler::Jump Assembler::branchDouble(bool invertCondition, IR::AluOp op,
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::branchDouble(bool invertCondition, IR::AluOp op,
IR::Expr *left, IR::Expr *right)
{
- Assembler::DoubleCondition cond;
+ DoubleCondition cond;
switch (op) {
case IR::OpGt: cond = Assembler::DoubleGreaterThan; break;
case IR::OpLt: cond = Assembler::DoubleLessThan; break;
@@ -465,12 +470,13 @@ Assembler::Jump Assembler::branchDouble(bool invertCondition, IR::AluOp op,
Q_UNREACHABLE();
}
if (invertCondition)
- cond = JSC::MacroAssembler::invert(cond);
+ cond = TargetConfiguration::MacroAssembler::invert(cond);
- return JSC::MacroAssembler::branchDouble(cond, toDoubleRegister(left, FPGpr0), toDoubleRegister(right, FPGpr1));
+ return TargetConfiguration::MacroAssembler::branchDouble(cond, toDoubleRegister(left, FPGpr0), toDoubleRegister(right, JITTargetPlatform::FPGpr1));
}
-Assembler::Jump Assembler::branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right)
{
Assembler::RelationalCondition cond;
switch (op) {
@@ -486,18 +492,51 @@ Assembler::Jump Assembler::branchInt32(bool invertCondition, IR::AluOp op, IR::E
Q_UNREACHABLE();
}
if (invertCondition)
- cond = JSC::MacroAssembler::invert(cond);
+ cond = TargetConfiguration::MacroAssembler::invert(cond);
- return JSC::MacroAssembler::branch32(cond,
- toInt32Register(left, Assembler::ScratchRegister),
- toInt32Register(right, Assembler::ReturnValueRegister));
+ return TargetConfiguration::MacroAssembler::branch32(cond,
+ toInt32Register(left, Assembler::ScratchRegister),
+ toInt32Register(right, Assembler::ReturnValueRegister));
}
-void Assembler::setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave)
{
_stackLayout.reset(new StackLayout(_function, maxArgCountForBuiltins, regularRegistersToSave, fpRegistersToSave));
}
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInformation regularRegistersToSave, RegisterInformation fpRegistersToSave)
+{
+ if (!s) {
+ // this only happens if the method doesn't have a return statement and can
+ // only exit through an exception
+ } else if (IR::Temp *t = s->expr->asTemp()) {
+ RegisterSizeDependentOps::setFunctionReturnValueFromTemp(this, t);
+ } else if (IR::Const *c = s->expr->asConst()) {
+ QV4::Primitive retVal = convertToValue(c);
+ RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal);
+ } else {
+ Q_UNREACHABLE();
+ Q_UNUSED(s);
+ }
+
+ Label leaveStackFrame = label();
+
+ const int locals = stackLayout().calculateJSStackFrameSize();
+ subPtr(TrustedImm32(sizeof(QV4::Value)*locals), JITTargetPlatform::LocalsRegister);
+ loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
+ loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, engine)), JITTargetPlatform::ScratchRegister);
+ storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
+
+ leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
+ ret();
+
+ exceptionReturnLabel = label();
+ QV4::Primitive retVal = Primitive::undefinedValue();
+ RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal);
+ jump(leaveStackFrame);
+}
namespace {
class QIODevicePrintStream: public FilePrintStream
@@ -563,7 +602,8 @@ static void qt_closePmap()
#endif
-JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
+template <typename TargetConfiguration>
+JSC::MacroAssemblerCodeRef Assembler<TargetConfiguration>::link(int *codeSize)
{
Label endOfCode = label();
@@ -577,7 +617,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
}
JSC::JSGlobalData dummy(_executableAllocator);
- JSC::LinkBuffer linkBuffer(dummy, this, 0);
+ JSC::LinkBuffer<typename TargetConfiguration::MacroAssembler> linkBuffer(dummy, this, 0);
for (const DataLabelPatch &p : qAsConst(_dataLabelPatches))
linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target));
@@ -668,4 +708,9 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
return codeRef;
}
+template class QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>;
+#if defined(V4_BOOTSTRAP) && CPU(X86_64)
+template class QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
+#endif
+
#endif
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index de9c246ed6..6d8d773ff0 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -55,7 +55,8 @@
#include "private/qv4isel_p.h"
#include "private/qv4isel_util_p.h"
#include "private/qv4value_p.h"
-#include "private/qv4lookup_p.h"
+#include "private/qv4context_p.h"
+#include "private/qv4engine_p.h"
#include "qv4targetplatform_p.h"
#include <config.h>
@@ -73,46 +74,637 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
-class InstructionSelection;
-
struct CompilationUnit : public QV4::CompiledData::CompilationUnit
{
virtual ~CompilationUnit();
+#if !defined(V4_BOOTSTRAP)
void linkBackendToEngine(QV4::ExecutionEngine *engine) Q_DECL_OVERRIDE;
+ bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
+#endif
void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit) Q_DECL_OVERRIDE;
bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString) Q_DECL_OVERRIDE;
- bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
// Coderef + execution engine
QVector<JSC::MacroAssemblerCodeRef> codeRefs;
};
-struct LookupCall {
- JSC::MacroAssembler::Address addr;
- uint getterSetterOffset;
+template <typename PlatformAssembler, TargetOperatingSystemSpecialization Specialization>
+struct AssemblerTargetConfiguration
+{
+ typedef JSC::MacroAssembler<PlatformAssembler> MacroAssembler;
+ typedef TargetPlatform<PlatformAssembler, Specialization> Platform;
+ // More things coming here in the future, such as Target OS
+};
+
+#if CPU(ARM_THUMB2)
+typedef JSC::MacroAssemblerARMv7 DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(ARM64)
+typedef JSC::MacroAssemblerARM64 DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(ARM_TRADITIONAL)
+typedef JSC::MacroAssemblerARM DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(MIPS)
+typedef JSC::MacroAssemblerMIPS DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(X86)
+typedef JSC::MacroAssemblerX86 DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(X86_64)
+typedef JSC::MacroAssemblerX86_64 DefaultPlatformMacroAssembler;
+
+#if OS(WINDOWS)
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, WindowsSpecialization> DefaultAssemblerTargetConfiguration;
+#else
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#endif
- LookupCall(const JSC::MacroAssembler::Address &addr, uint getterSetterOffset)
- : addr(addr)
- , getterSetterOffset(getterSetterOffset)
- {}
+#elif CPU(SH4)
+typedef JSC::MacroAssemblerSH4 DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#endif
+
+#define isel_stringIfyx(s) #s
+#define isel_stringIfy(s) isel_stringIfyx(s)
+
+#define generateRuntimeCall(as, t, function, ...) \
+ as->generateFunctionCallImp(Runtime::Method_##function##_NeedsExceptionCheck, t, "Runtime::" isel_stringIfy(function), typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, function)), __VA_ARGS__)
+
+
+template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform, int RegisterSize>
+struct RegisterSizeDependentAssembler
+{
};
-struct RuntimeCall {
- JSC::MacroAssembler::Address addr;
+template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform>
+struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatform, 4>
+{
+ using RegisterID = typename JITAssembler::RegisterID;
+ using FPRegisterID = typename JITAssembler::FPRegisterID;
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using Address = typename JITAssembler::Address;
+ using Pointer = typename JITAssembler::Pointer;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+ using TrustedImm64 = typename JITAssembler::TrustedImm64;
+ using Jump = typename JITAssembler::Jump;
+
+ static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
+ {
+ as->MacroAssembler::loadDouble(addr, dest);
+ }
+
+ static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr)
+ {
+ as->MacroAssembler::storeDouble(source, addr);
+ }
+
+ static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target)
+ {
+ Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->storeDouble(source, ptr);
+ }
+
+ static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination)
+ {
+ as->store32(TrustedImm32(value.int_32()), destination);
+ destination.offset += 4;
+ as->store32(TrustedImm32(value.tag()), destination);
+ }
+
+ template <typename Source, typename Destination>
+ static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination)
+ {
+ as->loadDouble(source, TargetPlatform::FPGpr0);
+ as->storeDouble(TargetPlatform::FPGpr0, destination);
+ }
+
+ static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target)
+ {
+ as->MacroAssembler::loadDouble(as->loadConstant(c, TargetPlatform::ScratchRegister), target);
+ }
+
+ static void storeReturnValue(JITAssembler *as, FPRegisterID dest)
+ {
+ as->moveIntsToDouble(TargetPlatform::LowReturnValueRegister, TargetPlatform::HighReturnValueRegister, dest, TargetPlatform::FPGpr0);
+ }
+
+ static void storeReturnValue(JITAssembler *as, const Pointer &dest)
+ {
+ Address destination = dest;
+ as->store32(TargetPlatform::LowReturnValueRegister, destination);
+ destination.offset += 4;
+ as->store32(TargetPlatform::HighReturnValueRegister, destination);
+ }
+
+ static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t)
+ {
+ const auto lowReg = TargetPlatform::LowReturnValueRegister;
+ const auto highReg = TargetPlatform::HighReturnValueRegister;
+
+ if (t->kind == IR::Temp::PhysicalRegister) {
+ switch (t->type) {
+ case IR::DoubleType:
+ as->moveDoubleToInts((FPRegisterID) t->index, lowReg, highReg);
+ break;
+ case IR::UInt32Type: {
+ RegisterID srcReg = (RegisterID) t->index;
+ Jump intRange = as->branch32(JITAssembler::GreaterThanOrEqual, srcReg, TrustedImm32(0));
+ as->convertUInt32ToDouble(srcReg, TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
+ as->moveDoubleToInts(TargetPlatform::FPGpr0, lowReg, highReg);
+ Jump done = as->jump();
+ intRange.link(as);
+ as->move(srcReg, lowReg);
+ as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
+ done.link(as);
+ } break;
+ case IR::SInt32Type:
+ as->move((RegisterID) t->index, lowReg);
+ as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
+ break;
+ case IR::BoolType:
+ as->move((RegisterID) t->index, lowReg);
+ as->move(TrustedImm32(QV4::Value::Boolean_Type_Internal), highReg);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ } else {
+ Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, t);
+ as->load32(addr, lowReg);
+ addr.offset += 4;
+ as->load32(addr, highReg);
+ }
+ }
+
+ static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal)
+ {
+ as->move(TrustedImm32(retVal.int_32()), TargetPlatform::LowReturnValueRegister);
+ as->move(TrustedImm32(retVal.tag()), TargetPlatform::HighReturnValueRegister);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Temp* temp, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(as);
+ Q_UNUSED(temp);
+ Q_UNUSED(dest);
+ Q_UNUSED(argumentNumber);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::ArgLocal* al, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(as);
+ Q_UNUSED(al);
+ Q_UNUSED(dest);
+ Q_UNUSED(argumentNumber);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Const* c, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(as);
+ Q_UNUSED(c);
+ Q_UNUSED(dest);
+ Q_UNUSED(argumentNumber);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Expr* expr, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(as);
+ Q_UNUSED(expr);
+ Q_UNUSED(dest);
+ Q_UNUSED(argumentNumber);
+ }
+
+ static void zeroRegister(JITAssembler *as, RegisterID reg)
+ {
+ as->move(TrustedImm32(0), reg);
+ }
+
+ static void zeroStackSlot(JITAssembler *as, int slot)
+ {
+ as->poke(TrustedImm32(0), slot);
+ }
+
+ static void generateCJumpOnUndefined(JITAssembler *as,
+ RelationalCondition cond, IR::Expr *right,
+ RegisterID scratchRegister, RegisterID tagRegister,
+ IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock,
+ IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
+ {
+ Pointer tagAddr = as->loadAddress(scratchRegister, right);
+ as->load32(tagAddr, tagRegister);
+ Jump j = as->branch32(JITAssembler::invert(cond), tagRegister, TrustedImm32(0));
+ as->addPatch(falseBlock, j);
+
+ tagAddr.offset += 4;
+ as->load32(tagAddr, tagRegister);
+ const TrustedImm32 tag(QV4::Value::Managed_Type_Internal);
+ Q_ASSERT(nextBlock == as->nextBlock());
+ Q_UNUSED(nextBlock);
+ as->generateCJumpOnCompare(cond, tagRegister, tag, currentBlock, trueBlock, falseBlock);
+ }
+
+ static void convertVarToSInt32(JITAssembler *as, IR::Expr *source, IR::Expr *target)
+ {
+ Q_ASSERT(source->type == IR::VarType);
+ // load the tag:
+ Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source);
+ Pointer tagAddr = addr;
+ tagAddr.offset += 4;
+ as->load32(tagAddr, TargetPlatform::ReturnValueRegister);
+
+ // check if it's an int32:
+ Jump fallback = as->branch32(RelationalCondition::NotEqual, TargetPlatform::ReturnValueRegister,
+ TrustedImm32(Value::Integer_Type_Internal));
+ IR::Temp *targetTemp = target->asTemp();
+ if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
+ as->load32(addr, TargetPlatform::ReturnValueRegister);
+ Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
+ targetAddr.offset += 4;
+ as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr);
+ } else {
+ as->load32(addr, (RegisterID) targetTemp->index);
+ }
+ Jump intDone = as->jump();
+
+ // not an int:
+ fallback.link(as);
+ generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt,
+ as->loadAddress(TargetPlatform::ScratchRegister, source));
+ as->storeInt32(TargetPlatform::ReturnValueRegister, target);
+
+ intDone.link(as);
+ }
+
+ static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr)
+ {
+ as->store32(registerWithPtr, destAddr);
+ destAddr.offset += 4;
+ as->store32(TrustedImm32(QV4::Value::Managed_Type_Internal_32), destAddr);
+ }
+
+ static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister)
+ {
+ as->and32(TrustedImm32(Value::NotDouble_Mask), tagOrValueRegister);
+ return as->branch32(RelationalCondition::NotEqual, tagOrValueRegister,
+ TrustedImm32(Value::NotDouble_Mask));
+ }
+};
+
+template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform>
+struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatform, 8>
+{
+ using RegisterID = typename JITAssembler::RegisterID;
+ using FPRegisterID = typename JITAssembler::FPRegisterID;
+ using Address = typename JITAssembler::Address;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+ using TrustedImm64 = typename JITAssembler::TrustedImm64;
+ using Pointer = typename JITAssembler::Pointer;
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using BranchTruncateType = typename JITAssembler::BranchTruncateType;
+ using Jump = typename JITAssembler::Jump;
+
+ static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
+ {
+ as->load64(addr, TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest);
+ }
+
+ static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr)
+ {
+ as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->store64(TargetPlatform::ReturnValueRegister, addr);
+ }
+
+ static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target)
+ {
+ as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->store64(TargetPlatform::ReturnValueRegister, ptr);
+ }
+
+ static void storeReturnValue(JITAssembler *as, FPRegisterID dest)
+ {
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest);
+ }
+
+ static void storeReturnValue(JITAssembler *as, const Pointer &dest)
+ {
+ as->store64(TargetPlatform::ReturnValueRegister, dest);
+ }
+
+ static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t)
+ {
+ if (t->kind == IR::Temp::PhysicalRegister) {
+ if (t->type == IR::DoubleType) {
+ as->moveDoubleTo64((FPRegisterID) t->index,
+ TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask),
+ TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ } else if (t->type == IR::UInt32Type) {
+ RegisterID srcReg = (RegisterID) t->index;
+ Jump intRange = as->branch32(RelationalCondition::GreaterThanOrEqual, srcReg, TrustedImm32(0));
+ as->convertUInt32ToDouble(srcReg, TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
+ as->moveDoubleTo64(TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ Jump done = as->jump();
+ intRange.link(as);
+ as->zeroExtend32ToPtr(srcReg, TargetPlatform::ReturnValueRegister);
+ quint64 tag = QV4::Value::Integer_Type_Internal;
+ as->or64(TrustedImm64(tag << 32),
+ TargetPlatform::ReturnValueRegister);
+ done.link(as);
+ } else {
+ as->zeroExtend32ToPtr((RegisterID) t->index, TargetPlatform::ReturnValueRegister);
+ quint64 tag;
+ switch (t->type) {
+ case IR::SInt32Type:
+ tag = QV4::Value::Integer_Type_Internal;
+ break;
+ case IR::BoolType:
+ tag = QV4::Value::Boolean_Type_Internal;
+ break;
+ default:
+ tag = 31337; // bogus value
+ Q_UNREACHABLE();
+ }
+ as->or64(TrustedImm64(tag << 32),
+ TargetPlatform::ReturnValueRegister);
+ }
+ } else {
+ as->copyValue(TargetPlatform::ReturnValueRegister, t);
+ }
+ }
+
+ static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal)
+ {
+ as->move(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister);
+ }
+
+ static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination)
+ {
+ as->store64(TrustedImm64(value.rawValue()), destination);
+ }
+
+ template <typename Source, typename Destination>
+ static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination)
+ {
+ // Use ReturnValueRegister as "scratch" register because loadArgument
+ // and storeArgument are functions that may need a scratch register themselves.
+ as->loadArgumentInRegister(source, TargetPlatform::ReturnValueRegister, 0);
+ as->storeReturnValue(destination);
+ }
+
+ static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target)
+ {
+ Q_STATIC_ASSERT(sizeof(int64_t) == sizeof(double));
+ int64_t i;
+ memcpy(&i, &c->value, sizeof(double));
+ as->move(TrustedImm64(i), TargetPlatform::ReturnValueRegister);
+ as->move64ToDouble(TargetPlatform::ReturnValueRegister, target);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Temp* temp, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(argumentNumber);
+
+ if (temp) {
+ Pointer addr = as->loadTempAddress(temp);
+ as->load64(addr, dest);
+ } else {
+ QV4::Value undefined = QV4::Primitive::undefinedValue();
+ as->move(TrustedImm64(undefined.rawValue()), dest);
+ }
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::ArgLocal* al, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(argumentNumber);
+
+ if (al) {
+ Pointer addr = as->loadArgLocalAddress(dest, al);
+ as->load64(addr, dest);
+ } else {
+ QV4::Value undefined = QV4::Primitive::undefinedValue();
+ as->move(TrustedImm64(undefined.rawValue()), dest);
+ }
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Const* c, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(argumentNumber);
+
+ QV4::Value v = convertToValue(c);
+ as->move(TrustedImm64(v.rawValue()), dest);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Expr* expr, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(argumentNumber);
+
+ if (!expr) {
+ QV4::Value undefined = QV4::Primitive::undefinedValue();
+ as->move(TrustedImm64(undefined.rawValue()), dest);
+ } else if (IR::Temp *t = expr->asTemp()){
+ loadArgumentInRegister(as, t, dest, argumentNumber);
+ } else if (IR::ArgLocal *al = expr->asArgLocal()) {
+ loadArgumentInRegister(as, al, dest, argumentNumber);
+ } else if (IR::Const *c = expr->asConst()) {
+ loadArgumentInRegister(as, c, dest, argumentNumber);
+ } else {
+ Q_ASSERT(!"unimplemented expression type in loadArgument");
+ }
+ }
+
+ static void zeroRegister(JITAssembler *as, RegisterID reg)
+ {
+ as->move(TrustedImm64(0), reg);
+ }
- inline RuntimeCall(uint offset = uint(INT_MIN));
- bool isValid() const { return addr.offset >= 0; }
+ static void zeroStackSlot(JITAssembler *as, int slot)
+ {
+ as->store64(TrustedImm64(0), as->addressForPoke(slot));
+ }
+
+ static void generateCJumpOnCompare(JITAssembler *as,
+ RelationalCondition cond,
+ RegisterID left,
+ TrustedImm64 right,
+ IR::BasicBlock *nextBlock,
+ IR::BasicBlock *currentBlock,
+ IR::BasicBlock *trueBlock,
+ IR::BasicBlock *falseBlock)
+ {
+ if (trueBlock == nextBlock) {
+ Jump target = as->branch64(as->invert(cond), left, right);
+ as->addPatch(falseBlock, target);
+ } else {
+ Jump target = as->branch64(cond, left, right);
+ as->addPatch(trueBlock, target);
+ as->jumpToBlock(currentBlock, falseBlock);
+ }
+ }
+
+ static void generateCJumpOnUndefined(JITAssembler *as,
+ RelationalCondition cond, IR::Expr *right,
+ RegisterID scratchRegister, RegisterID tagRegister,
+ IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock,
+ IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
+ {
+ Pointer addr = as->loadAddress(scratchRegister, right);
+ as->load64(addr, tagRegister);
+ const TrustedImm64 tag(0);
+ generateCJumpOnCompare(as, cond, tagRegister, tag, nextBlock, currentBlock, trueBlock, falseBlock);
+ }
+
+ static void convertVarToSInt32(JITAssembler *as, IR::Expr *source, IR::Expr *target)
+ {
+ Q_ASSERT(source->type == IR::VarType);
+ Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source);
+ as->load64(addr, TargetPlatform::ScratchRegister);
+ as->move(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+
+ // check if it's integer convertible
+ as->urshift64(TrustedImm32(QV4::Value::IsIntegerConvertible_Shift), TargetPlatform::ScratchRegister);
+ Jump isIntConvertible = as->branch32(RelationalCondition::Equal, TargetPlatform::ScratchRegister, TrustedImm32(3));
+
+ // nope, not integer convertible, so check for a double:
+ as->urshift64(TrustedImm32(
+ QV4::Value::IsDoubleTag_Shift - QV4::Value::IsIntegerConvertible_Shift),
+ TargetPlatform::ScratchRegister);
+ Jump fallback = as->branch32(RelationalCondition::GreaterThan, TargetPlatform::ScratchRegister, TrustedImm32(0));
+
+ // it's a double
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->move64ToDouble(TargetPlatform::ReturnValueRegister, TargetPlatform::FPGpr0);
+ Jump success =
+ as->branchTruncateDoubleToInt32(TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister,
+ BranchTruncateType::BranchIfTruncateSuccessful);
+
+ // not an int:
+ fallback.link(as);
+ generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt,
+ as->loadAddress(TargetPlatform::ScratchRegister, source));
+
+
+ isIntConvertible.link(as);
+ success.link(as);
+ IR::Temp *targetTemp = target->asTemp();
+ if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
+ Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
+ targetAddr.offset += 4;
+ as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr);
+ } else {
+ as->storeInt32(TargetPlatform::ReturnValueRegister, target);
+ }
+ }
+
+ static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr)
+ {
+ as->store64(registerWithPtr, destAddr);
+ }
+
+ static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister)
+ {
+ as->rshift32(TrustedImm32(Value::IsDoubleTag_Shift), tagOrValueRegister);
+ return as->branch32(RelationalCondition::NotEqual, tagOrValueRegister,
+ TrustedImm32(0));
+ }
};
-class Assembler : public JSC::MacroAssembler, public TargetPlatform
+template <typename TargetConfiguration>
+class Assembler : public TargetConfiguration::MacroAssembler, public TargetConfiguration::Platform
{
Q_DISABLE_COPY(Assembler)
public:
Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator);
+ using MacroAssembler = typename TargetConfiguration::MacroAssembler;
+ using RegisterID = typename MacroAssembler::RegisterID;
+ using FPRegisterID = typename MacroAssembler::FPRegisterID;
+ using Address = typename MacroAssembler::Address;
+ using Label = typename MacroAssembler::Label;
+ using Jump = typename MacroAssembler::Jump;
+ using DataLabelPtr = typename MacroAssembler::DataLabelPtr;
+ using TrustedImm32 = typename MacroAssembler::TrustedImm32;
+ using TrustedImm64 = typename MacroAssembler::TrustedImm64;
+ using TrustedImmPtr = typename MacroAssembler::TrustedImmPtr;
+ using RelationalCondition = typename MacroAssembler::RelationalCondition;
+ using typename MacroAssembler::DoubleCondition;
+ using MacroAssembler::label;
+ using MacroAssembler::move;
+ using MacroAssembler::jump;
+ using MacroAssembler::add32;
+ using MacroAssembler::and32;
+ using MacroAssembler::store32;
+ using MacroAssembler::loadPtr;
+ using MacroAssembler::load32;
+ using MacroAssembler::branch32;
+ using MacroAssembler::subDouble;
+ using MacroAssembler::subPtr;
+ using MacroAssembler::addPtr;
+ using MacroAssembler::call;
+ using MacroAssembler::poke;
+ using MacroAssembler::branchTruncateDoubleToUint32;
+ using MacroAssembler::or32;
+ using MacroAssembler::moveDouble;
+ using MacroAssembler::convertUInt32ToDouble;
+ using MacroAssembler::invert;
+ using MacroAssembler::convertInt32ToDouble;
+ using MacroAssembler::rshift32;
+ using MacroAssembler::storePtr;
+ using MacroAssembler::ret;
+
+ using JITTargetPlatform = typename TargetConfiguration::Platform;
+ using JITTargetPlatform::RegisterArgumentCount;
+ using JITTargetPlatform::StackSpaceAllocatedUponFunctionEntry;
+ using JITTargetPlatform::RegisterSize;
+ using JITTargetPlatform::StackAlignment;
+ using JITTargetPlatform::ReturnValueRegister;
+ using JITTargetPlatform::StackPointerRegister;
+ using JITTargetPlatform::ScratchRegister;
+ using JITTargetPlatform::EngineRegister;
+ using JITTargetPlatform::StackShadowSpace;
+ using JITTargetPlatform::registerForArgument;
+ using JITTargetPlatform::FPGpr0;
+ using JITTargetPlatform::platformEnterStandardStackFrame;
+ using JITTargetPlatform::platformLeaveStandardStackFrame;
+
+ using RegisterSizeDependentOps = RegisterSizeDependentAssembler<Assembler<TargetConfiguration>, MacroAssembler, JITTargetPlatform, RegisterSize>;
+
+ struct LookupCall {
+ Address addr;
+ uint getterSetterOffset;
+
+ LookupCall(const Address &addr, uint getterSetterOffset)
+ : addr(addr)
+ , getterSetterOffset(getterSetterOffset)
+ {}
+ };
+
+ struct RuntimeCall {
+ Address addr;
+
+ inline RuntimeCall(uint offset = uint(INT_MIN));
+ bool isValid() const { return addr.offset >= 0; }
+ };
+
// Explicit type to allow distinguishing between
// pushing an address itself or the value it points
// to onto the stack when calling functions.
@@ -319,20 +911,29 @@ public:
void addPatch(DataLabelPtr patch, IR::BasicBlock *target);
void generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, TrustedImm64 right,
- IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock);
-#endif
void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, TrustedImm32 right,
IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock);
void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, RegisterID right,
IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock);
- Jump genTryDoubleConversion(IR::Expr *src, Assembler::FPRegisterID dest);
- Assembler::Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
- Assembler::Jump branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
+ void generateCJumpOnUndefined(RelationalCondition cond, IR::Expr *right,
+ RegisterID scratchRegister, RegisterID tagRegister,
+ IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
+ IR::BasicBlock *falseBlock)
+ {
+ RegisterSizeDependentOps::generateCJumpOnUndefined(this, cond, right, scratchRegister, tagRegister,
+ _nextBlock, currentBlock, trueBlock, falseBlock);
+ }
+
+ Jump generateIsDoubleCheck(RegisterID tagOrValueRegister)
+ {
+ return RegisterSizeDependentOps::generateIsDoubleCheck(this, tagOrValueRegister);
+ }
+
+ Jump genTryDoubleConversion(IR::Expr *src, FPRegisterID dest);
+ Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
+ Jump branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
Pointer loadAddress(RegisterID tmp, IR::Expr *t);
Pointer loadTempAddress(IR::Temp *t);
@@ -396,7 +997,7 @@ public:
void loadArgumentInRegister(PointerToValue temp, RegisterID dest, int argumentNumber)
{
if (!temp.value) {
- move(TrustedImmPtr(0), dest);
+ RegisterSizeDependentOps::zeroRegister(this, dest);
} else {
Pointer addr = toAddress(dest, temp.value, argumentNumber);
loadArgumentInRegister(addr, dest, argumentNumber);
@@ -415,70 +1016,31 @@ public:
loadArgumentInRegister(addr, dest, argumentNumber);
}
-#ifdef VALUE_FITS_IN_REGISTER
void loadArgumentInRegister(IR::Temp* temp, RegisterID dest, int argumentNumber)
{
- Q_UNUSED(argumentNumber);
-
- if (temp) {
- Pointer addr = loadTempAddress(temp);
- load64(addr, dest);
- } else {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
- move(TrustedImm64(undefined.rawValue()), dest);
- }
+ RegisterSizeDependentOps::loadArgumentInRegister(this, temp, dest, argumentNumber);
}
void loadArgumentInRegister(IR::ArgLocal* al, RegisterID dest, int argumentNumber)
{
- Q_UNUSED(argumentNumber);
-
- if (al) {
- Pointer addr = loadArgLocalAddress(dest, al);
- load64(addr, dest);
- } else {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
- move(TrustedImm64(undefined.rawValue()), dest);
- }
+ RegisterSizeDependentOps::loadArgumentInRegister(this, al, dest, argumentNumber);
}
void loadArgumentInRegister(IR::Const* c, RegisterID dest, int argumentNumber)
{
- Q_UNUSED(argumentNumber);
-
- QV4::Value v = convertToValue(c);
- move(TrustedImm64(v.rawValue()), dest);
+ RegisterSizeDependentOps::loadArgumentInRegister(this, c, dest, argumentNumber);
}
void loadArgumentInRegister(IR::Expr* expr, RegisterID dest, int argumentNumber)
{
- Q_UNUSED(argumentNumber);
-
- if (!expr) {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
- move(TrustedImm64(undefined.rawValue()), dest);
- } else if (IR::Temp *t = expr->asTemp()){
- loadArgumentInRegister(t, dest, argumentNumber);
- } else if (IR::ArgLocal *al = expr->asArgLocal()) {
- loadArgumentInRegister(al, dest, argumentNumber);
- } else if (IR::Const *c = expr->asConst()) {
- loadArgumentInRegister(c, dest, argumentNumber);
- } else {
- Q_ASSERT(!"unimplemented expression type in loadArgument");
- }
- }
-#else
- void loadArgumentInRegister(IR::Expr*, RegisterID)
- {
- Q_ASSERT(!"unimplemented: expression in loadArgument");
+ RegisterSizeDependentOps::loadArgumentInRegister(this, expr, dest, argumentNumber);
}
-#endif
void loadArgumentInRegister(TrustedImm32 imm32, RegisterID dest, int argumentNumber)
{
Q_UNUSED(argumentNumber);
- xorPtr(dest, dest);
+ RegisterSizeDependentOps::zeroRegister(this, dest);
if (imm32.m_value)
move(imm32, dest);
}
@@ -499,55 +1061,13 @@ public:
void storeReturnValue(FPRegisterID dest)
{
-#ifdef VALUE_FITS_IN_REGISTER
- move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, ReturnValueRegister);
- move64ToDouble(ReturnValueRegister, dest);
-#elif defined(Q_PROCESSOR_ARM)
- moveIntsToDouble(JSC::ARMRegisters::r0, JSC::ARMRegisters::r1, dest, FPGpr0);
-#elif defined(Q_PROCESSOR_X86)
- moveIntsToDouble(JSC::X86Registers::eax, JSC::X86Registers::edx, dest, FPGpr0);
-#elif defined(Q_PROCESSOR_MIPS)
- moveIntsToDouble(JSC::MIPSRegisters::v0, JSC::MIPSRegisters::v1, dest, FPGpr0);
-#else
- subPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister);
- Pointer tmp(StackPointerRegister, 0);
- storeReturnValue(tmp);
- loadDouble(tmp, dest);
- addPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister);
-#endif
+ RegisterSizeDependentOps::storeReturnValue(this, dest);
}
-#ifdef VALUE_FITS_IN_REGISTER
- void storeReturnValue(const Pointer &dest)
- {
- store64(ReturnValueRegister, dest);
- }
-#elif defined(Q_PROCESSOR_X86)
- void storeReturnValue(const Pointer &dest)
- {
- Pointer destination = dest;
- store32(JSC::X86Registers::eax, destination);
- destination.offset += 4;
- store32(JSC::X86Registers::edx, destination);
- }
-#elif defined(Q_PROCESSOR_ARM)
- void storeReturnValue(const Pointer &dest)
- {
- Pointer destination = dest;
- store32(JSC::ARMRegisters::r0, destination);
- destination.offset += 4;
- store32(JSC::ARMRegisters::r1, destination);
- }
-#elif defined(Q_PROCESSOR_MIPS)
void storeReturnValue(const Pointer &dest)
{
- Pointer destination = dest;
- store32(JSC::MIPSRegisters::v0, destination);
- destination.offset += 4;
- store32(JSC::MIPSRegisters::v1, destination);
+ RegisterSizeDependentOps::storeReturnValue(this, dest);
}
-#endif
void storeReturnValue(IR::Expr *target)
{
@@ -609,7 +1129,7 @@ public:
Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber);
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
} else {
- poke(TrustedImmPtr(0), StackSlot);
+ RegisterSizeDependentOps::zeroStackSlot(this, StackSlot);
}
}
@@ -648,38 +1168,18 @@ public:
moveDouble(source, (FPRegisterID) targetTemp->index);
return;
}
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- moveDoubleTo64(source, ReturnValueRegister);
- move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, ReturnValueRegister);
- Pointer ptr = loadAddress(ScratchRegister, target);
- store64(ReturnValueRegister, ptr);
-#else
- Pointer ptr = loadAddress(ScratchRegister, target);
- storeDouble(source, ptr);
-#endif
+ RegisterSizeDependentOps::storeDouble(this, source, target);
}
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- // We need to (de)mangle the double
+
void loadDouble(Address addr, FPRegisterID dest)
{
- load64(addr, ReturnValueRegister);
- move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, ReturnValueRegister);
- move64ToDouble(ReturnValueRegister, dest);
+ RegisterSizeDependentOps::loadDouble(this, addr, dest);
}
void storeDouble(FPRegisterID source, Address addr)
{
- moveDoubleTo64(source, ReturnValueRegister);
- move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, ReturnValueRegister);
- store64(ReturnValueRegister, addr);
+ RegisterSizeDependentOps::storeDouble(this, source, addr);
}
-#else
- using JSC::MacroAssembler::loadDouble;
- using JSC::MacroAssembler::storeDouble;
-#endif
template <typename Result, typename Source>
void copyValue(Result result, Source source);
@@ -691,8 +1191,15 @@ public:
{
Q_ASSERT(!source->asTemp() || source->asTemp()->kind != IR::Temp::PhysicalRegister);
Q_ASSERT(target.base != scratchRegister);
- JSC::MacroAssembler::loadDouble(loadAddress(scratchRegister, source), FPGpr0);
- JSC::MacroAssembler::storeDouble(FPGpr0, target);
+ TargetConfiguration::MacroAssembler::loadDouble(loadAddress(scratchRegister, source), FPGpr0);
+ TargetConfiguration::MacroAssembler::storeDouble(FPGpr0, target);
+ }
+
+ // The scratch register is used to calculate the temp address for the source.
+ void memcopyValue(IR::Expr *target, Pointer source, FPRegisterID fpScratchRegister, RegisterID scratchRegister)
+ {
+ TargetConfiguration::MacroAssembler::loadDouble(source, fpScratchRegister);
+ TargetConfiguration::MacroAssembler::storeDouble(fpScratchRegister, loadAddress(scratchRegister, target));
}
void storeValue(QV4::Primitive value, RegisterID destination)
@@ -704,13 +1211,7 @@ public:
void storeValue(QV4::Primitive value, Address destination)
{
-#ifdef VALUE_FITS_IN_REGISTER
- store64(TrustedImm64(value.rawValue()), destination);
-#else
- store32(TrustedImm32(value.int_32()), destination);
- destination.offset += 4;
- store32(TrustedImm32(value.tag()), destination);
-#endif
+ RegisterSizeDependentOps::storeValue(this, value, destination);
}
void storeValue(QV4::Primitive value, IR::Expr* temp);
@@ -722,7 +1223,7 @@ public:
void checkException() {
load32(Address(EngineRegister, qOffsetOf(QV4::ExecutionEngine, hasException)), ScratchRegister);
- Jump exceptionThrown = branch32(NotEqual, ScratchRegister, TrustedImm32(0));
+ Jump exceptionThrown = branch32(RelationalCondition::NotEqual, ScratchRegister, TrustedImm32(0));
if (catchBlock)
addPatch(catchBlock, exceptionThrown);
else
@@ -781,6 +1282,27 @@ public:
enum { Size = 0 };
};
+ template <typename T> bool prepareCall(T &)
+ { return true; }
+
+ bool prepareCall(LookupCall &lookupCall)
+ {
+ // IMPORTANT! See generateLookupCall in qv4isel_masm_p.h for details!
+
+ // load the table from the context
+ loadPtr(Address(EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), ScratchRegister);
+ loadPtr(Address(ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, lookups)),
+ lookupCall.addr.base);
+ // pre-calculate the indirect address for the lookupCall table:
+ if (lookupCall.addr.offset)
+ addPtr(TrustedImm32(lookupCall.addr.offset), lookupCall.addr.base);
+ // store it as the first argument
+ loadArgumentOnStackOrRegister<0>(lookupCall.addr.base);
+ // set the destination addresses offset to the getterSetterOffset. The base is the lookupCall table's address
+ lookupCall.addr.offset = lookupCall.getterSetterOffset;
+ return false;
+ }
+
template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6>
void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6)
{
@@ -813,11 +1335,11 @@ public:
loadArgumentOnStackOrRegister<2>(arg3);
loadArgumentOnStackOrRegister<1>(arg2);
- if (prepareCall(function, this))
+ if (prepareCall(function))
loadArgumentOnStackOrRegister<0>(arg1);
#ifdef RESTORE_EBX_ON_CALL
- load32(ebxAddressOnStack(), JSC::X86Registers::ebx); // restore the GOT ptr
+ load32(this->ebxAddressOnStack(), JSC::X86Registers::ebx); // restore the GOT ptr
#endif
callAbsolute(functionName, function);
@@ -957,7 +1479,7 @@ public:
void storeUInt32(RegisterID reg, Pointer addr)
{
// The UInt32 representation in QV4::Value is really convoluted. See also toUInt32Register.
- Jump intRange = branch32(GreaterThanOrEqual, reg, TrustedImm32(0));
+ Jump intRange = branch32(RelationalCondition::GreaterThanOrEqual, reg, TrustedImm32(0));
convertUInt32ToDouble(reg, FPGpr0, ReturnValueRegister);
storeDouble(FPGpr0, addr);
Jump done = jump();
@@ -980,15 +1502,7 @@ public:
FPRegisterID toDoubleRegister(IR::Expr *e, FPRegisterID target = FPGpr0)
{
if (IR::Const *c = e->asConst()) {
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- Q_STATIC_ASSERT(sizeof(int64_t) == sizeof(double));
- int64_t i;
- memcpy(&i, &c->value, sizeof(double));
- move(TrustedImm64(i), ReturnValueRegister);
- move64ToDouble(ReturnValueRegister, target);
-#else
- JSC::MacroAssembler::loadDouble(loadConstant(c, ScratchRegister), target);
-#endif
+ RegisterSizeDependentOps::loadDoubleConstant(this, c, target);
return target;
}
@@ -1047,7 +1561,7 @@ public:
Pointer tagAddr = addr;
tagAddr.offset += 4;
load32(tagAddr, scratchReg);
- Jump inIntRange = branch32(Equal, scratchReg, TrustedImm32(QV4::Value::Integer_Type_Internal));
+ Jump inIntRange = branch32(RelationalCondition::Equal, scratchReg, TrustedImm32(QV4::Value::Integer_Type_Internal));
// it's not in signed int range, so load it as a double, and truncate it down
loadDouble(addr, FPGpr0);
@@ -1065,6 +1579,8 @@ public:
return scratchReg;
}
+ void returnFromFunction(IR::Ret *s, RegisterInformation regularRegistersToSave, RegisterInformation fpRegistersToSave);
+
JSC::MacroAssemblerCodeRef link(int *codeSize);
void setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave);
@@ -1095,22 +1611,16 @@ private:
QV4::Compiler::JSUnitGenerator *_jsGenerator;
};
+template <typename TargetConfiguration>
template <typename Result, typename Source>
-void Assembler::copyValue(Result result, Source source)
+void Assembler<TargetConfiguration>::copyValue(Result result, Source source)
{
-#ifdef VALUE_FITS_IN_REGISTER
- // Use ReturnValueRegister as "scratch" register because loadArgument
- // and storeArgument are functions that may need a scratch register themselves.
- loadArgumentInRegister(source, ReturnValueRegister, 0);
- storeReturnValue(result);
-#else
- loadDouble(source, FPGpr0);
- storeDouble(FPGpr0, result);
-#endif
+ RegisterSizeDependentOps::copyValueViaRegisters(this, source, result);
}
+template <typename TargetConfiguration>
template <typename Result>
-void Assembler::copyValue(Result result, IR::Expr* source)
+void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source)
{
if (source->type == IR::BoolType) {
RegisterID reg = toInt32Register(source, ScratchRegister);
@@ -1124,15 +1634,7 @@ void Assembler::copyValue(Result result, IR::Expr* source)
} else if (source->type == IR::DoubleType) {
storeDouble(toDoubleRegister(source), result);
} else if (source->asTemp() || source->asArgLocal()) {
-#ifdef VALUE_FITS_IN_REGISTER
- // Use ReturnValueRegister as "scratch" register because loadArgument
- // and storeArgument are functions that may need a scratch register themselves.
- loadArgumentInRegister(source, ReturnValueRegister, 0);
- storeReturnValue(result);
-#else
- loadDouble(source, FPGpr0);
- storeDouble(FPGpr0, result);
-#endif
+ RegisterSizeDependentOps::copyValueViaRegisters(this, source, result);
} else if (IR::Const *c = source->asConst()) {
QV4::Primitive v = convertToValue(c);
storeValue(v, result);
@@ -1141,34 +1643,12 @@ void Assembler::copyValue(Result result, IR::Expr* source)
}
}
-inline RuntimeCall::RuntimeCall(uint offset)
+template <typename TargetConfiguration>
+inline Assembler<TargetConfiguration>::RuntimeCall::RuntimeCall(uint offset)
: addr(Assembler::EngineRegister, offset + qOffsetOf(QV4::ExecutionEngine, runtime))
{
}
-
-
-template <typename T> inline bool prepareCall(T &, Assembler *)
-{ return true; }
-
-template <> inline bool prepareCall(LookupCall &lookupCall, Assembler *as)
-{
- // IMPORTANT! See generateLookupCall in qv4isel_masm_p.h for details!
-
- // load the table from the context
- as->loadPtr(Assembler::Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- as->loadPtr(Assembler::Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, lookups)),
- lookupCall.addr.base);
- // pre-calculate the indirect address for the lookupCall table:
- if (lookupCall.addr.offset)
- as->addPtr(Assembler::TrustedImm32(lookupCall.addr.offset), lookupCall.addr.base);
- // store it as the first argument
- as->loadArgumentOnStackOrRegister<0>(lookupCall.addr.base);
- // set the destination addresses offset to the getterSetterOffset. The base is the lookupCall table's address
- lookupCall.addr.offset = lookupCall.getterSetterOffset;
- return false;
-}
-
} // end of namespace JIT
} // end of namespace QV4
diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp
index d2758c4a47..8468bf65a6 100644
--- a/src/qml/jit/qv4binop.cpp
+++ b/src/qml/jit/qv4binop.cpp
@@ -57,7 +57,8 @@ using namespace JIT;
#define NULL_OP \
{ 0, 0, 0, 0, 0, false }
-const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = {
+template <typename JITAssembler>
+const typename Binop<JITAssembler>::OpInfo Binop<JITAssembler>::operations[IR::LastAluOp + 1] = {
NULL_OP, // OpInvalid
NULL_OP, // OpIfTrue
NULL_OP, // OpNot
@@ -67,20 +68,20 @@ const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = {
NULL_OP, // OpIncrement
NULL_OP, // OpDecrement
- INLINE_OP(bitAnd, &Binop::inline_and32, &Binop::inline_and32), // OpBitAnd
- INLINE_OP(bitOr, &Binop::inline_or32, &Binop::inline_or32), // OpBitOr
- INLINE_OP(bitXor, &Binop::inline_xor32, &Binop::inline_xor32), // OpBitXor
+ INLINE_OP(bitAnd, &Binop<JITAssembler>::inline_and32, &Binop<JITAssembler>::inline_and32), // OpBitAnd
+ INLINE_OP(bitOr, &Binop<JITAssembler>::inline_or32, &Binop<JITAssembler>::inline_or32), // OpBitOr
+ INLINE_OP(bitXor, &Binop<JITAssembler>::inline_xor32, &Binop<JITAssembler>::inline_xor32), // OpBitXor
- INLINE_OPCONTEXT(add, &Binop::inline_add32, &Binop::inline_add32), // OpAdd
- INLINE_OP(sub, &Binop::inline_sub32, &Binop::inline_sub32), // OpSub
- INLINE_OP(mul, &Binop::inline_mul32, &Binop::inline_mul32), // OpMul
+ INLINE_OPCONTEXT(add, &Binop<JITAssembler>::inline_add32, &Binop<JITAssembler>::inline_add32), // OpAdd
+ INLINE_OP(sub, &Binop<JITAssembler>::inline_sub32, &Binop<JITAssembler>::inline_sub32), // OpSub
+ INLINE_OP(mul, &Binop<JITAssembler>::inline_mul32, &Binop<JITAssembler>::inline_mul32), // OpMul
OP(div), // OpDiv
OP(mod), // OpMod
- INLINE_OP(shl, &Binop::inline_shl32, &Binop::inline_shl32), // OpLShift
- INLINE_OP(shr, &Binop::inline_shr32, &Binop::inline_shr32), // OpRShift
- INLINE_OP(ushr, &Binop::inline_ushr32, &Binop::inline_ushr32), // OpURShift
+ INLINE_OP(shl, &Binop<JITAssembler>::inline_shl32, &Binop<JITAssembler>::inline_shl32), // OpLShift
+ INLINE_OP(shr, &Binop<JITAssembler>::inline_shr32, &Binop<JITAssembler>::inline_shr32), // OpRShift
+ INLINE_OP(ushr, &Binop<JITAssembler>::inline_ushr32, &Binop<JITAssembler>::inline_ushr32), // OpURShift
OP(greaterThan), // OpGt
OP(lessThan), // OpLt
@@ -100,7 +101,8 @@ const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = {
-void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
+template <typename JITAssembler>
+void Binop<JITAssembler>::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
{
if (op != IR::OpMod
&& lhs->type == IR::DoubleType && rhs->type == IR::DoubleType) {
@@ -125,15 +127,15 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
info = stringAdd;
}
- RuntimeCall fallBack(info.fallbackImplementation);
- RuntimeCall context(info.contextImplementation);
+ typename JITAssembler::RuntimeCall fallBack(info.fallbackImplementation);
+ typename JITAssembler::RuntimeCall context(info.contextImplementation);
if (fallBack.isValid()) {
as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, fallBack,
PointerToValue(lhs),
PointerToValue(rhs));
} else if (context.isValid()) {
as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, context,
- Assembler::EngineRegister,
+ JITAssembler::EngineRegister,
PointerToValue(lhs),
PointerToValue(rhs));
} else {
@@ -145,14 +147,15 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
}
-void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
+template <typename JITAssembler>
+void Binop<JITAssembler>::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
FPRegisterID targetReg;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
targetReg = (FPRegisterID) targetTemp->index;
else
- targetReg = Assembler::FPGpr0;
+ targetReg = JITAssembler::FPGpr0;
switch (op) {
case IR::OpAdd:
@@ -162,7 +165,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
#if CPU(X86)
if (IR::Const *c = rhs->asConst()) { // Y = X + constant -> Y = X; Y += [constant-address]
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Address addr = as->loadConstant(c, Assembler::ScratchRegister);
+ Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
as->addDouble(addr, targetReg);
break;
}
@@ -174,7 +177,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
}
}
#endif
- as->addDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), as->toDoubleRegister(rhs, Assembler::FPGpr1), targetReg);
+ as->addDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
break;
case IR::OpMul:
@@ -184,7 +187,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
#if CPU(X86)
if (IR::Const *c = rhs->asConst()) { // Y = X * constant -> Y = X; Y *= [constant-address]
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Address addr = as->loadConstant(c, Assembler::ScratchRegister);
+ Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
as->mulDouble(addr, targetReg);
break;
}
@@ -196,14 +199,14 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
}
}
#endif
- as->mulDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), as->toDoubleRegister(rhs, Assembler::FPGpr1), targetReg);
+ as->mulDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
break;
case IR::OpSub:
#if CPU(X86)
if (IR::Const *c = rhs->asConst()) { // Y = X - constant -> Y = X; Y -= [constant-address]
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Address addr = as->loadConstant(c, Assembler::ScratchRegister);
+ Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
as->subDouble(addr, targetReg);
break;
}
@@ -219,19 +222,19 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
&& targetTemp
&& targetTemp->kind == IR::Temp::PhysicalRegister
&& targetTemp->index == rhs->asTemp()->index) { // Y = X - Y -> Tmp = Y; Y = X - Tmp
- as->moveDouble(as->toDoubleRegister(rhs, Assembler::FPGpr1), Assembler::FPGpr1);
- as->subDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), Assembler::FPGpr1, targetReg);
+ as->moveDouble(as->toDoubleRegister(rhs, JITAssembler::FPGpr1), JITAssembler::FPGpr1);
+ as->subDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), JITAssembler::FPGpr1, targetReg);
break;
}
- as->subDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), as->toDoubleRegister(rhs, Assembler::FPGpr1), targetReg);
+ as->subDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
break;
case IR::OpDiv:
#if CPU(X86)
if (IR::Const *c = rhs->asConst()) { // Y = X / constant -> Y = X; Y /= [constant-address]
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Address addr = as->loadConstant(c, Assembler::ScratchRegister);
+ Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
as->divDouble(addr, targetReg);
break;
}
@@ -248,12 +251,12 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
&& targetTemp
&& targetTemp->kind == IR::Temp::PhysicalRegister
&& targetTemp->index == rhs->asTemp()->index) { // Y = X / Y -> Tmp = Y; Y = X / Tmp
- as->moveDouble(as->toDoubleRegister(rhs, Assembler::FPGpr1), Assembler::FPGpr1);
- as->divDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), Assembler::FPGpr1, targetReg);
+ as->moveDouble(as->toDoubleRegister(rhs, JITAssembler::FPGpr1), JITAssembler::FPGpr1);
+ as->divDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), JITAssembler::FPGpr1, targetReg);
break;
}
- as->divDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), as->toDoubleRegister(rhs, Assembler::FPGpr1), targetReg);
+ as->divDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
break;
default: {
@@ -271,8 +274,8 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
as->storeDouble(targetReg, target);
}
-
-bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
+template <typename JITAssembler>
+bool Binop<JITAssembler>::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
Q_ASSERT(leftSource->type == IR::SInt32Type);
Q_ASSERT(rightSource->type == IR::SInt32Type);
@@ -305,7 +308,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
bool inplaceOpWithAddress = false;
IR::Temp *targetTemp = target->asTemp();
- RegisterID targetReg = Assembler::ReturnValueRegister;
+ RegisterID targetReg = JITAssembler::ReturnValueRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
IR::Temp *rhs = rightSource->asTemp();
if (!rhs || rhs->kind != IR::Temp::PhysicalRegister || rhs->index != targetTemp->index) {
@@ -369,12 +372,12 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
&& targetTemp->index == rightSource->asTemp()->index) {
// X = Y - X -> Tmp = X; X = Y; X -= Tmp
targetReg = (RegisterID) targetTemp->index;
- as->move(targetReg, Assembler::ScratchRegister);
+ as->move(targetReg, JITAssembler::ScratchRegister);
as->move(as->toInt32Register(leftSource, targetReg), targetReg);
- as->sub32(Assembler::ScratchRegister, targetReg);
+ as->sub32(JITAssembler::ScratchRegister, targetReg);
} else {
as->move(as->toInt32Register(leftSource, targetReg), targetReg);
- as->sub32(as->toInt32Register(rightSource, Assembler::ScratchRegister), targetReg);
+ as->sub32(as->toInt32Register(rightSource, JITAssembler::ScratchRegister), targetReg);
}
as->storeInt32(targetReg, target);
return true;
@@ -419,7 +422,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
return false;
}
} else if (inplaceOpWithAddress) { // All cases of X = X op [address-of-Y]
- Pointer rhsAddr = as->loadAddress(Assembler::ScratchRegister, rightSource);
+ Pointer rhsAddr = as->loadAddress(JITAssembler::ScratchRegister, rightSource);
switch (op) {
case IR::OpBitAnd: as->and32(rhsAddr, targetReg); break;
case IR::OpBitOr: as->or32 (rhsAddr, targetReg); break;
@@ -433,7 +436,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
return false;
}
} else { // All cases of Z = X op Y
- RegisterID r = as->toInt32Register(rightSource, Assembler::ScratchRegister);
+ RegisterID r = as->toInt32Register(rightSource, JITAssembler::ScratchRegister);
switch (op) {
case IR::OpBitAnd: as->and32(l, r, targetReg); break;
case IR::OpBitOr: as->or32 (l, r, targetReg); break;
@@ -452,18 +455,18 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
// Not all CPUs accept shifts over more than 31 bits, and some CPUs (like ARM) will do
// surprising stuff when shifting over 0 bits.
#define CHECK_RHS(op) { \
- as->and32(TrustedImm32(0x1f), r, Assembler::ScratchRegister); \
- Jump notZero = as->branch32(RelationalCondition::NotEqual, Assembler::ScratchRegister, TrustedImm32(0)); \
+ as->and32(TrustedImm32(0x1f), r, JITAssembler::ScratchRegister); \
+ Jump notZero = as->branch32(RelationalCondition::NotEqual, JITAssembler::ScratchRegister, TrustedImm32(0)); \
as->move(l, targetReg); \
Jump done = as->jump(); \
notZero.link(as); \
op; \
done.link(as); \
}
- case IR::OpLShift: CHECK_RHS(as->lshift32(l, Assembler::ScratchRegister, targetReg)); break;
- case IR::OpRShift: CHECK_RHS(as->rshift32(l, Assembler::ScratchRegister, targetReg)); break;
+ case IR::OpLShift: CHECK_RHS(as->lshift32(l, JITAssembler::ScratchRegister, targetReg)); break;
+ case IR::OpRShift: CHECK_RHS(as->rshift32(l, JITAssembler::ScratchRegister, targetReg)); break;
case IR::OpURShift:
- CHECK_RHS(as->urshift32(l, Assembler::ScratchRegister, targetReg));
+ CHECK_RHS(as->urshift32(l, JITAssembler::ScratchRegister, targetReg));
as->storeUInt32(targetReg, target);
// IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations!
return true;
@@ -481,17 +484,19 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
return true;
}
-static inline Assembler::FPRegisterID getFreeFPReg(IR::Expr *shouldNotOverlap, unsigned hint)
+template <typename JITAssembler>
+inline typename JITAssembler::FPRegisterID getFreeFPReg(IR::Expr *shouldNotOverlap, unsigned hint)
{
if (IR::Temp *t = shouldNotOverlap->asTemp())
if (t->type == IR::DoubleType)
if (t->kind == IR::Temp::PhysicalRegister)
if (t->index == hint)
- return Assembler::FPRegisterID(hint + 1);
- return Assembler::FPRegisterID(hint);
+ return typename JITAssembler::FPRegisterID(hint + 1);
+ return typename JITAssembler::FPRegisterID(hint);
}
-Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
+template <typename JITAssembler>
+typename JITAssembler::Jump Binop<JITAssembler>::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
Jump done;
@@ -505,8 +510,8 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
// register.
switch (op) {
case IR::OpAdd: {
- FPRegisterID lReg = getFreeFPReg(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg(leftSource, 4);
+ FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
+ FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
@@ -520,8 +525,8 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
rightIsNoDbl.link(as);
} break;
case IR::OpMul: {
- FPRegisterID lReg = getFreeFPReg(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg(leftSource, 4);
+ FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
+ FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
@@ -535,8 +540,8 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
rightIsNoDbl.link(as);
} break;
case IR::OpSub: {
- FPRegisterID lReg = getFreeFPReg(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg(leftSource, 4);
+ FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
+ FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
@@ -550,8 +555,8 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
rightIsNoDbl.link(as);
} break;
case IR::OpDiv: {
- FPRegisterID lReg = getFreeFPReg(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg(leftSource, 4);
+ FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
+ FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
@@ -571,4 +576,9 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
return done;
}
+template struct QV4::JIT::Binop<QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>>;
+#if defined(V4_BOOTSTRAP) && CPU(X86_64)
+template struct QV4::JIT::Binop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>>;
+#endif
+
#endif
diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h
index 3742e99e5a..d2d9ba7753 100644
--- a/src/qml/jit/qv4binop_p.h
+++ b/src/qml/jit/qv4binop_p.h
@@ -61,21 +61,22 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
+template <typename JITAssembler>
struct Binop {
- Binop(Assembler *assembler, IR::AluOp operation)
+ Binop(JITAssembler *assembler, IR::AluOp operation)
: as(assembler)
, op(operation)
{}
- using Jump = Assembler::Jump;
- using Address = Assembler::Address;
- using RegisterID = Assembler::RegisterID;
- using FPRegisterID = Assembler::FPRegisterID;
- using TrustedImm32 = Assembler::TrustedImm32;
- using ResultCondition = Assembler::ResultCondition;
- using RelationalCondition = Assembler::RelationalCondition;
- using Pointer = Assembler::Pointer;
- using PointerToValue = Assembler::PointerToValue;
+ using Jump = typename JITAssembler::Jump;
+ using Address = typename JITAssembler::Address;
+ using RegisterID = typename JITAssembler::RegisterID;
+ using FPRegisterID = typename JITAssembler::FPRegisterID;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+ using ResultCondition = typename JITAssembler::ResultCondition;
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using Pointer = typename JITAssembler::Pointer;
+ using PointerToValue = typename JITAssembler::PointerToValue;
void generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target);
void doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target);
@@ -103,8 +104,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
return as->branchAdd32(ResultCondition::Overflow, addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- return as->branchAdd32(ResultCondition::Overflow, Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ return as->branchAdd32(ResultCondition::Overflow, JITAssembler::ScratchRegister, reg);
#endif
}
@@ -118,8 +119,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
return as->branchSub32(ResultCondition::Overflow, addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- return as->branchSub32(ResultCondition::Overflow, Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ return as->branchSub32(ResultCondition::Overflow, JITAssembler::ScratchRegister, reg);
#endif
}
@@ -131,10 +132,10 @@ struct Binop {
Jump inline_mul32(Address addr, RegisterID reg)
{
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
- return as->branchMul32(Assembler::Overflow, addr, reg);
+ return as->branchMul32(JITAssembler::Overflow, addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- return as->branchMul32(ResultCondition::Overflow, Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ return as->branchMul32(ResultCondition::Overflow, JITAssembler::ScratchRegister, reg);
#endif
}
@@ -145,9 +146,9 @@ struct Binop {
Jump inline_shl32(Address addr, RegisterID reg)
{
- as->load32(addr, Assembler::ScratchRegister);
- as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister);
- as->lshift32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->and32(TrustedImm32(0x1f), JITAssembler::ScratchRegister);
+ as->lshift32(JITAssembler::ScratchRegister, reg);
return Jump();
}
@@ -160,9 +161,9 @@ struct Binop {
Jump inline_shr32(Address addr, RegisterID reg)
{
- as->load32(addr, Assembler::ScratchRegister);
- as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister);
- as->rshift32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->and32(TrustedImm32(0x1f), JITAssembler::ScratchRegister);
+ as->rshift32(JITAssembler::ScratchRegister, reg);
return Jump();
}
@@ -175,9 +176,9 @@ struct Binop {
Jump inline_ushr32(Address addr, RegisterID reg)
{
- as->load32(addr, Assembler::ScratchRegister);
- as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister);
- as->urshift32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->and32(TrustedImm32(0x1f), JITAssembler::ScratchRegister);
+ as->urshift32(JITAssembler::ScratchRegister, reg);
return as->branchTest32(ResultCondition::Signed, reg, reg);
}
@@ -193,8 +194,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
as->and32(addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- as->and32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->and32(JITAssembler::ScratchRegister, reg);
#endif
return Jump();
}
@@ -210,8 +211,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
as->or32(addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- as->or32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->or32(JITAssembler::ScratchRegister, reg);
#endif
return Jump();
}
@@ -227,8 +228,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
as->xor32(addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- as->xor32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->xor32(JITAssembler::ScratchRegister, reg);
#endif
return Jump();
}
@@ -241,7 +242,7 @@ struct Binop {
- Assembler *as;
+ JITAssembler *as;
IR::AluOp op;
};
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 20752b5c34..b1134d2bec 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -39,11 +39,7 @@
#include "qv4isel_masm_p.h"
#include "qv4runtime_p.h"
-#include "qv4object_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4regexpobject_p.h"
#include "qv4lookup_p.h"
-#include "qv4function_p.h"
#include "qv4ssa_p.h"
#include "qv4regalloc_p.h"
#include "qv4assembler_p.h"
@@ -68,7 +64,8 @@ using namespace QV4;
using namespace QV4::JIT;
-InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
+template <typename JITAssembler>
+InstructionSelection<JITAssembler>::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
: EvalInstructionSelection(execAllocator, module, jsGenerator, iselFactory)
, _block(0)
, _as(0)
@@ -79,12 +76,14 @@ InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::Ex
module->unitFlags |= QV4::CompiledData::Unit::ContainsMachineCode;
}
-InstructionSelection::~InstructionSelection()
+template <typename JITAssembler>
+InstructionSelection<JITAssembler>::~InstructionSelection()
{
delete _as;
}
-void InstructionSelection::run(int functionIndex)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::run(int functionIndex)
{
IR::Function *function = irModule->functions[functionIndex];
qSwap(_function, function);
@@ -93,8 +92,8 @@ void InstructionSelection::run(int functionIndex)
opt.run(qmlEngine);
static const bool withRegisterAllocator = qEnvironmentVariableIsEmpty("QV4_NO_REGALLOC");
- if (Assembler::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) {
- RegisterAllocator regalloc(Assembler::getRegisterInfo());
+ if (JITTargetPlatform::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) {
+ RegisterAllocator regalloc(JITTargetPlatform::getRegisterInfo());
regalloc.run(_function, opt);
calculateRegistersToSave(regalloc.usedRegisters());
} else {
@@ -103,47 +102,47 @@ void InstructionSelection::run(int functionIndex)
opt.convertOutOfSSA();
ConvertTemps().toStackSlots(_function);
IR::Optimizer::showMeTheCode(_function, "After stack slot allocation");
- calculateRegistersToSave(Assembler::getRegisterInfo()); // FIXME: this saves all registers. We can probably do with a subset: those that are not used by the register allocator.
+ calculateRegistersToSave(JITTargetPlatform::getRegisterInfo()); // FIXME: this saves all registers. We can probably do with a subset: those that are not used by the register allocator.
}
BitVector removableJumps = opt.calculateOptionalJumps();
qSwap(_removableJumps, removableJumps);
- Assembler* oldAssembler = _as;
- _as = new Assembler(jsGenerator, _function, executableAllocator);
+ JITAssembler* oldAssembler = _as;
+ _as = new JITAssembler(jsGenerator, _function, executableAllocator);
_as->setStackLayout(6, // 6 == max argc for calls to built-ins with an argument array
regularRegistersToSave.size(),
fpRegistersToSave.size());
_as->enterStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
#ifdef ARGUMENTS_IN_REGISTERS
- _as->move(_as->registerForArgument(0), Assembler::EngineRegister);
+ _as->move(_as->registerForArgument(0), JITTargetPlatform::EngineRegister);
#else
- _as->loadPtr(addressForArgument(0), Assembler::EngineRegister);
+ _as->loadPtr(addressForArgument(0), JITTargetPlatform::EngineRegister);
#endif
const int locals = _as->stackLayout().calculateJSStackFrameSize();
if (locals > 0) {
- _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)), Assembler::LocalsRegister);
+ _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)), JITTargetPlatform::LocalsRegister);
#ifdef VALUE_FITS_IN_REGISTER
- _as->move(Assembler::TrustedImm64(0), Assembler::ReturnValueRegister);
- _as->move(Assembler::TrustedImm32(locals), Assembler::ScratchRegister);
- Assembler::Label loop = _as->label();
- _as->store64(Assembler::ReturnValueRegister, Assembler::Address(Assembler::LocalsRegister));
- _as->add64(Assembler::TrustedImm32(8), Assembler::LocalsRegister);
- Assembler::Jump jump = _as->branchSub32(Assembler::NonZero, Assembler::TrustedImm32(1), Assembler::ScratchRegister);
+ _as->move(TrustedImm64(0), JITTargetPlatform::ReturnValueRegister);
+ _as->move(TrustedImm32(locals), JITTargetPlatform::ScratchRegister);
+ Label loop = _as->label();
+ _as->store64(JITTargetPlatform::ReturnValueRegister, Address(JITTargetPlatform::LocalsRegister));
+ _as->add64(TrustedImm32(8), JITTargetPlatform::LocalsRegister);
+ Jump jump = _as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), JITTargetPlatform::ScratchRegister);
jump.linkTo(loop, _as);
#else
- _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister);
- _as->move(Assembler::TrustedImm32(locals), Assembler::ScratchRegister);
- Assembler::Label loop = _as->label();
- _as->store32(Assembler::ReturnValueRegister, Assembler::Address(Assembler::LocalsRegister));
- _as->add32(Assembler::TrustedImm32(4), Assembler::LocalsRegister);
- _as->store32(Assembler::ReturnValueRegister, Assembler::Address(Assembler::LocalsRegister));
- _as->add32(Assembler::TrustedImm32(4), Assembler::LocalsRegister);
- Assembler::Jump jump = _as->branchSub32(Assembler::NonZero, Assembler::TrustedImm32(1), Assembler::ScratchRegister);
+ _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister);
+ _as->move(TrustedImm32(locals), JITTargetPlatform::ScratchRegister);
+ Label loop = _as->label();
+ _as->store32(JITTargetPlatform::ReturnValueRegister, Address(JITTargetPlatform::LocalsRegister));
+ _as->add32(TrustedImm32(4), JITTargetPlatform::LocalsRegister);
+ _as->store32(JITTargetPlatform::ReturnValueRegister, Address(JITTargetPlatform::LocalsRegister));
+ _as->add32(TrustedImm32(4), JITTargetPlatform::LocalsRegister);
+ Jump jump = _as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), JITTargetPlatform::ScratchRegister);
jump.linkTo(loop, _as);
#endif
- _as->storePtr(Assembler::LocalsRegister, Address(Assembler::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
+ _as->storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
}
@@ -158,9 +157,9 @@ void InstructionSelection::run(int functionIndex)
for (IR::Stmt *s : _block->statements()) {
if (s->location.isValid()) {
if (int(s->location.startLine) != lastLine) {
- _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- Assembler::Address lineAddr(Assembler::ScratchRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber));
- _as->store32(Assembler::TrustedImm32(s->location.startLine), lineAddr);
+ _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
+ Address lineAddr(JITTargetPlatform::ScratchRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber));
+ _as->store32(TrustedImm32(s->location.startLine), lineAddr);
lastLine = s->location.startLine;
}
}
@@ -181,165 +180,187 @@ void InstructionSelection::run(int functionIndex)
qSwap(_removableJumps, removableJumps);
}
-QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backendCompileStep()
+template <typename JITAssembler>
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection<JITAssembler>::backendCompileStep()
{
QQmlRefPointer<QV4::CompiledData::CompilationUnit> result;
result.adopt(compilationUnit.take());
return result;
}
-void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result)
{
prepareCallData(args, 0);
if (useFastLookups && func->global) {
uint index = registerGlobalGetterLookup(*func->id);
- generateRuntimeCall(result, callGlobalLookup,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(index),
+ generateRuntimeCall(_as, result, callGlobalLookup,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(index),
baseAddressForCallData());
} else {
- generateRuntimeCall(result, callActivationProperty,
- Assembler::EngineRegister,
- Assembler::StringToIndex(*func->id),
+ generateRuntimeCall(_as, result, callActivationProperty,
+ JITTargetPlatform::EngineRegister,
+ StringToIndex(*func->id),
baseAddressForCallData());
}
}
-void InstructionSelection::callBuiltinTypeofQmlContextProperty(IR::Expr *base,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofQmlContextProperty(IR::Expr *base,
IR::Member::MemberKind kind,
int propertyIndex, IR::Expr *result)
{
if (kind == IR::Member::MemberOfQmlScopeObject) {
- generateRuntimeCall(result, typeofScopeObjectProperty, Assembler::EngineRegister,
- Assembler::PointerToValue(base),
- Assembler::TrustedImm32(propertyIndex));
+ generateRuntimeCall(_as, result, typeofScopeObjectProperty, JITTargetPlatform::EngineRegister,
+ PointerToValue(base),
+ TrustedImm32(propertyIndex));
} else if (kind == IR::Member::MemberOfQmlContextObject) {
- generateRuntimeCall(result, typeofContextObjectProperty,
- Assembler::EngineRegister, Assembler::PointerToValue(base),
- Assembler::TrustedImm32(propertyIndex));
+ generateRuntimeCall(_as, result, typeofContextObjectProperty,
+ JITTargetPlatform::EngineRegister, PointerToValue(base),
+ TrustedImm32(propertyIndex));
} else {
Q_UNREACHABLE();
}
}
-void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString &name,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofMember(IR::Expr *base, const QString &name,
IR::Expr *result)
{
- generateRuntimeCall(result, typeofMember, Assembler::EngineRegister,
- Assembler::PointerToValue(base), Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, result, typeofMember, JITTargetPlatform::EngineRegister,
+ PointerToValue(base), StringToIndex(name));
}
-void InstructionSelection::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index,
IR::Expr *result)
{
- generateRuntimeCall(result, typeofElement,
- Assembler::EngineRegister,
- Assembler::PointerToValue(base), Assembler::PointerToValue(index));
+ generateRuntimeCall(_as, result, typeofElement,
+ JITTargetPlatform::EngineRegister,
+ PointerToValue(base), PointerToValue(index));
}
-void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofName(const QString &name, IR::Expr *result)
{
- generateRuntimeCall(result, typeofName, Assembler::EngineRegister,
- Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, result, typeofName, JITTargetPlatform::EngineRegister,
+ StringToIndex(name));
}
-void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result)
{
- generateRuntimeCall(result, typeofValue, Assembler::EngineRegister,
- Assembler::PointerToValue(value));
+ generateRuntimeCall(_as, result, typeofValue, JITTargetPlatform::EngineRegister,
+ PointerToValue(value));
}
-void InstructionSelection::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result)
{
- generateRuntimeCall(result, deleteMember, Assembler::EngineRegister,
- Assembler::Reference(base), Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, result, deleteMember, JITTargetPlatform::EngineRegister,
+ Reference(base), StringToIndex(name));
}
-void InstructionSelection::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index,
IR::Expr *result)
{
- generateRuntimeCall(result, deleteElement, Assembler::EngineRegister,
- Assembler::Reference(base), Assembler::PointerToValue(index));
+ generateRuntimeCall(_as, result, deleteElement, JITTargetPlatform::EngineRegister,
+ Reference(base), PointerToValue(index));
}
-void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeleteName(const QString &name, IR::Expr *result)
{
- generateRuntimeCall(result, deleteName, Assembler::EngineRegister,
- Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, result, deleteName, JITTargetPlatform::EngineRegister,
+ StringToIndex(name));
}
-void InstructionSelection::callBuiltinDeleteValue(IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeleteValue(IR::Expr *result)
{
_as->storeValue(Primitive::fromBoolean(false), result);
}
-void InstructionSelection::callBuiltinThrow(IR::Expr *arg)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinThrow(IR::Expr *arg)
{
- generateRuntimeCall(Assembler::ReturnValueRegister, throwException, Assembler::EngineRegister,
- Assembler::PointerToValue(arg));
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, throwException, JITTargetPlatform::EngineRegister,
+ PointerToValue(arg));
}
-void InstructionSelection::callBuiltinReThrow()
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinReThrow()
{
_as->jumpToExceptionHandler();
}
-void InstructionSelection::callBuiltinUnwindException(IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinUnwindException(IR::Expr *result)
{
- generateRuntimeCall(result, unwindException, Assembler::EngineRegister);
+ generateRuntimeCall(_as, result, unwindException, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionName)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinPushCatchScope(const QString &exceptionName)
{
- generateRuntimeCall(Assembler::Void, pushCatchScope, Assembler::EngineRegister, Assembler::StringToIndex(exceptionName));
+ generateRuntimeCall(_as, JITAssembler::Void, pushCatchScope, JITTargetPlatform::EngineRegister, StringToIndex(exceptionName));
}
-void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result)
{
Q_ASSERT(arg);
Q_ASSERT(result);
- generateRuntimeCall(result, foreachIterator, Assembler::EngineRegister, Assembler::PointerToValue(arg));
+ generateRuntimeCall(_as, result, foreachIterator, JITTargetPlatform::EngineRegister, PointerToValue(arg));
}
-void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result)
{
Q_ASSERT(arg);
Q_ASSERT(result);
- generateRuntimeCall(result, foreachNextPropertyName, Assembler::Reference(arg));
+ generateRuntimeCall(_as, result, foreachNextPropertyName, Reference(arg));
}
-void InstructionSelection::callBuiltinPushWithScope(IR::Expr *arg)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinPushWithScope(IR::Expr *arg)
{
Q_ASSERT(arg);
- generateRuntimeCall(Assembler::Void, pushWithScope, Assembler::Reference(arg), Assembler::EngineRegister);
+ generateRuntimeCall(_as, JITAssembler::Void, pushWithScope, Reference(arg), JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callBuiltinPopScope()
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinPopScope()
{
- generateRuntimeCall(Assembler::Void, popScope, Assembler::EngineRegister);
+ generateRuntimeCall(_as, JITAssembler::Void, popScope, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &name)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeclareVar(bool deletable, const QString &name)
{
- generateRuntimeCall(Assembler::Void, declareVar, Assembler::EngineRegister,
- Assembler::TrustedImm32(deletable), Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, JITAssembler::Void, declareVar, JITTargetPlatform::EngineRegister,
+ TrustedImm32(deletable), StringToIndex(name));
}
-void InstructionSelection::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args)
{
Q_ASSERT(result);
int length = prepareVariableArguments(args);
- generateRuntimeCall(result, arrayLiteral, Assembler::EngineRegister,
- baseAddressForCallArguments(), Assembler::TrustedImm32(length));
+ generateRuntimeCall(_as, result, arrayLiteral, JITTargetPlatform::EngineRegister,
+ baseAddressForCallArguments(), TrustedImm32(length));
}
-void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
{
Q_ASSERT(result);
@@ -415,81 +436,89 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int
it = it->next;
}
- generateRuntimeCall(result, objectLiteral, Assembler::EngineRegister,
- baseAddressForCallArguments(), Assembler::TrustedImm32(classId),
- Assembler::TrustedImm32(arrayValueCount), Assembler::TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30)));
+ generateRuntimeCall(_as, result, objectLiteral, JITTargetPlatform::EngineRegister,
+ baseAddressForCallArguments(), TrustedImm32(classId),
+ TrustedImm32(arrayValueCount), TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30)));
}
-void InstructionSelection::callBuiltinSetupArgumentObject(IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinSetupArgumentObject(IR::Expr *result)
{
- generateRuntimeCall(result, setupArgumentsObject, Assembler::EngineRegister);
+ generateRuntimeCall(_as, result, setupArgumentsObject, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callBuiltinConvertThisToObject()
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinConvertThisToObject()
{
- generateRuntimeCall(Assembler::Void, convertThisToObject, Assembler::EngineRegister);
+ generateRuntimeCall(_as, JITAssembler::Void, convertThisToObject, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
{
Q_ASSERT(value);
prepareCallData(args, 0);
if (value->asConst())
- generateRuntimeCall(result, callValue, Assembler::EngineRegister,
- Assembler::PointerToValue(value),
+ generateRuntimeCall(_as, result, callValue, JITTargetPlatform::EngineRegister,
+ PointerToValue(value),
baseAddressForCallData());
else
- generateRuntimeCall(result, callValue, Assembler::EngineRegister,
- Assembler::Reference(value),
+ generateRuntimeCall(_as, result, callValue, JITTargetPlatform::EngineRegister,
+ Reference(value),
baseAddressForCallData());
}
-void InstructionSelection::loadThisObject(IR::Expr *temp)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadThisObject(IR::Expr *temp)
{
- _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- _as->loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), Assembler::ScratchRegister);
+ _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
+ _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ScratchRegister);
#if defined(VALUE_FITS_IN_REGISTER)
- _as->load64(Pointer(Assembler::ScratchRegister, qOffsetOf(CallData, thisObject)),
- Assembler::ReturnValueRegister);
+ _as->load64(Pointer(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject)),
+ JITTargetPlatform::ReturnValueRegister);
_as->storeReturnValue(temp);
#else
- _as->copyValue(temp, Pointer(Assembler::ScratchRegister, qOffsetOf(CallData, thisObject)));
+ _as->copyValue(temp, Pointer(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject)));
#endif
}
-void InstructionSelection::loadQmlContext(IR::Expr *temp)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadQmlContext(IR::Expr *temp)
{
- generateRuntimeCall(temp, getQmlContext, Assembler::EngineRegister);
+ generateRuntimeCall(_as, temp, getQmlContext, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::loadQmlImportedScripts(IR::Expr *temp)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadQmlImportedScripts(IR::Expr *temp)
{
- generateRuntimeCall(temp, getQmlImportedScripts, Assembler::EngineRegister);
+ generateRuntimeCall(_as, temp, getQmlImportedScripts, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *temp)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadQmlSingleton(const QString &name, IR::Expr *temp)
{
- generateRuntimeCall(temp, getQmlSingleton, Assembler::EngineRegister, Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, temp, getQmlSingleton, JITTargetPlatform::EngineRegister, StringToIndex(name));
}
-void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadConst(IR::Const *sourceConst, IR::Expr *target)
{
if (IR::Temp *targetTemp = target->asTemp()) {
if (targetTemp->kind == IR::Temp::PhysicalRegister) {
if (targetTemp->type == IR::DoubleType) {
Q_ASSERT(sourceConst->type == IR::DoubleType);
- _as->toDoubleRegister(sourceConst, (Assembler::FPRegisterID) targetTemp->index);
+ _as->toDoubleRegister(sourceConst, (FPRegisterID) targetTemp->index);
} else if (targetTemp->type == IR::SInt32Type) {
Q_ASSERT(sourceConst->type == IR::SInt32Type);
- _as->toInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index);
+ _as->toInt32Register(sourceConst, (RegisterID) targetTemp->index);
} else if (targetTemp->type == IR::UInt32Type) {
Q_ASSERT(sourceConst->type == IR::UInt32Type);
- _as->toUInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index);
+ _as->toUInt32Register(sourceConst, (RegisterID) targetTemp->index);
} else if (targetTemp->type == IR::BoolType) {
Q_ASSERT(sourceConst->type == IR::BoolType);
- _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32()),
- (Assembler::RegisterID) targetTemp->index);
+ _as->move(TrustedImm32(convertToValue(sourceConst).int_32()),
+ (RegisterID) targetTemp->index);
} else {
Q_UNREACHABLE();
}
@@ -500,147 +529,155 @@ void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target)
_as->storeValue(convertToValue(sourceConst), target);
}
-void InstructionSelection::loadString(const QString &str, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadString(const QString &str, IR::Expr *target)
{
- Pointer srcAddr = _as->loadStringAddress(Assembler::ReturnValueRegister, str);
- _as->loadPtr(srcAddr, Assembler::ReturnValueRegister);
- Pointer destAddr = _as->loadAddress(Assembler::ScratchRegister, target);
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- _as->store64(Assembler::ReturnValueRegister, destAddr);
-#else
- _as->store32(Assembler::ReturnValueRegister, destAddr);
- destAddr.offset += 4;
- _as->store32(Assembler::TrustedImm32(QV4::Value::Managed_Type_Internal), destAddr);
-#endif
+ Pointer srcAddr = _as->loadStringAddress(JITTargetPlatform::ReturnValueRegister, str);
+ _as->loadPtr(srcAddr, JITTargetPlatform::ReturnValueRegister);
+ Pointer destAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, target);
+ JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr);
}
-void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target)
{
int id = registerRegExp(sourceRegexp);
- generateRuntimeCall(target, regexpLiteral, Assembler::EngineRegister, Assembler::TrustedImm32(id));
+ generateRuntimeCall(_as, target, regexpLiteral, JITTargetPlatform::EngineRegister, TrustedImm32(id));
}
-void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getActivationProperty(const IR::Name *name, IR::Expr *target)
{
if (useFastLookups && name->global) {
uint index = registerGlobalGetterLookup(*name->id);
- generateLookupCall(target, index, qOffsetOf(QV4::Lookup, globalGetter), Assembler::EngineRegister, Assembler::Void);
+ generateLookupCall(target, index, qOffsetOf(QV4::Lookup, globalGetter), JITTargetPlatform::EngineRegister, JITAssembler::Void);
return;
}
- generateRuntimeCall(target, getActivationProperty, Assembler::EngineRegister, Assembler::StringToIndex(*name->id));
+ generateRuntimeCall(_as, target, getActivationProperty, JITTargetPlatform::EngineRegister, StringToIndex(*name->id));
}
-void InstructionSelection::setActivationProperty(IR::Expr *source, const QString &targetName)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setActivationProperty(IR::Expr *source, const QString &targetName)
{
// ### should use a lookup call here
- generateRuntimeCall(Assembler::Void, setActivationProperty,
- Assembler::EngineRegister, Assembler::StringToIndex(targetName), Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setActivationProperty,
+ JITTargetPlatform::EngineRegister, StringToIndex(targetName), PointerToValue(source));
}
-void InstructionSelection::initClosure(IR::Closure *closure, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::initClosure(IR::Closure *closure, IR::Expr *target)
{
int id = closure->value;
- generateRuntimeCall(target, closure, Assembler::EngineRegister, Assembler::TrustedImm32(id));
+ generateRuntimeCall(_as, target, closure, JITTargetPlatform::EngineRegister, TrustedImm32(id));
}
-void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getProperty(IR::Expr *base, const QString &name, IR::Expr *target)
{
if (useFastLookups) {
uint index = registerGetterLookup(name);
- generateLookupCall(target, index, qOffsetOf(QV4::Lookup, getter), Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::Void);
+ generateLookupCall(target, index, qOffsetOf(QV4::Lookup, getter), JITTargetPlatform::EngineRegister, PointerToValue(base), JITAssembler::Void);
} else {
- generateRuntimeCall(target, getProperty, Assembler::EngineRegister,
- Assembler::PointerToValue(base), Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, target, getProperty, JITTargetPlatform::EngineRegister,
+ PointerToValue(base), StringToIndex(name));
}
}
-void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target)
{
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(target, getQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index), Assembler::TrustedImm32(captureRequired));
+ generateRuntimeCall(_as, target, getQmlScopeObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index), TrustedImm32(captureRequired));
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(target, getQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index), Assembler::TrustedImm32(captureRequired));
+ generateRuntimeCall(_as, target, getQmlContextObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index), TrustedImm32(captureRequired));
else if (kind == IR::Member::MemberOfIdObjectsArray)
- generateRuntimeCall(target, getQmlIdObject, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
+ generateRuntimeCall(_as, target, getQmlIdObject, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index));
else
Q_ASSERT(false);
}
-void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
{
if (attachedPropertiesId != 0)
- generateRuntimeCall(target, getQmlAttachedProperty, Assembler::EngineRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex));
+ generateRuntimeCall(_as, target, getQmlAttachedProperty, JITTargetPlatform::EngineRegister, TrustedImm32(attachedPropertiesId), TrustedImm32(propertyIndex));
else if (isSingleton)
- generateRuntimeCall(target, getQmlSingletonQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
- Assembler::TrustedImm32(captureRequired));
+ generateRuntimeCall(_as, target, getQmlSingletonQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(propertyIndex),
+ TrustedImm32(captureRequired));
else
- generateRuntimeCall(target, getQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
- Assembler::TrustedImm32(captureRequired));
+ generateRuntimeCall(_as, target, getQmlQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(propertyIndex),
+ TrustedImm32(captureRequired));
}
-void InstructionSelection::setProperty(IR::Expr *source, IR::Expr *targetBase,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setProperty(IR::Expr *source, IR::Expr *targetBase,
const QString &targetName)
{
if (useFastLookups) {
uint index = registerSetterLookup(targetName);
- generateLookupCall(Assembler::Void, index, qOffsetOf(QV4::Lookup, setter),
- Assembler::EngineRegister,
- Assembler::PointerToValue(targetBase),
- Assembler::PointerToValue(source));
+ generateLookupCall(JITAssembler::Void, index, qOffsetOf(QV4::Lookup, setter),
+ JITTargetPlatform::EngineRegister,
+ PointerToValue(targetBase),
+ PointerToValue(source));
} else {
- generateRuntimeCall(Assembler::Void, setProperty, Assembler::EngineRegister,
- Assembler::PointerToValue(targetBase), Assembler::StringToIndex(targetName),
- Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setProperty, JITTargetPlatform::EngineRegister,
+ PointerToValue(targetBase), StringToIndex(targetName),
+ PointerToValue(source));
}
}
-void InstructionSelection::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex)
{
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(Assembler::Void, setQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
- Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setQmlScopeObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase),
+ TrustedImm32(propertyIndex), PointerToValue(source));
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(Assembler::Void, setQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
- Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setQmlContextObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase),
+ TrustedImm32(propertyIndex), PointerToValue(source));
else
Q_ASSERT(false);
}
-void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex)
{
- generateRuntimeCall(Assembler::Void, setQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
- Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setQmlQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase),
+ TrustedImm32(propertyIndex), PointerToValue(source));
}
-void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
{
if (useFastLookups) {
uint lookup = registerIndexedGetterLookup();
generateLookupCall(target, lookup, qOffsetOf(QV4::Lookup, indexedGetter),
- Assembler::PointerToValue(base),
- Assembler::PointerToValue(index));
+ PointerToValue(base),
+ PointerToValue(index));
return;
}
- generateRuntimeCall(target, getElement, Assembler::EngineRegister,
- Assembler::PointerToValue(base), Assembler::PointerToValue(index));
+ generateRuntimeCall(_as, target, getElement, JITTargetPlatform::EngineRegister,
+ PointerToValue(base), PointerToValue(index));
}
-void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex)
{
if (useFastLookups) {
uint lookup = registerIndexedSetterLookup();
- generateLookupCall(Assembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter),
- Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex),
- Assembler::PointerToValue(source));
+ generateLookupCall(JITAssembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter),
+ PointerToValue(targetBase), PointerToValue(targetIndex),
+ PointerToValue(source));
return;
}
- generateRuntimeCall(Assembler::Void, setElement, Assembler::EngineRegister,
- Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex),
- Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setElement, JITTargetPlatform::EngineRegister,
+ PointerToValue(targetBase), PointerToValue(targetIndex),
+ PointerToValue(source));
}
-void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::copyValue(IR::Expr *source, IR::Expr *target)
{
IR::Temp *sourceTemp = source->asTemp();
IR::Temp *targetTemp = target->asTemp();
@@ -655,25 +692,25 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) {
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
if (sourceTemp->type == IR::DoubleType)
- _as->moveDouble((Assembler::FPRegisterID) sourceTemp->index,
- (Assembler::FPRegisterID) targetTemp->index);
+ _as->moveDouble((FPRegisterID) sourceTemp->index,
+ (FPRegisterID) targetTemp->index);
else
- _as->move((Assembler::RegisterID) sourceTemp->index,
- (Assembler::RegisterID) targetTemp->index);
+ _as->move((RegisterID) sourceTemp->index,
+ (RegisterID) targetTemp->index);
return;
} else {
switch (sourceTemp->type) {
case IR::DoubleType:
- _as->storeDouble((Assembler::FPRegisterID) sourceTemp->index, target);
+ _as->storeDouble((FPRegisterID) sourceTemp->index, target);
break;
case IR::SInt32Type:
- _as->storeInt32((Assembler::RegisterID) sourceTemp->index, target);
+ _as->storeInt32((RegisterID) sourceTemp->index, target);
break;
case IR::UInt32Type:
- _as->storeUInt32((Assembler::RegisterID) sourceTemp->index, target);
+ _as->storeUInt32((RegisterID) sourceTemp->index, target);
break;
case IR::BoolType:
- _as->storeBool((Assembler::RegisterID) sourceTemp->index, target);
+ _as->storeBool((RegisterID) sourceTemp->index, target);
break;
default:
Q_ASSERT(!"Unreachable");
@@ -685,19 +722,19 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
switch (targetTemp->type) {
case IR::DoubleType:
Q_ASSERT(source->type == IR::DoubleType);
- _as->toDoubleRegister(source, (Assembler::FPRegisterID) targetTemp->index);
+ _as->toDoubleRegister(source, (FPRegisterID) targetTemp->index);
return;
case IR::BoolType:
Q_ASSERT(source->type == IR::BoolType);
- _as->toInt32Register(source, (Assembler::RegisterID) targetTemp->index);
+ _as->toInt32Register(source, (RegisterID) targetTemp->index);
return;
case IR::SInt32Type:
Q_ASSERT(source->type == IR::SInt32Type);
- _as->toInt32Register(source, (Assembler::RegisterID) targetTemp->index);
+ _as->toInt32Register(source, (RegisterID) targetTemp->index);
return;
case IR::UInt32Type:
Q_ASSERT(source->type == IR::UInt32Type);
- _as->toUInt32Register(source, (Assembler::RegisterID) targetTemp->index);
+ _as->toUInt32Register(source, (RegisterID) targetTemp->index);
return;
default:
Q_ASSERT(!"Unreachable");
@@ -706,10 +743,11 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
}
// The target is not a physical register, nor is the source. So we can do a memory-to-memory copy:
- _as->memcopyValue(_as->loadAddress(Assembler::ReturnValueRegister, target), source, Assembler::ScratchRegister);
+ _as->memcopyValue(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, target), source, JITTargetPlatform::ScratchRegister);
}
-void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *target)
{
IR::Temp *sourceTemp = source->asTemp();
IR::Temp *targetTemp = target->asTemp();
@@ -719,26 +757,27 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
Q_ASSERT(sourceTemp->type == targetTemp->type);
if (sourceTemp->type == IR::DoubleType) {
- _as->moveDouble((Assembler::FPRegisterID) targetTemp->index, Assembler::FPGpr0);
- _as->moveDouble((Assembler::FPRegisterID) sourceTemp->index,
- (Assembler::FPRegisterID) targetTemp->index);
- _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) sourceTemp->index);
+ _as->moveDouble((FPRegisterID) targetTemp->index, JITTargetPlatform::FPGpr0);
+ _as->moveDouble((FPRegisterID) sourceTemp->index,
+ (FPRegisterID) targetTemp->index);
+ _as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) sourceTemp->index);
} else {
- _as->swap((Assembler::RegisterID) sourceTemp->index,
- (Assembler::RegisterID) targetTemp->index);
+ _as->swap((RegisterID) sourceTemp->index,
+ (RegisterID) targetTemp->index);
}
return;
}
} else if (!sourceTemp || sourceTemp->kind == IR::Temp::StackSlot) {
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
// Note: a swap for two stack-slots can involve different types.
- Assembler::Pointer sAddr = _as->loadAddress(Assembler::ScratchRegister, source);
- Assembler::Pointer tAddr = _as->loadAddress(Assembler::ReturnValueRegister, target);
+ Pointer sAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer tAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target);
// use the implementation in JSC::MacroAssembler, as it doesn't do bit swizzling
- _as->JSC::MacroAssembler::loadDouble(sAddr, Assembler::FPGpr0);
- _as->JSC::MacroAssembler::loadDouble(tAddr, Assembler::FPGpr1);
- _as->JSC::MacroAssembler::storeDouble(Assembler::FPGpr1, sAddr);
- _as->JSC::MacroAssembler::storeDouble(Assembler::FPGpr0, tAddr);
+ auto platformAs = static_cast<typename JITAssembler::MacroAssembler*>(_as);
+ platformAs->loadDouble(sAddr, JITTargetPlatform::FPGpr0);
+ platformAs->loadDouble(tAddr, JITTargetPlatform::FPGpr1);
+ platformAs->storeDouble(JITTargetPlatform::FPGpr1, sAddr);
+ platformAs->storeDouble(JITTargetPlatform::FPGpr0, tAddr);
return;
}
}
@@ -749,18 +788,18 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
Q_ASSERT(memExpr);
Q_ASSERT(regTemp);
- Assembler::Pointer addr = _as->loadAddress(Assembler::ReturnValueRegister, memExpr);
+ Pointer addr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, memExpr);
if (regTemp->type == IR::DoubleType) {
- _as->loadDouble(addr, Assembler::FPGpr0);
- _as->storeDouble((Assembler::FPRegisterID) regTemp->index, addr);
- _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) regTemp->index);
+ _as->loadDouble(addr, JITTargetPlatform::FPGpr0);
+ _as->storeDouble((FPRegisterID) regTemp->index, addr);
+ _as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) regTemp->index);
} else if (regTemp->type == IR::UInt32Type) {
- _as->toUInt32Register(addr, Assembler::ScratchRegister);
- _as->storeUInt32((Assembler::RegisterID) regTemp->index, addr);
- _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) regTemp->index);
+ _as->toUInt32Register(addr, JITTargetPlatform::ScratchRegister);
+ _as->storeUInt32((RegisterID) regTemp->index, addr);
+ _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index);
} else {
- _as->load32(addr, Assembler::ScratchRegister);
- _as->store32((Assembler::RegisterID) regTemp->index, addr);
+ _as->load32(addr, JITTargetPlatform::ScratchRegister);
+ _as->store32((RegisterID) regTemp->index, addr);
if (regTemp->type != memExpr->type) {
addr.offset += 4;
quint32 tag;
@@ -775,55 +814,59 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
tag = 31337; // bogus value
Q_UNREACHABLE();
}
- _as->store32(Assembler::TrustedImm32(tag), addr);
+ _as->store32(TrustedImm32(tag), addr);
}
- _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) regTemp->index);
+ _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index);
}
}
#define setOp(op, opName, operation) \
do { \
- op = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
+ op = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \
} while (0)
#define setOpContext(op, opName, operation) \
do { \
- opContext = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
+ opContext = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \
} while (0)
-void InstructionSelection::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target)
{
- QV4::JIT::Unop unop(_as, oper);
+ QV4::JIT::Unop<JITAssembler> unop(_as, oper);
unop.generate(source, target);
}
-void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
- QV4::JIT::Binop binop(_as, oper);
+ QV4::JIT::Binop<JITAssembler> binop(_as, oper);
binop.generate(leftSource, rightSource, target);
}
-void InstructionSelection::callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result)
{
prepareCallData(args, base);
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(result, callQmlScopeObjectProperty,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(propertyIndex),
+ generateRuntimeCall(_as, result, callQmlScopeObjectProperty,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(propertyIndex),
baseAddressForCallData());
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(result, callQmlContextObjectProperty,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(propertyIndex),
+ generateRuntimeCall(_as, result, callQmlContextObjectProperty,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(propertyIndex),
baseAddressForCallData());
else
Q_ASSERT(false);
}
-void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
IR::Expr *result)
{
Q_ASSERT(base != 0);
@@ -832,29 +875,31 @@ void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR:
if (useFastLookups) {
uint index = registerGetterLookup(name);
- generateRuntimeCall(result, callPropertyLookup,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(index),
+ generateRuntimeCall(_as, result, callPropertyLookup,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(index),
baseAddressForCallData());
} else {
- generateRuntimeCall(result, callProperty, Assembler::EngineRegister,
- Assembler::StringToIndex(name),
+ generateRuntimeCall(_as, result, callProperty, JITTargetPlatform::EngineRegister,
+ StringToIndex(name),
baseAddressForCallData());
}
}
-void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
IR::Expr *result)
{
Q_ASSERT(base != 0);
prepareCallData(args, base);
- generateRuntimeCall(result, callElement, Assembler::EngineRegister,
- Assembler::PointerToValue(index),
+ generateRuntimeCall(_as, result, callElement, JITTargetPlatform::EngineRegister,
+ PointerToValue(index),
baseAddressForCallData());
}
-void InstructionSelection::convertType(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertType(IR::Expr *source, IR::Expr *target)
{
switch (target->type) {
case IR::DoubleType:
@@ -875,7 +920,8 @@ void InstructionSelection::convertType(IR::Expr *source, IR::Expr *target)
}
}
-void InstructionSelection::convertTypeSlowPath(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeSlowPath(IR::Expr *source, IR::Expr *target)
{
Q_ASSERT(target->type != IR::BoolType);
@@ -885,7 +931,8 @@ void InstructionSelection::convertTypeSlowPath(IR::Expr *source, IR::Expr *targe
copyValue(source, target);
}
-void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, IR::Expr *target)
{
switch (source->type) {
case IR::SInt32Type:
@@ -897,51 +944,37 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *targe
convertUIntToDouble(source, target);
break;
case IR::UndefinedType:
- _as->loadDouble(_as->loadAddress(Assembler::ScratchRegister, source), Assembler::FPGpr0);
- _as->storeDouble(Assembler::FPGpr0, target);
+ _as->loadDouble(_as->loadAddress(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0);
+ _as->storeDouble(JITTargetPlatform::FPGpr0, target);
break;
case IR::StringType:
case IR::VarType: {
// load the tag:
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, source);
+ Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ScratchRegister);
+ _as->load32(tagAddr, JITTargetPlatform::ScratchRegister);
// check if it's an int32:
- Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
+ Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
+ TrustedImm32(Value::Integer_Type_Internal));
convertIntToDouble(source, target);
- Assembler::Jump intDone = _as->jump();
+ Jump intDone = _as->jump();
// not an int, check if it's NOT a double:
isNoInt.link(_as);
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- _as->rshift32(Assembler::TrustedImm32(Value::IsDoubleTag_Shift), Assembler::ScratchRegister);
- Assembler::Jump isDbl = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(0));
-#else
- _as->and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister);
- Assembler::Jump isDbl = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::NotDouble_Mask));
-#endif
+ Jump isDbl = _as->generateIsDoubleCheck(JITTargetPlatform::ScratchRegister);
- generateRuntimeCall(target, toDouble, Assembler::PointerToValue(source));
- Assembler::Jump noDoubleDone = _as->jump();
+ generateRuntimeCall(_as, target, toDouble, PointerToValue(source));
+ Jump noDoubleDone = _as->jump();
// it is a double:
isDbl.link(_as);
- Assembler::Pointer addr2 = _as->loadAddress(Assembler::ScratchRegister, source);
+ Pointer addr2 = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
IR::Temp *targetTemp = target->asTemp();
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
-#if Q_PROCESSOR_WORDSIZE == 8
- _as->load64(addr2, Assembler::ScratchRegister);
- _as->store64(Assembler::ScratchRegister, _as->loadAddress(Assembler::ReturnValueRegister, target));
-#else
- _as->loadDouble(addr2, Assembler::FPGpr0);
- _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(Assembler::ReturnValueRegister, target));
-#endif
+ _as->memcopyValue(target, addr2, JITTargetPlatform::FPGpr0, JITTargetPlatform::ReturnValueRegister);
} else {
- _as->loadDouble(addr2, (Assembler::FPRegisterID) targetTemp->index);
+ _as->loadDouble(addr2, (FPRegisterID) targetTemp->index);
}
noDoubleDone.link(_as);
@@ -953,7 +986,8 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *targe
}
}
-void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeToBool(IR::Expr *source, IR::Expr *target)
{
IR::Temp *sourceTemp = source->asTemp();
switch (source->type) {
@@ -965,16 +999,16 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target)
// The source is in a register if the register allocator is used. If the register
// allocator was not used, then that means that we can use any register for to
// load the double into.
- Assembler::FPRegisterID reg;
+ FPRegisterID reg;
if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister)
- reg = (Assembler::FPRegisterID) sourceTemp->index;
+ reg = (FPRegisterID) sourceTemp->index;
else
- reg = _as->toDoubleRegister(source, (Assembler::FPRegisterID) 1);
- Assembler::Jump nonZero = _as->branchDoubleNonZero(reg, Assembler::FPGpr0);
+ reg = _as->toDoubleRegister(source, (FPRegisterID) 1);
+ Jump nonZero = _as->branchDoubleNonZero(reg, JITTargetPlatform::FPGpr0);
// it's 0, so false:
_as->storeBool(false, target);
- Assembler::Jump done = _as->jump();
+ Jump done = _as->jump();
// it's non-zero, so true:
nonZero.link(_as);
@@ -988,283 +1022,220 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target)
_as->storeBool(false, target);
break;
case IR::StringType:
- generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean,
- Assembler::PointerToValue(source));
- _as->storeBool(Assembler::ReturnValueRegister, target);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
+ PointerToValue(source));
+ _as->storeBool(JITTargetPlatform::ReturnValueRegister, target);
case IR::VarType:
default:
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
- Assembler::Pointer tagAddr = addr;
+ Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer tagAddr = addr;
tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ReturnValueRegister);
+ _as->load32(tagAddr, JITTargetPlatform::ReturnValueRegister);
// checkif it's a bool:
- Assembler::Jump notBool = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
- Assembler::TrustedImm32(Value::Boolean_Type_Internal));
- _as->load32(addr, Assembler::ReturnValueRegister);
- Assembler::Jump boolDone = _as->jump();
+ Jump notBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister,
+ TrustedImm32(Value::Boolean_Type_Internal));
+ _as->load32(addr, JITTargetPlatform::ReturnValueRegister);
+ Jump boolDone = _as->jump();
// check if it's an int32:
notBool.link(_as);
- Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
- _as->load32(addr, Assembler::ReturnValueRegister);
- Assembler::Jump isZero = _as->branch32(Assembler::Equal, Assembler::ReturnValueRegister,
- Assembler::TrustedImm32(0));
- _as->move(Assembler::TrustedImm32(1), Assembler::ReturnValueRegister);
- Assembler::Jump intDone = _as->jump();
+ Jump fallback = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister,
+ TrustedImm32(Value::Integer_Type_Internal));
+ _as->load32(addr, JITTargetPlatform::ReturnValueRegister);
+ Jump isZero = _as->branch32(RelationalCondition::Equal, JITTargetPlatform::ReturnValueRegister,
+ TrustedImm32(0));
+ _as->move(TrustedImm32(1), JITTargetPlatform::ReturnValueRegister);
+ Jump intDone = _as->jump();
// not an int:
fallback.link(_as);
- generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean,
- Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
+ PointerToValue(source));
isZero.link(_as);
intDone.link(_as);
boolDone.link(_as);
- _as->storeBool(Assembler::ReturnValueRegister, target);
+ _as->storeBool(JITTargetPlatform::ReturnValueRegister, target);
break;
}
}
-void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeToSInt32(IR::Expr *source, IR::Expr *target)
{
switch (source->type) {
case IR::VarType: {
-
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
- _as->load64(addr, Assembler::ScratchRegister);
- _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
-
- // check if it's integer convertible
- _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsIntegerConvertible_Shift), Assembler::ScratchRegister);
- Assembler::Jump isIntConvertible = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(3));
-
- // nope, not integer convertible, so check for a double:
- _as->urshift64(Assembler::TrustedImm32(
- QV4::Value::IsDoubleTag_Shift - QV4::Value::IsIntegerConvertible_Shift),
- Assembler::ScratchRegister);
- Assembler::Jump fallback = _as->branch32(Assembler::GreaterThan, Assembler::ScratchRegister, Assembler::TrustedImm32(0));
-
- // it's a double
- _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister);
- _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
- _as->move64ToDouble(Assembler::ReturnValueRegister, Assembler::FPGpr0);
- Assembler::Jump success =
- _as->branchTruncateDoubleToInt32(Assembler::FPGpr0, Assembler::ReturnValueRegister,
- Assembler::BranchIfTruncateSuccessful);
-
- // not an int:
- fallback.link(_as);
- generateRuntimeCall(Assembler::ReturnValueRegister, toInt,
- _as->loadAddress(Assembler::ScratchRegister, source));
-
- isIntConvertible.link(_as);
- success.link(_as);
- IR::Temp *targetTemp = target->asTemp();
- if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
- Assembler::Pointer targetAddr = _as->loadAddress(Assembler::ScratchRegister, target);
- _as->store32(Assembler::ReturnValueRegister, targetAddr);
- targetAddr.offset += 4;
- _as->store32(Assembler::TrustedImm32(Value::Integer_Type_Internal), targetAddr);
- } else {
- _as->storeInt32(Assembler::ReturnValueRegister, target);
- }
-#else
- // load the tag:
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
- Assembler::Pointer tagAddr = addr;
- tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ReturnValueRegister);
-
- // check if it's an int32:
- Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
- IR::Temp *targetTemp = target->asTemp();
- if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
- _as->load32(addr, Assembler::ReturnValueRegister);
- Assembler::Pointer targetAddr = _as->loadAddress(Assembler::ScratchRegister, target);
- _as->store32(Assembler::ReturnValueRegister, targetAddr);
- targetAddr.offset += 4;
- _as->store32(Assembler::TrustedImm32(Value::Integer_Type_Internal), targetAddr);
- } else {
- _as->load32(addr, (Assembler::RegisterID) targetTemp->index);
- }
- Assembler::Jump intDone = _as->jump();
-
- // not an int:
- fallback.link(_as);
- generateRuntimeCall(Assembler::ReturnValueRegister, toInt,
- _as->loadAddress(Assembler::ScratchRegister, source));
- _as->storeInt32(Assembler::ReturnValueRegister, target);
-
- intDone.link(_as);
-#endif
-
+ JITAssembler::RegisterSizeDependentOps::convertVarToSInt32(_as, source, target);
} break;
case IR::DoubleType: {
- Assembler::Jump success =
+ Jump success =
_as->branchTruncateDoubleToInt32(_as->toDoubleRegister(source),
- Assembler::ReturnValueRegister,
- Assembler::BranchIfTruncateSuccessful);
- generateRuntimeCall(Assembler::ReturnValueRegister, doubleToInt,
- Assembler::PointerToValue(source));
+ JITTargetPlatform::ReturnValueRegister,
+ BranchTruncateType::BranchIfTruncateSuccessful);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, doubleToInt,
+ PointerToValue(source));
success.link(_as);
- _as->storeInt32(Assembler::ReturnValueRegister, target);
+ _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
} break;
case IR::UInt32Type:
- _as->storeInt32(_as->toUInt32Register(source, Assembler::ReturnValueRegister), target);
+ _as->storeInt32(_as->toUInt32Register(source, JITTargetPlatform::ReturnValueRegister), target);
break;
case IR::NullType:
case IR::UndefinedType:
- _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister);
- _as->storeInt32(Assembler::ReturnValueRegister, target);
+ _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister);
+ _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
case IR::BoolType:
- _as->storeInt32(_as->toInt32Register(source, Assembler::ReturnValueRegister), target);
+ _as->storeInt32(_as->toInt32Register(source, JITTargetPlatform::ReturnValueRegister), target);
break;
case IR::StringType:
default:
- generateRuntimeCall(Assembler::ReturnValueRegister, toInt,
- _as->loadAddress(Assembler::ScratchRegister, source));
- _as->storeInt32(Assembler::ReturnValueRegister, target);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toInt,
+ _as->loadAddress(JITTargetPlatform::ScratchRegister, source));
+ _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
} // switch (source->type)
}
-void InstructionSelection::convertTypeToUInt32(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeToUInt32(IR::Expr *source, IR::Expr *target)
{
switch (source->type) {
case IR::VarType: {
// load the tag:
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, source);
+ Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ScratchRegister);
+ _as->load32(tagAddr, JITTargetPlatform::ScratchRegister);
// check if it's an int32:
- Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
- _as->storeUInt32(_as->toInt32Register(addr, Assembler::ScratchRegister), target);
- Assembler::Jump intDone = _as->jump();
+ Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
+ TrustedImm32(Value::Integer_Type_Internal));
+ Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ _as->storeUInt32(_as->toInt32Register(addr, JITTargetPlatform::ScratchRegister), target);
+ Jump intDone = _as->jump();
// not an int:
isNoInt.link(_as);
- generateRuntimeCall(Assembler::ReturnValueRegister, toUInt,
- _as->loadAddress(Assembler::ScratchRegister, source));
- _as->storeInt32(Assembler::ReturnValueRegister, target);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt,
+ _as->loadAddress(JITTargetPlatform::ScratchRegister, source));
+ _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
intDone.link(_as);
} break;
case IR::DoubleType: {
- Assembler::FPRegisterID reg = _as->toDoubleRegister(source);
- Assembler::Jump success =
- _as->branchTruncateDoubleToUint32(reg, Assembler::ReturnValueRegister,
- Assembler::BranchIfTruncateSuccessful);
- generateRuntimeCall(Assembler::ReturnValueRegister, doubleToUInt,
- Assembler::PointerToValue(source));
+ FPRegisterID reg = _as->toDoubleRegister(source);
+ Jump success =
+ _as->branchTruncateDoubleToUint32(reg, JITTargetPlatform::ReturnValueRegister,
+ BranchTruncateType::BranchIfTruncateSuccessful);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, doubleToUInt,
+ PointerToValue(source));
success.link(_as);
- _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target);
} break;
case IR::NullType:
case IR::UndefinedType:
- _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister);
- _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister);
+ _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
case IR::StringType:
- generateRuntimeCall(Assembler::ReturnValueRegister, toUInt,
- Assembler::PointerToValue(source));
- _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt,
+ PointerToValue(source));
+ _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
case IR::SInt32Type:
case IR::BoolType:
- _as->storeUInt32(_as->toInt32Register(source, Assembler::ReturnValueRegister), target);
+ _as->storeUInt32(_as->toInt32Register(source, JITTargetPlatform::ReturnValueRegister), target);
break;
default:
break;
} // switch (source->type)
}
-void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result)
{
Q_ASSERT(func != 0);
prepareCallData(args, 0);
if (useFastLookups && func->global) {
uint index = registerGlobalGetterLookup(*func->id);
- generateRuntimeCall(result, constructGlobalLookup,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(index), baseAddressForCallData());
+ generateRuntimeCall(_as, result, constructGlobalLookup,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(index), baseAddressForCallData());
return;
}
- generateRuntimeCall(result, constructActivationProperty,
- Assembler::EngineRegister,
- Assembler::StringToIndex(*func->id),
+ generateRuntimeCall(_as, result, constructActivationProperty,
+ JITTargetPlatform::EngineRegister,
+ StringToIndex(*func->id),
baseAddressForCallData());
}
-void InstructionSelection::constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result)
{
prepareCallData(args, base);
if (useFastLookups) {
uint index = registerGetterLookup(name);
- generateRuntimeCall(result, constructPropertyLookup,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(index),
+ generateRuntimeCall(_as, result, constructPropertyLookup,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(index),
baseAddressForCallData());
return;
}
- generateRuntimeCall(result, constructProperty, Assembler::EngineRegister,
- Assembler::StringToIndex(name),
+ generateRuntimeCall(_as, result, constructProperty, JITTargetPlatform::EngineRegister,
+ StringToIndex(name),
baseAddressForCallData());
}
-void InstructionSelection::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
{
Q_ASSERT(value != 0);
prepareCallData(args, 0);
- generateRuntimeCall(result, constructValue,
- Assembler::EngineRegister,
- Assembler::Reference(value),
+ generateRuntimeCall(_as, result, constructValue,
+ JITTargetPlatform::EngineRegister,
+ Reference(value),
baseAddressForCallData());
}
-void InstructionSelection::visitJump(IR::Jump *s)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitJump(IR::Jump *s)
{
if (!_removableJumps.at(_block->index()))
_as->jumpToBlock(_block, s->target);
}
-void InstructionSelection::visitCJump(IR::CJump *s)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitCJump(IR::CJump *s)
{
IR::Temp *t = s->cond->asTemp();
if (t || s->cond->asArgLocal()) {
- Assembler::RegisterID reg;
+ RegisterID reg;
if (t && t->kind == IR::Temp::PhysicalRegister) {
Q_ASSERT(t->type == IR::BoolType);
- reg = (Assembler::RegisterID) t->index;
+ reg = (RegisterID) t->index;
} else if (t && t->kind == IR::Temp::StackSlot && t->type == IR::BoolType) {
- reg = Assembler::ReturnValueRegister;
+ reg = JITTargetPlatform::ReturnValueRegister;
_as->toInt32Register(t, reg);
} else {
- Address temp = _as->loadAddress(Assembler::ScratchRegister, s->cond);
+ Address temp = _as->loadAddress(JITTargetPlatform::ScratchRegister, s->cond);
Address tag = temp;
tag.offset += QV4::Value::tagOffset();
- Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal));
+ Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag, TrustedImm32(QV4::Value::Boolean_Type_Internal));
Address data = temp;
data.offset += QV4::Value::valueOffset();
- _as->load32(data, Assembler::ReturnValueRegister);
- Assembler::Jump testBoolean = _as->jump();
+ _as->load32(data, JITTargetPlatform::ReturnValueRegister);
+ Jump testBoolean = _as->jump();
booleanConversion.link(_as);
- reg = Assembler::ReturnValueRegister;
- generateRuntimeCall(reg, toBoolean, Assembler::Reference(s->cond));
+ reg = JITTargetPlatform::ReturnValueRegister;
+ generateRuntimeCall(_as, reg, toBoolean, Reference(s->cond));
testBoolean.link(_as);
}
@@ -1274,9 +1245,9 @@ void InstructionSelection::visitCJump(IR::CJump *s)
} else if (IR::Const *c = s->cond->asConst()) {
// TODO: SSA optimization for constant condition evaluation should remove this.
// See also visitCJump() in RegAllocInfo.
- generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean,
- Assembler::PointerToValue(c));
- _as->generateCJumpOnNonZero(Assembler::ReturnValueRegister, _block, s->iftrue, s->iffalse);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
+ PointerToValue(c));
+ _as->generateCJumpOnNonZero(JITTargetPlatform::ReturnValueRegister, _block, s->iftrue, s->iffalse);
return;
} else if (IR::Binop *b = s->cond->asBinop()) {
if (b->left->type == IR::DoubleType && b->right->type == IR::DoubleType
@@ -1296,8 +1267,8 @@ void InstructionSelection::visitCJump(IR::CJump *s)
return;
}
- RuntimeCall op;
- RuntimeCall opContext;
+ typename JITAssembler::RuntimeCall op;
+ typename JITAssembler::RuntimeCall opContext;
const char *opName = 0;
bool needsExceptionCheck;
switch (b->op) {
@@ -1321,165 +1292,30 @@ void InstructionSelection::visitCJump(IR::CJump *s)
// elimination (which isn't there either) would remove the whole else block.
if (opContext.isValid())
_as->generateFunctionCallImp(needsExceptionCheck,
- Assembler::ReturnValueRegister, opName, opContext,
- Assembler::EngineRegister,
- Assembler::PointerToValue(b->left),
- Assembler::PointerToValue(b->right));
+ JITTargetPlatform::ReturnValueRegister, opName, opContext,
+ JITTargetPlatform::EngineRegister,
+ PointerToValue(b->left),
+ PointerToValue(b->right));
else
_as->generateFunctionCallImp(needsExceptionCheck,
- Assembler::ReturnValueRegister, opName, op,
- Assembler::PointerToValue(b->left),
- Assembler::PointerToValue(b->right));
+ JITTargetPlatform::ReturnValueRegister, opName, op,
+ PointerToValue(b->left),
+ PointerToValue(b->right));
- _as->generateCJumpOnNonZero(Assembler::ReturnValueRegister, _block, s->iftrue, s->iffalse);
+ _as->generateCJumpOnNonZero(JITTargetPlatform::ReturnValueRegister, _block, s->iftrue, s->iffalse);
return;
}
Q_UNREACHABLE();
}
-void InstructionSelection::visitRet(IR::Ret *s)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitRet(IR::Ret *s)
{
- if (!s) {
- // this only happens if the method doesn't have a return statement and can
- // only exit through an exception
- } else if (IR::Temp *t = s->expr->asTemp()) {
-#if CPU(X86) || CPU(ARM) || CPU(MIPS)
-
-# if CPU(X86)
- Assembler::RegisterID lowReg = JSC::X86Registers::eax;
- Assembler::RegisterID highReg = JSC::X86Registers::edx;
-# elif CPU(MIPS)
- Assembler::RegisterID lowReg = JSC::MIPSRegisters::v0;
- Assembler::RegisterID highReg = JSC::MIPSRegisters::v1;
-# else // CPU(ARM)
- Assembler::RegisterID lowReg = JSC::ARMRegisters::r0;
- Assembler::RegisterID highReg = JSC::ARMRegisters::r1;
-# endif
-
- if (t->kind == IR::Temp::PhysicalRegister) {
- switch (t->type) {
- case IR::DoubleType:
- _as->moveDoubleToInts((Assembler::FPRegisterID) t->index, lowReg, highReg);
- break;
- case IR::UInt32Type: {
- Assembler::RegisterID srcReg = (Assembler::RegisterID) t->index;
- Assembler::Jump intRange = _as->branch32(Assembler::GreaterThanOrEqual, srcReg, Assembler::TrustedImm32(0));
- _as->convertUInt32ToDouble(srcReg, Assembler::FPGpr0, Assembler::ReturnValueRegister);
- _as->moveDoubleToInts(Assembler::FPGpr0, lowReg, highReg);
- Assembler::Jump done = _as->jump();
- intRange.link(_as);
- _as->move(srcReg, lowReg);
- _as->move(Assembler::TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
- done.link(_as);
- } break;
- case IR::SInt32Type:
- _as->move((Assembler::RegisterID) t->index, lowReg);
- _as->move(Assembler::TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
- break;
- case IR::BoolType:
- _as->move((Assembler::RegisterID) t->index, lowReg);
- _as->move(Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal), highReg);
- break;
- default:
- Q_UNREACHABLE();
- }
- } else {
- Pointer addr = _as->loadAddress(Assembler::ScratchRegister, t);
- _as->load32(addr, lowReg);
- addr.offset += 4;
- _as->load32(addr, highReg);
- }
-#else
- if (t->kind == IR::Temp::PhysicalRegister) {
- if (t->type == IR::DoubleType) {
- _as->moveDoubleTo64((Assembler::FPRegisterID) t->index,
- Assembler::ReturnValueRegister);
- _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask),
- Assembler::ScratchRegister);
- _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
- } else if (t->type == IR::UInt32Type) {
- Assembler::RegisterID srcReg = (Assembler::RegisterID) t->index;
- Assembler::Jump intRange = _as->branch32(Assembler::GreaterThanOrEqual, srcReg, Assembler::TrustedImm32(0));
- _as->convertUInt32ToDouble(srcReg, Assembler::FPGpr0, Assembler::ReturnValueRegister);
- _as->moveDoubleTo64(Assembler::FPGpr0, Assembler::ReturnValueRegister);
- _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister);
- _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
- Assembler::Jump done = _as->jump();
- intRange.link(_as);
- _as->zeroExtend32ToPtr(srcReg, Assembler::ReturnValueRegister);
- quint64 tag = QV4::Value::Integer_Type_Internal;
- _as->or64(Assembler::TrustedImm64(tag << 32),
- Assembler::ReturnValueRegister);
- done.link(_as);
- } else {
- _as->zeroExtend32ToPtr((Assembler::RegisterID) t->index, Assembler::ReturnValueRegister);
- quint64 tag;
- switch (t->type) {
- case IR::SInt32Type:
- tag = QV4::Value::Integer_Type_Internal;
- break;
- case IR::BoolType:
- tag = QV4::Value::Boolean_Type_Internal;
- break;
- default:
- tag = 31337; // bogus value
- Q_UNREACHABLE();
- }
- _as->or64(Assembler::TrustedImm64(tag << 32),
- Assembler::ReturnValueRegister);
- }
- } else {
- _as->copyValue(Assembler::ReturnValueRegister, t);
- }
-#endif
- } else if (IR::Const *c = s->expr->asConst()) {
- QV4::Primitive retVal = convertToValue(c);
-#if CPU(X86)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::X86Registers::eax);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::X86Registers::edx);
-#elif CPU(ARM)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::ARMRegisters::r0);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::ARMRegisters::r1);
-#elif CPU(MIPS)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::MIPSRegisters::v0);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::MIPSRegisters::v1);
-#else
- _as->move(Assembler::TrustedImm64(retVal.rawValue()), Assembler::ReturnValueRegister);
-#endif
- } else {
- Q_UNREACHABLE();
- Q_UNUSED(s);
- }
-
- Assembler::Label leaveStackFrame = _as->label();
-
- const int locals = _as->stackLayout().calculateJSStackFrameSize();
- _as->subPtr(Assembler::TrustedImm32(sizeof(QV4::Value)*locals), Assembler::LocalsRegister);
- _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- _as->loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(ExecutionContext::Data, engine)), Assembler::ScratchRegister);
- _as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
-
- _as->leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
- _as->ret();
-
- _as->exceptionReturnLabel = _as->label();
- QV4::Primitive retVal = Primitive::undefinedValue();
-#if CPU(X86)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::X86Registers::eax);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::X86Registers::edx);
-#elif CPU(ARM)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::ARMRegisters::r0);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::ARMRegisters::r1);
-#elif CPU(MIPS)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::MIPSRegisters::v0);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::MIPSRegisters::v1);
-#else
- _as->move(Assembler::TrustedImm64(retVal.rawValue()), Assembler::ReturnValueRegister);
-#endif
- _as->jump(leaveStackFrame);
+ _as->returnFromFunction(s, regularRegistersToSave, fpRegistersToSave);
}
-int InstructionSelection::prepareVariableArguments(IR::ExprList* args)
+template <typename JITAssembler>
+int InstructionSelection<JITAssembler>::prepareVariableArguments(IR::ExprList* args)
{
int argc = 0;
for (IR::ExprList *it = args; it; it = it->next) {
@@ -1492,7 +1328,7 @@ int InstructionSelection::prepareVariableArguments(IR::ExprList* args)
Q_ASSERT(arg != 0);
Pointer dst(_as->stackLayout().argumentAddressForCall(i));
if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister)
- _as->memcopyValue(dst, arg->asTemp(), Assembler::ScratchRegister);
+ _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister);
else
_as->copyValue(dst, arg);
}
@@ -1500,7 +1336,8 @@ int InstructionSelection::prepareVariableArguments(IR::ExprList* args)
return argc;
}
-int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObject)
+template <typename JITAssembler>
+int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR::Expr *thisObject)
{
int argc = 0;
for (IR::ExprList *it = args; it; it = it->next) {
@@ -1508,9 +1345,9 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObje
}
Pointer p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, tag));
- _as->store32(Assembler::TrustedImm32(QV4::Value::Integer_Type_Internal), p);
+ _as->store32(TrustedImm32(QV4::Value::Integer_Type_Internal), p);
p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, argc));
- _as->store32(Assembler::TrustedImm32(argc), p);
+ _as->store32(TrustedImm32(argc), p);
p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, thisObject));
if (!thisObject)
_as->storeValue(QV4::Primitive::undefinedValue(), p);
@@ -1523,19 +1360,20 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObje
Q_ASSERT(arg != 0);
Pointer dst(_as->stackLayout().argumentAddressForCall(i));
if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister)
- _as->memcopyValue(dst, arg->asTemp(), Assembler::ScratchRegister);
+ _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister);
else
_as->copyValue(dst, arg);
}
return argc;
}
-void InstructionSelection::calculateRegistersToSave(const RegisterInformation &used)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::calculateRegistersToSave(const RegisterInformation &used)
{
regularRegistersToSave.clear();
fpRegistersToSave.clear();
- for (const RegisterInfo &ri : Assembler::getRegisterInfo()) {
+ for (const RegisterInfo &ri : JITTargetPlatform::getRegisterInfo()) {
#if defined(RESTORE_EBX_ON_CALL)
if (ri.isRegularRegister() && ri.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) {
regularRegistersToSave.append(ri);
@@ -1564,35 +1402,38 @@ bool operator==(const Primitive &v1, const Primitive &v2)
} // QV4 namespace
QT_END_NAMESPACE
-bool InstructionSelection::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right,
IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
{
if (_as->nextBlock() == iftrue) {
- Assembler::Jump target = _as->branchDouble(true, op, left, right);
+ Jump target = _as->branchDouble(true, op, left, right);
_as->addPatch(iffalse, target);
} else {
- Assembler::Jump target = _as->branchDouble(false, op, left, right);
+ Jump target = _as->branchDouble(false, op, left, right);
_as->addPatch(iftrue, target);
_as->jumpToBlock(_block, iffalse);
}
return true;
}
-bool InstructionSelection::visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right,
IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
{
if (_as->nextBlock() == iftrue) {
- Assembler::Jump target = _as->branchInt32(true, op, left, right);
+ Jump target = _as->branchInt32(true, op, left, right);
_as->addPatch(iffalse, target);
} else {
- Assembler::Jump target = _as->branchInt32(false, op, left, right);
+ Jump target = _as->branchInt32(false, op, left, right);
_as->addPatch(iftrue, target);
_as->jumpToBlock(_block, iffalse);
}
return true;
}
-void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *trueBlock,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
Q_ASSERT(binop->op == IR::OpStrictEqual || binop->op == IR::OpStrictNotEqual);
@@ -1607,15 +1448,16 @@ void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *tr
IR::Expr *left = binop->left;
IR::Expr *right = binop->right;
- generateRuntimeCall(Assembler::ReturnValueRegister, compareStrictEqual,
- Assembler::PointerToValue(left), Assembler::PointerToValue(right));
- _as->generateCJumpOnCompare(binop->op == IR::OpStrictEqual ? Assembler::NotEqual : Assembler::Equal,
- Assembler::ReturnValueRegister, Assembler::TrustedImm32(0),
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, compareStrictEqual,
+ PointerToValue(left), PointerToValue(right));
+ _as->generateCJumpOnCompare(binop->op == IR::OpStrictEqual ? RelationalCondition::NotEqual : RelationalCondition::Equal,
+ JITTargetPlatform::ReturnValueRegister, TrustedImm32(0),
_block, trueBlock, falseBlock);
}
// Only load the non-null temp.
-bool InstructionSelection::visitCJumpStrictNull(IR::Binop *binop,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpStrictNull(IR::Binop *binop,
IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
@@ -1640,19 +1482,20 @@ bool InstructionSelection::visitCJumpStrictNull(IR::Binop *binop,
return true;
}
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
+ Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc);
tagAddr.offset += 4;
- const Assembler::RegisterID tagReg = Assembler::ScratchRegister;
+ const RegisterID tagReg = JITTargetPlatform::ScratchRegister;
_as->load32(tagAddr, tagReg);
- Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal
- : Assembler::NotEqual;
- const Assembler::TrustedImm32 tag(QV4::Value::Null_Type_Internal);
+ RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
+ : RelationalCondition::NotEqual;
+ const TrustedImm32 tag(QV4::Value::Null_Type_Internal);
_as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock);
return true;
}
-bool InstructionSelection::visitCJumpStrictUndefined(IR::Binop *binop,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpStrictUndefined(IR::Binop *binop,
IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
@@ -1677,28 +1520,15 @@ bool InstructionSelection::visitCJumpStrictUndefined(IR::Binop *binop,
return true;
}
- Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal
- : Assembler::NotEqual;
- const Assembler::RegisterID tagReg = Assembler::ReturnValueRegister;
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
- _as->load64(addr, tagReg);
- const Assembler::TrustedImm64 tag(0);
-#else // !QV4_USE_64_BIT_VALUE_ENCODING
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
- _as->load32(tagAddr, tagReg);
- Assembler::Jump j = _as->branch32(Assembler::invert(cond), tagReg, Assembler::TrustedImm32(0));
- _as->addPatch(falseBlock, j);
-
- tagAddr.offset += 4;
- _as->load32(tagAddr, tagReg);
- const Assembler::TrustedImm32 tag(QV4::Value::Managed_Type_Internal);
-#endif
- _as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock);
+ RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
+ : RelationalCondition::NotEqual;
+ const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister;
+ _as->generateCJumpOnUndefined(cond, varSrc, JITTargetPlatform::ScratchRegister, tagReg, _block, trueBlock, falseBlock);
return true;
}
-bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
IR::Expr *boolSrc = 0, *otherSrc = 0;
@@ -1712,13 +1542,20 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock
// neither operands are statically typed as bool, so bail out.
return false;
}
+ if (otherSrc->type == IR::UnknownType) {
+ // Ok, we really need to call into the runtime.
+ // (This case doesn't happen when the optimizer ran, because everything will be typed (yes,
+ // possibly as "var" meaning anything), but it does happen for $0===true, which is generated
+ // for things where the optimizer didn't run (like functions with a try block).)
+ return false;
+ }
- Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal
- : Assembler::NotEqual;
+ RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
+ : RelationalCondition::NotEqual;
if (otherSrc->type == IR::BoolType) { // both are boolean
- Assembler::RegisterID one = _as->toBoolRegister(boolSrc, Assembler::ReturnValueRegister);
- Assembler::RegisterID two = _as->toBoolRegister(otherSrc, Assembler::ScratchRegister);
+ RegisterID one = _as->toBoolRegister(boolSrc, JITTargetPlatform::ReturnValueRegister);
+ RegisterID two = _as->toBoolRegister(otherSrc, JITTargetPlatform::ScratchRegister);
_as->generateCJumpOnCompare(cond, one, two, _block, trueBlock, falseBlock);
return true;
}
@@ -1728,13 +1565,13 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock
return true;
}
- Assembler::Pointer otherAddr = _as->loadAddress(Assembler::ReturnValueRegister, otherSrc);
+ Pointer otherAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, otherSrc);
otherAddr.offset += 4; // tag address
// check if the tag of the var operand is indicates 'boolean'
- _as->load32(otherAddr, Assembler::ScratchRegister);
- Assembler::Jump noBool = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal));
+ _as->load32(otherAddr, JITTargetPlatform::ScratchRegister);
+ Jump noBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
+ TrustedImm32(QV4::Value::Boolean_Type_Internal));
if (binop->op == IR::OpStrictEqual)
_as->addPatch(falseBlock, noBool);
else
@@ -1742,14 +1579,15 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock
// ok, both are boolean, so let's load them and compare them.
otherAddr.offset -= 4; // int_32 address
- _as->load32(otherAddr, Assembler::ReturnValueRegister);
- Assembler::RegisterID boolReg = _as->toBoolRegister(boolSrc, Assembler::ScratchRegister);
- _as->generateCJumpOnCompare(cond, boolReg, Assembler::ReturnValueRegister, _block, trueBlock,
+ _as->load32(otherAddr, JITTargetPlatform::ReturnValueRegister);
+ RegisterID boolReg = _as->toBoolRegister(boolSrc, JITTargetPlatform::ScratchRegister);
+ _as->generateCJumpOnCompare(cond, boolReg, JITTargetPlatform::ReturnValueRegister, _block, trueBlock,
falseBlock);
return true;
}
-bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop,
IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
@@ -1776,18 +1614,18 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Bin
return true;
}
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
+ Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc);
tagAddr.offset += 4;
- const Assembler::RegisterID tagReg = Assembler::ReturnValueRegister;
+ const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister;
_as->load32(tagAddr, tagReg);
if (binop->op == IR::OpNotEqual)
qSwap(trueBlock, falseBlock);
- Assembler::Jump isNull = _as->branch32(Assembler::Equal, tagReg, Assembler::TrustedImm32(int(QV4::Value::Null_Type_Internal)));
- Assembler::Jump isNotUndefinedTag = _as->branch32(Assembler::NotEqual, tagReg, Assembler::TrustedImm32(int(QV4::Value::Managed_Type_Internal)));
+ Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(int(QV4::Value::Null_Type_Internal)));
+ Jump isNotUndefinedTag = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(int(QV4::Value::Managed_Type_Internal)));
tagAddr.offset -= 4;
_as->load32(tagAddr, tagReg);
- Assembler::Jump isNotUndefinedValue = _as->branch32(Assembler::NotEqual, tagReg, Assembler::TrustedImm32(0));
+ Jump isNotUndefinedValue = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(0));
_as->addPatch(trueBlock, isNull);
_as->addPatch(falseBlock, isNotUndefinedTag);
_as->addPatch(falseBlock, isNotUndefinedValue);
@@ -1797,7 +1635,8 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Bin
}
-void InstructionSelection::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *trueBlock,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
Q_ASSERT(binop->op == IR::OpEqual || binop->op == IR::OpNotEqual);
@@ -1808,18 +1647,54 @@ void InstructionSelection::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *tru
IR::Expr *left = binop->left;
IR::Expr *right = binop->right;
- generateRuntimeCall(Assembler::ReturnValueRegister, compareEqual,
- Assembler::PointerToValue(left), Assembler::PointerToValue(right));
- _as->generateCJumpOnCompare(binop->op == IR::OpEqual ? Assembler::NotEqual : Assembler::Equal,
- Assembler::ReturnValueRegister, Assembler::TrustedImm32(0),
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, compareEqual,
+ PointerToValue(left), PointerToValue(right));
+ _as->generateCJumpOnCompare(binop->op == IR::OpEqual ? RelationalCondition::NotEqual : RelationalCondition::Equal,
+ JITTargetPlatform::ReturnValueRegister, TrustedImm32(0),
_block, trueBlock, falseBlock);
}
-QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory::createUnitForLoading()
+template <typename JITAssembler>
+QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory<JITAssembler>::createUnitForLoading()
{
QQmlRefPointer<CompiledData::CompilationUnit> result;
result.adopt(new JIT::CompilationUnit);
return result;
}
+QT_BEGIN_NAMESPACE
+namespace QV4 { namespace JIT {
+template class Q_QML_EXPORT InstructionSelection<>;
+template class Q_QML_EXPORT ISelFactory<>;
+#if defined(V4_BOOTSTRAP) && CPU(X86_64)
+
+Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &architecture)
+{
+ using ARMv7CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
+
+ if (architecture == QLatin1String("armv7"))
+ return new ISelFactory<ARMv7CrossAssembler>;
+
+ QString hostArch;
+#if CPU(ARM_THUMB2)
+ hostArch = QStringLiteral("armv7");
+#elif CPU(ARM64)
+ hostArch = QStringLiteral("armv8");
+#elif CPU(MIPS)
+ hostArch = QStringLiteral("mips");
+#elif CPU(X86)
+ hostArch = QStringLiteral("x86");
+#elif CPU(X86_64)
+ hostArch = QStringLiteral("x86_64");
+#endif
+ if (!hostArch.isEmpty() && architecture == hostArch)
+ return new ISelFactory<>;
+
+ return nullptr;
+}
+
+#endif
+} }
+QT_END_NAMESPACE
+
#endif // ENABLE(ASSEMBLER)
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
index 012745c5f2..6ae50c3260 100644
--- a/src/qml/jit/qv4isel_masm_p.h
+++ b/src/qml/jit/qv4isel_masm_p.h
@@ -72,6 +72,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
+template <typename JITAssembler = Assembler<DefaultAssemblerTargetConfiguration>>
class Q_QML_EXPORT InstructionSelection:
protected IR::IRDecoder,
public EvalInstructionSelection
@@ -136,8 +137,23 @@ protected:
void unop(IR::AluOp oper, IR::Expr *sourceTemp, IR::Expr *target) override;
void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) override;
- typedef Assembler::Address Address;
- typedef Assembler::Pointer Pointer;
+ using Address = typename JITAssembler::Address;
+ using Pointer = typename JITAssembler::Pointer;
+ using PointerToValue = typename JITAssembler::PointerToValue;
+ using RegisterID = typename JITAssembler::RegisterID;
+ using FPRegisterID = typename JITAssembler::FPRegisterID;
+ using ResultCondition = typename JITAssembler::ResultCondition;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+ using TrustedImm64 = typename JITAssembler::TrustedImm64;
+ using Label = typename JITAssembler::Label;
+ using Jump = typename JITAssembler::Jump;
+ using StringToIndex = typename JITAssembler::StringToIndex;
+ using Reference = typename JITAssembler::Reference;
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using BranchTruncateType = typename JITAssembler::BranchTruncateType;
+ using RuntimeCall = typename JITAssembler::RuntimeCall;
+
+ using JITTargetPlatform = typename JITAssembler::JITTargetPlatform;
#if !defined(ARGUMENTS_IN_REGISTERS)
Address addressForArgument(int index) const
@@ -145,7 +161,7 @@ protected:
// FramePointerRegister points to its old value on the stack, and above
// it we have the return address, hence the need to step over two
// values before reaching the first argument.
- return Address(Assembler::FramePointerRegister, (index + 2) * sizeof(void*));
+ return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * sizeof(void*));
}
#endif
@@ -192,61 +208,55 @@ private:
if (targetTemp->kind == IR::Temp::PhysicalRegister) {
if (IR::Temp *sourceTemp = source->asTemp()) {
if (sourceTemp->kind == IR::Temp::PhysicalRegister) {
- _as->convertInt32ToDouble((Assembler::RegisterID) sourceTemp->index,
- (Assembler::FPRegisterID) targetTemp->index);
+ _as->convertInt32ToDouble((RegisterID) sourceTemp->index,
+ (FPRegisterID) targetTemp->index);
} else {
- _as->convertInt32ToDouble(_as->loadAddress(Assembler::ReturnValueRegister, sourceTemp),
- (Assembler::FPRegisterID) targetTemp->index);
+ _as->convertInt32ToDouble(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, sourceTemp),
+ (FPRegisterID) targetTemp->index);
}
} else {
- _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
- (Assembler::FPRegisterID) targetTemp->index);
+ _as->convertInt32ToDouble(_as->toInt32Register(source, JITTargetPlatform::ScratchRegister),
+ (FPRegisterID) targetTemp->index);
}
return;
}
}
- _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
- Assembler::FPGpr0);
- _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(Assembler::ReturnValueRegister, target));
+ _as->convertInt32ToDouble(_as->toInt32Register(source, JITTargetPlatform::ScratchRegister),
+ JITTargetPlatform::FPGpr0);
+ _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target));
}
void convertUIntToDouble(IR::Expr *source, IR::Expr *target)
{
- Assembler::RegisterID tmpReg = Assembler::ScratchRegister;
- Assembler::RegisterID reg = _as->toInt32Register(source, tmpReg);
+ RegisterID tmpReg = JITTargetPlatform::ScratchRegister;
+ RegisterID reg = _as->toInt32Register(source, tmpReg);
if (IR::Temp *targetTemp = target->asTemp()) {
if (targetTemp->kind == IR::Temp::PhysicalRegister) {
- _as->convertUInt32ToDouble(reg, (Assembler::FPRegisterID) targetTemp->index, tmpReg);
+ _as->convertUInt32ToDouble(reg, (FPRegisterID) targetTemp->index, tmpReg);
return;
}
}
_as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg),
- Assembler::FPGpr0, tmpReg);
- _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(tmpReg, target));
+ JITTargetPlatform::FPGpr0, tmpReg);
+ _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(tmpReg, target));
}
void convertIntToBool(IR::Expr *source, IR::Expr *target)
{
- Assembler::RegisterID reg = Assembler::ScratchRegister;
+ RegisterID reg = JITTargetPlatform::ScratchRegister;
if (IR::Temp *targetTemp = target->asTemp())
if (targetTemp->kind == IR::Temp::PhysicalRegister)
- reg = (Assembler::RegisterID) targetTemp->index;
+ reg = (RegisterID) targetTemp->index;
_as->move(_as->toInt32Register(source, reg), reg);
- _as->compare32(Assembler::NotEqual, reg, Assembler::TrustedImm32(0), reg);
+ _as->compare32(RelationalCondition::NotEqual, reg, TrustedImm32(0), reg);
_as->storeBool(reg, target);
}
- #define isel_stringIfyx(s) #s
- #define isel_stringIfy(s) isel_stringIfyx(s)
-
- #define generateRuntimeCall(t, function, ...) \
- _as->generateFunctionCallImp(Runtime::Method_##function##_NeedsExceptionCheck, t, "Runtime::" isel_stringIfy(function), RuntimeCall(qOffsetOf(QV4::Runtime, function)), __VA_ARGS__)
-
int prepareVariableArguments(IR::ExprList* args);
int prepareCallData(IR::ExprList* args, IR::Expr *thisObject);
@@ -259,22 +269,22 @@ private:
// goes into the same register as the return value (currently only ARM), the prepareCall
// will combine loading the looupAddr into the register and calculating the indirect call
// address.
- Assembler::Pointer lookupAddr(Assembler::ReturnValueRegister, index * sizeof(QV4::Lookup));
+ Pointer lookupAddr(JITTargetPlatform::ReturnValueRegister, index * sizeof(QV4::Lookup));
_as->generateFunctionCallImp(true, retval, "lookup getter/setter",
- LookupCall(lookupAddr, getterSetterOffset), lookupAddr,
+ typename JITAssembler::LookupCall(lookupAddr, getterSetterOffset), lookupAddr,
arg1, arg2, arg3);
}
template <typename Retval, typename Arg1, typename Arg2>
void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2)
{
- generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, Assembler::VoidType());
+ generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, typename JITAssembler::VoidType());
}
IR::BasicBlock *_block;
BitVector _removableJumps;
- Assembler* _as;
+ JITAssembler* _as;
QScopedPointer<CompilationUnit> compilationUnit;
QQmlEnginePrivate *qmlEngine;
@@ -282,13 +292,14 @@ private:
RegisterInformation fpRegistersToSave;
};
+template <typename JITAssembler = Assembler<DefaultAssemblerTargetConfiguration>>
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
ISelFactory() : EvalISelFactory(QStringLiteral("jit")) {}
virtual ~ISelFactory() {}
EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) Q_DECL_OVERRIDE Q_DECL_FINAL
- { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator, this); }
+ { return new InstructionSelection<JITAssembler>(qmlEngine, execAllocator, module, jsGenerator, this); }
bool jitCompileRegexps() const Q_DECL_OVERRIDE Q_DECL_FINAL
{ return true; }
QQmlRefPointer<CompiledData::CompilationUnit> createUnitForLoading() Q_DECL_OVERRIDE Q_DECL_FINAL;
diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp
index 3fb0815299..d5da863ee0 100644
--- a/src/qml/jit/qv4regalloc.cpp
+++ b/src/qml/jit/qv4regalloc.cpp
@@ -973,7 +973,15 @@ private:
break;
Q_ASSERT(!i->isFixedInterval());
- _liveIntervals.push_back(i);
+ auto it = _liveIntervals.begin();
+ for (; it != _liveIntervals.end(); ++it) {
+ if ((*it)->temp() == i->temp()) {
+ *it = i;
+ break;
+ }
+ }
+ if (it == _liveIntervals.end())
+ _liveIntervals.push_back(i);
// qDebug() << "-- Activating interval for temp" << i->temp().index;
_unprocessedReverseOrder.removeLast();
@@ -1521,7 +1529,7 @@ static inline int indexOfRangeCoveringPosition(const LifeTimeInterval::Ranges &r
return -1;
}
-static inline int intersectionPosition(const LifeTimeInterval::Range &one, const LifeTimeInterval::Range &two)
+static inline int intersectionPosition(const LifeTimeIntervalRange &one, const LifeTimeIntervalRange &two)
{
if (one.covers(two.start))
return two.start;
@@ -1779,9 +1787,9 @@ int RegisterAllocator::nextIntersection(const LifeTimeInterval &current,
return -1;
for (int currentEnd = currentRanges.size(); currentIt < currentEnd; ++currentIt) {
- const LifeTimeInterval::Range currentRange = currentRanges.at(currentIt);
+ const LifeTimeIntervalRange currentRange = currentRanges.at(currentIt);
for (int anotherIt = anotherItStart, anotherEnd = anotherRanges.size(); anotherIt < anotherEnd; ++anotherIt) {
- const LifeTimeInterval::Range anotherRange = anotherRanges.at(anotherIt);
+ const LifeTimeIntervalRange anotherRange = anotherRanges.at(anotherIt);
if (anotherRange.start > currentRange.end)
break;
int intersectPos = intersectionPosition(currentRange, anotherRange);
diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h
index 7e265258d5..1c29aa2a70 100644
--- a/src/qml/jit/qv4targetplatform_p.h
+++ b/src/qml/jit/qv4targetplatform_p.h
@@ -63,6 +63,11 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
+enum TargetOperatingSystemSpecialization {
+ NoOperatingSystemSpecialization,
+ WindowsSpecialization
+};
+
// The TargetPlatform class describes how the stack and the registers work on a CPU+ABI combination.
//
// All combinations have a separate definition, guarded by #ifdefs. The exceptions are:
@@ -79,25 +84,37 @@ namespace JIT {
// a call, we add a load it right before emitting the call instruction.
//
// NOTE: When adding new architecture, do not forget to whitelist it in qv4global_p.h!
+template <typename PlatformAssembler, TargetOperatingSystemSpecialization specialization = NoOperatingSystemSpecialization>
class TargetPlatform
{
-public:
+};
+
#if CPU(X86) && (OS(LINUX) || OS(WINDOWS) || OS(QNX) || OS(FREEBSD) || defined(Q_OS_IOS))
- enum { RegAllocIsSupported = 1 };
+template <>
+class TargetPlatform<JSC::MacroAssemblerX86, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerX86;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::X86Registers::ebp;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::edi;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::X86Registers::esi;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::ecx;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+ enum { RegAllocIsSupported = 1 };
- static RegisterInformation getPlatformRegisterInfo()
+ static const RegisterID FramePointerRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID LocalsRegister = JSC::X86Registers::edi;
+ static const RegisterID EngineRegister = JSC::X86Registers::esi;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::ecx;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+ static const RegisterID LowReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID HighReturnValueRegister = JSC::X86Registers::edx;
+
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::X86Registers::edx, QStringLiteral("edx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::ebx, QStringLiteral("ebx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::edi, QStringLiteral("edi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
@@ -109,6 +126,7 @@ public:
<< RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
;
+ return info;
}
# define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
@@ -117,19 +135,20 @@ public:
# undef ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 0;
- static JSC::MacroAssembler::RegisterID registerForArgument(int) { Q_UNREACHABLE(); }
+ static RegisterID registerForArgument(int) { Q_UNREACHABLE(); }
static const int StackAlignment = 16;
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(FramePointerRegister); }
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(FramePointerRegister); }
+ static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as) { as->pop(FramePointerRegister); }
#if OS(WINDOWS) || OS(QNX) || \
((OS(LINUX) || OS(FREEBSD)) && (defined(__PIC__) || defined(__PIE__)))
#define RESTORE_EBX_ON_CALL
- static JSC::MacroAssembler::Address ebxAddressOnStack()
+ using Address = PlatformAssembler::Address;
+ static Address ebxAddressOnStack()
{
static int ebxIdx = -1;
if (ebxIdx == -1) {
@@ -146,28 +165,36 @@ public:
Q_ASSERT(ebxIdx >= 0);
ebxIdx += 1;
}
- return JSC::MacroAssembler::Address(FramePointerRegister, ebxIdx * -int(sizeof(void*)));
+ return Address(FramePointerRegister, ebxIdx * -int(sizeof(void*)));
}
#endif
-
-#endif // Windows on x86
+};
+#endif // x86
#if CPU(X86_64) && (OS(LINUX) || OS(MAC_OS_X) || OS(FREEBSD) || OS(QNX) || defined(Q_OS_IOS))
+template <>
+class TargetPlatform<JSC::MacroAssemblerX86_64, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerX86_64;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+
enum { RegAllocIsSupported = 1 };
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::X86Registers::ebp;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::X86Registers::r14;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+ static const RegisterID FramePointerRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID LocalsRegister = JSC::X86Registers::r12;
+ static const RegisterID EngineRegister = JSC::X86Registers::r14;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
- static RegisterInformation getPlatformRegisterInfo()
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
@@ -185,6 +212,7 @@ public:
<< RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
;
+ return info;
}
#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
@@ -193,9 +221,9 @@ public:
#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 6;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::X86Registers::edi,
JSC::X86Registers::esi,
JSC::X86Registers::edx,
@@ -210,29 +238,38 @@ public:
static const int StackAlignment = 16;
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(FramePointerRegister); }
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(FramePointerRegister); }
+ static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as) { as->pop(FramePointerRegister); }
+};
#endif // Linux/MacOS on x86_64
#if CPU(X86_64) && OS(WINDOWS)
+template <>
+class TargetPlatform<JSC::MacroAssemblerX86_64, WindowsSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerX86_64;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+
// Register allocation is not (yet) supported on win64, because the ABI related stack handling
// is not completely implemented. Specifically, the saving of xmm registers, and the saving of
// incoming function parameters to the shadow space is missing.
enum { RegAllocIsSupported = 0 };
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::X86Registers::ebp;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::X86Registers::r14;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+ static const RegisterID FramePointerRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID LocalsRegister = JSC::X86Registers::r12;
+ static const RegisterID EngineRegister = JSC::X86Registers::r14;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
- static RegisterInformation getPlatformRegisterInfo()
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
@@ -244,6 +281,7 @@ public:
<< RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
;
+ return info;
}
#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
@@ -252,9 +290,9 @@ public:
#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 4;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::X86Registers::ecx,
JSC::X86Registers::edx,
JSC::X86Registers::r8,
@@ -267,11 +305,20 @@ public:
static const int StackAlignment = 16;
static const int StackShadowSpace = 32;
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(FramePointerRegister); }
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(FramePointerRegister); }
+ static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as) { as->pop(FramePointerRegister); }
+};
#endif // Windows on x86_64
-#if CPU(ARM)
+#if CPU(ARM) || defined(V4_BOOTSTRAP)
+template <>
+class TargetPlatform<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerARMv7;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+
enum { RegAllocIsSupported = 1 };
// The AAPCS specifies that the platform ABI has to define the usage of r9. Known are:
@@ -287,23 +334,25 @@ public:
// is used for the subroutine: r7 for Thumb or Thumb2, and r11 for ARM. We assign the constants
// accordingly, and assign the locals-register to the "other" register.
#if CPU(ARM_THUMB2)
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r11;
+ static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
+ static const RegisterID LocalsRegister = JSC::ARMRegisters::r11;
#else // Thumbs down
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::ARMRegisters::r11;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r7;
+ static const RegisterID FramePointerRegister = JSC::ARMRegisters::r11;
+ static const RegisterID LocalsRegister = JSC::ARMRegisters::r7;
#endif
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::ARMRegisters::r13;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::ARMRegisters::r5;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::ARMRegisters::r10;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::ARMRegisters::d1;
-
- static RegisterInformation getPlatformRegisterInfo()
+ static const RegisterID StackPointerRegister = JSC::ARMRegisters::r13;
+ static const RegisterID ScratchRegister = JSC::ARMRegisters::r5;
+ static const RegisterID EngineRegister = JSC::ARMRegisters::r10;
+ static const RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
+ static const FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
+ static const FPRegisterID FPGpr1 = JSC::ARMRegisters::d1;
+ static const RegisterID LowReturnValueRegister = JSC::ARMRegisters::r0;
+ static const RegisterID HighReturnValueRegister = JSC::ARMRegisters::r1;
+
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::ARMRegisters::r0, QStringLiteral("r0"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
<< RI(JSC::ARMRegisters::r1, QStringLiteral("r1"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::ARMRegisters::r2, QStringLiteral("r2"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
@@ -336,6 +385,7 @@ public:
<< RI(JSC::ARMRegisters::d14, QStringLiteral("d14"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::ARMRegisters::d15, QStringLiteral("d15"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
;
+ return info;
}
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
@@ -344,9 +394,9 @@ public:
#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 4;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::ARMRegisters::r0,
JSC::ARMRegisters::r1,
JSC::ARMRegisters::r2,
@@ -361,35 +411,44 @@ public:
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformEnterStandardStackFrame(PlatformAssembler *as)
{
as->push(JSC::ARMRegisters::lr);
as->push(FramePointerRegister);
}
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as)
{
as->pop(FramePointerRegister);
as->pop(JSC::ARMRegisters::lr);
}
+};
#endif // ARM (32 bit)
#if CPU(ARM64)
+template <>
+class TargetPlatform<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerARM64;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+
enum { RegAllocIsSupported = 1 };
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::ARM64Registers::fp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARM64Registers::x28;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::ARM64Registers::sp;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::ARM64Registers::x9;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::ARM64Registers::x27;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::ARM64Registers::x0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::ARM64Registers::q0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::ARM64Registers::q1;
+ static const RegisterID FramePointerRegister = JSC::ARM64Registers::fp;
+ static const RegisterID LocalsRegister = JSC::ARM64Registers::x28;
+ static const RegisterID StackPointerRegister = JSC::ARM64Registers::sp;
+ static const RegisterID ScratchRegister = JSC::ARM64Registers::x9;
+ static const RegisterID EngineRegister = JSC::ARM64Registers::x27;
+ static const RegisterID ReturnValueRegister = JSC::ARM64Registers::x0;
+ static const FPRegisterID FPGpr0 = JSC::ARM64Registers::q0;
+ static const FPRegisterID FPGpr1 = JSC::ARM64Registers::q1;
- static RegisterInformation getPlatformRegisterInfo()
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::ARM64Registers::x0, QStringLiteral("x0"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
<< RI(JSC::ARM64Registers::x1, QStringLiteral("x1"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::ARM64Registers::x2, QStringLiteral("x2"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
@@ -447,6 +506,7 @@ public:
<< RI(JSC::ARM64Registers::q30, QStringLiteral("q30"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::ARM64Registers::q31, QStringLiteral("q31"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
;
+ return info;
}
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
@@ -455,9 +515,9 @@ public:
#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 8;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::ARM64Registers::x0,
JSC::ARM64Registers::x1,
JSC::ARM64Registers::x2,
@@ -476,33 +536,43 @@ public:
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformEnterStandardStackFrame(PlatformAssembler *as)
{
as->pushPair(FramePointerRegister, JSC::ARM64Registers::lr);
}
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as)
{
as->popPair(FramePointerRegister, JSC::ARM64Registers::lr);
}
+};
#endif // ARM64
#if defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX)
+template <>
+class TargetPlatform<JSC::MacroAssemblerMIPS, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerMIPS;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
enum { RegAllocIsSupported = 1 };
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::MIPSRegisters::fp;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::MIPSRegisters::sp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::MIPSRegisters::s0;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::MIPSRegisters::s1;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::MIPSRegisters::v0;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::MIPSRegisters::s2;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::MIPSRegisters::f0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::MIPSRegisters::f2;
-
- static RegisterInformation getPlatformRegisterInfo()
+ static const RegisterID FramePointerRegister = JSC::MIPSRegisters::fp;
+ static const RegisterID StackPointerRegister = JSC::MIPSRegisters::sp;
+ static const RegisterID LocalsRegister = JSC::MIPSRegisters::s0;
+ static const RegisterID EngineRegister = JSC::MIPSRegisters::s1;
+ static const RegisterID ReturnValueRegister = JSC::MIPSRegisters::v0;
+ static const RegisterID ScratchRegister = JSC::MIPSRegisters::s2;
+ static const FPRegisterID FPGpr0 = JSC::MIPSRegisters::f0;
+ static const FPRegisterID FPGpr1 = JSC::MIPSRegisters::f2;
+ static const RegisterID LowReturnValueRegister = JSC::MIPSRegisters::v0;
+ static const RegisterID HighReturnValueRegister = JSC::MIPSRegisters::v1;
+
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
// Note: t0, t1, t2, t3 and f16 are already used by MacroAssemblerMIPS.
<< RI(JSC::MIPSRegisters::t4, QStringLiteral("t4"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::MIPSRegisters::t5, QStringLiteral("t5"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
@@ -524,6 +594,7 @@ public:
<< RI(JSC::MIPSRegisters::f26, QStringLiteral("f26"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::MIPSRegisters::f28, QStringLiteral("f28"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
;
+ return info;
}
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
@@ -532,9 +603,9 @@ public:
#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 4;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::MIPSRegisters::a0,
JSC::MIPSRegisters::a1,
JSC::MIPSRegisters::a2,
@@ -549,27 +620,19 @@ public:
static const int StackShadowSpace = 4 * RegisterSize; // Stack space for 4 argument registers.
static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformEnterStandardStackFrame(PlatformAssembler *as)
{
as->push(JSC::MIPSRegisters::ra);
as->push(FramePointerRegister);
}
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as)
{
as->pop(FramePointerRegister);
as->pop(JSC::MIPSRegisters::ra);
}
-#endif // Linux on MIPS (32 bit)
-
-public: // utility functions
- static const RegisterInformation getRegisterInfo()
- {
- static const RegisterInformation info = getPlatformRegisterInfo();
-
- return info;
- }
};
+#endif // Linux on MIPS (32 bit)
} // JIT namespace
} // QV4 namespace
diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp
index 799103849b..31355e5dce 100644
--- a/src/qml/jit/qv4unop.cpp
+++ b/src/qml/jit/qv4unop.cpp
@@ -48,14 +48,15 @@ using namespace JIT;
#define stringIfy(s) stringIfyx(s)
#define setOp(operation) \
do { \
- call = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); name = "Runtime::" stringIfy(operation); \
+ call = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); name = "Runtime::" stringIfy(operation); \
needsExceptionCheck = Runtime::Method_##operation##_NeedsExceptionCheck; \
} while (0)
-void Unop::generate(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void Unop<JITAssembler>::generate(IR::Expr *source, IR::Expr *target)
{
bool needsExceptionCheck;
- RuntimeCall call;
+ typename JITAssembler::RuntimeCall call;
const char *name = 0;
switch (op) {
case IR::OpNot:
@@ -75,17 +76,18 @@ void Unop::generate(IR::Expr *source, IR::Expr *target)
} // switch
Q_ASSERT(call.isValid());
- _as->generateFunctionCallImp(needsExceptionCheck, target, name, call, Assembler::PointerToValue(source));
+ _as->generateFunctionCallImp(needsExceptionCheck, target, name, call, PointerToValue(source));
}
-void Unop::generateUMinus(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void Unop<JITAssembler>::generateUMinus(IR::Expr *source, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
if (source->type == IR::SInt32Type) {
- Assembler::RegisterID tReg = Assembler::ScratchRegister;
+ typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) targetTemp->index;
- Assembler::RegisterID sReg = _as->toInt32Register(source, tReg);
+ tReg = (typename JITAssembler::RegisterID) targetTemp->index;
+ typename JITAssembler::RegisterID sReg = _as->toInt32Register(source, tReg);
_as->move(sReg, tReg);
_as->neg32(tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
@@ -93,26 +95,27 @@ void Unop::generateUMinus(IR::Expr *source, IR::Expr *target)
return;
}
- generateRuntimeCall(target, uMinus, Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, target, uMinus, PointerToValue(source));
}
-void Unop::generateNot(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void Unop<JITAssembler>::generateNot(IR::Expr *source, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
if (source->type == IR::BoolType) {
- Assembler::RegisterID tReg = Assembler::ScratchRegister;
+ typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) targetTemp->index;
- _as->xor32(Assembler::TrustedImm32(0x1), _as->toInt32Register(source, tReg), tReg);
+ tReg = (typename JITAssembler::RegisterID) targetTemp->index;
+ _as->xor32(TrustedImm32(0x1), _as->toInt32Register(source, tReg), tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
_as->storeBool(tReg, target);
return;
} else if (source->type == IR::SInt32Type) {
- Assembler::RegisterID tReg = Assembler::ScratchRegister;
+ typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) targetTemp->index;
- _as->compare32(Assembler::Equal,
- _as->toInt32Register(source, Assembler::ScratchRegister), Assembler::TrustedImm32(0),
+ tReg = (typename JITAssembler::RegisterID) targetTemp->index;
+ _as->compare32(RelationalCondition::Equal,
+ _as->toInt32Register(source, JITAssembler::ScratchRegister), TrustedImm32(0),
tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
_as->storeBool(tReg, target);
@@ -122,22 +125,28 @@ void Unop::generateNot(IR::Expr *source, IR::Expr *target)
}
// ## generic implementation testing for int/bool
- generateRuntimeCall(target, uNot, Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, target, uNot, PointerToValue(source));
}
-void Unop::generateCompl(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void Unop<JITAssembler>::generateCompl(IR::Expr *source, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
if (source->type == IR::SInt32Type) {
- Assembler::RegisterID tReg = Assembler::ScratchRegister;
+ typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) targetTemp->index;
- _as->xor32(Assembler::TrustedImm32(0xffffffff), _as->toInt32Register(source, tReg), tReg);
+ tReg = (typename JITAssembler::RegisterID) targetTemp->index;
+ _as->xor32(TrustedImm32(0xffffffff), _as->toInt32Register(source, tReg), tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
_as->storeInt32(tReg, target);
return;
}
- generateRuntimeCall(target, complement, Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, target, complement, PointerToValue(source));
}
+template struct QV4::JIT::Unop<QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>>;
+#if defined(V4_BOOTSTRAP) && CPU(X86_64)
+template struct QV4::JIT::Unop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>>;
+#endif
+
#endif
diff --git a/src/qml/jit/qv4unop_p.h b/src/qml/jit/qv4unop_p.h
index 1141a84913..fb68f80eec 100644
--- a/src/qml/jit/qv4unop_p.h
+++ b/src/qml/jit/qv4unop_p.h
@@ -60,21 +60,25 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
-class Assembler;
-
+template <typename JITAssembler>
struct Unop {
- Unop(Assembler *assembler, IR::AluOp operation)
+ Unop(JITAssembler *assembler, IR::AluOp operation)
: _as(assembler)
, op(operation)
{}
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using PointerToValue = typename JITAssembler::PointerToValue;
+ using RuntimeCall = typename JITAssembler::RuntimeCall;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+
void generate(IR::Expr *source, IR::Expr *target);
void generateUMinus(IR::Expr *source, IR::Expr *target);
void generateNot(IR::Expr *source, IR::Expr *target);
void generateCompl(IR::Expr *source, IR::Expr *target);
- Assembler *_as;
+ JITAssembler *_as;
IR::AluOp op;
};
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 919524d1ed..955cf585e4 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -35,7 +35,6 @@ SOURCES += \
$$PWD/qv4regexp.cpp \
$$PWD/qv4serialize.cpp \
$$PWD/qv4script.cpp \
- $$PWD/qv4executableallocator.cpp \
$$PWD/qv4sequenceobject.cpp \
$$PWD/qv4include.cpp \
$$PWD/qv4qobjectwrapper.cpp \
@@ -113,7 +112,8 @@ HEADERS += \
SOURCES += \
$$PWD/qv4runtime.cpp \
$$PWD/qv4string.cpp \
- $$PWD/qv4value.cpp
+ $$PWD/qv4value.cpp \
+ $$PWD/qv4executableallocator.cpp
valgrind {
DEFINES += V4_USE_VALGRIND
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 5a190d6690..9354bcb1a3 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -88,10 +88,12 @@ void ArgumentsObject::fullyCreate()
Scope scope(engine());
Scoped<MemberData> md(scope, d()->mappedArguments);
- d()->mappedArguments = md->allocate(engine(), numAccessors);
- for (uint i = 0; i < numAccessors; ++i) {
- d()->mappedArguments->data[i] = context()->callData->args[i];
- arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor);
+ if (numAccessors) {
+ d()->mappedArguments = md->allocate(engine(), numAccessors);
+ for (uint i = 0; i < numAccessors; ++i) {
+ d()->mappedArguments->data[i] = context()->callData->args[i];
+ arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor);
+ }
}
arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors);
for (uint i = numAccessors; i < argCount; ++i)
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index 23075aa78c..ffe9aa846f 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -81,16 +81,19 @@ void ArrayBufferCtor::call(const Managed *that, Scope &scope, CallData *callData
construct(that, scope, callData);
}
-ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx)
+void ArrayBufferCtor::method_isView(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<TypedArray> a(scope, ctx->argument(0));
- if (!!a)
- return Encode(true);
- QV4::Scoped<DataView> v(scope, ctx->argument(0));
- if (!!v)
- return Encode(true);
- return Encode(false);
+ QV4::Scoped<TypedArray> a(scope, callData->argument(0));
+ if (!!a) {
+ scope.result = Encode(true);
+ return;
+ }
+ QV4::Scoped<DataView> v(scope, callData->argument(0));
+ if (!!v) {
+ scope.result = Encode(true);
+ return;
+ }
+ scope.result = Encode(false);
}
@@ -160,54 +163,48 @@ void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("toString"), method_toString, 0);
}
-ReturnedValue ArrayBufferPrototype::method_get_byteLength(CallContext *ctx)
+void ArrayBufferPrototype::method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<ArrayBuffer> v(scope, ctx->thisObject());
+ Scoped<ArrayBuffer> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->data->size);
+ scope.result = Encode(v->d()->data->size);
}
-ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx)
+void ArrayBufferPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<ArrayBuffer> a(scope, ctx->thisObject());
+ Scoped<ArrayBuffer> a(scope, callData->thisObject);
if (!a)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- double start = ctx->argc() > 0 ? ctx->args()[0].toInteger() : 0;
- double end = (ctx->argc() < 2 || ctx->args()[1].isUndefined()) ?
- a->d()->data->size : ctx->args()[1].toInteger();
- if (scope.engine->hasException)
- return Encode::undefined();
+ double start = callData->argc > 0 ? callData->args[0].toInteger() : 0;
+ double end = (callData->argc < 2 || callData->args[1].isUndefined()) ?
+ a->d()->data->size : callData->args[1].toInteger();
+ CHECK_EXCEPTION();
double first = (start < 0) ? qMax(a->d()->data->size + start, 0.) : qMin(start, (double)a->d()->data->size);
double final = (end < 0) ? qMax(a->d()->data->size + end, 0.) : qMin(end, (double)a->d()->data->size);
ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor()));
if (!constructor)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, 1);
+ ScopedCallData cData(scope, 1);
double newLen = qMax(final - first, 0.);
- callData->args[0] = QV4::Encode(newLen);
- constructor->construct(scope, callData);
- QV4::Scoped<ArrayBuffer> newBuffer(scope, scope.result.asReturnedValue());
+ cData->args[0] = QV4::Encode(newLen);
+ constructor->construct(scope, cData);
+ QV4::Scoped<ArrayBuffer> newBuffer(scope, scope.result);
if (!newBuffer || newBuffer->d()->data->size < (int)newLen)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
memcpy(newBuffer->d()->data->data(), a->d()->data->data() + (uint)first, newLen);
-
- return newBuffer.asReturnedValue();
}
-ReturnedValue ArrayBufferPrototype::method_toString(CallContext *ctx)
+void ArrayBufferPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<ArrayBuffer> a(scope, ctx->thisObject());
+ Scoped<ArrayBuffer> a(scope, callData->thisObject);
if (!a)
- return Encode::undefined();
- return Encode(ctx->engine()->newString(QString::fromUtf8(a->asByteArray())));
+ RETURN_UNDEFINED();
+ scope.result = scope.engine->newString(QString::fromUtf8(a->asByteArray()));
}
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index bc56d1ea31..4f7926d3dc 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -81,7 +81,7 @@ struct ArrayBufferCtor: FunctionObject
static void construct(const Managed *m, Scope &scope, CallData *callData);
static void call(const Managed *that, Scope &scope, CallData *callData);
- static ReturnedValue method_isView(CallContext *ctx);
+ static void method_isView(const BuiltinFunction *, Scope &scope, CallData *callData);
};
@@ -104,9 +104,9 @@ struct ArrayBufferPrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_get_byteLength(CallContext *ctx);
- static ReturnedValue method_slice(CallContext *ctx);
- static ReturnedValue method_toString(CallContext *ctx);
+ static void method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index bfeb3d4699..d8a7de5466 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -237,8 +237,14 @@ void ArrayData::ensureAttributes(Object *o)
void SimpleArrayData::markObjects(Heap::Base *d, ExecutionEngine *e)
{
Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(d);
- for (uint i = 0; i < dd->len; ++i)
- dd->arrayData[dd->mappedIndex(i)].mark(e);
+ uint end = dd->offset + dd->len;
+ if (end > dd->alloc) {
+ for (uint i = 0; i < end - dd->alloc; ++i)
+ dd->arrayData[i].mark(e);
+ end = dd->alloc;
+ }
+ for (uint i = dd->offset; i < end; ++i)
+ dd->arrayData[i].mark(e);
}
ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index)
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 20ba11fd75..759354f4e2 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -44,6 +44,7 @@
#include "qv4argumentsobject_p.h"
#include "qv4runtime_p.h"
#include "qv4string_p.h"
+#include <QtCore/qscopedvaluerollback.h>
using namespace QV4;
@@ -118,42 +119,40 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("reduceRight"), method_reduceRight, 1);
}
-ReturnedValue ArrayPrototype::method_isArray(CallContext *ctx)
+void ArrayPrototype::method_isArray(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- bool isArray = ctx->argc() && ctx->args()[0].as<ArrayObject>();
- return Encode(isArray);
+ bool isArray = callData->argc && callData->args[0].as<ArrayObject>();
+ scope.result = Encode(isArray);
}
-ReturnedValue ArrayPrototype::method_toString(CallContext *ctx)
+void ArrayPrototype::method_toString(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->thisObject(), ScopedObject::Convert);
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
- ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("join")));
+ ScopedObject o(scope, callData->thisObject, ScopedObject::Convert);
+ CHECK_EXCEPTION();
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("join")));
ScopedFunctionObject f(scope, o->get(s));
if (!!f) {
ScopedCallData d(scope, 0);
- d->thisObject = ctx->thisObject();
+ d->thisObject = callData->thisObject;
f->call(scope, d);
- return scope.result.asReturnedValue();
+ return;
}
- return ObjectPrototype::method_toString(ctx);
+ ObjectPrototype::method_toString(builtin, scope, callData);
}
-ReturnedValue ArrayPrototype::method_toLocaleString(CallContext *ctx)
+void ArrayPrototype::method_toLocaleString(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
{
- return method_toString(ctx);
+ return method_toString(builtin, scope, callData);
}
-ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
+void ArrayPrototype::method_concat(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject result(scope, ctx->d()->engine->newArrayObject());
-
- ScopedObject thisObject(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject thisObject(scope, callData->thisObject.toObject(scope.engine));
if (!thisObject)
- return Encode::undefined();
+ RETURN_UNDEFINED();
+
+ ScopedArrayObject result(scope, scope.engine->newArrayObject());
+
if (thisObject->isArrayObject()) {
result->copyArrayData(thisObject);
} else {
@@ -163,9 +162,9 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
ScopedArrayObject elt(scope);
ScopedObject eltAsObj(scope);
ScopedValue entry(scope);
- for (int i = 0; i < ctx->argc(); ++i) {
- eltAsObj = ctx->args()[i];
- elt = ctx->args()[i];
+ for (int i = 0; i < callData->argc; ++i) {
+ eltAsObj = callData->args[i];
+ elt = callData->args[i];
if (elt) {
uint n = elt->getLength();
uint newLen = ArrayData::append(result, elt, n);
@@ -177,95 +176,90 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
result->putIndexed(startIndex + i, entry);
}
} else {
- result->arraySet(result->getLength(), ctx->args()[i]);
+ result->arraySet(result->getLength(), callData->args[i]);
}
}
- return result.asReturnedValue();
+ scope.result = result;
}
-ReturnedValue ArrayPrototype::method_find(CallContext *ctx)
+void ArrayPrototype::method_find(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, 3);
- callData->thisObject = ctx->argument(1);
- callData->args[2] = instance;
+ ScopedCallData cData(scope, 3);
+ cData->thisObject = callData->argument(1);
+ cData->args[2] = instance;
ScopedValue v(scope);
for (uint k = 0; k < len; ++k) {
v = instance->getIndexed(k);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
- if (scope.hasException())
- return Encode::undefined();
- else if (scope.result.toBoolean())
- return v->asReturnedValue();
+ CHECK_EXCEPTION();
+ if (scope.result.toBoolean())
+ RETURN_RESULT(v);
}
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue ArrayPrototype::method_findIndex(CallContext *ctx)
+void ArrayPrototype::method_findIndex(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, 3);
- callData->thisObject = ctx->argument(1);
- callData->args[2] = instance;
+ ScopedCallData cData(scope, 3);
+ cData->thisObject = callData->argument(1);
+ cData->args[2] = instance;
ScopedValue v(scope);
for (uint k = 0; k < len; ++k) {
v = instance->getIndexed(k);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
- if (scope.hasException())
- return Encode::undefined();
- else if (scope.result.toBoolean())
- return Encode(k);
+ CHECK_EXCEPTION();
+ if (scope.result.toBoolean())
+ RETURN_RESULT(Encode(k));
}
- return Encode(-1);
+ RETURN_RESULT(Encode(-1));
}
-ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
+void ArrayPrototype::method_join(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue arg(scope, ctx->argument(0));
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedValue arg(scope, callData->argument(0));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
- if (!instance)
- return ctx->d()->engine->newString()->asReturnedValue();
+ if (!instance) {
+ scope.result = scope.engine->newString();
+ return;
+ }
QString r4;
if (arg->isUndefined())
@@ -273,11 +267,13 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
else
r4 = arg->toQString();
- ScopedValue length(scope, instance->get(ctx->d()->engine->id_length()));
+ ScopedValue length(scope, instance->get(scope.engine->id_length()));
const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32();
- if (!r2)
- return ctx->d()->engine->newString()->asReturnedValue();
+ if (!r2) {
+ scope.result = scope.engine->newString();
+ return;
+ }
QString R;
@@ -289,8 +285,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
R += r4;
e = a->getIndexed(i);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (!e->isNullOrUndefined())
R += e->toQString();
}
@@ -298,7 +293,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
//
// crazy!
//
- ScopedString name(scope, ctx->d()->engine->newString(QStringLiteral("0")));
+ ScopedString name(scope, scope.engine->newString(QStringLiteral("0")));
ScopedValue r6(scope, instance->get(name));
if (!r6->isNullOrUndefined())
R = r6->toQString();
@@ -309,99 +304,98 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
name = Primitive::fromDouble(k).toString(scope.engine);
r12 = instance->get(name);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (!r12->isNullOrUndefined())
R += r12->toQString();
}
}
- return ctx->d()->engine->newString(R)->asReturnedValue();
+ scope.result = scope.engine->newString(R);
}
-ReturnedValue ArrayPrototype::method_pop(CallContext *ctx)
+void ArrayPrototype::method_pop(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
+
uint len = instance->getLength();
if (!len) {
if (!instance->isArrayObject())
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0)));
- return Encode::undefined();
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0)));
+ RETURN_UNDEFINED();
}
ScopedValue result(scope, instance->getIndexed(len - 1));
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
instance->deleteIndexedProperty(len - 1);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
+
if (instance->isArrayObject())
instance->setArrayLength(len - 1);
else
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1)));
- return result->asReturnedValue();
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1)));
+ scope.result = result;
}
-ReturnedValue ArrayPrototype::method_push(CallContext *ctx)
+void ArrayPrototype::method_push(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
instance->arrayCreate();
Q_ASSERT(instance->arrayData());
uint len = instance->getLength();
- if (len + ctx->argc() < len) {
+ if (len + callData->argc < len) {
// ughh...
double l = len;
ScopedString s(scope);
- for (int i = 0; i < ctx->argc(); ++i) {
+ for (int i = 0; i < callData->argc; ++i) {
s = Primitive::fromDouble(l + i).toString(scope.engine);
- instance->put(s, ctx->args()[i]);
+ instance->put(s, callData->args[i]);
}
- double newLen = l + ctx->argc();
+ double newLen = l + callData->argc;
if (!instance->isArrayObject())
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen)));
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen)));
else {
- ScopedString str(scope, ctx->d()->engine->newString(QStringLiteral("Array.prototype.push: Overflow")));
- return ctx->engine()->throwRangeError(str);
+ ScopedString str(scope, scope.engine->newString(QStringLiteral("Array.prototype.push: Overflow")));
+ scope.result = scope.engine->throwRangeError(str);
+ return;
}
- return Encode(newLen);
+ scope.result = Encode(newLen);
+ return;
}
- if (!ctx->argc())
+ if (!callData->argc)
;
else if (!instance->protoHasArray() && instance->arrayData()->length() <= len && instance->arrayData()->type == Heap::ArrayData::Simple) {
- instance->arrayData()->vtable()->putArray(instance, len, ctx->args(), ctx->argc());
+ instance->arrayData()->vtable()->putArray(instance, len, callData->args, callData->argc);
len = instance->arrayData()->length();
} else {
- for (int i = 0; i < ctx->argc(); ++i)
- instance->putIndexed(len + i, ctx->args()[i]);
- len += ctx->argc();
+ for (int i = 0; i < callData->argc; ++i)
+ instance->putIndexed(len + i, callData->args[i]);
+ len += callData->argc;
}
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(len);
else
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len)));
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len)));
- return Encode(len);
+ scope.result = Encode(len);
}
-ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx)
+void ArrayPrototype::method_reverse(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
+
uint length = instance->getLength();
int lo = 0, hi = length - 1;
@@ -412,28 +406,25 @@ ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx)
bool loExists, hiExists;
lval = instance->getIndexed(lo, &loExists);
hval = instance->getIndexed(hi, &hiExists);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (hiExists)
instance->putIndexed(lo, hval);
else
instance->deleteIndexedProperty(lo);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (loExists)
instance->putIndexed(hi, lval);
else
instance->deleteIndexedProperty(hi);
}
- return instance.asReturnedValue();
+ scope.result = instance;
}
-ReturnedValue ArrayPrototype::method_shift(CallContext *ctx)
+void ArrayPrototype::method_shift(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
instance->arrayCreate();
Q_ASSERT(instance->arrayData());
@@ -442,54 +433,46 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx)
if (!len) {
if (!instance->isArrayObject())
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0)));
- return Encode::undefined();
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0)));
+ RETURN_UNDEFINED();
}
- ScopedValue result(scope);
-
if (!instance->protoHasArray() && !instance->arrayData()->attrs && instance->arrayData()->length() <= len && instance->arrayData()->type != Heap::ArrayData::Custom) {
- result = instance->arrayData()->vtable()->pop_front(instance);
+ scope.result = instance->arrayData()->vtable()->pop_front(instance);
} else {
- result = instance->getIndexed(0);
- if (scope.hasException())
- return Encode::undefined();
+ scope.result = instance->getIndexed(0);
+ CHECK_EXCEPTION();
ScopedValue v(scope);
// do it the slow way
for (uint k = 1; k < len; ++k) {
bool exists;
v = instance->getIndexed(k, &exists);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (exists)
instance->putIndexed(k - 1, v);
else
instance->deleteIndexedProperty(k - 1);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
}
instance->deleteIndexedProperty(len - 1);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
}
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(len - 1);
else
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1)));
- return result->asReturnedValue();
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1)));
}
-ReturnedValue ArrayPrototype::method_slice(CallContext *ctx)
+void ArrayPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject o(scope, callData->thisObject.toObject(scope.engine));
if (!o)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- ScopedArrayObject result(scope, ctx->d()->engine->newArrayObject());
+ ScopedArrayObject result(scope, scope.engine->newArrayObject());
uint len = o->getLength();
- double s = ScopedValue(scope, ctx->argument(0))->toInteger();
+ double s = ScopedValue(scope, callData->argument(0))->toInteger();
uint start;
if (s < 0)
start = (uint)qMax(len + s, 0.);
@@ -498,8 +481,8 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx)
else
start = (uint) s;
uint end = len;
- if (ctx->argc() > 1 && !ctx->args()[1].isUndefined()) {
- double e = ctx->args()[1].toInteger();
+ if (callData->argc > 1 && !callData->args[1].isUndefined()) {
+ double e = callData->args[1].toInteger();
if (e < 0)
end = (uint)qMax(len + e, 0.);
else if (e > len)
@@ -513,115 +496,107 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx)
for (uint i = start; i < end; ++i) {
bool exists;
v = o->getIndexed(i, &exists);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (exists)
result->arraySet(n, v);
++n;
}
- return result.asReturnedValue();
+ scope.result = result;
}
-ReturnedValue ArrayPrototype::method_sort(CallContext *ctx)
+void ArrayPrototype::method_sort(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedValue comparefn(scope, ctx->argument(0));
+ ScopedValue comparefn(scope, callData->argument(0));
ArrayData::sort(scope.engine, instance, comparefn, len);
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
}
-ReturnedValue ArrayPrototype::method_splice(CallContext *ctx)
+void ArrayPrototype::method_splice(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
+
uint len = instance->getLength();
- ScopedArrayObject newArray(scope, ctx->d()->engine->newArrayObject());
+ ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
- double rs = ScopedValue(scope, ctx->argument(0))->toInteger();
+ double rs = ScopedValue(scope, callData->argument(0))->toInteger();
uint start;
if (rs < 0)
start = (uint) qMax(0., len + rs);
else
start = (uint) qMin(rs, (double)len);
- uint deleteCount = (uint)qMin(qMax(ScopedValue(scope, ctx->argument(1))->toInteger(), 0.), (double)(len - start));
+ uint deleteCount = (uint)qMin(qMax(ScopedValue(scope, callData->argument(1))->toInteger(), 0.), (double)(len - start));
newArray->arrayReserve(deleteCount);
ScopedValue v(scope);
for (uint i = 0; i < deleteCount; ++i) {
bool exists;
v = instance->getIndexed(start + i, &exists);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (exists)
newArray->arrayPut(i, v);
}
newArray->setArrayLengthUnchecked(deleteCount);
- uint itemCount = ctx->argc() < 2 ? 0 : ctx->argc() - 2;
+ uint itemCount = callData->argc < 2 ? 0 : callData->argc - 2;
if (itemCount < deleteCount) {
for (uint k = start; k < len - deleteCount; ++k) {
bool exists;
v = instance->getIndexed(k + deleteCount, &exists);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (exists)
instance->putIndexed(k + itemCount, v);
else
instance->deleteIndexedProperty(k + itemCount);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
}
for (uint k = len; k > len - deleteCount + itemCount; --k) {
instance->deleteIndexedProperty(k - 1);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
}
} else if (itemCount > deleteCount) {
uint k = len - deleteCount;
while (k > start) {
bool exists;
v = instance->getIndexed(k + deleteCount - 1, &exists);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (exists)
instance->putIndexed(k + itemCount - 1, v);
else
instance->deleteIndexedProperty(k + itemCount - 1);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
--k;
}
}
for (uint i = 0; i < itemCount; ++i) {
- instance->putIndexed(start + i, ctx->args()[i + 2]);
- if (scope.hasException())
- return Encode::undefined();
+ instance->putIndexed(start + i, callData->args[i + 2]);
+ CHECK_EXCEPTION();
}
- ctx->d()->strictMode = true;
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount)));
+ bool wasStrict = scope.engine->current->strictMode;
+ scope.engine->current->strictMode = true;
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount)));
- return newArray.asReturnedValue();
+ scope.result = newArray;
+ scope.engine->current->strictMode = wasStrict;
}
-ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx)
+void ArrayPrototype::method_unshift(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
instance->arrayCreate();
Q_ASSERT(instance->arrayData());
@@ -630,50 +605,52 @@ ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx)
if (!instance->protoHasArray() && !instance->arrayData()->attrs && instance->arrayData()->length() <= len &&
instance->arrayData()->type != Heap::ArrayData::Custom) {
- instance->arrayData()->vtable()->push_front(instance, ctx->args(), ctx->argc());
+ instance->arrayData()->vtable()->push_front(instance, callData->args, callData->argc);
} else {
ScopedValue v(scope);
for (uint k = len; k > 0; --k) {
bool exists;
v = instance->getIndexed(k - 1, &exists);
if (exists)
- instance->putIndexed(k + ctx->argc() - 1, v);
+ instance->putIndexed(k + callData->argc - 1, v);
else
- instance->deleteIndexedProperty(k + ctx->argc() - 1);
+ instance->deleteIndexedProperty(k + callData->argc - 1);
}
- for (int i = 0; i < ctx->argc(); ++i)
- instance->putIndexed(i, ctx->args()[i]);
+ for (int i = 0; i < callData->argc; ++i)
+ instance->putIndexed(i, callData->args[i]);
}
- uint newLen = len + ctx->argc();
+ uint newLen = len + callData->argc;
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(newLen);
else
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen)));
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen)));
- return Encode(newLen);
+ scope.result = Encode(newLen);
}
-ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
+void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
-
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
+
uint len = instance->getLength();
- if (!len)
- return Encode(-1);
+ if (!len) {
+ scope.result = Encode(-1);
+ return;
+ }
- ScopedValue searchValue(scope, ctx->argument(0));
+ ScopedValue searchValue(scope, callData->argument(0));
uint fromIndex = 0;
- if (ctx->argc() >= 2) {
- double f = ctx->args()[1].toInteger();
- if (scope.hasException())
- return Encode::undefined();
- if (f >= len)
- return Encode(-1);
+ if (callData->argc >= 2) {
+ double f = callData->args[1].toInteger();
+ CHECK_EXCEPTION();
+ if (f >= len) {
+ scope.result = Encode(-1);
+ return;
+ }
if (f < 0)
f = qMax(len + f, 0.);
fromIndex = (uint) f;
@@ -684,10 +661,13 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
for (uint k = fromIndex; k < len; ++k) {
bool exists;
v = instance->getIndexed(k, &exists);
- if (exists && RuntimeHelpers::strictEqual(v, searchValue))
- return Encode(k);
+ if (exists && RuntimeHelpers::strictEqual(v, searchValue)) {
+ scope.result = Encode(k);
+ return;
+ }
}
- return Encode(-1);
+ scope.result = Encode(-1);
+ return;
}
ScopedValue value(scope);
@@ -698,13 +678,15 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
for (uint i = fromIndex; i < len; ++i) {
bool exists;
value = instance->getIndexed(i, &exists);
- if (scope.hasException())
- return Encode::undefined();
- if (exists && RuntimeHelpers::strictEqual(value, searchValue))
- return Encode(i);
+ CHECK_EXCEPTION();
+ if (exists && RuntimeHelpers::strictEqual(value, searchValue)) {
+ scope.result = Encode(i);
+ return;
+ }
}
} else if (!instance->arrayData()) {
- return Encode(-1);
+ scope.result = Encode(-1);
+ return;
} else {
Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex);
Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>();
@@ -713,45 +695,48 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
uint idx = fromIndex;
while (idx < len) {
value = sa->data(idx);
- if (scope.hasException())
- return Encode::undefined();
- if (RuntimeHelpers::strictEqual(value, searchValue))
- return Encode(idx);
+ CHECK_EXCEPTION();
+ if (RuntimeHelpers::strictEqual(value, searchValue)) {
+ scope.result = Encode(idx);
+ return;
+ }
++idx;
}
}
- return Encode(-1);
+ scope.result = Encode(-1);
}
-ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx)
+void ArrayPrototype::method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
-
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
+
uint len = instance->getLength();
- if (!len)
- return Encode(-1);
+ if (!len) {
+ scope.result = Encode(-1);
+ return;
+ }
ScopedValue searchValue(scope);
uint fromIndex = len;
- if (ctx->argc() >= 1)
- searchValue = ctx->argument(0);
+ if (callData->argc >= 1)
+ searchValue = callData->argument(0);
else
searchValue = Primitive::undefinedValue();
- if (ctx->argc() >= 2) {
- double f = ctx->args()[1].toInteger();
- if (scope.hasException())
- return Encode::undefined();
+ if (callData->argc >= 2) {
+ double f = callData->args[1].toInteger();
+ CHECK_EXCEPTION();
if (f > 0)
f = qMin(f, (double)(len - 1));
else if (f < 0) {
f = len + f;
- if (f < 0)
- return Encode(-1);
+ if (f < 0) {
+ scope.result = Encode(-1);
+ return;
+ }
}
fromIndex = (uint) f + 1;
}
@@ -761,30 +746,30 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx)
--k;
bool exists;
v = instance->getIndexed(k, &exists);
- if (scope.hasException())
- return Encode::undefined();
- if (exists && RuntimeHelpers::strictEqual(v, searchValue))
- return Encode(k);
+ CHECK_EXCEPTION();
+ if (exists && RuntimeHelpers::strictEqual(v, searchValue)) {
+ scope.result = Encode(k);
+ return;
+ }
}
- return Encode(-1);
+ scope.result = Encode(-1);
}
-ReturnedValue ArrayPrototype::method_every(CallContext *ctx)
+void ArrayPrototype::method_every(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, 3);
- callData->args[2] = instance;
- callData->thisObject = ctx->argument(1);
+ ScopedCallData cData(scope, 3);
+ cData->args[2] = instance;
+ cData->thisObject = callData->argument(1);
ScopedValue v(scope);
bool ok = true;
@@ -794,30 +779,29 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx)
if (!exists)
continue;
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
ok = scope.result.toBoolean();
}
- return Encode(ok);
+ scope.result = Encode(ok);
}
-ReturnedValue ArrayPrototype::method_some(CallContext *ctx)
+void ArrayPrototype::method_some(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, 3);
- callData->thisObject = ctx->argument(1);
- callData->args[2] = instance;
+ ScopedCallData cData(scope, 3);
+ cData->thisObject = callData->argument(1);
+ cData->args[2] = instance;
ScopedValue v(scope);
for (uint k = 0; k < len; ++k) {
@@ -826,31 +810,32 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx)
if (!exists)
continue;
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
- if (scope.result.toBoolean())
- return Encode(true);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
+ if (scope.result.toBoolean()) {
+ scope.result = Encode(true);
+ return;
+ }
}
- return Encode(false);
+ scope.result = Encode(false);
}
-ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx)
+void ArrayPrototype::method_forEach(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, 3);
- callData->thisObject = ctx->argument(1);
- callData->args[2] = instance;
+ ScopedCallData cData(scope, 3);
+ cData->thisObject = callData->argument(1);
+ cData->args[2] = instance;
ScopedValue v(scope);
for (uint k = 0; k < len; ++k) {
@@ -859,33 +844,32 @@ ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx)
if (!exists)
continue;
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
}
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
+void ArrayPrototype::method_map(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject());
+ ScopedArrayObject a(scope, scope.engine->newArrayObject());
a->arrayReserve(len);
a->setArrayLengthUnchecked(len);
- ScopedCallData callData(scope, 3);
- callData->thisObject = ctx->argument(1);
- callData->args[2] = instance;
+ ScopedCallData cData(scope, 3);
+ cData->thisObject = callData->argument(1);
+ cData->args[2] = instance;
ScopedValue v(scope);
for (uint k = 0; k < len; ++k) {
@@ -894,33 +878,32 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
if (!exists)
continue;
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
a->arraySet(k, scope.result);
}
- return a.asReturnedValue();
+ scope.result = a.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
+void ArrayPrototype::method_filter(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject());
+ ScopedArrayObject a(scope, scope.engine->newArrayObject());
a->arrayReserve(len);
- ScopedCallData callData(scope, 3);
- callData->thisObject = ctx->argument(1);
- callData->args[2] = instance;
+ ScopedCallData cData(scope, 3);
+ cData->thisObject = callData->argument(1);
+ cData->args[2] = instance;
ScopedValue v(scope);
@@ -931,35 +914,34 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
if (!exists)
continue;
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
if (scope.result.toBoolean()) {
a->arraySet(to, v);
++to;
}
}
- return a.asReturnedValue();
+ scope.result = a.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
+void ArrayPrototype::method_reduce(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
uint k = 0;
ScopedValue v(scope);
- if (ctx->argc() > 1) {
- scope.result = ctx->argument(1);
+ if (callData->argc > 1) {
+ scope.result = callData->argument(1);
} else {
bool kPresent = false;
while (k < len && !kPresent) {
@@ -969,51 +951,50 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
++k;
}
if (!kPresent)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
}
- ScopedCallData callData(scope, 4);
- callData->thisObject = Primitive::undefinedValue();
- callData->args[0] = scope.result;
- callData->args[3] = instance;
+ ScopedCallData cData(scope, 4);
+ cData->thisObject = Primitive::undefinedValue();
+ cData->args[0] = scope.result;
+ cData->args[3] = instance;
while (k < len) {
bool kPresent;
v = instance->getIndexed(k, &kPresent);
if (kPresent) {
- callData->args[0] = scope.result;
- callData->args[1] = v;
- callData->args[2] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = scope.result;
+ cData->args[1] = v;
+ cData->args[2] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
}
++k;
}
- return scope.result.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
+void ArrayPrototype::method_reduceRight(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (len == 0) {
- if (ctx->argc() == 1)
- return ctx->engine()->throwTypeError();
- return ctx->argument(1);
+ if (callData->argc == 1)
+ THROW_TYPE_ERROR();
+ scope.result = callData->argument(1);
+ return;
}
uint k = len;
ScopedValue v(scope);
- if (ctx->argc() > 1) {
- scope.result = ctx->argument(1);
+ if (callData->argc > 1) {
+ scope.result = callData->argument(1);
} else {
bool kPresent = false;
while (k > 0 && !kPresent) {
@@ -1023,24 +1004,24 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
--k;
}
if (!kPresent)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
}
- ScopedCallData callData(scope, 4);
- callData->thisObject = Primitive::undefinedValue();
- callData->args[3] = instance;
+ ScopedCallData cData(scope, 4);
+ cData->thisObject = Primitive::undefinedValue();
+ cData->args[3] = instance;
while (k > 0) {
bool kPresent;
v = instance->getIndexed(k - 1, &kPresent);
if (kPresent) {
- callData->args[0] = scope.result;
- callData->args[1] = v;
- callData->args[2] = Primitive::fromDouble(k - 1);
- callback->call(scope, callData);
+ cData->args[0] = scope.result;
+ cData->args[1] = v;
+ cData->args[2] = Primitive::fromDouble(k - 1);
+ callback->call(scope, cData);
}
--k;
}
- return scope.result.asReturnedValue();
+ scope.result = scope.result.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index f00c0c0249..689752433b 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -78,30 +78,30 @@ struct ArrayPrototype: ArrayObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_isArray(CallContext *ctx);
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_toLocaleString(CallContext *ctx);
- static ReturnedValue method_concat(CallContext *ctx);
- static ReturnedValue method_find(CallContext *ctx);
- static ReturnedValue method_findIndex(CallContext *ctx);
- static ReturnedValue method_join(CallContext *ctx);
- static ReturnedValue method_pop(CallContext *ctx);
- static ReturnedValue method_push(CallContext *ctx);
- static ReturnedValue method_reverse(CallContext *ctx);
- static ReturnedValue method_shift(CallContext *ctx);
- static ReturnedValue method_slice(CallContext *ctx);
- static ReturnedValue method_sort(CallContext *ctx);
- static ReturnedValue method_splice(CallContext *ctx);
- static ReturnedValue method_unshift(CallContext *ctx);
- static ReturnedValue method_indexOf(CallContext *ctx);
- static ReturnedValue method_lastIndexOf(CallContext *ctx);
- static ReturnedValue method_every(CallContext *ctx);
- static ReturnedValue method_some(CallContext *ctx);
- static ReturnedValue method_forEach(CallContext *ctx);
- static ReturnedValue method_map(CallContext *ctx);
- static ReturnedValue method_filter(CallContext *ctx);
- static ReturnedValue method_reduce(CallContext *ctx);
- static ReturnedValue method_reduceRight(CallContext *ctx);
+ static void method_isArray(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_toString(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_toLocaleString(const BuiltinFunction *builtin, Scope &, CallData *callData);
+ static void method_concat(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_find(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_findIndex(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_join(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_pop(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_push(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_reverse(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_shift(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_slice(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_sort(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_splice(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_unshift(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_indexOf(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_lastIndexOf(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_every(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_some(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_forEach(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_map(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_filter(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_reduce(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_reduceRight(const BuiltinFunction *, Scope &, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index 8047993266..601066110f 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -73,29 +73,31 @@ void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(engine->id_valueOf(), method_valueOf);
}
-ReturnedValue BooleanPrototype::method_toString(CallContext *ctx)
+void BooleanPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
bool result;
- if (ctx->thisObject().isBoolean()) {
- result = ctx->thisObject().booleanValue();
+ if (callData->thisObject.isBoolean()) {
+ result = callData->thisObject.booleanValue();
} else {
- const BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>();
+ const BooleanObject *thisObject = callData->thisObject.as<BooleanObject>();
if (!thisObject)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
result = thisObject->value();
}
- return Encode(ctx->d()->engine->newString(QLatin1String(result ? "true" : "false")));
+ scope.result = scope.engine->newString(QLatin1String(result ? "true" : "false"));
}
-ReturnedValue BooleanPrototype::method_valueOf(CallContext *ctx)
+void BooleanPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->thisObject().isBoolean())
- return ctx->thisObject().asReturnedValue();
+ if (callData->thisObject.isBoolean()) {
+ scope.result = callData->thisObject.asReturnedValue();
+ return;
+ }
- const BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>();
+ const BooleanObject *thisObject = callData->thisObject.as<BooleanObject>();
if (!thisObject)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(thisObject->value());
+ scope.result = Encode(thisObject->value());
}
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index 4c2f3c09e7..9c8b1d67f1 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -78,8 +78,8 @@ struct BooleanPrototype: BooleanObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_valueOf(CallContext *ctx);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 544d39339b..60b90e4bf0 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -95,6 +95,17 @@ Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData
return c;
}
+Heap::CallContext *Heap::CallContext::createSimpleContext(ExecutionEngine *v4)
+{
+ Heap::CallContext *ctxt = v4->memoryManager->allocSimpleCallContext(v4);
+ return ctxt;
+}
+
+void Heap::CallContext::freeSimpleCallContext()
+{
+ engine->memoryManager->freeSimpleCallContext();
+}
+
Heap::WithContext *ExecutionContext::newWithContext(Heap::Object *with)
{
return d()->engine->memoryManager->alloc<WithContext>(d(), with);
@@ -325,26 +336,27 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data ctx = CallContext::Data::createOnStack(scope.engine);
+ CallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(scope.engine);
- ctx.strictMode = function->isStrict();
- ctx.callData = callData;
- ctx.v4Function = function;
- ctx.compilationUnit = function->compilationUnit;
- ctx.lookups = function->compilationUnit->runtimeLookups;
- ctx.constantTable = function->compilationUnit->constants;
- ctx.outer = this->d();
- ctx.locals = scope.alloc(function->compiledFunction->nLocals);
+ ctx->strictMode = function->isStrict();
+ ctx->callData = callData;
+ ctx->v4Function = function;
+ ctx->compilationUnit = function->compilationUnit;
+ ctx->lookups = function->compilationUnit->runtimeLookups;
+ ctx->constantTable = function->compilationUnit->constants;
+ ctx->outer = this->d();
+ ctx->locals = scope.alloc(function->compiledFunction->nLocals);
for (int i = callData->argc; i < (int)function->nFormals; ++i)
callData->args[i] = Encode::undefined();
- scope.engine->pushContext(&ctx);
- Q_ASSERT(scope.engine->current == &ctx);
+ scope.engine->pushContext(ctx);
+ Q_ASSERT(scope.engine->current == ctx);
scope.result = Q_V4_PROFILE(scope.engine, function);
if (function->hasQmlDependencies)
QQmlPropertyCapture::registerQmlDependencies(function->compiledFunction, scope);
+ scope.engine->memoryManager->freeSimpleCallContext();
}
void ExecutionContext::setProperty(String *name, const Value &value)
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index c985fdb24d..bcfee2e1f8 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -109,14 +109,8 @@ struct ExecutionContext : Base {
{
Base::init();
- callData = nullptr;
this->engine = engine;
- outer = nullptr;
- lookups = nullptr;
- constantTable = nullptr;
- compilationUnit = nullptr;
type = t;
- strictMode = false;
lineNumber = -1;
}
@@ -135,15 +129,12 @@ struct ExecutionContext : Base {
V4_ASSERT_IS_TRIVIAL(ExecutionContext)
struct CallContext : ExecutionContext {
- static CallContext createOnStack(ExecutionEngine *v4);
+ static CallContext *createSimpleContext(ExecutionEngine *v4);
+ void freeSimpleCallContext();
void init(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext)
{
ExecutionContext::init(engine, t);
- function = 0;
- v4Function = 0;
- locals = 0;
- activation = 0;
}
inline unsigned int formalParameterCount() const;
@@ -247,6 +238,7 @@ struct Q_QML_EXPORT CallContext : public ExecutionContext
inline ReturnedValue argument(int i) const;
bool needsOwnArguments() const;
+
};
inline ReturnedValue CallContext::argument(int i) const {
@@ -289,16 +281,6 @@ inline const WithContext *ExecutionContext::asWithContext() const
return d()->type == Heap::ExecutionContext::Type_WithContext ? static_cast<const WithContext *>(this) : 0;
}
-inline Heap::CallContext Heap::CallContext::createOnStack(ExecutionEngine *v4)
-{
- Heap::CallContext ctxt;
- memset(&ctxt, 0, sizeof(Heap::CallContext));
- ctxt.mm_data = 0;
- ctxt.setVtable(QV4::CallContext::staticVTable());
- ctxt.init(v4);
- return ctxt;
-}
-
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index db8376272d..a810b38f24 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -129,90 +129,84 @@ void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0);
}
-ReturnedValue DataViewPrototype::method_get_buffer(CallContext *ctx)
+void DataViewPrototype::method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
+ Scoped<DataView> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->buffer->asReturnedValue());
+ scope.result = v->d()->buffer;
}
-ReturnedValue DataViewPrototype::method_get_byteLength(CallContext *ctx)
+void DataViewPrototype::method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
+ Scoped<DataView> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->byteLength);
+ scope.result = Encode(v->d()->byteLength);
}
-ReturnedValue DataViewPrototype::method_get_byteOffset(CallContext *ctx)
+void DataViewPrototype::method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
+ Scoped<DataView> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->byteOffset);
+ scope.result = Encode(v->d()->byteOffset);
}
template <typename T>
-ReturnedValue DataViewPrototype::method_getChar(CallContext *ctx)
+void DataViewPrototype::method_getChar(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
- if (!v || ctx->argc() < 1)
- return scope.engine->throwTypeError();
- double l = ctx->args()[0].toNumber();
+ Scoped<DataView> v(scope, callData->thisObject);
+ if (!v || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
idx += v->d()->byteOffset;
T t = T(v->d()->buffer->data->data()[idx]);
- return Encode((int)t);
+ scope.result = Encode((int)t);
}
template <typename T>
-ReturnedValue DataViewPrototype::method_get(CallContext *ctx)
+void DataViewPrototype::method_get(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
- if (!v || ctx->argc() < 1)
- return scope.engine->throwTypeError();
- double l = ctx->args()[0].toNumber();
+ Scoped<DataView> v(scope, callData->thisObject);
+ if (!v || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
idx += v->d()->byteOffset;
- bool littleEndian = ctx->argc() < 2 ? false : ctx->args()[1].toBoolean();
+ bool littleEndian = callData->argc < 2 ? false : callData->args[1].toBoolean();
T t = littleEndian
? qFromLittleEndian<T>((uchar *)v->d()->buffer->data->data() + idx)
: qFromBigEndian<T>((uchar *)v->d()->buffer->data->data() + idx);
- return Encode(t);
+ scope.result = Encode(t);
}
template <typename T>
-ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx)
+void DataViewPrototype::method_getFloat(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
- if (!v || ctx->argc() < 1)
- return scope.engine->throwTypeError();
- double l = ctx->args()[0].toNumber();
+ Scoped<DataView> v(scope, callData->thisObject);
+ if (!v || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
idx += v->d()->byteOffset;
- bool littleEndian = ctx->argc() < 2 ? false : ctx->args()[1].toBoolean();
+ bool littleEndian = callData->argc < 2 ? false : callData->args[1].toBoolean();
if (sizeof(T) == 4) {
// float
@@ -223,7 +217,7 @@ ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx)
u.i = littleEndian
? qFromLittleEndian<uint>((uchar *)v->d()->buffer->data->data() + idx)
: qFromBigEndian<uint>((uchar *)v->d()->buffer->data->data() + idx);
- return Encode(u.f);
+ scope.result = Encode(u.f);
} else {
Q_ASSERT(sizeof(T) == 8);
union {
@@ -233,69 +227,66 @@ ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx)
u.i = littleEndian
? qFromLittleEndian<quint64>((uchar *)v->d()->buffer->data->data() + idx)
: qFromBigEndian<quint64>((uchar *)v->d()->buffer->data->data() + idx);
- return Encode(u.d);
+ scope.result = Encode(u.d);
}
}
template <typename T>
-ReturnedValue DataViewPrototype::method_setChar(CallContext *ctx)
+void DataViewPrototype::method_setChar(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
- if (!v || ctx->argc() < 1)
- return scope.engine->throwTypeError();
- double l = ctx->args()[0].toNumber();
+ Scoped<DataView> v(scope, callData->thisObject);
+ if (!v || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
idx += v->d()->byteOffset;
- int val = ctx->argc() >= 2 ? ctx->args()[1].toInt32() : 0;
+ int val = callData->argc >= 2 ? callData->args[1].toInt32() : 0;
v->d()->buffer->data->data()[idx] = (char)val;
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
template <typename T>
-ReturnedValue DataViewPrototype::method_set(CallContext *ctx)
+void DataViewPrototype::method_set(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
- if (!v || ctx->argc() < 1)
- return scope.engine->throwTypeError();
- double l = ctx->args()[0].toNumber();
+ Scoped<DataView> v(scope, callData->thisObject);
+ if (!v || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
idx += v->d()->byteOffset;
- int val = ctx->argc() >= 2 ? ctx->args()[1].toInt32() : 0;
+ int val = callData->argc >= 2 ? callData->args[1].toInt32() : 0;
- bool littleEndian = ctx->argc() < 3 ? false : ctx->args()[2].toBoolean();
+ bool littleEndian = callData->argc < 3 ? false : callData->args[2].toBoolean();
if (littleEndian)
qToLittleEndian<T>(val, (uchar *)v->d()->buffer->data->data() + idx);
else
qToBigEndian<T>(val, (uchar *)v->d()->buffer->data->data() + idx);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
template <typename T>
-ReturnedValue DataViewPrototype::method_setFloat(CallContext *ctx)
+void DataViewPrototype::method_setFloat(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
- if (!v || ctx->argc() < 1)
- return scope.engine->throwTypeError();
- double l = ctx->args()[0].toNumber();
+ Scoped<DataView> v(scope, callData->thisObject);
+ if (!v || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
idx += v->d()->byteOffset;
- double val = ctx->argc() >= 2 ? ctx->args()[1].toNumber() : qt_qnan();
- bool littleEndian = ctx->argc() < 3 ? false : ctx->args()[2].toBoolean();
+ double val = callData->argc >= 2 ? callData->args[1].toNumber() : qt_qnan();
+ bool littleEndian = callData->argc < 3 ? false : callData->args[2].toBoolean();
if (sizeof(T) == 4) {
// float
@@ -320,5 +311,5 @@ ReturnedValue DataViewPrototype::method_setFloat(CallContext *ctx)
else
qToBigEndian(u.i, (uchar *)v->d()->buffer->data->data() + idx);
}
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index 246124394a..11cc0a6bd9 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -92,21 +92,21 @@ struct DataViewPrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_get_buffer(CallContext *ctx);
- static ReturnedValue method_get_byteLength(CallContext *ctx);
- static ReturnedValue method_get_byteOffset(CallContext *ctx);
+ static void method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData);
template <typename T>
- static ReturnedValue method_getChar(CallContext *ctx);
+ static void method_getChar(const BuiltinFunction *, Scope &scope, CallData *callData);
template <typename T>
- static ReturnedValue method_get(CallContext *ctx);
+ static void method_get(const BuiltinFunction *, Scope &scope, CallData *callData);
template <typename T>
- static ReturnedValue method_getFloat(CallContext *ctx);
+ static void method_getFloat(const BuiltinFunction *, Scope &scope, CallData *callData);
template <typename T>
- static ReturnedValue method_setChar(CallContext *ctx);
+ static void method_setChar(const BuiltinFunction *, Scope &scope, CallData *callData);
template <typename T>
- static ReturnedValue method_set(CallContext *ctx);
+ static void method_set(const BuiltinFunction *, Scope &scope, CallData *callData);
template <typename T>
- static ReturnedValue method_setFloat(CallContext *ctx);
+ static void method_setFloat(const BuiltinFunction *, Scope &scope, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 8cc6a25fea..b90c335b1c 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -780,435 +780,435 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("toJSON"), method_toJSON, 1);
}
-double DatePrototype::getThisDate(ExecutionContext *ctx)
+double DatePrototype::getThisDate(Scope &scope, CallData *callData)
{
- if (DateObject *thisObject = ctx->thisObject().as<DateObject>())
+ if (DateObject *thisObject = callData->thisObject.as<DateObject>())
return thisObject->date();
else {
- ctx->engine()->throwTypeError();
+ scope.engine->throwTypeError();
return 0;
}
}
-ReturnedValue DatePrototype::method_parse(CallContext *ctx)
+void DatePrototype::method_parse(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!ctx->argc())
- return Encode(qt_qnan());
- return Encode(ParseString(ctx->args()[0].toQString()));
+ if (!callData->argc)
+ scope.result = Encode(qt_qnan());
+ else
+ scope.result = Encode(ParseString(callData->args[0].toQString()));
}
-ReturnedValue DatePrototype::method_UTC(CallContext *ctx)
+void DatePrototype::method_UTC(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- const int numArgs = ctx->argc();
+ const int numArgs = callData->argc;
if (numArgs >= 2) {
- double year = ctx->args()[0].toNumber();
- double month = ctx->args()[1].toNumber();
- double day = numArgs >= 3 ? ctx->args()[2].toNumber() : 1;
- double hours = numArgs >= 4 ? ctx->args()[3].toNumber() : 0;
- double mins = numArgs >= 5 ? ctx->args()[4].toNumber() : 0;
- double secs = numArgs >= 6 ? ctx->args()[5].toNumber() : 0;
- double ms = numArgs >= 7 ? ctx->args()[6].toNumber() : 0;
+ double year = callData->args[0].toNumber();
+ double month = callData->args[1].toNumber();
+ double day = numArgs >= 3 ? callData->args[2].toNumber() : 1;
+ double hours = numArgs >= 4 ? callData->args[3].toNumber() : 0;
+ double mins = numArgs >= 5 ? callData->args[4].toNumber() : 0;
+ double secs = numArgs >= 6 ? callData->args[5].toNumber() : 0;
+ double ms = numArgs >= 7 ? callData->args[6].toNumber() : 0;
if (year >= 0 && year <= 99)
year += 1900;
double t = MakeDate(MakeDay(year, month, day),
MakeTime(hours, mins, secs, ms));
- return Encode(TimeClip(t));
+ scope.result = Encode(TimeClip(t));
+ return;
}
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue DatePrototype::method_now(CallContext *ctx)
+void DatePrototype::method_now(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Q_UNUSED(ctx);
+ Q_UNUSED(callData);
double t = currentTime();
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_toString(CallContext *ctx)
+void DatePrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return ctx->d()->engine->newString(ToString(t))->asReturnedValue();
+ double t = getThisDate(scope, callData);
+ scope.result = scope.engine->newString(ToString(t));
}
-ReturnedValue DatePrototype::method_toDateString(CallContext *ctx)
+void DatePrototype::method_toDateString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return ctx->d()->engine->newString(ToDateString(t))->asReturnedValue();
+ double t = getThisDate(scope, callData);
+ scope.result = scope.engine->newString(ToDateString(t));
}
-ReturnedValue DatePrototype::method_toTimeString(CallContext *ctx)
+void DatePrototype::method_toTimeString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return ctx->d()->engine->newString(ToTimeString(t))->asReturnedValue();
+ double t = getThisDate(scope, callData);
+ scope.result = scope.engine->newString(ToTimeString(t));
}
-ReturnedValue DatePrototype::method_toLocaleString(CallContext *ctx)
+void DatePrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return ctx->d()->engine->newString(ToLocaleString(t))->asReturnedValue();
+ double t = getThisDate(scope, callData);
+ scope.result = scope.engine->newString(ToLocaleString(t));
}
-ReturnedValue DatePrototype::method_toLocaleDateString(CallContext *ctx)
+void DatePrototype::method_toLocaleDateString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return ctx->d()->engine->newString(ToLocaleDateString(t))->asReturnedValue();
+ double t = getThisDate(scope, callData);
+ scope.result = scope.engine->newString(ToLocaleDateString(t));
}
-ReturnedValue DatePrototype::method_toLocaleTimeString(CallContext *ctx)
+void DatePrototype::method_toLocaleTimeString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return ctx->d()->engine->newString(ToLocaleTimeString(t))->asReturnedValue();
+ double t = getThisDate(scope, callData);
+ scope.result = scope.engine->newString(ToLocaleTimeString(t));
}
-ReturnedValue DatePrototype::method_valueOf(CallContext *ctx)
+void DatePrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return Encode(t);
+ double t = getThisDate(scope, callData);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getTime(CallContext *ctx)
+void DatePrototype::method_getTime(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return Encode(t);
+ double t = getThisDate(scope, callData);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getYear(CallContext *ctx)
+void DatePrototype::method_getYear(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = YearFromTime(LocalTime(t)) - 1900;
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getFullYear(CallContext *ctx)
+void DatePrototype::method_getFullYear(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = YearFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCFullYear(CallContext *ctx)
+void DatePrototype::method_getUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = YearFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getMonth(CallContext *ctx)
+void DatePrototype::method_getMonth(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = MonthFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCMonth(CallContext *ctx)
+void DatePrototype::method_getUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = MonthFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getDate(CallContext *ctx)
+void DatePrototype::method_getDate(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = DateFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCDate(CallContext *ctx)
+void DatePrototype::method_getUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = DateFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getDay(CallContext *ctx)
+void DatePrototype::method_getDay(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = WeekDay(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCDay(CallContext *ctx)
+void DatePrototype::method_getUTCDay(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = WeekDay(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getHours(CallContext *ctx)
+void DatePrototype::method_getHours(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = HourFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCHours(CallContext *ctx)
+void DatePrototype::method_getUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = HourFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getMinutes(CallContext *ctx)
+void DatePrototype::method_getMinutes(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = MinFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCMinutes(CallContext *ctx)
+void DatePrototype::method_getUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = MinFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getSeconds(CallContext *ctx)
+void DatePrototype::method_getSeconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = SecFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCSeconds(CallContext *ctx)
+void DatePrototype::method_getUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = SecFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getMilliseconds(CallContext *ctx)
+void DatePrototype::method_getMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = msFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCMilliseconds(CallContext *ctx)
+void DatePrototype::method_getUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = msFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getTimezoneOffset(CallContext *ctx)
+void DatePrototype::method_getTimezoneOffset(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = (t - LocalTime(t)) / msPerMinute;
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_setTime(CallContext *ctx)
+void DatePrototype::method_setTime(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DateObject> self(scope, ctx->thisObject());
+ Scoped<DateObject> self(scope, callData->thisObject);
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- double t = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double t = callData->argc ? callData->args[0].toNumber() : qt_qnan();
self->setDate(TimeClip(t));
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx)
+void DatePrototype::method_setMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DateObject> self(scope, ctx->thisObject());
+ Scoped<DateObject> self(scope, callData->thisObject);
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
- double ms = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCMilliseconds(CallContext *ctx)
+void DatePrototype::method_setUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double ms = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))));
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setSeconds(CallContext *ctx)
+void DatePrototype::method_setSeconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
- double sec = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double ms = (ctx->argc() < 2) ? msFromTime(t) : ctx->args()[1].toNumber();
+ double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCSeconds(CallContext *ctx)
+void DatePrototype::method_setUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double sec = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double ms = (ctx->argc() < 2) ? msFromTime(t) : ctx->args()[1].toNumber();
+ double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber();
t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setMinutes(CallContext *ctx)
+void DatePrototype::method_setMinutes(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
- double min = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double sec = (ctx->argc() < 2) ? SecFromTime(t) : ctx->args()[1].toNumber();
- double ms = (ctx->argc() < 3) ? msFromTime(t) : ctx->args()[2].toNumber();
+ double min = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber();
+ double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCMinutes(CallContext *ctx)
+void DatePrototype::method_setUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double min = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double sec = (ctx->argc() < 2) ? SecFromTime(t) : ctx->args()[1].toNumber();
- double ms = (ctx->argc() < 3) ? msFromTime(t) : ctx->args()[2].toNumber();
+ double min = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber();
+ double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber();
t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setHours(CallContext *ctx)
+void DatePrototype::method_setHours(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
- double hour = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double min = (ctx->argc() < 2) ? MinFromTime(t) : ctx->args()[1].toNumber();
- double sec = (ctx->argc() < 3) ? SecFromTime(t) : ctx->args()[2].toNumber();
- double ms = (ctx->argc() < 4) ? msFromTime(t) : ctx->args()[3].toNumber();
+ double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber();
+ double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber();
+ double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCHours(CallContext *ctx)
+void DatePrototype::method_setUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double hour = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double min = (ctx->argc() < 2) ? MinFromTime(t) : ctx->args()[1].toNumber();
- double sec = (ctx->argc() < 3) ? SecFromTime(t) : ctx->args()[2].toNumber();
- double ms = (ctx->argc() < 4) ? msFromTime(t) : ctx->args()[3].toNumber();
+ double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber();
+ double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber();
+ double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber();
t = TimeClip(MakeDate(Day(t), MakeTime(hour, min, sec, ms)));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setDate(CallContext *ctx)
+void DatePrototype::method_setDate(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
- double date = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCDate(CallContext *ctx)
+void DatePrototype::method_setUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double date = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setMonth(CallContext *ctx)
+void DatePrototype::method_setMonth(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
- double month = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double date = (ctx->argc() < 2) ? DateFromTime(t) : ctx->args()[1].toNumber();
+ double month = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCMonth(CallContext *ctx)
+void DatePrototype::method_setUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double month = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double date = (ctx->argc() < 2) ? DateFromTime(t) : ctx->args()[1].toNumber();
+ double month = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber();
t = TimeClip(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setYear(CallContext *ctx)
+void DatePrototype::method_setYear(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
if (std::isnan(t))
t = 0;
else
t = LocalTime(t);
- double year = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
double r;
if (std::isnan(year)) {
r = qt_qnan();
@@ -1220,49 +1220,49 @@ ReturnedValue DatePrototype::method_setYear(CallContext *ctx)
r = TimeClip(r);
}
self->setDate(r);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCFullYear(CallContext *ctx)
+void DatePrototype::method_setUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double year = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double month = (ctx->argc() < 2) ? MonthFromTime(t) : ctx->args()[1].toNumber();
- double date = (ctx->argc() < 3) ? DateFromTime(t) : ctx->args()[2].toNumber();
+ double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber();
+ double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber();
t = TimeClip(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setFullYear(CallContext *ctx)
+void DatePrototype::method_setFullYear(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
if (std::isnan(t))
t = 0;
- double year = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double month = (ctx->argc() < 2) ? MonthFromTime(t) : ctx->args()[1].toNumber();
- double date = (ctx->argc() < 3) ? DateFromTime(t) : ctx->args()[2].toNumber();
+ double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber();
+ double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber();
t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_toUTCString(CallContext *ctx)
+void DatePrototype::method_toUTCString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- return ctx->d()->engine->newString(ToUTCString(t))->asReturnedValue();
+ scope.result = scope.engine->newString(ToUTCString(t));
}
static void addZeroPrefixedInt(QString &str, int num, int nDigits)
@@ -1278,21 +1278,21 @@ static void addZeroPrefixedInt(QString &str, int num, int nDigits)
}
}
-ReturnedValue DatePrototype::method_toISOString(CallContext *ctx)
+void DatePrototype::method_toISOString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
if (!std::isfinite(t))
- return ctx->engine()->throwRangeError(ctx->thisObject());
+ RETURN_RESULT(scope.engine->throwRangeError(callData->thisObject));
QString result;
int year = (int)YearFromTime(t);
if (year < 0 || year > 9999) {
if (qAbs(year) >= 1000000)
- return ctx->d()->engine->newString(QStringLiteral("Invalid Date"))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("Invalid Date")));
result += year < 0 ? QLatin1Char('-') : QLatin1Char('+');
year = qAbs(year);
addZeroPrefixedInt(result, year, 6);
@@ -1313,32 +1313,29 @@ ReturnedValue DatePrototype::method_toISOString(CallContext *ctx)
addZeroPrefixedInt(result, msFromTime(t), 3);
result += QLatin1Char('Z');
- return ctx->d()->engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
-ReturnedValue DatePrototype::method_toJSON(CallContext *ctx)
+void DatePrototype::method_toJSON(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject O(scope, ctx->thisObject().toObject(scope.engine));
- if (scope.hasException())
- return Encode::undefined();
+ ScopedObject O(scope, callData->thisObject.toObject(scope.engine));
+ CHECK_EXCEPTION();
ScopedValue tv(scope, RuntimeHelpers::toPrimitive(O, NUMBER_HINT));
if (tv->isNumber() && !std::isfinite(tv->toNumber()))
- return Encode::null();
+ RETURN_RESULT(Encode::null());
- ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toISOString")));
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("toISOString")));
ScopedValue v(scope, O->get(s));
FunctionObject *toIso = v->as<FunctionObject>();
if (!toIso)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope);
- callData->thisObject = ctx->thisObject();
- toIso->call(scope, callData);
- return scope.result.asReturnedValue();
+ ScopedCallData cData(scope);
+ cData->thisObject = callData->thisObject;
+ toIso->call(scope, cData);
}
void DatePrototype::timezoneUpdated()
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index 835f6adbe0..a56d17f9b1 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -116,57 +116,57 @@ struct DatePrototype: DateObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static double getThisDate(ExecutionContext *ctx);
-
- static ReturnedValue method_parse(CallContext *ctx);
- static ReturnedValue method_UTC(CallContext *ctx);
- static ReturnedValue method_now(CallContext *ctx);
-
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_toDateString(CallContext *ctx);
- static ReturnedValue method_toTimeString(CallContext *ctx);
- static ReturnedValue method_toLocaleString(CallContext *ctx);
- static ReturnedValue method_toLocaleDateString(CallContext *ctx);
- static ReturnedValue method_toLocaleTimeString(CallContext *ctx);
- static ReturnedValue method_valueOf(CallContext *ctx);
- static ReturnedValue method_getTime(CallContext *ctx);
- static ReturnedValue method_getYear(CallContext *ctx);
- static ReturnedValue method_getFullYear(CallContext *ctx);
- static ReturnedValue method_getUTCFullYear(CallContext *ctx);
- static ReturnedValue method_getMonth(CallContext *ctx);
- static ReturnedValue method_getUTCMonth(CallContext *ctx);
- static ReturnedValue method_getDate(CallContext *ctx);
- static ReturnedValue method_getUTCDate(CallContext *ctx);
- static ReturnedValue method_getDay(CallContext *ctx);
- static ReturnedValue method_getUTCDay(CallContext *ctx);
- static ReturnedValue method_getHours(CallContext *ctx);
- static ReturnedValue method_getUTCHours(CallContext *ctx);
- static ReturnedValue method_getMinutes(CallContext *ctx);
- static ReturnedValue method_getUTCMinutes(CallContext *ctx);
- static ReturnedValue method_getSeconds(CallContext *ctx);
- static ReturnedValue method_getUTCSeconds(CallContext *ctx);
- static ReturnedValue method_getMilliseconds(CallContext *ctx);
- static ReturnedValue method_getUTCMilliseconds(CallContext *ctx);
- static ReturnedValue method_getTimezoneOffset(CallContext *ctx);
- static ReturnedValue method_setTime(CallContext *ctx);
- static ReturnedValue method_setMilliseconds(CallContext *ctx);
- static ReturnedValue method_setUTCMilliseconds(CallContext *ctx);
- static ReturnedValue method_setSeconds(CallContext *ctx);
- static ReturnedValue method_setUTCSeconds(CallContext *ctx);
- static ReturnedValue method_setMinutes(CallContext *ctx);
- static ReturnedValue method_setUTCMinutes(CallContext *ctx);
- static ReturnedValue method_setHours(CallContext *ctx);
- static ReturnedValue method_setUTCHours(CallContext *ctx);
- static ReturnedValue method_setDate(CallContext *ctx);
- static ReturnedValue method_setUTCDate(CallContext *ctx);
- static ReturnedValue method_setMonth(CallContext *ctx);
- static ReturnedValue method_setUTCMonth(CallContext *ctx);
- static ReturnedValue method_setYear(CallContext *ctx);
- static ReturnedValue method_setFullYear(CallContext *ctx);
- static ReturnedValue method_setUTCFullYear(CallContext *ctx);
- static ReturnedValue method_toUTCString(CallContext *ctx);
- static ReturnedValue method_toISOString(CallContext *ctx);
- static ReturnedValue method_toJSON(CallContext *ctx);
+ static double getThisDate(Scope &scope, CallData *callData);
+
+ static void method_parse(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_UTC(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_now(const BuiltinFunction *, Scope &scope, CallData *callData);
+
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toDateString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toTimeString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleDateString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleTimeString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getTime(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getYear(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getFullYear(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getMonth(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getDate(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getDay(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCDay(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getHours(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getMinutes(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getSeconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getTimezoneOffset(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setTime(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setSeconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setMinutes(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setHours(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setDate(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setMonth(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setYear(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setFullYear(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toUTCString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toISOString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toJSON(const BuiltinFunction *, Scope &scope, CallData *callData);
static void timezoneUpdated();
};
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index a11f7f0875..084ddc9010 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -91,7 +91,9 @@
#if USE(PTHREADS)
# include <pthread.h>
+#if !defined(Q_OS_INTEGRITY)
# include <sys/resource.h>
+#endif
#if HAVE(PTHREAD_NP_H)
# include <pthread_np.h>
#endif
@@ -168,7 +170,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
if (forceMoth) {
factory = new Moth::ISelFactory;
} else {
- factory = new JIT::ISelFactory;
+ factory = new JIT::ISelFactory<>;
jitDisabled = false;
}
#else // !V4_ENABLE_JIT
@@ -1109,7 +1111,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
if (typeHint == qMetaTypeId<QJSValue>())
return QVariant::fromValue(QJSValue(e, value.asReturnedValue()));
- if (value.as<Object>()) {
+ if (value.as<QV4::Object>()) {
QV4::ScopedObject object(scope, value);
if (typeHint == QMetaType::QJsonObject
&& !value.as<ArrayObject>() && !value.as<FunctionObject>()) {
@@ -1755,7 +1757,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
return false;
}
-static bool convertToNativeQObject(QV4::ExecutionEngine *e, const Value &value, const QByteArray &targetType, void **result)
+static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, const QByteArray &targetType, void **result)
{
if (!targetType.endsWith('*'))
return false;
@@ -1770,7 +1772,7 @@ static bool convertToNativeQObject(QV4::ExecutionEngine *e, const Value &value,
return false;
}
-static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const Value &value)
+static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value)
{
if (!value.isObject())
return 0;
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 597ded6ae1..f290bc5136 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -153,12 +153,11 @@ const char *ErrorObject::className(Heap::ErrorObject::ErrorType t)
Q_UNREACHABLE();
}
-ReturnedValue ErrorObject::method_get_stack(CallContext *ctx)
+void ErrorObject::method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<ErrorObject> This(scope, ctx->thisObject());
+ Scoped<ErrorObject> This(scope, callData->thisObject);
if (!This)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (!This->d()->stack) {
QString trace;
for (int i = 0; i < This->d()->stackTrace->count(); ++i) {
@@ -169,9 +168,9 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx)
if (frame.line >= 0)
trace += QLatin1Char(':') + QString::number(frame.line);
}
- This->d()->stack = ctx->d()->engine->newString(trace);
+ This->d()->stack = scope.engine->newString(trace);
}
- return This->d()->stack->asReturnedValue();
+ scope.result = This->d()->stack;
}
void ErrorObject::markObjects(Heap::Base *that, ExecutionEngine *e)
@@ -335,22 +334,20 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He
obj->defineDefaultProperty(engine->id_toString(), method_toString, 0);
}
-ReturnedValue ErrorPrototype::method_toString(CallContext *ctx)
+void ErrorPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
-
- Object *o = ctx->thisObject().as<Object>();
+ Object *o = callData->thisObject.as<Object>();
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedValue name(scope, o->get(ctx->d()->engine->id_name()));
+ ScopedValue name(scope, o->get(scope.engine->id_name()));
QString qname;
if (name->isUndefined())
qname = QStringLiteral("Error");
else
qname = name->toQString();
- ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("message")));
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("message")));
ScopedValue message(scope, o->get(s));
QString qmessage;
if (!message->isUndefined())
@@ -365,5 +362,5 @@ ReturnedValue ErrorPrototype::method_toString(CallContext *ctx)
str = qname + QLatin1String(": ") + qmessage;
}
- return ctx->d()->engine->newString(str)->asReturnedValue();
+ scope.result = scope.engine->newString(str)->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 2b3ab25e2d..9ba9f05234 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -172,7 +172,7 @@ struct ErrorObject: Object {
static const char *className(Heap::ErrorObject::ErrorType t);
- static ReturnedValue method_get_stack(CallContext *ctx);
+ static void method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData);
static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
@@ -282,7 +282,7 @@ struct ErrorPrototype : ErrorObject
void init(ExecutionEngine *engine, Object *ctor) { init(engine, ctor, this, Heap::ErrorObject::Error); }
static void init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t);
- static ReturnedValue method_toString(CallContext *ctx);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
};
struct EvalErrorPrototype : ErrorObject
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 64f7b98618..b2d89220ea 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -270,23 +270,22 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
}
-ReturnedValue FunctionPrototype::method_toString(CallContext *ctx)
+void FunctionPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- FunctionObject *fun = ctx->thisObject().as<FunctionObject>();
+ FunctionObject *fun = callData->thisObject.as<FunctionObject>();
if (!fun)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return ctx->d()->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue();
+ scope.result = scope.engine->newString(QStringLiteral("function() { [code] }"));
}
-ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
+void FunctionPrototype::method_apply(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- FunctionObject *o = ctx->thisObject().as<FunctionObject>();
+ FunctionObject *o = callData->thisObject.as<FunctionObject>();
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- Scope scope(ctx);
- ScopedValue arg(scope, ctx->argument(1));
+ ScopedValue arg(scope, callData->argument(1));
ScopedObject arr(scope, arg);
@@ -294,75 +293,71 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
if (!arr) {
len = 0;
if (!arg->isNullOrUndefined())
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
} else {
len = arr->getLength();
}
- ScopedCallData callData(scope, len);
+ ScopedCallData cData(scope, len);
if (len) {
if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
QV4::ArgumentsObject *a = arr->cast<ArgumentsObject>();
int l = qMin(len, (uint)a->d()->context->callData->argc);
- memcpy(callData->args, a->d()->context->callData->args, l*sizeof(Value));
+ memcpy(cData->args, a->d()->context->callData->args, l*sizeof(Value));
for (quint32 i = l; i < len; ++i)
- callData->args[i] = Primitive::undefinedValue();
+ cData->args[i] = Primitive::undefinedValue();
} else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) {
auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData());
uint alen = sad ? sad->len : 0;
if (alen > len)
alen = len;
for (uint i = 0; i < alen; ++i)
- callData->args[i] = sad->data(i);
+ cData->args[i] = sad->data(i);
for (quint32 i = alen; i < len; ++i)
- callData->args[i] = Primitive::undefinedValue();
+ cData->args[i] = Primitive::undefinedValue();
} else {
for (quint32 i = 0; i < len; ++i)
- callData->args[i] = arr->getIndexed(i);
+ cData->args[i] = arr->getIndexed(i);
}
}
- callData->thisObject = ctx->argument(0);
- o->call(scope, callData);
- return scope.result.asReturnedValue();
+ cData->thisObject = callData->argument(0);
+ o->call(scope, cData);
}
-ReturnedValue FunctionPrototype::method_call(CallContext *ctx)
+void FunctionPrototype::method_call(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- FunctionObject *o = ctx->thisObject().as<FunctionObject>();
+ FunctionObject *o = callData->thisObject.as<FunctionObject>();
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- Scope scope(ctx);
- ScopedCallData callData(scope, ctx->argc() ? ctx->argc() - 1 : 0);
- if (ctx->argc()) {
- for (int i = 1; i < ctx->argc(); ++i)
- callData->args[i - 1] = ctx->args()[i];
+ ScopedCallData cData(scope, callData->argc ? callData->argc - 1 : 0);
+ if (callData->argc) {
+ for (int i = 1; i < callData->argc; ++i)
+ cData->args[i - 1] = callData->args[i];
}
- callData->thisObject = ctx->argument(0);
+ cData->thisObject = callData->argument(0);
- o->call(scope, callData);
- return scope.result.asReturnedValue();
+ o->call(scope, cData);
}
-ReturnedValue FunctionPrototype::method_bind(CallContext *ctx)
+void FunctionPrototype::method_bind(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- FunctionObject *target = ctx->thisObject().as<FunctionObject>();
+ FunctionObject *target = callData->thisObject.as<FunctionObject>();
if (!target)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- Scope scope(ctx);
- ScopedValue boundThis(scope, ctx->argument(0));
+ ScopedValue boundThis(scope, callData->argument(0));
Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0);
- if (ctx->argc() > 1) {
- boundArgs = MemberData::allocate(scope.engine, ctx->argc() - 1);
- boundArgs->d()->size = ctx->argc() - 1;
- memcpy(boundArgs->data(), ctx->args() + 1, (ctx->argc() - 1)*sizeof(Value));
+ if (callData->argc > 1) {
+ boundArgs = MemberData::allocate(scope.engine, callData->argc - 1);
+ boundArgs->d()->size = callData->argc - 1;
+ memcpy(boundArgs->data(), callData->args + 1, (callData->argc - 1)*sizeof(Value));
}
ExecutionContext *global = scope.engine->rootContext();
- return BoundFunction::create(global, target, boundThis, boundArgs)->asReturnedValue();
+ scope.result = BoundFunction::create(global, target, boundThis, boundArgs);
}
DEFINE_OBJECT_VTABLE(ScriptFunction);
@@ -459,22 +454,22 @@ Heap::Object *ScriptFunction::protoForConstructor() const
-DEFINE_OBJECT_VTABLE(BuiltinFunction);
+DEFINE_OBJECT_VTABLE(OldBuiltinFunction);
-void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *))
+void Heap::OldBuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *))
{
Heap::FunctionObject::init(scope, name);
this->code = code;
}
-void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *)
+void OldBuiltinFunction::construct(const Managed *f, Scope &scope, CallData *)
{
- scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
+ scope.result = static_cast<const OldBuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
}
-void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
+void OldBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
- const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that);
+ const OldBuiltinFunction *f = static_cast<const OldBuiltinFunction *>(that);
ExecutionEngine *v4 = scope.engine;
if (v4->hasException) {
scope.result = Encode::undefined();
@@ -484,15 +479,41 @@ void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data ctx = CallContext::Data::createOnStack(v4);
- ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
- ctx.callData = callData;
- v4->pushContext(&ctx);
- Q_ASSERT(v4->current == &ctx);
+ CallContext::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);
scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext));
+ v4->memoryManager->freeSimpleCallContext();
+}
+
+DEFINE_OBJECT_VTABLE(BuiltinFunction);
+
+void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *))
+{
+ Heap::FunctionObject::init(scope, name);
+ this->code = code;
+}
+
+void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *)
+{
+ scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
+}
+
+void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
+{
+ const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ f->d()->code(f, scope, callData);
}
+
void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
const IndexedBuiltinFunction *f = static_cast<const IndexedBuiltinFunction *>(that);
@@ -505,13 +526,14 @@ void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *c
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data ctx = CallContext::Data::createOnStack(v4);
- ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
- ctx.callData = callData;
- v4->pushContext(&ctx);
- Q_ASSERT(v4->current == &ctx);
+ CallContext::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);
scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index);
+ v4->memoryManager->freeSimpleCallContext();
}
DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index a02e89e883..45d7485f1b 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -61,6 +61,8 @@ struct QQmlSourceLocation;
namespace QV4 {
+struct BuiltinFunction;
+
namespace Heap {
struct Q_QML_PRIVATE_EXPORT FunctionObject : Object {
@@ -93,11 +95,16 @@ struct FunctionPrototype : FunctionObject {
void init();
};
-struct Q_QML_EXPORT BuiltinFunction : FunctionObject {
+struct Q_QML_EXPORT OldBuiltinFunction : FunctionObject {
void init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *));
ReturnedValue (*code)(QV4::CallContext *);
};
+struct Q_QML_EXPORT BuiltinFunction : FunctionObject {
+ void init(QV4::ExecutionContext *scope, QV4::String *name, void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *));
+ void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *);
+};
+
struct IndexedBuiltinFunction : FunctionObject {
inline void init(QV4::ExecutionContext *scope, uint index, ReturnedValue (*code)(QV4::CallContext *ctx, uint index));
ReturnedValue (*code)(QV4::CallContext *, uint index);
@@ -177,16 +184,27 @@ struct FunctionPrototype: FunctionObject
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_apply(CallContext *ctx);
- static ReturnedValue method_call(CallContext *ctx);
- static ReturnedValue method_bind(CallContext *ctx);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_apply(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_call(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_bind(const BuiltinFunction *, Scope &scope, CallData *callData);
};
-struct Q_QML_EXPORT BuiltinFunction: FunctionObject {
+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)
- static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *))
+ 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);
}
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 1dbc538be2..66861bf697 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -208,6 +208,7 @@ struct StringObject;
struct ArrayObject;
struct DateObject;
struct FunctionObject;
+struct BuiltinFunction;
struct ErrorObject;
struct ArgumentsObject;
struct Managed;
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index af92ce1ad8..1bc91f832b 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -423,18 +423,15 @@ static inline int toInt(const QChar &qc, int R)
}
// parseInt [15.1.2.2]
-ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx)
+void GlobalFunctions::method_parseInt(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue inputString(scope, ctx->argument(0));
- ScopedValue radix(scope, ctx->argument(1));
+ ScopedValue inputString(scope, callData->argument(0));
+ ScopedValue radix(scope, callData->argument(1));
int R = radix->isUndefined() ? 0 : radix->toInt32();
// [15.1.2.2] step by step:
QString trimmed = inputString->toQString().trimmed(); // 1 + 2
-
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
+ CHECK_EXCEPTION();
const QChar *pos = trimmed.constData();
const QChar *end = pos + trimmed.length();
@@ -449,7 +446,7 @@ ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx)
bool stripPrefix = true; // 7
if (R) { // 8
if (R < 2 || R > 36)
- return Encode(std::numeric_limits<double>::quiet_NaN()); // 8a
+ RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN())); // 8a
if (R != 16)
stripPrefix = false; // 8b
} else { // 9
@@ -466,13 +463,13 @@ ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx)
// 11: Z is progressively built below
// 13: this is handled by the toInt function
if (pos == end) // 12
- return Encode(std::numeric_limits<double>::quiet_NaN());
+ RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN()));
bool overflow = false;
qint64 v_overflow = 0;
unsigned overflow_digit_count = 0;
int d = toInt(*pos++, R);
if (d == -1)
- return Encode(std::numeric_limits<double>::quiet_NaN());
+ RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN()));
qint64 v = d;
while (pos != end) {
d = toInt(*pos++, R);
@@ -499,155 +496,148 @@ ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx)
if (overflow) {
double result = (double) v_overflow * pow(static_cast<double>(R), static_cast<double>(overflow_digit_count));
result += v;
- return Encode(sign * result);
+ RETURN_RESULT(Encode(sign * result));
} else {
- return Encode(sign * (double) v); // 15
+ RETURN_RESULT(Encode(sign * (double) v)); // 15
}
}
// parseFloat [15.1.2.3]
-ReturnedValue GlobalFunctions::method_parseFloat(CallContext *ctx)
+void GlobalFunctions::method_parseFloat(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
-
// [15.1.2.3] step by step:
- ScopedString inputString(scope, ctx->argument(0), ScopedString::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedString inputString(scope, callData->argument(0), ScopedString::Convert);
+ CHECK_EXCEPTION();
QString trimmed = inputString->toQString().trimmed(); // 2
// 4:
if (trimmed.startsWith(QLatin1String("Infinity"))
|| trimmed.startsWith(QLatin1String("+Infinity")))
- return Encode(Q_INFINITY);
+ RETURN_RESULT(Encode(Q_INFINITY));
if (trimmed.startsWith(QLatin1String("-Infinity")))
- return Encode(-Q_INFINITY);
+ RETURN_RESULT(Encode(-Q_INFINITY));
QByteArray ba = trimmed.toLatin1();
bool ok;
const char *begin = ba.constData();
const char *end = 0;
double d = qstrtod(begin, &end, &ok);
if (end - begin == 0)
- return Encode(std::numeric_limits<double>::quiet_NaN()); // 3
+ RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN())); // 3
else
- return Encode(d);
+ RETURN_RESULT(Encode(d));
}
/// isNaN [15.1.2.4]
-ReturnedValue GlobalFunctions::method_isNaN(CallContext *ctx)
+void GlobalFunctions::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!ctx->argc())
+ if (!callData->argc)
// undefined gets converted to NaN
- return Encode(true);
+ RETURN_RESULT(Encode(true));
- if (ctx->args()[0].integerCompatible())
- return Encode(false);
+ if (callData->args[0].integerCompatible())
+ RETURN_RESULT(Encode(false));
- double d = ctx->args()[0].toNumber();
- return Encode((bool)std::isnan(d));
+ double d = callData->args[0].toNumber();
+ RETURN_RESULT(Encode((bool)std::isnan(d)));
}
/// isFinite [15.1.2.5]
-ReturnedValue GlobalFunctions::method_isFinite(CallContext *ctx)
+void GlobalFunctions::method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!ctx->argc())
+ if (!callData->argc)
// undefined gets converted to NaN
- return Encode(false);
+ RETURN_RESULT(Encode(false));
- if (ctx->args()[0].integerCompatible())
- return Encode(true);
+ if (callData->args[0].integerCompatible())
+ RETURN_RESULT(Encode(true));
- double d = ctx->args()[0].toNumber();
- return Encode((bool)std::isfinite(d));
+ double d = callData->args[0].toNumber();
+ RETURN_RESULT(Encode((bool)std::isfinite(d)));
}
/// decodeURI [15.1.3.1]
-ReturnedValue GlobalFunctions::method_decodeURI(CallContext *context)
+void GlobalFunctions::method_decodeURI(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (context->argc() == 0)
- return Encode::undefined();
+ if (callData->argc == 0)
+ RETURN_UNDEFINED();
- QString uriString = context->args()[0].toQString();
+ QString uriString = callData->args[0].toQString();
bool ok;
QString out = decode(uriString, DecodeNonReserved, &ok);
if (!ok) {
- Scope scope(context);
- ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence")));
- return context->engine()->throwURIError(s);
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
+ RETURN_RESULT(scope.engine->throwURIError(s));
}
- return context->d()->engine->newString(out)->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(out));
}
/// decodeURIComponent [15.1.3.2]
-ReturnedValue GlobalFunctions::method_decodeURIComponent(CallContext *context)
+void GlobalFunctions::method_decodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (context->argc() == 0)
- return Encode::undefined();
+ if (callData->argc == 0)
+ RETURN_UNDEFINED();
- QString uriString = context->args()[0].toQString();
+ QString uriString = callData->args[0].toQString();
bool ok;
QString out = decode(uriString, DecodeAll, &ok);
if (!ok) {
- Scope scope(context);
- ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence")));
- return context->engine()->throwURIError(s);
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
+ RETURN_RESULT(scope.engine->throwURIError(s));
}
- return context->d()->engine->newString(out)->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(out));
}
/// encodeURI [15.1.3.3]
-ReturnedValue GlobalFunctions::method_encodeURI(CallContext *context)
+void GlobalFunctions::method_encodeURI(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (context->argc() == 0)
- return Encode::undefined();
+ if (callData->argc == 0)
+ RETURN_UNDEFINED();
- QString uriString = context->args()[0].toQString();
+ QString uriString = callData->args[0].toQString();
bool ok;
QString out = encode(uriString, uriUnescapedReserved, &ok);
if (!ok) {
- Scope scope(context);
- ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence")));
- return context->engine()->throwURIError(s);
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
+ RETURN_RESULT(scope.engine->throwURIError(s));
}
- return context->d()->engine->newString(out)->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(out));
}
/// encodeURIComponent [15.1.3.4]
-ReturnedValue GlobalFunctions::method_encodeURIComponent(CallContext *context)
+void GlobalFunctions::method_encodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (context->argc() == 0)
- return Encode::undefined();
+ if (callData->argc == 0)
+ RETURN_UNDEFINED();
- QString uriString = context->args()[0].toQString();
+ QString uriString = callData->args[0].toQString();
bool ok;
QString out = encode(uriString, uriUnescaped, &ok);
if (!ok) {
- Scope scope(context);
- ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence")));
- return context->engine()->throwURIError(s);
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
+ RETURN_RESULT(scope.engine->throwURIError(s));
}
- return context->d()->engine->newString(out)->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(out));
}
-ReturnedValue GlobalFunctions::method_escape(CallContext *context)
+void GlobalFunctions::method_escape(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!context->argc())
- return context->d()->engine->newString(QStringLiteral("undefined"))->asReturnedValue();
+ if (!callData->argc)
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("undefined")));
- QString str = context->args()[0].toQString();
- return context->d()->engine->newString(escape(str))->asReturnedValue();
+ QString str = callData->args[0].toQString();
+ RETURN_RESULT(scope.engine->newString(escape(str)));
}
-ReturnedValue GlobalFunctions::method_unescape(CallContext *context)
+void GlobalFunctions::method_unescape(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!context->argc())
- return context->d()->engine->newString(QStringLiteral("undefined"))->asReturnedValue();
+ if (!callData->argc)
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("undefined")));
- QString str = context->args()[0].toQString();
- return context->d()->engine->newString(unescape(str))->asReturnedValue();
+ QString str = callData->args[0].toQString();
+ RETURN_RESULT(scope.engine->newString(unescape(str)));
}
diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h
index e8b3a92d34..273f1ba7ea 100644
--- a/src/qml/jsruntime/qv4globalobject_p.h
+++ b/src/qml/jsruntime/qv4globalobject_p.h
@@ -76,16 +76,16 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject
struct GlobalFunctions
{
- static ReturnedValue method_parseInt(CallContext *context);
- static ReturnedValue method_parseFloat(CallContext *context);
- static ReturnedValue method_isNaN(CallContext *context);
- static ReturnedValue method_isFinite(CallContext *ctx);
- static ReturnedValue method_decodeURI(CallContext *context);
- static ReturnedValue method_decodeURIComponent(CallContext *context);
- static ReturnedValue method_encodeURI(CallContext *context);
- static ReturnedValue method_encodeURIComponent(CallContext *context);
- static ReturnedValue method_escape(CallContext *context);
- static ReturnedValue method_unescape(CallContext *context);
+ static void method_parseInt(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_parseFloat(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_decodeURI(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_decodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_encodeURI(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_encodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_escape(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_unescape(const BuiltinFunction *, Scope &scope, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 1d393cf0aa..f033eb2d2d 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -195,23 +195,22 @@ void QV4Include::finished()
/*
Documented in qv8engine.cpp
*/
-QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
+void QV4Include::method_include(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- if (!ctx->argc())
- return QV4::Encode::undefined();
+ if (!callData->argc)
+ RETURN_UNDEFINED();
- QV4::Scope scope(ctx->engine());
QQmlContextData *context = scope.engine->callingQmlContext();
if (!context || !context->isJSContext)
- V4THROW_ERROR("Qt.include(): Can only be called from JavaScript files");
+ RETURN_RESULT(scope.engine->throwError(QString::fromUtf8("Qt.include(): Can only be called from JavaScript files")));
QV4::ScopedValue callbackFunction(scope, QV4::Primitive::undefinedValue());
- if (ctx->argc() >= 2 && ctx->args()[1].as<QV4::FunctionObject>())
- callbackFunction = ctx->args()[1];
+ if (callData->argc >= 2 && callData->args[1].as<QV4::FunctionObject>())
+ callbackFunction = callData->args[1];
#if QT_CONFIG(qml_network)
- QUrl url(scope.engine->resolvedUrl(ctx->args()[0].toQStringNoThrow()));
+ QUrl url(scope.engine->resolvedUrl(callData->args[0].toQStringNoThrow()));
if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor())
url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile);
@@ -261,12 +260,12 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
callback(callbackFunction, result);
}
- return result->asReturnedValue();
+ scope.result = result;
#else
QV4::ScopedValue result(scope);
result = resultValue(scope.engine, NetworkError);
callback(callbackFunction, result);
- return result->asReturnedValue();
+ scope.result = result;
#endif
}
diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h
index 4c601a5e7b..5908d6bfde 100644
--- a/src/qml/jsruntime/qv4include_p.h
+++ b/src/qml/jsruntime/qv4include_p.h
@@ -77,7 +77,7 @@ public:
Exception = 3
};
- static QV4::ReturnedValue method_include(QV4::CallContext *ctx);
+ static void method_include(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
private Q_SLOTS:
void finished();
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index d17da9af0c..bac71b4537 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -128,48 +128,22 @@ InternalClass::InternalClass(const QV4::InternalClass &other)
static void insertHoleIntoPropertyData(Object *object, int idx)
{
- int inlineSize = object->d()->inlineMemberSize;
int icSize = object->internalClass()->size;
- int from = qMax(idx, inlineSize);
+ int from = idx;
int to = from + 1;
- if (from < icSize) {
+ if (from < icSize)
memmove(object->propertyData(to), object->propertyData(from),
(icSize - from - 1) * sizeof(Value));
- }
- if (from == idx)
- return;
- if (inlineSize < icSize)
- *object->propertyData(inlineSize) = *object->propertyData(inlineSize - 1);
- from = idx;
- to = from + 1;
- if (from < inlineSize - 1) {
- memmove(object->propertyData(to), object->propertyData(from),
- (inlineSize - from - 1) * sizeof(Value));
- }
}
static void removeFromPropertyData(Object *object, int idx, bool accessor = false)
{
- int inlineSize = object->d()->inlineMemberSize;
int delta = (accessor ? 2 : 1);
int oldSize = object->internalClass()->size + delta;
int to = idx;
int from = to + delta;
- if (from < inlineSize) {
- memmove(object->propertyData(to), object->d()->propertyData(from), (inlineSize - from)*sizeof(Value));
- to = inlineSize - delta;
- from = inlineSize;
- }
- if (to < inlineSize && from < oldSize) {
- Q_ASSERT(from >= inlineSize);
- memcpy(object->propertyData(to), object->d()->propertyData(from), (inlineSize - to)*sizeof(Value));
- to = inlineSize;
- from = inlineSize + delta;
- }
- if (from < oldSize) {
- Q_ASSERT(to >= inlineSize && from > to);
+ if (from < oldSize)
memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value));
- }
}
void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index)
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index dcda949c97..1d8ef4b0fb 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -234,7 +234,7 @@ struct InternalClassTransition
{ return id == other.id && flags == other.flags; }
bool operator<(const InternalClassTransition &other) const
- { return id < other.id; }
+ { return id < other.id || (id == other.id && flags < other.flags); }
};
struct InternalClass : public QQmlJS::Managed {
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index d79e6242ba..1d571f53f3 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -883,10 +883,9 @@ void Heap::JsonObject::init()
}
-ReturnedValue JsonObject::method_parse(CallContext *ctx)
+void JsonObject::method_parse(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue v(scope, ctx->argument(0));
+ ScopedValue v(scope, callData->argument(0));
QString jtext = v->toQString();
DEBUG << "parsing source = " << jtext;
@@ -895,19 +894,17 @@ ReturnedValue JsonObject::method_parse(CallContext *ctx)
ScopedValue result(scope, parser.parse(&error));
if (error.error != QJsonParseError::NoError) {
DEBUG << "parse error" << error.errorString();
- return ctx->engine()->throwSyntaxError(QStringLiteral("JSON.parse: Parse error"));
+ RETURN_RESULT(scope.engine->throwSyntaxError(QStringLiteral("JSON.parse: Parse error")));
}
- return result->asReturnedValue();
+ scope.result = result;
}
-ReturnedValue JsonObject::method_stringify(CallContext *ctx)
+void JsonObject::method_stringify(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
-
Stringify stringify(scope.engine);
- ScopedObject o(scope, ctx->argument(1));
+ ScopedObject o(scope, callData->argument(1));
if (o) {
stringify.replacerFunction = o->as<FunctionObject>();
if (o->isArrayObject()) {
@@ -932,7 +929,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx)
}
}
- ScopedValue s(scope, ctx->argument(2));
+ ScopedValue s(scope, callData->argument(2));
if (NumberObject *n = s->as<NumberObject>())
s = Encode(n->value());
else if (StringObject *so = s->as<StringObject>())
@@ -945,11 +942,11 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx)
}
- ScopedValue arg0(scope, ctx->argument(0));
+ ScopedValue arg0(scope, callData->argument(0));
QString result = stringify.Str(QString(), arg0);
if (result.isEmpty() || scope.engine->hasException)
- return Encode::undefined();
- return ctx->d()->engine->newString(result)->asReturnedValue();
+ RETURN_UNDEFINED();
+ scope.result = scope.engine->newString(result);
}
diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h
index 43248a214d..a73ce1c74e 100644
--- a/src/qml/jsruntime/qv4jsonobject_p.h
+++ b/src/qml/jsruntime/qv4jsonobject_p.h
@@ -88,8 +88,8 @@ private:
typedef QSet<ObjectItem> V4ObjectSet;
public:
- static ReturnedValue method_parse(CallContext *ctx);
- static ReturnedValue method_stringify(CallContext *ctx);
+ static void method_parse(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_stringify(const BuiltinFunction *, Scope &scope, CallData *callData);
static ReturnedValue fromJsonValue(ExecutionEngine *engine, const QJsonValue &value);
static ReturnedValue fromJsonObject(ExecutionEngine *engine, const QJsonObject &object);
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 52f54e25f5..c5ee92fedd 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -54,8 +54,11 @@
#include "qv4runtime_p.h"
#include "qv4engine_p.h"
#include "qv4context_p.h"
+
+#if !defined(V4_BOOTSTRAP)
#include "qv4object_p.h"
#include "qv4internalclass_p.h"
+#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index e03b2762cc..2d9d81c64b 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -92,160 +92,160 @@ static Q_ALWAYS_INLINE double copySign(double x, double y)
return ::copysign(x, y);
}
-ReturnedValue MathObject::method_abs(CallContext *context)
+void MathObject::method_abs(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!context->argc())
- return Encode(qt_qnan());
+ if (!callData->argc)
+ RETURN_RESULT(Encode(qt_qnan()));
- if (context->args()[0].isInteger()) {
- int i = context->args()[0].integerValue();
- return Encode(i < 0 ? - i : i);
+ if (callData->args[0].isInteger()) {
+ int i = callData->args[0].integerValue();
+ RETURN_RESULT(Encode(i < 0 ? - i : i));
}
- double v = context->args()[0].toNumber();
+ double v = callData->args[0].toNumber();
if (v == 0) // 0 | -0
- return Encode(0);
+ RETURN_RESULT(Encode(0));
- return Encode(v < 0 ? -v : v);
+ RETURN_RESULT(Encode(v < 0 ? -v : v));
}
-ReturnedValue MathObject::method_acos(CallContext *context)
+void MathObject::method_acos(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : 2;
+ double v = callData->argc ? callData->args[0].toNumber() : 2;
if (v > 1)
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
- return Encode(std::acos(v));
+ RETURN_RESULT(Encode(std::acos(v)));
}
-ReturnedValue MathObject::method_asin(CallContext *context)
+void MathObject::method_asin(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : 2;
+ double v = callData->argc ? callData->args[0].toNumber() : 2;
if (v > 1)
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
else
- return Encode(std::asin(v));
+ RETURN_RESULT(Encode(std::asin(v)));
}
-ReturnedValue MathObject::method_atan(CallContext *context)
+void MathObject::method_atan(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (v == 0.0)
- return Encode(v);
+ RETURN_RESULT(Encode(v));
else
- return Encode(std::atan(v));
+ RETURN_RESULT(Encode(std::atan(v)));
}
-ReturnedValue MathObject::method_atan2(CallContext *context)
+void MathObject::method_atan2(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v1 = context->argc() ? context->args()[0].toNumber() : qt_qnan();
- double v2 = context->argc() > 1 ? context->args()[1].toNumber() : qt_qnan();
+ double v1 = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double v2 = callData->argc > 1 ? callData->args[1].toNumber() : qt_qnan();
if ((v1 < 0) && qt_is_finite(v1) && qt_is_inf(v2) && (copySign(1.0, v2) == 1.0))
- return Encode(copySign(0, -1.0));
+ RETURN_RESULT(Encode(copySign(0, -1.0)));
if ((v1 == 0.0) && (v2 == 0.0)) {
if ((copySign(1.0, v1) == 1.0) && (copySign(1.0, v2) == -1.0)) {
- return Encode(M_PI);
+ RETURN_RESULT(Encode(M_PI));
} else if ((copySign(1.0, v1) == -1.0) && (copySign(1.0, v2) == -1.0)) {
- return Encode(-M_PI);
+ RETURN_RESULT(Encode(-M_PI));
}
}
- return Encode(std::atan2(v1, v2));
+ RETURN_RESULT(Encode(std::atan2(v1, v2)));
}
-ReturnedValue MathObject::method_ceil(CallContext *context)
+void MathObject::method_ceil(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (v < 0.0 && v > -1.0)
- return Encode(copySign(0, -1.0));
+ RETURN_RESULT(Encode(copySign(0, -1.0)));
else
- return Encode(std::ceil(v));
+ RETURN_RESULT(Encode(std::ceil(v)));
}
-ReturnedValue MathObject::method_cos(CallContext *context)
+void MathObject::method_cos(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
- return Encode(std::cos(v));
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ RETURN_RESULT(Encode(std::cos(v)));
}
-ReturnedValue MathObject::method_exp(CallContext *context)
+void MathObject::method_exp(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (qt_is_inf(v)) {
if (copySign(1.0, v) == -1.0)
- return Encode(0);
+ RETURN_RESULT(Encode(0));
else
- return Encode(qt_inf());
+ RETURN_RESULT(Encode(qt_inf()));
} else {
- return Encode(std::exp(v));
+ RETURN_RESULT(Encode(std::exp(v)));
}
}
-ReturnedValue MathObject::method_floor(CallContext *context)
+void MathObject::method_floor(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
- return Encode(std::floor(v));
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ RETURN_RESULT(Encode(std::floor(v)));
}
-ReturnedValue MathObject::method_log(CallContext *context)
+void MathObject::method_log(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (v < 0)
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
else
- return Encode(std::log(v));
+ RETURN_RESULT(Encode(std::log(v)));
}
-ReturnedValue MathObject::method_max(CallContext *context)
+void MathObject::method_max(const BuiltinFunction *, Scope &scope, CallData *callData)
{
double mx = -qt_inf();
- for (int i = 0; i < context->argc(); ++i) {
- double x = context->args()[i].toNumber();
+ for (int i = 0; i < callData->argc; ++i) {
+ double x = callData->args[i].toNumber();
if (x > mx || std::isnan(x))
mx = x;
}
- return Encode(mx);
+ RETURN_RESULT(Encode(mx));
}
-ReturnedValue MathObject::method_min(CallContext *context)
+void MathObject::method_min(const BuiltinFunction *, Scope &scope, CallData *callData)
{
double mx = qt_inf();
- for (int i = 0; i < context->argc(); ++i) {
- double x = context->args()[i].toNumber();
+ for (int i = 0; i < callData->argc; ++i) {
+ double x = callData->args[i].toNumber();
if ((x == 0 && mx == x && copySign(1.0, x) == -1.0)
|| (x < mx) || std::isnan(x)) {
mx = x;
}
}
- return Encode(mx);
+ RETURN_RESULT(Encode(mx));
}
-ReturnedValue MathObject::method_pow(CallContext *context)
+void MathObject::method_pow(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double x = context->argc() > 0 ? context->args()[0].toNumber() : qt_qnan();
- double y = context->argc() > 1 ? context->args()[1].toNumber() : qt_qnan();
+ double x = callData->argc > 0 ? callData->args[0].toNumber() : qt_qnan();
+ double y = callData->argc > 1 ? callData->args[1].toNumber() : qt_qnan();
if (std::isnan(y))
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
if (y == 0) {
- return Encode(1);
+ RETURN_RESULT(Encode(1));
} else if (((x == 1) || (x == -1)) && std::isinf(y)) {
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
} else if (((x == 0) && copySign(1.0, x) == 1.0) && (y < 0)) {
- return Encode(qInf());
+ RETURN_RESULT(Encode(qInf()));
} else if ((x == 0) && copySign(1.0, x) == -1.0) {
if (y < 0) {
if (std::fmod(-y, 2.0) == 1.0)
- return Encode(-qt_inf());
+ RETURN_RESULT(Encode(-qt_inf()));
else
- return Encode(qt_inf());
+ RETURN_RESULT(Encode(qt_inf()));
} else if (y > 0) {
if (std::fmod(y, 2.0) == 1.0)
- return Encode(copySign(0, -1.0));
+ RETURN_RESULT(Encode(copySign(0, -1.0)));
else
- return Encode(0);
+ RETURN_RESULT(Encode(0));
}
}
@@ -253,78 +253,78 @@ ReturnedValue MathObject::method_pow(CallContext *context)
else if (qt_is_inf(x) && copySign(1.0, x) == -1.0) {
if (y > 0) {
if (std::fmod(y, 2.0) == 1.0)
- return Encode(-qt_inf());
+ RETURN_RESULT(Encode(-qt_inf()));
else
- return Encode(qt_inf());
+ RETURN_RESULT(Encode(qt_inf()));
} else if (y < 0) {
if (std::fmod(-y, 2.0) == 1.0)
- return Encode(copySign(0, -1.0));
+ RETURN_RESULT(Encode(copySign(0, -1.0)));
else
- return Encode(0);
+ RETURN_RESULT(Encode(0));
}
}
#endif
else {
- return Encode(std::pow(x, y));
+ RETURN_RESULT(Encode(std::pow(x, y)));
}
// ###
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
}
Q_GLOBAL_STATIC(QThreadStorage<bool *>, seedCreatedStorage);
-ReturnedValue MathObject::method_random(CallContext *context)
+void MathObject::method_random(const BuiltinFunction *, Scope &scope, CallData *)
{
if (!seedCreatedStorage()->hasLocalData()) {
int msecs = QTime(0,0,0).msecsTo(QTime::currentTime());
Q_ASSERT(msecs >= 0);
- qsrand(uint(uint(msecs) ^ reinterpret_cast<quintptr>(context)));
+ qsrand(uint(uint(msecs) ^ reinterpret_cast<quintptr>(scope.engine)));
seedCreatedStorage()->setLocalData(new bool(true));
}
// rand()/qrand() return a value where the upperbound is RAND_MAX inclusive. So, instead of
// dividing by RAND_MAX (which would return 0..RAND_MAX inclusive), we divide by RAND_MAX + 1.
qint64 upperLimit = qint64(RAND_MAX) + 1;
- return Encode(qrand() / double(upperLimit));
+ RETURN_RESULT(Encode(qrand() / double(upperLimit)));
}
-ReturnedValue MathObject::method_round(CallContext *context)
+void MathObject::method_round(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
v = copySign(std::floor(v + 0.5), v);
- return Encode(v);
+ RETURN_RESULT(Encode(v));
}
-ReturnedValue MathObject::method_sign(CallContext *context)
+void MathObject::method_sign(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (std::isnan(v))
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
if (qIsNull(v))
- return v;
+ RETURN_RESULT(Encode(v));
- return Encode(std::signbit(v) ? -1 : 1);
+ RETURN_RESULT(Encode(std::signbit(v) ? -1 : 1));
}
-ReturnedValue MathObject::method_sin(CallContext *context)
+void MathObject::method_sin(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
- return Encode(std::sin(v));
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ RETURN_RESULT(Encode(std::sin(v)));
}
-ReturnedValue MathObject::method_sqrt(CallContext *context)
+void MathObject::method_sqrt(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
- return Encode(std::sqrt(v));
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ RETURN_RESULT(Encode(std::sqrt(v)));
}
-ReturnedValue MathObject::method_tan(CallContext *context)
+void MathObject::method_tan(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (v == 0.0)
- return Encode(v);
+ RETURN_RESULT(Encode(v));
else
- return Encode(std::tan(v));
+ RETURN_RESULT(Encode(std::tan(v)));
}
diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h
index f6b1a4395f..e617712905 100644
--- a/src/qml/jsruntime/qv4mathobject_p.h
+++ b/src/qml/jsruntime/qv4mathobject_p.h
@@ -69,25 +69,25 @@ struct MathObject: Object
V4_OBJECT2(MathObject, Object)
Q_MANAGED_TYPE(MathObject)
- static ReturnedValue method_abs(CallContext *context);
- static ReturnedValue method_acos(CallContext *context);
- static ReturnedValue method_asin(CallContext *context);
- static ReturnedValue method_atan(CallContext *context);
- static ReturnedValue method_atan2(CallContext *context);
- static ReturnedValue method_ceil(CallContext *context);
- static ReturnedValue method_cos(CallContext *context);
- static ReturnedValue method_exp(CallContext *context);
- static ReturnedValue method_floor(CallContext *context);
- static ReturnedValue method_log(CallContext *context);
- static ReturnedValue method_max(CallContext *context);
- static ReturnedValue method_min(CallContext *context);
- static ReturnedValue method_pow(CallContext *context);
- static ReturnedValue method_random(CallContext *context);
- static ReturnedValue method_round(CallContext *context);
- static ReturnedValue method_sign(CallContext *context);
- static ReturnedValue method_sin(CallContext *context);
- static ReturnedValue method_sqrt(CallContext *context);
- static ReturnedValue method_tan(CallContext *context);
+ static void method_abs(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_acos(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_asin(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_atan(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_atan2(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_ceil(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_cos(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_exp(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_floor(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_log(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_max(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_min(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_pow(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_random(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_round(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_sign(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_sin(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_sqrt(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_tan(const BuiltinFunction *, Scope &scope, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp
index d5f75415cc..db45c77472 100644
--- a/src/qml/jsruntime/qv4memberdata.cpp
+++ b/src/qml/jsruntime/qv4memberdata.cpp
@@ -55,13 +55,14 @@ void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e)
Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old)
{
Q_ASSERT(!old || old->size < n);
+ Q_ASSERT(n);
- uint alloc = sizeof(Heap::MemberData) + (n)*sizeof(Value);
+ size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value));
Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc);
if (old)
- memcpy(m, old, sizeof(Heap::MemberData) + old->size * sizeof(Value));
+ memcpy(m, old, sizeof(Heap::MemberData) + (old->size - 1)* sizeof(Value));
else
m->init();
- m->size = n;
+ m->size = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
return m;
}
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index 3a6b9da763..09644c161d 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -120,61 +120,71 @@ QT_WARNING_POP
defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision);
}
-inline ReturnedValue thisNumberValue(ExecutionContext *ctx)
+inline ReturnedValue thisNumberValue(Scope &scope, CallData *callData)
{
- if (ctx->thisObject().isNumber())
- return ctx->thisObject().asReturnedValue();
- NumberObject *n = ctx->thisObject().as<NumberObject>();
- if (!n)
- return ctx->engine()->throwTypeError();
+ if (callData->thisObject.isNumber())
+ return callData->thisObject.asReturnedValue();
+ NumberObject *n = callData->thisObject.as<NumberObject>();
+ if (!n) {
+ scope.engine->throwTypeError();
+ return Encode::undefined();
+ }
return Encode(n->value());
}
-inline double thisNumber(ExecutionContext *ctx)
+inline double thisNumber(Scope &scope, CallData *callData)
{
- if (ctx->thisObject().isNumber())
- return ctx->thisObject().asDouble();
- NumberObject *n = ctx->thisObject().as<NumberObject>();
- if (!n)
- return ctx->engine()->throwTypeError();
+ if (callData->thisObject.isNumber())
+ return callData->thisObject.asDouble();
+ NumberObject *n = callData->thisObject.as<NumberObject>();
+ if (!n) {
+ scope.engine->throwTypeError();
+ return 0;
+ }
return n->value();
}
-ReturnedValue NumberPrototype::method_isFinite(CallContext *ctx)
+void NumberPrototype::method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!ctx->argc())
- return Encode(false);
+ if (!callData->argc) {
+ scope.result = Encode(false);
+ return;
+ }
- double v = ctx->args()[0].toNumber();
- return Encode(!std::isnan(v) && !qt_is_inf(v));
+ double v = callData->args[0].toNumber();
+ scope.result = Encode(!std::isnan(v) && !qt_is_inf(v));
}
-ReturnedValue NumberPrototype::method_isNaN(CallContext *ctx)
+void NumberPrototype::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!ctx->argc())
- return Encode(false);
+ if (!callData->argc) {
+ scope.result = Encode(false);
+ return;
+ }
- double v = ctx->args()[0].toNumber();
- return Encode(std::isnan(v));
+ double v = callData->args[0].toNumber();
+ scope.result = Encode(std::isnan(v));
}
-ReturnedValue NumberPrototype::method_toString(CallContext *ctx)
+void NumberPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- double num = thisNumber(ctx);
- if (scope.engine->hasException)
- return Encode::undefined();
+ double num = thisNumber(scope, callData);
+ CHECK_EXCEPTION();
- if (ctx->argc() && !ctx->args()[0].isUndefined()) {
- int radix = ctx->args()[0].toInt32();
- if (radix < 2 || radix > 36)
- return ctx->engine()->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix")
+ if (callData->argc && !callData->args[0].isUndefined()) {
+ int radix = callData->args[0].toInt32();
+ if (radix < 2 || radix > 36) {
+ scope.result = scope.engine->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix")
.arg(radix));
+ return;
+ }
if (std::isnan(num)) {
- return scope.engine->newString(QStringLiteral("NaN"))->asReturnedValue();
+ scope.result = scope.engine->newString(QStringLiteral("NaN"));
+ return;
} else if (qt_is_inf(num)) {
- return scope.engine->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity"))->asReturnedValue();
+ scope.result = scope.engine->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity"));
+ return;
}
if (radix != 10) {
@@ -204,45 +214,43 @@ ReturnedValue NumberPrototype::method_toString(CallContext *ctx)
}
if (negative)
str.prepend(QLatin1Char('-'));
- return scope.engine->newString(str)->asReturnedValue();
+ scope.result = scope.engine->newString(str);
+ return;
}
}
- return Primitive::fromDouble(num).toString(scope.engine)->asReturnedValue();
+ scope.result = Primitive::fromDouble(num).toString(scope.engine);
}
-ReturnedValue NumberPrototype::method_toLocaleString(CallContext *ctx)
+void NumberPrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue v(scope, thisNumberValue(ctx));
- ScopedString str(scope, v->toString(scope.engine));
- if (scope.engine->hasException)
- return Encode::undefined();
- return str.asReturnedValue();
+ ScopedValue v(scope, thisNumberValue(scope, callData));
+ scope.result = v->toString(scope.engine);
+ CHECK_EXCEPTION();
}
-ReturnedValue NumberPrototype::method_valueOf(CallContext *ctx)
+void NumberPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- return thisNumberValue(ctx);
+ scope.result = thisNumberValue(scope, callData);
}
-ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx)
+void NumberPrototype::method_toFixed(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- double v = thisNumber(ctx);
- if (scope.engine->hasException)
- return Encode::undefined();
+ double v = thisNumber(scope, callData);
+ CHECK_EXCEPTION();
double fdigits = 0;
- if (ctx->argc() > 0)
- fdigits = ctx->args()[0].toInteger();
+ if (callData->argc > 0)
+ fdigits = callData->args[0].toInteger();
if (std::isnan(fdigits))
fdigits = 0;
- if (fdigits < 0 || fdigits > 20)
- return ctx->engine()->throwRangeError(ctx->thisObject());
+ if (fdigits < 0 || fdigits > 20) {
+ scope.result = scope.engine->throwRangeError(callData->thisObject);
+ return;
+ }
QString str;
if (std::isnan(v))
@@ -251,48 +259,50 @@ ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx)
str = QString::fromLatin1(v < 0 ? "-Infinity" : "Infinity");
else if (v < 1.e21)
str = NumberLocale::instance()->toString(v, 'f', int(fdigits));
- else
- return RuntimeHelpers::stringFromNumber(ctx->engine(), v)->asReturnedValue();
- return scope.engine->newString(str)->asReturnedValue();
+ else {
+ scope.result = RuntimeHelpers::stringFromNumber(scope.engine, v);
+ return;
+ }
+ scope.result = scope.engine->newString(str);
}
-ReturnedValue NumberPrototype::method_toExponential(CallContext *ctx)
+void NumberPrototype::method_toExponential(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- double d = thisNumber(ctx);
- if (scope.engine->hasException)
- return Encode::undefined();
+ double d = thisNumber(scope, callData);
+ CHECK_EXCEPTION();
int fdigits = NumberLocale::instance()->defaultDoublePrecision;
- if (ctx->argc() && !ctx->args()[0].isUndefined()) {
- fdigits = ctx->args()[0].toInt32();
+ if (callData->argc && !callData->args[0].isUndefined()) {
+ fdigits = callData->args[0].toInt32();
if (fdigits < 0 || fdigits > 20) {
ScopedString error(scope, scope.engine->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range")));
- return ctx->engine()->throwRangeError(error);
+ scope.result = scope.engine->throwRangeError(error);
+ return;
}
}
QString result = NumberLocale::instance()->toString(d, 'e', fdigits);
- return scope.engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
-ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx)
+void NumberPrototype::method_toPrecision(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue v(scope, thisNumberValue(ctx));
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedValue v(scope, thisNumberValue(scope, callData));
+ CHECK_EXCEPTION();
- if (!ctx->argc() || ctx->args()[0].isUndefined())
- return Encode(v->toString(scope.engine));
+ if (!callData->argc || callData->args[0].isUndefined()) {
+ scope.result = v->toString(scope.engine);
+ return;
+ }
- int precision = ctx->args()[0].toInt32();
+ int precision = callData->args[0].toInt32();
if (precision < 1 || precision > 21) {
ScopedString error(scope, scope.engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range")));
- return ctx->engine()->throwRangeError(error);
+ scope.result = scope.engine->throwRangeError(error);
+ return;
}
QString result = NumberLocale::instance()->toString(v->asDouble(), 'g', precision);
- return scope.engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index 6022b3a029..364b866a16 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -87,14 +87,14 @@ struct NumberPrototype: NumberObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_isFinite(CallContext *ctx);
- static ReturnedValue method_isNaN(CallContext *ctx);
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_toLocaleString(CallContext *ctx);
- static ReturnedValue method_valueOf(CallContext *ctx);
- static ReturnedValue method_toFixed(CallContext *ctx);
- static ReturnedValue method_toExponential(CallContext *ctx);
- static ReturnedValue method_toPrecision(CallContext *ctx);
+ static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toFixed(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toExponential(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toPrecision(const BuiltinFunction *, Scope &scope, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 8acca16dd0..2f664c6398 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -61,9 +61,8 @@ DEFINE_OBJECT_VTABLE(Object);
void Object::setInternalClass(InternalClass *ic)
{
d()->internalClass = ic;
- if ((ic->size > d()->inlineMemberSize && !d()->memberData) ||
- (d()->memberData && d()->memberData->size < ic->size - d()->inlineMemberSize))
- d()->memberData = MemberData::allocate(ic->engine, ic->size - d()->inlineMemberSize, d()->memberData);
+ if ((!d()->memberData && ic->size) || (d()->memberData->size < ic->size))
+ d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData);
}
void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const
@@ -167,6 +166,17 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca
defineDefaultProperty(s, function);
}
+void Object::defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), 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->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ defineDefaultProperty(s, function);
+}
+
void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount)
{
ExecutionEngine *e = engine();
@@ -177,6 +187,16 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallConte
defineDefaultProperty(name, function);
}
+void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount)
+{
+ ExecutionEngine *e = engine();
+ Scope scope(e);
+ ExecutionContext *global = e->rootContext();
+ ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code));
+ function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ defineDefaultProperty(name, function);
+}
+
void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *))
{
ExecutionEngine *e = engine();
@@ -196,6 +216,27 @@ void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(CallCo
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 *))
+{
+ ExecutionEngine *e = engine();
+ Scope scope(e);
+ ScopedString s(scope, e->newIdentifier(name));
+ defineAccessorProperty(s, getter, setter);
+}
+
+void Object::defineAccessorProperty(String *name, void (*getter)(const BuiltinFunction *, Scope &, CallData *),
+ void (*setter)(const BuiltinFunction *, Scope &, CallData *))
+{
+ 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::defineReadonlyProperty(const QString &name, const Value &value)
{
QV4::ExecutionEngine *e = engine();
@@ -213,12 +254,6 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e)
{
Heap::Object *o = static_cast<Heap::Object *>(that);
- if (o->inlineMemberSize) {
- Value *v = o->propertyData(0);
- for (uint i = 0; i < o->inlineMemberSize; ++i)
- v[i].mark(e);
- }
-
if (o->memberData)
o->memberData->mark(e);
if (o->arrayData)
@@ -1120,6 +1155,49 @@ uint Object::getLength(const Managed *m)
return v->toUInt32();
}
+// 'var' is 'V' in 15.3.5.3.
+ReturnedValue Object::instanceOf(const Object *typeObject, const Value &var)
+{
+ QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
+
+ // 15.3.5.3, Assume F is a Function object.
+ const FunctionObject *function = typeObject->as<FunctionObject>();
+ if (!function)
+ return engine->throwTypeError();
+
+ Heap::FunctionObject *f = function->d();
+ if (function->isBoundFunction())
+ f = function->cast<BoundFunction>()->target();
+
+ // 15.3.5.3, 1: HasInstance can only be used on an object
+ const Object *lhs = var.as<Object>();
+ if (!lhs)
+ return Encode(false);
+
+ // 15.3.5.3, 2
+ const Object *o = f->protoProperty();
+ if (!o) // 15.3.5.3, 3
+ return engine->throwTypeError();
+
+ Heap::Object *v = lhs->d();
+
+ // 15.3.5.3, 4
+ while (v) {
+ // 15.3.5.3, 4, a
+ v = v->prototype;
+
+ // 15.3.5.3, 4, b
+ if (!v)
+ break; // will return false
+
+ // 15.3.5.3, 4, c
+ else if (o->d() == v)
+ return Encode(true);
+ }
+
+ return Encode(false);
+}
+
bool Object::setArrayLength(uint newLen)
{
Q_ASSERT(isArrayObject());
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 6c679deb10..6a543ae1a8 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -63,17 +63,17 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+struct BuiltinFunction;
+
namespace Heap {
struct Object : Base {
void init() { Base::init(); }
void destroy() { Base::destroy(); }
- const Value *propertyData(uint index) const { if (index < inlineMemberSize) return reinterpret_cast<const Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; }
- Value *propertyData(uint index) { if (index < inlineMemberSize) return reinterpret_cast<Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; }
+ const Value *propertyData(uint index) const { return memberData->data + index; }
+ Value *propertyData(uint index) { return memberData->data + index; }
- uint inlineMemberOffset;
- uint inlineMemberSize;
InternalClass *internalClass;
Pointer<Object> prototype;
Pointer<MemberData> memberData;
@@ -140,6 +140,7 @@ struct ObjectVTable
void (*setLookup)(Managed *m, Lookup *l, const Value &v);
uint (*getLength)(const Managed *m);
void (*advanceIterator)(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
+ ReturnedValue (*instanceOf)(const Object *typeObject, const Value &var);
};
#define DEFINE_OBJECT_VTABLE_BASE(classname) \
@@ -159,7 +160,8 @@ const QV4::ObjectVTable classname::static_vtbl = \
getLookup, \
setLookup, \
getLength, \
- advanceIterator \
+ advanceIterator, \
+ instanceOf \
}
#define DEFINE_OBJECT_VTABLE(classname) \
@@ -238,9 +240,15 @@ struct Q_QML_EXPORT Object: Managed {
}
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 *),
+ void (*setter)(const BuiltinFunction *, Scope &, CallData *));
/* Fixed: Writable: false, Enumerable: false, Configurable: false */
void defineReadonlyProperty(const QString &name, const Value &value);
void defineReadonlyProperty(String *name, const Value &value);
@@ -345,6 +353,8 @@ public:
void advanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes)
{ vtable()->advanceIterator(this, it, name, index, p, attributes); }
uint getLength() const { return vtable()->getLength(this); }
+ ReturnedValue instanceOf(const Value &var) const
+ { return vtable()->instanceOf(this, var); }
inline void construct(Scope &scope, CallData *d) const
{ return vtable()->construct(this, scope, d); }
@@ -366,6 +376,7 @@ protected:
static void setLookup(Managed *m, Lookup *l, const Value &v);
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);
private:
ReturnedValue internalGet(String *name, bool *hasProperty) const;
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 8191083544..97dbe24339 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -121,100 +121,100 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
insertMember(v4->id___proto__(), p, Attr_Accessor|Attr_NotEnumerable);
}
-ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx)
+void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
ScopedObject p(scope, o->prototype());
- return !!p ? p->asReturnedValue() : Encode::null();
+ scope.result = !!p ? p->asReturnedValue() : Encode::null();
}
-ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx)
+void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject O(scope, ctx->argument(0));
- if (!O)
- return ctx->engine()->throwTypeError();
+ ScopedObject O(scope, callData->argument(0));
+ if (!O) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
if (ArgumentsObject::isNonStrictArgumentsObject(O))
static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate();
- ScopedValue v(scope, ctx->argument(1));
+ ScopedValue v(scope, callData->argument(1));
ScopedString name(scope, v->toString(scope.engine));
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
+
PropertyAttributes attrs;
ScopedProperty desc(scope);
O->getOwnProperty(name, &attrs, desc);
- return fromPropertyDescriptor(scope.engine, desc, attrs);
+ scope.result = fromPropertyDescriptor(scope.engine, desc, attrs);
}
-ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context)
+void ObjectPrototype::method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(context);
- ScopedObject O(scope, context->argument(0));
- if (!O)
- return context->engine()->throwTypeError();
+ ScopedObject O(scope, callData->argument(0));
+ if (!O) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
- ScopedArrayObject array(scope, getOwnPropertyNames(context->d()->engine, context->args()[0]));
- return array.asReturnedValue();
+ scope.result = getOwnPropertyNames(scope.engine, callData->args[0]);
}
-ReturnedValue ObjectPrototype::method_create(CallContext *ctx)
+void ObjectPrototype::method_create(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue O(scope, ctx->argument(0));
- if (!O->isObject() && !O->isNull())
- return ctx->engine()->throwTypeError();
+ ScopedValue O(scope, callData->argument(0));
+ if (!O->isObject() && !O->isNull()) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
- ScopedObject newObject(scope, ctx->d()->engine->newObject());
+ ScopedObject newObject(scope, scope.engine->newObject());
newObject->setPrototype(O->as<Object>());
- if (ctx->argc() > 1 && !ctx->args()[1].isUndefined()) {
- ctx->d()->callData->args[0] = newObject.asReturnedValue();
- return method_defineProperties(ctx);
+ if (callData->argc > 1 && !callData->args[1].isUndefined()) {
+ callData->args[0] = newObject;
+ method_defineProperties(builtin, scope, callData);
+ return;
}
- return newObject.asReturnedValue();
+ scope.result = newObject;
}
-ReturnedValue ObjectPrototype::method_defineProperty(CallContext *ctx)
+void ObjectPrototype::method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject O(scope, ctx->argument(0));
- if (!O)
- return ctx->engine()->throwTypeError();
+ ScopedObject O(scope, callData->argument(0));
+ if (!O) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
- ScopedString name(scope, ctx->argument(1), ScopedString::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedString name(scope, callData->argument(1), ScopedString::Convert);
+ CHECK_EXCEPTION();
- ScopedValue attributes(scope, ctx->argument(2));
+ ScopedValue attributes(scope, callData->argument(2));
ScopedProperty pd(scope);
PropertyAttributes attrs;
toPropertyDescriptor(scope.engine, attributes, pd, &attrs);
- if (scope.engine->hasException)
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (!O->__defineOwnProperty__(scope.engine, name, pd, attrs))
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return O.asReturnedValue();
+ scope.result = O;
}
-ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx)
+void ObjectPrototype::method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject O(scope, ctx->argument(0));
+ ScopedObject O(scope, callData->argument(0));
if (!O)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
+
+ ScopedObject o(scope, callData->argument(1), ScopedObject::Convert);
+ CHECK_EXCEPTION();
- ScopedObject o(scope, ctx->argument(1), ScopedObject::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
ScopedValue val(scope);
ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
@@ -230,26 +230,24 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx)
PropertyAttributes nattrs;
val = o->getValue(pd->value, attrs);
toPropertyDescriptor(scope.engine, val, n, &nattrs);
- if (scope.engine->hasException)
- return Encode::undefined();
+ CHECK_EXCEPTION();
bool ok;
if (name)
ok = O->__defineOwnProperty__(scope.engine, name, n, nattrs);
else
ok = O->__defineOwnProperty__(scope.engine, index, n, nattrs);
if (!ok)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
}
- return O.asReturnedValue();
+ scope.result = O;
}
-ReturnedValue ObjectPrototype::method_seal(CallContext *ctx)
+void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
o->setInternalClass(o->internalClass()->sealed());
@@ -261,15 +259,14 @@ ReturnedValue ObjectPrototype::method_seal(CallContext *ctx)
}
}
- return o.asReturnedValue();
+ scope.result = o;
}
-ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx)
+void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (ArgumentsObject::isNonStrictArgumentsObject(o))
static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate();
@@ -285,96 +282,111 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx)
o->arrayData()->attrs[i].setWritable(false);
}
}
- return o.asReturnedValue();
+ scope.result = o;
}
-ReturnedValue ObjectPrototype::method_preventExtensions(CallContext *ctx)
+void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
o->setInternalClass(o->internalClass()->nonExtensible());
- return o.asReturnedValue();
+ scope.result = o;
}
-ReturnedValue ObjectPrototype::method_isSealed(CallContext *ctx)
+void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- if (o->isExtensible())
- return Encode(false);
+ if (o->isExtensible()) {
+ scope.result = Encode(false);
+ return;
+ }
- if (o->internalClass() != o->internalClass()->sealed())
- return Encode(false);
+ if (o->internalClass() != o->internalClass()->sealed()) {
+ scope.result = Encode(false);
+ return;
+ }
- if (!o->arrayData() || !o->arrayData()->length())
- return Encode(true);
+ if (!o->arrayData() || !o->arrayData()->length()) {
+ scope.result = Encode(true);
+ return;
+ }
Q_ASSERT(o->arrayData() && o->arrayData()->length());
- if (!o->arrayData()->attrs)
- return Encode(false);
+ if (!o->arrayData()->attrs) {
+ scope.result = Encode(false);
+ return;
+ }
for (uint i = 0; i < o->arrayData()->alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
- if (o->arrayData()->attributes(i).isConfigurable())
- return Encode(false);
+ if (o->arrayData()->attributes(i).isConfigurable()) {
+ scope.result = Encode(false);
+ return;
+ }
}
- return Encode(true);
+ scope.result = Encode(true);
}
-ReturnedValue ObjectPrototype::method_isFrozen(CallContext *ctx)
+void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- if (o->isExtensible())
- return Encode(false);
+ if (o->isExtensible()) {
+ scope.result = Encode(false);
+ return;
+ }
- if (o->internalClass() != o->internalClass()->frozen())
- return Encode(false);
+ if (o->internalClass() != o->internalClass()->frozen()) {
+ scope.result = Encode(false);
+ return;
+ }
- if (!o->arrayData() || !o->arrayData()->length())
- return Encode(true);
+ if (!o->arrayData() || !o->arrayData()->length()) {
+ scope.result = Encode(true);
+ return;
+ }
Q_ASSERT(o->arrayData() && o->arrayData()->length());
- if (!o->arrayData()->attrs)
- return Encode(false);
+ if (!o->arrayData()->attrs) {
+ scope.result = Encode(false);
+ return;
+ }
for (uint i = 0; i < o->arrayData()->alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
- if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable())
- return Encode(false);
+ if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) {
+ scope.result = Encode(false);
+ return;
+ }
}
- return Encode(true);
+ scope.result = Encode(true);
}
-ReturnedValue ObjectPrototype::method_isExtensible(CallContext *ctx)
+void ObjectPrototype::method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode((bool)o->isExtensible());
+ scope.result = Encode((bool)o->isExtensible());
}
-ReturnedValue ObjectPrototype::method_keys(CallContext *ctx)
+void ObjectPrototype::method_keys(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject());
+ ScopedArrayObject a(scope, scope.engine->newArrayObject());
ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
ScopedValue name(scope);
@@ -385,175 +397,159 @@ ReturnedValue ObjectPrototype::method_keys(CallContext *ctx)
a->push_back(name);
}
- return a.asReturnedValue();
+ scope.result = a;
}
-ReturnedValue ObjectPrototype::method_toString(CallContext *ctx)
+void ObjectPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- if (ctx->thisObject().isUndefined()) {
- return ctx->d()->engine->newString(QStringLiteral("[object Undefined]"))->asReturnedValue();
- } else if (ctx->thisObject().isNull()) {
- return ctx->d()->engine->newString(QStringLiteral("[object Null]"))->asReturnedValue();
+ if (callData->thisObject.isUndefined()) {
+ scope.result = scope.engine->newString(QStringLiteral("[object Undefined]"));
+ } else if (callData->thisObject.isNull()) {
+ scope.result = scope.engine->newString(QStringLiteral("[object Null]"));
} else {
- ScopedObject obj(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject obj(scope, callData->thisObject.toObject(scope.engine));
QString className = obj->className();
- return ctx->d()->engine->newString(QStringLiteral("[object %1]").arg(className))->asReturnedValue();
+ scope.result = scope.engine->newString(QStringLiteral("[object %1]").arg(className));
}
}
-ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx)
+void ObjectPrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject o(scope, callData->thisObject.toObject(scope.engine));
if (!o)
- return Encode::undefined();
- ScopedFunctionObject f(scope, o->get(ctx->d()->engine->id_toString()));
+ RETURN_UNDEFINED();
+
+ ScopedFunctionObject f(scope, o->get(scope.engine->id_toString()));
if (!f)
- return ctx->engine()->throwTypeError();
- ScopedCallData callData(scope);
- callData->thisObject = o;
+ THROW_TYPE_ERROR();
+ ScopedCallData cData(scope);
+ cData->thisObject = o;
f->call(scope, callData);
- return scope.result.asReturnedValue();
}
-ReturnedValue ObjectPrototype::method_valueOf(CallContext *ctx)
+void ObjectPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue v(scope, ctx->thisObject().toObject(scope.engine));
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
- return v->asReturnedValue();
+ scope.result = callData->thisObject.toObject(scope.engine);
}
-ReturnedValue ObjectPrototype::method_hasOwnProperty(CallContext *ctx)
+void ObjectPrototype::method_hasOwnProperty(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedString P(scope, ctx->argument(0), ScopedString::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
- ScopedObject O(scope, ctx->thisObject(), ScopedObject::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedString P(scope, callData->argument(0), ScopedString::Convert);
+ CHECK_EXCEPTION();
+ ScopedObject O(scope, callData->thisObject, ScopedObject::Convert);
+ CHECK_EXCEPTION();
bool r = O->hasOwnProperty(P);
if (!r)
r = !O->query(P).isEmpty();
- return Encode(r);
+ scope.result = Encode(r);
}
-ReturnedValue ObjectPrototype::method_isPrototypeOf(CallContext *ctx)
+void ObjectPrototype::method_isPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject V(scope, ctx->argument(0));
- if (!V)
- return Encode(false);
+ ScopedObject V(scope, callData->argument(0));
+ if (!V) {
+ scope.result = Encode(false);
+ return;
+ }
- ScopedObject O(scope, ctx->thisObject(), ScopedObject::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedObject O(scope, callData->thisObject, ScopedObject::Convert);
+ CHECK_EXCEPTION();
ScopedObject proto(scope, V->prototype());
while (proto) {
- if (O->d() == proto->d())
- return Encode(true);
+ if (O->d() == proto->d()) {
+ scope.result = Encode(true);
+ return;
+ }
proto = proto->prototype();
}
- return Encode(false);
+ scope.result = Encode(false);
}
-ReturnedValue ObjectPrototype::method_propertyIsEnumerable(CallContext *ctx)
+void ObjectPrototype::method_propertyIsEnumerable(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedString p(scope, ctx->argument(0), ScopedString::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedString p(scope, callData->argument(0), ScopedString::Convert);
+ CHECK_EXCEPTION();
- ScopedObject o(scope, ctx->thisObject(), ScopedObject::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedObject o(scope, callData->thisObject, ScopedObject::Convert);
+ CHECK_EXCEPTION();
PropertyAttributes attrs;
o->getOwnProperty(p, &attrs);
- return Encode(attrs.isEnumerable());
+ scope.result = Encode(attrs.isEnumerable());
}
-ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx)
+void ObjectPrototype::method_defineGetter(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 2)
- return ctx->engine()->throwTypeError();
+ if (callData->argc < 2)
+ THROW_TYPE_ERROR();
- Scope scope(ctx);
- ScopedFunctionObject f(scope, ctx->argument(1));
+ ScopedFunctionObject f(scope, callData->argument(1));
if (!f)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedString prop(scope, ctx->argument(0), ScopedString::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedString prop(scope, callData->argument(0), ScopedString::Convert);
+ CHECK_EXCEPTION();
- ScopedObject o(scope, ctx->thisObject());
+ ScopedObject o(scope, callData->thisObject);
if (!o) {
- if (!ctx->thisObject().isUndefined())
- return Encode::undefined();
- o = ctx->d()->engine->globalObject;
+ if (!callData->thisObject.isUndefined())
+ RETURN_UNDEFINED();
+ o = scope.engine->globalObject;
}
ScopedProperty pd(scope);
pd->value = f;
pd->set = Primitive::emptyValue();
o->__defineOwnProperty__(scope.engine, prop, pd, Attr_Accessor);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx)
+void ObjectPrototype::method_defineSetter(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 2)
- return ctx->engine()->throwTypeError();
+ if (callData->argc < 2)
+ THROW_TYPE_ERROR();
- Scope scope(ctx);
- ScopedFunctionObject f(scope, ctx->argument(1));
+ ScopedFunctionObject f(scope, callData->argument(1));
if (!f)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedString prop(scope, ctx->argument(0), ScopedString::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedString prop(scope, callData->argument(0), ScopedString::Convert);
+ CHECK_EXCEPTION();
- ScopedObject o(scope, ctx->thisObject());
+ ScopedObject o(scope, callData->thisObject);
if (!o) {
- if (!ctx->thisObject().isUndefined())
- return Encode::undefined();
- o = ctx->d()->engine->globalObject;
+ if (!callData->thisObject.isUndefined())
+ RETURN_UNDEFINED();
+ o = scope.engine->globalObject;
}
ScopedProperty pd(scope);
pd->value = Primitive::emptyValue();
pd->set = f;
o->__defineOwnProperty__(scope.engine, prop, pd, Attr_Accessor);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx)
+void ObjectPrototype::method_get_proto(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->thisObject().as<Object>());
+ ScopedObject o(scope, callData->thisObject.as<Object>());
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return o->prototype()->asReturnedValue();
+ scope.result = o->prototype();
}
-ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx)
+void ObjectPrototype::method_set_proto(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->thisObject());
- if (!o || !ctx->argc())
- return ctx->engine()->throwTypeError();
+ ScopedObject o(scope, callData->thisObject);
+ if (!o || !callData->argc)
+ THROW_TYPE_ERROR();
- if (ctx->args()[0].isNull()) {
+ if (callData->args[0].isNull()) {
o->setPrototype(0);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
- ScopedObject p(scope, ctx->args()[0]);
+ ScopedObject p(scope, callData->args[0]);
bool ok = false;
if (!!p) {
if (o->prototype() == p->d()) {
@@ -562,9 +558,11 @@ ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx)
ok = o->setPrototype(p);
}
}
- if (!ok)
- return ctx->engine()->throwTypeError(QStringLiteral("Cyclic __proto__ value"));
- return Encode::undefined();
+ if (!ok) {
+ scope.result = scope.engine->throwTypeError(QStringLiteral("Cyclic __proto__ value"));
+ return;
+ }
+ RETURN_UNDEFINED();
}
void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value &v, Property *desc, PropertyAttributes *attrs)
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index e3d85782d5..1db8615511 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -78,32 +78,32 @@ struct ObjectPrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_getPrototypeOf(CallContext *ctx);
- static ReturnedValue method_getOwnPropertyDescriptor(CallContext *ctx);
- static ReturnedValue method_getOwnPropertyNames(CallContext *context);
- static ReturnedValue method_create(CallContext *ctx);
- static ReturnedValue method_defineProperty(CallContext *ctx);
- static ReturnedValue method_defineProperties(CallContext *ctx);
- static ReturnedValue method_seal(CallContext *ctx);
- static ReturnedValue method_freeze(CallContext *ctx);
- static ReturnedValue method_preventExtensions(CallContext *ctx);
- static ReturnedValue method_isSealed(CallContext *ctx);
- static ReturnedValue method_isFrozen(CallContext *ctx);
- static ReturnedValue method_isExtensible(CallContext *ctx);
- static ReturnedValue method_keys(CallContext *ctx);
-
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_toLocaleString(CallContext *ctx);
- static ReturnedValue method_valueOf(CallContext *ctx);
- static ReturnedValue method_hasOwnProperty(CallContext *ctx);
- static ReturnedValue method_isPrototypeOf(CallContext *ctx);
- static ReturnedValue method_propertyIsEnumerable(CallContext *ctx);
-
- static ReturnedValue method_defineGetter(CallContext *ctx);
- static ReturnedValue method_defineSetter(CallContext *ctx);
-
- static ReturnedValue method_get_proto(CallContext *ctx);
- static ReturnedValue method_set_proto(CallContext *ctx);
+ static void method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_create(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_seal(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_keys(const BuiltinFunction *, Scope &scope, CallData *callData);
+
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_hasOwnProperty(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_propertyIsEnumerable(const BuiltinFunction *, Scope &scope, CallData *callData);
+
+ static void method_defineGetter(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_defineSetter(const BuiltinFunction *, Scope &scope, CallData *callData);
+
+ static void method_get_proto(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_set_proto(const BuiltinFunction *, Scope &scope, CallData *callData);
static void toPropertyDescriptor(ExecutionEngine *engine, const Value &v, Property *desc, PropertyAttributes *attrs);
static ReturnedValue fromPropertyDescriptor(ExecutionEngine *engine, const Property *desc, PropertyAttributes attrs);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 77dbb18b50..7260e71fab 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -826,40 +826,39 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
} // namespace QV4
-ReturnedValue QObjectWrapper::method_connect(CallContext *ctx)
+void QObjectWrapper::method_connect(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() == 0)
- V4THROW_ERROR("Function.prototype.connect: no arguments given");
+ if (callData->argc == 0)
+ THROW_GENERIC_ERROR("Function.prototype.connect: no arguments given");
- QPair<QObject *, int> signalInfo = extractQtSignal(ctx->thisObject());
+ QPair<QObject *, int> signalInfo = extractQtSignal(callData->thisObject);
QObject *signalObject = signalInfo.first;
int signalIndex = signalInfo.second; // in method range, not signal range!
if (signalIndex < 0)
- V4THROW_ERROR("Function.prototype.connect: this object is not a signal");
+ THROW_GENERIC_ERROR("Function.prototype.connect: this object is not a signal");
if (!signalObject)
- V4THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
+ THROW_GENERIC_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
- V4THROW_ERROR("Function.prototype.connect: this object is not a signal");
+ THROW_GENERIC_ERROR("Function.prototype.connect: this object is not a signal");
- QV4::Scope scope(ctx);
QV4::ScopedFunctionObject f(scope);
QV4::ScopedValue thisObject (scope, QV4::Encode::undefined());
- if (ctx->argc() == 1) {
- f = ctx->args()[0];
- } else if (ctx->argc() >= 2) {
- thisObject = ctx->args()[0];
- f = ctx->args()[1];
+ if (callData->argc == 1) {
+ f = callData->args[0];
+ } else if (callData->argc >= 2) {
+ thisObject = callData->args[0];
+ f = callData->args[1];
}
if (!f)
- V4THROW_ERROR("Function.prototype.connect: target is not a function");
+ THROW_GENERIC_ERROR("Function.prototype.connect: target is not a function");
if (!thisObject->isUndefined() && !thisObject->isObject())
- V4THROW_ERROR("Function.prototype.connect: target this is not an object");
+ THROW_GENERIC_ERROR("Function.prototype.connect: target this is not an object");
QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher;
slot->signalIndex = signalIndex;
@@ -874,49 +873,47 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx)
}
QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx)
+void QObjectWrapper::method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() == 0)
- V4THROW_ERROR("Function.prototype.disconnect: no arguments given");
-
- QV4::Scope scope(ctx);
+ if (callData->argc == 0)
+ THROW_GENERIC_ERROR("Function.prototype.disconnect: no arguments given");
- QPair<QObject *, int> signalInfo = extractQtSignal(ctx->thisObject());
+ QPair<QObject *, int> signalInfo = extractQtSignal(callData->thisObject);
QObject *signalObject = signalInfo.first;
int signalIndex = signalInfo.second;
if (signalIndex == -1)
- V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+ THROW_GENERIC_ERROR("Function.prototype.disconnect: this object is not a signal");
if (!signalObject)
- V4THROW_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject");
+ THROW_GENERIC_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject");
if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
- V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+ THROW_GENERIC_ERROR("Function.prototype.disconnect: this object is not a signal");
QV4::ScopedFunctionObject functionValue(scope);
QV4::ScopedValue functionThisValue(scope, QV4::Encode::undefined());
- if (ctx->argc() == 1) {
- functionValue = ctx->args()[0];
- } else if (ctx->argc() >= 2) {
- functionThisValue = ctx->args()[0];
- functionValue = ctx->args()[1];
+ if (callData->argc == 1) {
+ functionValue = callData->args[0];
+ } else if (callData->argc >= 2) {
+ functionThisValue = callData->args[0];
+ functionValue = callData->args[1];
}
if (!functionValue)
- V4THROW_ERROR("Function.prototype.disconnect: target is not a function");
+ THROW_GENERIC_ERROR("Function.prototype.disconnect: target is not a function");
if (!functionThisValue->isUndefined() && !functionThisValue->isObject())
- V4THROW_ERROR("Function.prototype.disconnect: target this is not an object");
+ THROW_GENERIC_ERROR("Function.prototype.disconnect: target this is not an object");
QPair<QObject *, int> functionData = QObjectMethod::extractQtMethod(functionValue);
void *a[] = {
- ctx->d()->engine,
+ scope.engine,
functionValue.ptr,
functionThisValue.ptr,
functionData.first,
@@ -925,7 +922,7 @@ ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx)
QObjectPrivate::disconnect(signalObject, signalIndex, reinterpret_cast<void**>(&a));
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
static void markChildQObjectsRecursively(QObject *parent, QV4::ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index c7c4f4dd77..b09e06cec5 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -197,8 +197,8 @@ protected:
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
- static ReturnedValue method_connect(CallContext *ctx);
- static ReturnedValue method_disconnect(CallContext *ctx);
+ static void method_connect(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData);
private:
Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object);
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 41d8010fef..40682aaa4b 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -349,34 +349,33 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor)
defineDefaultProperty(QStringLiteral("compile"), method_compile, 2);
}
-ReturnedValue RegExpPrototype::method_exec(CallContext *ctx)
+void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<RegExpObject> r(scope, ctx->thisObject().as<RegExpObject>());
+ Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedValue arg(scope, ctx->argument(0));
+ ScopedValue arg(scope, callData->argument(0));
ScopedString str(scope, arg->toString(scope.engine));
if (scope.hasException())
- return Encode::undefined();
+ RETURN_UNDEFINED();
QString s = str->toQString();
int offset = r->global() ? r->lastIndexProperty()->toInt32() : 0;
if (offset < 0 || offset > s.length()) {
*r->lastIndexProperty() = Primitive::fromInt32(0);
- return Encode::null();
+ RETURN_RESULT(Encode::null());
}
uint* matchOffsets = (uint*)alloca(r->value()->captureCount() * 2 * sizeof(uint));
const int result = Scoped<RegExp>(scope, r->value())->match(s, offset, matchOffsets);
- Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor());
+ Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor());
regExpCtor->d()->clearLastMatch();
if (result == -1) {
*r->lastIndexProperty() = Primitive::fromInt32(0);
- return Encode::null();
+ RETURN_RESULT(Encode::null());
}
// fill in result data
@@ -387,7 +386,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx)
for (int i = 0; i < len; ++i) {
int start = matchOffsets[i * 2];
int end = matchOffsets[i * 2 + 1];
- v = (start != -1) ? ctx->d()->engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined();
+ v = (start != -1) ? scope.engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined();
array->arrayPut(i, v);
}
array->setArrayLengthUnchecked(len);
@@ -403,84 +402,75 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx)
if (r->global())
*r->lastIndexProperty() = Primitive::fromInt32(matchOffsets[1]);
- return array.asReturnedValue();
+ scope.result = array;
}
-ReturnedValue RegExpPrototype::method_test(CallContext *ctx)
+void RegExpPrototype::method_test(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue r(scope, method_exec(ctx));
- return Encode(!r->isNull());
+ method_exec(b, scope, callData);
+ scope.result = Encode(!scope.result.isNull());
}
-ReturnedValue RegExpPrototype::method_toString(CallContext *ctx)
+void RegExpPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<RegExpObject> r(scope, ctx->thisObject().as<RegExpObject>());
+ Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return ctx->d()->engine->newString(r->toString())->asReturnedValue();
+ scope.result = scope.engine->newString(r->toString());
}
-ReturnedValue RegExpPrototype::method_compile(CallContext *ctx)
+void RegExpPrototype::method_compile(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<RegExpObject> r(scope, ctx->thisObject().as<RegExpObject>());
+ Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, ctx->argc());
- memcpy(callData->args, ctx->args(), ctx->argc()*sizeof(Value));
+ ScopedCallData cData(scope, callData->argc);
+ memcpy(cData->args, callData->args, callData->argc*sizeof(Value));
- ctx->d()->engine->regExpCtor()->as<FunctionObject>()->construct(scope, callData);
+ scope.engine->regExpCtor()->as<FunctionObject>()->construct(scope, cData);
Scoped<RegExpObject> re(scope, scope.result.asReturnedValue());
r->d()->value = re->value();
r->d()->global = re->global();
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
template <int index>
-ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx)
+void RegExpPrototype::method_get_lastMatch_n(const BuiltinFunction *, Scope &scope, CallData *)
{
- Scope scope(ctx);
- ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastMatch());
- ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(index) : Encode::undefined());
- if (result->isUndefined())
- return ctx->d()->engine->newString()->asReturnedValue();
- return result->asReturnedValue();
+ ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(scope.engine->regExpCtor())->lastMatch());
+ scope.result = lastMatch ? lastMatch->getIndexed(index) : Encode::undefined();
+ if (scope.result.isUndefined())
+ scope.result = scope.engine->newString();
}
-ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx)
+void RegExpPrototype::method_get_lastParen(const BuiltinFunction *, Scope &scope, CallData *)
{
- Scope scope(ctx);
- ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastMatch());
- ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined());
- if (result->isUndefined())
- return ctx->d()->engine->newString()->asReturnedValue();
- return result->asReturnedValue();
+ ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(scope.engine->regExpCtor())->lastMatch());
+ scope.result = lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined();
+ if (scope.result.isUndefined())
+ scope.result = scope.engine->newString();
}
-ReturnedValue RegExpPrototype::method_get_input(CallContext *ctx)
+void RegExpPrototype::method_get_input(const BuiltinFunction *, Scope &scope, CallData *)
{
- return static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastInput()->asReturnedValue();
+ scope.result = static_cast<RegExpCtor*>(scope.engine->regExpCtor())->lastInput();
}
-ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx)
+void RegExpPrototype::method_get_leftContext(const BuiltinFunction *, Scope &scope, CallData *)
{
- Scope scope(ctx);
- Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor());
+ Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor());
QString lastInput = regExpCtor->lastInput()->toQString();
- return ctx->d()->engine->newString(lastInput.left(regExpCtor->lastMatchStart()))->asReturnedValue();
+ scope.result = scope.engine->newString(lastInput.left(regExpCtor->lastMatchStart()));
}
-ReturnedValue RegExpPrototype::method_get_rightContext(CallContext *ctx)
+void RegExpPrototype::method_get_rightContext(const BuiltinFunction *, Scope &scope, CallData *)
{
- Scope scope(ctx);
- Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor());
+ Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor());
QString lastInput = regExpCtor->lastInput()->toQString();
- return ctx->d()->engine->newString(lastInput.mid(regExpCtor->lastMatchEnd()))->asReturnedValue();
+ scope.result = scope.engine->newString(lastInput.mid(regExpCtor->lastMatchEnd()));
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 2c82cfdfd1..c0c7dfa78a 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -149,17 +149,17 @@ struct RegExpPrototype: RegExpObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_exec(CallContext *ctx);
- static ReturnedValue method_test(CallContext *ctx);
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_compile(CallContext *ctx);
+ static void method_exec(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_test(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_compile(const BuiltinFunction *, Scope &scope, CallData *callData);
template <int index>
- static ReturnedValue method_get_lastMatch_n(CallContext *ctx);
- static ReturnedValue method_get_lastParen(CallContext *ctx);
- static ReturnedValue method_get_input(CallContext *ctx);
- static ReturnedValue method_get_leftContext(CallContext *ctx);
- static ReturnedValue method_get_rightContext(CallContext *ctx);
+ static void method_get_lastMatch_n(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_lastParen(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_input(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_leftContext(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_rightContext(const BuiltinFunction *, Scope &scope, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 023a739e33..7f184f8221 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -343,35 +343,15 @@ ReturnedValue Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex)
return Encode(engine->currentContext->deleteProperty(name));
}
-QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &left, const Value &right)
+QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &lval, const Value &rval)
{
- const FunctionObject *function = right.as<FunctionObject>();
- if (!function)
- return engine->throwTypeError();
-
- Heap::FunctionObject *f = function->d();
- if (function->isBoundFunction())
- f = function->cast<BoundFunction>()->target();
-
- const Object *o = left.as<Object>();
- if (!o)
- return Encode(false);
- Heap::Object *v = o->d();
-
- o = f->protoProperty();
- if (!o)
- return engine->throwTypeError();
-
- while (v) {
- v = v->prototype;
-
- if (!v)
- break;
- else if (o->d() == v)
- return Encode(true);
- }
+ // 11.8.6, 5: rval must be an Object
+ const Object *rhs = rval.as<Object>();
+ if (!rhs)
+ return engine->throwTypeError();
- return Encode(false);
+ // 11.8.6, 7: call "HasInstance", which we term instanceOf, and return the result.
+ return rhs->instanceOf(lval);
}
QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right)
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index 4e627e003f..6775028272 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -68,6 +68,38 @@ namespace QV4 {
struct ScopedValue;
+#define CHECK_EXCEPTION() \
+ do { \
+ if (scope.hasException()) { \
+ scope.result = QV4::Encode::undefined(); \
+ return; \
+ } \
+ } while (false)
+
+#define RETURN_UNDEFINED() \
+ do { \
+ scope.result = QV4::Encode::undefined(); \
+ return; \
+ } while (false)
+
+#define RETURN_RESULT(r) \
+ do { \
+ scope.result = r; \
+ return; \
+ } while (false)
+
+#define THROW_TYPE_ERROR() \
+ do { \
+ scope.result = scope.engine->throwTypeError(); \
+ return; \
+ } while (false)
+
+#define THROW_GENERIC_ERROR(str) \
+ do { \
+ scope.result = scope.engine->throwError(QString::fromUtf8(str)); \
+ return; \
+ } while (false)
+
struct Scope {
inline Scope(ExecutionContext *ctx)
: engine(ctx->d()->engine)
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 58da7b9f68..8ce10e326d 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -404,28 +404,28 @@ public:
struct CompareFunctor
{
- CompareFunctor(QV4::ExecutionContext *ctx, const QV4::Value &compareFn)
- : m_ctx(ctx), m_compareFn(&compareFn)
+ CompareFunctor(QV4::ExecutionEngine *v4, const QV4::Value &compareFn)
+ : m_v4(v4), m_compareFn(&compareFn)
{}
bool operator()(typename Container::value_type lhs, typename Container::value_type rhs)
{
- QV4::Scope scope(m_ctx);
+ QV4::Scope scope(m_v4);
ScopedObject compare(scope, m_compareFn);
ScopedCallData callData(scope, 2);
- callData->args[0] = convertElementToValue(this->m_ctx->d()->engine, lhs);
- callData->args[1] = convertElementToValue(this->m_ctx->d()->engine, rhs);
- callData->thisObject = this->m_ctx->d()->engine->globalObject;
+ callData->args[0] = convertElementToValue(m_v4, lhs);
+ callData->args[1] = convertElementToValue(m_v4, rhs);
+ callData->thisObject = m_v4->globalObject;
compare->call(scope, callData);
return scope.result.toNumber() < 0;
}
private:
- QV4::ExecutionContext *m_ctx;
+ QV4::ExecutionEngine *m_v4;
const QV4::Value *m_compareFn;
};
- void sort(QV4::CallContext *ctx)
+ void sort(const BuiltinFunction *, Scope &scope, CallData *callData)
{
if (d()->isReference) {
if (!d()->object)
@@ -433,9 +433,8 @@ public:
loadReference();
}
- QV4::Scope scope(ctx);
- if (ctx->argc() == 1 && ctx->args()[0].as<FunctionObject>()) {
- CompareFunctor cf(ctx, ctx->args()[0]);
+ if (callData->argc == 1 && callData->args[0].as<FunctionObject>()) {
+ CompareFunctor cf(scope.engine, callData->args[0]);
std::sort(d()->container->begin(), d()->container->end(), cf);
} else {
DefaultCompareFunctor cf;
@@ -446,45 +445,43 @@ public:
storeReference();
}
- static QV4::ReturnedValue method_get_length(QV4::CallContext *ctx)
+ static void method_get_length(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->thisObject().as<QQmlSequence<Container> >());
+ QV4::Scoped<QQmlSequence<Container> > This(scope, callData->thisObject.as<QQmlSequence<Container> >());
if (!This)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (This->d()->isReference) {
if (!This->d()->object)
- return QV4::Encode(0);
+ RETURN_RESULT(Encode(0));
This->loadReference();
}
- return QV4::Encode(This->d()->container->count());
+ RETURN_RESULT(Encode(This->d()->container->count()));
}
- static QV4::ReturnedValue method_set_length(QV4::CallContext* ctx)
+ static void method_set_length(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->thisObject().as<QQmlSequence<Container> >());
+ QV4::Scoped<QQmlSequence<Container> > This(scope, callData->thisObject.as<QQmlSequence<Container> >());
if (!This)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- quint32 newLength = ctx->args()[0].toUInt32();
+ quint32 newLength = callData->args[0].toUInt32();
/* Qt containers have int (rather than uint) allowable indexes. */
if (newLength > INT_MAX) {
generateWarning(scope.engine, QLatin1String("Index out of range during length set"));
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/* Read the sequence from the QObject property if we're a reference */
if (This->d()->isReference) {
if (!This->d()->object)
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
This->loadReference();
}
/* Determine whether we need to modify the sequence */
qint32 newCount = static_cast<qint32>(newLength);
qint32 count = This->d()->container->count();
if (newCount == count) {
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
} else if (newCount > count) {
/* according to ECMA262r3 we need to insert */
/* undefined values increasing length to newLength. */
@@ -506,7 +503,7 @@ public:
/* write back. already checked that object is non-null, so skip that check here. */
This->storeReference();
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
QVariant toVariant() const
@@ -625,26 +622,25 @@ void SequencePrototype::init()
}
#undef REGISTER_QML_SEQUENCE_METATYPE
-QV4::ReturnedValue SequencePrototype::method_sort(QV4::CallContext *ctx)
+void SequencePrototype::method_sort(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::ScopedObject o(scope, ctx->thisObject());
+ QV4::ScopedObject o(scope, callData->thisObject);
if (!o || !o->isListType())
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- if (ctx->argc() >= 2)
- return o.asReturnedValue();
+ if (callData->argc >= 2)
+ RETURN_RESULT(o);
#define CALL_SORT(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue) \
if (QQml##SequenceElementTypeName##List *s = o->as<QQml##SequenceElementTypeName##List>()) { \
- s->sort(ctx); \
+ s->sort(b, scope, callData); \
} else
FOREACH_QML_SEQUENCE_TYPE(CALL_SORT)
#undef CALL_SORT
{}
- return o.asReturnedValue();
+ RETURN_RESULT(o);
}
#define IS_SEQUENCE(unused1, unused2, SequenceType, unused3) \
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index c0416ad639..6f96b9f760 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -67,12 +67,12 @@ struct SequencePrototype : public QV4::Object
{
void init();
- static ReturnedValue method_valueOf(QV4::CallContext *ctx)
+ static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- return ctx->thisObject().toString(ctx->engine())->asReturnedValue();
+ scope.result = callData->thisObject.toString(scope.engine);
}
- static ReturnedValue method_sort(QV4::CallContext *ctx);
+ static void method_sort(const BuiltinFunction *, Scope &scope, CallData *callData);
static bool isSequenceType(int sequenceTypeId);
static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded);
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 6fbf1c3c85..3c6a24e035 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -214,10 +214,9 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("trim"), method_trim);
}
-static QString getThisString(ExecutionContext *ctx)
+static QString getThisString(Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue t(scope, ctx->thisObject());
+ ScopedValue t(scope, callData->thisObject);
if (String *s = t->stringValue())
return s->toQString();
if (StringObject *thisString = t->as<StringObject>())
@@ -229,158 +228,146 @@ static QString getThisString(ExecutionContext *ctx)
return t->toQString();
}
-ReturnedValue StringPrototype::method_toString(CallContext *context)
+void StringPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (context->thisObject().isString())
- return context->thisObject().asReturnedValue();
+ if (callData->thisObject.isString())
+ RETURN_RESULT(callData->thisObject);
- StringObject *o = context->thisObject().as<StringObject>();
+ StringObject *o = callData->thisObject.as<StringObject>();
if (!o)
- return context->engine()->throwTypeError();
- return Encode(o->d()->string);
+ THROW_TYPE_ERROR();
+ scope.result = o->d()->string;
}
-ReturnedValue StringPrototype::method_charAt(CallContext *context)
+void StringPrototype::method_charAt(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- const QString str = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ const QString str = getThisString(scope, callData);
+ CHECK_EXCEPTION();
int pos = 0;
- if (context->argc() > 0)
- pos = (int) context->args()[0].toInteger();
+ if (callData->argc > 0)
+ pos = (int) callData->args[0].toInteger();
QString result;
if (pos >= 0 && pos < str.length())
result += str.at(pos);
- return context->d()->engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
-ReturnedValue StringPrototype::method_charCodeAt(CallContext *context)
+void StringPrototype::method_charCodeAt(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- const QString str = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ const QString str = getThisString(scope, callData);
+ CHECK_EXCEPTION();
int pos = 0;
- if (context->argc() > 0)
- pos = (int) context->args()[0].toInteger();
+ if (callData->argc > 0)
+ pos = (int) callData->args[0].toInteger();
if (pos >= 0 && pos < str.length())
- return Encode(str.at(pos).unicode());
+ RETURN_RESULT(Encode(str.at(pos).unicode()));
- return Encode(qt_qnan());
+ scope.result = Encode(qt_qnan());
}
-ReturnedValue StringPrototype::method_concat(CallContext *context)
+void StringPrototype::method_concat(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(context);
-
- QString value = getThisString(context);
- if (scope.engine->hasException)
- return Encode::undefined();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
ScopedString s(scope);
- for (int i = 0; i < context->argc(); ++i) {
- s = context->args()[i].toString(scope.engine);
- if (scope.hasException())
- return Encode::undefined();
+ for (int i = 0; i < callData->argc; ++i) {
+ s = callData->args[i].toString(scope.engine);
+ CHECK_EXCEPTION();
+
Q_ASSERT(s->isString());
value += s->toQString();
}
- return context->d()->engine->newString(value)->asReturnedValue();
+ scope.result = scope.engine->newString(value);
}
-ReturnedValue StringPrototype::method_endsWith(CallContext *context)
+void StringPrototype::method_endsWith(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
QString searchString;
- if (context->argc()) {
- if (context->args()[0].as<RegExpObject>())
- return context->engine()->throwTypeError();
- searchString = context->args()[0].toQString();
+ if (callData->argc) {
+ if (callData->args[0].as<RegExpObject>())
+ THROW_TYPE_ERROR();
+ searchString = callData->args[0].toQString();
}
int pos = value.length();
- if (context->argc() > 1)
- pos = (int) context->args()[1].toInteger();
+ if (callData->argc > 1)
+ pos = (int) callData->args[1].toInteger();
if (pos == value.length())
- return Encode(value.endsWith(searchString));
+ RETURN_RESULT(Encode(value.endsWith(searchString)));
QStringRef stringToSearch = value.leftRef(pos);
- return Encode(stringToSearch.endsWith(searchString));
+ scope.result = Encode(stringToSearch.endsWith(searchString));
}
-ReturnedValue StringPrototype::method_indexOf(CallContext *context)
+void StringPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
QString searchString;
- if (context->argc())
- searchString = context->args()[0].toQString();
+ if (callData->argc)
+ searchString = callData->args[0].toQString();
int pos = 0;
- if (context->argc() > 1)
- pos = (int) context->args()[1].toInteger();
+ if (callData->argc > 1)
+ pos = (int) callData->args[1].toInteger();
int index = -1;
if (! value.isEmpty())
index = value.indexOf(searchString, qMin(qMax(pos, 0), value.length()));
- return Encode(index);
+ scope.result = Encode(index);
}
-ReturnedValue StringPrototype::method_includes(CallContext *context)
+void StringPrototype::method_includes(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
QString searchString;
- if (context->argc()) {
- if (context->args()[0].as<RegExpObject>())
- return context->engine()->throwTypeError();
- searchString = context->args()[0].toQString();
+ if (callData->argc) {
+ if (callData->args[0].as<RegExpObject>())
+ THROW_TYPE_ERROR();
+ searchString = callData->args[0].toQString();
}
int pos = 0;
- if (context->argc() > 1) {
- Scope scope(context);
- ScopedValue posArg(scope, context->argument(1));
+ if (callData->argc > 1) {
+ ScopedValue posArg(scope, callData->argument(1));
pos = (int) posArg->toInteger();
if (!posArg->isInteger() && posArg->isNumber() && qIsInf(posArg->toNumber()))
pos = value.length();
}
if (pos == 0)
- return Encode(value.contains(searchString));
+ RETURN_RESULT(Encode(value.contains(searchString)));
QStringRef stringToSearch = value.midRef(pos);
- return Encode(stringToSearch.contains(searchString));
+ scope.result = Encode(stringToSearch.contains(searchString));
}
-ReturnedValue StringPrototype::method_lastIndexOf(CallContext *context)
+void StringPrototype::method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(context);
-
- const QString value = getThisString(context);
- if (scope.engine->hasException)
- return Encode::undefined();
+ const QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
QString searchString;
- if (context->argc())
- searchString = context->args()[0].toQString();
+ if (callData->argc)
+ searchString = callData->args[0].toQString();
- ScopedValue posArg(scope, context->argument(1));
+ ScopedValue posArg(scope, callData->argument(1));
double position = RuntimeHelpers::toNumber(posArg);
if (std::isnan(position))
position = +qInf();
@@ -391,43 +378,40 @@ ReturnedValue StringPrototype::method_lastIndexOf(CallContext *context)
if (!searchString.isEmpty() && pos == value.length())
--pos;
if (searchString.isNull() && pos == 0)
- return Encode(-1);
+ RETURN_RESULT(Encode(-1));
int index = value.lastIndexOf(searchString, pos);
- return Encode(index);
+ scope.result = Encode(index);
}
-ReturnedValue StringPrototype::method_localeCompare(CallContext *context)
+void StringPrototype::method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(context);
- const QString value = getThisString(context);
- if (scope.engine->hasException)
- return Encode::undefined();
+ const QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
- ScopedValue v(scope, context->argument(0));
+ ScopedValue v(scope, callData->argument(0));
const QString that = v->toQString();
- return Encode(QString::localeAwareCompare(value, that));
+ scope.result = Encode(QString::localeAwareCompare(value, that));
}
-ReturnedValue StringPrototype::method_match(CallContext *context)
+void StringPrototype::method_match(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (context->thisObject().isUndefined() || context->thisObject().isNull())
- return context->engine()->throwTypeError();
+ if (callData->thisObject.isUndefined() || callData->thisObject.isNull())
+ THROW_TYPE_ERROR();
- Scope scope(context);
- ScopedString s(scope, context->thisObject().toString(scope.engine));
+ ScopedString s(scope, callData->thisObject.toString(scope.engine));
- ScopedValue regexp(scope, context->argument(0));
+ ScopedValue regexp(scope, callData->argument(0));
Scoped<RegExpObject> rx(scope, regexp);
if (!rx) {
ScopedCallData callData(scope, 1);
callData->args[0] = regexp;
- context->d()->engine->regExpCtor()->construct(scope, callData);
+ scope.engine->regExpCtor()->construct(scope, callData);
rx = scope.result.asReturnedValue();
}
if (!rx)
// ### CHECK
- return context->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
bool global = rx->global();
@@ -435,24 +419,24 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
ScopedString execString(scope, scope.engine->newString(QStringLiteral("exec")));
ScopedFunctionObject exec(scope, scope.engine->regExpPrototype()->get(execString));
- ScopedCallData callData(scope, 1);
- callData->thisObject = rx;
- callData->args[0] = s;
+ ScopedCallData cData(scope, 1);
+ cData->thisObject = rx;
+ cData->args[0] = s;
if (!global) {
- exec->call(scope, callData);
- return scope.result.asReturnedValue();
+ exec->call(scope, cData);
+ return;
}
- ScopedString lastIndex(scope, context->d()->engine->newString(QStringLiteral("lastIndex")));
+ ScopedString lastIndex(scope, scope.engine->newString(QStringLiteral("lastIndex")));
rx->put(lastIndex, ScopedValue(scope, Primitive::fromInt32(0)));
- ScopedArrayObject a(scope, context->d()->engine->newArrayObject());
+ ScopedArrayObject a(scope, scope.engine->newArrayObject());
double previousLastIndex = 0;
uint n = 0;
ScopedValue matchStr(scope);
ScopedValue index(scope);
while (1) {
- exec->call(scope, callData);
+ exec->call(scope, cData);
if (scope.result.isNull())
break;
assert(scope.result.isObject());
@@ -469,10 +453,9 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
++n;
}
if (!n)
- return Encode::null();
-
- return a.asReturnedValue();
-
+ scope.result = Encode::null();
+ else
+ scope.result = a;
}
static void appendReplacementString(QString *result, const QString &input, const QString& replaceValue, uint* matchOffsets, int captureCount)
@@ -521,14 +504,13 @@ static void appendReplacementString(QString *result, const QString &input, const
}
}
-ReturnedValue StringPrototype::method_replace(CallContext *ctx)
+void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
QString string;
- if (StringObject *thisString = ctx->thisObject().as<StringObject>())
+ if (StringObject *thisString = callData->thisObject.as<StringObject>())
string = thisString->d()->string->toQString();
else
- string = ctx->thisObject().toQString();
+ string = callData->thisObject.toQString();
int numCaptures = 0;
int numStringMatches = 0;
@@ -537,7 +519,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
uint _matchOffsets[64];
uint *matchOffsets = _matchOffsets;
- ScopedValue searchValue(scope, ctx->argument(0));
+ ScopedValue searchValue(scope, callData->argument(0));
Scoped<RegExpObject> regExp(scope, searchValue);
if (regExp) {
uint offset = 0;
@@ -580,7 +562,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
}
QString result;
- ScopedValue replaceValue(scope, ctx->argument(1));
+ ScopedValue replaceValue(scope, callData->argument(1));
ScopedFunctionObject searchCallback(scope, replaceValue);
if (!!searchCallback) {
result.reserve(string.length() + 10*numStringMatches);
@@ -595,14 +577,14 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
uint end = matchOffsets[idx + 1];
entry = Primitive::undefinedValue();
if (start != JSC::Yarr::offsetNoMatch && end != JSC::Yarr::offsetNoMatch)
- entry = ctx->d()->engine->newString(string.mid(start, end - start));
+ entry = scope.engine->newString(string.mid(start, end - start));
callData->args[k] = entry;
}
uint matchStart = matchOffsets[i * numCaptures * 2];
Q_ASSERT(matchStart >= static_cast<uint>(lastEnd));
uint matchEnd = matchOffsets[i * numCaptures * 2 + 1];
callData->args[numCaptures] = Primitive::fromUInt32(matchStart);
- callData->args[numCaptures + 1] = ctx->d()->engine->newString(string);
+ callData->args[numCaptures + 1] = scope.engine->newString(string);
searchCallback->call(scope, callData);
result += string.midRef(lastEnd, matchStart - lastEnd);
@@ -632,23 +614,22 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
if (matchOffsets != _matchOffsets)
free(matchOffsets);
- return ctx->d()->engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
-ReturnedValue StringPrototype::method_search(CallContext *ctx)
+void StringPrototype::method_search(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- QString string = getThisString(ctx);
- scope.result = ctx->argument(0);
- if (scope.engine->hasException)
- return Encode::undefined();
+ QString string = getThisString(scope, callData);
+ scope.result = callData->argument(0);
+ CHECK_EXCEPTION();
+
Scoped<RegExpObject> regExp(scope, scope.result.as<RegExpObject>());
if (!regExp) {
ScopedCallData callData(scope, 1);
callData->args[0] = scope.result;
- ctx->d()->engine->regExpCtor()->construct(scope, callData);
- if (scope.engine->hasException)
- return Encode::undefined();
+ scope.engine->regExpCtor()->construct(scope, callData);
+ CHECK_EXCEPTION();
+
regExp = scope.result.as<RegExpObject>();
Q_ASSERT(regExp);
}
@@ -656,21 +637,21 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx)
uint* matchOffsets = (uint*)alloca(regExp->value()->captureCount() * 2 * sizeof(uint));
uint result = re->match(string, /*offset*/0, matchOffsets);
if (result == JSC::Yarr::offsetNoMatch)
- return Encode(-1);
- return Encode(result);
+ scope.result = Encode(-1);
+ else
+ scope.result = Encode(result);
}
-ReturnedValue StringPrototype::method_slice(CallContext *ctx)
+void StringPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- const QString text = getThisString(ctx);
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
+ const QString text = getThisString(scope, callData);
+ CHECK_EXCEPTION();
const double length = text.length();
- double start = ctx->argc() ? ctx->args()[0].toInteger() : 0;
- double end = (ctx->argc() < 2 || ctx->args()[1].isUndefined())
- ? length : ctx->args()[1].toInteger();
+ double start = callData->argc ? callData->args[0].toInteger() : 0;
+ double end = (callData->argc < 2 || callData->args[1].isUndefined())
+ ? length : callData->args[1].toInteger();
if (start < 0)
start = qMax(length + start, 0.);
@@ -686,40 +667,38 @@ ReturnedValue StringPrototype::method_slice(CallContext *ctx)
const int intEnd = int(end);
int count = qMax(0, intEnd - intStart);
- return ctx->d()->engine->newString(text.mid(intStart, count))->asReturnedValue();
+ scope.result = scope.engine->newString(text.mid(intStart, count));
}
-ReturnedValue StringPrototype::method_split(CallContext *ctx)
+void StringPrototype::method_split(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- QString text = getThisString(ctx);
- if (scope.engine->hasException)
- return Encode::undefined();
+ QString text = getThisString(scope, callData);
+ CHECK_EXCEPTION();
- ScopedValue separatorValue(scope, ctx->argument(0));
- ScopedValue limitValue(scope, ctx->argument(1));
+ ScopedValue separatorValue(scope, callData->argument(0));
+ ScopedValue limitValue(scope, callData->argument(1));
- ScopedArrayObject array(scope, ctx->d()->engine->newArrayObject());
+ ScopedArrayObject array(scope, scope.engine->newArrayObject());
if (separatorValue->isUndefined()) {
if (limitValue->isUndefined()) {
- ScopedString s(scope, ctx->d()->engine->newString(text));
+ ScopedString s(scope, scope.engine->newString(text));
array->push_back(s);
- return array.asReturnedValue();
+ RETURN_RESULT(array);
}
- return ctx->d()->engine->newString(text.left(limitValue->toInteger()))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(text.left(limitValue->toInteger())));
}
uint limit = limitValue->isUndefined() ? UINT_MAX : limitValue->toUInt32();
if (limit == 0)
- return array.asReturnedValue();
+ RETURN_RESULT(array);
Scoped<RegExpObject> re(scope, separatorValue);
if (re) {
if (re->value()->pattern->isEmpty()) {
re = (RegExpObject *)0;
- separatorValue = ctx->d()->engine->newString();
+ separatorValue = scope.engine->newString();
}
}
@@ -733,7 +712,7 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx)
if (result == JSC::Yarr::offsetNoMatch)
break;
- array->push_back((s = ctx->d()->engine->newString(text.mid(offset, matchOffsets[0] - offset))));
+ array->push_back((s = scope.engine->newString(text.mid(offset, matchOffsets[0] - offset))));
offset = qMax(offset + 1, matchOffsets[1]);
if (array->getLength() >= limit)
@@ -742,72 +721,70 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx)
for (int i = 1; i < re->value()->captureCount(); ++i) {
uint start = matchOffsets[i * 2];
uint end = matchOffsets[i * 2 + 1];
- array->push_back((s = ctx->d()->engine->newString(text.mid(start, end - start))));
+ array->push_back((s = scope.engine->newString(text.mid(start, end - start))));
if (array->getLength() >= limit)
break;
}
}
if (array->getLength() < limit)
- array->push_back((s = ctx->d()->engine->newString(text.mid(offset))));
+ array->push_back((s = scope.engine->newString(text.mid(offset))));
} else {
QString separator = separatorValue->toQString();
if (separator.isEmpty()) {
for (uint i = 0; i < qMin(limit, uint(text.length())); ++i)
- array->push_back((s = ctx->d()->engine->newString(text.mid(i, 1))));
- return array.asReturnedValue();
+ array->push_back((s = scope.engine->newString(text.mid(i, 1))));
+ RETURN_RESULT(array);
}
int start = 0;
int end;
while ((end = text.indexOf(separator, start)) != -1) {
- array->push_back((s = ctx->d()->engine->newString(text.mid(start, end - start))));
+ array->push_back((s = scope.engine->newString(text.mid(start, end - start))));
start = end + separator.size();
if (array->getLength() >= limit)
break;
}
if (array->getLength() < limit && start != -1)
- array->push_back((s = ctx->d()->engine->newString(text.mid(start))));
+ array->push_back((s = scope.engine->newString(text.mid(start))));
}
- return array.asReturnedValue();
+ RETURN_RESULT(array);
}
-ReturnedValue StringPrototype::method_startsWith(CallContext *context)
+void StringPrototype::method_startsWith(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
QString searchString;
- if (context->argc()) {
- if (context->args()[0].as<RegExpObject>())
- return context->engine()->throwTypeError();
- searchString = context->args()[0].toQString();
+ if (callData->argc) {
+ if (callData->args[0].as<RegExpObject>())
+ THROW_TYPE_ERROR();
+ searchString = callData->args[0].toQString();
}
int pos = 0;
- if (context->argc() > 1)
- pos = (int) context->args()[1].toInteger();
+ if (callData->argc > 1)
+ pos = (int) callData->args[1].toInteger();
if (pos == 0)
- return Encode(value.startsWith(searchString));
+ RETURN_RESULT(Encode(value.startsWith(searchString)));
QStringRef stringToSearch = value.midRef(pos);
- return Encode(stringToSearch.startsWith(searchString));
+ RETURN_RESULT(Encode(stringToSearch.startsWith(searchString)));
}
-ReturnedValue StringPrototype::method_substr(CallContext *context)
+void StringPrototype::method_substr(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- const QString value = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ const QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
double start = 0;
- if (context->argc() > 0)
- start = context->args()[0].toInteger();
+ if (callData->argc > 0)
+ start = callData->args[0].toInteger();
double length = +qInf();
- if (context->argc() > 1)
- length = context->args()[1].toInteger();
+ if (callData->argc > 1)
+ length = callData->args[1].toInteger();
double count = value.length();
if (start < 0)
@@ -817,24 +794,23 @@ ReturnedValue StringPrototype::method_substr(CallContext *context)
qint32 x = Primitive::toInt32(start);
qint32 y = Primitive::toInt32(length);
- return context->d()->engine->newString(value.mid(x, y))->asReturnedValue();
+ scope.result = scope.engine->newString(value.mid(x, y));
}
-ReturnedValue StringPrototype::method_substring(CallContext *context)
+void StringPrototype::method_substring(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
+
int length = value.length();
double start = 0;
double end = length;
- if (context->argc() > 0)
- start = context->args()[0].toInteger();
+ if (callData->argc > 0)
+ start = callData->args[0].toInteger();
- Scope scope(context);
- ScopedValue endValue(scope, context->argument(1));
+ ScopedValue endValue(scope, callData->argument(1));
if (!endValue->isUndefined())
end = endValue->toInteger();
@@ -858,51 +834,50 @@ ReturnedValue StringPrototype::method_substring(CallContext *context)
qint32 x = (int)start;
qint32 y = (int)(end - start);
- return context->d()->engine->newString(value.mid(x, y))->asReturnedValue();
+ scope.result = scope.engine->newString(value.mid(x, y));
}
-ReturnedValue StringPrototype::method_toLowerCase(CallContext *ctx)
+void StringPrototype::method_toLowerCase(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(ctx);
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
- return ctx->d()->engine->newString(value.toLower())->asReturnedValue();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
+
+ scope.result = scope.engine->newString(value.toLower());
}
-ReturnedValue StringPrototype::method_toLocaleLowerCase(CallContext *ctx)
+void StringPrototype::method_toLocaleLowerCase(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- return method_toLowerCase(ctx);
+ method_toLowerCase(b, scope, callData);
}
-ReturnedValue StringPrototype::method_toUpperCase(CallContext *ctx)
+void StringPrototype::method_toUpperCase(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(ctx);
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
- return ctx->d()->engine->newString(value.toUpper())->asReturnedValue();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
+
+ scope.result = scope.engine->newString(value.toUpper());
}
-ReturnedValue StringPrototype::method_toLocaleUpperCase(CallContext *ctx)
+void StringPrototype::method_toLocaleUpperCase(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- return method_toUpperCase(ctx);
+ return method_toUpperCase(b, scope, callData);
}
-ReturnedValue StringPrototype::method_fromCharCode(CallContext *context)
+void StringPrototype::method_fromCharCode(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString str(context->argc(), Qt::Uninitialized);
+ QString str(callData->argc, Qt::Uninitialized);
QChar *ch = str.data();
- for (int i = 0; i < context->argc(); ++i) {
- *ch = QChar(context->args()[i].toUInt16());
+ for (int i = 0; i < callData->argc; ++i) {
+ *ch = QChar(callData->args[i].toUInt16());
++ch;
}
- return context->d()->engine->newString(str)->asReturnedValue();
+ scope.result = scope.engine->newString(str);
}
-ReturnedValue StringPrototype::method_trim(CallContext *ctx)
+void StringPrototype::method_trim(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString s = getThisString(ctx);
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
+ QString s = getThisString(scope, callData);
+ CHECK_EXCEPTION();
const QChar *chars = s.constData();
int start, end;
@@ -915,5 +890,5 @@ ReturnedValue StringPrototype::method_trim(CallContext *ctx)
break;
}
- return ctx->d()->engine->newString(QString(chars + start, end - start + 1))->asReturnedValue();
+ scope.result = scope.engine->newString(QString(chars + start, end - start + 1));
}
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index b9f9d44fe8..0ee7a6ece9 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -111,29 +111,29 @@ struct StringPrototype: StringObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_toString(CallContext *context);
- static ReturnedValue method_charAt(CallContext *context);
- static ReturnedValue method_charCodeAt(CallContext *context);
- static ReturnedValue method_concat(CallContext *context);
- static ReturnedValue method_endsWith(CallContext *ctx);
- static ReturnedValue method_indexOf(CallContext *context);
- static ReturnedValue method_includes(CallContext *context);
- static ReturnedValue method_lastIndexOf(CallContext *context);
- static ReturnedValue method_localeCompare(CallContext *context);
- static ReturnedValue method_match(CallContext *context);
- static ReturnedValue method_replace(CallContext *ctx);
- static ReturnedValue method_search(CallContext *ctx);
- static ReturnedValue method_slice(CallContext *ctx);
- static ReturnedValue method_split(CallContext *ctx);
- static ReturnedValue method_startsWith(CallContext *ctx);
- static ReturnedValue method_substr(CallContext *context);
- static ReturnedValue method_substring(CallContext *context);
- static ReturnedValue method_toLowerCase(CallContext *ctx);
- static ReturnedValue method_toLocaleLowerCase(CallContext *ctx);
- static ReturnedValue method_toUpperCase(CallContext *ctx);
- static ReturnedValue method_toLocaleUpperCase(CallContext *ctx);
- static ReturnedValue method_fromCharCode(CallContext *context);
- static ReturnedValue method_trim(CallContext *ctx);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_charAt(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_charCodeAt(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_concat(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_endsWith(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_includes(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_match(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_replace(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_search(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_split(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_startsWith(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_substr(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_substring(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLowerCase(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleLowerCase(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toUpperCase(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleUpperCase(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_fromCharCode(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_trim(const BuiltinFunction *, Scope &scope, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index 009c573bf8..cecd1e6958 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -438,79 +438,74 @@ void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor)
defineDefaultProperty(QStringLiteral("subarray"), method_subarray, 0);
}
-ReturnedValue TypedArrayPrototype::method_get_buffer(CallContext *ctx)
+void TypedArrayPrototype::method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<TypedArray> v(scope, ctx->thisObject());
+ Scoped<TypedArray> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->buffer->asReturnedValue());
+ scope.result = v->d()->buffer;
}
-ReturnedValue TypedArrayPrototype::method_get_byteLength(CallContext *ctx)
+void TypedArrayPrototype::method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<TypedArray> v(scope, ctx->thisObject());
+ Scoped<TypedArray> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->byteLength);
+ scope.result = Encode(v->d()->byteLength);
}
-ReturnedValue TypedArrayPrototype::method_get_byteOffset(CallContext *ctx)
+void TypedArrayPrototype::method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<TypedArray> v(scope, ctx->thisObject());
+ Scoped<TypedArray> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->byteOffset);
+ scope.result = Encode(v->d()->byteOffset);
}
-ReturnedValue TypedArrayPrototype::method_get_length(CallContext *ctx)
+void TypedArrayPrototype::method_get_length(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<TypedArray> v(scope, ctx->thisObject());
+ Scoped<TypedArray> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->byteLength/v->d()->type->bytesPerElement);
+ scope.result = Encode(v->d()->byteLength/v->d()->type->bytesPerElement);
}
-ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx)
+void TypedArrayPrototype::method_set(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<TypedArray> a(scope, ctx->thisObject());
+ Scoped<TypedArray> a(scope, callData->thisObject);
if (!a)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
Scoped<ArrayBuffer> buffer(scope, a->d()->buffer);
if (!buffer)
scope.engine->throwTypeError();
- double doffset = ctx->argc() >= 2 ? ctx->args()[1].toInteger() : 0;
+ double doffset = callData->argc >= 2 ? callData->args[1].toInteger() : 0;
if (scope.engine->hasException)
- return Encode::undefined();
+ RETURN_UNDEFINED();
if (doffset < 0 || doffset >= UINT_MAX)
- return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"));
+ RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
uint offset = (uint)doffset;
uint elementSize = a->d()->type->bytesPerElement;
- Scoped<TypedArray> srcTypedArray(scope, ctx->args()[0]);
+ Scoped<TypedArray> srcTypedArray(scope, callData->args[0]);
if (!srcTypedArray) {
// src is a regular object
- ScopedObject o(scope, ctx->args()[0].toObject(scope.engine));
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
if (scope.engine->hasException || !o)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
double len = ScopedValue(scope, o->get(scope.engine->id_length()))->toNumber();
uint l = (uint)len;
if (scope.engine->hasException || l != len)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
if (offset + l > a->length())
- return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"));
+ RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
uint idx = 0;
char *b = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize;
@@ -519,28 +514,28 @@ ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx)
val = o->getIndexed(idx);
a->d()->type->write(scope.engine, b, 0, val);
if (scope.engine->hasException)
- return Encode::undefined();
+ RETURN_UNDEFINED();
++idx;
b += elementSize;
}
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
// src is a typed array
Scoped<ArrayBuffer> srcBuffer(scope, srcTypedArray->d()->buffer);
if (!srcBuffer)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
uint l = srcTypedArray->length();
if (offset + l > a->length())
- return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"));
+ RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
char *dest = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize;
const char *src = srcBuffer->d()->data->data() + srcTypedArray->d()->byteOffset;
if (srcTypedArray->d()->type == a->d()->type) {
// same type of typed arrays, use memmove (as srcbuffer and buffer could be the same)
memmove(dest, src, srcTypedArray->d()->byteLength);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
char *srcCopy = 0;
@@ -564,28 +559,27 @@ ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx)
if (srcCopy)
delete [] srcCopy;
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx)
+void TypedArrayPrototype::method_subarray(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<TypedArray> a(scope, ctx->thisObject());
+ Scoped<TypedArray> a(scope, callData->thisObject);
if (!a)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
Scoped<ArrayBuffer> buffer(scope, a->d()->buffer);
if (!buffer)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
int len = a->length();
- double b = ctx->argc() > 0 ? ctx->args()[0].toInteger() : 0;
+ double b = callData->argc > 0 ? callData->args[0].toInteger() : 0;
if (b < 0)
b = len + b;
uint begin = (uint)qBound(0., b, (double)len);
- double e = ctx->argc() < 2 || ctx->args()[1].isUndefined() ? len : ctx->args()[1].toInteger();
+ double e = callData->argc < 2 || callData->args[1].isUndefined() ? len : callData->args[1].toInteger();
if (e < 0)
e = len + e;
uint end = (uint)qBound(0., e, (double)len);
@@ -593,18 +587,17 @@ ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx)
end = begin;
if (scope.engine->hasException)
- return Encode::undefined();
+ RETURN_UNDEFINED();
int newLen = end - begin;
ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor()));
if (!constructor)
- return scope.engine->throwTypeError();
-
- ScopedCallData callData(scope, 3);
- callData->args[0] = buffer;
- callData->args[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement);
- callData->args[2] = Encode(newLen);
- constructor->construct(scope, callData);
- return scope.result.asReturnedValue();
+ THROW_TYPE_ERROR();
+
+ ScopedCallData cData(scope, 3);
+ cData->args[0] = buffer;
+ cData->args[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement);
+ cData->args[2] = Encode(newLen);
+ constructor->construct(scope, cData);
}
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 0112d2e4a1..eefed2db4b 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -151,13 +151,13 @@ struct TypedArrayPrototype : Object
void init(ExecutionEngine *engine, TypedArrayCtor *ctor);
- static ReturnedValue method_get_buffer(CallContext *ctx);
- static ReturnedValue method_get_byteLength(CallContext *ctx);
- static ReturnedValue method_get_byteOffset(CallContext *ctx);
- static ReturnedValue method_get_length(CallContext *ctx);
+ static void method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_length(const BuiltinFunction *, Scope &scope, CallData *callData);
- static ReturnedValue method_set(CallContext *ctx);
- static ReturnedValue method_subarray(CallContext *ctx);
+ static void method_set(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_subarray(const BuiltinFunction *, Scope &scope, CallData *callData);
};
inline void
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 816b8fb11b..4ff0565f9b 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -254,34 +254,47 @@ public:
Q_ASSERT(isDouble()); return Double_Type;
}
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
+ // Shared between 32-bit and 64-bit encoding
+ enum {
+ Tag_Shift = 32
+ };
+
+ // Used only by 64-bit encoding
+ static const quint64 NaNEncodeMask = 0xfffc000000000000ll;
+ enum {
+ IsDouble_Shift = 64-14,
+ IsManagedOrUndefined_Shift = 64-15,
+ IsIntegerConvertible_Shift = 64-16,
+ IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift,
+ Managed_Type_Internal_64 = 0
+ };
+ static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
+
+ // Used only by 32-bit encoding
enum Masks {
SilentNaNBit = 0x00040000,
- NaN_Mask = 0x7ff80000,
NotDouble_Mask = 0x7ffa0000,
- Immediate_Mask = NotDouble_Mask | 0x00020000u | SilentNaNBit,
- Tag_Shift = 32
};
+ static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
enum {
- Managed_Type_Internal = NotDouble_Mask
+ Managed_Type_Internal_32 = NotDouble_Mask
};
-#else
- static const quint64 NaNEncodeMask = 0xfffc000000000000ll;
- static const quint64 Immediate_Mask = 0x00020000u; // bit 49
- enum Masks {
- NaN_Mask = 0x7ff80000,
+#ifdef QV4_USE_64_BIT_VALUE_ENCODING
+ enum {
+ Managed_Type_Internal = Managed_Type_Internal_64
};
+ static const quint64 Immediate_Mask = Immediate_Mask_64;
+#else
enum {
- IsDouble_Shift = 64-14,
- IsManagedOrUndefined_Shift = 64-15,
- IsIntegerConvertible_Shift = 64-16,
- Tag_Shift = 32,
- IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift,
- Managed_Type_Internal = 0
+ Managed_Type_Internal = Managed_Type_Internal_32
};
+ static const quint64 Immediate_Mask = Immediate_Mask_32;
#endif
+ enum {
+ NaN_Mask = 0x7ff80000,
+ };
enum ValueTypeInternal {
Empty_Type_Internal = Immediate_Mask | 0,
ConvertibleToInt = Immediate_Mask | 0x10000u, // bit 48
@@ -544,7 +557,7 @@ inline bool Value::asArrayIndex(uint &idx) const
}
double d = doubleValue();
idx = (uint)d;
- return (idx == d);
+ return (idx == d && idx != UINT_MAX);
}
#endif
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index 455a7ccb65..5cab4c5386 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -113,67 +113,68 @@ void VariantPrototype::init()
defineDefaultProperty(engine()->id_toString(), method_toString, 0);
}
-QV4::ReturnedValue VariantPrototype::method_preserve(CallContext *ctx)
+void VariantPrototype::method_preserve(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>());
+ Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>());
if (o && o->d()->isScarce())
o->d()->addVmePropertyReference();
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-QV4::ReturnedValue VariantPrototype::method_destroy(CallContext *ctx)
+void VariantPrototype::method_destroy(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>());
+ Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>());
if (o) {
if (o->d()->isScarce())
o->d()->addVmePropertyReference();
o->d()->data() = QVariant();
}
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-QV4::ReturnedValue VariantPrototype::method_toString(CallContext *ctx)
+void VariantPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>());
+ Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>());
if (!o)
- return Encode::undefined();
+ RETURN_UNDEFINED();
QString result = o->d()->data().toString();
if (result.isEmpty() && !o->d()->data().canConvert(QVariant::String)) {
result = QLatin1String("QVariant(")
+ QLatin1String(o->d()->data().typeName())
+ QLatin1Char(')');
}
- return Encode(ctx->d()->engine->newString(result));
+ scope.result = scope.engine->newString(result);
}
-QV4::ReturnedValue VariantPrototype::method_valueOf(CallContext *ctx)
+void VariantPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>());
+ Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>());
if (o) {
QVariant v = o->d()->data();
switch (v.type()) {
case QVariant::Invalid:
- return Encode::undefined();
+ scope.result = Encode::undefined();
+ return;
case QVariant::String:
- return Encode(ctx->d()->engine->newString(v.toString()));
+ scope.result = scope.engine->newString(v.toString());
+ return;
case QVariant::Int:
- return Encode(v.toInt());
+ scope.result = Encode(v.toInt());
+ return;
case QVariant::Double:
case QVariant::UInt:
- return Encode(v.toDouble());
+ scope.result = Encode(v.toDouble());
+ return;
case QVariant::Bool:
- return Encode(v.toBool());
+ scope.result = Encode(v.toBool());
+ return;
default:
if (QMetaType::typeFlags(v.userType()) & QMetaType::IsEnumeration)
- return Encode(v.toInt());
+ RETURN_RESULT(Encode(v.toInt()));
break;
}
}
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h
index 9a04069c12..ef51b6632d 100644
--- a/src/qml/jsruntime/qv4variantobject_p.h
+++ b/src/qml/jsruntime/qv4variantobject_p.h
@@ -107,10 +107,10 @@ struct VariantPrototype : VariantObject
public:
void init();
- static ReturnedValue method_preserve(CallContext *ctx);
- static ReturnedValue method_destroy(CallContext *ctx);
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_valueOf(CallContext *ctx);
+ static void method_preserve(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_destroy(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 622359a7d9..b9183313cd 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -347,6 +347,10 @@ Param traceParam(const Param &param)
goto catchException; \
VALUE(param) = tmp; \
}
+// qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro
+#ifdef CHECK_EXCEPTION
+#undef CHECK_EXCEPTION
+#endif
#define CHECK_EXCEPTION \
if (engine->hasException) \
goto catchException
diff --git a/src/qml/memory/memory.pri b/src/qml/memory/memory.pri
index 04b7566ccc..38fadbf23f 100644
--- a/src/qml/memory/memory.pri
+++ b/src/qml/memory/memory.pri
@@ -6,8 +6,8 @@ SOURCES += \
$$PWD/qv4mm.cpp \
HEADERS += \
- $$PWD/qv4mm_p.h
-
+ $$PWD/qv4mm_p.h \
+ $$PWD/qv4mmdefs_p.h
}
HEADERS += \
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index 5a3797f397..8285ef4de7 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -52,6 +52,7 @@
#include <QtCore/QString>
#include <private/qv4global_p.h>
+#include <private/qv4mmdefs_p.h>
#include <QSharedPointer>
// To check if Heap::Base::init is called (meaning, all subclasses did their init and called their
@@ -90,43 +91,31 @@ namespace Heap {
struct Q_QML_EXPORT Base {
void *operator new(size_t) = delete;
- quintptr mm_data; // vtable and markbit
+ const VTable *vt;
inline ReturnedValue asReturnedValue() const;
inline void mark(QV4::ExecutionEngine *engine);
- enum {
- MarkBit = 0x1,
- NotInUse = 0x2,
- PointerMask = ~0x3
- };
-
- void setVtable(const VTable *v) {
- Q_ASSERT(!(mm_data & MarkBit));
- mm_data = reinterpret_cast<quintptr>(v);
- }
- VTable *vtable() const {
- return reinterpret_cast<VTable *>(mm_data & PointerMask);
- }
+ void setVtable(const VTable *v) { vt = v; }
+ const VTable *vtable() const { return vt; }
inline bool isMarked() const {
- return mm_data & MarkBit;
+ const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
+ Chunk *c = h->chunk();
+ Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
+ return Chunk::testBit(c->blackBitmap, h - c->realBase());
}
inline void setMarkBit() {
- mm_data |= MarkBit;
- }
- inline void clearMarkBit() {
- mm_data &= ~MarkBit;
+ const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
+ Chunk *c = h->chunk();
+ Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
+ return Chunk::setBit(c->blackBitmap, h - c->realBase());
}
inline bool inUse() const {
- return !(mm_data & NotInUse);
- }
-
- Base *nextFree() {
- return reinterpret_cast<Base *>(mm_data & PointerMask);
- }
- void setNextFree(Base *m) {
- mm_data = (reinterpret_cast<quintptr>(m) | NotInUse);
+ const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
+ Chunk *c = h->chunk();
+ Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
+ return Chunk::testBit(c->objectBitmap, h - c->realBase());
}
void *operator new(size_t, Managed *m) { return m; }
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 51eb82059a..6330ef6038 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -42,8 +42,12 @@
#include "qv4objectproto_p.h"
#include "qv4mm_p.h"
#include "qv4qobjectwrapper_p.h"
+#include <QtCore/qalgorithms.h>
+#include <QtCore/private/qnumeric_p.h>
#include <qqmlengine.h>
+#include "PageReservation.h"
#include "PageAllocation.h"
+#include "PageAllocationAligned.h"
#include "StdLibExtras.h"
#include <QElapsedTimer>
@@ -56,6 +60,14 @@
#include "qv4alloca_p.h"
#include "qv4profiling_p.h"
+#define MM_DEBUG 0
+
+#if MM_DEBUG
+#define DEBUG qDebug() << "MM:"
+#else
+#define DEBUG if (1) ; else qDebug() << "MM:"
+#endif
+
#ifdef V4_USE_VALGRIND
#include <valgrind/valgrind.h>
#include <valgrind/memcheck.h>
@@ -79,310 +91,616 @@ using namespace WTF;
QT_BEGIN_NAMESPACE
-static uint maxShiftValue()
-{
- static uint result = 0;
- if (!result) {
- result = 6;
- if (Q_UNLIKELY(qEnvironmentVariableIsSet(QV4_MM_MAXBLOCK_SHIFT))) {
- bool ok;
- const uint overrideValue = qgetenv(QV4_MM_MAXBLOCK_SHIFT).toUInt(&ok);
- if (ok && overrideValue <= 11 && overrideValue > 0)
- result = overrideValue;
+namespace QV4 {
+
+enum {
+ MinSlotsGCLimit = QV4::Chunk::AvailableSlots*16,
+ GCOverallocation = 200 /* Max overallocation by the GC in % */
+};
+
+struct MemorySegment {
+ enum {
+ NumChunks = 8*sizeof(quint64),
+ SegmentSize = NumChunks*Chunk::ChunkSize,
+ };
+
+ MemorySegment(size_t size)
+ {
+ size += Chunk::ChunkSize; // make sure we can get enough 64k aligment memory
+ if (size < SegmentSize)
+ size = SegmentSize;
+
+ pageReservation = PageReservation::reserve(size, OSAllocator::JSGCHeapPages);
+ base = reinterpret_cast<Chunk *>((reinterpret_cast<quintptr>(pageReservation.base()) + Chunk::ChunkSize - 1) & ~(Chunk::ChunkSize - 1));
+ nChunks = NumChunks;
+ if (base != pageReservation.base())
+ --nChunks;
+ }
+ MemorySegment(MemorySegment &&other) {
+ qSwap(pageReservation, other.pageReservation);
+ qSwap(base, other.base);
+ qSwap(nChunks, other.nChunks);
+ qSwap(allocatedMap, other.allocatedMap);
+ }
+
+ ~MemorySegment() {
+ if (base)
+ pageReservation.deallocate();
+ }
+
+ void setBit(size_t index) {
+ Q_ASSERT(index < nChunks);
+ quint64 bit = static_cast<quint64>(1) << index;
+// qDebug() << " setBit" << hex << index << (index & (Bits - 1)) << bit;
+ allocatedMap |= bit;
+ }
+ void clearBit(size_t index) {
+ Q_ASSERT(index < nChunks);
+ quint64 bit = static_cast<quint64>(1) << index;
+// qDebug() << " setBit" << hex << index << (index & (Bits - 1)) << bit;
+ allocatedMap &= ~bit;
+ }
+ bool testBit(size_t index) const {
+ Q_ASSERT(index < nChunks);
+ quint64 bit = static_cast<quint64>(1) << index;
+ return (allocatedMap & bit);
+ }
+
+ Chunk *allocate(size_t size);
+ void free(Chunk *chunk, size_t size) {
+ DEBUG << "freeing chunk" << chunk;
+ size_t index = static_cast<size_t>(chunk - base);
+ size_t end = index + (size - 1)/Chunk::ChunkSize + 1;
+ while (index < end) {
+ Q_ASSERT(testBit(index));
+ clearBit(index);
+ ++index;
}
+
+ size_t pageSize = WTF::pageSize();
+ size = (size + pageSize - 1) & ~(pageSize - 1);
+ pageReservation.decommit(chunk, size);
+ }
+
+ bool contains(Chunk *c) const {
+ return c >= base && c < base + nChunks;
}
- return result;
-}
-static std::size_t maxChunkSizeValue()
+ PageReservation pageReservation;
+ Chunk *base = 0;
+ quint64 allocatedMap = 0;
+ uint nChunks = 0;
+};
+
+Chunk *MemorySegment::allocate(size_t size)
{
- static std::size_t result = 0;
- if (!result) {
- result = 32 * 1024;
- if (Q_UNLIKELY(qEnvironmentVariableIsSet(QV4_MM_MAX_CHUNK_SIZE))) {
- bool ok;
- const std::size_t overrideValue = qgetenv(QV4_MM_MAX_CHUNK_SIZE).toUInt(&ok);
- if (ok)
- result = overrideValue;
+ size_t requiredChunks = (size + sizeof(Chunk) - 1)/sizeof(Chunk);
+ uint sequence = 0;
+ Chunk *candidate = 0;
+ for (uint i = 0; i < nChunks; ++i) {
+ if (!testBit(i)) {
+ if (!candidate)
+ candidate = base + i;
+ ++sequence;
+ } else {
+ candidate = 0;
+ sequence = 0;
+ }
+ if (sequence == requiredChunks) {
+ pageReservation.commit(candidate, size);
+ for (uint i = 0; i < requiredChunks; ++i)
+ setBit(candidate - base + i);
+ DEBUG << "allocated chunk " << candidate << hex << size;
+ return candidate;
}
}
- return result;
+ return 0;
}
-using namespace QV4;
-
-struct MemoryManager::Data
-{
- const size_t pageSize;
-
- struct ChunkHeader {
- Heap::Base freeItems;
- ChunkHeader *nextNonFull;
- char *itemStart;
- char *itemEnd;
- unsigned itemSize;
- };
+struct ChunkAllocator {
+ ChunkAllocator() {}
- ExecutionEngine *engine;
+ size_t requiredChunkSize(size_t size) {
+ size += Chunk::HeaderSize; // space required for the Chunk header
+ size_t pageSize = WTF::pageSize();
+ size = (size + pageSize - 1) & ~(pageSize - 1); // align to page sizes
+ if (size < Chunk::ChunkSize)
+ size = Chunk::ChunkSize;
+ return size;
+ }
- std::size_t maxChunkSize;
- std::vector<PageAllocation> heapChunks;
- std::size_t unmanagedHeapSize; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
- std::size_t unmanagedHeapSizeGCLimit;
+ Chunk *allocate(size_t size = 0);
+ void free(Chunk *chunk, size_t size = 0);
- struct LargeItem {
- LargeItem *next;
- size_t size;
- void *data;
+ std::vector<MemorySegment> memorySegments;
+};
- Heap::Base *heapObject() {
- return reinterpret_cast<Heap::Base *>(&data);
+Chunk *ChunkAllocator::allocate(size_t size)
+{
+ size = requiredChunkSize(size);
+ for (auto &m : memorySegments) {
+ if (~m.allocatedMap) {
+ Chunk *c = m.allocate(size);
+ if (c)
+ return c;
}
- };
-
- LargeItem *largeItems;
- std::size_t totalLargeItemsAllocated;
+ }
- enum { MaxItemSize = 512 };
- ChunkHeader *nonFullChunks[MaxItemSize/16];
- uint nChunks[MaxItemSize/16];
- uint availableItems[MaxItemSize/16];
- uint allocCount[MaxItemSize/16];
- int totalItems;
- int totalAlloc;
- uint maxShift;
+ // allocate a new segment
+ memorySegments.push_back(MemorySegment(size));
+ Chunk *c = memorySegments.back().allocate(size);
+ Q_ASSERT(c);
+ return c;
+}
- bool gcBlocked;
- bool aggressiveGC;
- bool gcStats;
- bool unused; // suppress padding warning
+void ChunkAllocator::free(Chunk *chunk, size_t size)
+{
+ size = requiredChunkSize(size);
+ for (auto &m : memorySegments) {
+ if (m.contains(chunk)) {
+ m.free(chunk, size);
+ return;
+ }
+ }
+ Q_ASSERT(false);
+}
- // statistics:
-#ifdef DETAILED_MM_STATS
- QVector<unsigned> allocSizeCounters;
-#endif // DETAILED_MM_STATS
- Data()
- : pageSize(WTF::pageSize())
- , engine(0)
- , maxChunkSize(maxChunkSizeValue())
- , unmanagedHeapSize(0)
- , unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT)
- , largeItems(0)
- , totalLargeItemsAllocated(0)
- , totalItems(0)
- , totalAlloc(0)
- , maxShift(maxShiftValue())
- , gcBlocked(false)
- , aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
- , gcStats(!qEnvironmentVariableIsEmpty(QV4_MM_STATS))
- {
- memset(nonFullChunks, 0, sizeof(nonFullChunks));
- memset(nChunks, 0, sizeof(nChunks));
- memset(availableItems, 0, sizeof(availableItems));
- memset(allocCount, 0, sizeof(allocCount));
+void Chunk::sweep()
+{
+ // DEBUG << "sweeping chunk" << this << (*freeList);
+ HeapItem *o = realBase();
+ for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) {
+ Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects
+ quintptr toFree = objectBitmap[i] ^ blackBitmap[i];
+ Q_ASSERT((toFree & objectBitmap[i]) == toFree); // check all black objects are marked as being used
+ quintptr e = extendsBitmap[i];
+ // DEBUG << hex << " index=" << i << toFree;
+ while (toFree) {
+ uint index = qCountTrailingZeroBits(toFree);
+ quintptr bit = (static_cast<quintptr>(1) << index);
+
+ toFree ^= bit; // mask out freed slot
+ // DEBUG << " index" << hex << index << toFree;
+
+ // remove all extends slots that have been freed
+ // this is a bit of bit trickery.
+ quintptr mask = (bit << 1) - 1; // create a mask of 1's to the right of and up to the current bit
+ quintptr objmask = e | mask; // or'ing mask with e gives all ones until the end of the current object
+ quintptr result = objmask + 1;
+ Q_ASSERT(qCountTrailingZeroBits(result) - index != 0); // ensure we freed something
+ result |= mask; // ensure we don't clear stuff to the right of the current object
+ e &= result;
+
+ HeapItem *itemToFree = o + index;
+ Heap::Base *b = *itemToFree;
+ if (b->vtable()->destroy) {
+ b->vtable()->destroy(b);
+ b->_checkIsDestroyed();
+ }
+ }
+ objectBitmap[i] = blackBitmap[i];
+ blackBitmap[i] = 0;
+ extendsBitmap[i] = e;
+ o += Chunk::Bits;
}
+ // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots.";
+}
- ~Data()
- {
- for (std::vector<PageAllocation>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) {
- Q_V4_PROFILE_DEALLOC(engine, i->size(), Profiling::HeapPage);
- i->deallocate();
+void Chunk::freeAll()
+{
+ // DEBUG << "sweeping chunk" << this << (*freeList);
+ HeapItem *o = realBase();
+ for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) {
+ quintptr toFree = objectBitmap[i];
+ quintptr e = extendsBitmap[i];
+ // DEBUG << hex << " index=" << i << toFree;
+ while (toFree) {
+ uint index = qCountTrailingZeroBits(toFree);
+ quintptr bit = (static_cast<quintptr>(1) << index);
+
+ toFree ^= bit; // mask out freed slot
+ // DEBUG << " index" << hex << index << toFree;
+
+ // remove all extends slots that have been freed
+ // this is a bit of bit trickery.
+ quintptr mask = (bit << 1) - 1; // create a mask of 1's to the right of and up to the current bit
+ quintptr objmask = e | mask; // or'ing mask with e gives all ones until the end of the current object
+ quintptr result = objmask + 1;
+ Q_ASSERT(qCountTrailingZeroBits(result) - index != 0); // ensure we freed something
+ result |= mask; // ensure we don't clear stuff to the right of the current object
+ e &= result;
+
+ HeapItem *itemToFree = o + index;
+ Heap::Base *b = *itemToFree;
+ if (b->vtable()->destroy) {
+ b->vtable()->destroy(b);
+ b->_checkIsDestroyed();
+ }
}
+ objectBitmap[i] = 0;
+ blackBitmap[i] = 0;
+ extendsBitmap[i] = e;
+ o += Chunk::Bits;
}
-};
-
-namespace {
+ // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots.";
+}
-bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, ExecutionEngine *engine)
+void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
{
- bool isEmpty = true;
- Heap::Base *tail = &header->freeItems;
-// qDebug("chunkStart @ %p, size=%x, pos=%x", header->itemStart, header->itemSize, header->itemSize>>4);
-#ifdef V4_USE_VALGRIND
- VALGRIND_DISABLE_ERROR_REPORTING;
+ HeapItem *base = realBase();
+#if QT_POINTER_SIZE == 8
+ const int start = 0;
+#else
+ const int start = 1;
#endif
- for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
- Heap::Base *m = reinterpret_cast<Heap::Base *>(item);
-// qDebug("chunk @ %p, in use: %s, mark bit: %s",
-// item, (m->inUse() ? "yes" : "no"), (m->isMarked() ? "true" : "false"));
-
- Q_ASSERT(qintptr(item) % 16 == 0);
-
- if (m->isMarked()) {
- Q_ASSERT(m->inUse());
- m->clearMarkBit();
- isEmpty = false;
- ++(*itemsInUse);
- } else {
- if (m->inUse()) {
-// qDebug() << "-- collecting it." << m << tail << m->nextFree();
-#ifdef V4_USE_VALGRIND
- VALGRIND_ENABLE_ERROR_REPORTING;
+ for (int i = start; i < EntriesInBitmap; ++i) {
+ quintptr usedSlots = (objectBitmap[i]|extendsBitmap[i]);
+#if QT_POINTER_SIZE == 8
+ if (!i)
+ usedSlots |= (static_cast<quintptr>(1) << (HeaderSize/SlotSize)) - 1;
#endif
- if (m->vtable()->destroy) {
- m->vtable()->destroy(m);
- m->_checkIsDestroyed();
- }
+ uint index = qCountTrailingZeroBits(usedSlots + 1);
+ if (index == Bits)
+ continue;
+ uint freeStart = i*Bits + index;
+ usedSlots &= ~((static_cast<quintptr>(1) << index) - 1);
+ while (i < EntriesInBitmap && !usedSlots) {
+ ++i;
+ usedSlots = (objectBitmap[i]|extendsBitmap[i]);
+ }
+ if (i == EntriesInBitmap)
+ usedSlots = 1;
+ HeapItem *freeItem = base + freeStart;
+
+ uint freeEnd = i*Bits + qCountTrailingZeroBits(usedSlots);
+ uint nSlots = freeEnd - freeStart;
+ Q_ASSERT(freeEnd > freeStart && freeEnd <= NumSlots);
+ freeItem->freeData.availableSlots = nSlots;
+ uint bin = qMin(nBins - 1, nSlots);
+ freeItem->freeData.next = bins[bin];
+ bins[bin] = freeItem;
+ // DEBUG << "binnig item" << freeItem << nSlots << bin << freeItem->freeData.availableSlots;
+ }
+}
- memset(m, 0, sizeof(Heap::Base));
-#ifdef V4_USE_VALGRIND
- VALGRIND_DISABLE_ERROR_REPORTING;
- VALGRIND_MEMPOOL_FREE(engine->memoryManager, m);
+
+template<typename T>
+StackAllocator<T>::StackAllocator(ChunkAllocator *chunkAlloc)
+ : chunkAllocator(chunkAlloc)
+{
+ chunks.push_back(chunkAllocator->allocate());
+ firstInChunk = chunks.back()->first();
+ nextFree = firstInChunk;
+ lastInChunk = firstInChunk + (Chunk::AvailableSlots - 1)/requiredSlots*requiredSlots;
+}
+
+template<typename T>
+void StackAllocator<T>::freeAll()
+{
+ for (auto c : chunks)
+ chunkAllocator->free(c);
+}
+
+template<typename T>
+void StackAllocator<T>::nextChunk() {
+ Q_ASSERT(nextFree == lastInChunk);
+ ++currentChunk;
+ if (currentChunk >= chunks.size()) {
+ Chunk *newChunk = chunkAllocator->allocate();
+ chunks.push_back(newChunk);
+ }
+ firstInChunk = chunks.at(currentChunk)->first();
+ nextFree = firstInChunk;
+ lastInChunk = firstInChunk + (Chunk::AvailableSlots - 1)/requiredSlots*requiredSlots;
+}
+
+template<typename T>
+void QV4::StackAllocator<T>::prevChunk() {
+ Q_ASSERT(nextFree == firstInChunk);
+ Q_ASSERT(chunks.at(currentChunk) == nextFree->chunk());
+ Q_ASSERT(currentChunk > 0);
+ --currentChunk;
+ firstInChunk = chunks.at(currentChunk)->first();
+ lastInChunk = firstInChunk + (Chunk::AvailableSlots - 1)/requiredSlots*requiredSlots;
+ nextFree = lastInChunk;
+}
+
+template struct StackAllocator<Heap::CallContext>;
+
+
+HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
+ Q_ASSERT((size % Chunk::SlotSize) == 0);
+ size_t slotsRequired = size >> Chunk::SlotSizeShift;
+#if MM_DEBUG
+ ++allocations[bin];
#endif
-#ifdef V4_USE_HEAPTRACK
- heaptrack_report_free(m);
+
+ HeapItem **last;
+
+ HeapItem *m;
+
+ if (slotsRequired < NumBins - 1) {
+ m = freeBins[slotsRequired];
+ if (m) {
+ freeBins[slotsRequired] = m->freeData.next;
+ goto done;
+ }
+ }
+#if 0
+ for (uint b = bin + 1; b < NumBins - 1; ++b) {
+ if ((m = freeBins[b])) {
+ Q_ASSERT(binForSlots(m->freeData.availableSlots) == b);
+ freeBins[b] = m->freeData.next;
+ // DEBUG << "looking for empty bin" << bin << "size" << size << "found" << b;
+ uint remainingSlots = m->freeData.availableSlots - slotsRequired;
+ // DEBUG << "found free slots of size" << m->freeData.availableSlots << m << "remaining" << remainingSlots;
+ if (remainingSlots < 2) {
+ // avoid too much fragmentation and rather mark the memory as used
+ size += remainingSlots*Chunk::SlotSize;
+ goto done;
+ }
+ HeapItem *remainder = m + slotsRequired;
+ remainder->freeData.availableSlots = remainingSlots;
+ uint binForRemainder = binForSlots(remainingSlots);
+ remainder->freeData.next = freeBins[binForRemainder];
+ freeBins[binForRemainder] = remainder;
+ goto done;
+ }
+ }
#endif
- Q_V4_PROFILE_DEALLOC(engine, header->itemSize, Profiling::SmallItem);
- ++(*itemsInUse);
+ if (nFree >= slotsRequired) {
+ // use bump allocation
+ Q_ASSERT(nextFree);
+ m = nextFree;
+ nextFree += slotsRequired;
+ nFree -= slotsRequired;
+ goto done;
+ }
+
+ // DEBUG << "No matching bin found for item" << size << bin;
+ // search last bin for a large enough item
+ last = &freeBins[NumBins - 1];
+ while ((m = *last)) {
+ if (m->freeData.availableSlots >= slotsRequired) {
+ *last = m->freeData.next; // take it out of the list
+
+ size_t remainingSlots = m->freeData.availableSlots - slotsRequired;
+ // DEBUG << "found large free slots of size" << m->freeData.availableSlots << m << "remaining" << remainingSlots;
+ if (remainingSlots < 2) {
+ // avoid too much fragmentation and rather mark the memory as used
+ size += remainingSlots*Chunk::SlotSize;
+ goto done;
}
- // Relink all free blocks to rewrite references to any released chunk.
- tail->setNextFree(m);
- tail = m;
+ HeapItem *remainder = m + slotsRequired;
+ if (remainingSlots >= 2*NumBins) {
+ if (nFree) {
+ size_t bin = binForSlots(nFree);
+ nextFree->freeData.next = freeBins[bin];
+ nextFree->freeData.availableSlots = nFree;
+ freeBins[bin] = nextFree;
+ }
+ nextFree = remainder;
+ nFree = remainingSlots;
+ } else {
+ remainder->freeData.availableSlots = remainingSlots;
+ size_t binForRemainder = binForSlots(remainingSlots);
+ remainder->freeData.next = freeBins[binForRemainder];
+ freeBins[binForRemainder] = remainder;
+ }
+ goto done;
}
+ last = &m->freeData.next;
}
- tail->setNextFree(0);
-#ifdef V4_USE_VALGRIND
- VALGRIND_ENABLE_ERROR_REPORTING;
+
+ if (!m) {
+ if (!forceAllocation)
+ return 0;
+ Chunk *newChunk = chunkAllocator->allocate();
+ chunks.push_back(newChunk);
+ nextFree = newChunk->first();
+ nFree = Chunk::AvailableSlots;
+ m = nextFree;
+ nextFree += slotsRequired;
+ nFree -= slotsRequired;
+ }
+
+done:
+ m->setAllocatedSlots(slotsRequired);
+ // DEBUG << " " << hex << m->chunk() << m->chunk()->objectBitmap[0] << m->chunk()->extendsBitmap[0] << (m - m->chunk()->realBase());
+ return m;
+}
+
+void BlockAllocator::sweep()
+{
+ nextFree = 0;
+ nFree = 0;
+ memset(freeBins, 0, sizeof(freeBins));
+
+// qDebug() << "BlockAlloc: sweep";
+ usedSlotsAfterLastSweep = 0;
+ for (auto c : chunks) {
+ c->sweep();
+ c->sortIntoBins(freeBins, NumBins);
+// qDebug() << "used slots in chunk" << c << ":" << c->nUsedSlots();
+ usedSlotsAfterLastSweep += c->nUsedSlots();
+ }
+}
+
+void BlockAllocator::freeAll()
+{
+ for (auto c : chunks) {
+ c->freeAll();
+ chunkAllocator->free(c);
+ }
+}
+
+#if MM_DEBUG
+void BlockAllocator::stats() {
+ DEBUG << "MM stats:";
+ QString s;
+ for (int i = 0; i < 10; ++i) {
+ uint c = 0;
+ HeapItem *item = freeBins[i];
+ while (item) {
+ ++c;
+ item = item->freeData.next;
+ }
+ s += QString::number(c) + QLatin1String(", ");
+ }
+ HeapItem *item = freeBins[NumBins - 1];
+ uint c = 0;
+ while (item) {
+ ++c;
+ item = item->freeData.next;
+ }
+ s += QLatin1String("..., ") + QString::number(c);
+ DEBUG << "bins:" << s;
+ QString a;
+ for (int i = 0; i < 10; ++i)
+ a += QString::number(allocations[i]) + QLatin1String(", ");
+ a += QLatin1String("..., ") + QString::number(allocations[NumBins - 1]);
+ DEBUG << "allocs:" << a;
+ memset(allocations, 0, sizeof(allocations));
+}
#endif
- return isEmpty;
+
+
+HeapItem *HugeItemAllocator::allocate(size_t size) {
+ Chunk *c = chunkAllocator->allocate(size);
+ chunks.push_back(HugeChunk{c, size});
+ Chunk::setBit(c->objectBitmap, c->first() - c->realBase());
+ return c->first();
+}
+
+static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocator::HugeChunk &c)
+{
+ HeapItem *itemToFree = c.chunk->first();
+ Heap::Base *b = *itemToFree;
+ if (b->vtable()->destroy) {
+ b->vtable()->destroy(b);
+ b->_checkIsDestroyed();
+ }
+ chunkAllocator->free(c.chunk, c.size);
+}
+
+void HugeItemAllocator::sweep() {
+ auto isBlack = [this] (const HugeChunk &c) {
+ bool b = c.chunk->first()->isBlack();
+ Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase());
+ if (!b)
+ freeHugeChunk(chunkAllocator, c);
+ return !b;
+ };
+
+ auto newEnd = std::remove_if(chunks.begin(), chunks.end(), isBlack);
+ chunks.erase(newEnd, chunks.end());
+}
+
+void HugeItemAllocator::freeAll()
+{
+ for (auto &c : chunks) {
+ freeHugeChunk(chunkAllocator, c);
+ }
}
-} // namespace
MemoryManager::MemoryManager(ExecutionEngine *engine)
: engine(engine)
- , m_d(new Data)
+ , chunkAllocator(new ChunkAllocator)
+ , stackAllocator(chunkAllocator)
+ , blockAllocator(chunkAllocator)
+ , hugeItemAllocator(chunkAllocator)
, m_persistentValues(new PersistentValueStorage(engine))
, m_weakValues(new PersistentValueStorage(engine))
+ , unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT)
+ , aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
+ , gcStats(!qEnvironmentVariableIsEmpty(QV4_MM_STATS))
{
#ifdef V4_USE_VALGRIND
VALGRIND_CREATE_MEMPOOL(this, 0, true);
#endif
- m_d->engine = engine;
}
-Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize)
+Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
{
- if (m_d->aggressiveGC)
+ if (aggressiveGC)
runGC();
-#ifdef DETAILED_MM_STATS
- willAllocate(size);
-#endif // DETAILED_MM_STATS
- Q_ASSERT(size >= 16);
- Q_ASSERT(size % 16 == 0);
-
-// qDebug() << "unmanagedHeapSize:" << m_d->unmanagedHeapSize << "limit:" << m_d->unmanagedHeapSizeGCLimit << "unmanagedSize:" << unmanagedSize;
- m_d->unmanagedHeapSize += unmanagedSize;
+ const size_t stringSize = align(sizeof(Heap::String));
+ unmanagedHeapSize += unmanagedSize;
bool didGCRun = false;
- if (m_d->unmanagedHeapSize > m_d->unmanagedHeapSizeGCLimit) {
+ if (unmanagedHeapSize > unmanagedHeapSizeGCLimit) {
runGC();
- if (3*m_d->unmanagedHeapSizeGCLimit <= 4*m_d->unmanagedHeapSize)
+ if (3*unmanagedHeapSizeGCLimit <= 4*unmanagedHeapSize)
// more than 75% full, raise limit
- m_d->unmanagedHeapSizeGCLimit = std::max(m_d->unmanagedHeapSizeGCLimit, m_d->unmanagedHeapSize) * 2;
- else if (m_d->unmanagedHeapSize * 4 <= m_d->unmanagedHeapSizeGCLimit)
+ unmanagedHeapSizeGCLimit = std::max(unmanagedHeapSizeGCLimit, unmanagedHeapSize) * 2;
+ else if (unmanagedHeapSize * 4 <= unmanagedHeapSizeGCLimit)
// less than 25% full, lower limit
- m_d->unmanagedHeapSizeGCLimit = qMax(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT, m_d->unmanagedHeapSizeGCLimit/2);
+ unmanagedHeapSizeGCLimit = qMax(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT, unmanagedHeapSizeGCLimit/2);
didGCRun = true;
}
- size_t pos = size >> 4;
-
- // doesn't fit into a small bucket
- if (size >= MemoryManager::Data::MaxItemSize) {
- if (!didGCRun && m_d->totalLargeItemsAllocated > 8 * 1024 * 1024)
+ HeapItem *m = blockAllocator.allocate(stringSize);
+ if (!m) {
+ if (!didGCRun && shouldRunGC())
runGC();
-
- // we use malloc for this
- const size_t totalSize = size + sizeof(MemoryManager::Data::LargeItem);
- Q_V4_PROFILE_ALLOC(engine, totalSize, Profiling::LargeItem);
- MemoryManager::Data::LargeItem *item =
- static_cast<MemoryManager::Data::LargeItem *>(malloc(totalSize));
- memset(item, 0, totalSize);
- item->next = m_d->largeItems;
- item->size = size;
- m_d->largeItems = item;
- m_d->totalLargeItemsAllocated += size;
- return item->heapObject();
+ m = blockAllocator.allocate(stringSize, true);
}
- Heap::Base *m = 0;
- Data::ChunkHeader *header = m_d->nonFullChunks[pos];
- if (header) {
- m = header->freeItems.nextFree();
- goto found;
- }
+ memset(m, 0, stringSize);
+ return *m;
+}
- // try to free up space, otherwise allocate
- if (!didGCRun && m_d->allocCount[pos] > (m_d->availableItems[pos] >> 1) && m_d->totalAlloc > (m_d->totalItems >> 1) && !m_d->aggressiveGC) {
+Heap::Base *MemoryManager::allocData(std::size_t size)
+{
+ if (aggressiveGC)
runGC();
- header = m_d->nonFullChunks[pos];
- if (header) {
- m = header->freeItems.nextFree();
- goto found;
- }
- }
+#ifdef DETAILED_MM_STATS
+ willAllocate(size);
+#endif // DETAILED_MM_STATS
- // no free item available, allocate a new chunk
- {
- // allocate larger chunks at a time to avoid excessive GC, but cap at maximum chunk size (2MB by default)
- uint shift = ++m_d->nChunks[pos];
- if (shift > m_d->maxShift)
- shift = m_d->maxShift;
- std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift);
- allocSize = roundUpToMultipleOf(m_d->pageSize, allocSize);
- Q_V4_PROFILE_ALLOC(engine, allocSize, Profiling::HeapPage);
- PageAllocation allocation = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages);
- m_d->heapChunks.push_back(allocation);
-
- header = reinterpret_cast<Data::ChunkHeader *>(allocation.base());
- Q_ASSERT(size <= UINT_MAX);
- header->itemSize = unsigned(size);
- header->itemStart = reinterpret_cast<char *>(allocation.base()) + roundUpToMultipleOf(16, sizeof(Data::ChunkHeader));
- header->itemEnd = reinterpret_cast<char *>(allocation.base()) + allocation.size() - header->itemSize;
-
- header->nextNonFull = m_d->nonFullChunks[pos];
- m_d->nonFullChunks[pos] = header;
-
- Heap::Base *last = &header->freeItems;
- for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
- Heap::Base *o = reinterpret_cast<Heap::Base *>(item);
- last->setNextFree(o);
- last = o;
+ Q_ASSERT(size >= Chunk::SlotSize);
+ Q_ASSERT(size % Chunk::SlotSize == 0);
- }
- last->setNextFree(0);
- m = header->freeItems.nextFree();
- Q_ASSERT(header->itemEnd >= header->itemStart);
- const size_t increase = quintptr(header->itemEnd - header->itemStart) / header->itemSize;
- m_d->availableItems[pos] += uint(increase);
- m_d->totalItems += int(increase);
-#ifdef V4_USE_VALGRIND
- VALGRIND_MAKE_MEM_NOACCESS(allocation.base(), allocSize);
- VALGRIND_MEMPOOL_ALLOC(this, header, sizeof(Data::ChunkHeader));
-#endif
-#ifdef V4_USE_HEAPTRACK
- heaptrack_report_alloc(header, sizeof(Data::ChunkHeader));
-#endif
+// qDebug() << "unmanagedHeapSize:" << unmanagedHeapSize << "limit:" << unmanagedHeapSizeGCLimit << "unmanagedSize:" << unmanagedSize;
+
+ if (size > Chunk::DataSize)
+ return *hugeItemAllocator.allocate(size);
+
+ HeapItem *m = blockAllocator.allocate(size);
+ if (!m) {
+ if (shouldRunGC())
+ runGC();
+ m = blockAllocator.allocate(size, true);
}
- found:
-#ifdef V4_USE_VALGRIND
- VALGRIND_MEMPOOL_ALLOC(this, m, size);
-#endif
-#ifdef V4_USE_HEAPTRACK
- heaptrack_report_alloc(m, size);
-#endif
- Q_V4_PROFILE_ALLOC(engine, size, Profiling::SmallItem);
+ memset(m, 0, size);
+ return *m;
+}
- ++m_d->allocCount[pos];
- ++m_d->totalAlloc;
- header->freeItems.setNextFree(m->nextFree());
- if (!header->freeItems.nextFree())
- m_d->nonFullChunks[pos] = header->nextNonFull;
- return m;
+Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nMembers)
+{
+ Heap::Object *o = static_cast<Heap::Object *>(allocData(size));
+
+ // ### Could optimize this and allocate both in one go through the block allocator
+ if (nMembers) {
+ std::size_t memberSize = align(sizeof(Heap::MemberData) + (nMembers - 1)*sizeof(Value));
+// qDebug() << "allocating member data for" << o << nMembers << memberSize;
+ Heap::Base *m;
+ if (memberSize > Chunk::DataSize)
+ m = *hugeItemAllocator.allocate(memberSize);
+ else
+ m = *blockAllocator.allocate(memberSize, true);
+ memset(m, 0, memberSize);
+ o->memberData = static_cast<Heap::MemberData *>(m);
+ o->memberData->setVtable(MemberData::staticVTable());
+ o->memberData->size = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
+ o->memberData->init();
+// qDebug() << " got" << o->memberData << o->memberData->size;
+ }
+ return o;
}
static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
@@ -486,88 +804,34 @@ void MemoryManager::sweep(bool lastSweep)
}
}
- bool *chunkIsEmpty = static_cast<bool *>(alloca(m_d->heapChunks.size() * sizeof(bool)));
- uint itemsInUse[MemoryManager::Data::MaxItemSize/16];
- memset(itemsInUse, 0, sizeof(itemsInUse));
- memset(m_d->nonFullChunks, 0, sizeof(m_d->nonFullChunks));
-
- for (size_t i = 0; i < m_d->heapChunks.size(); ++i) {
- Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(m_d->heapChunks[i].base());
- chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], engine);
- }
-
- std::vector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin();
- for (size_t i = 0; i < m_d->heapChunks.size(); ++i) {
- Q_ASSERT(chunkIter != m_d->heapChunks.end());
- Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(chunkIter->base());
- const size_t pos = header->itemSize >> 4;
- Q_ASSERT(header->itemEnd >= header->itemStart);
- const size_t decrease = quintptr(header->itemEnd - header->itemStart) / header->itemSize;
-
- // Release that chunk if it could have been spared since the last GC run without any difference.
- if (chunkIsEmpty[i] && m_d->availableItems[pos] - decrease >= itemsInUse[pos]) {
- Q_V4_PROFILE_DEALLOC(engine, chunkIter->size(), Profiling::HeapPage);
-#ifdef V4_USE_VALGRIND
- VALGRIND_MEMPOOL_FREE(this, header);
-#endif
-#ifdef V4_USE_HEAPTRACK
- heaptrack_report_free(header);
-#endif
- --m_d->nChunks[pos];
- m_d->availableItems[pos] -= uint(decrease);
- m_d->totalItems -= int(decrease);
- chunkIter->deallocate();
- chunkIter = m_d->heapChunks.erase(chunkIter);
- continue;
- } else if (header->freeItems.nextFree()) {
- header->nextNonFull = m_d->nonFullChunks[pos];
- m_d->nonFullChunks[pos] = header;
- }
- ++chunkIter;
- }
-
- Data::LargeItem *i = m_d->largeItems;
- Data::LargeItem **last = &m_d->largeItems;
- while (i) {
- Heap::Base *m = i->heapObject();
- Q_ASSERT(m->inUse());
- if (m->isMarked()) {
- m->clearMarkBit();
- last = &i->next;
- i = i->next;
- continue;
- }
- if (m->vtable()->destroy)
- m->vtable()->destroy(m);
-
- *last = i->next;
- Q_V4_PROFILE_DEALLOC(engine, i->size + sizeof(Data::LargeItem), Profiling::LargeItem);
- free(i);
- i = *last;
- }
+ blockAllocator.sweep();
+ hugeItemAllocator.sweep();
+}
- // some execution contexts are allocated on the stack, make sure we clear their markBit as well
- if (!lastSweep) {
- QV4::ExecutionContext *ctx = engine->currentContext;
- while (ctx) {
- ctx->d()->clearMarkBit();
- ctx = engine->parentContext(ctx);
- }
- }
+bool MemoryManager::shouldRunGC() const
+{
+ size_t total = blockAllocator.totalSlots();
+ size_t usedSlots = blockAllocator.usedSlotsAfterLastSweep;
+ if (total > MinSlotsGCLimit && usedSlots * GCOverallocation < total * 100)
+ return true;
+ return false;
}
+
void MemoryManager::runGC()
{
- if (m_d->gcBlocked) {
+ if (gcBlocked) {
// qDebug() << "Not running GC.";
return;
}
- QScopedValueRollback<bool> gcBlocker(m_d->gcBlocked, true);
+ QScopedValueRollback<bool> gcBlocker(gcBlocked, true);
- if (!m_d->gcStats) {
+ if (!gcStats) {
+// uint oldUsed = allocator.usedMem();
mark();
sweep();
+// DEBUG << "RUN GC: allocated:" << allocator.allocatedMem() << "used before" << oldUsed << "used now" << allocator.usedMem();
} else {
const size_t totalMem = getAllocatedMem();
@@ -577,7 +841,6 @@ void MemoryManager::runGC()
qint64 markTime = t.restart();
const size_t usedBefore = getUsedMem();
const size_t largeItemsBefore = getLargeItemsMem();
- size_t chunksBefore = m_d->heapChunks.size();
sweep();
const size_t usedAfter = getUsedMem();
const size_t largeItemsAfter = getLargeItemsMem();
@@ -586,56 +849,30 @@ void MemoryManager::runGC()
qDebug() << "========== GC ==========";
qDebug() << "Marked object in" << markTime << "ms.";
qDebug() << "Sweeped object in" << sweepTime << "ms.";
- qDebug() << "Allocated" << totalMem << "bytes in" << m_d->heapChunks.size() << "chunks.";
+ qDebug() << "Allocated" << totalMem << "bytes";
qDebug() << "Used memory before GC:" << usedBefore;
qDebug() << "Used memory after GC:" << usedAfter;
qDebug() << "Freed up bytes:" << (usedBefore - usedAfter);
- qDebug() << "Released chunks:" << (chunksBefore - m_d->heapChunks.size());
qDebug() << "Large item memory before GC:" << largeItemsBefore;
qDebug() << "Large item memory after GC:" << largeItemsAfter;
qDebug() << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter);
qDebug() << "======== End GC ========";
}
-
- memset(m_d->allocCount, 0, sizeof(m_d->allocCount));
- m_d->totalAlloc = 0;
- m_d->totalLargeItemsAllocated = 0;
}
size_t MemoryManager::getUsedMem() const
{
- size_t usedMem = 0;
- for (std::vector<PageAllocation>::const_iterator i = m_d->heapChunks.cbegin(), ei = m_d->heapChunks.cend(); i != ei; ++i) {
- Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(i->base());
- for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
- Heap::Base *m = reinterpret_cast<Heap::Base *>(item);
- Q_ASSERT(qintptr(item) % 16 == 0);
- if (m->inUse())
- usedMem += header->itemSize;
- }
- }
- return usedMem;
+ return blockAllocator.usedMem();
}
size_t MemoryManager::getAllocatedMem() const
{
- size_t total = 0;
- for (size_t i = 0; i < m_d->heapChunks.size(); ++i)
- total += m_d->heapChunks.at(i).size();
- return total;
+ return blockAllocator.allocatedMem() + hugeItemAllocator.usedMem();
}
size_t MemoryManager::getLargeItemsMem() const
{
- size_t total = 0;
- for (const Data::LargeItem *i = m_d->largeItems; i != 0; i = i->next)
- total += i->size;
- return total;
-}
-
-void MemoryManager::changeUnmanagedHeapSizeUsage(qptrdiff delta)
-{
- m_d->unmanagedHeapSize += delta;
+ return hugeItemAllocator.usedMem();
}
MemoryManager::~MemoryManager()
@@ -643,23 +880,26 @@ MemoryManager::~MemoryManager()
delete m_persistentValues;
sweep(/*lastSweep*/true);
+ blockAllocator.freeAll();
+ hugeItemAllocator.freeAll();
+ stackAllocator.freeAll();
delete m_weakValues;
#ifdef V4_USE_VALGRIND
VALGRIND_DESTROY_MEMPOOL(this);
#endif
+ delete chunkAllocator;
}
-
void MemoryManager::dumpStats() const
{
#ifdef DETAILED_MM_STATS
std::cerr << "=================" << std::endl;
std::cerr << "Allocation stats:" << std::endl;
std::cerr << "Requests for each chunk size:" << std::endl;
- for (int i = 0; i < m_d->allocSizeCounters.size(); ++i) {
- if (unsigned count = m_d->allocSizeCounters[i]) {
+ for (int i = 0; i < allocSizeCounters.size(); ++i) {
+ if (unsigned count = allocSizeCounters[i]) {
std::cerr << "\t" << (i << 4) << " bytes chunks: " << count << std::endl;
}
}
@@ -670,7 +910,7 @@ void MemoryManager::dumpStats() const
void MemoryManager::willAllocate(std::size_t size)
{
unsigned alignedSize = (size + 15) >> 4;
- QVector<unsigned> &counters = m_d->allocSizeCounters;
+ QVector<unsigned> &counters = allocSizeCounters;
if ((unsigned) counters.size() < alignedSize + 1)
counters.resize(alignedSize + 1);
counters[alignedSize]++;
@@ -690,4 +930,7 @@ void MemoryManager::collectFromJSStack() const
++v;
}
}
+
+} // namespace QV4
+
QT_END_NAMESPACE
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index e6417cb2e0..00daf8a622 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -55,6 +55,7 @@
#include <private/qv4value_p.h>
#include <private/qv4scopedvalue_p.h>
#include <private/qv4object_p.h>
+#include <private/qv4mmdefs_p.h>
#include <QVector>
//#define DETAILED_MM_STATS
@@ -63,35 +64,166 @@
#define QV4_MM_MAX_CHUNK_SIZE "QV4_MM_MAX_CHUNK_SIZE"
#define QV4_MM_STATS "QV4_MM_STATS"
+#define MM_DEBUG 0
+
QT_BEGIN_NAMESPACE
namespace QV4 {
-struct GCDeletable;
+struct ChunkAllocator;
+
+template<typename T>
+struct StackAllocator {
+ Q_STATIC_ASSERT(sizeof(T) < Chunk::DataSize);
+ static const uint requiredSlots = (sizeof(T) + sizeof(HeapItem) - 1)/sizeof(HeapItem);
+
+ StackAllocator(ChunkAllocator *chunkAlloc);
+
+ T *allocate() {
+ T *m = nextFree->as<T>();
+ if (Q_UNLIKELY(nextFree == lastInChunk)) {
+ nextChunk();
+ } else {
+ nextFree += requiredSlots;
+ }
+#if MM_DEBUG
+ Chunk *c = m->chunk();
+ Chunk::setBit(c->objectBitmap, m - c->realBase());
+#endif
+ return m;
+ }
+ void free() {
+#if MM_DEBUG
+ Chunk::clearBit(item->chunk()->objectBitmap, item - item->chunk()->realBase());
+#endif
+ if (Q_UNLIKELY(nextFree == firstInChunk)) {
+ prevChunk();
+ } else {
+ nextFree -= requiredSlots;
+ }
+ }
+
+ void nextChunk();
+ void prevChunk();
+
+ void freeAll();
+
+ ChunkAllocator *chunkAllocator;
+ HeapItem *nextFree = 0;
+ HeapItem *firstInChunk = 0;
+ HeapItem *lastInChunk = 0;
+ std::vector<Chunk *> chunks;
+ uint currentChunk = 0;
+};
+
+struct BlockAllocator {
+ BlockAllocator(ChunkAllocator *chunkAllocator)
+ : chunkAllocator(chunkAllocator)
+ {
+ memset(freeBins, 0, sizeof(freeBins));
+#if MM_DEBUG
+ memset(allocations, 0, sizeof(allocations));
+#endif
+ }
+
+ enum { NumBins = 8 };
+
+ static inline size_t binForSlots(size_t nSlots) {
+ return nSlots >= NumBins ? NumBins - 1 : nSlots;
+ }
+
+#if MM_DEBUG
+ void stats();
+#endif
+
+ HeapItem *allocate(size_t size, bool forceAllocation = false);
+
+ size_t totalSlots() const {
+ return Chunk::AvailableSlots*chunks.size();
+ }
+
+ size_t allocatedMem() const {
+ return chunks.size()*Chunk::DataSize;
+ }
+ size_t usedMem() const {
+ uint used = 0;
+ for (auto c : chunks)
+ used += c->nUsedSlots()*Chunk::SlotSize;
+ return used;
+ }
+
+ void sweep();
+ void freeAll();
+
+ // bump allocations
+ HeapItem *nextFree = 0;
+ size_t nFree = 0;
+ size_t usedSlotsAfterLastSweep = 0;
+ HeapItem *freeBins[NumBins];
+ ChunkAllocator *chunkAllocator;
+ std::vector<Chunk *> chunks;
+#if MM_DEBUG
+ uint allocations[NumBins];
+#endif
+};
+
+struct HugeItemAllocator {
+ HugeItemAllocator(ChunkAllocator *chunkAllocator)
+ : chunkAllocator(chunkAllocator)
+ {}
+
+ HeapItem *allocate(size_t size);
+ void sweep();
+ void freeAll();
+
+ size_t usedMem() const {
+ size_t used = 0;
+ for (const auto &c : chunks)
+ used += c.size;
+ return used;
+ }
+
+ ChunkAllocator *chunkAllocator;
+ struct HugeChunk {
+ Chunk *chunk;
+ size_t size;
+ };
+
+ std::vector<HugeChunk> chunks;
+};
+
class Q_QML_EXPORT MemoryManager
{
Q_DISABLE_COPY(MemoryManager);
public:
- struct Data;
-
-public:
MemoryManager(ExecutionEngine *engine);
~MemoryManager();
// TODO: this is only for 64bit (and x86 with SSE/AVX), so exend it for other architectures to be slightly more efficient (meaning, align on 8-byte boundaries).
// Note: all occurrences of "16" in alloc/dealloc are also due to the alignment.
- static inline std::size_t align(std::size_t size)
- { return (size + 15) & ~0xf; }
+ Q_DECL_CONSTEXPR static inline std::size_t align(std::size_t size)
+ { return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); }
+
+ QV4::Heap::CallContext *allocSimpleCallContext(QV4::ExecutionEngine *v4)
+ {
+ Heap::CallContext *ctxt = stackAllocator.allocate();
+ memset(ctxt, 0, sizeof(Heap::CallContext));
+ ctxt->setVtable(QV4::CallContext::staticVTable());
+ ctxt->init(v4);
+ return ctxt;
+
+ }
+ void freeSimpleCallContext()
+ { stackAllocator.free(); }
template<typename ManagedType>
- inline typename ManagedType::Data *allocManaged(std::size_t size, std::size_t unmanagedSize = 0)
+ inline typename ManagedType::Data *allocManaged(std::size_t size)
{
V4_ASSERT_IS_TRIVIAL(typename ManagedType::Data)
size = align(size);
- Heap::Base *o = allocData(size, unmanagedSize);
- memset(o, 0, size);
+ Heap::Base *o = allocData(size);
o->setVtable(ManagedType::staticVTable());
return static_cast<typename ManagedType::Data *>(o);
}
@@ -99,35 +231,31 @@ public:
template <typename ObjectType>
typename ObjectType::Data *allocateObject(InternalClass *ic)
{
- const int size = (sizeof(typename ObjectType::Data) + (sizeof(Value) - 1)) & ~(sizeof(Value) - 1);
- typename ObjectType::Data *o = allocManaged<ObjectType>(size + ic->size*sizeof(Value));
+ Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size);
+ o->setVtable(ObjectType::staticVTable());
o->internalClass = ic;
- o->inlineMemberSize = ic->size;
- o->inlineMemberOffset = size/sizeof(Value);
- return o;
+ return static_cast<typename ObjectType::Data *>(o);
}
template <typename ObjectType>
typename ObjectType::Data *allocateObject()
{
InternalClass *ic = ObjectType::defaultInternalClass(engine);
- const int size = (sizeof(typename ObjectType::Data) + (sizeof(Value) - 1)) & ~(sizeof(Value) - 1);
- typename ObjectType::Data *o = allocManaged<ObjectType>(size + ic->size*sizeof(Value));
+ Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size);
+ o->setVtable(ObjectType::staticVTable());
Object *prototype = ObjectType::defaultPrototype(engine);
o->internalClass = ic;
o->prototype = prototype->d();
- o->inlineMemberSize = ic->size;
- o->inlineMemberOffset = size/sizeof(Value);
- return o;
+ return static_cast<typename ObjectType::Data *>(o);
}
template <typename ManagedType, typename Arg1>
typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1)
{
- Scope scope(engine);
- Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data), unmanagedSize));
- t->d_unchecked()->init(this, arg1);
- return t->d();
+ typename ManagedType::Data *o = reinterpret_cast<typename ManagedType::Data *>(allocString(unmanagedSize));
+ o->setVtable(ManagedType::staticVTable());
+ o->init(this, arg1);
+ return o;
}
template <typename ObjectType>
@@ -297,12 +425,15 @@ public:
size_t getAllocatedMem() const;
size_t getLargeItemsMem() const;
- void changeUnmanagedHeapSizeUsage(qptrdiff delta); // called when a JS object grows itself. Specifically: Heap::String::append
+ // called when a JS object grows itself. Specifically: Heap::String::append
+ void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; }
+
protected:
/// expects size to be aligned
- // TODO: try to inline
- Heap::Base *allocData(std::size_t size, std::size_t unmanagedSize);
+ Heap::Base *allocString(std::size_t unmanagedSize);
+ Heap::Base *allocData(std::size_t size);
+ Heap::Object *allocObjectWithMemberData(std::size_t size, uint nMembers);
#ifdef DETAILED_MM_STATS
void willAllocate(std::size_t size);
@@ -312,13 +443,24 @@ private:
void collectFromJSStack() const;
void mark();
void sweep(bool lastSweep = false);
+ bool shouldRunGC() const;
public:
QV4::ExecutionEngine *engine;
- QScopedPointer<Data> m_d;
+ ChunkAllocator *chunkAllocator;
+ StackAllocator<Heap::CallContext> stackAllocator;
+ BlockAllocator blockAllocator;
+ HugeItemAllocator hugeItemAllocator;
PersistentValueStorage *m_persistentValues;
PersistentValueStorage *m_weakValues;
QVector<Value *> m_pendingFreedObjectWrapperValue;
+
+ std::size_t unmanagedHeapSize = 0; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
+ std::size_t unmanagedHeapSizeGCLimit;
+
+ bool gcBlocked = false;
+ bool aggressiveGC = false;
+ bool gcStats = false;
};
}
diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
new file mode 100644
index 0000000000..588ae21ee0
--- /dev/null
+++ b/src/qml/memory/qv4mmdefs_p.h
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 QV4MMDEFS_P_H
+#define QV4MMDEFS_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 <QtCore/qalgorithms.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+/*
+ * Chunks are the basic structure containing GC managed objects.
+ *
+ * Chunks are 64k aligned in memory, so that retrieving the Chunk pointer from a Heap object
+ * is a simple masking operation. Each Chunk has 4 bitmaps for managing purposes,
+ * and 32byte wide slots for the objects following afterwards.
+ *
+ * The gray and black bitmaps are used for mark/sweep.
+ * The object bitmap has a bit set if this location represents the start of a Heap object.
+ * The extends bitmap denotes the extend of an object. It has a cleared bit at the start of the object
+ * and a set bit for all following slots used by the object.
+ *
+ * Free memory has both used and extends bits set to 0.
+ *
+ * This gives the following operations when allocating an object of size s:
+ * Find s/Alignment consecutive free slots in the chunk. Set the object bit for the first
+ * slot to 1. Set the extends bits for all following slots to 1.
+ *
+ * All used slots can be found by object|extents.
+ *
+ * When sweeping, simply copy the black bits over to the object bits.
+ *
+ */
+struct HeapItem;
+struct Chunk {
+ enum {
+ ChunkSize = 64*1024,
+ ChunkShift = 16,
+ SlotSize = 32,
+ SlotSizeShift = 5,
+ NumSlots = ChunkSize/SlotSize,
+ BitmapSize = NumSlots/8,
+ HeaderSize = 4*BitmapSize,
+ DataSize = ChunkSize - HeaderSize,
+ AvailableSlots = DataSize/SlotSize,
+#if QT_POINTER_SIZE == 8
+ Bits = 64,
+ BitShift = 6,
+#else
+ Bits = 32,
+ BitShift = 5,
+#endif
+ EntriesInBitmap = BitmapSize/sizeof(quintptr)
+ };
+ quintptr grayBitmap[BitmapSize/sizeof(quintptr)];
+ quintptr blackBitmap[BitmapSize/sizeof(quintptr)];
+ quintptr objectBitmap[BitmapSize/sizeof(quintptr)];
+ quintptr extendsBitmap[BitmapSize/sizeof(quintptr)];
+ char data[ChunkSize - HeaderSize];
+
+ HeapItem *realBase();
+ HeapItem *first();
+
+ static void setBit(quintptr *bitmap, size_t index) {
+// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
+ bitmap += index >> BitShift;
+ quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1));
+ *bitmap |= bit;
+ }
+ static void clearBit(quintptr *bitmap, size_t index) {
+// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
+ bitmap += index >> BitShift;
+ quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1));
+ *bitmap &= ~bit;
+ }
+ static bool testBit(quintptr *bitmap, size_t index) {
+// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
+ bitmap += index >> BitShift;
+ quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1));
+ return (*bitmap & bit);
+ }
+ static void setBits(quintptr *bitmap, size_t index, size_t nBits) {
+// Q_ASSERT(index >= HeaderSize/SlotSize && index + nBits <= ChunkSize/SlotSize);
+ if (!nBits)
+ return;
+ bitmap += index >> BitShift;
+ index &= (Bits - 1);
+ while (1) {
+ size_t bitsToSet = qMin(nBits, Bits - index);
+ quintptr mask = static_cast<quintptr>(-1) >> (Bits - bitsToSet) << index;
+ *bitmap |= mask;
+ nBits -= bitsToSet;
+ if (!nBits)
+ return;
+ index = 0;
+ ++bitmap;
+ }
+ }
+ static bool hasNonZeroBit(quintptr *bitmap) {
+ for (uint i = 0; i < EntriesInBitmap; ++i)
+ if (bitmap[i])
+ return true;
+ return false;
+ }
+ static uint lowestNonZeroBit(quintptr *bitmap) {
+ for (uint i = 0; i < EntriesInBitmap; ++i) {
+ if (bitmap[i]) {
+ quintptr b = bitmap[i];
+ return i*Bits + qCountTrailingZeroBits(b);
+ }
+ }
+ return 0;
+ }
+
+ uint nFreeSlots() const {
+ return AvailableSlots - nUsedSlots();
+ }
+ uint nUsedSlots() const {
+ uint usedSlots = 0;
+ for (uint i = 0; i < EntriesInBitmap; ++i) {
+ quintptr used = objectBitmap[i] | extendsBitmap[i];
+ usedSlots += qPopulationCount(used);
+ }
+ return usedSlots;
+ }
+
+ void sweep();
+ void freeAll();
+
+ void sortIntoBins(HeapItem **bins, uint nBins);
+};
+
+struct HeapItem {
+ union {
+ struct {
+ HeapItem *next;
+ size_t availableSlots;
+ } freeData;
+ quint64 payload[Chunk::SlotSize/sizeof(quint64)];
+ };
+ operator Heap::Base *() { return reinterpret_cast<Heap::Base *>(this); }
+
+ template<typename T>
+ T *as() { return static_cast<T *>(reinterpret_cast<Heap::Base *>(this)); }
+
+ Chunk *chunk() const {
+ return reinterpret_cast<Chunk *>(reinterpret_cast<quintptr>(this) >> Chunk::ChunkShift << Chunk::ChunkShift);
+ }
+
+ bool isGray() const {
+ Chunk *c = chunk();
+ uint index = this - c->realBase();
+ return Chunk::testBit(c->grayBitmap, index);
+ }
+ bool isBlack() const {
+ Chunk *c = chunk();
+ uint index = this - c->realBase();
+ return Chunk::testBit(c->blackBitmap, index);
+ }
+ bool isInUse() const {
+ Chunk *c = chunk();
+ uint index = this - c->realBase();
+ return Chunk::testBit(c->objectBitmap, index);
+ }
+
+ void setAllocatedSlots(size_t nSlots) {
+// Q_ASSERT(size && !(size % sizeof(HeapItem)));
+ Chunk *c = chunk();
+ size_t index = this - c->realBase();
+// Q_ASSERT(!Chunk::testBit(c->objectBitmap, index));
+ Chunk::setBit(c->objectBitmap, index);
+ Chunk::setBits(c->extendsBitmap, index + 1, nSlots - 1);
+// for (uint i = index + 1; i < nBits - 1; ++i)
+// Q_ASSERT(Chunk::testBit(c->extendsBitmap, i));
+// Q_ASSERT(!Chunk::testBit(c->extendsBitmap, index));
+ }
+
+ // Doesn't report correctly for huge items
+ size_t size() const {
+ Chunk *c = chunk();
+ uint index = this - c->realBase();
+ Q_ASSERT(Chunk::testBit(c->objectBitmap, index));
+ // ### optimize me
+ uint end = index + 1;
+ while (end < Chunk::NumSlots && Chunk::testBit(c->extendsBitmap, end))
+ ++end;
+ return (end - index)*sizeof(HeapItem);
+ }
+};
+
+inline HeapItem *Chunk::realBase()
+{
+ return reinterpret_cast<HeapItem *>(this);
+}
+
+inline HeapItem *Chunk::first()
+{
+ return reinterpret_cast<HeapItem *>(data);
+}
+
+Q_STATIC_ASSERT(sizeof(Chunk) == Chunk::ChunkSize);
+Q_STATIC_ASSERT((1 << Chunk::ChunkShift) == Chunk::ChunkSize);
+Q_STATIC_ASSERT(1 << Chunk::SlotSizeShift == Chunk::SlotSize);
+Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize);
+Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits);
+Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits);
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 4fbd828307..19ece44beb 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -199,7 +199,7 @@ void QQmlBoundSignalExpression::evaluate(void **a)
// for several cases (such as QVariant type and QObject-derived types)
//args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
if (type == qMetaTypeId<QJSValue>()) {
- if (QV4::Value *v4Value = QJSValuePrivate::getValue(reinterpret_cast<QJSValue *>(a[ii + 1])))
+ if (QV4::Value *v4Value = QJSValuePrivate::valueForData(reinterpret_cast<QJSValue *>(a[ii + 1]), &callData->args[ii]))
callData->args[ii] = *v4Value;
else
callData->args[ii] = QV4::Encode::undefined();
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 50ed58e63d..a04f47e6a4 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1063,11 +1063,11 @@ struct QmlIncubatorObject : public QV4::Object
V4_OBJECT2(QmlIncubatorObject, Object)
V4_NEEDS_DESTROY
- static QV4::ReturnedValue method_get_statusChanged(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_statusChanged(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_status(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_object(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_forceCompletion(QV4::CallContext *ctx);
+ static void method_get_statusChanged(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_set_statusChanged(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_status(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_object(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_forceCompletion(const BuiltinFunction *, Scope &scope, CallData *callData);
static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e);
@@ -1415,58 +1415,53 @@ QQmlComponentExtension::QQmlComponentExtension(QV4::ExecutionEngine *v4)
incubationProto.set(v4, proto);
}
-QV4::ReturnedValue QV4::QmlIncubatorObject::method_get_object(QV4::CallContext *ctx)
+void QV4::QmlIncubatorObject::method_get_object(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>());
+ QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>());
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, o->d()->incubator->object());
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, o->d()->incubator->object());
}
-QV4::ReturnedValue QV4::QmlIncubatorObject::method_forceCompletion(QV4::CallContext *ctx)
+void QV4::QmlIncubatorObject::method_forceCompletion(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>());
+ QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>());
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
o->d()->incubator->forceCompletion();
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
-QV4::ReturnedValue QV4::QmlIncubatorObject::method_get_status(QV4::CallContext *ctx)
+void QV4::QmlIncubatorObject::method_get_status(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>());
+ QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>());
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return QV4::Encode(o->d()->incubator->status());
+ scope.result = QV4::Encode(o->d()->incubator->status());
}
-QV4::ReturnedValue QV4::QmlIncubatorObject::method_get_statusChanged(QV4::CallContext *ctx)
+void QV4::QmlIncubatorObject::method_get_statusChanged(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>());
+ QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>());
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return o->d()->statusChanged.asReturnedValue();
+ scope.result = o->d()->statusChanged;
}
-QV4::ReturnedValue QV4::QmlIncubatorObject::method_set_statusChanged(QV4::CallContext *ctx)
+void QV4::QmlIncubatorObject::method_set_statusChanged(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>());
- if (!o || ctx->argc() < 1)
- return ctx->engine()->throwTypeError();
+ QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>());
+ if (!o || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ o->d()->statusChanged = callData->args[0];
- o->d()->statusChanged = ctx->args()[0];
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
QQmlComponentExtension::~QQmlComponentExtension()
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index 7552e1e82b..d5d2c9a28d 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -105,17 +105,15 @@ void QQmlDelayedCallQueue::init(QV4::ExecutionEngine* engine)
m_tickedMethod = metaObject.method(methodIndex);
}
-QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::CallContext *ctx)
+void QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- const QV4::CallData *callData = ctx->d()->callData;
-
if (callData->argc == 0)
- V4THROW_ERROR("Qt.callLater: no arguments given");
+ THROW_GENERIC_ERROR("Qt.callLater: no arguments given");
const QV4::FunctionObject *func = callData->args[0].as<QV4::FunctionObject>();
if (!func)
- V4THROW_ERROR("Qt.callLater: first argument not a function or signal");
+ THROW_GENERIC_ERROR("Qt.callLater: first argument not a function or signal");
QPair<QObject *, int> functionData = QV4::QObjectMethod::extractQtMethod(func);
@@ -171,7 +169,7 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::CallCon
m_tickedMethod.invoke(this, Qt::QueuedConnection);
m_callbackOutstanding = true;
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, const QV4::CallData *callData, int offset, QV4::ExecutionEngine *engine)
diff --git a/src/qml/qml/qqmldelayedcallqueue_p.h b/src/qml/qml/qqmldelayedcallqueue_p.h
index ef899170a2..cffde4f0c0 100644
--- a/src/qml/qml/qqmldelayedcallqueue_p.h
+++ b/src/qml/qml/qqmldelayedcallqueue_p.h
@@ -70,7 +70,7 @@ public:
void init(QV4::ExecutionEngine *);
- QV4::ReturnedValue addUniquelyAndExecuteLater(QV4::CallContext *ctx);
+ void addUniquelyAndExecuteLater(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
public Q_SLOTS:
void ticked();
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 8712b638c5..c07d5c740a 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -130,42 +131,74 @@ bool isPathAbsolute(const QString &path)
#endif
}
-// If the type does not already exist as a file import, add the type and return the new type
-QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeName,
+/*
+ \internal
+
+ Fetches the QQmlType instance registered for \a urlString, creating a
+ registration for it if it is not already registered, using the associated
+ \a typeName, \a isCompositeSingleton, \a majorVersion and \a minorVersion
+ details.
+
+ Errors (if there are any) are placed into \a errors, if it is nonzero. Note
+ that errors are treated as fatal if \a errors is not set.
+*/
+QQmlType *fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringRef& typeName,
bool isCompositeSingleton, QList<QQmlError> *errors,
int majorVersion=-1, int minorVersion=-1)
{
- QUrl url(urlString);
+ QUrl url(urlString); // ### unfortunate (costly) conversion
QQmlType *ret = QQmlMetaType::qmlType(url);
- if (!ret) { //QQmlType not yet existing for composite or composite singleton type
- int dot = typeName.indexOf(QLatin1Char('.'));
- QHashedStringRef unqualifiedtype = dot < 0 ? typeName : QHashedStringRef(typeName.constData() + dot + 1, typeName.length() - dot - 1);
-
- //XXX: The constData of the string ref is pointing somewhere unsafe in qmlregister, so we need to create a temporary copy
- QByteArray buf(unqualifiedtype.toString().toUtf8());
-
- if (isCompositeSingleton) {
- QQmlPrivate::RegisterCompositeSingletonType reg = {
- url,
- "", //Empty URI indicates loaded via file imports
- majorVersion,
- minorVersion,
- buf.constData()
- };
- ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, &reg));
- } else {
- QQmlPrivate::RegisterCompositeType reg = {
- url,
- "", //Empty URI indicates loaded via file imports
- majorVersion,
- minorVersion,
- buf.constData()
- };
- ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &reg));
- }
+ if (ret)
+ return ret;
+
+ int dot = typeName.indexOf(QLatin1Char('.'));
+ QHashedStringRef unqualifiedtype = dot < 0 ? typeName : QHashedStringRef(typeName.constData() + dot + 1, typeName.length() - dot - 1);
+
+ // We need a pointer, but we were passed a string. Take a copy so we
+ // can guarentee it will live long enough to reach qmlregister.
+ QByteArray buf(unqualifiedtype.toString().toUtf8());
+
+ // Register the type. Note that the URI parameters here are empty; for
+ // file type imports, we do not place them in a URI as we don't
+ // necessarily have a good and unique one (picture a library import,
+ // which may be found in multiple plugin locations on disk), but there
+ // are other reasons for this too.
+ //
+ // By not putting them in a URI, we prevent the types from being
+ // registered on a QQmlTypeModule; this is important, as once types are
+ // placed on there, they cannot be easily removed, meaning if the
+ // developer subsequently loads a different import (meaning different
+ // types) with the same URI (using, say, a different plugin path), it is
+ // very undesirable that we continue to associate the types from the
+ // "old" URI with that new module.
+ //
+ // Not having URIs also means that the types cannot be found by name
+ // etc, the only way to look them up is through QQmlImports -- for
+ // better or worse.
+ if (isCompositeSingleton) {
+ QQmlPrivate::RegisterCompositeSingletonType reg = {
+ url,
+ "", // uri
+ majorVersion,
+ minorVersion,
+ buf.constData()
+ };
+ ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, &reg));
+ } else {
+ QQmlPrivate::RegisterCompositeType reg = {
+ url,
+ "", // uri
+ majorVersion,
+ minorVersion,
+ buf.constData()
+ };
+ ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &reg));
}
- if (!ret) {//Usually when a type name is "found" but invalid
- //qDebug() << ret << urlString << QQmlMetaType::qmlType(url);
+
+ // This means that the type couldn't be found by URL, but could not be
+ // registered either, meaning we most likely were passed some kind of bad
+ // data.
+ if (!ret) {
if (!errors) // Cannot list errors properly, just quit
qFatal("%s", QQmlMetaType::typeRegistrationFailures().join('\n').toLatin1().constData());
QQmlError error;
@@ -204,44 +237,38 @@ void qmlClearEnginePlugins()
typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair;
#endif
-class QQmlImportNamespace
-{
-public:
- QQmlImportNamespace() : nextNamespace(0) {}
- ~QQmlImportNamespace() { qDeleteAll(imports); }
-
- struct Import {
- QString uri;
- QString url;
- int majversion;
- int minversion;
- bool isLibrary;
- QQmlDirComponents qmlDirComponents;
- QQmlDirScripts qmlDirScripts;
-
- bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoader::QmldirContent *qmldir,
- QQmlImportNamespace *nameSpace, QList<QQmlError> *errors);
-
- static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin);
-
- bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
- int *vmajor, int *vminor, QQmlType** type_return,
- QString *base = 0, bool *typeRecursionDetected = 0) const;
- };
- QList<Import *> imports;
+/*!
+ \internal
+ \class QQmlImportInstance
- Import *findImport(const QString &uri) const;
+ A QQmlImportType represents a single import of a document, held within a
+ namespace.
- bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
- int *vmajor, int *vminor, QQmlType** type_return,
- QString *base = 0, QList<QQmlError> *errors = 0);
+ \note The uri here may not necessarily be unique (e.g. for file imports).
- // Prefix when used as a qualified import. Otherwise empty.
- QHashedString prefix;
+ \note Version numbers may be -1 for file imports: this means that no
+ version was specified as part of the import. Type resolution will be
+ responsible for attempting to find the "best" possible version.
+*/
- // Used by QQmlImportsPrivate::qualifiedSets
- QQmlImportNamespace *nextNamespace;
-};
+/*!
+ \internal
+ \class QQmlImportNamespace
+
+ A QQmlImportNamespace is a way of seperating imports into a local namespace.
+
+ Within a QML document, there is at least one namespace (the
+ "unqualified set") where imports without a qualifier are placed, i.e:
+
+ import QtQuick 2.6
+
+ will have a single namespace (the unqualified set) containing a single import
+ for QtQuick 2.6. However, there may be others if an import statement gives
+ a qualifier, i.e the following will result in an additional new
+ QQmlImportNamespace in the qualified set:
+
+ import MyFoo 1.0 as Foo
+*/
class QQmlImportsPrivate
{
@@ -273,9 +300,12 @@ public:
QString base;
int ref;
+ // storage of data related to imports without a namespace
mutable QQmlImportNamespace unqualifiedset;
QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &) const;
+
+ // storage of data related to imports with a namespace
mutable QFieldList<QQmlImportNamespace, &QQmlImportNamespace::nextNamespace> qualifiedSets;
QQmlTypeLoader *typeLoader;
@@ -284,21 +314,21 @@ public:
QQmlImportDatabase *database,
QString *outQmldirFilePath, QString *outUrl);
- static bool validateQmldirVersion(const QQmlTypeLoader::QmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
+ static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
QList<QQmlError> *errors);
bool importExtension(const QString &absoluteFilePath, const QString &uri,
int vmaj, int vmin,
QQmlImportDatabase *database,
- const QQmlTypeLoader::QmldirContent *qmldir,
+ const QQmlTypeLoaderQmldirContent *qmldir,
QList<QQmlError> *errors);
bool getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- const QQmlTypeLoader::QmldirContent **qmldir, QList<QQmlError> *errors);
+ const QQmlTypeLoaderQmldirContent **qmldir, QList<QQmlError> *errors);
QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
- QQmlImportNamespace::Import *addImportToNamespace(QQmlImportNamespace *nameSpace,
+ QQmlImportInstance *addImportToNamespace(QQmlImportNamespace *nameSpace,
const QString &uri, const QString &url,
int vmaj, int vmin, QV4::CompiledData::Import::ImportType type,
QList<QQmlError> *errors, bool lowPrecedence = false);
@@ -363,12 +393,22 @@ QUrl QQmlImports::baseUrl() const
return d->baseUrl;
}
+/*
+ \internal
+
+ This method is responsible for populating data of all types visible in this
+ document's imports into the \a cache for resolution elsewhere (e.g. in JS,
+ or when loading additional types).
+
+ \note This is for C++ types only. Composite types are handled separately,
+ as they do not have a QQmlTypeModule.
+*/
void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
{
const QQmlImportNamespace &set = d->unqualifiedset;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion);
if (module) {
cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, import->minversion));
@@ -379,11 +419,14 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
const QQmlImportNamespace &set = *ns;
+ // positioning is important; we must create the namespace even if there is no module.
+ QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[set.prefix];
+ typeimport.m_qualifier = set.prefix;
+
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion);
if (module) {
- QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[set.prefix];
typeimport.modules.append(QQmlTypeModuleVersion(module, import->minversion));
}
}
@@ -412,7 +455,7 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
typedef QQmlDirComponents::const_iterator ConstIterator;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
const QQmlDirComponents &components = import->qmlDirComponents;
@@ -430,6 +473,15 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
}
}
+/*
+ \internal
+
+ Returns a list of all composite singletons present in this document's
+ imports.
+
+ This information is used by QQmlTypeLoader to ensure that composite singletons
+ are marked as dependencies during type loading.
+*/
QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSingletons() const
{
QList<QQmlImports::CompositeSingletonReference> compositeSingletons;
@@ -445,6 +497,12 @@ QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSi
return compositeSingletons;
}
+/*
+ \internal
+
+ Returns a list of scripts imported by this document. This is used by
+ QQmlTypeLoader to properly handle dependencies on imported scripts.
+*/
QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
{
QList<QQmlImports::ScriptReference> scripts;
@@ -452,7 +510,7 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
const QQmlImportNamespace &set = d->unqualifiedset;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
for (const QQmlDirParser::Script &script : import->qmlDirScripts) {
ScriptReference ref;
@@ -466,7 +524,7 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
const QQmlImportNamespace &set = *ns;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
for (const QQmlDirParser::Script &script : import->qmlDirScripts) {
ScriptReference ref;
@@ -590,7 +648,7 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
return false;
}
-bool QQmlImportNamespace::Import::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoader::QmldirContent *qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
+bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent *qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
{
Q_ASSERT(resolvedUrl.endsWith(Slash));
url = resolvedUrl;
@@ -600,7 +658,7 @@ bool QQmlImportNamespace::Import::setQmldirContent(const QString &resolvedUrl, c
const QQmlDirScripts &scripts = qmldir->scripts();
if (!scripts.isEmpty()) {
// Verify that we haven't imported these scripts already
- for (QList<QQmlImportNamespace::Import *>::const_iterator it = nameSpace->imports.constBegin();
+ for (QList<QQmlImportInstance *>::const_iterator it = nameSpace->imports.constBegin();
it != nameSpace->imports.constEnd(); ++it) {
if ((*it != this) && ((*it)->uri == uri)) {
QQmlError error;
@@ -616,7 +674,7 @@ bool QQmlImportNamespace::Import::setQmldirContent(const QString &resolvedUrl, c
return true;
}
-QQmlDirScripts QQmlImportNamespace::Import::getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin)
+QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin)
{
QMap<QString, QQmlDirParser::Script> versioned;
@@ -652,7 +710,7 @@ bool QQmlImports::resolveType(QQmlImportNamespace* ns, const QHashedStringRef &t
return ns->resolveType(d->typeLoader,type,vmaj,vmin,type_return);
}
-bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
+bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader,
const QHashedStringRef& type, int *vmajor, int *vminor,
QQmlType** type_return, QString *base, bool *typeRecursionDetected) const
{
@@ -683,15 +741,17 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
if ((candidate == end) ||
(c.majorVersion > candidate->majorVersion) ||
((c.majorVersion == candidate->majorVersion) && (c.minorVersion > candidate->minorVersion))) {
- componentUrl = resolveLocalUrl(QString(url + c.typeName + dotqml_string), c.fileName);
- if (c.internal && base) {
- if (resolveLocalUrl(*base, c.fileName) != componentUrl)
- continue; // failed attempt to access an internal type
- }
- if (base && (*base == componentUrl)) {
- if (typeRecursionDetected)
- *typeRecursionDetected = true;
- continue; // no recursion
+ if (base) {
+ componentUrl = resolveLocalUrl(QString(url + c.typeName + dotqml_string), c.fileName);
+ if (c.internal) {
+ if (resolveLocalUrl(*base, c.fileName) != componentUrl)
+ continue; // failed attempt to access an internal type
+ }
+ if (*base == componentUrl) {
+ if (typeRecursionDetected)
+ *typeRecursionDetected = true;
+ continue; // no recursion
+ }
}
// This is our best candidate so far
@@ -702,9 +762,11 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
}
if (candidate != end) {
+ if (!base) // ensure we have a componentUrl
+ componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName);
int major = vmajor ? *vmajor : -1;
int minor = vminor ? *vminor : -1;
- QQmlType *returnType = getTypeForUrl(componentUrl, type, isCompositeSingleton, 0,
+ QQmlType *returnType = fetchOrCreateTypeForUrl(componentUrl, type, isCompositeSingleton, 0,
major, minor);
if (type_return)
*type_return = returnType;
@@ -732,7 +794,7 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
if (typeRecursionDetected)
*typeRecursionDetected = true;
} else {
- QQmlType *returnType = getTypeForUrl(qmlUrl, type, false, 0);
+ QQmlType *returnType = fetchOrCreateTypeForUrl(qmlUrl, type, false, 0);
if (type_return)
*type_return = returnType;
return returnType != 0;
@@ -777,7 +839,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
return true;
if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) {
// qualified, and only 1 url
- *type_return = getTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors);
+ *type_return = fetchOrCreateTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors);
return (*type_return != 0);
}
}
@@ -785,9 +847,9 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
return false;
}
-QQmlImportNamespace::Import *QQmlImportNamespace::findImport(const QString &uri) const
+QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const
{
- for (Import *import : imports) {
+ for (QQmlImportInstance *import : imports) {
if (import->uri == uri)
return import;
}
@@ -800,13 +862,13 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
{
bool typeRecursionDetected = false;
for (int i=0; i<imports.count(); ++i) {
- const Import *import = imports.at(i);
+ const QQmlImportInstance *import = imports.at(i);
if (import->resolveType(typeLoader, type, vmajor, vminor, type_return,
base, &typeRecursionDetected)) {
if (qmlCheckTypes()) {
// check for type clashes
for (int j = i+1; j<imports.count(); ++j) {
- const Import *import2 = imports.at(j);
+ const QQmlImportInstance *import2 = imports.at(j);
if (import2->resolveType(typeLoader, type, vmajor, vminor, 0, base)) {
if (errors) {
QString u1 = import->url;
@@ -949,10 +1011,12 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
}
#endif
+#if defined(QT_SHARED) || !QT_CONFIG(library)
static inline QString msgCannotLoadPlugin(const QString &uri, const QString &why)
{
return QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri, why);
}
+#endif
/*!
Import an extension defined by a qmldir file.
@@ -963,7 +1027,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
const QString &uri,
int vmaj, int vmin,
QQmlImportDatabase *database,
- const QQmlTypeLoader::QmldirContent *qmldir,
+ const QQmlTypeLoaderQmldirContent *qmldir,
QList<QQmlError> *errors)
{
#if QT_CONFIG(library)
@@ -1099,7 +1163,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
}
bool QQmlImportsPrivate::getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- const QQmlTypeLoader::QmldirContent **qmldir, QList<QQmlError> *errors)
+ const QQmlTypeLoaderQmldirContent **qmldir, QList<QQmlError> *errors)
{
Q_ASSERT(errors);
Q_ASSERT(qmldir);
@@ -1224,7 +1288,7 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ
return false;
}
-bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoader::QmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
+bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
QList<QQmlError> *errors)
{
int lowest_min = INT_MAX;
@@ -1307,7 +1371,7 @@ QQmlImportNamespace *QQmlImportsPrivate::importNamespace(const QString &prefix)
return nameSpace;
}
-QQmlImportNamespace::Import *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace *nameSpace,
+QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace *nameSpace,
const QString &uri, const QString &url, int vmaj, int vmin,
QV4::CompiledData::Import::ImportType type,
QList<QQmlError> *errors, bool lowPrecedence)
@@ -1317,7 +1381,7 @@ QQmlImportNamespace::Import *QQmlImportsPrivate::addImportToNamespace(QQmlImport
Q_UNUSED(errors);
Q_ASSERT(url.isEmpty() || url.endsWith(Slash));
- QQmlImportNamespace::Import *import = new QQmlImportNamespace::Import;
+ QQmlImportInstance *import = new QQmlImportInstance;
import->uri = uri;
import->url = url;
import->majversion = vmaj;
@@ -1343,11 +1407,11 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre
QQmlImportNamespace *nameSpace = importNamespace(prefix);
Q_ASSERT(nameSpace);
- QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QV4::CompiledData::Import::ImportLibrary, errors);
+ QQmlImportInstance *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QV4::CompiledData::Import::ImportLibrary, errors);
Q_ASSERT(inserted);
if (!incomplete) {
- const QQmlTypeLoader::QmldirContent *qmldir = 0;
+ const QQmlTypeLoaderQmldirContent *qmldir = 0;
if (!qmldirIdentifier.isEmpty()) {
if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
@@ -1444,11 +1508,11 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
if (!url.endsWith(Slash) && !url.endsWith(Backslash))
url += Slash;
- QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport);
+ QQmlImportInstance *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport);
Q_ASSERT(inserted);
if (!incomplete && !qmldirIdentifier.isEmpty()) {
- const QQmlTypeLoader::QmldirContent *qmldir = 0;
+ const QQmlTypeLoaderQmldirContent *qmldir = 0;
if (!getQmldirContent(qmldirIdentifier, importUri, &qmldir, errors))
return false;
@@ -1471,8 +1535,8 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &
QQmlImportNamespace *nameSpace = importNamespace(prefix);
Q_ASSERT(nameSpace);
- if (QQmlImportNamespace::Import *import = nameSpace->findImport(uri)) {
- const QQmlTypeLoader::QmldirContent *qmldir = 0;
+ if (QQmlImportInstance *import = nameSpace->findImport(uri)) {
+ const QQmlTypeLoaderQmldirContent *qmldir = 0;
if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
return false;
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 0e7848730f..7c691a468c 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -68,6 +68,48 @@ class QQmlImportNamespace;
class QQmlImportsPrivate;
class QQmlImportDatabase;
class QQmlTypeLoader;
+class QQmlTypeLoaderQmldirContent;
+
+struct QQmlImportInstance
+{
+ QString uri; // e.g. QtQuick
+ QString url; // the base path of the import
+ int majversion; // the major version imported
+ int minversion; // the minor version imported
+ bool isLibrary; // true means that this is not a file import
+ QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir
+ QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir
+
+ bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent *qmldir,
+ QQmlImportNamespace *nameSpace, QList<QQmlError> *errors);
+
+ static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin);
+
+ bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
+ int *vmajor, int *vminor, QQmlType** type_return,
+ QString *base = 0, bool *typeRecursionDetected = 0) const;
+};
+
+class QQmlImportNamespace
+{
+public:
+ QQmlImportNamespace() : nextNamespace(0) {}
+ ~QQmlImportNamespace() { qDeleteAll(imports); }
+
+ QList<QQmlImportInstance *> imports;
+
+ QQmlImportInstance *findImport(const QString &uri) const;
+
+ bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
+ int *vmajor, int *vminor, QQmlType** type_return,
+ QString *base = 0, QList<QQmlError> *errors = 0);
+
+ // Prefix when used as a qualified import. Otherwise empty.
+ QHashedString prefix;
+
+ // Used by QQmlImportsPrivate::qualifiedSets
+ QQmlImportNamespace *nextNamespace;
+};
class Q_QML_PRIVATE_EXPORT QQmlImports
{
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index 3876e774c3..712da78807 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -56,10 +56,17 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(QQmlLocaleData);
+#define THROW_ERROR(string) \
+ do { \
+ scope.result = scope.engine->throwError(QString::fromUtf8(string)); \
+ return; \
+ } while (false)
+
+
#define GET_LOCALE_DATA_RESOURCE(OBJECT) \
QV4::Scoped<QQmlLocaleData> r(scope, OBJECT.as<QQmlLocaleData>()); \
if (!r) \
- V4THROW_ERROR("Not a valid Locale object")
+ THROW_ERROR("Not a valid Locale object")
static bool isLocaleObject(const QV4::Value &val)
{
@@ -80,215 +87,219 @@ void QQmlDateExtension::registerExtension(QV4::ExecutionEngine *engine)
engine->dateCtor()->defineDefaultProperty(QStringLiteral("timeZoneUpdated"), method_timeZoneUpdated);
}
-QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ctx)
+void QQmlDateExtension::method_toLocaleString(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() > 2)
- return QV4::DatePrototype::method_toLocaleString(ctx);
-
- QV4::Scope scope(ctx);
+ if (callData->argc > 2) {
+ QV4::DatePrototype::method_toLocaleString(b, scope, callData);
+ return;
+ }
- QV4::DateObject *date = ctx->thisObject().as<DateObject>();
- if (!date)
- return QV4::DatePrototype::method_toLocaleString(ctx);
+ QV4::DateObject *date = callData->thisObject.as<DateObject>();
+ if (!date) {
+ QV4::DatePrototype::method_toLocaleString(b, scope, callData);
+ return;
+ }
QDateTime dt = date->toQDateTime();
- if (ctx->argc() == 0) {
+ if (callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->d()->engine->newString(locale.toString(dt))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(locale.toString(dt)));
}
- if (!isLocaleObject(ctx->args()[0]))
- return QV4::DatePrototype::method_toLocaleString(ctx); // Use the default Date toLocaleString()
+ if (!isLocaleObject(callData->args[0])) {
+ QV4::DatePrototype::method_toLocaleString(b, scope, callData); // Use the default Date toLocaleString()
+ return;
+ }
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QString formattedDt;
- if (ctx->argc() == 2) {
- if (String *s = ctx->args()[1].stringValue()) {
+ if (callData->argc == 2) {
+ if (String *s = callData->args[1].stringValue()) {
QString format = s->toQString();
formattedDt = r->d()->locale->toString(dt, format);
- } else if (ctx->args()[1].isNumber()) {
- quint32 intFormat = ctx->args()[1].toNumber();
+ } else if (callData->args[1].isNumber()) {
+ quint32 intFormat = callData->args[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
formattedDt = r->d()->locale->toString(dt, format);
} else {
- V4THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format");
+ THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format");
}
} else {
formattedDt = r->d()->locale->toString(dt, enumFormat);
}
- return ctx->d()->engine->newString(formattedDt)->asReturnedValue();
+ scope.result = scope.engine->newString(formattedDt);
}
-QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::CallContext *ctx)
+void QQmlDateExtension::method_toLocaleTimeString(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() > 2)
- return QV4::DatePrototype::method_toLocaleTimeString(ctx);
-
- QV4::Scope scope(ctx);
+ if (callData->argc > 2) {
+ QV4::DatePrototype::method_toLocaleTimeString(b, scope, callData);
+ return;
+ }
- QV4::DateObject *date = ctx->thisObject().as<DateObject>();
- if (!date)
- return QV4::DatePrototype::method_toLocaleTimeString(ctx);
+ QV4::DateObject *date = callData->thisObject.as<DateObject>();
+ if (!date) {
+ QV4::DatePrototype::method_toLocaleTimeString(b, scope, callData);
+ return;
+ }
QDateTime dt = date->toQDateTime();
QTime time = dt.time();
- if (ctx->argc() == 0) {
+ if (callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->d()->engine->newString(locale.toString(time))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(locale.toString(time)));
}
- if (!isLocaleObject(ctx->args()[0]))
- return QV4::DatePrototype::method_toLocaleTimeString(ctx); // Use the default Date toLocaleTimeString()
+ if (!isLocaleObject(callData->args[0]))
+ return QV4::DatePrototype::method_toLocaleTimeString(b, scope, callData); // Use the default Date toLocaleTimeString()
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QString formattedTime;
- if (ctx->argc() == 2) {
- if (String *s = ctx->args()[1].stringValue()) {
+ if (callData->argc == 2) {
+ if (String *s = callData->args[1].stringValue()) {
QString format = s->toQString();
formattedTime = r->d()->locale->toString(time, format);
- } else if (ctx->args()[1].isNumber()) {
- quint32 intFormat = ctx->args()[1].toNumber();
+ } else if (callData->args[1].isNumber()) {
+ quint32 intFormat = callData->args[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
formattedTime = r->d()->locale->toString(time, format);
} else {
- V4THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format");
+ THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format");
}
} else {
formattedTime = r->d()->locale->toString(time, enumFormat);
}
- return ctx->d()->engine->newString(formattedTime)->asReturnedValue();
+ scope.result = scope.engine->newString(formattedTime);
}
-QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext *ctx)
+void QQmlDateExtension::method_toLocaleDateString(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() > 2)
- return QV4::DatePrototype::method_toLocaleDateString(ctx);
-
- QV4::Scope scope(ctx);
+ if (callData->argc > 2) {
+ QV4::DatePrototype::method_toLocaleDateString(b, scope, callData);
+ return;
+ }
- QV4::DateObject *dateObj = ctx->thisObject().as<DateObject>();
- if (!dateObj)
- return QV4::DatePrototype::method_toLocaleDateString(ctx);
+ QV4::DateObject *dateObj = callData->thisObject.as<DateObject>();
+ if (!dateObj) {
+ QV4::DatePrototype::method_toLocaleDateString(b, scope, callData);
+ return;
+ }
QDateTime dt = dateObj->toQDateTime();
QDate date = dt.date();
- if (ctx->argc() == 0) {
+ if (callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->d()->engine->newString(locale.toString(date))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(locale.toString(date)));
}
- if (!isLocaleObject(ctx->args()[0]))
- return QV4::DatePrototype::method_toLocaleDateString(ctx); // Use the default Date toLocaleDateString()
+ if (!isLocaleObject(callData->args[0]))
+ return QV4::DatePrototype::method_toLocaleDateString(b, scope, callData); // Use the default Date toLocaleDateString()
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QString formattedDate;
- if (ctx->argc() == 2) {
- if (String *s = ctx->args()[1].stringValue()) {
+ if (callData->argc == 2) {
+ if (String *s = callData->args[1].stringValue()) {
QString format = s->toQString();
formattedDate = r->d()->locale->toString(date, format);
- } else if (ctx->args()[1].isNumber()) {
- quint32 intFormat = ctx->args()[1].toNumber();
+ } else if (callData->args[1].isNumber()) {
+ quint32 intFormat = callData->args[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
formattedDate = r->d()->locale->toString(date, format);
} else {
- V4THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format");
+ THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format");
}
} else {
formattedDate = r->d()->locale->toString(date, enumFormat);
}
- return ctx->d()->engine->newString(formattedDate)->asReturnedValue();
+ scope.result = scope.engine->newString(formattedDate);
}
-QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::CallContext *ctx)
+void QQmlDateExtension::method_fromLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::ExecutionEngine * const engine = ctx->d()->engine;
- if (ctx->argc() == 1) {
- if (String *s = ctx->args()[0].stringValue()) {
+ QV4::ExecutionEngine * const engine = scope.engine;
+ if (callData->argc == 1) {
+ if (String *s = callData->args[0].stringValue()) {
QLocale locale;
QString dateString = s->toQString();
QDateTime dt = locale.toDateTime(dateString);
- return QV4::Encode(engine->newDateObject(dt));
+ RETURN_RESULT(engine->newDateObject(dt));
}
}
- QV4::Scope scope(ctx);
-
- if (ctx->argc() < 1 || ctx->argc() > 3 || !isLocaleObject(ctx->args()[0]))
- V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments");
+ if (callData->argc < 1 || callData->argc > 3 || !isLocaleObject(callData->args[0]))
+ THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QDateTime dt;
- QString dateString = ctx->args()[1].toQStringNoThrow();
- if (ctx->argc() == 3) {
- if (String *s = ctx->args()[2].stringValue()) {
+ QString dateString = callData->args[1].toQStringNoThrow();
+ if (callData->argc == 3) {
+ if (String *s = callData->args[2].stringValue()) {
QString format = s->toQString();
dt = r->d()->locale->toDateTime(dateString, format);
- } else if (ctx->args()[2].isNumber()) {
- quint32 intFormat = ctx->args()[2].toNumber();
+ } else if (callData->args[2].isNumber()) {
+ quint32 intFormat = callData->args[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
dt = r->d()->locale->toDateTime(dateString, format);
} else {
- V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format");
+ THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format");
}
} else {
dt = r->d()->locale->toDateTime(dateString, enumFormat);
}
- return QV4::Encode(engine->newDateObject(dt));
+ scope.result = engine->newDateObject(dt);
}
-QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallContext *ctx)
+void QQmlDateExtension::method_fromLocaleTimeString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::ExecutionEngine * const engine = ctx->d()->engine;
+ QV4::ExecutionEngine * const engine = scope.engine;
- if (ctx->argc() == 1) {
- if (String *s = ctx->args()[0].stringValue()) {
+ if (callData->argc == 1) {
+ if (String *s = callData->args[0].stringValue()) {
QLocale locale;
QString timeString = s->toQString();
QTime time = locale.toTime(timeString);
QDateTime dt = QDateTime::currentDateTime();
dt.setTime(time);
- return QV4::Encode(engine->newDateObject(dt));
+ RETURN_RESULT(engine->newDateObject(dt));
}
}
- if (ctx->argc() < 1 || ctx->argc() > 3 || !isLocaleObject(ctx->args()[0]))
- V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments");
-
- QV4::Scope scope(ctx);
+ if (callData->argc < 1 || callData->argc > 3 || !isLocaleObject(callData->args[0]))
+ THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QTime tm;
- QString dateString = ctx->args()[1].toQStringNoThrow();
- if (ctx->argc() == 3) {
- if (String *s = ctx->args()[2].stringValue()) {
+ QString dateString = callData->args[1].toQStringNoThrow();
+ if (callData->argc == 3) {
+ if (String *s = callData->args[2].stringValue()) {
QString format = s->toQString();
tm = r->d()->locale->toTime(dateString, format);
- } else if (ctx->args()[2].isNumber()) {
- quint32 intFormat = ctx->args()[2].toNumber();
+ } else if (callData->args[2].isNumber()) {
+ quint32 intFormat = callData->args[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
tm = r->d()->locale->toTime(dateString, format);
} else {
- V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format");
+ THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format");
}
} else {
tm = r->d()->locale->toTime(dateString, enumFormat);
@@ -300,58 +311,56 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallConte
dt.setTime(tm);
}
- return QV4::Encode(engine->newDateObject(dt));
+ RETURN_RESULT(engine->newDateObject(dt));
}
-QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::CallContext *ctx)
+void QQmlDateExtension::method_fromLocaleDateString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::ExecutionEngine * const engine = ctx->d()->engine;
+ QV4::ExecutionEngine * const engine = scope.engine;
- if (ctx->argc() == 1) {
- if (String *s = ctx->args()[0].stringValue()) {
+ if (callData->argc == 1) {
+ if (String *s = callData->args[0].stringValue()) {
QLocale locale;
QString dateString = s->toQString();
QDate date = locale.toDate(dateString);
- return QV4::Encode(engine->newDateObject(QDateTime(date)));
+ RETURN_RESULT(engine->newDateObject(QDateTime(date)));
}
}
- if (ctx->argc() < 1 || ctx->argc() > 3 || !isLocaleObject(ctx->args()[0]))
- V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments");
+ if (callData->argc < 1 || callData->argc > 3 || !isLocaleObject(callData->args[0]))
+ THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments");
- QV4::Scope scope(ctx);
-
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QDate dt;
- QString dateString = ctx->args()[1].toQStringNoThrow();
- if (ctx->argc() == 3) {
- if (String *s = ctx->args()[2].stringValue()) {
+ QString dateString = callData->args[1].toQStringNoThrow();
+ if (callData->argc == 3) {
+ if (String *s = callData->args[2].stringValue()) {
QString format = s->toQString();
dt = r->d()->locale->toDate(dateString, format);
- } else if (ctx->args()[2].isNumber()) {
- quint32 intFormat = ctx->args()[2].toNumber();
+ } else if (callData->args[2].isNumber()) {
+ quint32 intFormat = callData->args[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
dt = r->d()->locale->toDate(dateString, format);
} else {
- V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format");
+ THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format");
}
} else {
dt = r->d()->locale->toDate(dateString, enumFormat);
}
- return QV4::Encode(engine->newDateObject(QDateTime(dt)));
+ RETURN_RESULT(engine->newDateObject(QDateTime(dt)));
}
-QV4::ReturnedValue QQmlDateExtension::method_timeZoneUpdated(QV4::CallContext *ctx)
+void QQmlDateExtension::method_timeZoneUpdated(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 0)
- V4THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments");
+ if (callData->argc != 0)
+ THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments");
QV4::DatePrototype::timezoneUpdated();
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
//-----------------
@@ -364,148 +373,143 @@ void QQmlNumberExtension::registerExtension(QV4::ExecutionEngine *engine)
engine->numberCtor()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString);
}
-QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::CallContext *ctx)
+void QQmlNumberExtension::method_toLocaleString(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() > 3)
- V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ if (callData->argc > 3)
+ THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- double number = ctx->thisObject().toNumber();
+ double number = callData->thisObject.toNumber();
- if (ctx->argc() == 0) {
+ if (callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->d()->engine->newString(locale.toString(number))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(locale.toString(number)));
}
- if (!isLocaleObject(ctx->args()[0]))
- return QV4::NumberPrototype::method_toLocaleString(ctx); // Use the default Number toLocaleString()
-
- QV4::Scope scope(ctx);
+ if (!isLocaleObject(callData->args[0])) {
+ QV4::NumberPrototype::method_toLocaleString(b, scope, callData); // Use the default Number toLocaleString()
+ return;
+ }
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
quint16 format = 'f';
- if (ctx->argc() > 1) {
- if (!ctx->args()[1].isString())
- V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- QString fs = ctx->args()[1].toQString();
+ if (callData->argc > 1) {
+ if (!callData->args[1].isString())
+ THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ QString fs = callData->args[1].toQString();
if (fs.length())
format = fs.at(0).unicode();
}
int prec = 2;
- if (ctx->argc() > 2) {
- if (!ctx->args()[2].isNumber())
- V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- prec = ctx->args()[2].toInt32();
+ if (callData->argc > 2) {
+ if (!callData->args[2].isNumber())
+ THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ prec = callData->args[2].toInt32();
}
- return ctx->d()->engine->newString(r->d()->locale->toString(number, (char)format, prec))->asReturnedValue();
+ scope.result = scope.engine->newString(r->d()->locale->toString(number, (char)format, prec));
}
-QV4::ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(QV4::CallContext *ctx)
+void QQmlNumberExtension::method_toLocaleCurrencyString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() > 2)
- V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
+ if (callData->argc > 2)
+ THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
- double number = ctx->thisObject().toNumber();
+ double number = callData->thisObject.toNumber();
- if (ctx->argc() == 0) {
+ if (callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->d()->engine->newString(locale.toString(number))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(locale.toString(number)));
}
- if (!isLocaleObject(ctx->args()[0]))
- V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
-
- QV4::Scope scope(ctx);
+ if (!isLocaleObject(callData->args[0]))
+ THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QString symbol;
- if (ctx->argc() > 1) {
- if (!ctx->args()[1].isString())
- V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- symbol = ctx->args()[1].toQStringNoThrow();
+ if (callData->argc > 1) {
+ if (!callData->args[1].isString())
+ THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ symbol = callData->args[1].toQStringNoThrow();
}
- return ctx->d()->engine->newString(r->d()->locale->toCurrencyString(number, symbol))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(r->d()->locale->toCurrencyString(number, symbol)));
}
-QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext *ctx)
+void QQmlNumberExtension::method_fromLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1 || ctx->argc() > 2)
- V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
+ if (callData->argc < 1 || callData->argc > 2)
+ THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
int numberIdx = 0;
QLocale locale;
- QV4::Scope scope(ctx);
-
- if (ctx->argc() == 2) {
- if (!isLocaleObject(ctx->args()[0]))
- V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
+ if (callData->argc == 2) {
+ if (!isLocaleObject(callData->args[0]))
+ THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
locale = *r->d()->locale;
numberIdx = 1;
}
- QString ns = ctx->args()[numberIdx].toQString();
+ QString ns = callData->args[numberIdx].toQString();
if (!ns.length())
- return QV4::Encode(Q_QNAN);
+ RETURN_RESULT(QV4::Encode(Q_QNAN));
bool ok = false;
double val = locale.toDouble(ns, &ok);
if (!ok)
- V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid format")
+ THROW_ERROR("Locale: Number.fromLocaleString(): Invalid format");
- return QV4::Encode(val);
+ scope.result = QV4::Encode(val);
}
//--------------
// Locale object
-QV4::ReturnedValue QQmlLocaleData::method_get_firstDayOfWeek(QV4::CallContext *ctx)
+void QQmlLocaleData::method_get_firstDayOfWeek(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QLocale *locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(scope, callData);
if (!locale)
- return QV4::Encode::undefined();
+ return;
int fdow = int(locale->firstDayOfWeek());
if (fdow == 7)
fdow = 0; // Qt::Sunday = 7, but Sunday is 0 in JS Date
- return QV4::Encode(fdow);
+ scope.result = QV4::Encode(fdow);
}
-QV4::ReturnedValue QQmlLocaleData::method_get_measurementSystem(QV4::CallContext *ctx)
+void QQmlLocaleData::method_get_measurementSystem(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QLocale *locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(scope, callData);
if (!locale)
- return QV4::Encode::undefined();
- return QV4::Encode(locale->measurementSystem());
+ return;
+ scope.result = QV4::Encode(locale->measurementSystem());
}
-QV4::ReturnedValue QQmlLocaleData::method_get_textDirection(QV4::CallContext *ctx)
+void QQmlLocaleData::method_get_textDirection(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QLocale *locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(scope, callData);
if (!locale)
- return QV4::Encode::undefined();
+ return;
- return QV4::Encode(locale->textDirection());
+ scope.result = QV4::Encode(locale->textDirection());
}
-QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::CallContext *ctx)
+void QQmlLocaleData::method_get_weekDays(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QLocale *locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(scope, callData);
if (!locale)
- return QV4::Encode::undefined();
+ return;
QList<Qt::DayOfWeek> days = locale->weekdays();
- QV4::ScopedArrayObject result(scope, ctx->d()->engine->newArrayObject());
+ QV4::ScopedArrayObject result(scope, scope.engine->newArrayObject());
result->arrayReserve(days.size());
for (int i = 0; i < days.size(); ++i) {
int day = days.at(i);
@@ -515,59 +519,58 @@ QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::CallContext *ctx)
}
result->setArrayLengthUnchecked(days.size());
- return result.asReturnedValue();
+ scope.result = result.asReturnedValue();
}
-QV4::ReturnedValue QQmlLocaleData::method_get_uiLanguages(QV4::CallContext *ctx)
+void QQmlLocaleData::method_get_uiLanguages(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QLocale *locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(scope, callData);
if (!locale)
- return QV4::Encode::undefined();
+ return;
QStringList langs = locale->uiLanguages();
- QV4::ScopedArrayObject result(scope, ctx->d()->engine->newArrayObject());
+ QV4::ScopedArrayObject result(scope, scope.engine->newArrayObject());
result->arrayReserve(langs.size());
QV4::ScopedValue v(scope);
for (int i = 0; i < langs.size(); ++i)
- result->arrayPut(i, (v = ctx->d()->engine->newString(langs.at(i))));
+ result->arrayPut(i, (v = scope.engine->newString(langs.at(i))));
result->setArrayLengthUnchecked(langs.size());
- return result.asReturnedValue();
+ scope.result = result.asReturnedValue();
}
-QV4::ReturnedValue QQmlLocaleData::method_currencySymbol(QV4::CallContext *ctx)
+void QQmlLocaleData::method_currencySymbol(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QLocale *locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(scope, callData);
if (!locale)
- return QV4::Encode::undefined();
+ return;
- if (ctx->argc() > 1)
- V4THROW_ERROR("Locale: currencySymbol(): Invalid arguments");
+ if (callData->argc > 1)
+ THROW_ERROR("Locale: currencySymbol(): Invalid arguments");
QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol;
- if (ctx->argc() == 1) {
- quint32 intFormat = ctx->args()[0].toNumber();
+ if (callData->argc == 1) {
+ quint32 intFormat = callData->args[0].toNumber();
format = QLocale::CurrencySymbolFormat(intFormat);
}
- return ctx->d()->engine->newString(locale->currencySymbol(format))->asReturnedValue();
+ scope.result = scope.engine->newString(locale->currencySymbol(format));
}
#define LOCALE_FORMAT(FUNC) \
-QV4::ReturnedValue QQmlLocaleData::method_ ##FUNC (QV4::CallContext *ctx) { \
- QLocale *locale = getThisLocale(ctx); \
+void QQmlLocaleData::method_ ##FUNC (const BuiltinFunction *, Scope &scope, CallData *callData) { \
+ QLocale *locale = getThisLocale(scope, callData); \
if (!locale) \
- return QV4::Encode::undefined(); \
- if (ctx->argc() > 1) \
- V4THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \
+ return; \
+ if (callData->argc > 1) \
+ THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \
QLocale::FormatType format = QLocale::LongFormat;\
- if (ctx->argc() == 1) { \
- quint32 intFormat = ctx->args()[0].toUInt32(); \
+ if (callData->argc == 1) { \
+ quint32 intFormat = callData->args[0].toUInt32(); \
format = QLocale::FormatType(intFormat); \
} \
- return ctx->engine()->newString(locale-> FUNC (format))->asReturnedValue(); \
+ scope.result = scope.engine->newString(locale-> FUNC (format)); \
}
LOCALE_FORMAT(dateTimeFormat)
@@ -576,57 +579,57 @@ LOCALE_FORMAT(dateFormat)
// +1 added to idx because JS is 0-based, whereas QLocale months begin at 1.
#define LOCALE_FORMATTED_MONTHNAME(VARIABLE) \
-QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) {\
- QLocale *locale = getThisLocale(ctx); \
+void QQmlLocaleData::method_ ## VARIABLE (const BuiltinFunction *, Scope &scope, CallData *callData) {\
+ QLocale *locale = getThisLocale(scope, callData); \
if (!locale) \
- return QV4::Encode::undefined(); \
- if (ctx->argc() < 1 || ctx->argc() > 2) \
- V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
+ return; \
+ if (callData->argc < 1 || callData->argc > 2) \
+ THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
QLocale::FormatType enumFormat = QLocale::LongFormat; \
- int idx = ctx->args()[0].toInt32() + 1; \
+ int idx = callData->args[0].toInt32() + 1; \
if (idx < 1 || idx > 12) \
- V4THROW_ERROR("Locale: Invalid month"); \
+ THROW_ERROR("Locale: Invalid month"); \
QString name; \
- if (ctx->argc() == 2) { \
- if (ctx->args()[1].isNumber()) { \
- quint32 intFormat = ctx->args()[1].toUInt32(); \
+ if (callData->argc == 2) { \
+ if (callData->args[1].isNumber()) { \
+ quint32 intFormat = callData->args[1].toUInt32(); \
QLocale::FormatType format = QLocale::FormatType(intFormat); \
name = locale-> VARIABLE(idx, format); \
} else { \
- V4THROW_ERROR("Locale: Invalid datetime format"); \
+ THROW_ERROR("Locale: Invalid datetime format"); \
} \
} else { \
name = locale-> VARIABLE(idx, enumFormat); \
} \
- return ctx->engine()->newString(name)->asReturnedValue(); \
+ scope.result = scope.engine->newString(name); \
}
// 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
#define LOCALE_FORMATTED_DAYNAME(VARIABLE) \
-QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) {\
- QLocale *locale = getThisLocale(ctx); \
+void QQmlLocaleData::method_ ## VARIABLE (const BuiltinFunction *, Scope &scope, CallData *callData) {\
+ QLocale *locale = getThisLocale(scope, callData); \
if (!locale) \
- return QV4::Encode::undefined(); \
- if (ctx->argc() < 1 || ctx->argc() > 2) \
- V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
+ return; \
+ if (callData->argc < 1 || callData->argc > 2) \
+ THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
QLocale::FormatType enumFormat = QLocale::LongFormat; \
- int idx = ctx->args()[0].toInt32(); \
+ int idx = callData->args[0].toInt32(); \
if (idx < 0 || idx > 7) \
- V4THROW_ERROR("Locale: Invalid day"); \
+ THROW_ERROR("Locale: Invalid day"); \
if (idx == 0) idx = 7; \
QString name; \
- if (ctx->argc() == 2) { \
- if (ctx->args()[1].isNumber()) { \
- quint32 intFormat = ctx->args()[1].toUInt32(); \
+ if (callData->argc == 2) { \
+ if (callData->args[1].isNumber()) { \
+ quint32 intFormat = callData->args[1].toUInt32(); \
QLocale::FormatType format = QLocale::FormatType(intFormat); \
name = locale-> VARIABLE(idx, format); \
} else { \
- V4THROW_ERROR("Locale: Invalid datetime format"); \
+ THROW_ERROR("Locale: Invalid datetime format"); \
} \
} else { \
name = locale-> VARIABLE(idx, enumFormat); \
} \
- return ctx->engine()->newString(name)->asReturnedValue(); \
+ scope.result = scope.engine->newString(name); \
}
LOCALE_FORMATTED_MONTHNAME(monthName)
@@ -634,12 +637,12 @@ LOCALE_FORMATTED_MONTHNAME(standaloneMonthName)
LOCALE_FORMATTED_DAYNAME(dayName)
LOCALE_FORMATTED_DAYNAME(standaloneDayName)
-#define LOCALE_STRING_PROPERTY(VARIABLE) QV4::ReturnedValue QQmlLocaleData::method_get_ ## VARIABLE (QV4::CallContext* ctx) \
+#define LOCALE_STRING_PROPERTY(VARIABLE) void QQmlLocaleData::method_get_ ## VARIABLE (const BuiltinFunction *, Scope &scope, CallData *callData) \
{ \
- QLocale *locale = getThisLocale(ctx); \
+ QLocale *locale = getThisLocale(scope, callData); \
if (!locale) \
- return QV4::Encode::undefined(); \
- return ctx->engine()->newString(locale-> VARIABLE())->asReturnedValue();\
+ return; \
+ scope.result = scope.engine->newString(locale-> VARIABLE());\
}
LOCALE_STRING_PROPERTY(name)
@@ -830,18 +833,22 @@ void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine)
engine->stringPrototype()->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare);
}
-QV4::ReturnedValue QQmlLocale::method_localeCompare(QV4::CallContext *ctx)
+void QQmlLocale::method_localeCompare(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1 || (!ctx->args()[0].isString() && !ctx->args()[0].as<StringObject>()))
- return QV4::StringPrototype::method_localeCompare(ctx);
+ if (callData->argc != 1 || (!callData->args[0].isString() && !callData->args[0].as<StringObject>())) {
+ QV4::StringPrototype::method_localeCompare(b, scope, callData);
+ return;
+ }
- if (!ctx->thisObject().isString() && !ctx->thisObject().as<StringObject>())
- return QV4::StringPrototype::method_localeCompare(ctx);
+ if (!callData->thisObject.isString() && !callData->thisObject.as<StringObject>()) {
+ QV4::StringPrototype::method_localeCompare(b, scope, callData);
+ return;
+ }
- QString thisString = ctx->thisObject().toQStringNoThrow();
- QString thatString = ctx->args()[0].toQStringNoThrow();
+ QString thisString = callData->thisObject.toQStringNoThrow();
+ QString thatString = callData->args[0].toQStringNoThrow();
- return QV4::Encode(QString::localeAwareCompare(thisString, thatString));
+ scope.result = QV4::Encode(QString::localeAwareCompare(thisString, thatString));
}
/*!
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 275f58db7d..1a2ffc72b0 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -67,13 +67,13 @@ public:
static void registerExtension(QV4::ExecutionEngine *engine);
private:
- static QV4::ReturnedValue method_toLocaleString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_toLocaleTimeString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_toLocaleDateString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_fromLocaleString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_fromLocaleTimeString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_fromLocaleDateString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_timeZoneUpdated(QV4::CallContext *ctx);
+ static void method_toLocaleString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_toLocaleTimeString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_toLocaleDateString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_fromLocaleString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_fromLocaleTimeString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_fromLocaleDateString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_timeZoneUpdated(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
@@ -83,9 +83,9 @@ public:
static void registerExtension(QV4::ExecutionEngine *engine);
private:
- static QV4::ReturnedValue method_toLocaleString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_fromLocaleString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_toLocaleCurrencyString(QV4::CallContext *ctx);
+ static void method_toLocaleString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_fromLocaleString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_toLocaleCurrencyString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
@@ -135,7 +135,7 @@ public:
private:
QQmlLocale();
- static QV4::ReturnedValue method_localeCompare(QV4::CallContext *ctx);
+ static void method_localeCompare(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
namespace QV4 {
@@ -158,43 +158,43 @@ struct QQmlLocaleData : public QV4::Object
V4_OBJECT2(QQmlLocaleData, Object)
V4_NEEDS_DESTROY
- static QLocale *getThisLocale(QV4::CallContext *ctx) {
- QV4::Object *o = ctx->thisObject().as<Object>();
+ static QLocale *getThisLocale(QV4::Scope &scope, QV4::CallData *callData) {
+ QV4::Object *o = callData->thisObject.as<Object>();
QQmlLocaleData *thisObject = o ? o->as<QQmlLocaleData>() : 0;
if (!thisObject) {
- ctx->engine()->throwTypeError();
+ scope.engine->throwTypeError();
return 0;
}
return thisObject->d()->locale;
}
- static QV4::ReturnedValue method_currencySymbol(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_dateTimeFormat(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_timeFormat(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_dateFormat(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_monthName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_standaloneMonthName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_dayName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_standaloneDayName(QV4::CallContext *ctx);
-
- static QV4::ReturnedValue method_get_firstDayOfWeek(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_measurementSystem(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_textDirection(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_weekDays(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_uiLanguages(QV4::CallContext *ctx);
-
- static QV4::ReturnedValue method_get_name(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_nativeLanguageName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_nativeCountryName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_decimalPoint(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_groupSeparator(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_percent(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_zeroDigit(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_negativeSign(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_positiveSign(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_exponential(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_amText(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_pmText(QV4::CallContext *ctx);
+ static void method_currencySymbol(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_dateTimeFormat(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_timeFormat(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_dateFormat(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_monthName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_standaloneMonthName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_dayName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_standaloneDayName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ static void method_get_firstDayOfWeek(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_measurementSystem(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_textDirection(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_weekDays(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_uiLanguages(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ static void method_get_name(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_nativeLanguageName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_nativeCountryName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_decimalPoint(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_groupSeparator(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_percent(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_zeroDigit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_negativeSign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_positiveSign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_exponential(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_amText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_pmText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
}
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 520c44f4da..bd6b9a1599 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -79,7 +79,7 @@ struct QQmlMetaTypeData
Files urlToNonFileImportType; // For non-file imported composite and composite
// singleton types. This way we can locate any
// of them by url, even if it was registered as
- // a module via qmlRegisterCompositeType.
+ // a module via QQmlPrivate::RegisterCompositeType
typedef QHash<const QMetaObject *, QQmlType *> MetaObjects;
MetaObjects metaObjectToType;
typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 38a16b8cde..85fbd86dc4 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -170,7 +170,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
context = new QQmlContextData;
context->isInternal = true;
- context->imports = compilationUnit->importCache;
+ context->imports = compilationUnit->typeNameCache;
context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex);
context->setParent(parentContext);
@@ -1150,7 +1150,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
customParser->engine = QQmlEnginePrivate::get(engine);
- customParser->imports = compilationUnit->importCache;
+ customParser->imports = compilationUnit->typeNameCache;
QList<const QV4::CompiledData::Binding *> bindings;
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 562aa1c88a..88ce2fa1b9 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -76,7 +76,8 @@ public:
int argumentsValid:1;
QList<QByteArray> *names;
- int arguments[0];
+
+ int arguments[1];
};
// Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
@@ -919,7 +920,7 @@ static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int argc, const QList<QByteArray> &names)
{
typedef QQmlPropertyCacheMethodArguments A;
- A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
+ A *args = static_cast<A *>(malloc(sizeof(A) + (argc) * sizeof(int)));
args->arguments[0] = argc;
args->argumentsValid = false;
args->signalParameterStringForJS = 0;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 5b1bba46dd..f4f04e12c0 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1362,7 +1362,7 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::Compile
if (!importQualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
- const QmldirContent *qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
+ const QQmlTypeLoaderQmldirContent *qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
const auto qmldirScripts = qmldir->scripts();
for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
@@ -1410,7 +1410,7 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
if (!importQualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
- const QmldirContent *qmldir = typeLoader()->qmldirContent(qmldirFilePath);
+ const QQmlTypeLoaderQmldirContent *qmldir = typeLoader()->qmldirContent(qmldirFilePath);
const auto qmldirScripts = qmldir->scripts();
for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
@@ -1539,57 +1539,57 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlE
}
-QQmlTypeLoader::QmldirContent::QmldirContent()
+QQmlTypeLoaderQmldirContent::QQmlTypeLoaderQmldirContent()
{
}
-bool QQmlTypeLoader::QmldirContent::hasError() const
+bool QQmlTypeLoaderQmldirContent::hasError() const
{
return m_parser.hasError();
}
-QList<QQmlError> QQmlTypeLoader::QmldirContent::errors(const QString &uri) const
+QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const
{
return m_parser.errors(uri);
}
-QString QQmlTypeLoader::QmldirContent::typeNamespace() const
+QString QQmlTypeLoaderQmldirContent::typeNamespace() const
{
return m_parser.typeNamespace();
}
-void QQmlTypeLoader::QmldirContent::setContent(const QString &location, const QString &content)
+void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
{
m_location = location;
m_parser.parse(content);
}
-void QQmlTypeLoader::QmldirContent::setError(const QQmlError &error)
+void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error)
{
m_parser.setError(error);
}
-QQmlDirComponents QQmlTypeLoader::QmldirContent::components() const
+QQmlDirComponents QQmlTypeLoaderQmldirContent::components() const
{
return m_parser.components();
}
-QQmlDirScripts QQmlTypeLoader::QmldirContent::scripts() const
+QQmlDirScripts QQmlTypeLoaderQmldirContent::scripts() const
{
return m_parser.scripts();
}
-QQmlDirPlugins QQmlTypeLoader::QmldirContent::plugins() const
+QQmlDirPlugins QQmlTypeLoaderQmldirContent::plugins() const
{
return m_parser.plugins();
}
-QString QQmlTypeLoader::QmldirContent::pluginLocation() const
+QString QQmlTypeLoaderQmldirContent::pluginLocation() const
{
return m_location;
}
-bool QQmlTypeLoader::QmldirContent::designerSupported() const
+bool QQmlTypeLoaderQmldirContent::designerSupported() const
{
return m_parser.designerSupported();
}
@@ -1861,13 +1861,13 @@ bool QQmlTypeLoader::directoryExists(const QString &path)
/*!
-Return a QmldirContent for absoluteFilePath. The QmldirContent may be cached.
+Return a QQmlTypeLoaderQmldirContent for absoluteFilePath. The QQmlTypeLoaderQmldirContent may be cached.
\a filePath is a local file path.
It can also be a remote path for a remote directory import, but it will have been cached by now in this case.
*/
-const QQmlTypeLoader::QmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePathIn)
+const QQmlTypeLoaderQmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePathIn)
{
QUrl url(filePathIn); //May already contain http scheme
if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https"))
@@ -1883,10 +1883,10 @@ const QQmlTypeLoader::QmldirContent *QQmlTypeLoader::qmldirContent(const QString
else
filePath = url.path();
- QmldirContent *qmldir;
- QmldirContent **val = m_importQmlDirCache.value(filePath);
+ QQmlTypeLoaderQmldirContent *qmldir;
+ QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(filePath);
if (!val) {
- qmldir = new QmldirContent;
+ qmldir = new QQmlTypeLoaderQmldirContent;
#define ERROR(description) { QQmlError e; e.setDescription(description); qmldir->setError(e); }
#define NOT_READABLE_ERROR QString(QLatin1String("module \"$$URI$$\" definition \"%1\" not readable"))
@@ -1916,12 +1916,12 @@ const QQmlTypeLoader::QmldirContent *QQmlTypeLoader::qmldirContent(const QString
void QQmlTypeLoader::setQmldirContent(const QString &url, const QString &content)
{
- QmldirContent *qmldir;
- QmldirContent **val = m_importQmlDirCache.value(url);
+ QQmlTypeLoaderQmldirContent *qmldir;
+ QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(url);
if (val) {
qmldir = *val;
} else {
- qmldir = new QmldirContent;
+ qmldir = new QQmlTypeLoaderQmldirContent;
m_importQmlDirCache.insert(url, qmldir);
}
@@ -2075,6 +2075,11 @@ bool QQmlTypeData::tryLoadFromDiskCache()
}
}
+ if (unit->data->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
+ restoreIR(unit);
+ return true;
+ }
+
m_compiledData = unit;
for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
@@ -2127,11 +2132,11 @@ bool QQmlTypeData::tryLoadFromDiskCache()
return true;
}
-void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
{
Q_ASSERT(m_compiledData);
- m_compiledData->importCache = importCache;
+ m_compiledData->typeNameCache = typeNameCache;
m_compiledData->resolvedTypes = resolvedTypeCache;
QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
@@ -2217,10 +2222,10 @@ void QQmlTypeData::done()
}
}
- QQmlRefPointer<QQmlTypeNameCache> importCache;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
{
- QQmlCompileError error = buildTypeResolutionCaches(&importCache, &resolvedTypeCache);
+ QQmlCompileError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
if (error.isSet()) {
setError(error);
return;
@@ -2240,9 +2245,9 @@ void QQmlTypeData::done()
if (!m_document.isNull()) {
// Compile component
- compile(importCache, resolvedTypeCache);
+ compile(typeNameCache, resolvedTypeCache);
} else {
- createTypeAndPropertyCaches(importCache, resolvedTypeCache);
+ createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
}
if (isError())
@@ -2303,7 +2308,7 @@ void QQmlTypeData::done()
qualifier = qualifier.mid(lastDotIndex+1);
}
- m_compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
+ m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
QQmlScriptData *scriptData = script.script->scriptData();
scriptData->addref();
m_compiledData->dependentScripts << scriptData;
@@ -2397,6 +2402,15 @@ bool QQmlTypeData::loadFromSource()
return true;
}
+void QQmlTypeData::restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit)
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ QmlIR::IRLoader loader(unit->data, m_document.data());
+ loader.load();
+ m_document->javaScriptCompilationUnit = unit;
+ continueLoadFromIR();
+}
+
void QQmlTypeData::continueLoadFromIR()
{
m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
@@ -2489,12 +2503,12 @@ QString QQmlTypeData::stringAt(int index) const
return m_document->jsGenerator.stringTable.stringForIndex(index);
}
-void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
+void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
{
Q_ASSERT(m_compiledData.isNull());
QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
- QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), importCache, resolvedTypeCache);
+ QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache);
m_compiledData = compiler.compile();
if (!m_compiledData) {
setError(compiler.compilationErrors());
@@ -2598,20 +2612,20 @@ void QQmlTypeData::resolveTypes()
}
QQmlCompileError QQmlTypeData::buildTypeResolutionCaches(
- QQmlRefPointer<QQmlTypeNameCache> *importCache,
+ QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
) const
{
- importCache->adopt(new QQmlTypeNameCache);
+ typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
for (const QString &ns: m_namespaces)
- (*importCache)->add(ns);
+ (*typeNameCache)->add(ns);
// Add any Composite Singletons that were used to the import cache
for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
- (*importCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
+ (*typeNameCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
- m_importCache.populateCache(*importCache);
+ m_importCache.populateCache(*typeNameCache);
QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
@@ -2710,7 +2724,7 @@ void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData:
}
QQmlScriptData::QQmlScriptData()
- : importCache(0)
+ : typeNameCache(0)
, m_loaded(false)
, m_program(0)
{
@@ -2767,8 +2781,8 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
// For backward compatibility, if there are no imports, we need to use the
// imports from the parent context. See QTBUG-17518.
- if (!importCache->isEmpty()) {
- ctxt->imports = importCache;
+ if (!typeNameCache->isEmpty()) {
+ ctxt->imports = typeNameCache;
} else if (effectiveCtxt) {
ctxt->imports = effectiveCtxt->imports;
ctxt->importedScripts = effectiveCtxt->importedScripts;
@@ -2823,9 +2837,9 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
void QQmlScriptData::clear()
{
- if (importCache) {
- importCache->release();
- importCache = 0;
+ if (typeNameCache) {
+ typeNameCache->release();
+ typeNameCache = 0;
}
for (int ii = 0; ii < scripts.count(); ++ii)
@@ -2946,7 +2960,7 @@ void QQmlScriptBlob::done()
}
}
- m_scriptData->importCache = new QQmlTypeNameCache();
+ m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache);
QSet<QString> ns;
@@ -2958,13 +2972,13 @@ void QQmlScriptBlob::done()
if (!script.nameSpace.isNull()) {
if (!ns.contains(script.nameSpace)) {
ns.insert(script.nameSpace);
- m_scriptData->importCache->add(script.nameSpace);
+ m_scriptData->typeNameCache->add(script.nameSpace);
}
}
- m_scriptData->importCache->add(script.qualifier, scriptIndex, script.nameSpace);
+ m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
}
- m_importCache.populateCache(m_scriptData->importCache);
+ m_importCache.populateCache(m_scriptData->typeNameCache);
}
QString QQmlScriptBlob::stringAt(int index) const
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index c60435a2d6..915b1bcc4c 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -218,6 +218,34 @@ private:
class QQmlTypeLoaderThread;
+class QQmlTypeLoaderQmldirContent
+{
+private:
+ friend class QQmlTypeLoader;
+ QQmlTypeLoaderQmldirContent();
+
+ void setContent(const QString &location, const QString &content);
+ void setError(const QQmlError &);
+
+public:
+ bool hasError() const;
+ QList<QQmlError> errors(const QString &uri) const;
+
+ QString typeNamespace() const;
+
+ QQmlDirComponents components() const;
+ QQmlDirScripts scripts() const;
+ QQmlDirPlugins plugins() const;
+
+ QString pluginLocation() const;
+
+ bool designerSupported() const;
+
+private:
+ QQmlDirParser m_parser;
+ QString m_location;
+};
+
class Q_AUTOTEST_EXPORT QQmlTypeLoader
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader)
@@ -256,34 +284,6 @@ public:
QList<QQmlQmldirData *> m_qmldirs;
};
- class QmldirContent
- {
- private:
- friend class QQmlTypeLoader;
- QmldirContent();
-
- void setContent(const QString &location, const QString &content);
- void setError(const QQmlError &);
-
- public:
- bool hasError() const;
- QList<QQmlError> errors(const QString &uri) const;
-
- QString typeNamespace() const;
-
- QQmlDirComponents components() const;
- QQmlDirScripts scripts() const;
- QQmlDirPlugins plugins() const;
-
- QString pluginLocation() const;
-
- bool designerSupported() const;
-
- private:
- QQmlDirParser m_parser;
- QString m_location;
- };
-
QQmlTypeLoader(QQmlEngine *);
~QQmlTypeLoader();
@@ -298,7 +298,7 @@ public:
QString absoluteFilePath(const QString &path);
bool directoryExists(const QString &path);
- const QmldirContent *qmldirContent(const QString &filePath);
+ const QQmlTypeLoaderQmldirContent *qmldirContent(const QString &filePath);
void setQmldirContent(const QString &filePath, const QString &content);
void clearCache();
@@ -363,7 +363,7 @@ private:
typedef QHash<QUrl, QQmlQmldirData *> QmldirCache;
typedef QStringHash<bool> StringSet;
typedef QStringHash<StringSet*> ImportDirCache;
- typedef QStringHash<QmldirContent *> ImportQmlDirCache;
+ typedef QStringHash<QQmlTypeLoaderQmldirContent *> ImportQmlDirCache;
QQmlEngine *m_engine;
QQmlTypeLoaderThread *m_thread;
@@ -446,15 +446,16 @@ protected:
private:
bool tryLoadFromDiskCache();
bool loadFromSource();
+ void restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit);
void continueLoadFromIR();
void resolveTypes();
QQmlCompileError buildTypeResolutionCaches(
- QQmlRefPointer<QQmlTypeNameCache> *importCache,
+ QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
) const;
- void compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
- void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref, int lineNumber = -1, int columnNumber = -1, bool reportErrors = true);
@@ -504,7 +505,7 @@ public:
QUrl url;
QString urlString;
- QQmlTypeNameCache *importCache;
+ QQmlTypeNameCache *typeNameCache;
QList<QQmlScriptBlob *> scripts;
QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index c2098bc9a1..c8e2b92c29 100644
--- a/src/qml/qml/qqmltypenamecache.cpp
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -43,7 +43,8 @@
QT_BEGIN_NAMESPACE
-QQmlTypeNameCache::QQmlTypeNameCache()
+QQmlTypeNameCache::QQmlTypeNameCache(const QQmlImports &importCache)
+ : m_imports(importCache)
{
}
@@ -70,6 +71,7 @@ void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex,
{
Import import;
import.scriptIndex = importedScriptIndex;
+ import.m_qualifier = name;
if (nameSpace.length() != 0) {
Import *i = m_namedImports.value(nameSpace);
@@ -94,6 +96,18 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name)
if (!result.isValid())
result = query(m_anonymousCompositeSingletons, name);
+ if (!result.isValid()) {
+ // Look up anonymous types from the imports of this document
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+ QQmlType *t = 0;
+ bool typeFound = m_imports.resolveType(name, &t, 0, 0, &typeNamespace, &errors);
+ if (typeFound) {
+ return Result(t);
+ }
+
+ }
+
return result;
}
@@ -109,6 +123,20 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name,
if (!result.isValid())
result = query(i->compositeSingletons, name);
+ if (!result.isValid()) {
+ // Look up types from the imports of this document
+ // ### it would be nice if QQmlImports allowed us to resolve a namespace
+ // first, and then types on it.
+ QString qualifiedTypeName = i->m_qualifier + QLatin1Char('.') + name.toString();
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+ QQmlType *t = 0;
+ bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, 0, 0, &typeNamespace, &errors);
+ if (typeFound) {
+ return Result(t);
+ }
+ }
+
return result;
}
@@ -122,6 +150,19 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) cons
if (!result.isValid())
result = query(m_anonymousCompositeSingletons, name);
+ if (!result.isValid()) {
+ // Look up anonymous types from the imports of this document
+ QString typeName = name->toQStringNoThrow();
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+ QQmlType *t = 0;
+ bool typeFound = m_imports.resolveType(typeName, &t, 0, 0, &typeNamespace, &errors);
+ if (typeFound) {
+ return Result(t);
+ }
+
+ }
+
return result;
}
@@ -143,6 +184,20 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, cons
if (!r.isValid())
r = query(i->compositeSingletons, name);
+ if (!r.isValid()) {
+ // Look up types from the imports of this document
+ // ### it would be nice if QQmlImports allowed us to resolve a namespace
+ // first, and then types on it.
+ QString qualifiedTypeName = i->m_qualifier + QLatin1Char('.') + name->toQStringNoThrow();
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+ QQmlType *t = 0;
+ bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, 0, 0, &typeNamespace, &errors);
+ if (typeFound) {
+ return Result(t);
+ }
+ }
+
return r;
}
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h
index 8a387bed5f..7cdcbe91b6 100644
--- a/src/qml/qml/qqmltypenamecache_p.h
+++ b/src/qml/qml/qqmltypenamecache_p.h
@@ -56,6 +56,7 @@
#include "qqmlmetatype_p.h"
#include <private/qhashedstring_p.h>
+#include <private/qqmlimport_p.h>
#include <QtCore/qvector.h>
@@ -66,7 +67,7 @@ class QQmlEngine;
class QQmlTypeNameCache : public QQmlRefCount
{
public:
- QQmlTypeNameCache();
+ QQmlTypeNameCache(const QQmlImports &imports);
virtual ~QQmlTypeNameCache();
inline bool isEmpty() const;
@@ -105,6 +106,9 @@ private:
// Or, imported compositeSingletons
QStringHash<QUrl> compositeSingletons;
+
+ // The qualifier of this import
+ QString m_qualifier;
};
template<typename Key>
@@ -112,6 +116,7 @@ private:
{
Import *i = imports.value(key);
if (i) {
+ Q_ASSERT(!i->m_qualifier.isEmpty());
if (i->scriptIndex != -1) {
return Result(i->scriptIndex);
} else {
@@ -151,6 +156,7 @@ private:
QMap<const Import *, QStringHash<Import> > m_namespacedImports;
QVector<QQmlTypeModuleVersion> m_anonymousImports;
QStringHash<QUrl> m_anonymousCompositeSingletons;
+ QQmlImports m_imports;
};
QQmlTypeNameCache::Result::Result()
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 6ce52bb9e5..44b612e7d2 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -312,18 +312,18 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
return true;
}
-ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx)
+void QQmlValueTypeWrapper::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Object *o = ctx->thisObject().as<Object>();
+ Object *o = callData->thisObject.as<Object>();
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
QQmlValueTypeWrapper *w = o->as<QQmlValueTypeWrapper>();
if (!w)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (QQmlValueTypeReference *ref = w->as<QQmlValueTypeReference>())
if (!ref->readReferenceValue())
- return Encode::undefined();
+ RETURN_UNDEFINED();
QString result;
// Prepare a buffer to pass to QMetaType::convert()
@@ -346,7 +346,7 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx)
}
result += QLatin1Char(')');
}
- return Encode(ctx->engine()->newString(result));
+ scope.result = scope.engine->newString(result);
}
ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *hasProperty)
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index fec54df770..87f9116056 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -111,7 +111,7 @@ public:
static PropertyAttributes query(const Managed *, String *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
- static QV4::ReturnedValue method_toString(CallContext *ctx);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
static void initProto(ExecutionEngine *v4);
};
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 545daa96f8..490a4e19ab 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -325,9 +325,12 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
if (compiledObject->nProperties || compiledObject->nFunctions) {
Q_ASSERT(cache && cache->engine);
QV4::ExecutionEngine *v4 = cache->engine;
- QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, compiledObject->nProperties + compiledObject->nFunctions);
- propertyAndMethodStorage.set(v4, data);
- std::fill(data->data, data->data + data->size, QV4::Encode::undefined());
+ uint size = compiledObject->nProperties + compiledObject->nFunctions;
+ if (size) {
+ QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, size);
+ propertyAndMethodStorage.set(v4, data);
+ std::fill(data->data, data->data + data->size, QV4::Encode::undefined());
+ }
// Need JS wrapper to ensure properties/methods are marked.
ensureQObjectWrapper();
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 22c3c49c58..d0d9f080da 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -71,10 +71,12 @@ using namespace QV4;
#if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network)
-#define V4THROW_REFERENCE(string) { \
- ScopedObject error(scope, ctx->engine()->newReferenceErrorObject(QStringLiteral(string))); \
- return ctx->engine()->throwError(error); \
- }
+#define V4THROW_REFERENCE(string) \
+ do { \
+ ScopedObject error(scope, scope.engine->newReferenceErrorObject(QStringLiteral(string))); \
+ scope.result = scope.engine->throwError(error); \
+ return; \
+ } while (false)
QT_BEGIN_NAMESPACE
@@ -274,25 +276,25 @@ public:
static void initClass(ExecutionEngine *engine);
// JS API
- static ReturnedValue method_get_nodeName(CallContext *ctx);
- static ReturnedValue method_get_nodeValue(CallContext *ctx);
- static ReturnedValue method_get_nodeType(CallContext *ctx);
- static ReturnedValue method_get_namespaceUri(CallContext *ctx);
-
- static ReturnedValue method_get_parentNode(CallContext *ctx);
- static ReturnedValue method_get_childNodes(CallContext *ctx);
- static ReturnedValue method_get_firstChild(CallContext *ctx);
- static ReturnedValue method_get_lastChild(CallContext *ctx);
- static ReturnedValue method_get_previousSibling(CallContext *ctx);
- static ReturnedValue method_get_nextSibling(CallContext *ctx);
- static ReturnedValue method_get_attributes(CallContext *ctx);
-
- //static ReturnedValue ownerDocument(CallContext *ctx);
- //static ReturnedValue namespaceURI(CallContext *ctx);
- //static ReturnedValue prefix(CallContext *ctx);
- //static ReturnedValue localName(CallContext *ctx);
- //static ReturnedValue baseURI(CallContext *ctx);
- //static ReturnedValue textContent(CallContext *ctx);
+ static void method_get_nodeName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_nodeValue(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_nodeType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_namespaceUri(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ static void method_get_parentNode(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_childNodes(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_firstChild(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_lastChild(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_previousSibling(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_nextSibling(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_attributes(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ //static void ownerDocument(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ //static void namespaceURI(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ //static void prefix(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ //static void localName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ //static void baseURI(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ //static void textContent(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
static ReturnedValue getProto(ExecutionEngine *v4);
@@ -353,12 +355,12 @@ class Attr : public Node
{
public:
// JS API
- static ReturnedValue method_name(CallContext *ctx);
-// static ReturnedValue specified(CallContext *);
- static ReturnedValue method_value(CallContext *ctx);
- static ReturnedValue method_ownerElement(CallContext *ctx);
-// static ReturnedValue schemaTypeInfo(CallContext *);
-// static ReturnedValue isId(CallContext *c);
+ static void method_name(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+// static void specified(CallContext *);
+ static void method_value(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_ownerElement(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+// static void schemaTypeInfo(CallContext *);
+// static void isId(CallContext *c);
// C++ API
static ReturnedValue prototype(ExecutionEngine *);
@@ -368,7 +370,7 @@ class CharacterData : public Node
{
public:
// JS API
- static ReturnedValue method_length(CallContext *ctx);
+ static void method_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
// C++ API
static ReturnedValue prototype(ExecutionEngine *v4);
@@ -378,8 +380,8 @@ class Text : public CharacterData
{
public:
// JS API
- static ReturnedValue method_isElementContentWhitespace(CallContext *ctx);
- static ReturnedValue method_wholeText(CallContext *ctx);
+ static void method_isElementContentWhitespace(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_wholeText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
// C++ API
static ReturnedValue prototype(ExecutionEngine *);
@@ -396,10 +398,10 @@ class Document : public Node
{
public:
// JS API
- static ReturnedValue method_xmlVersion(CallContext *ctx);
- static ReturnedValue method_xmlEncoding(CallContext *ctx);
- static ReturnedValue method_xmlStandalone(CallContext *ctx);
- static ReturnedValue method_documentElement(CallContext *ctx);
+ static void method_xmlVersion(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_xmlEncoding(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_xmlStandalone(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_documentElement(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
// C++ API
static ReturnedValue prototype(ExecutionEngine *);
@@ -418,12 +420,11 @@ void NodeImpl::release()
document->release();
}
-ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx)
+void NodePrototype::method_get_nodeName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
QString name;
switch (r->d()->d->type) {
@@ -440,15 +441,14 @@ ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx)
name = r->d()->d->name;
break;
}
- return Encode(ctx->d()->engine->newString(name));
+ scope.result = Encode(scope.engine->newString(name));
}
-ReturnedValue NodePrototype::method_get_nodeValue(CallContext *ctx)
+void NodePrototype::method_get_nodeValue(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (r->d()->d->type == NodeImpl::Document ||
r->d()->d->type == NodeImpl::DocumentFragment ||
@@ -457,135 +457,128 @@ ReturnedValue NodePrototype::method_get_nodeValue(CallContext *ctx)
r->d()->d->type == NodeImpl::Entity ||
r->d()->d->type == NodeImpl::EntityReference ||
r->d()->d->type == NodeImpl::Notation)
- return Encode::null();
+ RETURN_RESULT(Encode::null());
- return Encode(ctx->d()->engine->newString(r->d()->d->data));
+ scope.result = Encode(scope.engine->newString(r->d()->d->data));
}
-ReturnedValue NodePrototype::method_get_nodeType(CallContext *ctx)
+void NodePrototype::method_get_nodeType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(r->d()->d->type);
+ scope.result = Encode(r->d()->d->type);
}
-ReturnedValue NodePrototype::method_get_namespaceUri(CallContext *ctx)
+void NodePrototype::method_get_namespaceUri(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(ctx->d()->engine->newString(r->d()->d->namespaceUri));
+ scope.result = Encode(scope.engine->newString(r->d()->d->namespaceUri));
}
-ReturnedValue NodePrototype::method_get_parentNode(CallContext *ctx)
+void NodePrototype::method_get_parentNode(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (r->d()->d->parent)
- return Node::create(scope.engine, r->d()->d->parent);
+ scope.result = Node::create(scope.engine, r->d()->d->parent);
else
- return Encode::null();
+ scope.result = Encode::null();
}
-ReturnedValue NodePrototype::method_get_childNodes(CallContext *ctx)
+void NodePrototype::method_get_childNodes(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return NodeList::create(scope.engine, r->d()->d);
+ scope.result = NodeList::create(scope.engine, r->d()->d);
}
-ReturnedValue NodePrototype::method_get_firstChild(CallContext *ctx)
+void NodePrototype::method_get_firstChild(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (r->d()->d->children.isEmpty())
- return Encode::null();
+ scope.result = Encode::null();
else
- return Node::create(scope.engine, r->d()->d->children.constFirst());
+ scope.result = Node::create(scope.engine, r->d()->d->children.constFirst());
}
-ReturnedValue NodePrototype::method_get_lastChild(CallContext *ctx)
+void NodePrototype::method_get_lastChild(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (r->d()->d->children.isEmpty())
- return Encode::null();
+ scope.result = Encode::null();
else
- return Node::create(scope.engine, r->d()->d->children.constLast());
+ scope.result = Node::create(scope.engine, r->d()->d->children.constLast());
}
-ReturnedValue NodePrototype::method_get_previousSibling(CallContext *ctx)
+void NodePrototype::method_get_previousSibling(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (!r->d()->d->parent)
- return Encode::null();
+ RETURN_RESULT(Encode::null());
for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) {
if (r->d()->d->parent->children.at(ii) == r->d()->d) {
if (ii == 0)
- return Encode::null();
+ scope.result = Encode::null();
else
- return Node::create(scope.engine, r->d()->d->parent->children.at(ii - 1));
+ scope.result = Node::create(scope.engine, r->d()->d->parent->children.at(ii - 1));
+ return;
}
}
- return Encode::null();
+ scope.result = Encode::null();
}
-ReturnedValue NodePrototype::method_get_nextSibling(CallContext *ctx)
+void NodePrototype::method_get_nextSibling(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (!r->d()->d->parent)
- return Encode::null();
+ RETURN_RESULT(Encode::null());
for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) {
if (r->d()->d->parent->children.at(ii) == r->d()->d) {
if ((ii + 1) == r->d()->d->parent->children.count())
- return Encode::null();
+ scope.result = Encode::null();
else
- return Node::create(scope.engine, r->d()->d->parent->children.at(ii + 1));
+ scope.result = Node::create(scope.engine, r->d()->d->parent->children.at(ii + 1));
+ return;
}
}
- return Encode::null();
+ scope.result = Encode::null();
}
-ReturnedValue NodePrototype::method_get_attributes(CallContext *ctx)
+void NodePrototype::method_get_attributes(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (r->d()->d->type != NodeImpl::Element)
- return Encode::null();
+ scope.result = Encode::null();
else
- return NamedNodeMap::create(scope.engine, r->d()->d, r->d()->d->attributes);
+ scope.result = NamedNodeMap::create(scope.engine, r->d()->d, r->d()->d->attributes);
}
ReturnedValue NodePrototype::getProto(ExecutionEngine *v4)
@@ -666,44 +659,40 @@ ReturnedValue Attr::prototype(ExecutionEngine *engine)
return d->attrPrototype.value();
}
-ReturnedValue Attr::method_name(CallContext *ctx)
+void Attr::method_name(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return QV4::Encode(scope.engine->newString(r->d()->d->name));
+ scope.result = scope.engine->newString(r->d()->d->name);
}
-ReturnedValue Attr::method_value(CallContext *ctx)
+void Attr::method_value(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return QV4::Encode(scope.engine->newString(r->d()->d->data));
+ scope.result = scope.engine->newString(r->d()->d->data);
}
-ReturnedValue Attr::method_ownerElement(CallContext *ctx)
+void Attr::method_ownerElement(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return Node::create(scope.engine, r->d()->d->parent);
+ scope.result = Node::create(scope.engine, r->d()->d->parent);
}
-ReturnedValue CharacterData::method_length(CallContext *ctx)
+void CharacterData::method_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return Encode(r->d()->d->data.length());
+ scope.result = Encode(r->d()->d->data.length());
}
ReturnedValue CharacterData::prototype(ExecutionEngine *v4)
@@ -722,23 +711,22 @@ ReturnedValue CharacterData::prototype(ExecutionEngine *v4)
return d->characterDataPrototype.value();
}
-ReturnedValue Text::method_isElementContentWhitespace(CallContext *ctx)
+void Text::method_isElementContentWhitespace(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
- if (!r) return Encode::undefined();
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
+ if (!r)
+ RETURN_UNDEFINED();
- return Encode(QStringRef(&r->d()->d->data).trimmed().isEmpty());
+ scope.result = Encode(QStringRef(&r->d()->d->data).trimmed().isEmpty());
}
-ReturnedValue Text::method_wholeText(CallContext *ctx)
+void Text::method_wholeText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return QV4::Encode(scope.engine->newString(r->d()->d->data));
+ scope.result = scope.engine->newString(r->d()->d->data);
}
ReturnedValue Text::prototype(ExecutionEngine *v4)
@@ -964,44 +952,40 @@ ReturnedValue NodeList::create(ExecutionEngine *v4, NodeImpl *data)
return (v4->memoryManager->allocObject<NodeList>(data))->asReturnedValue();
}
-ReturnedValue Document::method_documentElement(CallContext *ctx)
+void Document::method_documentElement(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r || r->d()->d->type != NodeImpl::Document)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return Node::create(scope.engine, static_cast<DocumentImpl *>(r->d()->d)->root);
+ scope.result = Node::create(scope.engine, static_cast<DocumentImpl *>(r->d()->d)->root);
}
-ReturnedValue Document::method_xmlStandalone(CallContext *ctx)
+void Document::method_xmlStandalone(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r || r->d()->d->type != NodeImpl::Document)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return Encode(static_cast<DocumentImpl *>(r->d()->d)->isStandalone);
+ scope.result = Encode(static_cast<DocumentImpl *>(r->d()->d)->isStandalone);
}
-ReturnedValue Document::method_xmlVersion(CallContext *ctx)
+void Document::method_xmlVersion(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r || r->d()->d->type != NodeImpl::Document)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return QV4::Encode(scope.engine->newString(static_cast<DocumentImpl *>(r->d()->d)->version));
+ scope.result = scope.engine->newString(static_cast<DocumentImpl *>(r->d()->d)->version);
}
-ReturnedValue Document::method_xmlEncoding(CallContext *ctx)
+void Document::method_xmlEncoding(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r || r->d()->d->type != NodeImpl::Document)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return QV4::Encode(scope.engine->newString(static_cast<DocumentImpl *>(r->d()->d)->encoding));
+ scope.result = scope.engine->newString(static_cast<DocumentImpl *>(r->d()->d)->encoding);
}
class QQmlXMLHttpRequest : public QObject
@@ -1657,21 +1641,21 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
void setupProto();
- static ReturnedValue method_open(CallContext *ctx);
- static ReturnedValue method_setRequestHeader(CallContext *ctx);
- static ReturnedValue method_send(CallContext *ctx);
- static ReturnedValue method_abort(CallContext *ctx);
- static ReturnedValue method_getResponseHeader(CallContext *ctx);
- static ReturnedValue method_getAllResponseHeaders(CallContext *ctx);
-
- static ReturnedValue method_get_readyState(CallContext *ctx);
- static ReturnedValue method_get_status(CallContext *ctx);
- static ReturnedValue method_get_statusText(CallContext *ctx);
- static ReturnedValue method_get_responseText(CallContext *ctx);
- static ReturnedValue method_get_responseXML(CallContext *ctx);
- static ReturnedValue method_get_response(CallContext *ctx);
- static ReturnedValue method_get_responseType(CallContext *ctx);
- static ReturnedValue method_set_responseType(CallContext *ctx);
+ static void method_open(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_setRequestHeader(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_send(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_abort(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_getResponseHeader(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_getAllResponseHeaders(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ static void method_get_readyState(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_status(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_statusText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_responseText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_responseXML(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_response(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_responseType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_responseType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
}
@@ -1733,19 +1717,18 @@ void QQmlXMLHttpRequestCtor::setupProto()
// XMLHttpRequest methods
-ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_open(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- if (ctx->argc() < 2 || ctx->argc() > 5)
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (callData->argc < 2 || callData->argc > 5)
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
// Argument 0 - Method
- QString method = ctx->args()[0].toQStringNoThrow().toUpper();
+ QString method = callData->args[0].toQStringNoThrow().toUpper();
if (method != QLatin1String("GET") &&
method != QLatin1String("PUT") &&
method != QLatin1String("HEAD") &&
@@ -1754,26 +1737,26 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
method != QLatin1String("OPTIONS") &&
method != QLatin1String("PROPFIND") &&
method != QLatin1String("PATCH"))
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type");
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type");
// Argument 1 - URL
- QUrl url = QUrl(ctx->args()[1].toQStringNoThrow());
+ QUrl url = QUrl(callData->args[1].toQStringNoThrow());
if (url.isRelative())
url = scope.engine->callingQmlContext()->resolvedUrl(url);
bool async = true;
// Argument 2 - async (optional)
- if (ctx->argc() > 2) {
- async = ctx->args()[2].booleanValue();
+ if (callData->argc > 2) {
+ async = callData->args[2].booleanValue();
}
// Argument 3/4 - user/pass (optional)
QString username, password;
- if (ctx->argc() > 3)
- username = ctx->args()[3].toQStringNoThrow();
- if (ctx->argc() > 4)
- password = ctx->args()[4].toQStringNoThrow();
+ if (callData->argc > 3)
+ username = callData->args[3].toQStringNoThrow();
+ if (callData->argc > 4)
+ password = callData->args[4].toQStringNoThrow();
// Clear the fragment (if any)
url.setFragment(QString());
@@ -1782,25 +1765,24 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
if (!username.isNull()) url.setUserName(username);
if (!password.isNull()) url.setPassword(password);
- return r->open(w, scope.engine->callingQmlContext(), method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad);
+ scope.result = r->open(w, scope.engine->callingQmlContext(), method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad);
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_setRequestHeader(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- if (ctx->argc() != 2)
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (callData->argc != 2)
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
if (r->readyState() != QQmlXMLHttpRequest::Opened || r->sendFlag())
- V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
- QString name = ctx->args()[0].toQStringNoThrow();
- QString value = ctx->args()[1].toQStringNoThrow();
+ QString name = callData->args[0].toQStringNoThrow();
+ QString value = callData->args[1].toQStringNoThrow();
// ### Check that name and value are well formed
@@ -1825,148 +1807,139 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx)
nameUpper == QLatin1String("VIA") ||
nameUpper.startsWith(QLatin1String("PROXY-")) ||
nameUpper.startsWith(QLatin1String("SEC-")))
- return Encode::undefined();
+ RETURN_UNDEFINED();
r->addHeader(name, value);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_send(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_send(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
if (r->readyState() != QQmlXMLHttpRequest::Opened ||
r->sendFlag())
- V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
QByteArray data;
- if (ctx->argc() > 0)
- data = ctx->args()[0].toQStringNoThrow().toUtf8();
+ if (callData->argc > 0)
+ data = callData->args[0].toQStringNoThrow().toUtf8();
- return r->send(w, scope.engine->callingQmlContext(), data);
+ scope.result = r->send(w, scope.engine->callingQmlContext(), data);
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_abort(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_abort(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- return r->abort(w, scope.engine->callingQmlContext());
+ scope.result = r->abort(w, scope.engine->callingQmlContext());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_getResponseHeader(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- if (ctx->argc() != 1)
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (callData->argc != 1)
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done &&
r->readyState() != QQmlXMLHttpRequest::HeadersReceived)
- V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
- return QV4::Encode(scope.engine->newString(r->header(ctx->args()[0].toQStringNoThrow())));
+ scope.result = scope.engine->newString(r->header(callData->args[0].toQStringNoThrow()));
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- if (ctx->argc() != 0)
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (callData->argc != 0)
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done &&
r->readyState() != QQmlXMLHttpRequest::HeadersReceived)
- V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
- return QV4::Encode(scope.engine->newString(r->headers()));
+ scope.result = scope.engine->newString(r->headers());
}
// XMLHttpRequest properties
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_readyState(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_readyState(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- return Encode(r->readyState());
+ scope.result = Encode(r->readyState());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_status(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_status(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
if (r->readyState() == QQmlXMLHttpRequest::Unsent ||
r->readyState() == QQmlXMLHttpRequest::Opened)
- V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
if (r->errorFlag())
- return Encode(0);
+ scope.result = Encode(0);
else
- return Encode(r->replyStatus());
+ scope.result = Encode(r->replyStatus());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_statusText(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_statusText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
if (r->readyState() == QQmlXMLHttpRequest::Unsent ||
r->readyState() == QQmlXMLHttpRequest::Opened)
- V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
if (r->errorFlag())
- return QV4::Encode(scope.engine->newString(QString()));
+ scope.result = scope.engine->newString(QString());
else
- return QV4::Encode(scope.engine->newString(r->replyStatusText()));
+ scope.result = scope.engine->newString(r->replyStatusText());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseText(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_responseText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done)
- return QV4::Encode(scope.engine->newString(QString()));
+ scope.result = scope.engine->newString(QString());
else
- return QV4::Encode(scope.engine->newString(r->responseBody()));
+ scope.result = scope.engine->newString(r->responseBody());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_responseXML(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
@@ -1974,66 +1947,63 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(CallContext *ctx)
if (!r->receivedXml() ||
(r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done)) {
- return Encode::null();
+ scope.result = Encode::null();
} else {
if (r->responseType().isEmpty())
r->setResponseType(QLatin1String("document"));
- return r->xmlResponseBody(scope.engine);
+ scope.result = r->xmlResponseBody(scope.engine);
}
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_response(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_response(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done)
- return QV4::Encode(scope.engine->newString(QString()));
+ RETURN_RESULT(scope.engine->newString(QString()));
const QString& responseType = r->responseType();
if (responseType.compare(QLatin1String("text"), Qt::CaseInsensitive) == 0 || responseType.isEmpty()) {
- return QV4::Encode(scope.engine->newString(r->responseBody()));
+ RETURN_RESULT(scope.engine->newString(r->responseBody()));
} else if (responseType.compare(QLatin1String("arraybuffer"), Qt::CaseInsensitive) == 0) {
- return QV4::Encode(scope.engine->newArrayBuffer(r->rawResponseBody()));
+ RETURN_RESULT(scope.engine->newArrayBuffer(r->rawResponseBody()));
} else if (responseType.compare(QLatin1String("json"), Qt::CaseInsensitive) == 0) {
- return r->jsonResponseBody(scope.engine);
+ RETURN_RESULT(r->jsonResponseBody(scope.engine));
} else if (responseType.compare(QLatin1String("document"), Qt::CaseInsensitive) == 0) {
- return r->xmlResponseBody(scope.engine);
+ RETURN_RESULT(r->xmlResponseBody(scope.engine));
} else {
- return QV4::Encode(scope.engine->newString(QString()));
+ RETURN_RESULT(scope.engine->newString(QString()));
}
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseType(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_responseType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- return QV4::Encode(scope.engine->newString(r->responseType()));
+ scope.result = scope.engine->newString(r->responseType());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_set_responseType(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_set_responseType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- if (ctx->argc() < 1)
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (callData->argc < 1)
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
// Argument 0 - response type
- r->setResponseType(ctx->args()[0].toQStringNoThrow());
+ r->setResponseType(callData->args[0].toQStringNoThrow());
- return Encode::undefined();
+ scope.result = Encode::undefined();
}
void qt_rem_qmlxmlhttprequest(ExecutionEngine * /* engine */, void *d)
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 19dc100f40..d359a0f62f 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -85,6 +85,12 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(QtObject);
+#define THROW_TYPE_ERROR_WITH_MESSAGE(msg) \
+ do { \
+ scope.result = scope.engine->throwTypeError(QString::fromUtf8(msg)); \
+ return; \
+ } while (false)
+
struct StaticQtMetaObject : public QObject
{
static const QMetaObject *get()
@@ -223,12 +229,12 @@ void QtObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint
\qmlmethod bool Qt::isQtObject(object)
Returns true if \c object is a valid reference to a Qt or QML object, otherwise false.
*/
-ReturnedValue QtObject::method_isQtObject(QV4::CallContext *ctx)
+void QtObject::method_isQtObject(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() == 0)
- return QV4::Encode(false);
+ if (callData->argc == 0)
+ RETURN_RESULT(QV4::Encode(false));
- return QV4::Encode(ctx->args()[0].as<QV4::QObjectWrapper>() != 0);
+ scope.result = QV4::Encode(callData->args[0].as<QV4::QObjectWrapper>() != 0);
}
/*!
@@ -237,16 +243,16 @@ ReturnedValue QtObject::method_isQtObject(QV4::CallContext *ctx)
Returns a color with the specified \c red, \c green, \c blue and \c alpha components.
All components should be in the range 0-1 inclusive.
*/
-ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx)
+void QtObject::method_rgba(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- int argCount = ctx->argc();
+ int argCount = callData->argc;
if (argCount < 3 || argCount > 4)
- V4THROW_ERROR("Qt.rgba(): Invalid arguments");
+ THROW_GENERIC_ERROR("Qt.rgba(): Invalid arguments");
- double r = ctx->args()[0].toNumber();
- double g = ctx->args()[1].toNumber();
- double b = ctx->args()[2].toNumber();
- double a = (argCount == 4) ? ctx->args()[3].toNumber() : 1;
+ double r = callData->args[0].toNumber();
+ double g = callData->args[1].toNumber();
+ double b = callData->args[2].toNumber();
+ double a = (argCount == 4) ? callData->args[3].toNumber() : 1;
if (r < 0.0) r=0.0;
if (r > 1.0) r=1.0;
@@ -257,7 +263,7 @@ ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx)
if (a < 0.0) a=0.0;
if (a > 1.0) a=1.0;
- return ctx->engine()->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a));
+ scope.result = scope.engine->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a));
}
/*!
@@ -266,16 +272,16 @@ ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx)
Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components.
All components should be in the range 0-1 inclusive.
*/
-ReturnedValue QtObject::method_hsla(QV4::CallContext *ctx)
+void QtObject::method_hsla(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- int argCount = ctx->argc();
+ int argCount = callData->argc;
if (argCount < 3 || argCount > 4)
- V4THROW_ERROR("Qt.hsla(): Invalid arguments");
+ THROW_GENERIC_ERROR("Qt.hsla(): Invalid arguments");
- double h = ctx->args()[0].toNumber();
- double s = ctx->args()[1].toNumber();
- double l = ctx->args()[2].toNumber();
- double a = (argCount == 4) ? ctx->args()[3].toNumber() : 1;
+ double h = callData->args[0].toNumber();
+ double s = callData->args[1].toNumber();
+ double l = callData->args[2].toNumber();
+ double a = (argCount == 4) ? callData->args[3].toNumber() : 1;
if (h < 0.0) h=0.0;
if (h > 1.0) h=1.0;
@@ -286,7 +292,7 @@ ReturnedValue QtObject::method_hsla(QV4::CallContext *ctx)
if (a < 0.0) a=0.0;
if (a > 1.0) a=1.0;
- return ctx->engine()->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a));
+ scope.result = scope.engine->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a));
}
/*!
@@ -297,23 +303,23 @@ All components should be in the range 0-1 inclusive.
\since 5.5
*/
-ReturnedValue QtObject::method_hsva(QV4::CallContext *ctx)
+void QtObject::method_hsva(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- int argCount = ctx->argc();
+ int argCount = callData->argc;
if (argCount < 3 || argCount > 4)
- V4THROW_ERROR("Qt.hsva(): Invalid arguments");
+ THROW_GENERIC_ERROR("Qt.hsva(): Invalid arguments");
- double h = ctx->args()[0].toNumber();
- double s = ctx->args()[1].toNumber();
- double v = ctx->args()[2].toNumber();
- double a = (argCount == 4) ? ctx->args()[3].toNumber() : 1;
+ double h = callData->args[0].toNumber();
+ double s = callData->args[1].toNumber();
+ double v = callData->args[2].toNumber();
+ double a = (argCount == 4) ? callData->args[3].toNumber() : 1;
h = qBound(0.0, h, 1.0);
s = qBound(0.0, s, 1.0);
v = qBound(0.0, v, 1.0);
a = qBound(0.0, a, 1.0);
- return ctx->engine()->fromVariant(QQml_colorProvider()->fromHsvF(h, s, v, a));
+ scope.result = scope.engine->fromVariant(QQml_colorProvider()->fromHsvF(h, s, v, a));
}
/*!
@@ -324,35 +330,35 @@ may be either color values or string values. If a string value is supplied it
must be convertible to a color, as described for the \l{colorbasictypedocs}{color}
basic type.
*/
-ReturnedValue QtObject::method_colorEqual(QV4::CallContext *ctx)
+void QtObject::method_colorEqual(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 2)
- V4THROW_ERROR("Qt.colorEqual(): Invalid arguments");
+ if (callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments");
bool ok = false;
- QVariant lhs = ctx->d()->engine->toVariant(ctx->args()[0], -1);
+ QVariant lhs = scope.engine->toVariant(callData->args[0], -1);
if (lhs.userType() == QVariant::String) {
lhs = QQmlStringConverters::colorFromString(lhs.toString(), &ok);
if (!ok) {
- V4THROW_ERROR("Qt.colorEqual(): Invalid color name");
+ THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid color name");
}
} else if (lhs.userType() != QVariant::Color) {
- V4THROW_ERROR("Qt.colorEqual(): Invalid arguments");
+ THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments");
}
- QVariant rhs = ctx->engine()->toVariant(ctx->args()[1], -1);
+ QVariant rhs = scope.engine->toVariant(callData->args[1], -1);
if (rhs.userType() == QVariant::String) {
rhs = QQmlStringConverters::colorFromString(rhs.toString(), &ok);
if (!ok) {
- V4THROW_ERROR("Qt.colorEqual(): Invalid color name");
+ THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid color name");
}
} else if (rhs.userType() != QVariant::Color) {
- V4THROW_ERROR("Qt.colorEqual(): Invalid arguments");
+ THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments");
}
bool equal = (lhs == rhs);
- return QV4::Encode(equal);
+ scope.result = QV4::Encode(equal);
}
/*!
@@ -362,47 +368,47 @@ Returns a \c rect with the top-left corner at \c x, \c y and the specified \c wi
The returned object has \c x, \c y, \c width and \c height attributes with the given values.
*/
-ReturnedValue QtObject::method_rect(QV4::CallContext *ctx)
+void QtObject::method_rect(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 4)
- V4THROW_ERROR("Qt.rect(): Invalid arguments");
+ if (callData->argc != 4)
+ THROW_GENERIC_ERROR("Qt.rect(): Invalid arguments");
- double x = ctx->args()[0].toNumber();
- double y = ctx->args()[1].toNumber();
- double w = ctx->args()[2].toNumber();
- double h = ctx->args()[3].toNumber();
+ double x = callData->args[0].toNumber();
+ double y = callData->args[1].toNumber();
+ double w = callData->args[2].toNumber();
+ double h = callData->args[3].toNumber();
- return ctx->engine()->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
+ scope.result = scope.engine->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
}
/*!
\qmlmethod point Qt::point(int x, int y)
Returns a Point with the specified \c x and \c y coordinates.
*/
-ReturnedValue QtObject::method_point(QV4::CallContext *ctx)
+void QtObject::method_point(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 2)
- V4THROW_ERROR("Qt.point(): Invalid arguments");
+ if (callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.point(): Invalid arguments");
- double x = ctx->args()[0].toNumber();
- double y = ctx->args()[1].toNumber();
+ double x = callData->args[0].toNumber();
+ double y = callData->args[1].toNumber();
- return ctx->engine()->fromVariant(QVariant::fromValue(QPointF(x, y)));
+ scope.result = scope.engine->fromVariant(QVariant::fromValue(QPointF(x, y)));
}
/*!
\qmlmethod Qt::size(int width, int height)
Returns a Size with the specified \c width and \c height.
*/
-ReturnedValue QtObject::method_size(QV4::CallContext *ctx)
+void QtObject::method_size(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 2)
- V4THROW_ERROR("Qt.size(): Invalid arguments");
+ if (callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.size(): Invalid arguments");
- double w = ctx->args()[0].toNumber();
- double h = ctx->args()[1].toNumber();
+ double w = callData->args[0].toNumber();
+ double h = callData->args[1].toNumber();
- return ctx->engine()->fromVariant(QVariant::fromValue(QSizeF(w, h)));
+ scope.result = scope.engine->fromVariant(QVariant::fromValue(QSizeF(w, h)));
}
/*!
@@ -413,17 +419,17 @@ key-value pairs where valid keys are the \l{fontbasictypedocs}{font} type's
subproperty names, and the values are valid values for each subproperty.
Invalid keys will be ignored.
*/
-ReturnedValue QtObject::method_font(QV4::CallContext *ctx)
+void QtObject::method_font(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1 || !ctx->args()[0].isObject())
- V4THROW_ERROR("Qt.font(): Invalid arguments");
+ if (callData->argc != 1 || !callData->args[0].isObject())
+ THROW_GENERIC_ERROR("Qt.font(): Invalid arguments");
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV4Handle(ctx->args()[0]), v4, &ok);
+ QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV4Handle(callData->args[0]), v4, &ok);
if (!ok)
- V4THROW_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified");
- return ctx->engine()->fromVariant(v);
+ THROW_GENERIC_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified");
+ scope.result = scope.engine->fromVariant(v);
}
@@ -432,73 +438,73 @@ ReturnedValue QtObject::method_font(QV4::CallContext *ctx)
\qmlmethod Qt::vector2d(real x, real y)
Returns a Vector2D with the specified \c x and \c y.
*/
-ReturnedValue QtObject::method_vector2d(QV4::CallContext *ctx)
+void QtObject::method_vector2d(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 2)
- V4THROW_ERROR("Qt.vector2d(): Invalid arguments");
+ if (callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.vector2d(): Invalid arguments");
float xy[3]; // qvector2d uses float internally
- xy[0] = ctx->args()[0].toNumber();
- xy[1] = ctx->args()[1].toNumber();
+ xy[0] = callData->args[0].toNumber();
+ xy[1] = callData->args[1].toNumber();
const void *params[] = { xy };
- return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector2D, 1, params));
+ scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector2D, 1, params));
}
/*!
\qmlmethod Qt::vector3d(real x, real y, real z)
Returns a Vector3D with the specified \c x, \c y and \c z.
*/
-ReturnedValue QtObject::method_vector3d(QV4::CallContext *ctx)
+void QtObject::method_vector3d(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 3)
- V4THROW_ERROR("Qt.vector3d(): Invalid arguments");
+ if (callData->argc != 3)
+ THROW_GENERIC_ERROR("Qt.vector3d(): Invalid arguments");
float xyz[3]; // qvector3d uses float internally
- xyz[0] = ctx->args()[0].toNumber();
- xyz[1] = ctx->args()[1].toNumber();
- xyz[2] = ctx->args()[2].toNumber();
+ xyz[0] = callData->args[0].toNumber();
+ xyz[1] = callData->args[1].toNumber();
+ xyz[2] = callData->args[2].toNumber();
const void *params[] = { xyz };
- return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector3D, 1, params));
+ scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector3D, 1, params));
}
/*!
\qmlmethod Qt::vector4d(real x, real y, real z, real w)
Returns a Vector4D with the specified \c x, \c y, \c z and \c w.
*/
-ReturnedValue QtObject::method_vector4d(QV4::CallContext *ctx)
+void QtObject::method_vector4d(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 4)
- V4THROW_ERROR("Qt.vector4d(): Invalid arguments");
+ if (callData->argc != 4)
+ THROW_GENERIC_ERROR("Qt.vector4d(): Invalid arguments");
float xyzw[4]; // qvector4d uses float internally
- xyzw[0] = ctx->args()[0].toNumber();
- xyzw[1] = ctx->args()[1].toNumber();
- xyzw[2] = ctx->args()[2].toNumber();
- xyzw[3] = ctx->args()[3].toNumber();
+ xyzw[0] = callData->args[0].toNumber();
+ xyzw[1] = callData->args[1].toNumber();
+ xyzw[2] = callData->args[2].toNumber();
+ xyzw[3] = callData->args[3].toNumber();
const void *params[] = { xyzw };
- return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector4D, 1, params));
+ scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector4D, 1, params));
}
/*!
\qmlmethod Qt::quaternion(real scalar, real x, real y, real z)
Returns a Quaternion with the specified \c scalar, \c x, \c y, and \c z.
*/
-ReturnedValue QtObject::method_quaternion(QV4::CallContext *ctx)
+void QtObject::method_quaternion(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 4)
- V4THROW_ERROR("Qt.quaternion(): Invalid arguments");
+ if (callData->argc != 4)
+ THROW_GENERIC_ERROR("Qt.quaternion(): Invalid arguments");
qreal sxyz[4]; // qquaternion uses qreal internally
- sxyz[0] = ctx->args()[0].toNumber();
- sxyz[1] = ctx->args()[1].toNumber();
- sxyz[2] = ctx->args()[2].toNumber();
- sxyz[3] = ctx->args()[3].toNumber();
+ sxyz[0] = callData->args[0].toNumber();
+ sxyz[1] = callData->args[1].toNumber();
+ sxyz[2] = callData->args[2].toNumber();
+ sxyz[3] = callData->args[3].toNumber();
const void *params[] = { sxyz };
- return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params));
+ scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params));
}
/*!
@@ -510,44 +516,47 @@ matrix values.
Finally, the function may be called with no arguments and the resulting
matrix will be the identity matrix.
*/
-ReturnedValue QtObject::method_matrix4x4(QV4::CallContext *ctx)
+void QtObject::method_matrix4x4(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
- if (ctx->argc() == 0)
- return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 0, Q_NULLPTR));
+ if (callData->argc == 0) {
+ scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 0, Q_NULLPTR));
+ return;
+ }
- if (ctx->argc() == 1 && ctx->args()[0].isObject()) {
+ if (callData->argc == 1 && callData->args[0].isObject()) {
bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV4Handle(ctx->args()[0]), v4, &ok);
+ QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV4Handle(callData->args[0]), v4, &ok);
if (!ok)
- V4THROW_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array");
- return ctx->engine()->fromVariant(v);
+ THROW_GENERIC_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array");
+ scope.result = scope.engine->fromVariant(v);
+ return;
}
- if (ctx->argc() != 16)
- V4THROW_ERROR("Qt.matrix4x4(): Invalid arguments");
+ if (callData->argc != 16)
+ THROW_GENERIC_ERROR("Qt.matrix4x4(): Invalid arguments");
qreal vals[16]; // qmatrix4x4 uses qreal internally
- vals[0] = ctx->args()[0].toNumber();
- vals[1] = ctx->args()[1].toNumber();
- vals[2] = ctx->args()[2].toNumber();
- vals[3] = ctx->args()[3].toNumber();
- vals[4] = ctx->args()[4].toNumber();
- vals[5] = ctx->args()[5].toNumber();
- vals[6] = ctx->args()[6].toNumber();
- vals[7] = ctx->args()[7].toNumber();
- vals[8] = ctx->args()[8].toNumber();
- vals[9] = ctx->args()[9].toNumber();
- vals[10] = ctx->args()[10].toNumber();
- vals[11] = ctx->args()[11].toNumber();
- vals[12] = ctx->args()[12].toNumber();
- vals[13] = ctx->args()[13].toNumber();
- vals[14] = ctx->args()[14].toNumber();
- vals[15] = ctx->args()[15].toNumber();
+ vals[0] = callData->args[0].toNumber();
+ vals[1] = callData->args[1].toNumber();
+ vals[2] = callData->args[2].toNumber();
+ vals[3] = callData->args[3].toNumber();
+ vals[4] = callData->args[4].toNumber();
+ vals[5] = callData->args[5].toNumber();
+ vals[6] = callData->args[6].toNumber();
+ vals[7] = callData->args[7].toNumber();
+ vals[8] = callData->args[8].toNumber();
+ vals[9] = callData->args[9].toNumber();
+ vals[10] = callData->args[10].toNumber();
+ vals[11] = callData->args[11].toNumber();
+ vals[12] = callData->args[12].toNumber();
+ vals[13] = callData->args[13].toNumber();
+ vals[14] = callData->args[14].toNumber();
+ vals[15] = callData->args[15].toNumber();
const void *params[] = { vals };
- return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params));
+ scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params));
}
/*!
@@ -564,27 +573,29 @@ by factor and converts the color back to RGB.
If \c factor is not supplied, returns a color 50% lighter than \c baseColor (factor 1.5).
*/
-ReturnedValue QtObject::method_lighter(QV4::CallContext *ctx)
+void QtObject::method_lighter(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1 && ctx->argc() != 2)
- V4THROW_ERROR("Qt.lighter(): Invalid arguments");
+ if (callData->argc != 1 && callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.lighter(): Invalid arguments");
- QVariant v = ctx->engine()->toVariant(ctx->args()[0], -1);
+ QVariant v = scope.engine->toVariant(callData->args[0], -1);
if (v.userType() == QVariant::String) {
bool ok = false;
v = QQmlStringConverters::colorFromString(v.toString(), &ok);
if (!ok) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
} else if (v.userType() != QVariant::Color) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
qreal factor = 1.5;
- if (ctx->argc() == 2)
- factor = ctx->args()[1].toNumber();
+ if (callData->argc == 2)
+ factor = callData->args[1].toNumber();
- return ctx->engine()->fromVariant(QQml_colorProvider()->lighter(v, factor));
+ scope.result = scope.engine->fromVariant(QQml_colorProvider()->lighter(v, factor));
}
/*!
@@ -602,27 +613,29 @@ by factor and converts the color back to RGB.
If \c factor is not supplied, returns a color 50% darker than \c baseColor (factor 2.0).
*/
-ReturnedValue QtObject::method_darker(QV4::CallContext *ctx)
+void QtObject::method_darker(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1 && ctx->argc() != 2)
- V4THROW_ERROR("Qt.darker(): Invalid arguments");
+ if (callData->argc != 1 && callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.darker(): Invalid arguments");
- QVariant v = ctx->engine()->toVariant(ctx->args()[0], -1);
+ QVariant v = scope.engine->toVariant(callData->args[0], -1);
if (v.userType() == QVariant::String) {
bool ok = false;
v = QQmlStringConverters::colorFromString(v.toString(), &ok);
if (!ok) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
} else if (v.userType() != QVariant::Color) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
qreal factor = 2.0;
- if (ctx->argc() == 2)
- factor = ctx->args()[1].toNumber();
+ if (callData->argc == 2)
+ factor = callData->args[1].toNumber();
- return ctx->engine()->fromVariant(QQml_colorProvider()->darker(v, factor));
+ scope.result = scope.engine->fromVariant(QQml_colorProvider()->darker(v, factor));
}
/*!
@@ -649,36 +662,40 @@ ReturnedValue QtObject::method_darker(QV4::CallContext *ctx)
Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color.
*/
-ReturnedValue QtObject::method_tint(QV4::CallContext *ctx)
+void QtObject::method_tint(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 2)
- V4THROW_ERROR("Qt.tint(): Invalid arguments");
+ if (callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.tint(): Invalid arguments");
// base color
- QVariant v1 = ctx->engine()->toVariant(ctx->args()[0], -1);
+ QVariant v1 = scope.engine->toVariant(callData->args[0], -1);
if (v1.userType() == QVariant::String) {
bool ok = false;
v1 = QQmlStringConverters::colorFromString(v1.toString(), &ok);
if (!ok) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
} else if (v1.userType() != QVariant::Color) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
// tint color
- QVariant v2 = ctx->engine()->toVariant(ctx->args()[1], -1);
+ QVariant v2 = scope.engine->toVariant(callData->args[1], -1);
if (v2.userType() == QVariant::String) {
bool ok = false;
v2 = QQmlStringConverters::colorFromString(v2.toString(), &ok);
if (!ok) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
} else if (v2.userType() != QVariant::Color) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
- return ctx->engine()->fromVariant(QQml_colorProvider()->tint(v1, v2));
+ scope.result = scope.engine->fromVariant(QQml_colorProvider()->tint(v1, v2));
}
/*!
@@ -697,32 +714,31 @@ If \a format is not specified, \a date is formatted using
\sa Locale
*/
-ReturnedValue QtObject::method_formatDate(QV4::CallContext *ctx)
+void QtObject::method_formatDate(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1 || ctx->argc() > 2)
- V4THROW_ERROR("Qt.formatDate(): Invalid arguments");
- QV4::Scope scope(ctx);
+ if (callData->argc < 1 || callData->argc > 2)
+ THROW_GENERIC_ERROR("Qt.formatDate(): Invalid arguments");
Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QDate date = ctx->engine()->toVariant(ctx->args()[0], -1).toDateTime().date();
+ QDate date = scope.engine->toVariant(callData->args[0], -1).toDateTime().date();
QString formattedDate;
- if (ctx->argc() == 2) {
- QV4::ScopedString s(scope, ctx->args()[1]);
+ if (callData->argc == 2) {
+ QV4::ScopedString s(scope, callData->args[1]);
if (s) {
QString format = s->toQString();
formattedDate = date.toString(format);
- } else if (ctx->args()[1].isNumber()) {
- quint32 intFormat = ctx->args()[1].asDouble();
+ } else if (callData->args[1].isNumber()) {
+ quint32 intFormat = callData->args[1].asDouble();
Qt::DateFormat format = Qt::DateFormat(intFormat);
formattedDate = date.toString(format);
} else {
- V4THROW_ERROR("Qt.formatDate(): Invalid date format");
+ THROW_GENERIC_ERROR("Qt.formatDate(): Invalid date format");
}
} else {
formattedDate = date.toString(enumFormat);
}
- return ctx->d()->engine->newString(formattedDate)->asReturnedValue();
+ scope.result = scope.engine->newString(formattedDate);
}
/*!
@@ -740,38 +756,37 @@ If \a format is not specified, \a time is formatted using
\sa Locale
*/
-ReturnedValue QtObject::method_formatTime(QV4::CallContext *ctx)
+void QtObject::method_formatTime(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1 || ctx->argc() > 2)
- V4THROW_ERROR("Qt.formatTime(): Invalid arguments");
- QV4::Scope scope(ctx);
+ if (callData->argc < 1 || callData->argc > 2)
+ THROW_GENERIC_ERROR("Qt.formatTime(): Invalid arguments");
- QVariant argVariant = ctx->engine()->toVariant(ctx->args()[0], -1);
+ QVariant argVariant = scope.engine->toVariant(callData->args[0], -1);
QTime time;
- if (ctx->args()[0].as<DateObject>() || (argVariant.type() == QVariant::String))
+ if (callData->args[0].as<DateObject>() || (argVariant.type() == QVariant::String))
time = argVariant.toDateTime().time();
else // if (argVariant.type() == QVariant::Time), or invalid.
time = argVariant.toTime();
Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
QString formattedTime;
- if (ctx->argc() == 2) {
- QV4::ScopedString s(scope, ctx->args()[1]);
+ if (callData->argc == 2) {
+ QV4::ScopedString s(scope, callData->args[1]);
if (s) {
QString format = s->toQString();
formattedTime = time.toString(format);
- } else if (ctx->args()[1].isNumber()) {
- quint32 intFormat = ctx->args()[1].asDouble();
+ } else if (callData->args[1].isNumber()) {
+ quint32 intFormat = callData->args[1].asDouble();
Qt::DateFormat format = Qt::DateFormat(intFormat);
formattedTime = time.toString(format);
} else {
- V4THROW_ERROR("Qt.formatTime(): Invalid time format");
+ THROW_GENERIC_ERROR("Qt.formatTime(): Invalid time format");
}
} else {
formattedTime = time.toString(enumFormat);
}
- return ctx->d()->engine->newString(formattedTime)->asReturnedValue();
+ scope.result = scope.engine->newString(formattedTime);
}
/*!
@@ -864,32 +879,31 @@ with the \a format values below to produce the following results:
\sa Locale
*/
-ReturnedValue QtObject::method_formatDateTime(QV4::CallContext *ctx)
+void QtObject::method_formatDateTime(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1 || ctx->argc() > 2)
- V4THROW_ERROR("Qt.formatDateTime(): Invalid arguments");
- QV4::Scope scope(ctx);
+ if (callData->argc < 1 || callData->argc > 2)
+ THROW_GENERIC_ERROR("Qt.formatDateTime(): Invalid arguments");
Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QDateTime dt = ctx->engine()->toVariant(ctx->args()[0], -1).toDateTime();
+ QDateTime dt = scope.engine->toVariant(callData->args[0], -1).toDateTime();
QString formattedDt;
- if (ctx->argc() == 2) {
- QV4::ScopedString s(scope, ctx->args()[1]);
+ if (callData->argc == 2) {
+ QV4::ScopedString s(scope, callData->args[1]);
if (s) {
QString format = s->toQString();
formattedDt = dt.toString(format);
- } else if (ctx->args()[1].isNumber()) {
- quint32 intFormat = ctx->args()[1].asDouble();
+ } else if (callData->args[1].isNumber()) {
+ quint32 intFormat = callData->args[1].asDouble();
Qt::DateFormat format = Qt::DateFormat(intFormat);
formattedDt = dt.toString(format);
} else {
- V4THROW_ERROR("Qt.formatDateTime(): Invalid datetime format");
+ THROW_GENERIC_ERROR("Qt.formatDateTime(): Invalid datetime format");
}
} else {
formattedDt = dt.toString(enumFormat);
}
- return ctx->d()->engine->newString(formattedDt)->asReturnedValue();
+ scope.result = scope.engine->newString(formattedDt);
}
/*!
@@ -903,90 +917,94 @@ ReturnedValue QtObject::method_formatDateTime(QV4::CallContext *ctx)
still fail to launch or fail to open the requested URL. This result will not be reported back
to the application.
*/
-ReturnedValue QtObject::method_openUrlExternally(QV4::CallContext *ctx)
+void QtObject::method_openUrlExternally(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- return QV4::Encode(false);
+ if (callData->argc != 1) {
+ scope.result = QV4::Encode(false);
+ return;
+ }
- QUrl url(Value::fromReturnedValue(method_resolvedUrl(ctx)).toQStringNoThrow());
- return ctx->engine()->fromVariant(QQml_guiProvider()->openUrlExternally(url));
+ method_resolvedUrl(b, scope, callData);
+ QUrl url(scope.result.toQStringNoThrow());
+ scope.result = scope.engine->fromVariant(QQml_guiProvider()->openUrlExternally(url));
}
/*!
\qmlmethod url Qt::resolvedUrl(url url)
Returns \a url resolved relative to the URL of the caller.
*/
-ReturnedValue QtObject::method_resolvedUrl(QV4::CallContext *ctx)
+void QtObject::method_resolvedUrl(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ExecutionEngine *v4 = ctx->engine();
+ ExecutionEngine *v4 = scope.engine;
- QUrl url = v4->toVariant(ctx->args()[0], -1).toUrl();
+ QUrl url = v4->toVariant(callData->args[0], -1).toUrl();
QQmlEngine *e = v4->qmlEngine();
QQmlEnginePrivate *p = 0;
if (e) p = QQmlEnginePrivate::get(e);
if (p) {
QQmlContextData *ctxt = v4->callingQmlContext();
if (ctxt)
- return v4->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue();
+ scope.result = v4->newString(ctxt->resolvedUrl(url).toString());
else
- return v4->newString(url.toString())->asReturnedValue();
+ scope.result = v4->newString(url.toString());
+ return;
}
- return v4->newString(e->baseUrl().resolved(url).toString())->asReturnedValue();
+ scope.result = v4->newString(e->baseUrl().resolved(url).toString());
}
/*!
\qmlmethod list<string> Qt::fontFamilies()
Returns a list of the font families available to the application.
*/
-ReturnedValue QtObject::method_fontFamilies(CallContext *ctx)
+void QtObject::method_fontFamilies(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 0)
- V4THROW_ERROR("Qt.fontFamilies(): Invalid arguments");
+ if (callData->argc != 0)
+ THROW_GENERIC_ERROR("Qt.fontFamilies(): Invalid arguments");
- return ctx->engine()->fromVariant(QVariant(QQml_guiProvider()->fontFamilies()));
+ scope.result = scope.engine->fromVariant(QVariant(QQml_guiProvider()->fontFamilies()));
}
/*!
\qmlmethod string Qt::md5(data)
Returns a hex string of the md5 hash of \c data.
*/
-ReturnedValue QtObject::method_md5(CallContext *ctx)
+void QtObject::method_md5(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("Qt.md5(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("Qt.md5(): Invalid arguments");
- QByteArray data = ctx->args()[0].toQStringNoThrow().toUtf8();
+ QByteArray data = callData->args[0].toQStringNoThrow().toUtf8();
QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
- return ctx->d()->engine->newString(QLatin1String(result.toHex()))->asReturnedValue();
+ scope.result = scope.engine->newString(QLatin1String(result.toHex()));
}
/*!
\qmlmethod string Qt::btoa(data)
Binary to ASCII - this function returns a base64 encoding of \c data.
*/
-ReturnedValue QtObject::method_btoa(CallContext *ctx)
+void QtObject::method_btoa(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("Qt.btoa(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("Qt.btoa(): Invalid arguments");
- QByteArray data = ctx->args()[0].toQStringNoThrow().toUtf8();
+ QByteArray data = callData->args[0].toQStringNoThrow().toUtf8();
- return ctx->d()->engine->newString(QLatin1String(data.toBase64()))->asReturnedValue();
+ scope.result = scope.engine->newString(QLatin1String(data.toBase64()));
}
/*!
\qmlmethod string Qt::atob(data)
ASCII to binary - this function decodes the base64 encoded \a data string and returns it.
*/
-ReturnedValue QtObject::method_atob(CallContext *ctx)
+void QtObject::method_atob(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("Qt.atob(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("Qt.atob(): Invalid arguments");
- QByteArray data = ctx->args()[0].toQStringNoThrow().toLatin1();
+ QByteArray data = callData->args[0].toQStringNoThrow().toLatin1();
- return ctx->d()->engine->newString(QString::fromUtf8(QByteArray::fromBase64(data)))->asReturnedValue();
+ scope.result = scope.engine->newString(QString::fromUtf8(QByteArray::fromBase64(data)));
}
/*!
@@ -998,10 +1016,10 @@ QQmlEngine::quit() signal to the QCoreApplication::quit() slot.
\sa exit()
*/
-ReturnedValue QtObject::method_quit(CallContext *ctx)
+void QtObject::method_quit(const BuiltinFunction *, Scope &scope, CallData *)
{
- QQmlEnginePrivate::get(ctx->engine()->qmlEngine())->sendQuit();
- return QV4::Encode::undefined();
+ QQmlEnginePrivate::get(scope.engine->qmlEngine())->sendQuit();
+ scope.result = Encode::undefined();
}
/*!
@@ -1015,15 +1033,15 @@ ReturnedValue QtObject::method_quit(CallContext *ctx)
\sa quit()
*/
-ReturnedValue QtObject::method_exit(CallContext *ctx)
+void QtObject::method_exit(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("Qt.exit(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("Qt.exit(): Invalid arguments");
- int retCode = ctx->args()[0].toNumber();
+ int retCode = callData->args[0].toNumber();
- QQmlEnginePrivate::get(ctx->engine()->qmlEngine())->sendExit(retCode);
- return QV4::Encode::undefined();
+ QQmlEnginePrivate::get(scope.engine->qmlEngine())->sendExit(retCode);
+ scope.result = QV4::Encode::undefined();
}
/*!
@@ -1050,11 +1068,10 @@ If this is the case, consider using \l{QtQml::Qt::createComponent()}{Qt.createCo
See \l {Dynamic QML Object Creation from JavaScript} for more information on using this function.
*/
-ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
+void QtObject::method_createQmlObject(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- if (ctx->argc() < 2 || ctx->argc() > 3)
- V4THROW_ERROR("Qt.createQmlObject(): Invalid arguments");
+ if (callData->argc < 2 || callData->argc > 3)
+ THROW_GENERIC_ERROR("Qt.createQmlObject(): Invalid arguments");
struct Error {
static ReturnedValue create(QV4::ExecutionEngine *v4, const QList<QQmlError> &errors) {
@@ -1085,7 +1102,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
}
};
- QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QV8Engine *v8engine = scope.engine->v8Engine;
QQmlEngine *engine = v8engine->engine();
QQmlContextData *context = scope.engine->callingQmlContext();
@@ -1097,13 +1114,13 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
effectiveContext = context->asQQmlContext();
Q_ASSERT(effectiveContext);
- QString qml = ctx->args()[0].toQStringNoThrow();
+ QString qml = callData->args[0].toQStringNoThrow();
if (qml.isEmpty())
- return QV4::Encode::null();
+ RETURN_RESULT(Encode::null());
QUrl url;
- if (ctx->argc() > 2)
- url = QUrl(ctx->args()[2].toQStringNoThrow());
+ if (callData->argc > 2)
+ url = QUrl(callData->args[2].toQStringNoThrow());
else
url = QUrl(QLatin1String("inline"));
@@ -1111,11 +1128,11 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
url = context->resolvedUrl(url);
QObject *parentArg = 0;
- QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, ctx->args()[1]);
+ QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, callData->args[1]);
if (!!qobjectWrapper)
parentArg = qobjectWrapper->object();
if (!parentArg)
- V4THROW_ERROR("Qt.createQmlObject(): Missing parent object");
+ THROW_GENERIC_ERROR("Qt.createQmlObject(): Missing parent object");
QQmlTypeData *typeData = QQmlEnginePrivate::get(engine)->typeLoader.getType(
qml.toUtf8(), url, QQmlTypeLoader::Synchronous);
@@ -1126,12 +1143,12 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
componentPrivate->progress = 1.0;
if (component.isError()) {
- ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors()));
- return ctx->engine()->throwError(v);
+ ScopedValue v(scope, Error::create(scope.engine, component.errors()));
+ RETURN_RESULT(scope.engine->throwError(v));
}
if (!component.isReady())
- V4THROW_ERROR("Qt.createQmlObject(): Component is not ready");
+ THROW_GENERIC_ERROR("Qt.createQmlObject(): Component is not ready");
QObject *obj = component.beginCreate(effectiveContext);
if (obj) {
@@ -1150,13 +1167,14 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
component.completeCreate();
if (component.isError()) {
- ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors()));
- return ctx->engine()->throwError(v);
+ ScopedValue v(scope, Error::create(scope.engine, component.errors()));
+ scope.result = scope.engine->throwError(v);
+ return;
}
Q_ASSERT(obj);
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, obj);
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, obj);
}
/*!
@@ -1203,14 +1221,12 @@ See \l {Dynamic QML Object Creation from JavaScript} for more information on usi
To create a QML object from an arbitrary string of QML (instead of a file),
use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}.
*/
-ReturnedValue QtObject::method_createComponent(CallContext *ctx)
+void QtObject::method_createComponent(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1 || ctx->argc() > 3)
- return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
+ if (callData->argc < 1 || callData->argc > 3)
+ THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments");
- Scope scope(ctx);
-
- QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QV8Engine *v8engine = scope.engine->v8Engine;
QQmlEngine *engine = v8engine->engine();
QQmlContextData *context = scope.engine->callingQmlContext();
@@ -1219,41 +1235,41 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx)
if (context->isPragmaLibraryContext)
effectiveContext = 0;
- QString arg = ctx->args()[0].toQStringNoThrow();
+ QString arg = callData->args[0].toQStringNoThrow();
if (arg.isEmpty())
- return QV4::Encode::null();
+ RETURN_RESULT(QV4::Encode::null());
QQmlComponent::CompilationMode compileMode = QQmlComponent::PreferSynchronous;
QObject *parentArg = 0;
int consumedCount = 1;
- if (ctx->argc() > 1) {
- ScopedValue lastArg(scope, ctx->args()[ctx->argc()-1]);
+ if (callData->argc > 1) {
+ ScopedValue lastArg(scope, callData->args[callData->argc-1]);
// The second argument could be the mode enum
- if (ctx->args()[1].isInteger()) {
- int mode = ctx->args()[1].integerValue();
+ if (callData->args[1].isInteger()) {
+ int mode = callData->args[1].integerValue();
if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous))
- return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
+ THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments");
compileMode = QQmlComponent::CompilationMode(mode);
consumedCount += 1;
} else {
// The second argument could be the parent only if there are exactly two args
- if ((ctx->argc() != 2) || !(lastArg->isObject() || lastArg->isNull()))
- return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
+ if ((callData->argc != 2) || !(lastArg->isObject() || lastArg->isNull()))
+ THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments");
}
- if (consumedCount < ctx->argc()) {
+ if (consumedCount < callData->argc) {
if (lastArg->isObject()) {
Scoped<QObjectWrapper> qobjectWrapper(scope, lastArg);
if (qobjectWrapper)
parentArg = qobjectWrapper->object();
if (!parentArg)
- return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object"));
+ THROW_GENERIC_ERROR("Qt.createComponent(): Invalid parent object");
} else if (lastArg->isNull()) {
parentArg = 0;
} else {
- return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object"));
+ THROW_GENERIC_ERROR("Qt.createComponent(): Invalid parent object");
}
}
}
@@ -1264,7 +1280,7 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx)
QQmlData::get(c, true)->explicitIndestructibleSet = false;
QQmlData::get(c)->indestructible = false;
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, c);
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, c);
}
/*!
@@ -1287,18 +1303,18 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx)
\sa Locale
*/
-ReturnedValue QtObject::method_locale(CallContext *ctx)
+void QtObject::method_locale(const BuiltinFunction *, Scope &scope, CallData *callData)
{
QString code;
- if (ctx->argc() > 1)
- V4THROW_ERROR("locale() requires 0 or 1 argument");
- if (ctx->argc() == 1 && !ctx->args()[0].isString())
- V4THROW_TYPE("locale(): argument (locale code) must be a string");
+ if (callData->argc > 1)
+ THROW_GENERIC_ERROR("locale() requires 0 or 1 argument");
+ if (callData->argc == 1 && !callData->args[0].isString())
+ THROW_TYPE_ERROR_WITH_MESSAGE("locale(): argument (locale code) must be a string");
- if (ctx->argc() == 1)
- code = ctx->args()[0].toQStringNoThrow();
+ if (callData->argc == 1)
+ code = callData->args[0].toQStringNoThrow();
- return QQmlLocale::locale(ctx->engine(), code);
+ scope.result = QQmlLocale::locale(scope.engine, code);
}
void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *originalFunction)
@@ -1360,62 +1376,62 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction);
\since 5.0
*/
-ReturnedValue QtObject::method_binding(CallContext *ctx)
+void QtObject::method_binding(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("binding() requires 1 argument");
- const QV4::FunctionObject *f = ctx->args()[0].as<FunctionObject>();
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("binding() requires 1 argument");
+ const QV4::FunctionObject *f = callData->args[0].as<FunctionObject>();
if (!f)
- V4THROW_TYPE("binding(): argument (binding expression) must be a function");
+ THROW_TYPE_ERROR_WITH_MESSAGE("binding(): argument (binding expression) must be a function");
- return (ctx->d()->engine->memoryManager->allocObject<QQmlBindingFunction>(f))->asReturnedValue();
+ scope.result = scope.engine->memoryManager->allocObject<QQmlBindingFunction>(f);
}
-ReturnedValue QtObject::method_get_platform(CallContext *ctx)
+void QtObject::method_get_platform(const BuiltinFunction *, Scope &scope, CallData *callData)
{
// ### inefficient. Should be just a value based getter
- Object *o = ctx->thisObject().as<Object>();
+ Object *o = callData->thisObject.as<Object>();
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
QtObject *qt = o->as<QtObject>();
if (!qt)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (!qt->d()->platform)
// Only allocate a platform object once
- qt->d()->platform = new QQmlPlatform(ctx->d()->engine->jsEngine());
+ qt->d()->platform = new QQmlPlatform(scope.engine->jsEngine());
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, qt->d()->platform);
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, qt->d()->platform);
}
-ReturnedValue QtObject::method_get_application(CallContext *ctx)
+void QtObject::method_get_application(const BuiltinFunction *, Scope &scope, CallData *callData)
{
// ### inefficient. Should be just a value based getter
- Object *o = ctx->thisObject().as<Object>();
+ Object *o = callData->thisObject.as<Object>();
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
QtObject *qt = o->as<QtObject>();
if (!qt)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (!qt->d()->application)
// Only allocate an application object once
- qt->d()->application = QQml_guiProvider()->application(ctx->d()->engine->jsEngine());
+ qt->d()->application = QQml_guiProvider()->application(scope.engine->jsEngine());
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, qt->d()->application);
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, qt->d()->application);
}
-ReturnedValue QtObject::method_get_inputMethod(CallContext *ctx)
+void QtObject::method_get_inputMethod(const BuiltinFunction *, Scope &scope, CallData *)
{
QObject *o = QQml_guiProvider()->inputMethod();
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, o);
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, o);
}
-ReturnedValue QtObject::method_get_styleHints(CallContext *ctx)
+void QtObject::method_get_styleHints(const BuiltinFunction *, Scope &scope, CallData *)
{
QObject *o = QQml_guiProvider()->styleHints();
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, o);
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, o);
}
@@ -1475,35 +1491,35 @@ static QString jsStack(QV4::ExecutionEngine *engine) {
return stack;
}
-static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *ctx,
- bool printStack = false)
+static void writeToConsole(const BuiltinFunction *, Scope &scope, CallData *callData,
+ ConsoleLogTypes logType, bool printStack = false)
{
QLoggingCategory *loggingCategory = 0;
QString result;
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
int start = 0;
- if (ctx->argc() > 0) {
- if (const QObjectWrapper* wrapper = ctx->args()[0].as<QObjectWrapper>()) {
+ if (callData->argc > 0) {
+ if (const QObjectWrapper* wrapper = callData->args[0].as<QObjectWrapper>()) {
if (QQmlLoggingCategory* category = qobject_cast<QQmlLoggingCategory*>(wrapper->object())) {
if (category->category())
loggingCategory = category->category();
else
- V4THROW_ERROR("A QmlLoggingCatgory was provided without a valid name");
+ THROW_GENERIC_ERROR("A QmlLoggingCatgory was provided without a valid name");
start = 1;
}
}
}
- for (int i = start; i < ctx->argc(); ++i) {
+ for (int i = start; i < callData->argc; ++i) {
if (i != start)
result.append(QLatin1Char(' '));
- if (ctx->args()[i].as<ArrayObject>())
- result += QLatin1Char('[') + ctx->args()[i].toQStringNoThrow() + QLatin1Char(']');
+ if (callData->args[i].as<ArrayObject>())
+ result += QLatin1Char('[') + callData->args[i].toQStringNoThrow() + QLatin1Char(']');
else
- result.append(ctx->args()[i].toQStringNoThrow());
+ result.append(callData->args[i].toQStringNoThrow());
}
if (printStack)
@@ -1540,32 +1556,32 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *c
break;
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
DEFINE_OBJECT_VTABLE(ConsoleObject);
-QV4::ReturnedValue ConsoleObject::method_error(CallContext *ctx)
+void ConsoleObject::method_error(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- return writeToConsole(Error, ctx);
+ writeToConsole(b, scope, callData, Error);
}
-QV4::ReturnedValue ConsoleObject::method_log(CallContext *ctx)
+void ConsoleObject::method_log(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
//console.log
//console.debug
//print
- return writeToConsole(Log, ctx);
+ writeToConsole(b, scope, callData, Log);
}
-QV4::ReturnedValue ConsoleObject::method_info(CallContext *ctx)
+void ConsoleObject::method_info(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- return writeToConsole(Info, ctx);
+ writeToConsole(b, scope, callData, Info);
}
-QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx)
+void ConsoleObject::method_profile(const BuiltinFunction *, Scope &scope, CallData *)
{
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
QV4::StackFrame frame = v4->currentStackFrame();
const QByteArray baSource = frame.source.toUtf8();
@@ -1579,12 +1595,12 @@ QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx)
logger.debug("Profiling started.");
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx)
+void ConsoleObject::method_profileEnd(const BuiltinFunction *, Scope &scope, CallData *)
{
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
QV4::StackFrame frame = v4->currentStackFrame();
const QByteArray baSource = frame.source.toUtf8();
@@ -1599,46 +1615,46 @@ QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx)
logger.debug("Profiling ended.");
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_time(CallContext *ctx)
+void ConsoleObject::method_time(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("console.time(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("console.time(): Invalid arguments");
- QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QV8Engine *v8engine = scope.engine->v8Engine;
- QString name = ctx->args()[0].toQStringNoThrow();
+ QString name = callData->args[0].toQStringNoThrow();
v8engine->startTimer(name);
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_timeEnd(CallContext *ctx)
+void ConsoleObject::method_timeEnd(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("console.timeEnd(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("console.timeEnd(): Invalid arguments");
- QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QV8Engine *v8engine = scope.engine->v8Engine;
- QString name = ctx->args()[0].toQStringNoThrow();
+ QString name = callData->args[0].toQStringNoThrow();
bool wasRunning;
qint64 elapsed = v8engine->stopTimer(name, &wasRunning);
if (wasRunning) {
qDebug("%s: %llims", qPrintable(name), elapsed);
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_count(CallContext *ctx)
+void ConsoleObject::method_count(const BuiltinFunction *, Scope &scope, CallData *callData)
{
// first argument: name to print. Ignore any additional arguments
QString name;
- if (ctx->argc() > 0)
- name = ctx->args()[0].toQStringNoThrow();
+ if (callData->argc > 0)
+ name = callData->args[0].toQStringNoThrow();
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
- QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
+ QV8Engine *v8engine = scope.engine->v8Engine;
QV4::StackFrame frame = v4->currentStackFrame();
@@ -1651,15 +1667,15 @@ QV4::ReturnedValue ConsoleObject::method_count(CallContext *ctx)
qPrintable(frame.function))
.debug("%s", qPrintable(message));
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_trace(CallContext *ctx)
+void ConsoleObject::method_trace(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 0)
- V4THROW_ERROR("console.trace(): Invalid arguments");
+ if (callData->argc != 0)
+ THROW_GENERIC_ERROR("console.trace(): Invalid arguments");
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
QString stack = jsStack(v4);
@@ -1668,28 +1684,28 @@ QV4::ReturnedValue ConsoleObject::method_trace(CallContext *ctx)
frame.function.toUtf8().constData())
.debug("%s", qPrintable(stack));
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_warn(CallContext *ctx)
+void ConsoleObject::method_warn(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- return writeToConsole(Warn, ctx);
+ return writeToConsole(b, scope, callData, Warn);
}
-QV4::ReturnedValue ConsoleObject::method_assert(CallContext *ctx)
+void ConsoleObject::method_assert(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() == 0)
- V4THROW_ERROR("console.assert(): Missing argument");
+ if (callData->argc == 0)
+ THROW_GENERIC_ERROR("console.assert(): Missing argument");
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
- if (!ctx->args()[0].toBoolean()) {
+ if (!callData->args[0].toBoolean()) {
QString message;
- for (int i = 1; i < ctx->argc(); ++i) {
+ for (int i = 1; i < callData->argc; ++i) {
if (i != 1)
message.append(QLatin1Char(' '));
- message.append(ctx->args()[i].toQStringNoThrow());
+ message.append(callData->args[i].toQStringNoThrow());
}
QString stack = jsStack(v4);
@@ -1700,17 +1716,17 @@ QV4::ReturnedValue ConsoleObject::method_assert(CallContext *ctx)
.critical("%s\n%s",qPrintable(message), qPrintable(stack));
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_exception(CallContext *ctx)
+void ConsoleObject::method_exception(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() == 0)
- V4THROW_ERROR("console.exception(): Missing argument");
+ if (callData->argc == 0)
+ THROW_GENERIC_ERROR("console.exception(): Missing argument");
- writeToConsole(Error, ctx, true);
+ writeToConsole(b, scope, callData, Error, true);
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
@@ -1766,38 +1782,38 @@ void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions ext
\sa {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTranslate(CallContext *ctx)
-{
- if (ctx->argc() < 2)
- V4THROW_ERROR("qsTranslate() requires at least two arguments");
- if (!ctx->args()[0].isString())
- V4THROW_ERROR("qsTranslate(): first argument (context) must be a string");
- if (!ctx->args()[1].isString())
- V4THROW_ERROR("qsTranslate(): second argument (sourceText) must be a string");
- if ((ctx->argc() > 2) && !ctx->args()[2].isString())
- V4THROW_ERROR("qsTranslate(): third argument (disambiguation) must be a string");
-
- QString context = ctx->args()[0].toQStringNoThrow();
- QString text = ctx->args()[1].toQStringNoThrow();
+void GlobalExtensions::method_qsTranslate(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ if (callData->argc < 2)
+ THROW_GENERIC_ERROR("qsTranslate() requires at least two arguments");
+ if (!callData->args[0].isString())
+ THROW_GENERIC_ERROR("qsTranslate(): first argument (context) must be a string");
+ if (!callData->args[1].isString())
+ THROW_GENERIC_ERROR("qsTranslate(): second argument (sourceText) must be a string");
+ if ((callData->argc > 2) && !callData->args[2].isString())
+ THROW_GENERIC_ERROR("qsTranslate(): third argument (disambiguation) must be a string");
+
+ QString context = callData->args[0].toQStringNoThrow();
+ QString text = callData->args[1].toQStringNoThrow();
QString comment;
- if (ctx->argc() > 2) comment = ctx->args()[2].toQStringNoThrow();
+ if (callData->argc > 2) comment = callData->args[2].toQStringNoThrow();
int i = 3;
- if (ctx->argc() > i && ctx->args()[i].isString()) {
+ if (callData->argc > i && callData->args[i].isString()) {
qWarning("qsTranslate(): specifying the encoding as fourth argument is deprecated");
++i;
}
int n = -1;
- if (ctx->argc() > i)
- n = ctx->args()[i].toInt32();
+ if (callData->argc > i)
+ n = callData->args[i].toInt32();
QString result = QCoreApplication::translate(context.toUtf8().constData(),
text.toUtf8().constData(),
comment.toUtf8().constData(),
n);
- return ctx->d()->engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
/*!
@@ -1822,11 +1838,12 @@ ReturnedValue GlobalExtensions::method_qsTranslate(CallContext *ctx)
\sa {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTranslateNoOp(CallContext *ctx)
+void GlobalExtensions::method_qsTranslateNoOp(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 2)
- return QV4::Encode::undefined();
- return ctx->args()[1].asReturnedValue();
+ if (callData->argc < 2)
+ scope.result = QV4::Encode::undefined();
+ else
+ scope.result = callData->args[1];
}
/*!
@@ -1846,18 +1863,17 @@ ReturnedValue GlobalExtensions::method_qsTranslateNoOp(CallContext *ctx)
\sa {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
-{
- if (ctx->argc() < 1)
- V4THROW_ERROR("qsTr() requires at least one argument");
- if (!ctx->args()[0].isString())
- V4THROW_ERROR("qsTr(): first argument (sourceText) must be a string");
- if ((ctx->argc() > 1) && !ctx->args()[1].isString())
- V4THROW_ERROR("qsTr(): second argument (disambiguation) must be a string");
- if ((ctx->argc() > 2) && !ctx->args()[2].isNumber())
- V4THROW_ERROR("qsTr(): third argument (n) must be a number");
-
- Scope scope(ctx);
+void GlobalExtensions::method_qsTr(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ if (callData->argc < 1)
+ THROW_GENERIC_ERROR("qsTr() requires at least one argument");
+ if (!callData->args[0].isString())
+ THROW_GENERIC_ERROR("qsTr(): first argument (sourceText) must be a string");
+ if ((callData->argc > 1) && !callData->args[1].isString())
+ THROW_GENERIC_ERROR("qsTr(): second argument (disambiguation) must be a string");
+ if ((callData->argc > 2) && !callData->args[2].isNumber())
+ THROW_GENERIC_ERROR("qsTr(): third argument (n) must be a number");
+
QString context;
if (QQmlContextData *ctxt = scope.engine->callingQmlContext()) {
QString path = ctxt->urlString();
@@ -1866,7 +1882,7 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
int length = lastDot - (lastSlash + 1);
context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString();
} else {
- ExecutionContext *parentCtx = scope.engine->parentContext(ctx);
+ ExecutionContext *parentCtx = scope.engine->currentContext;
// The first non-empty source URL in the call stack determines the translation context.
while (!!parentCtx && context.isEmpty()) {
if (QV4::CompiledData::CompilationUnit *unit = parentCtx->d()->compilationUnit) {
@@ -1885,18 +1901,18 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
}
}
- QString text = ctx->args()[0].toQStringNoThrow();
+ QString text = callData->args[0].toQStringNoThrow();
QString comment;
- if (ctx->argc() > 1)
- comment = ctx->args()[1].toQStringNoThrow();
+ if (callData->argc > 1)
+ comment = callData->args[1].toQStringNoThrow();
int n = -1;
- if (ctx->argc() > 2)
- n = ctx->args()[2].toInt32();
+ if (callData->argc > 2)
+ n = callData->args[2].toInt32();
QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(),
comment.toUtf8().constData(), n);
- return ctx->d()->engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
/*!
@@ -1921,11 +1937,12 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
\sa {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTrNoOp(CallContext *ctx)
+void GlobalExtensions::method_qsTrNoOp(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1)
- return QV4::Encode::undefined();
- return ctx->args()[0].asReturnedValue();
+ if (callData->argc < 1)
+ scope.result = QV4::Encode::undefined();
+ else
+ scope.result = callData->args[0];
}
/*!
@@ -1958,20 +1975,20 @@ ReturnedValue GlobalExtensions::method_qsTrNoOp(CallContext *ctx)
\sa QT_TRID_NOOP(), {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTrId(CallContext *ctx)
+void GlobalExtensions::method_qsTrId(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1)
- V4THROW_ERROR("qsTrId() requires at least one argument");
- if (!ctx->args()[0].isString())
- V4THROW_TYPE("qsTrId(): first argument (id) must be a string");
- if (ctx->argc() > 1 && !ctx->args()[1].isNumber())
- V4THROW_TYPE("qsTrId(): second argument (n) must be a number");
+ if (callData->argc < 1)
+ THROW_GENERIC_ERROR("qsTrId() requires at least one argument");
+ if (!callData->args[0].isString())
+ THROW_TYPE_ERROR_WITH_MESSAGE("qsTrId(): first argument (id) must be a string");
+ if (callData->argc > 1 && !callData->args[1].isNumber())
+ THROW_TYPE_ERROR_WITH_MESSAGE("qsTrId(): second argument (n) must be a number");
int n = -1;
- if (ctx->argc() > 1)
- n = ctx->args()[1].toInt32();
+ if (callData->argc > 1)
+ n = callData->args[1].toInt32();
- return ctx->d()->engine->newString(qtTrId(ctx->args()[0].toQStringNoThrow().toUtf8().constData(), n))->asReturnedValue();
+ scope.result = scope.engine->newString(qtTrId(callData->args[0].toQStringNoThrow().toUtf8().constData(), n));
}
/*!
@@ -1990,41 +2007,41 @@ ReturnedValue GlobalExtensions::method_qsTrId(CallContext *ctx)
\sa qsTrId(), {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTrIdNoOp(CallContext *ctx)
+void GlobalExtensions::method_qsTrIdNoOp(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1)
- return QV4::Encode::undefined();
- return ctx->args()[0].asReturnedValue();
+ if (callData->argc < 1)
+ scope.result = QV4::Encode::undefined();
+ else
+ scope.result = callData->args[0];
}
#endif // translation
-QV4::ReturnedValue GlobalExtensions::method_gc(CallContext *ctx)
+void GlobalExtensions::method_gc(const BuiltinFunction *, Scope &scope, CallData *)
{
- ctx->d()->engine->memoryManager->runGC();
+ scope.engine->memoryManager->runGC();
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-ReturnedValue GlobalExtensions::method_string_arg(CallContext *ctx)
+void GlobalExtensions::method_string_arg(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("String.arg(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("String.arg(): Invalid arguments");
- QString value = ctx->thisObject().toQString();
+ QString value = callData->thisObject.toQString();
- QV4::Scope scope(ctx);
- QV4::ScopedValue arg(scope, ctx->args()[0]);
+ QV4::ScopedValue arg(scope, callData->args[0]);
if (arg->isInteger())
- return ctx->d()->engine->newString(value.arg(arg->integerValue()))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(value.arg(arg->integerValue())));
else if (arg->isDouble())
- return ctx->d()->engine->newString(value.arg(arg->doubleValue()))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(value.arg(arg->doubleValue())));
else if (arg->isBoolean())
- return ctx->d()->engine->newString(value.arg(arg->booleanValue()))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(value.arg(arg->booleanValue())));
- return ctx->d()->engine->newString(value.arg(arg->toQString()))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(value.arg(arg->toQString())));
}
/*!
@@ -2047,10 +2064,10 @@ be passed on to the function invoked. Note that if redundant calls
are eliminated, then only the last set of arguments will be passed to the
function.
*/
-ReturnedValue QtObject::method_callLater(CallContext *ctx)
+void QtObject::method_callLater(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- QV8Engine *v8engine = ctx->engine()->v8Engine;
- return v8engine->delayedCallQueue()->addUniquelyAndExecuteLater(ctx);
+ QV8Engine *v8engine = scope.engine->v8Engine;
+ v8engine->delayedCallQueue()->addUniquelyAndExecuteLater(b, scope, callData);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index fe43532647..21613b7c10 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -93,45 +93,45 @@ struct QtObject : Object
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
- static ReturnedValue method_isQtObject(CallContext *ctx);
- static ReturnedValue method_rgba(CallContext *ctx);
- static ReturnedValue method_hsla(CallContext *ctx);
- static ReturnedValue method_hsva(CallContext *ctx);
- static ReturnedValue method_colorEqual(CallContext *ctx);
- static ReturnedValue method_font(CallContext *ctx);
- static ReturnedValue method_rect(CallContext *ctx);
- static ReturnedValue method_point(CallContext *ctx);
- static ReturnedValue method_size(CallContext *ctx);
- static ReturnedValue method_vector2d(CallContext *ctx);
- static ReturnedValue method_vector3d(CallContext *ctx);
- static ReturnedValue method_vector4d(CallContext *ctx);
- static ReturnedValue method_quaternion(CallContext *ctx);
- static ReturnedValue method_matrix4x4(CallContext *ctx);
- static ReturnedValue method_lighter(CallContext *ctx);
- static ReturnedValue method_darker(CallContext *ctx);
- static ReturnedValue method_tint(CallContext *ctx);
- static ReturnedValue method_formatDate(CallContext *ctx);
- static ReturnedValue method_formatTime(CallContext *ctx);
- static ReturnedValue method_formatDateTime(CallContext *ctx);
- static ReturnedValue method_openUrlExternally(CallContext *ctx);
- static ReturnedValue method_fontFamilies(CallContext *ctx);
- static ReturnedValue method_md5(CallContext *ctx);
- static ReturnedValue method_btoa(CallContext *ctx);
- static ReturnedValue method_atob(CallContext *ctx);
- static ReturnedValue method_quit(CallContext *ctx);
- static ReturnedValue method_exit(CallContext *ctx);
- static ReturnedValue method_resolvedUrl(CallContext *ctx);
- static ReturnedValue method_createQmlObject(CallContext *ctx);
- static ReturnedValue method_createComponent(CallContext *ctx);
- static ReturnedValue method_locale(CallContext *ctx);
- static ReturnedValue method_binding(CallContext *ctx);
-
- static ReturnedValue method_get_platform(CallContext *ctx);
- static ReturnedValue method_get_application(CallContext *ctx);
- static ReturnedValue method_get_inputMethod(CallContext *ctx);
- static ReturnedValue method_get_styleHints(CallContext *ctx);
-
- static ReturnedValue method_callLater(CallContext *ctx);
+ static void method_isQtObject(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_rgba(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_hsla(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_hsva(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_colorEqual(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_font(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_rect(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_point(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_size(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_vector2d(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_vector3d(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_vector4d(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_quaternion(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_matrix4x4(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_lighter(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_darker(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_tint(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_formatDate(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_formatTime(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_formatDateTime(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_openUrlExternally(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_fontFamilies(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_md5(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_btoa(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_atob(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_quit(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_exit(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_resolvedUrl(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_createQmlObject(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_createComponent(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_locale(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_binding(const BuiltinFunction *, Scope &scope, CallData *callData);
+
+ static void method_get_platform(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_application(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_inputMethod(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_styleHints(const BuiltinFunction *, Scope &scope, CallData *callData);
+
+ static void method_callLater(const BuiltinFunction *, Scope &scope, CallData *callData);
private:
void addAll();
@@ -142,18 +142,18 @@ struct ConsoleObject : Object
{
V4_OBJECT2(ConsoleObject, Object)
- static ReturnedValue method_error(CallContext *ctx);
- static ReturnedValue method_log(CallContext *ctx);
- static ReturnedValue method_info(CallContext *ctx);
- static ReturnedValue method_profile(CallContext *ctx);
- static ReturnedValue method_profileEnd(CallContext *ctx);
- static ReturnedValue method_time(CallContext *ctx);
- static ReturnedValue method_timeEnd(CallContext *ctx);
- static ReturnedValue method_count(CallContext *ctx);
- static ReturnedValue method_trace(CallContext *ctx);
- static ReturnedValue method_warn(CallContext *ctx);
- static ReturnedValue method_assert(CallContext *ctx);
- static ReturnedValue method_exception(CallContext *ctx);
+ static void method_error(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_log(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_info(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_profile(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_profileEnd(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_time(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_timeEnd(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_count(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_trace(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_warn(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_assert(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_exception(const BuiltinFunction *, Scope &scope, CallData *callData);
};
@@ -161,17 +161,17 @@ struct Q_QML_PRIVATE_EXPORT GlobalExtensions {
static void init(Object *globalObject, QJSEngine::Extensions extensions);
#if QT_CONFIG(translation)
- static ReturnedValue method_qsTranslate(CallContext *ctx);
- static ReturnedValue method_qsTranslateNoOp(CallContext *ctx);
- static ReturnedValue method_qsTr(CallContext *ctx);
- static ReturnedValue method_qsTrNoOp(CallContext *ctx);
- static ReturnedValue method_qsTrId(CallContext *ctx);
- static ReturnedValue method_qsTrIdNoOp(CallContext *ctx);
+ static void method_qsTranslate(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_qsTranslateNoOp(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_qsTr(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_qsTrNoOp(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_qsTrId(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_qsTrIdNoOp(const BuiltinFunction *, Scope &scope, CallData *callData);
#endif
- static ReturnedValue method_gc(CallContext *ctx);
+ static void method_gc(const BuiltinFunction *, Scope &scope, CallData *callData);
// on String:prototype
- static ReturnedValue method_string_arg(CallContext *ctx);
+ static void method_string_arg(const BuiltinFunction *, Scope &scope, CallData *callData);
};
diff --git a/src/qml/qml/v8/qv4domerrors_p.h b/src/qml/qml/v8/qv4domerrors_p.h
index faa9dd8bc7..a9bdbe01ae 100644
--- a/src/qml/qml/v8/qv4domerrors_p.h
+++ b/src/qml/qml/v8/qv4domerrors_p.h
@@ -74,11 +74,12 @@ QT_BEGIN_NAMESPACE
#define DOMEXCEPTION_VALIDATION_ERR 16
#define DOMEXCEPTION_TYPE_MISMATCH_ERR 17
-#define V4THROW_DOM(error, string) { \
+#define THROW_DOM(error, string) { \
QV4::ScopedValue v(scope, scope.engine->newString(QStringLiteral(string))); \
QV4::ScopedObject ex(scope, scope.engine->newErrorObject(v)); \
ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(error))); \
- return ctx->engine()->throwError(ex); \
+ scope.result = scope.engine->throwError(ex); \
+ return; \
}
namespace QV4 {
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index c0d75cae33..a5878dcffd 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -1795,24 +1795,26 @@ int QQmlDelegateModelItemMetaType::parseGroups(const QV4::Value &groups) const
return groupFlags;
}
-QV4::ReturnedValue QQmlDelegateModelItem::get_model(QV4::CallContext *ctx)
+void QQmlDelegateModelItem::get_model(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>());
- if (!o)
- return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>());
+ if (!o) {
+ scope.result = scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return;
+ }
if (!o->d()->item->metaType->model)
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
- return o->d()->item->get();
+ scope.result = o->d()->item->get();
}
-QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::CallContext *ctx)
+void QQmlDelegateModelItem::get_groups(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>());
- if (!o)
- return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>());
+ if (!o) {
+ scope.result = scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return;
+ }
QStringList groups;
for (int i = 1; i < o->d()->item->metaType->groupCount; ++i) {
@@ -1820,27 +1822,29 @@ QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::CallContext *ctx)
groups.append(o->d()->item->metaType->groupNames.at(i - 1));
}
- return scope.engine->fromVariant(groups);
+ scope.result = scope.engine->fromVariant(groups);
}
-QV4::ReturnedValue QQmlDelegateModelItem::set_groups(QV4::CallContext *ctx)
+void QQmlDelegateModelItem::set_groups(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>());
- if (!o)
- return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
- if (!ctx->argc())
- return ctx->engine()->throwTypeError();
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>());
+ if (!o) {
+ scope.result = scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return;
+ }
+
+ if (!callData->argc)
+ THROW_TYPE_ERROR();
if (!o->d()->item->metaType->model)
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(o->d()->item->metaType->model);
- const int groupFlags = model->m_cacheMetaType->parseGroups(ctx->args()[0]);
+ const int groupFlags = model->m_cacheMetaType->parseGroups(callData->args[0]);
const int cacheIndex = model->m_cache.indexOf(o->d()->item);
Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
model->setGroups(it, 1, Compositor::Cache, groupFlags);
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
QV4::ReturnedValue QQmlDelegateModelItem::get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &)
@@ -3234,28 +3238,25 @@ struct QQmlDelegateModelGroupChange : QV4::Object
return e->memoryManager->allocObject<QQmlDelegateModelGroupChange>();
}
- static QV4::ReturnedValue method_get_index(QV4::CallContext *ctx) {
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->thisObject().as<QQmlDelegateModelGroupChange>());
+ static void method_get_index(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) {
+ QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, callData->thisObject.as<QQmlDelegateModelGroupChange>());
if (!that)
- return ctx->engine()->throwTypeError();
- return QV4::Encode(that->d()->change.index);
+ THROW_TYPE_ERROR();
+ scope.result = QV4::Encode(that->d()->change.index);
}
- static QV4::ReturnedValue method_get_count(QV4::CallContext *ctx) {
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->thisObject().as<QQmlDelegateModelGroupChange>());
+ static void method_get_count(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) {
+ QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, callData->thisObject.as<QQmlDelegateModelGroupChange>());
if (!that)
- return ctx->engine()->throwTypeError();
- return QV4::Encode(that->d()->change.count);
+ THROW_TYPE_ERROR();
+ scope.result = QV4::Encode(that->d()->change.count);
}
- static QV4::ReturnedValue method_get_moveId(QV4::CallContext *ctx) {
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->thisObject().as<QQmlDelegateModelGroupChange>());
+ static void method_get_moveId(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) {
+ QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, callData->thisObject.as<QQmlDelegateModelGroupChange>());
if (!that)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (that->d()->change.moveId < 0)
- return QV4::Encode::undefined();
- return QV4::Encode(that->d()->change.moveId);
+ RETURN_UNDEFINED();
+ scope.result = QV4::Encode(that->d()->change.moveId);
}
};
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 4c2841b8ba..cb4a1f79ba 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -131,9 +131,9 @@ public:
virtual void setValue(const QString &role, const QVariant &value) { Q_UNUSED(role); Q_UNUSED(value); }
virtual bool resolveIndex(const QQmlAdaptorModel &, int) { return false; }
- static QV4::ReturnedValue get_model(QV4::CallContext *ctx);
- static QV4::ReturnedValue get_groups(QV4::CallContext *ctx);
- static QV4::ReturnedValue set_groups(QV4::CallContext *ctx);
+ static void get_model(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void get_groups(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void set_groups(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
static QV4::ReturnedValue get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &);
static QV4::ReturnedValue set_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
static QV4::ReturnedValue get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index 5f716da17a..f35e17c34d 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -185,7 +185,7 @@ public:
int m_nextId;
- static QV4::ReturnedValue method_sendMessage(QV4::CallContext *ctx);
+ static void method_sendMessage(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
signals:
void stopThread();
@@ -292,14 +292,13 @@ QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *eng
{
}
-QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(QV4::CallContext *ctx)
+void QQuickWorkerScriptEnginePrivate::method_sendMessage(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- WorkerEngine *engine = (WorkerEngine*)ctx->engine()->v8Engine;
+ WorkerEngine *engine = (WorkerEngine*)scope.engine->v8Engine;
- int id = ctx->argc() > 1 ? ctx->args()[1].toInt32() : 0;
+ int id = callData->argc > 1 ? callData->args[1].toInt32() : 0;
- QV4::Scope scope(ctx);
- QV4::ScopedValue v(scope, ctx->argument(2));
+ QV4::ScopedValue v(scope, callData->argument(2));
QByteArray data = QV4::Serialize::serialize(v, scope.engine);
QMutexLocker locker(&engine->p->m_lock);
@@ -307,7 +306,7 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(QV4::Call
if (script && script->owner)
QCoreApplication::postEvent(script->owner, new WorkerDataEvent(0, data));
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *script)