1
/****************************************************************************
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtQml module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include "qv4object_p.h"
43
#include "qv4jsir_p.h"
44
#include "qv4isel_p.h"
45
#include "qv4objectproto_p.h"
46
#include "qv4stringobject_p.h"
47
#include "qv4function_p.h"
50
#include "qv4arrayobject_p.h"
51
#include "qv4scopedvalue_p.h"
53
#include <private/qqmljsengine_p.h>
54
#include <private/qqmljslexer_p.h>
55
#include <private/qqmljsparser_p.h>
56
#include <private/qqmljsast_p.h>
57
#include <private/qqmlcontextwrapper_p.h>
58
#include <private/qqmlengine_p.h>
59
#include <qv4jsir_p.h>
60
#include <qv4codegen_p.h>
61
#include "private/qlocale_tools_p.h"
63
#include <QtCore/qmath.h>
64
#include <QtCore/QDebug>
69
#include "qv4alloca_p.h"
70
#include "qv4profiling_p.h"
75
DEFINE_OBJECT_VTABLE(FunctionObject);
77
FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto)
78
: Object(scope->engine->functionClass)
82
init(name, createProto);
85
FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto)
86
: Object(scope->engine->functionClass)
91
ScopedValue protectThis(s, this);
92
ScopedString n(s, s.engine->newString(name));
96
FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValue name)
97
: Object(scope->engine->functionClass)
102
ScopedValue protectThis(s, this);
103
ScopedString n(s, name);
107
FunctionObject::FunctionObject(InternalClass *ic)
109
, scope(ic->engine->rootContext)
112
needsActivation = false;
114
memberData[Index_Prototype] = Encode::undefined();
117
FunctionObject::~FunctionObject()
120
function->compilationUnit->deref();
123
void FunctionObject::init(const StringRef n, bool createProto)
125
Scope s(internalClass->engine);
126
ScopedValue protectThis(s, this);
128
needsActivation = true;
132
Scoped<Object> proto(s, scope->engine->newObject(scope->engine->protoClass));
133
proto->memberData[Index_ProtoConstructor] = this->asReturnedValue();
134
memberData[Index_Prototype] = proto.asReturnedValue();
136
memberData[Index_Prototype] = Encode::undefined();
139
ScopedValue v(s, n.asReturnedValue());
140
defineReadonlyProperty(scope->engine->id_name, v);
143
ReturnedValue FunctionObject::name()
145
return get(scope->engine->id_name);
149
ReturnedValue FunctionObject::newInstance()
151
Scope scope(internalClass->engine);
152
ScopedCallData callData(scope, 0);
153
return construct(callData);
156
ReturnedValue FunctionObject::construct(Managed *that, CallData *)
158
that->internalClass->engine->currentContext()->throwTypeError();
159
return Encode::undefined();
162
ReturnedValue FunctionObject::call(Managed *, CallData *)
164
return Encode::undefined();
167
void FunctionObject::markObjects(Managed *that, ExecutionEngine *e)
169
FunctionObject *o = static_cast<FunctionObject *>(that);
173
Object::markObjects(that, e);
176
FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function, bool createProto)
178
if (function->needsActivation() ||
179
function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith ||
180
function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount ||
181
function->isNamedExpression())
182
return new (scope->engine->memoryManager) ScriptFunction(scope, function);
183
return new (scope->engine->memoryManager) SimpleScriptFunction(scope, function, createProto);
186
DEFINE_OBJECT_VTABLE(FunctionCtor);
188
FunctionCtor::FunctionCtor(ExecutionContext *scope)
189
: FunctionObject(scope, QStringLiteral("Function"))
191
setVTable(staticVTable());
195
ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
197
FunctionCtor *f = static_cast<FunctionCtor *>(that);
198
ExecutionEngine *v4 = f->internalClass->engine;
199
ExecutionContext *ctx = v4->currentContext();
202
if (callData->argc > 0) {
203
for (int i = 0; i < callData->argc - 1; ++i) {
205
arguments += QLatin1String(", ");
206
arguments += callData->args[i].toString(ctx)->toQString();
208
body = callData->args[callData->argc - 1].toString(ctx)->toQString();
210
if (ctx->engine->hasException)
211
return Encode::undefined();
213
QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1String("}");
215
QQmlJS::Engine ee, *engine = ⅇ
216
QQmlJS::Lexer lexer(engine);
217
lexer.setCode(function, 1, false);
218
QQmlJS::Parser parser(engine);
220
const bool parsed = parser.parseExpression();
223
return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error"));
225
using namespace QQmlJS::AST;
226
FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode());
228
return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error"));
230
IR::Module module(v4->debugger != 0);
232
QQmlJS::RuntimeCodegen cg(v4->currentContext(), f->strictMode);
233
cg.generateFromFunctionExpression(QString(), function, fe, &module);
235
QV4::Compiler::JSUnitGenerator jsGenerator(&module);
236
QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
237
QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
238
QV4::Function *vmf = compilationUnit->linkToEngine(v4);
240
return FunctionObject::createScriptFunction(v4->rootContext, vmf)->asReturnedValue();
243
// 15.3.1: This is equivalent to new Function(...)
244
ReturnedValue FunctionCtor::call(Managed *that, CallData *callData)
246
return construct(that, callData);
249
FunctionPrototype::FunctionPrototype(InternalClass *ic)
254
void FunctionPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
257
ScopedObject o(scope);
259
ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1));
260
ctor->defineReadonlyProperty(engine->id_prototype, (o = this));
262
defineReadonlyProperty(engine->id_length, Primitive::fromInt32(0));
263
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
264
defineDefaultProperty(engine->id_toString, method_toString, 0);
265
defineDefaultProperty(QStringLiteral("apply"), method_apply, 2);
266
defineDefaultProperty(QStringLiteral("call"), method_call, 1);
267
defineDefaultProperty(QStringLiteral("bind"), method_bind, 1);
271
ReturnedValue FunctionPrototype::method_toString(CallContext *ctx)
273
FunctionObject *fun = ctx->callData->thisObject.asFunctionObject();
275
return ctx->throwTypeError();
277
return ctx->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue();
280
ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
283
FunctionObject *o = ctx->callData->thisObject.asFunctionObject();
285
return ctx->throwTypeError();
287
ScopedValue arg(scope, ctx->argument(1));
289
ScopedObject arr(scope, arg);
294
if (!arg->isNullOrUndefined())
295
return ctx->throwTypeError();
297
len = arr->getLength();
300
ScopedCallData callData(scope, len);
303
if (arr->arrayType() != ArrayData::Simple || arr->protoHasArray() || arr->hasAccessorProperty) {
304
for (quint32 i = 0; i < len; ++i)
305
callData->args[i] = arr->getIndexed(i);
307
int alen = qMin(len, arr->arrayData->length());
309
memcpy(callData->args, arr->arrayData->data, alen*sizeof(Value));
310
for (quint32 i = alen; i < len; ++i)
311
callData->args[i] = Primitive::undefinedValue();
315
callData->thisObject = ctx->argument(0);
316
return o->call(callData);
319
ReturnedValue FunctionPrototype::method_call(CallContext *ctx)
323
FunctionObject *o = ctx->callData->thisObject.asFunctionObject();
325
return ctx->throwTypeError();
327
ScopedCallData callData(scope, ctx->callData->argc ? ctx->callData->argc - 1 : 0);
328
if (ctx->callData->argc) {
329
for (int i = 1; i < ctx->callData->argc; ++i)
330
callData->args[i - 1] = ctx->callData->args[i];
332
callData->thisObject = ctx->argument(0);
333
return o->call(callData);
336
ReturnedValue FunctionPrototype::method_bind(CallContext *ctx)
339
Scoped<FunctionObject> target(scope, ctx->callData->thisObject);
341
return ctx->throwTypeError();
343
ScopedValue boundThis(scope, ctx->argument(0));
344
QVector<Value> boundArgs;
345
for (int i = 1; i < ctx->callData->argc; ++i)
346
boundArgs += ctx->callData->args[i];
348
return ctx->engine->newBoundFunction(ctx->engine->rootContext, target, boundThis, boundArgs)->asReturnedValue();
351
DEFINE_OBJECT_VTABLE(ScriptFunction);
353
ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
354
: SimpleScriptFunction(scope, function, true)
356
setVTable(staticVTable());
359
ScopedValue protectThis(s, this);
365
ExecutionEngine *v4 = scope->engine;
367
needsActivation = function->needsActivation();
368
strictMode = function->isStrict();
370
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount()));
372
if (scope->strictMode) {
373
Property pd(v4->thrower, v4->thrower);
374
insertMember(scope->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
375
insertMember(scope->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
379
ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
381
ExecutionEngine *v4 = that->internalClass->engine;
382
if (v4->hasException)
383
return Encode::undefined();
384
CHECK_STACK_LIMITS(v4);
387
Scoped<ScriptFunction> f(scope, static_cast<ScriptFunction *>(that));
389
InternalClass *ic = f->internalClassForConstructor();
390
ScopedObject obj(scope, v4->newObject(ic));
392
ExecutionContext *context = v4->currentContext();
393
callData->thisObject = obj.asReturnedValue();
394
ExecutionContext *ctx = context->newCallContext(f.getPointer(), callData);
396
ExecutionContextSaver ctxSaver(context);
397
ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function));
399
if (f->function->compiledFunction->hasQmlDependencies())
400
QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
402
if (result->isObject())
403
return result.asReturnedValue();
404
return obj.asReturnedValue();
407
ReturnedValue ScriptFunction::call(Managed *that, CallData *callData)
409
ScriptFunction *f = static_cast<ScriptFunction *>(that);
410
ExecutionEngine *v4 = f->internalClass->engine;
411
if (v4->hasException)
412
return Encode::undefined();
413
CHECK_STACK_LIMITS(v4);
415
ExecutionContext *context = v4->currentContext();
416
Scope scope(context);
418
CallContext *ctx = context->newCallContext(f, callData);
420
ExecutionContextSaver ctxSaver(context);
421
ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function));
423
if (f->function->compiledFunction->hasQmlDependencies())
424
QmlContextWrapper::registerQmlDependencies(ctx->engine, f->function->compiledFunction);
426
return result.asReturnedValue();
429
DEFINE_OBJECT_VTABLE(SimpleScriptFunction);
431
SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *function, bool createProto)
432
: FunctionObject(scope, function->name(), createProto)
434
setVTable(staticVTable());
437
ScopedValue protectThis(s, this);
439
this->function = function;
440
this->function->compilationUnit->ref();
442
Q_ASSERT(function->code);
448
ExecutionEngine *v4 = scope->engine;
450
needsActivation = function->needsActivation();
451
strictMode = function->isStrict();
453
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount()));
455
if (scope->strictMode) {
456
Property pd(v4->thrower, v4->thrower);
457
insertMember(scope->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
458
insertMember(scope->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
462
ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
464
ExecutionEngine *v4 = that->internalClass->engine;
465
if (v4->hasException)
466
return Encode::undefined();
467
CHECK_STACK_LIMITS(v4);
470
Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that));
472
InternalClass *ic = f->internalClassForConstructor();
473
callData->thisObject = v4->newObject(ic);
475
ExecutionContext *context = v4->currentContext();
476
ExecutionContextSaver ctxSaver(context);
479
ctx.strictMode = f->strictMode;
480
ctx.callData = callData;
481
ctx.function = f.getPointer();
482
ctx.compilationUnit = f->function->compilationUnit;
483
ctx.lookups = ctx.compilationUnit->runtimeLookups;
484
ctx.outer = f->scope;
485
ctx.locals = v4->stackPush(f->varCount());
486
while (callData->argc < (int)f->formalParameterCount()) {
487
callData->args[callData->argc] = Encode::undefined();
490
Q_ASSERT(v4->currentContext() == &ctx);
492
Scoped<Object> result(scope, Q_V4_PROFILE(v4, &ctx, f->function));
494
if (f->function->compiledFunction->hasQmlDependencies())
495
QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
498
return callData->thisObject.asReturnedValue();
499
return result.asReturnedValue();
502
ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
504
ExecutionEngine *v4 = that->internalClass->engine;
505
if (v4->hasException)
506
return Encode::undefined();
507
CHECK_STACK_LIMITS(v4);
509
SimpleScriptFunction *f = static_cast<SimpleScriptFunction *>(that);
512
ExecutionContext *context = v4->currentContext();
513
ExecutionContextSaver ctxSaver(context);
516
ctx.strictMode = f->strictMode;
517
ctx.callData = callData;
519
ctx.compilationUnit = f->function->compilationUnit;
520
ctx.lookups = ctx.compilationUnit->runtimeLookups;
521
ctx.outer = f->scope;
522
ctx.locals = v4->stackPush(f->varCount());
523
while (callData->argc < (int)f->formalParameterCount()) {
524
callData->args[callData->argc] = Encode::undefined();
527
Q_ASSERT(v4->currentContext() == &ctx);
529
ScopedValue result(scope, Q_V4_PROFILE(v4, &ctx, f->function));
531
if (f->function->compiledFunction->hasQmlDependencies())
532
QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
534
return result.asReturnedValue();
537
InternalClass *SimpleScriptFunction::internalClassForConstructor()
539
ReturnedValue proto = protoProperty();
540
InternalClass *classForConstructor;
541
Scope scope(internalClass->engine);
542
ScopedObject p(scope, proto);
544
classForConstructor = internalClass->engine->constructClass->changePrototype(p.getPointer());
546
classForConstructor = scope.engine->objectClass;
548
return classForConstructor;
553
DEFINE_OBJECT_VTABLE(BuiltinFunction);
555
BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *))
556
: FunctionObject(scope, name)
559
setVTable(staticVTable());
562
ReturnedValue BuiltinFunction::construct(Managed *f, CallData *)
564
return f->internalClass->engine->currentContext()->throwTypeError();
567
ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
569
BuiltinFunction *f = static_cast<BuiltinFunction *>(that);
570
ExecutionEngine *v4 = f->internalClass->engine;
571
if (v4->hasException)
572
return Encode::undefined();
573
CHECK_STACK_LIMITS(v4);
575
ExecutionContext *context = v4->currentContext();
576
ExecutionContextSaver ctxSaver(context);
579
ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
580
ctx.callData = callData;
581
Q_ASSERT(v4->currentContext() == &ctx);
583
return f->code(&ctx);
586
ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData)
588
IndexedBuiltinFunction *f = static_cast<IndexedBuiltinFunction *>(that);
589
ExecutionEngine *v4 = f->internalClass->engine;
590
if (v4->hasException)
591
return Encode::undefined();
592
CHECK_STACK_LIMITS(v4);
594
ExecutionContext *context = v4->currentContext();
595
ExecutionContextSaver ctxSaver(context);
598
ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
599
ctx.callData = callData;
600
Q_ASSERT(v4->currentContext() == &ctx);
602
return f->code(&ctx, f->index);
605
DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
607
DEFINE_OBJECT_VTABLE(BoundFunction);
609
BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs)
610
: FunctionObject(scope, QStringLiteral("__bound function__"))
612
, boundArgs(boundArgs)
614
setVTable(staticVTable());
615
subtype = FunctionObject::BoundFunction;
616
this->boundThis = boundThis;
619
ScopedValue protectThis(s, this);
621
ScopedValue l(s, target->get(scope->engine->id_length));
622
int len = l->toUInt32();
623
len -= boundArgs.size();
626
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(len));
628
ExecutionEngine *v4 = scope->engine;
630
Property pd(v4->thrower, v4->thrower);
631
insertMember(scope->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
632
insertMember(scope->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
635
void BoundFunction::destroy(Managed *that)
637
static_cast<BoundFunction *>(that)->~BoundFunction();
640
ReturnedValue BoundFunction::call(Managed *that, CallData *dd)
642
BoundFunction *f = static_cast<BoundFunction *>(that);
643
Scope scope(f->scope->engine);
644
if (scope.hasException())
645
return Encode::undefined();
647
ScopedCallData callData(scope, f->boundArgs.size() + dd->argc);
648
callData->thisObject = f->boundThis;
649
memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value));
650
memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(Value));
651
return f->target->call(callData);
654
ReturnedValue BoundFunction::construct(Managed *that, CallData *dd)
656
BoundFunction *f = static_cast<BoundFunction *>(that);
657
Scope scope(f->scope->engine);
658
if (scope.hasException())
659
return Encode::undefined();
661
ScopedCallData callData(scope, f->boundArgs.size() + dd->argc);
662
memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value));
663
memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(Value));
664
return f->target->construct(callData);
667
void BoundFunction::markObjects(Managed *that, ExecutionEngine *e)
669
BoundFunction *o = static_cast<BoundFunction *>(that);
671
o->boundThis.mark(e);
672
for (int i = 0; i < o->boundArgs.size(); ++i)
673
o->boundArgs.at(i).mark(e);
674
FunctionObject::markObjects(that, e);