aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4functionobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4functionobject.cpp')
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp189
1 files changed, 86 insertions, 103 deletions
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index aa1cb89a44..6e5c137e0b 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -55,6 +55,7 @@
#include <private/qqmljsparser_p.h>
#include <private/qqmljsast_p.h>
#include <private/qqmlcontextwrapper_p.h>
+#include <private/qqmlengine_p.h>
#include <qv4jsir_p.h>
#include <qv4codegen_p.h>
#include "private/qlocale_tools_p.h"
@@ -75,11 +76,11 @@ DEFINE_MANAGED_VTABLE(FunctionObject);
FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto)
: Object(createProto ? scope->engine->functionWithProtoClass : scope->engine->functionClass)
, scope(scope)
- , formalParameterList(0)
- , varList(0)
, formalParameterCount(0)
, varCount(0)
, function(0)
+ , protoCacheClass(0)
+ , protoCacheIndex(UINT_MAX)
{
init(name, createProto);
}
@@ -87,11 +88,11 @@ FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bo
FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto)
: Object(createProto ? scope->engine->functionWithProtoClass : scope->engine->functionClass)
, scope(scope)
- , formalParameterList(0)
- , varList(0)
, formalParameterCount(0)
, varCount(0)
, function(0)
+ , protoCacheClass(0)
+ , protoCacheIndex(UINT_MAX)
{
// set the name to something here, so that a gc run a few lines below doesn't crash on it
this->name = scope->engine->id_undefined;
@@ -105,13 +106,10 @@ FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, boo
FunctionObject::FunctionObject(InternalClass *ic)
: Object(ic)
, scope(ic->engine->rootContext)
- , formalParameterList(0)
- , varList(0)
, formalParameterCount(0)
, varCount(0)
, function(0)
{
- vtbl = &static_vtbl;
name = ic->engine->id_undefined;
type = Type_FunctionObject;
@@ -127,7 +125,6 @@ FunctionObject::~FunctionObject()
void FunctionObject::init(const StringRef n, bool createProto)
{
- vtbl = &static_vtbl;
name = n;
Scope s(internalClass->engine);
@@ -157,43 +154,13 @@ ReturnedValue FunctionObject::newInstance()
return construct(callData);
}
-bool FunctionObject::hasInstance(Managed *that, const ValueRef value)
-{
- Scope scope(that->internalClass->engine);
- ScopedFunctionObject f(scope, static_cast<FunctionObject *>(that));
-
- ScopedObject v(scope, value);
- if (!v)
- return false;
-
- Scoped<Object> o(scope, f->get(scope.engine->id_prototype));
- if (!o) {
- scope.engine->current->throwTypeError();
- return false;
- }
-
- while (v) {
- v = v->prototype();
-
- if (! v)
- break;
- else if (o.getPointer() == v)
- return true;
- }
-
- return false;
-}
-
ReturnedValue FunctionObject::construct(Managed *that, CallData *)
{
ExecutionEngine *v4 = that->internalClass->engine;
Scope scope(v4);
Scoped<FunctionObject> f(scope, that, Scoped<FunctionObject>::Cast);
- InternalClass *ic = v4->objectClass;
- Scoped<Object> proto(scope, f->get(v4->id_prototype));
- if (!!proto)
- ic = v4->emptyClass->changePrototype(proto.getPointer());
+ InternalClass *ic = f->internalClassForConstructor();
Scoped<Object> obj(scope, v4->newObject(ic));
return obj.asReturnedValue();
}
@@ -213,7 +180,7 @@ void FunctionObject::markObjects(Managed *that, ExecutionEngine *e)
// formalParameterList[i]->mark();
// for (uint i = 0; i < varCount; ++i)
// varList[i]->mark();
- o->scope->mark();
+ o->scope->mark(e);
if (o->function)
o->function->mark(e);
@@ -230,13 +197,49 @@ FunctionObject *FunctionObject::creatScriptFunction(ExecutionContext *scope, Fun
return new (scope->engine->memoryManager) SimpleScriptFunction(scope, function);
}
+ReturnedValue FunctionObject::protoProperty()
+{
+ if (protoCacheClass != internalClass) {
+ protoCacheClass = internalClass;
+ protoCacheIndex = internalClass->find(internalClass->engine->id_prototype);
+ }
+ if (protoCacheIndex < UINT_MAX) {
+ if (internalClass->propertyData.at(protoCacheIndex).isData()) {
+ ReturnedValue v = memberData[protoCacheIndex].value.asReturnedValue();
+ if (v != protoValue) {
+ classForConstructor = 0;
+ protoValue = v;
+ }
+ return v;
+ }
+ }
+ classForConstructor = 0;
+ return get(internalClass->engine->id_prototype);
+}
+
+InternalClass *FunctionObject::internalClassForConstructor()
+{
+ // need to call this first to ensure we don't use a wrong class
+ ReturnedValue proto = protoProperty();
+ if (classForConstructor)
+ return classForConstructor;
+
+ Scope scope(internalClass->engine);
+ ScopedObject p(scope, proto);
+ if (p)
+ classForConstructor = InternalClass::create(scope.engine, &Object::static_vtbl, p.getPointer());
+ else
+ classForConstructor = scope.engine->objectClass;
+
+ return classForConstructor;
+}
DEFINE_MANAGED_VTABLE(FunctionCtor);
FunctionCtor::FunctionCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Function"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
// 15.3.2
@@ -244,7 +247,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
{
FunctionCtor *f = static_cast<FunctionCtor *>(that);
ExecutionEngine *v4 = f->internalClass->engine;
- ExecutionContext *ctx = v4->current;
+ ExecutionContext *ctx = v4->currentContext();
QString arguments;
QString body;
if (callData->argc > 0) {
@@ -268,20 +271,20 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
const bool parsed = parser.parseExpression();
if (!parsed)
- return v4->current->throwSyntaxError(QLatin1String("Parse error"));
+ return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error"));
using namespace QQmlJS::AST;
FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode());
if (!fe)
- return v4->current->throwSyntaxError(QLatin1String("Parse error"));
+ return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error"));
QQmlJS::V4IR::Module module(v4->debugger != 0);
- QQmlJS::RuntimeCodegen cg(v4->current, f->strictMode);
+ QQmlJS::RuntimeCodegen cg(v4->currentContext(), f->strictMode);
cg.generateFromFunctionExpression(QString(), function, fe, &module);
QV4::Compiler::JSUnitGenerator jsGenerator(&module);
- QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module, &jsGenerator));
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
QV4::Function *vmf = compilationUnit->linkToEngine(v4);
@@ -348,7 +351,7 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
ScopedCallData callData(scope, len);
if (len) {
- if (arr->protoHasArray() || arr->hasAccessorProperty) {
+ if (!(arr->flags & SimpleArray) || arr->protoHasArray() || arr->hasAccessorProperty) {
for (quint32 i = 0; i < len; ++i)
callData->args[i] = arr->getIndexed(i);
} else {
@@ -401,7 +404,7 @@ DEFINE_MANAGED_VTABLE(ScriptFunction);
ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
: FunctionObject(scope, function->name, true)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope s(scope);
ScopedValue protectThis(s, this);
@@ -409,7 +412,7 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
this->function = function;
this->function->compilationUnit->ref();
Q_ASSERT(function);
- Q_ASSERT(function->codePtr);
+ Q_ASSERT(function->code);
// global function
if (!scope)
@@ -419,12 +422,10 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
needsActivation = function->needsActivation();
strictMode = function->isStrict();
- formalParameterCount = function->formals.size();
- formalParameterList = function->formals.constData();
- defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount));
+ formalParameterCount = function->nArguments;
+ varCount = function->internalClass->size - function->nArguments;
- varCount = function->locals.size();
- varList = function->locals.constData();
+ defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount));
if (scope->strictMode) {
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
@@ -443,13 +444,10 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
Scope scope(v4);
Scoped<ScriptFunction> f(scope, static_cast<ScriptFunction *>(that));
- InternalClass *ic = v4->objectClass;
- ScopedObject proto(scope, f->memberData[Index_Prototype].value);
- if (proto)
- ic = v4->emptyClass->changePrototype(proto.getPointer());
+ InternalClass *ic = f->internalClassForConstructor();
ScopedObject obj(scope, v4->newObject(ic));
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
callData->thisObject = obj.asReturnedValue();
ExecutionContext *ctx = context->newCallContext(f.getPointer(), callData);
@@ -471,7 +469,7 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
Scope scope(context);
CallContext *ctx = context->newCallContext(f, callData);
@@ -488,7 +486,7 @@ DEFINE_MANAGED_VTABLE(SimpleScriptFunction);
SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *function)
: FunctionObject(scope, function->name, true)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope s(scope);
ScopedValue protectThis(s, this);
@@ -496,7 +494,7 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu
this->function = function;
this->function->compilationUnit->ref();
Q_ASSERT(function);
- Q_ASSERT(function->codePtr);
+ Q_ASSERT(function->code);
// global function
if (!scope)
@@ -506,12 +504,10 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu
needsActivation = function->needsActivation();
strictMode = function->isStrict();
- formalParameterCount = function->formals.size();
- formalParameterList = function->formals.constData();
- defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount));
+ formalParameterCount = function->nArguments;
+ varCount = function->internalClass->size - function->nArguments;
- varCount = function->locals.size();
- varList = function->locals.constData();
+ defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount));
if (scope->strictMode) {
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
@@ -530,33 +526,29 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
Scope scope(v4);
Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that));
- InternalClass *ic = v4->objectClass;
- Scoped<Object> proto(scope, f->memberData[Index_Prototype].value);
- if (!!proto)
- ic = v4->emptyClass->changePrototype(proto.getPointer());
+ InternalClass *ic = f->internalClassForConstructor();
callData->thisObject = v4->newObject(ic);
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
+ ExecutionContextSaver ctxSaver(context);
- CallContext ctx;
- ctx.initSimpleCallContext(v4, context);
+ CallContext ctx(v4);
ctx.strictMode = f->strictMode;
ctx.callData = callData;
ctx.function = f.getPointer();
ctx.compilationUnit = f->function->compilationUnit;
ctx.lookups = ctx.compilationUnit->runtimeLookups;
ctx.outer = f->scope;
- ctx.locals = v4->stackPush(f->function->locals.size());
+ ctx.locals = v4->stackPush(f->varCount);
while (callData->argc < (int)f->formalParameterCount) {
callData->args[callData->argc] = Encode::undefined();
++callData->argc;
}
- v4->pushContext(&ctx);
+ Q_ASSERT(v4->currentContext() == &ctx);
if (f->function->compiledFunction->hasQmlDependencies())
QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
- ExecutionContextSaver ctxSaver(context);
Scoped<Object> result(scope, f->function->code(&ctx, f->function->codeData));
if (!result)
@@ -574,27 +566,26 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
SimpleScriptFunction *f = static_cast<SimpleScriptFunction *>(that);
Scope scope(v4);
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
+ ExecutionContextSaver ctxSaver(context);
- CallContext ctx;
- ctx.initSimpleCallContext(v4, context);
+ CallContext ctx(v4);
ctx.strictMode = f->strictMode;
ctx.callData = callData;
ctx.function = f;
ctx.compilationUnit = f->function->compilationUnit;
ctx.lookups = ctx.compilationUnit->runtimeLookups;
ctx.outer = f->scope;
- ctx.locals = v4->stackPush(f->function->locals.size());
+ ctx.locals = v4->stackPush(f->varCount);
while (callData->argc < (int)f->formalParameterCount) {
callData->args[callData->argc] = Encode::undefined();
++callData->argc;
}
- v4->current = &ctx;
+ Q_ASSERT(v4->currentContext() == &ctx);
if (f->function->compiledFunction->hasQmlDependencies())
QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
- ExecutionContextSaver ctxSaver(context);
return f->function->code(&ctx, f->function->codeData);
}
@@ -607,12 +598,12 @@ BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name,
: FunctionObject(scope, name)
, code(code)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue BuiltinFunction::construct(Managed *f, CallData *)
{
- return f->internalClass->engine->current->throwTypeError();
+ return f->internalClass->engine->currentContext()->throwTypeError();
}
ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
@@ -623,15 +614,14 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
+ ExecutionContextSaver ctxSaver(context);
- CallContext ctx;
- ctx.initSimpleCallContext(v4, context);
+ CallContext ctx(v4);
ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
ctx.callData = callData;
- v4->pushContext(&ctx);
+ Q_ASSERT(v4->currentContext() == &ctx);
- ExecutionContextSaver ctxSaver(context);
return f->code(&ctx);
}
@@ -643,16 +633,14 @@ ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
- ExecutionContext *context = v4->current;
- Scope scope(v4);
+ ExecutionContext *context = v4->currentContext();
+ ExecutionContextSaver ctxSaver(context);
- CallContext ctx;
- ctx.initSimpleCallContext(v4, context);
+ CallContext ctx(v4);
ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
ctx.callData = callData;
- v4->pushContext(&ctx);
+ Q_ASSERT(v4->currentContext() == &ctx);
- ExecutionContextSaver ctxSaver(context);
return f->code(&ctx, f->index);
}
@@ -665,7 +653,8 @@ BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObjectRef target,
, target(target)
, boundArgs(boundArgs)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
+ subtype = FunctionObject::BoundFunction;
this->boundThis = boundThis;
Scope s(scope);
@@ -717,12 +706,6 @@ ReturnedValue BoundFunction::construct(Managed *that, CallData *dd)
return f->target->construct(callData);
}
-bool BoundFunction::hasInstance(Managed *that, const ValueRef value)
-{
- BoundFunction *f = static_cast<BoundFunction *>(that);
- return FunctionObject::hasInstance(f->target, value);
-}
-
void BoundFunction::markObjects(Managed *that, ExecutionEngine *e)
{
BoundFunction *o = static_cast<BoundFunction *>(that);