diff options
Diffstat (limited to 'src/qml/jsruntime')
45 files changed, 1090 insertions, 868 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index 4343924436..919524d1ed 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -27,6 +27,7 @@ SOURCES += \ $$PWD/qv4numberobject.cpp \ $$PWD/qv4object.cpp \ $$PWD/qv4objectproto.cpp \ + $$PWD/qv4qmlcontext.cpp \ $$PWD/qv4regexpobject.cpp \ $$PWD/qv4stringobject.cpp \ $$PWD/qv4variantobject.cpp \ @@ -48,7 +49,6 @@ HEADERS += \ $$PWD/qv4global_p.h \ $$PWD/qv4engine_p.h \ $$PWD/qv4context_p.h \ - $$PWD/qv4context_p_p.h \ $$PWD/qv4math_p.h \ $$PWD/qv4persistent_p.h \ $$PWD/qv4debugging_p.h \ @@ -73,6 +73,7 @@ HEADERS += \ $$PWD/qv4numberobject_p.h \ $$PWD/qv4object_p.h \ $$PWD/qv4objectproto_p.h \ + $$PWD/qv4qmlcontext_p.h \ $$PWD/qv4regexpobject_p.h \ $$PWD/qv4stringobject_p.h \ $$PWD/qv4variantobject_p.h \ diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 0dfdf25158..5a190d6690 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -39,7 +39,8 @@ #include <qv4argumentsobject_p.h> #include <qv4alloca_p.h> #include <qv4scopedvalue_p.h> -#include "qv4string_p.h" +#include <qv4string_p.h> +#include <qv4function_p.h> using namespace QV4; @@ -56,8 +57,6 @@ void Heap::ArgumentsObject::init(QV4::CallContext *context) Scope scope(v4); Scoped<QV4::ArgumentsObject> args(scope, this); - args->setArrayType(Heap::ArrayData::Complex); - if (context->d()->strictMode) { Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller())); @@ -83,7 +82,7 @@ void ArgumentsObject::fullyCreate() return; uint argCount = context()->callData->argc; - uint numAccessors = qMin(context()->function->formalParameterCount(), argCount); + uint numAccessors = qMin(context()->formalParameterCount(), argCount); ArrayData::realloc(this, Heap::ArrayData::Sparse, argCount, true); context()->engine->requireArgumentsAccessors(numAccessors); @@ -110,7 +109,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con ScopedProperty map(scope); PropertyAttributes mapAttrs; bool isMapped = false; - uint numAccessors = qMin((int)context()->function->formalParameterCount(), context()->callData->argc); + uint numAccessors = qMin((int)context()->formalParameterCount(), context()->callData->argc); if (pd && index < (uint)numAccessors) isMapped = arrayData()->attributes(index).isAccessor() && pd->getter() == context()->engine->argumentsAccessors[index].getter(); @@ -193,7 +192,7 @@ PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index) if (args->fullyCreated()) return Object::queryIndexed(m, index); - uint numAccessors = qMin((int)args->context()->function->formalParameterCount(), args->context()->callData->argc); + uint numAccessors = qMin((int)args->context()->formalParameterCount(), args->context()->callData->argc); uint argCount = args->context()->callData->argc; if (index >= argCount) return PropertyAttributes(); @@ -245,3 +244,11 @@ void ArgumentsObject::markObjects(Heap::Base *that, ExecutionEngine *e) Object::markObjects(that, e); } + +uint ArgumentsObject::getLength(const Managed *m) +{ + const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m); + if (a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->isInteger()) + return a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->integerValue(); + return Primitive::toUInt32(a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->doubleValue()); +} diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 37a8d0a94a..0a2ea3b42a 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -132,8 +132,10 @@ struct ArgumentsObject: Object { static bool deleteIndexedProperty(Managed *m, uint index); static PropertyAttributes queryIndexed(const Managed *m, uint index); static void markObjects(Heap::Base *that, ExecutionEngine *e); + static uint getLength(const Managed *m); void fullyCreate(); + }; } diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 390a5e7d7a..544d39339b 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -39,7 +39,7 @@ #include <QString> #include "qv4debugging_p.h" -#include <qv4context_p_p.h> +#include <qv4context_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> #include <private/qv4mm_p.h> @@ -47,6 +47,9 @@ #include "qv4function_p.h" #include "qv4errorobject_p.h" #include "qv4string_p.h" +#include "qv4qmlcontext_p.h" +#include "qv4profiling_p.h" +#include <private/qqmljavascriptexpression_p.h> using namespace QV4; @@ -55,29 +58,31 @@ DEFINE_MANAGED_VTABLE(CallContext); DEFINE_MANAGED_VTABLE(WithContext); DEFINE_MANAGED_VTABLE(CatchContext); DEFINE_MANAGED_VTABLE(GlobalContext); -DEFINE_MANAGED_VTABLE(QmlContext); -Heap::CallContext *ExecutionContext::newCallContext(const FunctionObject *function, CallData *callData) -{ - Q_ASSERT(function->function()); +/* Function *f, int argc */ +#define requiredMemoryForExecutionContect(f, argc) \ + ((sizeof(CallContext::Data) + 7) & ~7) + \ + sizeof(Value) * (f->compiledFunction->nLocals + qMax((uint)argc, f->nFormals)) + sizeof(CallData) +Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData) +{ Heap::CallContext *c = d()->engine->memoryManager->allocManaged<CallContext>( requiredMemoryForExecutionContect(function, callData->argc)); c->init(d()->engine, Heap::ExecutionContext::Type_CallContext); - c->function = function->d(); + c->v4Function = function; - c->strictMode = function->strictMode(); - c->outer = function->scope(); + c->strictMode = function->isStrict(); + c->outer = this->d(); c->activation = 0; - c->compilationUnit = function->function()->compilationUnit; + c->compilationUnit = function->compilationUnit; c->lookups = c->compilationUnit->runtimeLookups; c->constantTable = c->compilationUnit->constants; c->locals = (Value *)((quintptr(c + 1) + 7) & ~7); - const CompiledData::Function *compiledFunction = function->function()->compiledFunction; + const CompiledData::Function *compiledFunction = function->compiledFunction; int nLocals = compiledFunction->nLocals; if (nLocals) std::fill(c->locals, c->locals + nLocals, Primitive::undefinedValue()); @@ -102,20 +107,6 @@ Heap::CatchContext *ExecutionContext::newCatchContext(Heap::String *exceptionVar return d()->engine->memoryManager->alloc<CatchContext>(d(), exceptionVarName, e); } -Heap::QmlContext *ExecutionContext::newQmlContext(QmlContextWrapper *qml) -{ - Heap::QmlContext *c = d()->engine->memoryManager->alloc<QmlContext>(this, qml); - return c; -} - -Heap::QmlContext *ExecutionContext::newQmlContext(QQmlContextData *context, QObject *scopeObject) -{ - Scope scope(this); - Scoped<QmlContextWrapper> qml(scope, QmlContextWrapper::qmlScope(scope.engine, context, scopeObject)); - Heap::QmlContext *c = d()->engine->memoryManager->alloc<QmlContext>(this, qml); - return c; -} - void ExecutionContext::createMutableBinding(String *name, bool deletable) { Scope scope(this); @@ -182,38 +173,25 @@ void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionV this->exceptionValue = exceptionValue; } -void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml) -{ - Heap::ExecutionContext::init(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext); - outer = outerContext->d(); - strictMode = false; - callData = outer->callData; - lookups = outer->lookups; - constantTable = outer->constantTable; - compilationUnit = outer->compilationUnit; - - this->qml = qml->d(); -} - Identifier * const *CallContext::formals() const { - return (d()->function && d()->function->function) ? d()->function->function->internalClass->nameMap.constData() : 0; + return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() : 0; } unsigned int CallContext::formalCount() const { - return d()->function ? d()->function->formalParameterCount() : 0; + return d()->v4Function ? d()->v4Function->nFormals : 0; } Identifier * const *CallContext::variables() const { - return (d()->function && d()->function->function) ? d()->function->function->internalClass->nameMap.constData() + d()->function->formalParameterCount() : 0; + return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() + d()->v4Function->nFormals : 0; } unsigned int CallContext::variableCount() const { - return d()->function ? d()->function->varCount() : 0; + return d()->v4Function ? d()->v4Function->compiledFunction->nLocals : 0; } @@ -247,9 +225,8 @@ bool ExecutionContext::deleteProperty(String *name) case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - ScopedFunctionObject f(scope, c->function); - if (f->needsActivation() || hasWith) { - uint index = f->function()->internalClass->find(name); + if (c->v4Function && (c->v4Function->needsActivation() || hasWith)) { + uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) // ### throw in strict mode? return false; @@ -272,7 +249,8 @@ bool ExecutionContext::deleteProperty(String *name) bool CallContext::needsOwnArguments() const { - return d()->function->needsActivation() || argc() < static_cast<int>(d()->function->formalParameterCount()); + QV4::Function *f = d()->v4Function; + return (f && f->needsActivation()) || (argc() < (f ? static_cast<int>(f->nFormals) : 0)); } void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) @@ -304,14 +282,16 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) break; case Heap::ExecutionContext::Type_CallContext: { QV4::Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx); + Q_ASSERT(c->v4Function); ctx->callData->thisObject.mark(engine); - for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->function->formalParameterCount()); ++arg) + for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->v4Function->nFormals); ++arg) ctx->callData->args[arg].mark(engine); - for (unsigned local = 0, lastLocal = c->function->varCount(); local < lastLocal; ++local) + for (unsigned local = 0, lastLocal = c->v4Function->compiledFunction->nLocals; local < lastLocal; ++local) c->locals[local].mark(engine); if (c->activation) c->activation->mark(engine); - c->function->mark(engine); + if (c->function) + c->function->mark(engine); break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -322,6 +302,51 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) } } +// Do a standard call with this execution context as the outer scope +void ExecutionContext::call(Scope &scope, CallData *callData, Function *function, const FunctionObject *f) +{ + ExecutionContextSaver ctxSaver(scope); + + Scoped<CallContext> ctx(scope, newCallContext(function, callData)); + if (f) + ctx->d()->function = f->d(); + scope.engine->pushContext(ctx); + + scope.result = Q_V4_PROFILE(scope.engine, function); + + if (function->hasQmlDependencies) + QQmlPropertyCapture::registerQmlDependencies(function->compiledFunction, scope); +} + +// Do a simple, fast call with this execution context as the outer scope +void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Function *function) +{ + Q_ASSERT(function->canUseSimpleFunction()); + + ExecutionContextSaver ctxSaver(scope); + + CallContext::Data ctx = CallContext::Data::createOnStack(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); + 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.result = Q_V4_PROFILE(scope.engine, function); + + if (function->hasQmlDependencies) + QQmlPropertyCapture::registerQmlDependencies(function->compiledFunction, scope); +} + void ExecutionContext::setProperty(String *name, const Value &value) { Scope scope(this); @@ -354,13 +379,13 @@ void ExecutionContext::setProperty(String *name, const Value &value) case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - if (c->function->function) { - uint index = c->function->function->internalClass->find(name); + if (c->v4Function) { + uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) { - if (index < c->function->formalParameterCount()) { - c->callData->args[c->function->formalParameterCount() - index - 1] = value; + if (index < c->v4Function->nFormals) { + c->callData->args[c->v4Function->nFormals - index - 1] = value; } else { - index -= c->function->formalParameterCount(); + index -= c->v4Function->nFormals; c->locals[index] = value; } return; @@ -435,13 +460,12 @@ ReturnedValue ExecutionContext::getProperty(String *name) case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - ScopedFunctionObject f(scope, c->function); - if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) { - uint index = f->function()->internalClass->find(name); + if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { + uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) { - if (index < c->function->formalParameterCount()) - return c->callData->args[c->function->formalParameterCount() - index - 1].asReturnedValue(); - return c->locals[index - c->function->formalParameterCount()].asReturnedValue(); + if (index < c->v4Function->nFormals) + return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); + return c->locals[index - c->v4Function->nFormals].asReturnedValue(); } } ScopedObject activation(scope, c->activation); @@ -451,9 +475,9 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (hasProperty) return v->asReturnedValue(); } - if (f->function() && f->function()->isNamedExpression() - && name->equals(ScopedString(scope, f->function()->name()))) - return f.asReturnedValue(); + if (c->function && c->v4Function->isNamedExpression() + && name->equals(ScopedString(scope, c->v4Function->name()))) + return c->function->asReturnedValue(); break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -514,13 +538,12 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - ScopedFunctionObject f(scope, c->function); - if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) { - uint index = f->function()->internalClass->find(name); + if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { + uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) { - if (index < c->function->formalParameterCount()) - return c->callData->args[c->function->formalParameterCount() - index - 1].asReturnedValue(); - return c->locals[index - c->function->formalParameterCount()].asReturnedValue(); + if (index < c->v4Function->nFormals) + return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); + return c->locals[index - c->v4Function->nFormals].asReturnedValue(); } } ScopedObject activation(scope, c->activation); @@ -530,9 +553,9 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) if (hasProperty) return v->asReturnedValue(); } - if (f->function() && f->function()->isNamedExpression() - && name->equals(ScopedString(scope, f->function()->name()))) - return f.asReturnedValue(); + if (c->function && c->v4Function->isNamedExpression() + && name->equals(ScopedString(scope, c->v4Function->name()))) + return c->function->asReturnedValue(); break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -551,13 +574,13 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) return engine()->throwReferenceError(n); } -Heap::FunctionObject *ExecutionContext::getFunctionObject() const +Function *ExecutionContext::getFunction() const { Scope scope(d()->engine); ScopedContext it(scope, this->d()); for (; it; it = it->d()->outer) { if (const CallContext *callCtx = it->asCallContext()) - return callCtx->d()->function; + return callCtx->d()->v4Function; else if (it->asCatchContext() || it->asWithContext()) continue; // look in the parent context for a FunctionObject else diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 0b42288ccc..c985fdb24d 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -55,8 +55,8 @@ QT_BEGIN_NAMESPACE -class QQmlContextData; class QObject; +class QQmlContextData; namespace QV4 { @@ -65,11 +65,13 @@ struct CompilationUnit; struct Function; } -struct QmlContextWrapper; +struct Function; struct Identifier; struct CallContext; struct CatchContext; struct WithContext; +struct QmlContext; +struct QmlContextWrapper; struct CallData { @@ -91,6 +93,8 @@ struct CallData namespace Heap { +struct QmlContext; + struct ExecutionContext : Base { enum ContextType { Type_GlobalContext = 0x1, @@ -137,11 +141,15 @@ struct CallContext : ExecutionContext { { ExecutionContext::init(engine, t); function = 0; + v4Function = 0; locals = 0; activation = 0; } + inline unsigned int formalParameterCount() const; + Pointer<FunctionObject> function; + QV4::Function *v4Function; Value *locals; Pointer<Object> activation; }; @@ -177,14 +185,6 @@ struct WithContext : ExecutionContext { }; V4_ASSERT_IS_TRIVIAL(WithContext) -struct QmlContextWrapper; - -struct QmlContext : ExecutionContext { - void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml); - - Pointer<QmlContextWrapper> qml; -}; - } struct Q_QML_EXPORT ExecutionContext : public Managed @@ -198,11 +198,9 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ExecutionEngine *engine() const { return d()->engine; } - Heap::CallContext *newCallContext(const FunctionObject *f, CallData *callData); + Heap::CallContext *newCallContext(Function *f, CallData *callData); Heap::WithContext *newWithContext(Heap::Object *with); Heap::CatchContext *newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue); - Heap::QmlContext *newQmlContext(QmlContextWrapper *qml); - Heap::QmlContext *newQmlContext(QQmlContextData *context, QObject *scopeObject); void createMutableBinding(String *name, bool deletable); @@ -216,7 +214,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed inline const CatchContext *asCatchContext() const; inline const WithContext *asWithContext() const; - Heap::FunctionObject *getFunctionObject() const; + Function *getFunction() const; static void markObjects(Heap::Base *m, ExecutionEngine *e); @@ -232,6 +230,9 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ReturnedValue argument(int i) const { return d()->callData->argument(i); } + + void call(Scope &scope, CallData *callData, QV4::Function *function, const QV4::FunctionObject *f = 0); + void simpleCall(Scope &scope, CallData *callData, QV4::Function *function); }; struct Q_QML_EXPORT CallContext : public ExecutionContext @@ -244,11 +245,11 @@ struct Q_QML_EXPORT CallContext : public ExecutionContext Identifier * const *variables() const; unsigned int variableCount() const; - inline ReturnedValue argument(int i); + inline ReturnedValue argument(int i) const; bool needsOwnArguments() const; }; -inline ReturnedValue CallContext::argument(int i) { +inline ReturnedValue CallContext::argument(int i) const { return i < argc() ? args()[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue(); } @@ -268,16 +269,6 @@ struct WithContext : public ExecutionContext V4_MANAGED(WithContext, ExecutionContext) }; -struct Q_QML_EXPORT QmlContext : public ExecutionContext -{ - V4_MANAGED(QmlContext, ExecutionContext) - - QObject *qmlScope() const; - QQmlContextData *qmlContext() const; - - void takeContextOwnership(); -}; - inline CallContext *ExecutionContext::asCallContext() { return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0; @@ -308,10 +299,6 @@ inline Heap::CallContext Heap::CallContext::createOnStack(ExecutionEngine *v4) return ctxt; } -/* Function *f, int argc */ -#define requiredMemoryForExecutionContect(f, argc) \ - ((sizeof(CallContext::Data) + 7) & ~7) + sizeof(Value) * (f->varCount() + qMax((uint)argc, f->formalParameterCount())) + sizeof(CallData) - } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 4f3138a452..8cc6a25fea 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -689,8 +689,8 @@ void DateCtor::construct(const Managed *, Scope &scope, CallData *callData) } else { arg = RuntimeHelpers::toPrimitive(arg, PREFERREDTYPE_HINT); - if (arg->isString()) - t = ParseString(arg->stringValue()->toQString()); + if (String *s = arg->stringValue()) + t = ParseString(s->toQString()); else t = TimeClip(arg->toNumber()); } @@ -1319,14 +1319,17 @@ ReturnedValue DatePrototype::method_toISOString(CallContext *ctx) ReturnedValue DatePrototype::method_toJSON(CallContext *ctx) { Scope scope(ctx); - ScopedValue O(scope, RuntimeHelpers::toObject(scope.engine, ctx->thisObject())); + ScopedObject O(scope, ctx->thisObject().toObject(scope.engine)); + if (scope.hasException()) + return Encode::undefined(); + ScopedValue tv(scope, RuntimeHelpers::toPrimitive(O, NUMBER_HINT)); if (tv->isNumber() && !std::isfinite(tv->toNumber())) return Encode::null(); ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toISOString"))); - ScopedValue v(scope, O->objectValue()->get(s)); + ScopedValue v(scope, O->get(s)); FunctionObject *toIso = v->as<FunctionObject>(); if (!toIso) diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index 2d0648396e..835f6adbe0 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -101,7 +101,7 @@ struct DateObject: Object { template<> inline const DateObject *Value::as() const { - return isManaged() && m() && m()->vtable()->type == Managed::Type_DateObject ? static_cast<const DateObject *>(this) : 0; + return isManaged() && m()->vtable()->type == Managed::Type_DateObject ? static_cast<const DateObject *>(this) : 0; } struct DateCtor: FunctionObject diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 7265952f72..8f2c5174da 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ #include <qv4engine_p.h> -#include <qv4context_p.h> +#include <qv4qmlcontext_p.h> #include <qv4value_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> @@ -71,7 +71,6 @@ #include "qv4typedarray_p.h" #include <private/qv8engine_p.h> #include <private/qjsvalue_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <private/qqmltypewrapper_p.h> #include <private/qqmlvaluetypewrapper_p.h> #include <private/qqmlvaluetype_p.h> @@ -282,10 +281,10 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(functionProtoClass, objectPrototype()); functionClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - simpleScriptFunctionClass = functionClass->addMember(id_name(), Attr_ReadOnly, &index); - Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Name); - simpleScriptFunctionClass = simpleScriptFunctionClass->addMember(id_length(), Attr_ReadOnly, &index); - Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Length); + scriptFunctionClass = functionClass->addMember(id_name(), Attr_ReadOnly, &index); + Q_ASSERT(index == Heap::ScriptFunction::Index_Name); + scriptFunctionClass = scriptFunctionClass->addMember(id_length(), Attr_ReadOnly, &index); + Q_ASSERT(index == Heap::ScriptFunction::Index_Length); protoClass = emptyClass->addMember(id_constructor(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor); @@ -714,6 +713,27 @@ Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o) return obj->d(); } +Heap::QmlContext *ExecutionEngine::qmlContext() const +{ + Heap::ExecutionContext *ctx = current; + + // get the correct context when we're within a builtin function + if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) + ctx = parentContext(currentContext)->d(); + + if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer) + return 0; + + while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext) + ctx = ctx->outer; + + Q_ASSERT(ctx); + if (ctx->type != Heap::ExecutionContext::Type_QmlContext) + return 0; + + return static_cast<Heap::QmlContext *>(ctx); +} + QObject *ExecutionEngine::qmlScopeObject() const { Heap::QmlContext *ctx = qmlContext(); @@ -760,21 +780,17 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const QVector<StackFrame> stack; ExecutionContext *c = currentContext; - ScopedFunctionObject function(scope); while (c && frameLimit) { - function = c->getFunctionObject(); + QV4::Function *function = c->getFunction(); if (function) { StackFrame frame; - if (const Function *f = function->function()) - frame.source = f->sourceFile(); + frame.source = function->sourceFile(); name = function->name(); frame.function = name->toQString(); - frame.line = -1; - frame.column = -1; - if (function->function()) - // line numbers can be negative for places where you can't set a real breakpoint - frame.line = qAbs(c->d()->lineNumber); + // line numbers can be negative for places where you can't set a real breakpoint + frame.line = qAbs(c->d()->lineNumber); + frame.column = -1; stack.append(frame); --frameLimit; @@ -850,9 +866,8 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) ExecutionContext *c = currentContext; while (c) { CallContext *callCtx = c->asCallContext(); - if (callCtx && callCtx->d()->function) { - if (callCtx->d()->function->function) - base.setUrl(callCtx->d()->function->function->sourceFile()); + if (callCtx && callCtx->d()->v4Function) { + base.setUrl(callCtx->d()->v4Function->sourceFile()); break; } c = parentContext(c); @@ -1151,8 +1166,8 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return value.integerValue(); if (value.isNumber()) return value.asDouble(); - if (value.isString()) { - const QString &str = value.toQString(); + if (String *s = value.stringValue()) { + const QString &str = s->toQString(); // QChars are stored as a strings if (typeHint == QVariant::Char && str.size() == 1) return str.at(0); @@ -1591,8 +1606,8 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->toInt32()); return true; case QMetaType::QChar: - if (value->isString()) { - QString str = value->stringValue()->toQString(); + if (String *s = value->stringValue()) { + QString str = s->toQString(); *reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0); } else { *reinterpret_cast<QChar*>(data) = QChar(ushort(value->toUInt16())); @@ -1704,10 +1719,10 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) // We have T t, T* is requested, so return &t. *reinterpret_cast<void* *>(data) = var.data(); return true; - } else if (value->isObject()) { + } else if (Object *o = value->objectValue()) { // Look in the prototype chain. QV4::Scope scope(this); - QV4::ScopedObject proto(scope, value->objectValue()->prototype()); + QV4::ScopedObject proto(scope, o->prototype()); while (proto) { bool canCast = false; if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) { diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 25d6fc1970..1c20ad30aa 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -128,7 +128,8 @@ public: --jsStackTop; return jsStackTop->heapObject(); } - Value *jsAlloca(int nValues) { + + QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) { Value *ptr = jsStackTop; jsStackTop = ptr + nValues; for (int i = 0; i < nValues; ++i) @@ -254,7 +255,7 @@ public: InternalClass *stringClass; InternalClass *functionClass; - InternalClass *simpleScriptFunctionClass; + InternalClass *scriptFunctionClass; InternalClass *protoClass; InternalClass *regExpExecArrayClass; @@ -547,27 +548,6 @@ inline ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *contex return o ? context - o : 0; } -inline Heap::QmlContext *ExecutionEngine::qmlContext() const -{ - Heap::ExecutionContext *ctx = current; - - // get the correct context when we're within a builtin function - if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) - ctx = parentContext(currentContext)->d(); - - if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer) - return 0; - - while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext) - ctx = ctx->outer; - - Q_ASSERT(ctx); - if (ctx->type != Heap::ExecutionContext::Type_QmlContext) - return 0; - - return static_cast<Heap::QmlContext *>(ctx); -} - inline void Heap::Base::mark(QV4::ExecutionEngine *engine) { @@ -583,9 +563,6 @@ void Heap::Base::mark(QV4::ExecutionEngine *engine) inline void Value::mark(ExecutionEngine *e) { - if (!isManaged()) - return; - Heap::Base *o = heapObject(); if (o) o->mark(e); diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 42a6e0b4b1..2b3ab25e2d 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -178,7 +178,7 @@ struct ErrorObject: Object { template<> inline const ErrorObject *Value::as() const { - return isManaged() && m() && m()->vtable()->isErrorObject ? reinterpret_cast<const ErrorObject *>(this) : 0; + return isManaged() && m()->vtable()->isErrorObject ? reinterpret_cast<const ErrorObject *>(this) : 0; } struct EvalErrorObject: ErrorObject { diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index caabee322a..358c2d079c 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -55,6 +55,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, , compilationUnit(unit) , code(codePtr) , codeData(0) + , hasQmlDependencies(function->hasQmlDependencies()) { Q_UNUSED(engine); @@ -83,6 +84,9 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); activationRequired = compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject)); + + canUseSimpleCall = !needsActivation() && !(compiledFunction->flags & CompiledData::Function::HasCatchOrWith) && + !(compiledFunction->nFormals > QV4::Global::ReservedArgumentCount) && !isNamedExpression(); } Function::~Function() diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index aeef9ad61b..54d0528c42 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -51,7 +51,9 @@ // #include "qv4global_p.h" +#include <private/qqmlglobal_p.h> #include <private/qv4compileddata_p.h> +#include <private/qv4context_p.h> QT_BEGIN_NAMESPACE @@ -68,6 +70,8 @@ struct Q_QML_EXPORT Function { InternalClass *internalClass; uint nFormals; bool activationRequired; + bool hasQmlDependencies; + bool canUseSimpleCall; Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, ReturnedValue (*codePtr)(ExecutionEngine *, const uchar *)); @@ -88,8 +92,22 @@ struct Q_QML_EXPORT Function { inline bool needsActivation() const { return activationRequired; } + inline bool canUseSimpleFunction() const { return canUseSimpleCall; } + + QQmlSourceLocation sourceLocation() const + { + return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column); + } + }; + +inline unsigned int Heap::CallContext::formalParameterCount() const +{ + return v4Function ? v4Function->nFormals : 0; +} + + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 2cc58b74a6..64f7b98618 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -47,6 +47,7 @@ #include "qv4arrayobject_p.h" #include "qv4scopedvalue_p.h" +#include "qv4argumentsobject_p.h" #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> @@ -81,7 +82,8 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function, bool createProto) { Object::init(); - function = nullptr; + this->function = function; + function->compilationUnit->addref(); this->scope = scope->d(); Scope s(scope->engine()); ScopedString name(s, function->name()); @@ -91,46 +93,9 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const QString &name, bool createProto) { - Object::init(); - function = nullptr; - this->scope = scope->d(); - Scope s(scope->engine()); - ScopedFunctionObject f(s, this); - ScopedString n(s, s.engine->newString(name)); - f->init(n, createProto); -} - -void Heap::FunctionObject::init(ExecutionContext *scope, const QString &name, bool createProto) -{ - Object::init(); - function = nullptr; - this->scope = scope; - Scope s(scope->engine); - ScopedFunctionObject f(s, this); - ScopedString n(s, s.engine->newString(name)); - f->init(n, createProto); -} - -void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const ReturnedValue name) -{ - Object::init(); - function = nullptr; - this->scope = scope->d(); - Scope s(scope); - ScopedFunctionObject f(s, this); - ScopedString n(s, name); - f->init(n, false); -} - -void Heap::FunctionObject::init(ExecutionContext *scope, const ReturnedValue name) -{ - Object::init(); - function = nullptr; - this->scope = scope; - Scope s(scope->engine); - ScopedFunctionObject f(s, this); - ScopedString n(s, name); - f->init(n, false); + Scope valueScope(scope); + ScopedString s(valueScope, valueScope.engine->newString(name)); + init(scope, s, createProto); } void Heap::FunctionObject::init() @@ -165,8 +130,8 @@ void FunctionObject::init(String *n, bool createProto) *propertyData(Heap::FunctionObject::Index_Prototype) = Encode::undefined(); } - ScopedValue v(s, n); - defineReadonlyProperty(s.engine->id_name(), v); + if (n) + defineReadonlyProperty(s.engine->id_name(), *n); } ReturnedValue FunctionObject::name() const @@ -193,34 +158,11 @@ void FunctionObject::markObjects(Heap::Base *that, ExecutionEngine *e) Object::markObjects(that, e); } -Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function, bool createProto) +Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function) { - if (function->needsActivation() || - function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith || - function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount || - function->isNamedExpression()) - return scope->d()->engine->memoryManager->allocObject<ScriptFunction>(scope, function); - return scope->d()->engine->memoryManager->allocObject<SimpleScriptFunction>(scope, function, createProto); + return scope->d()->engine->memoryManager->allocObject<ScriptFunction>(scope, function); } -Heap::FunctionObject *FunctionObject::createQmlFunction(QQmlContextData *qmlContext, QObject *scopeObject, Function *runtimeFunction, const QList<QByteArray> &signalParameters, QString *error) -{ - ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine); - QV4::Scope valueScope(engine); - ExecutionContext *global = valueScope.engine->rootContext(); - QV4::Scoped<QmlContext> wrapperContext(valueScope, global->newQmlContext(qmlContext, scopeObject)); - - if (!signalParameters.isEmpty()) { - if (error) - QQmlPropertyCache::signalParameterStringForJS(engine, signalParameters, error); - runtimeFunction->updateInternalClass(engine, signalParameters); - } - - QV4::ScopedFunctionObject function(valueScope, QV4::FunctionObject::createScriptFunction(wrapperContext, runtimeFunction)); - return function->d(); -} - - bool FunctionObject::isBinding() const { return d()->vtable() == QQmlBindingFunction::staticVTable(); @@ -233,14 +175,7 @@ bool FunctionObject::isBoundFunction() const QQmlSourceLocation FunctionObject::sourceLocation() const { - if (isBinding()) { - Q_ASSERT(as<const QV4::QQmlBindingFunction>()); - return *static_cast<QV4::Heap::QQmlBindingFunction *>(d())->bindingLocation; - } - QV4::Function *function = d()->function; - Q_ASSERT(function); - - return QQmlSourceLocation(function->sourceFile(), function->compiledFunction->location.line, function->compiledFunction->location.column); + return d()->function->sourceLocation(); } DEFINE_OBJECT_VTABLE(FunctionCtor); @@ -346,11 +281,11 @@ ReturnedValue FunctionPrototype::method_toString(CallContext *ctx) ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) { - Scope scope(ctx); - ScopedFunctionObject o(scope, ctx->thisObject().as<FunctionObject>()); + FunctionObject *o = ctx->thisObject().as<FunctionObject>(); if (!o) return ctx->engine()->throwTypeError(); + Scope scope(ctx); ScopedValue arg(scope, ctx->argument(1)); ScopedObject arr(scope, arg); @@ -367,17 +302,24 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) ScopedCallData callData(scope, len); if (len) { - if (arr->arrayType() != Heap::ArrayData::Simple || arr->protoHasArray()) { - for (quint32 i = 0; i < len; ++i) - callData->args[i] = arr->getIndexed(i); - } else { - uint alen = arr->arrayData() ? arr->arrayData()->len : 0; + 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)); + for (quint32 i = l; i < len; ++i) + callData->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] = static_cast<Heap::SimpleArrayData *>(arr->arrayData())->data(i); + callData->args[i] = sad->data(i); for (quint32 i = alen; i < len; ++i) callData->args[i] = Primitive::undefinedValue(); + } else { + for (quint32 i = 0; i < len; ++i) + callData->args[i] = arr->getIndexed(i); } } @@ -388,12 +330,11 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) ReturnedValue FunctionPrototype::method_call(CallContext *ctx) { - Scope scope(ctx); - - ScopedFunctionObject o(scope, ctx->thisObject().as<FunctionObject>()); + FunctionObject *o = ctx->thisObject().as<FunctionObject>(); if (!o) return ctx->engine()->throwTypeError(); + Scope scope(ctx); ScopedCallData callData(scope, ctx->argc() ? ctx->argc() - 1 : 0); if (ctx->argc()) { for (int i = 1; i < ctx->argc(); ++i) @@ -407,11 +348,11 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx) ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) { - Scope scope(ctx); - ScopedFunctionObject target(scope, ctx->thisObject()); + FunctionObject *target = ctx->thisObject().as<FunctionObject>(); if (!target) return ctx->engine()->throwTypeError(); + Scope scope(ctx); ScopedValue boundThis(scope, ctx->argument(0)); Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0); if (ctx->argc() > 1) { @@ -426,15 +367,10 @@ ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) DEFINE_OBJECT_VTABLE(ScriptFunction); -void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function) -{ - Heap::SimpleScriptFunction::init(scope, function, true); -} - void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData) { ExecutionEngine *v4 = scope.engine; - if (v4->hasException) { + if (Q_UNLIKELY(v4->hasException)) { scope.result = Encode::undefined(); return; } @@ -447,17 +383,18 @@ void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *call InternalClass *ic = v4->emptyClass; ScopedObject proto(scope, f->protoForConstructor()); ScopedObject obj(scope, v4->newObject(ic, proto)); - callData->thisObject = obj.asReturnedValue(); - Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData)); - v4->pushContext(ctx); - scope.result = Q_V4_PROFILE(v4, f->function()); + QV4::Function *v4Function = f->function(); + Q_ASSERT(v4Function); - if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); + ScopedContext c(scope, f->scope()); + if (v4Function->canUseSimpleCall) + c->simpleCall(scope, callData, v4Function); + else + c->call(scope, callData, v4Function, f); - if (v4->hasException) { + if (Q_UNLIKELY(v4->hasException)) { scope.result = Encode::undefined(); } else if (!scope.result.isObject()) { scope.result = obj.asReturnedValue(); @@ -467,27 +404,25 @@ void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *call void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData) { ExecutionEngine *v4 = scope.engine; - if (v4->hasException) { + if (Q_UNLIKELY(v4->hasException)) { scope.result = Encode::undefined(); return; } CHECK_STACK_LIMITS(v4, scope); - ExecutionContextSaver ctxSaver(scope); - Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); - Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData)); - v4->pushContext(ctx); - scope.result = Q_V4_PROFILE(v4, f->function()); + QV4::Function *v4Function = f->function(); + Q_ASSERT(v4Function); - if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); + ScopedContext c(scope, f->scope()); + if (v4Function->canUseSimpleCall) + c->simpleCall(scope, callData, v4Function); + else + c->call(scope, callData, v4Function, f); } -DEFINE_OBJECT_VTABLE(SimpleScriptFunction); - -void Heap::SimpleScriptFunction::init(QV4::ExecutionContext *scope, Function *function, bool createProto) +void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function) { FunctionObject::init(); this->scope = scope->d(); @@ -500,16 +435,10 @@ void Heap::SimpleScriptFunction::init(QV4::ExecutionContext *scope, Function *fu Scope s(scope); ScopedFunctionObject f(s, this); - if (createProto) { - ScopedString name(s, function->name()); - f->init(name, createProto); - f->defineReadonlyProperty(scope->d()->engine->id_length(), Primitive::fromInt32(f->formalParameterCount())); - } else { - Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length); - Q_ASSERT(internalClass && internalClass->find(s.engine->id_name()) == Index_Name); - *propertyData(Index_Name) = function->name(); - *propertyData(Index_Length) = Primitive::fromInt32(f->formalParameterCount()); - } + ScopedString name(s, function->name()); + f->init(name, true); + Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length); + *propertyData(Index_Length) = Primitive::fromInt32(f->formalParameterCount()); if (scope->d()->strictMode) { ScopedProperty pd(s); @@ -520,89 +449,12 @@ void Heap::SimpleScriptFunction::init(QV4::ExecutionContext *scope, Function *fu } } -void SimpleScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData) -{ - ExecutionEngine *v4 = scope.engine; - if (v4->hasException) { - scope.result = Encode::undefined(); - return; - } - CHECK_STACK_LIMITS(v4, scope); - - ExecutionContextSaver ctxSaver(scope); - - Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); - - InternalClass *ic = scope.engine->emptyClass; - ScopedObject proto(scope, f->protoForConstructor()); - callData->thisObject = v4->newObject(ic, proto); - - CallContext::Data ctx = CallContext::Data::createOnStack(v4); - ctx.strictMode = f->strictMode(); - ctx.callData = callData; - ctx.function = f->d(); - ctx.compilationUnit = f->function()->compilationUnit; - ctx.lookups = ctx.compilationUnit->runtimeLookups; - ctx.constantTable = ctx.compilationUnit->constants; - ctx.outer = f->scope(); - ctx.locals = scope.alloc(f->varCount()); - for (int i = callData->argc; i < (int)f->formalParameterCount(); ++i) - callData->args[i] = Encode::undefined(); - v4->pushContext(&ctx); - Q_ASSERT(v4->current == &ctx); - - scope.result = Q_V4_PROFILE(v4, f->function()); - - if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); - - if (v4->hasException) { - scope.result = Encode::undefined(); - } else if (!scope.result.isObject()) { - scope.result = callData->thisObject; - } -} - -void SimpleScriptFunction::call(const Managed *that, Scope &scope, CallData *callData) -{ - ExecutionEngine *v4 = scope.engine; - if (v4->hasException) { - scope.result = Encode::undefined(); - return; - } - CHECK_STACK_LIMITS(v4, scope); - - ExecutionContextSaver ctxSaver(scope); - - Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); - - CallContext::Data ctx = CallContext::Data::createOnStack(v4); - ctx.strictMode = f->strictMode(); - ctx.callData = callData; - ctx.function = f->d(); - ctx.compilationUnit = f->function()->compilationUnit; - ctx.lookups = ctx.compilationUnit->runtimeLookups; - ctx.constantTable = ctx.compilationUnit->constants; - ctx.outer = f->scope(); - ctx.locals = scope.alloc(f->varCount()); - for (int i = callData->argc; i < (int)f->formalParameterCount(); ++i) - callData->args[i] = Encode::undefined(); - v4->pushContext(&ctx); - Q_ASSERT(v4->current == &ctx); - - scope.result = Q_V4_PROFILE(v4, f->function()); - - if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); -} - -Heap::Object *SimpleScriptFunction::protoForConstructor() +Heap::Object *ScriptFunction::protoForConstructor() const { - Scope scope(engine()); - ScopedObject p(scope, protoProperty()); - if (p) - return p->d(); - return scope.engine->objectPrototype()->d(); + const Object *o = d()->protoProperty(); + if (o) + return o->d(); + return engine()->objectPrototype()->d(); } diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index e58b83e2c3..a02e89e883 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -69,12 +69,9 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { Index_ProtoConstructor = 0 }; - void init(QV4::ExecutionContext *scope, QV4::String *name, bool createProto = false); + void init(QV4::ExecutionContext *scope, QV4::String *name = 0, bool createProto = false); void init(QV4::ExecutionContext *scope, QV4::Function *function, bool createProto = false); - void init(QV4::ExecutionContext *scope, const QString &name = QString(), bool createProto = false); - void init(ExecutionContext *scope, const QString &name = QString(), bool createProto = false); - void init(QV4::ExecutionContext *scope, const ReturnedValue name); - void init(ExecutionContext *scope, const ReturnedValue name); + void init(QV4::ExecutionContext *scope, const QString &name, bool createProto = false); void init(); void destroy(); @@ -82,6 +79,8 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } bool needsActivation() const { return function ? function->needsActivation() : false; } + const QV4::Object *protoProperty() const { return propertyData(Index_Prototype)->cast<QV4::Object>(); } + Pointer<ExecutionContext> scope; Function *function; }; @@ -105,15 +104,11 @@ struct IndexedBuiltinFunction : FunctionObject { uint index; }; -struct SimpleScriptFunction : FunctionObject { +struct ScriptFunction : FunctionObject { enum { Index_Name = FunctionObject::Index_Prototype + 1, Index_Length }; - void init(QV4::ExecutionContext *scope, Function *function, bool createProto); -}; - -struct ScriptFunction : SimpleScriptFunction { void init(QV4::ExecutionContext *scope, Function *function); }; @@ -150,11 +145,7 @@ struct Q_QML_EXPORT FunctionObject: Object { static void construct(const Managed *that, Scope &scope, CallData *); static void call(const Managed *that, Scope &scope, CallData *d); - static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true); - static Heap::FunctionObject *createQmlFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, - const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0); - - ReturnedValue protoProperty() { return propertyData(Heap::FunctionObject::Index_Prototype)->asReturnedValue(); } + static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function); bool needsActivation() const { return d()->needsActivation(); } bool strictMode() const { return d()->function ? d()->function->isStrict() : false; } @@ -168,7 +159,7 @@ struct Q_QML_EXPORT FunctionObject: Object { template<> inline const FunctionObject *Value::as() const { - return isManaged() && m() && m()->vtable()->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : 0; + return isManaged() && m()->vtable()->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : 0; } @@ -225,21 +216,14 @@ void Heap::IndexedBuiltinFunction::init(QV4::ExecutionContext *scope, uint index } -struct SimpleScriptFunction: FunctionObject { - V4_OBJECT2(SimpleScriptFunction, FunctionObject) - V4_INTERNALCLASS(simpleScriptFunctionClass) - - static void construct(const Managed *, Scope &scope, CallData *callData); - static void call(const Managed *that, Scope &scope, CallData *callData); - - Heap::Object *protoForConstructor(); -}; - -struct ScriptFunction: SimpleScriptFunction { +struct ScriptFunction : FunctionObject { V4_OBJECT2(ScriptFunction, FunctionObject) + V4_INTERNALCLASS(scriptFunctionClass) static void construct(const Managed *, Scope &scope, CallData *callData); static void call(const Managed *that, Scope &scope, CallData *callData); + + Heap::Object *protoForConstructor() const; }; diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 184375a9b6..c37ad1668d 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -58,6 +58,12 @@ #include <QtCore/qglobal.h> #include <QString> +#ifdef QT_NO_DEBUG +#define QML_NEARLY_ALWAYS_INLINE Q_ALWAYS_INLINE +#else +#define QML_NEARLY_ALWAYS_INLINE inline +#endif + #ifdef V4_BOOTSTRAP #include <private/qtqmldevtoolsglobal_p.h> #else diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index feb0d90d26..af92ce1ad8 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -357,12 +357,13 @@ void EvalFunction::evalCall(Scope &scope, CallData *callData, bool directCall) c ctx = v4->pushGlobalContext(); } - if (!callData->args[0].isString()) { + String *scode = callData->args[0].stringValue(); + if (!scode) { scope.result = callData->args[0].asReturnedValue(); return; } - const QString code = callData->args[0].stringValue()->toQString(); + const QString code = scode->toQString(); bool inheritContext = !ctx->d()->strictMode; Script script(ctx, code, QStringLiteral("eval code")); diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index be8057e9f5..1d393cf0aa 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -53,7 +53,6 @@ #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> #include <private/qv4context_p.h> -#include <private/qqmlcontextwrapper_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 94a6e4daa1..d79e6242ba 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -727,8 +727,8 @@ QString Stringify::Str(const QString &key, const Value &v) return QStringLiteral("null"); if (scope.result.isBoolean()) return scope.result.booleanValue() ? QStringLiteral("true") : QStringLiteral("false"); - if (scope.result.isString()) - return quote(scope.result.stringValue()->toQString()); + if (String *s = scope.result.stringValue()) + return quote(s->toQString()); if (scope.result.isNumber()) { double d = scope.result.toNumber(); @@ -917,7 +917,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) Value *v = stringify.propertyList + i; *v = o->getIndexed(i); if (v->as<NumberObject>() || v->as<StringObject>() || v->isNumber()) - *v = RuntimeHelpers::toString(scope.engine, *v); + *v = v->toString(scope.engine); if (!v->isString()) { v->setM(0); } else { @@ -940,8 +940,8 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) if (s->isNumber()) { stringify.gap = QString(qMin(10, (int)s->toInteger()), ' '); - } else if (s->isString()) { - stringify.gap = s->stringValue()->toQString().left(10); + } else if (String *str = s->stringValue()) { + stringify.gap = str->toQString().left(10); } @@ -982,8 +982,8 @@ QJsonValue JsonObject::toJsonValue(const Value &value, V4ObjectSet &visitedObjec return QJsonValue(QJsonValue::Null); else if (value.isUndefined()) return QJsonValue(QJsonValue::Undefined); - else if (value.isString()) - return QJsonValue(value.toQString()); + else if (String *s = value.stringValue()) + return QJsonValue(s->toQString()); Q_ASSERT(value.isObject()); Scope scope(value.as<Object>()->engine()); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 84755a6402..52ed449664 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -118,7 +118,8 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, const Value &object, const Value &index) { - if (object.isObject() && index.asArrayIndex() < UINT_MAX) { + uint idx; + if (object.isObject() && index.asArrayIndex(idx)) { l->indexedGetter = indexedGetterObjectInt; return indexedGetterObjectInt(l, object, index); } @@ -129,11 +130,12 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons { Q_UNUSED(l); Scope scope(l->engine); - uint idx = index.asArrayIndex(); + uint idx = 0; + bool isInt = index.asArrayIndex(idx); ScopedObject o(scope, object); if (!o) { - if (idx < UINT_MAX) { + if (isInt) { if (const String *str = object.as<String>()) { if (idx >= (uint)str->toQString().length()) { return Encode::undefined(); @@ -153,7 +155,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons return Encode::undefined(); } - if (idx < UINT_MAX) { + if (isInt) { if (o->d()->arrayData && !o->d()->arrayData->attrs) { ScopedValue v(scope, Scoped<ArrayData>(scope, o->arrayData())->get(idx)); if (!v->isEmpty()) @@ -173,16 +175,19 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, const Value &index) { - uint idx = index.asArrayIndex(); - if (idx == UINT_MAX || !object.isObject()) - return indexedGetterFallback(l, object, index); - - Object *o = object.objectValue(); - if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); - if (idx < s->len) - if (!s->data(idx).isEmpty()) - return s->data(idx).asReturnedValue(); + uint idx; + if (index.asArrayIndex(idx)) { + if (Heap::Base *b = object.heapObject()) { + if (b->vtable()->isObject) { + Heap::Object *o = static_cast<Heap::Object *>(b); + if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { + Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>(); + if (idx < s->len) + if (!s->data(idx).isEmpty()) + return s->data(idx).asReturnedValue(); + } + } + } } return indexedGetterFallback(l, object, index); @@ -190,9 +195,9 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con void Lookup::indexedSetterGeneric(Lookup *l, const Value &object, const Value &index, const Value &v) { - if (object.isObject()) { - Object *o = object.objectValue(); - if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple && index.asArrayIndex() < UINT_MAX) { + if (Object *o = object.objectValue()) { + uint idx; + if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple && index.asArrayIndex(idx)) { l->indexedSetter = indexedSetterObjectInt; indexedSetterObjectInt(l, object, index, v); return; @@ -208,8 +213,8 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value & if (scope.engine->hasException) return; - uint idx = index.asArrayIndex(); - if (idx < UINT_MAX) { + uint idx; + if (index.asArrayIndex(idx)) { if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); if (idx < s->len) { @@ -227,18 +232,19 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value & void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value &index, const Value &v) { - uint idx = index.asArrayIndex(); - if (idx == UINT_MAX || !object.isObject()) { - indexedSetterGeneric(l, object, index, v); - return; - } - - Object *o = object.objectValue(); - if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); - if (idx < s->len) { - s->data(idx) = v; - return; + uint idx; + if (index.asArrayIndex(idx)) { + if (Heap::Base *b = object.heapObject()) { + if (b->vtable()->isObject) { + Heap::Object *o = static_cast<Heap::Object *>(b); + if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { + Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>(); + if (idx < s->len) { + s->data(idx) = v; + return; + } + } + } } } indexedSetterFallback(l, object, index, v); @@ -345,11 +351,11 @@ ReturnedValue Lookup::getterFallback(Lookup *l, ExecutionEngine *engine, const V ReturnedValue Lookup::getter0(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass()) + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) return o->propertyData(l->index)->asReturnedValue(); } return getterTwoClasses(l, engine, object); @@ -357,25 +363,24 @@ ReturnedValue Lookup::getter0(Lookup *l, ExecutionEngine *engine, const Value &o ReturnedValue Lookup::getter1(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass() && - l->classList[1] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index)->asReturnedValue(); + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass && l->classList[1] == o->prototype->internalClass) + return o->prototype->propertyData(l->index)->asReturnedValue(); } return getterTwoClasses(l, engine, object); } ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass()) { - Heap::Object *p = o->prototype(); + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) { + Heap::Object *p = o->prototype; if (l->classList[1] == p->internalClass) { p = p->prototype; if (l->classList[2] == p->internalClass) @@ -389,13 +394,13 @@ ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &o ReturnedValue Lookup::getter0getter0(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass()) + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) return o->propertyData(l->index)->asReturnedValue(); - if (l->classList[2] == o->internalClass()) + if (l->classList[2] == o->internalClass) return o->propertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; @@ -404,15 +409,14 @@ ReturnedValue Lookup::getter0getter0(Lookup *l, ExecutionEngine *engine, const V ReturnedValue Lookup::getter0getter1(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass()) + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) return o->propertyData(l->index)->asReturnedValue(); - if (l->classList[2] == o->internalClass() && - l->classList[3] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index2)->asReturnedValue(); + if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass) + return o->prototype->propertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); @@ -420,16 +424,16 @@ ReturnedValue Lookup::getter0getter1(Lookup *l, ExecutionEngine *engine, const V ReturnedValue Lookup::getter1getter1(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass() && - l->classList[1] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index)->asReturnedValue(); - if (l->classList[2] == o->internalClass() && - l->classList[3] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index2)->asReturnedValue(); + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass && + l->classList[1] == o->prototype->internalClass) + return o->prototype->propertyData(l->index)->asReturnedValue(); + if (l->classList[2] == o->internalClass && + l->classList[3] == o->prototype->internalClass) + return o->prototype->propertyData(l->index2)->asReturnedValue(); return getterFallback(l, engine, object); } l->getter = getterFallback; @@ -439,12 +443,12 @@ ReturnedValue Lookup::getter1getter1(Lookup *l, ExecutionEngine *engine, const V ReturnedValue Lookup::getterAccessor0(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Object *o = object.objectValue(); - if (l->classList[0] == o->internalClass()) { - Scope scope(o->engine()); + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) { + Scope scope(o->internalClass->engine); ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -461,10 +465,10 @@ ReturnedValue Lookup::getterAccessor0(Lookup *l, ExecutionEngine *engine, const ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Heap::Object *o = object.objectValue()->d(); + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { if (l->classList[0] == o->internalClass && l->classList[1] == o->prototype->internalClass) { Scope scope(o->internalClass->engine); @@ -484,10 +488,10 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const Value &object) { - if (object.isManaged()) { - // we can safely cast to a QV4::Object here. If object is actually a string, - // the internal class won't match - Heap::Object *o = object.objectValue()->d(); + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (o) { if (l->classList[0] == o->internalClass) { o = o->prototype; if (l->classList[1] == o->internalClass) { diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 28b255bd9a..5c764e7ff0 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -206,6 +206,18 @@ public: bool markBit() const { return d()->isMarked(); } static void destroy(Heap::Base *) {} + + Q_ALWAYS_INLINE Heap::Base *heapObject() const { + return m(); + } + + template<typename T> inline T *cast() { + return static_cast<T *>(this); + } + template<typename T> inline const T *cast() const { + return static_cast<const T *>(this); + } + private: friend class MemoryManager; friend struct Identifiers; @@ -215,14 +227,12 @@ private: template<> inline const Managed *Value::as() const { - if (isManaged()) - return managed(); - return 0; + return managed(); } template<> inline const Object *Value::as() const { - return isManaged() && m() && m()->vtable()->isObject ? objectValue() : 0; + return objectValue(); } } diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index 5646a44891..d5f75415cc 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -52,30 +52,16 @@ void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e) m->data[i].mark(e); } -static Heap::MemberData *reallocateHelper(ExecutionEngine *e, Heap::MemberData *old, uint n) +Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old) { + Q_ASSERT(!old || old->size < n); + uint alloc = sizeof(Heap::MemberData) + (n)*sizeof(Value); - Scope scope(e); - Scoped<MemberData> newMemberData(scope, e->memoryManager->allocManaged<MemberData>(alloc)); + Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc); if (old) - memcpy(newMemberData->d_unchecked(), old, sizeof(Heap::MemberData) + old->size * sizeof(Value)); + memcpy(m, old, sizeof(Heap::MemberData) + old->size * sizeof(Value)); else - newMemberData->d_unchecked()->init(); - newMemberData->d()->size = n; - return newMemberData->d(); -} - -Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n) -{ - return reallocateHelper(e, 0, n); -} - -Heap::MemberData *MemberData::reallocate(ExecutionEngine *e, Heap::MemberData *old, uint n) -{ - uint s = old ? old->size : 0; - if (n < s) - return old; - - // n is multiplied by two to leave room for growth - return reallocateHelper(e, old, qMax((uint)4, 2*n)); + m->init(); + m->size = n; + return m; } diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 969eee3619..5c89dfe8ec 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -79,8 +79,7 @@ struct MemberData : Managed Value *data() { return d()->data; } inline uint size() const { return d()->size; } - static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n); - static Heap::MemberData *reallocate(QV4::ExecutionEngine *e, Heap::MemberData *old, uint n); + static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 9b1f72bc17..3a6b9da763 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -285,7 +285,7 @@ ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx) return Encode::undefined(); if (!ctx->argc() || ctx->args()[0].isUndefined()) - return RuntimeHelpers::toString(scope.engine, v); + return Encode(v->toString(scope.engine)); int precision = ctx->args()[0].toInt32(); if (precision < 1 || precision > 21) { diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 00e6d230da..8acca16dd0 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -61,7 +61,9 @@ DEFINE_OBJECT_VTABLE(Object); void Object::setInternalClass(InternalClass *ic) { d()->internalClass = ic; - ensureMemberData(); + 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); } void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const @@ -225,13 +227,6 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e) o->prototype->mark(e); } -void Object::ensureMemberData() -{ - QV4::InternalClass *ic = internalClass(); - if (ic->size > d()->inlineMemberSize) - d()->memberData = MemberData::reallocate(ic->engine, d()->memberData, ic->size - d()->inlineMemberSize); -} - void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes) { uint idx; diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 00a004ef5f..6c679deb10 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -367,8 +367,6 @@ protected: static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static uint getLength(const Managed *m); - void ensureMemberData(); - private: ReturnedValue internalGet(String *name, bool *hasProperty) const; ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const; @@ -500,7 +498,7 @@ inline void Object::arraySet(uint index, const Value &value) template<> inline const ArrayObject *Value::as() const { - return isManaged() && m() && m()->vtable()->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : 0; + return isManaged() && m()->vtable()->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : 0; } #ifndef V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index 7943a13ac0..59115dfe21 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -70,15 +70,16 @@ void ObjectIterator::next(Value *name, uint *index, Property *pd, PropertyAttrib ScopedString n(scope); while (1) { - if (!current->as<Object>()) + Object *co = current->objectValue(); + if (!co) break; while (1) { - current->as<Object>()->advanceIterator(this, name, index, pd, attrs); + co->advanceIterator(this, name, index, pd, attrs); if (attrs->isEmpty()) break; // check the property is not already defined earlier in the proto chain - if (current->heapObject() != object->heapObject()) { + if (co->heapObject() != object->heapObject()) { o = object->as<Object>(); n = *name; bool shadowed = false; @@ -97,7 +98,7 @@ void ObjectIterator::next(Value *name, uint *index, Property *pd, PropertyAttrib } if (flags & WithProtoChain) - current->setM(current->objectValue()->prototype()); + current->setM(co->prototype()); else current->setM(0); @@ -109,7 +110,8 @@ void ObjectIterator::next(Value *name, uint *index, Property *pd, PropertyAttrib ReturnedValue ObjectIterator::nextPropertyName(Value *value) { - if (!object->as<Object>()) + Object *o = object->objectValue(); + if (!o) return Encode::null(); PropertyAttributes attrs; @@ -121,7 +123,7 @@ ReturnedValue ObjectIterator::nextPropertyName(Value *value) if (attrs.isEmpty()) return Encode::null(); - *value = object->objectValue()->getValue(p->value, attrs); + *value = o->getValue(p->value, attrs); if (!!name) return name->asReturnedValue(); @@ -131,7 +133,8 @@ ReturnedValue ObjectIterator::nextPropertyName(Value *value) ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value) { - if (!object->as<Object>()) + Object *o = object->objectValue(); + if (!o) return Encode::null(); PropertyAttributes attrs; @@ -143,7 +146,7 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString(Value *value) if (attrs.isEmpty()) return Encode::null(); - *value = object->objectValue()->getValue(p->value, attrs); + *value = o->getValue(p->value, attrs); if (!!name) return name->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 6020c48250..8191083544 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -62,26 +62,24 @@ void Heap::ObjectCtor::init(QV4::ExecutionContext *scope) void ObjectCtor::construct(const Managed *that, Scope &scope, CallData *callData) { const ObjectCtor *ctor = static_cast<const ObjectCtor *>(that); - ExecutionEngine *v4 = ctor->engine(); if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) { - ScopedObject obj(scope, v4->newObject()); - ScopedObject proto(scope, ctor->get(v4->id_prototype())); + ScopedObject obj(scope, scope.engine->newObject()); + ScopedObject proto(scope, ctor->get(scope.engine->id_prototype())); if (!!proto) obj->setPrototype(proto); scope.result = obj.asReturnedValue(); } else { - scope.result = RuntimeHelpers::toObject(scope.engine, callData->args[0]); + scope.result = callData->args[0].toObject(scope.engine); } } -void ObjectCtor::call(const Managed *m, Scope &scope, CallData *callData) +void ObjectCtor::call(const Managed *, Scope &scope, CallData *callData) { - const ObjectCtor *ctor = static_cast<const ObjectCtor *>(m); - ExecutionEngine *v4 = ctor->engine(); + ExecutionEngine *v4 = scope.engine; if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) { scope.result = v4->newObject()->asReturnedValue(); } else { - scope.result = RuntimeHelpers::toObject(v4, callData->args[0]); + scope.result = callData->args[0].toObject(v4); } } @@ -398,7 +396,7 @@ ReturnedValue ObjectPrototype::method_toString(CallContext *ctx) } else if (ctx->thisObject().isNull()) { return ctx->d()->engine->newString(QStringLiteral("[object Null]"))->asReturnedValue(); } else { - ScopedObject obj(scope, RuntimeHelpers::toObject(scope.engine, ctx->thisObject())); + ScopedObject obj(scope, ctx->thisObject().toObject(scope.engine)); QString className = obj->className(); return ctx->d()->engine->newString(QStringLiteral("[object %1]").arg(className))->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index e06cb64a61..d27e853343 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -86,7 +86,7 @@ QT_END_NAMESPACE engine->profiler()->trackDealloc(size, type) : false) #define Q_V4_PROFILE(engine, function)\ - (engine->profiler() &&\ + (Q_UNLIKELY(engine->profiler()) &&\ (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureFunctionCall)) ?\ Profiling::FunctionCallProfiler::profileCall(engine->profiler(), engine, function) :\ function->code(engine, function->codeData)) diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h index 50e8f0ae7f..5069d7690b 100644 --- a/src/qml/jsruntime/qv4property_p.h +++ b/src/qml/jsruntime/qv4property_p.h @@ -87,8 +87,8 @@ struct Property { inline bool isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const; inline void merge(PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs); - inline Heap::FunctionObject *getter() const { return value.isManaged() ? reinterpret_cast<Heap::FunctionObject *>(value.heapObject()) : 0; } - inline Heap::FunctionObject *setter() const { return set.isManaged() ? reinterpret_cast<Heap::FunctionObject *>(set.heapObject()) : 0; } + inline Heap::FunctionObject *getter() const { return reinterpret_cast<Heap::FunctionObject *>(value.heapObject()); } + inline Heap::FunctionObject *setter() const { return reinterpret_cast<Heap::FunctionObject *>(set.heapObject()); } inline void setGetter(FunctionObject *g) { value = reinterpret_cast<Managed *>(g); } inline void setSetter(FunctionObject *s) { set = (s ? reinterpret_cast<Managed *>(s) : 0); } diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp new file mode 100644 index 0000000000..889f4ea288 --- /dev/null +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -0,0 +1,346 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include "qv4qmlcontext_p.h" +#include <private/qv8engine_p.h> + +#include <private/qqmlengine_p.h> +#include <private/qqmlcontext_p.h> + +#include <private/qv4engine_p.h> +#include <private/qv4value_p.h> +#include <private/qv4objectproto_p.h> +#include <private/qv4mm_p.h> +#include <private/qv4function_p.h> +#include <private/qv4compileddata_p.h> +#include <private/qqmltypewrapper_p.h> +#include <private/qqmllistwrapper_p.h> +#include <private/qqmljavascriptexpression_p.h> +#include <private/qjsvalue_p.h> +#include <private/qv4qobjectwrapper_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QV4; + +DEFINE_OBJECT_VTABLE(QmlContextWrapper); +DEFINE_MANAGED_VTABLE(QmlContext); + +void Heap::QmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject, bool ownsContext) +{ + Object::init(); + readOnly = true; + this->ownsContext = ownsContext; + isNullWrapper = false; + this->context = new QQmlGuardedContextData(context); + this->scopeObject.init(scopeObject); +} + +void Heap::QmlContextWrapper::destroy() +{ + if (*context && ownsContext) + (*context)->destroy(); + delete context; + scopeObject.destroy(); + Object::destroy(); +} + +ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty) +{ + Q_ASSERT(m->as<QmlContextWrapper>()); + const QmlContextWrapper *resource = static_cast<const QmlContextWrapper *>(m); + QV4::ExecutionEngine *v4 = resource->engine(); + QV4::Scope scope(v4); + + // In V8 the JS global object would come _before_ the QML global object, + // so simulate that here. + bool hasProp; + QV4::ScopedValue result(scope, v4->globalObject->get(name, &hasProp)); + if (hasProp) { + if (hasProperty) + *hasProperty = hasProp; + return result->asReturnedValue(); + } + + if (resource->d()->isNullWrapper) + return Object::get(m, name, hasProperty); + + if (v4->callingQmlContext() != *resource->d()->context) + return Object::get(m, name, hasProperty); + + result = Object::get(m, name, &hasProp); + if (hasProp) { + if (hasProperty) + *hasProperty = hasProp; + return result->asReturnedValue(); + } + + // Its possible we could delay the calculation of the "actual" context (in the case + // of sub contexts) until it is definately needed. + QQmlContextData *context = resource->getContext(); + QQmlContextData *expressionContext = context; + + if (!context) { + if (hasProperty) + *hasProperty = true; + return result->asReturnedValue(); + } + + // Search type (attached property/enum/imported scripts) names + // while (context) { + // Search context properties + // Search scope object + // Search context object + // context = context->parent + // } + + QObject *scopeObject = resource->getScopeObject(); + + if (context->imports && name->startsWithUpper()) { + // Search for attached properties, enums and imported scripts + QQmlTypeNameCache::Result r = context->imports->query(name); + + if (r.isValid()) { + if (hasProperty) + *hasProperty = true; + if (r.scriptIndex != -1) { + QV4::ScopedObject scripts(scope, context->importedScripts.valueRef()); + return scripts->getIndexed(r.scriptIndex); + } else if (r.type) { + return QmlTypeWrapper::create(v4, scopeObject, r.type); + } else if (r.importNamespace) { + return QmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace); + } + Q_ASSERT(!"Unreachable"); + } + + // Fall through + } + + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(v4->qmlEngine()); + + while (context) { + // Search context properties + const QV4::IdentifierHash<int> &properties = context->propertyNames(); + if (properties.count()) { + int propertyIdx = properties.value(name); + + if (propertyIdx != -1) { + + if (propertyIdx < context->idValueCount) { + + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(&context->idValues[propertyIdx].bindings); + if (hasProperty) + *hasProperty = true; + return QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx]); + } else { + + QQmlContextPrivate *cp = context->asQQmlContextPrivate(); + + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex); + + const QVariant &value = cp->propertyValues.at(propertyIdx); + if (hasProperty) + *hasProperty = true; + if (value.userType() == qMetaTypeId<QList<QObject*> >()) { + QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx), + QQmlContextPrivate::context_count, + QQmlContextPrivate::context_at); + return QmlListWrapper::create(v4, prop, qMetaTypeId<QQmlListProperty<QObject> >()); + } else { + return scope.engine->fromVariant(cp->propertyValues.at(propertyIdx)); + } + } + } + } + + // Search scope object + if (scopeObject) { + bool hasProp = false; + QV4::ScopedValue result(scope, QV4::QObjectWrapper::getQmlProperty(v4, context, scopeObject, + name, QV4::QObjectWrapper::CheckRevision, &hasProp)); + if (hasProp) { + if (hasProperty) + *hasProperty = true; + return result->asReturnedValue(); + } + } + scopeObject = 0; + + + // Search context object + if (context->contextObject) { + bool hasProp = false; + result = QV4::QObjectWrapper::getQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, &hasProp); + if (hasProp) { + if (hasProperty) + *hasProperty = true; + return result->asReturnedValue(); + } + } + + context = context->parent; + } + + expressionContext->unresolvedNames = true; + + return Encode::undefined(); +} + +void QmlContextWrapper::put(Managed *m, String *name, const Value &value) +{ + Q_ASSERT(m->as<QmlContextWrapper>()); + QmlContextWrapper *resource = static_cast<QmlContextWrapper *>(m); + ExecutionEngine *v4 = resource->engine(); + QV4::Scope scope(v4); + if (scope.hasException()) + return; + QV4::Scoped<QmlContextWrapper> wrapper(scope, resource); + + uint member = wrapper->internalClass()->find(name); + if (member < UINT_MAX) { + wrapper->putValue(member, value); + return; + } + + if (wrapper->d()->isNullWrapper) { + if (wrapper && wrapper->d()->readOnly) { + QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + + QLatin1Char('"'); + ScopedString e(scope, v4->newString(error)); + v4->throwError(e); + return; + } + + Object::put(m, name, value); + return; + } + + // Its possible we could delay the calculation of the "actual" context (in the case + // of sub contexts) until it is definately needed. + QQmlContextData *context = wrapper->getContext(); + QQmlContextData *expressionContext = context; + + if (!context) + return; + + // See QV8ContextWrapper::Getter for resolution order + + QObject *scopeObject = wrapper->getScopeObject(); + + while (context) { + const QV4::IdentifierHash<int> &properties = context->propertyNames(); + // Search context properties + if (properties.count() && properties.value(name) != -1) + return; + + // Search scope object + if (scopeObject && + QV4::QObjectWrapper::setQmlProperty(v4, context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, value)) + return; + scopeObject = 0; + + // Search context object + if (context->contextObject && + QV4::QObjectWrapper::setQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, value)) + return; + + context = context->parent; + } + + expressionContext->unresolvedNames = true; + + if (wrapper->d()->readOnly) { + QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + + QLatin1Char('"'); + v4->throwError(error); + return; + } + + Object::put(m, name, value); +} + +void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml) +{ + Heap::ExecutionContext::init(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext); + outer = outerContext->d(); + strictMode = false; + callData = outer->callData; + lookups = outer->lookups; + constantTable = outer->constantTable; + compilationUnit = outer->compilationUnit; + + this->qml = qml->d(); +} + +Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, const QUrl &source, Value *sendFunction) +{ + Scope scope(parent); + + QQmlContextData *context = new QQmlContextData; + context->baseUrl = source; + context->baseUrlString = source.toString(); + context->isInternal = true; + context->isJSContext = true; + + Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, (QObject*)0, true)); + qml->d()->isNullWrapper = true; + + qml->setReadOnly(false); + QV4::ScopedObject api(scope, scope.engine->newObject()); + api->put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("sendMessage"))), *sendFunction); + qml->QV4::Object::put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("WorkerScript"))), api); + qml->setReadOnly(true); + + Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc<QmlContext>(parent, qml); + return c; +} + +Heap::QmlContext *QmlContext::create(ExecutionContext *parent, QQmlContextData *context, QObject *scopeObject) +{ + Scope scope(parent); + + Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, scopeObject)); + Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc<QmlContext>(parent, qml); + return c; +} + +QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4context_p_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index ca8dc0b518..9aec7467da 100644 --- a/src/qml/jsruntime/qv4context_p_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -36,8 +36,9 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#ifndef QV4CONTEXT_P_P_H -#define QV4CONTEXT_P_P_H + +#ifndef QV4QMLCONTEXT_P_H +#define QV4QMLCONTEXT_P_H // // W A R N I N G @@ -50,34 +51,80 @@ // We mean it. // -// This header defines a couple of inlinable methods. -// These implementation cannot be put in qv4context_p.h, because they rely on the -// QQmlContextWrapper, which in turn is a QV4::Object subclass (so it includes qv4object_p.h), -// which includes qv4engine_p.h, that needs to include qv4context_p.h +#include <QtCore/qglobal.h> +#include <private/qtqmlglobal_p.h> -#include "qv4context_p.h" -#include "private/qqmlcontextwrapper_p.h" +#include <private/qv4object_p.h> +#include <private/qv4context_p.h> +#include <private/qqmlcontext_p.h> QT_BEGIN_NAMESPACE namespace QV4 { -QObject *QmlContext::qmlScope() const -{ - return d()->qml->scopeObject; +struct QmlContextWrapper; + +namespace Heap { + +struct QmlContextWrapper : Object { + void init(QQmlContextData *context, QObject *scopeObject, bool ownsContext = false); + void destroy(); + bool readOnly; + bool ownsContext; + bool isNullWrapper; + + QQmlGuardedContextData *context; + QQmlQPointer<QObject> scopeObject; +}; + +struct QmlContext : ExecutionContext { + void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml); + + Pointer<QmlContextWrapper> qml; +}; + } -QQmlContextData *QmlContext::qmlContext() const +struct Q_QML_EXPORT QmlContextWrapper : Object { - return *d()->qml->context; -} + V4_OBJECT2(QmlContextWrapper, Object) + V4_NEEDS_DESTROY -void QmlContext::takeContextOwnership() { - d()->qml->ownsContext = true; -} + void takeContextOwnership() { + d()->ownsContext = true; + } -} // QV4 namespace + inline QObject *getScopeObject() const { return d()->scopeObject; } + inline QQmlContextData *getContext() const { return *d()->context; } + + void setReadOnly(bool b) { d()->readOnly = b; } + + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); + static void put(Managed *m, String *name, const Value &value); +}; + +struct Q_QML_EXPORT QmlContext : public ExecutionContext +{ + V4_MANAGED(QmlContext, ExecutionContext) + + static Heap::QmlContext *createWorkerContext(QV4::ExecutionContext *parent, const QUrl &source, Value *sendFunction); + static Heap::QmlContext *create(QV4::ExecutionContext *parent, QQmlContextData *context, QObject *scopeObject); + + QObject *qmlScope() const { + return d()->qml->scopeObject; + } + QQmlContextData *qmlContext() const { + return *d()->qml->context; + } + + void takeContextOwnership() { + d()->qml->ownsContext = true; + } +}; + +} QT_END_NAMESPACE -#endif // QV4CONTEXT_P_P_H +#endif + diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 6b87f282cf..77dbb18b50 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -48,7 +48,6 @@ #include <private/qqmlglobal_p.h> #include <private/qqmltypewrapper_p.h> #include <private/qqmlvaluetypewrapper_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <private/qqmllistwrapper_p.h> #include <private/qqmlbuiltinfunctions_p.h> #include <private/qv8engine_p.h> @@ -392,9 +391,10 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP QQmlContextData *callingQmlContext = scope.engine->callingQmlContext(); QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); - bindingFunction->initBindingLocation(); - newBinding = QQmlBinding::create(property, value, object, callingQmlContext); + QV4::ScopedContext ctx(scope, bindingFunction->scope()); + newBinding = QQmlBinding::create(property, bindingFunction->function(), object, callingQmlContext, ctx); + newBinding->setSourceLocation(bindingFunction->currentLocation()); newBinding->setTarget(object, *property, nullptr); } } @@ -493,8 +493,7 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *object) { - if (QQmlData::wasDeleted(object)) - return QV4::Encode::null(); + Q_ASSERT(!QQmlData::wasDeleted(object)); QQmlData *ddata = QQmlData::get(object, true); if (!ddata) diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 504f6a69b8..c7c4f4dd77 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -206,14 +206,15 @@ private: inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object) { - if (Q_LIKELY(!QQmlData::wasDeleted(object))) { - QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object)); - if (Q_LIKELY(priv->declarativeData)) { - auto ddata = static_cast<QQmlData *>(priv->declarativeData); - if (Q_LIKELY(ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) { - // We own the JS object - return ddata->jsWrapper.value(); - } + if (Q_UNLIKELY(QQmlData::wasDeleted(object))) + return QV4::Encode::null(); + + QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object)); + if (Q_LIKELY(priv->declarativeData)) { + auto ddata = static_cast<QQmlData *>(priv->declarativeData); + if (Q_LIKELY(ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) { + // We own the JS object + return ddata->jsWrapper.value(); } } diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 4022d98c3f..218695624b 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -262,12 +262,12 @@ void RegExpCtor::construct(const Managed *, Scope &scope, CallData *callData) bool ignoreCase = false; bool multiLine = false; if (!f->isUndefined()) { - f = RuntimeHelpers::toString(scope.engine, f); + ScopedString s(scope, f->toString(scope.engine)); if (scope.hasException()) { scope.result = Encode::undefined(); return; } - QString str = f->stringValue()->toQString(); + QString str = s->toQString(); for (int i = 0; i < str.length(); ++i) { if (str.at(i) == QLatin1Char('g') && !global) { global = true; @@ -356,10 +356,10 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) return ctx->engine()->throwTypeError(); ScopedValue arg(scope, ctx->argument(0)); - arg = RuntimeHelpers::toString(scope.engine, arg); + ScopedString str(scope, arg->toString(scope.engine)); if (scope.hasException()) return Encode::undefined(); - QString s = arg->stringValue()->toQString(); + QString s = str->toQString(); int offset = r->global() ? r->lastIndexProperty()->toInt32() : 0; if (offset < 0 || offset > s.length()) { @@ -391,11 +391,11 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) } array->setArrayLengthUnchecked(len); *array->propertyData(Index_ArrayIndex) = Primitive::fromInt32(result); - *array->propertyData(Index_ArrayInput) = arg; + *array->propertyData(Index_ArrayInput) = str; RegExpCtor::Data *dd = regExpCtor->d(); dd->lastMatch = array; - dd->lastInput = arg->stringValue()->d(); + dd->lastInput = str->d(); dd->lastMatchStart = matchOffsets[0]; dd->lastMatchEnd = matchOffsets[1]; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 9c20133a26..d6c55926b1 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -53,7 +53,7 @@ #include "qv4numberobject_p.h" #include "private/qlocale_tools_p.h" #include "qv4scopedvalue_p.h" -#include <private/qqmlcontextwrapper_p.h> +#include <private/qv4qmlcontext_p.h> #include <private/qqmltypewrapper_p.h> #include <private/qqmlengine_p.h> #include <private/qqmljavascriptexpression_p.h> @@ -345,28 +345,29 @@ ReturnedValue Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex) QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &left, const Value &right) { - Scope scope(engine); - ScopedFunctionObject f(scope, right.as<FunctionObject>()); - if (!f) + const FunctionObject *function = right.as<FunctionObject>(); + if (!function) return engine->throwTypeError(); - if (f->isBoundFunction()) - f = static_cast<BoundFunction *>(f.getPointer())->target(); + Heap::FunctionObject *f = function->d(); + if (function->isBoundFunction()) + f = function->cast<BoundFunction>()->target(); - ScopedObject v(scope, left.as<Object>()); - if (!v) + const Object *o = left.as<Object>(); + if (!o) return Encode(false); + Heap::Object *v = o->d(); - ScopedObject o(scope, f->protoProperty()); + o = f->protoProperty(); if (!o) return engine->throwTypeError(); while (v) { - v = v->prototype(); + v = v->prototype; if (!v) break; - else if (o->d() == v->d()) + else if (o->d() == v) return Encode(true); } @@ -375,13 +376,14 @@ QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Val QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right) { - if (!right.isObject()) + Object *ro = right.objectValue(); + if (!ro) return engine->throwTypeError(); Scope scope(engine); ScopedString s(scope, left.toString(engine)); if (scope.hasException()) return Encode::undefined(); - bool r = right.objectValue()->hasProperty(s); + bool r = ro->hasProperty(s); return Encode(r); } @@ -492,8 +494,8 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val else return engine->id_false()->d(); case Value::Managed_Type: - if (value.isString()) - return value.stringValue()->d(); + if (String *s = value.stringValue()) + return s->d(); { Scope scope(engine); ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value, STRING_HINT)); @@ -523,8 +525,8 @@ static Heap::String *convert_to_string_add(ExecutionEngine *engine, const Value else return engine->id_false()->d(); case Value::Managed_Type: - if (value.isString()) - return value.stringValue()->d(); + if (String *s = value.stringValue()) + return s->d(); { Scope scope(engine); ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value, PREFERREDTYPE_HINT)); @@ -543,19 +545,25 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu ScopedValue pleft(scope, RuntimeHelpers::toPrimitive(left, PREFERREDTYPE_HINT)); ScopedValue pright(scope, RuntimeHelpers::toPrimitive(right, PREFERREDTYPE_HINT)); - if (pleft->isString() || pright->isString()) { - if (!pleft->isString()) + String *sleft = pleft->stringValue(); + String *sright = pright->stringValue(); + if (sleft || sright) { + if (!sleft) { pleft = convert_to_string_add(engine, pleft); - if (!pright->isString()) + sleft = static_cast<String *>(pleft.ptr); + } + if (!sright) { pright = convert_to_string_add(engine, pright); + sright = static_cast<String *>(pright.ptr); + } if (scope.engine->hasException) return Encode::undefined(); - if (!pleft->stringValue()->d()->length()) - return pright->asReturnedValue(); - if (!pright->stringValue()->d()->length()) - return pleft->asReturnedValue(); + if (!sleft->d()->length()) + return sright->asReturnedValue(); + if (!sright->d()->length()) + return sleft->asReturnedValue(); MemoryManager *mm = engine->memoryManager; - return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d()))->asReturnedValue(); + return (mm->alloc<String>(mm, sleft->d(), sright->d()))->asReturnedValue(); } double x = RuntimeHelpers::toNumber(pleft); double y = RuntimeHelpers::toNumber(pright); @@ -566,31 +574,28 @@ QV4::ReturnedValue Runtime::method_addString(ExecutionEngine *engine, const Valu { Q_ASSERT(left.isString() || right.isString()); - if (left.isString() && right.isString()) { - if (!left.stringValue()->d()->length()) - return right.asReturnedValue(); - if (!right.stringValue()->d()->length()) - return left.asReturnedValue(); - MemoryManager *mm = engine->memoryManager; - return (mm->alloc<String>(mm, left.stringValue()->d(), right.stringValue()->d()))->asReturnedValue(); - } - Scope scope(engine); ScopedValue pleft(scope, left); ScopedValue pright(scope, right); + String *sleft = pleft->stringValue(); + String *sright = pright->stringValue(); - if (!pleft->isString()) - pleft = convert_to_string_add(engine, left); - if (!pright->isString()) - pright = convert_to_string_add(engine, right); + if (!sleft) { + pleft = convert_to_string_add(engine, pleft); + sleft = static_cast<String *>(pleft.ptr); + } + if (!sright) { + pright = convert_to_string_add(engine, pright); + sright = static_cast<String *>(pright.ptr); + } if (scope.engine->hasException) return Encode::undefined(); - if (!pleft->stringValue()->d()->length()) + if (!sleft->d()->length()) return pright->asReturnedValue(); - if (!pright->stringValue()->d()->length()) + if (!sright->d()->length()) return pleft->asReturnedValue(); MemoryManager *mm = engine->memoryManager; - return (mm->alloc<String>(mm, pleft->stringValue()->d(), pright->stringValue()->d()))->asReturnedValue(); + return (mm->alloc<String>(mm, sleft->d(), sright->d()))->asReturnedValue(); } void Runtime::method_setProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value) @@ -750,13 +755,15 @@ uint RuntimeHelpers::equalHelper(const Value &x, const Value &y) #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - if ((x.isNumber() || x.isString()) && y.isObject()) { - Scope scope(y.objectValue()->engine()); - ScopedValue py(scope, RuntimeHelpers::toPrimitive(y, PREFERREDTYPE_HINT)); + Object *xo = x.objectValue(); + Object *yo = y.objectValue(); + if (yo && (x.isNumber() || x.isString())) { + Scope scope(yo->engine()); + ScopedValue py(scope, RuntimeHelpers::objectDefaultValue(yo, PREFERREDTYPE_HINT)); return Runtime::method_compareEqual(x, py); - } else if (x.isObject() && (y.isNumber() || y.isString())) { - Scope scope(x.objectValue()->engine()); - ScopedValue px(scope, RuntimeHelpers::toPrimitive(x, PREFERREDTYPE_HINT)); + } else if (xo && (y.isNumber() || y.isString())) { + Scope scope(xo->engine()); + ScopedValue px(scope, RuntimeHelpers::objectDefaultValue(xo, PREFERREDTYPE_HINT)); return Runtime::method_compareEqual(px, y); } #endif @@ -787,23 +794,27 @@ QV4::Bool Runtime::method_compareGreaterThan(const Value &l, const Value &r) return l.integerValue() > r.integerValue(); if (l.isNumber() && r.isNumber()) return l.asDouble() > r.asDouble(); - if (l.isString() && r.isString()) { + String *sl = l.stringValue(); + String *sr = r.stringValue(); + if (sl && sr) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); return false; #else - return r.stringValue()->compare(l.stringValue()); + return sr->compare(sl); #endif } - if (l.isObject() || r.isObject()) { + Object *ro = r.objectValue(); + Object *lo = l.objectValue(); + if (ro || lo) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - QV4::ExecutionEngine *e = (l.isObject() ? l.objectValue() : r.objectValue())->engine(); + QV4::ExecutionEngine *e = (lo ? lo : ro)->engine(); QV4::Scope scope(e); - QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT)); - QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT)); + QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); + QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); return Runtime::method_compareGreaterThan(pl, pr); #endif } @@ -820,23 +831,27 @@ QV4::Bool Runtime::method_compareLessThan(const Value &l, const Value &r) return l.integerValue() < r.integerValue(); if (l.isNumber() && r.isNumber()) return l.asDouble() < r.asDouble(); - if (l.isString() && r.isString()) { + String *sl = l.stringValue(); + String *sr = r.stringValue(); + if (sl && sr) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); return false; #else - return l.stringValue()->compare(r.stringValue()); + return sl->compare(sr); #endif } - if (l.isObject() || r.isObject()) { + Object *ro = r.objectValue(); + Object *lo = l.objectValue(); + if (ro || lo) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - QV4::ExecutionEngine *e = (l.isObject() ? l.objectValue() : r.objectValue())->engine(); + QV4::ExecutionEngine *e = (lo ? lo : ro)->engine(); QV4::Scope scope(e); - QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT)); - QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT)); + QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); + QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); return Runtime::method_compareLessThan(pl, pr); #endif } @@ -853,23 +868,27 @@ QV4::Bool Runtime::method_compareGreaterEqual(const Value &l, const Value &r) return l.integerValue() >= r.integerValue(); if (l.isNumber() && r.isNumber()) return l.asDouble() >= r.asDouble(); - if (l.isString() && r.isString()) { + String *sl = l.stringValue(); + String *sr = r.stringValue(); + if (sl && sr) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); return false; #else - return !l.stringValue()->compare(r.stringValue()); + return !sl->compare(sr); #endif } - if (l.isObject() || r.isObject()) { + Object *ro = r.objectValue(); + Object *lo = l.objectValue(); + if (ro || lo) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - QV4::ExecutionEngine *e = (l.isObject() ? l.objectValue() : r.objectValue())->engine(); + QV4::ExecutionEngine *e = (lo ? lo : ro)->engine(); QV4::Scope scope(e); - QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT)); - QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT)); + QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); + QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); return Runtime::method_compareGreaterEqual(pl, pr); #endif } @@ -886,23 +905,27 @@ QV4::Bool Runtime::method_compareLessEqual(const Value &l, const Value &r) return l.integerValue() <= r.integerValue(); if (l.isNumber() && r.isNumber()) return l.asDouble() <= r.asDouble(); - if (l.isString() && r.isString()) { + String *sl = l.stringValue(); + String *sr = r.stringValue(); + if (sl && sr) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); return false; #else - return !r.stringValue()->compare(l.stringValue()); + return !sr->compare(sl); #endif } - if (l.isObject() || r.isObject()) { + Object *ro = r.objectValue(); + Object *lo = l.objectValue(); + if (ro || lo) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - QV4::ExecutionEngine *e = (l.isObject() ? l.objectValue() : r.objectValue())->engine(); + QV4::ExecutionEngine *e = (lo ? lo : ro)->engine(); QV4::Scope scope(e); - QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT)); - QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT)); + QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); + QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); return Runtime::method_compareLessEqual(pl, pr); #endif } @@ -1045,13 +1068,13 @@ ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, uint i Lookup *l = engine->current->lookups + index; Value v; v = l->getter(l, engine, callData->thisObject); - if (v.isObject()) { + Object *o = v.objectValue(); + if (Q_LIKELY(o)) { Scope scope(engine); - v.objectValue()->call(scope, callData); + o->call(scope, callData); return scope.result.asReturnedValue(); - } else { - return engine->throwTypeError(); } + return engine->throwTypeError(); } ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, const Value &index, CallData *callData) @@ -1074,12 +1097,12 @@ ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, const Value & ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &func, CallData *callData) { - if (!func.isObject()) - return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); - - Scope scope(engine); - func.objectValue()->call(scope, callData); - return scope.result.asReturnedValue(); + if (Object *o = func.objectValue()) { + Scope scope(engine); + o->call(scope, callData); + return scope.result.asReturnedValue(); + } + return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); } @@ -1149,14 +1172,13 @@ ReturnedValue Runtime::method_constructPropertyLookup(ExecutionEngine *engine, u Lookup *l = engine->current->lookups + index; Value v; v = l->getter(l, engine, callData->thisObject); - if (v.isObject()) { + Object *o = v.objectValue(); + if (Q_LIKELY(o)) { Scope scope(engine); - ScopedValue result(scope); - v.objectValue()->construct(scope, callData); + o->construct(scope, callData); return scope.result.asReturnedValue(); - } else { - return engine->throwTypeError(); } + return engine->throwTypeError(); } @@ -1367,29 +1389,6 @@ QV4::ReturnedValue Runtime::method_decrement(const Value &value) } } -#ifndef V4_BOOTSTRAP - -QV4::ReturnedValue RuntimeHelpers::toString(ExecutionEngine *engine, const Value &value) -{ - if (value.isString()) - return value.asReturnedValue(); - return RuntimeHelpers::convertToString(engine, value)->asReturnedValue(); -} - -QV4::ReturnedValue RuntimeHelpers::toObject(ExecutionEngine *engine, const Value &value) -{ - if (value.isObject()) - return value.asReturnedValue(); - - Heap::Object *o = RuntimeHelpers::convertToObject(engine, value); - if (!o) // type error - return Encode::undefined(); - - return Encode(o); -} - -#endif // V4_BOOTSTRAP - ReturnedValue Runtime::method_toDouble(const Value &value) { TRACE1(value); diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index a32b3f1663..0d787714cf 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -106,10 +106,7 @@ struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { static double toNumber(const Value &value); static void numberToString(QString *result, double num, int radix = 10); - static ReturnedValue toString(ExecutionEngine *engine, const Value &value); static Heap::String *convertToString(ExecutionEngine *engine, const Value &value); - - static ReturnedValue toObject(ExecutionEngine *engine, const Value &value); static Heap::Object *convertToObject(ExecutionEngine *engine, const Value &value); static Bool equalHelper(const Value &x, const Value &y); diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index e06a3f5ec2..355b7890b6 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -63,6 +63,11 @@ template <typename T> struct ExceptionCheck { enum { NeedsCheck = 1 }; }; +// push_catch and pop context methods shouldn't check for exceptions +template <> +struct ExceptionCheck<void (*)(QV4::NoThrowEngine *)> { + enum { NeedsCheck = 0 }; +}; template <typename A> struct ExceptionCheck<void (*)(A, QV4::NoThrowEngine)> { enum { NeedsCheck = 0 }; diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 5022d7c3bc..4e627e003f 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -97,7 +97,7 @@ struct Scope { engine->jsStackTop = mark; } - Value *alloc(int nValues) const { + QML_NEARLY_ALWAYS_INLINE Value *alloc(int nValues) const { return engine->jsAlloca(nValues); } @@ -189,63 +189,70 @@ struct Scoped { enum ConvertType { Convert }; - inline void setPointer(const Managed *p) { + QML_NEARLY_ALWAYS_INLINE void setPointer(const Managed *p) { ptr->setM(p ? p->m() : 0); } - Scoped(const Scope &scope) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope) { ptr = scope.engine->jsAlloca(1); } - Scoped(const Scope &scope, const Value &v) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v) { ptr = scope.engine->jsAlloca(1); setPointer(v.as<T>()); } - Scoped(const Scope &scope, Heap::Base *o) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, Heap::Base *o) { Value v; v = o; ptr = scope.engine->jsAlloca(1); setPointer(v.as<T>()); } - Scoped(const Scope &scope, const ScopedValue &v) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ScopedValue &v) { ptr = scope.engine->jsAlloca(1); setPointer(v.ptr->as<T>()); } - Scoped(const Scope &scope, const Value &v, ConvertType) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v, ConvertType) { ptr = scope.engine->jsAlloca(1); ptr->setRawValue(value_convert<T>(scope.engine, v)); } - Scoped(const Scope &scope, const Value *v) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value *v) { ptr = scope.engine->jsAlloca(1); setPointer(v ? v->as<T>() : 0); } - Scoped(const Scope &scope, T *t) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, T *t) { ptr = scope.engine->jsAlloca(1); setPointer(t); } - Scoped(const Scope &scope, typename T::Data *t) + + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const T *t) + { + ptr = scope.engine->jsAlloca(1); + setPointer(t); + } + + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, typename T::Data *t) { ptr = scope.engine->jsAlloca(1); *ptr = t; } - Scoped(const Scope &scope, const ReturnedValue &v) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v) { ptr = scope.engine->jsAlloca(1); setPointer(QV4::Value::fromReturnedValue(v).as<T>()); } - Scoped(const Scope &scope, const ReturnedValue &v, ConvertType) + QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v, ConvertType) { ptr = scope.engine->jsAlloca(1); ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v))); @@ -291,11 +298,11 @@ struct Scoped } T *operator->() { - return ptr->cast<T>(); + return getPointer(); } const T *operator->() const { - return ptr->cast<T>(); + return getPointer(); } bool operator!() const { @@ -306,14 +313,19 @@ struct Scoped } T *getPointer() { - return ptr->cast<T>(); + return reinterpret_cast<T *>(ptr); + } + + const T *getPointer() const { + return reinterpret_cast<T *>(ptr); } + Value *getRef() { return ptr; } - ReturnedValue asReturnedValue() const { - return ptr->m() ? ptr->rawValue() : Encode::undefined(); + QML_NEARLY_ALWAYS_INLINE ReturnedValue asReturnedValue() const { + return ptr->rawValue(); } Value *ptr; @@ -358,8 +370,6 @@ struct ScopedProperty ScopedProperty(Scope &scope) { property = reinterpret_cast<Property*>(scope.alloc(sizeof(Property) / sizeof(Value))); - property->value = Encode::undefined(); - property->set = Encode::undefined(); } Property *operator->() { return property; } diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 552171256f..b54177bee9 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -54,71 +54,12 @@ #include <private/qv4profiling_p.h> #include <qv4jsir_p.h> #include <qv4codegen_p.h> -#include <private/qqmlcontextwrapper_p.h> #include <QtCore/QDebug> #include <QtCore/QString> -QT_BEGIN_NAMESPACE - -namespace QV4 { -namespace Heap { - -struct QmlBindingWrapper : FunctionObject { - void init(QV4::QmlContext *scope, Function *f); -}; - -} - -struct QmlBindingWrapper : FunctionObject { - V4_OBJECT2(QmlBindingWrapper, FunctionObject) - - static void call(const Managed *that, Scope &scope, CallData *callData); -}; - -} - -QT_END_NAMESPACE - using namespace QV4; -DEFINE_OBJECT_VTABLE(QmlBindingWrapper); - -void Heap::QmlBindingWrapper::init(QV4::QmlContext *scope, Function *f) -{ - Heap::FunctionObject::init(scope, scope->d()->engine->id_eval(), /*createProto = */ false); - - Q_ASSERT(scope->inUse()); - - function = f; - if (function) - function->compilationUnit->addref(); -} - -void QmlBindingWrapper::call(const Managed *that, Scope &scope, CallData *callData) -{ - const QmlBindingWrapper *This = static_cast<const QmlBindingWrapper *>(that); - ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); - if (v4->hasException) { - scope.result = Encode::undefined(); - return; - } - CHECK_STACK_LIMITS(v4, scope); - - ExecutionContextSaver ctxSaver(scope); - - QV4::Function *f = This->function(); - if (!f) { - scope.result = QV4::Encode::undefined(); - return; - } - - Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(This, callData)); - v4->pushContext(ctx); - - scope.result = Q_V4_PROFILE(v4, f); -} - Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit) : line(0), column(0), scope(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false) , compilationUnit(compilationUnit), vmFunction(0), parseAsBinding(true) @@ -230,10 +171,12 @@ ReturnedValue Script::run() return Q_V4_PROFILE(engine, vmFunction); } else { Scoped<QmlContext> qml(valueScope, qmlContext.value()); - ScopedFunctionObject f(valueScope, engine->memoryManager->allocObject<QmlBindingWrapper>(qml, vmFunction)); ScopedCallData callData(valueScope); callData->thisObject = Primitive::undefinedValue(); - f->call(valueScope, callData); + if (vmFunction->canUseSimpleFunction()) + qml->simpleCall(valueScope, callData, vmFunction); + else + qml->call(valueScope, callData, vmFunction); return valueScope.result.asReturnedValue(); } } @@ -303,17 +246,6 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module return isel->compile(/*generate unit data*/false); } -ReturnedValue Script::qmlBinding() -{ - if (!parsed) - parse(); - ExecutionEngine *v4 = scope->engine(); - Scope valueScope(v4); - Scoped<QmlContext> qml(valueScope, qmlContext.value()); - ScopedObject v(valueScope, v4->memoryManager->allocObject<QmlBindingWrapper>(qml, vmFunction)); - return v.asReturnedValue(); -} - QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext) { QV4::Scope scope(engine); diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 2e87a7692b..f96f0254a5 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -53,7 +53,7 @@ #include "qv4global_p.h" #include "qv4engine_p.h" #include "qv4functionobject_p.h" -#include "qv4context_p.h" +#include "qv4qmlcontext_p.h" #include <QQmlError> @@ -136,7 +136,6 @@ struct Q_QML_EXPORT Script { void parse(); ReturnedValue run(); - ReturnedValue qmlBinding(); Function *function(); diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 23ec3349b9..4890a85724 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -267,7 +267,7 @@ public: template<> inline const String *Value::as() const { - return isManaged() && m() && m()->vtable()->isString ? static_cast<const String *>(this) : 0; + return isManaged() && m()->vtable()->isString ? static_cast<const String *>(this) : 0; } #ifndef V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 829ada0c1a..6fbf1c3c85 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -218,8 +218,8 @@ static QString getThisString(ExecutionContext *ctx) { Scope scope(ctx); ScopedValue t(scope, ctx->thisObject()); - if (t->isString()) - return t->stringValue()->toQString(); + if (String *s = t->stringValue()) + return s->toQString(); if (StringObject *thisString = t->as<StringObject>()) return thisString->d()->string->toQString(); if (t->isUndefined() || t->isNull()) { @@ -282,13 +282,13 @@ ReturnedValue StringPrototype::method_concat(CallContext *context) if (scope.engine->hasException) return Encode::undefined(); - ScopedValue v(scope); + ScopedString s(scope); for (int i = 0; i < context->argc(); ++i) { - v = RuntimeHelpers::toString(scope.engine, context->args()[i]); + s = context->args()[i].toString(scope.engine); if (scope.hasException()) return Encode::undefined(); - Q_ASSERT(v->isString()); - value += v->stringValue()->toQString(); + Q_ASSERT(s->isString()); + value += s->toQString(); } return context->d()->engine->newString(value)->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 95c95b1974..e34ac9c764 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -77,24 +77,24 @@ int Value::toUInt16() const bool Value::toBoolean() const { - switch (type()) { - case Value::Undefined_Type: - case Value::Null_Type: + if (isInteger() || isBoolean()) + return static_cast<bool>(int_32()); + + if (isUndefined() || isNull()) return false; - case Value::Boolean_Type: - case Value::Integer_Type: - return (bool)int_32(); - case Value::Managed_Type: + + if (isManaged()) { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - if (isString()) - return stringValue()->toQString().length() > 0; + if (String *s = stringValue()) + return s->toQString().length() > 0; #endif return true; - default: // double - return doubleValue() && !std::isnan(doubleValue()); } + + // double + return doubleValue() && !std::isnan(doubleValue()); } double Value::toInteger() const @@ -114,8 +114,8 @@ double Value::toNumberImpl() const #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); #else - if (isString()) - return RuntimeHelpers::stringToNumber(stringValue()->toQString()); + if (String *s = stringValue()) + return RuntimeHelpers::stringToNumber(s->toQString()); { Q_ASSERT(isObject()); Scope scope(objectValue()->engine()); @@ -150,8 +150,8 @@ QString Value::toQStringNoThrow() const else return QStringLiteral("false"); case Value::Managed_Type: - if (isString()) - return stringValue()->toQString(); + if (String *s = stringValue()) + return s->toQString(); { Q_ASSERT(isObject()); Scope scope(objectValue()->engine()); @@ -203,8 +203,8 @@ QString Value::toQString() const else return QStringLiteral("false"); case Value::Managed_Type: - if (isString()) - return stringValue()->toQString(); + if (String *s = stringValue()) + return s->toQString(); { Q_ASSERT(isObject()); Scope scope(objectValue()->engine()); @@ -228,8 +228,10 @@ QString Value::toQString() const bool Value::sameValue(Value other) const { if (_val == other._val) return true; - if (isString() && other.isString()) - return stringValue()->isEqualTo(other.stringValue()); + String *s = stringValue(); + String *os = other.stringValue(); + if (s && os) + return s->isEqualTo(os); if (isInteger() && other.isDouble()) return int_32() ? (double(int_32()) == other.doubleValue()) : (other._val == 0); if (isDouble() && other.isInteger()) @@ -298,15 +300,15 @@ double Primitive::toInteger(double number) #ifndef V4_BOOTSTRAP Heap::String *Value::toString(ExecutionEngine *e) const { - if (isString()) - return stringValue()->d(); + if (String *s = stringValue()) + return s->d(); return RuntimeHelpers::convertToString(e, *this); } Heap::Object *Value::toObject(ExecutionEngine *e) const { - if (isObject()) - return objectValue()->d(); + if (Object *o = objectValue()) + return o->d(); return RuntimeHelpers::convertToObject(e, *this); } @@ -330,8 +332,8 @@ uint Value::asArrayLength(bool *ok) const } return idx; } - if (isString()) - return stringValue()->toUInt(ok); + if (String *s = stringValue()) + return s->toUInt(ok); uint idx = toUInt32(); double d = toNumber(); diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 6d5cff4ecc..816b8fb11b 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -160,9 +160,9 @@ private: quint64 _val; public: - Q_ALWAYS_INLINE quint64 &rawValueRef() { return _val; } - Q_ALWAYS_INLINE quint64 rawValue() const { return _val; } - Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; } + QML_NEARLY_ALWAYS_INLINE quint64 &rawValueRef() { return _val; } + QML_NEARLY_ALWAYS_INLINE quint64 rawValue() const { return _val; } + QML_NEARLY_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; } #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN static inline int valueOffset() { return 0; } @@ -171,23 +171,23 @@ public: static inline int valueOffset() { return 4; } static inline int tagOffset() { return 0; } #endif - Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; } - Q_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); } - Q_ALWAYS_INLINE quint32 tag() const { return _val >> 32; } + QML_NEARLY_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; } + QML_NEARLY_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); } + QML_NEARLY_ALWAYS_INLINE quint32 tag() const { return _val >> 32; } #if defined(QV4_USE_64_BIT_VALUE_ENCODING) - Q_ALWAYS_INLINE Heap::Base *m() const + QML_NEARLY_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; memcpy(&b, &_val, 8); return b; } - Q_ALWAYS_INLINE void setM(Heap::Base *b) + QML_NEARLY_ALWAYS_INLINE void setM(Heap::Base *b) { memcpy(&_val, &b, 8); } #else // !QV4_USE_64_BIT_VALUE_ENCODING - Q_ALWAYS_INLINE Heap::Base *m() const + QML_NEARLY_ALWAYS_INLINE Heap::Base *m() const { Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32)); Heap::Base *b; @@ -195,7 +195,7 @@ public: memcpy(&b, &v, 4); return b; } - Q_ALWAYS_INLINE void setM(Heap::Base *b) + QML_NEARLY_ALWAYS_INLINE void setM(Heap::Base *b) { quint32 v; memcpy(&v, &b, 4); @@ -203,32 +203,32 @@ public: } #endif - Q_ALWAYS_INLINE int int_32() const + QML_NEARLY_ALWAYS_INLINE int int_32() const { return int(value()); } - Q_ALWAYS_INLINE void setInt_32(int i) + QML_NEARLY_ALWAYS_INLINE void setInt_32(int i) { setTagValue(Integer_Type_Internal, quint32(i)); } - Q_ALWAYS_INLINE uint uint_32() const { return value(); } + QML_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); } - Q_ALWAYS_INLINE void setEmpty() + QML_NEARLY_ALWAYS_INLINE void setEmpty() { setTagValue(Empty_Type_Internal, value()); } - Q_ALWAYS_INLINE void setEmpty(int i) + QML_NEARLY_ALWAYS_INLINE void setEmpty(int i) { setTagValue(Empty_Type_Internal, quint32(i)); } - Q_ALWAYS_INLINE void setEmpty(quint32 i) + QML_NEARLY_ALWAYS_INLINE void setEmpty(quint32 i) { setTagValue(Empty_Type_Internal, i); } - Q_ALWAYS_INLINE quint32 emptyValue() + QML_NEARLY_ALWAYS_INLINE quint32 emptyValue() { Q_ASSERT(isEmpty()); return quint32(value()); @@ -302,6 +302,7 @@ public: inline bool isUndefined() const { return _val == 0; } inline bool isDouble() const { return (_val >> IsDouble_Shift); } inline bool isManaged() const { return !isUndefined() && ((_val >> IsManagedOrUndefined_Shift) == 0); } + inline bool isManagedOrUndefined() const { return ((_val >> IsManagedOrUndefined_Shift) == 0); } inline bool integerCompatible() const { return (_val >> IsIntegerConvertible_Shift) == 3; @@ -317,6 +318,7 @@ public: inline bool isUndefined() const { return tag() == Managed_Type_Internal && value() == 0; } inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; } inline bool isManaged() const { return tag() == Managed_Type_Internal && !isUndefined(); } + inline bool isManagedOrUndefined() const { return tag() == Managed_Type_Internal; } inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; } static inline bool integerCompatible(Value a, Value b) { return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt; @@ -326,7 +328,7 @@ public: } inline bool isNaN() const { return (tag() & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; } #endif - Q_ALWAYS_INLINE double doubleValue() const { + QML_NEARLY_ALWAYS_INLINE double doubleValue() const { Q_ASSERT(isDouble()); double d; quint64 v = _val; @@ -336,7 +338,7 @@ public: memcpy(&d, &v, 8); return d; } - Q_ALWAYS_INLINE void setDouble(double d) { + QML_NEARLY_ALWAYS_INLINE void setDouble(double d) { memcpy(&_val, &d, 8); #ifdef QV4_USE_64_BIT_VALUE_ENCODING _val ^= NaNEncodeMask; @@ -371,23 +373,23 @@ public: return int_32(); } - Q_ALWAYS_INLINE String *stringValue() const { + QML_NEARLY_ALWAYS_INLINE String *stringValue() const { if (!isString()) return nullptr; - return m() ? reinterpret_cast<String*>(const_cast<Value *>(this)) : 0; + return reinterpret_cast<String*>(const_cast<Value *>(this)); } - Q_ALWAYS_INLINE Object *objectValue() const { + QML_NEARLY_ALWAYS_INLINE Object *objectValue() const { if (!isObject()) return nullptr; - return m() ? reinterpret_cast<Object*>(const_cast<Value *>(this)) : 0; + return reinterpret_cast<Object*>(const_cast<Value *>(this)); } - Q_ALWAYS_INLINE Managed *managed() const { + QML_NEARLY_ALWAYS_INLINE Managed *managed() const { if (!isManaged()) return nullptr; - return m() ? reinterpret_cast<Managed*>(const_cast<Value *>(this)) : 0; + return reinterpret_cast<Managed*>(const_cast<Value *>(this)); } - Q_ALWAYS_INLINE Heap::Base *heapObject() const { - return isManaged() ? m() : nullptr; + QML_NEARLY_ALWAYS_INLINE Heap::Base *heapObject() const { + return isManagedOrUndefined() ? m() : nullptr; } static inline Value fromHeapObject(Heap::Base *m) @@ -420,7 +422,7 @@ public: template <typename T> const T *as() const { - if (!m() || !isManaged()) + if (!isManaged()) return 0; Q_ASSERT(m()->vtable()); @@ -451,6 +453,7 @@ public: } inline uint asArrayIndex() const; + inline bool asArrayIndex(uint &idx) const; #ifndef V4_BOOTSTRAP uint asArrayLength(bool *ok) const; #endif @@ -485,15 +488,13 @@ V4_ASSERT_IS_TRIVIAL(Value) inline bool Value::isString() const { - if (!isManaged()) - return false; - return m() && m()->vtable()->isString; + Heap::Base *b = heapObject(); + return b && b->vtable()->isString; } inline bool Value::isObject() const { - if (!isManaged()) - return false; - return m() && m()->vtable()->isObject; + Heap::Base *b = heapObject(); + return b && b->vtable()->isObject; } inline bool Value::isPrimitive() const @@ -531,6 +532,20 @@ inline uint Value::asArrayIndex() const return UINT_MAX; return idx; } + +inline bool Value::asArrayIndex(uint &idx) const +{ + if (!isDouble()) { + if (isInteger() && int_32() >= 0) { + idx = (uint)int_32(); + return true; + } + return false; + } + double d = doubleValue(); + idx = (uint)d; + return (idx == d); +} #endif inline diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index b19c36a5bd..622359a7d9 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -169,10 +169,8 @@ static Breakpoint qt_v4LastStop; static QV4::Function *qt_v4ExtractFunction(QV4::ExecutionContext *context) { - QV4::Scope scope(context->engine()); - QV4::ScopedFunctionObject function(scope, context->getFunctionObject()); - if (function) - return function->function(); + if (QV4::Function *function = context->getFunction()) + return function; else return context->d()->engine->globalCode; } |