1
/****************************************************************************
3
** Copyright (C) 2014 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:LGPL21$
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 or version 3 as published by the Free
20
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22
** following information to ensure the GNU Lesser General Public License
23
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
26
** In addition, as a special exception, Digia gives you certain additional
27
** rights. These rights are described in the Digia Qt LGPL Exception
28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
32
****************************************************************************/
34
#include "qv4object_p.h"
35
#include "qv4jsir_p.h"
36
#include "qv4isel_p.h"
37
#include "qv4objectproto_p.h"
38
#include "qv4stringobject_p.h"
39
#include "qv4function_p.h"
42
#include "qv4arrayobject_p.h"
43
#include "qv4scopedvalue_p.h"
45
#include <private/qqmljsengine_p.h>
46
#include <private/qqmljslexer_p.h>
47
#include <private/qqmljsparser_p.h>
48
#include <private/qqmljsast_p.h>
49
#include <private/qqmlcontextwrapper_p.h>
50
#include <private/qqmlengine_p.h>
51
#include <qv4jsir_p.h>
52
#include <qv4codegen_p.h>
53
#include "private/qlocale_tools_p.h"
55
#include <QtCore/qmath.h>
56
#include <QtCore/QDebug>
61
#include "qv4alloca_p.h"
62
#include "qv4profiling_p.h"
67
DEFINE_OBJECT_VTABLE(FunctionObject);
69
FunctionObject::Data::Data(ExecutionContext *scope, String *name, bool createProto)
70
: Object::Data(scope->d()->engine->functionClass)
74
ScopedFunctionObject f(s, this);
75
f->init(name, createProto);
79
FunctionObject::Data::Data(ExecutionContext *scope, const QString &name, bool createProto)
80
: Object::Data(scope->d()->engine->functionClass)
84
ScopedFunctionObject f(s, this);
85
ScopedString n(s, s.engine->newString(name));
86
f->init(n.getPointer(), createProto);
89
FunctionObject::Data::Data(ExecutionContext *scope, const ReturnedValue name)
90
: Object::Data(scope->d()->engine->functionClass)
94
ScopedFunctionObject f(s, this);
95
ScopedString n(s, name);
96
f->init(n.getPointer(), false);
99
FunctionObject::Data::Data(InternalClass *ic)
101
, scope(ic->engine->rootContext)
103
memberData.ensureIndex(ic->engine, Index_Prototype);
104
memberData[Index_Prototype] = Encode::undefined();
108
FunctionObject::Data::~Data()
111
function->compilationUnit->release();
114
void FunctionObject::init(String *n, bool createProto)
116
Scope s(internalClass()->engine);
117
ScopedValue protectThis(s, this);
119
d()->needsActivation = true;
120
d()->strictMode = false;
122
memberData().ensureIndex(s.engine, Index_Prototype);
124
Scoped<Object> proto(s, scope()->d()->engine->newObject(scope()->d()->engine->protoClass));
125
proto->memberData()[Index_ProtoConstructor] = this->asReturnedValue();
126
memberData()[Index_Prototype] = proto.asReturnedValue();
128
memberData()[Index_Prototype] = Encode::undefined();
132
defineReadonlyProperty(s.engine->id_name, v);
135
ReturnedValue FunctionObject::name()
137
return get(scope()->d()->engine->id_name);
141
ReturnedValue FunctionObject::newInstance()
143
Scope scope(internalClass()->engine);
144
ScopedCallData callData(scope, 0);
145
return construct(callData);
148
ReturnedValue FunctionObject::construct(Managed *that, CallData *)
150
that->internalClass()->engine->currentContext()->throwTypeError();
151
return Encode::undefined();
154
ReturnedValue FunctionObject::call(Managed *, CallData *)
156
return Encode::undefined();
159
void FunctionObject::markObjects(Managed *that, ExecutionEngine *e)
161
FunctionObject *o = static_cast<FunctionObject *>(that);
165
Object::markObjects(that, e);
168
FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function, bool createProto)
170
if (function->needsActivation() ||
171
function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith ||
172
function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount ||
173
function->isNamedExpression())
174
return scope->d()->engine->memoryManager->alloc<ScriptFunction>(scope, function);
175
return scope->d()->engine->memoryManager->alloc<SimpleScriptFunction>(scope, function, createProto);
178
DEFINE_OBJECT_VTABLE(FunctionCtor);
180
FunctionCtor::Data::Data(ExecutionContext *scope)
181
: FunctionObject::Data(scope, QStringLiteral("Function"))
183
setVTable(staticVTable());
187
ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
189
FunctionCtor *f = static_cast<FunctionCtor *>(that);
190
ExecutionEngine *v4 = f->internalClass()->engine;
191
ExecutionContext *ctx = v4->currentContext();
194
if (callData->argc > 0) {
195
for (int i = 0; i < callData->argc - 1; ++i) {
197
arguments += QLatin1String(", ");
198
arguments += callData->args[i].toString(ctx)->toQString();
200
body = callData->args[callData->argc - 1].toString(ctx)->toQString();
202
if (ctx->d()->engine->hasException)
203
return Encode::undefined();
205
QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1String("}");
207
QQmlJS::Engine ee, *engine = ⅇ
208
QQmlJS::Lexer lexer(engine);
209
lexer.setCode(function, 1, false);
210
QQmlJS::Parser parser(engine);
212
const bool parsed = parser.parseExpression();
215
return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error"));
217
using namespace QQmlJS::AST;
218
FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode());
220
return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error"));
222
IR::Module module(v4->debugger != 0);
224
QQmlJS::RuntimeCodegen cg(v4->currentContext(), f->strictMode());
225
cg.generateFromFunctionExpression(QString(), function, fe, &module);
227
QV4::Compiler::JSUnitGenerator jsGenerator(&module);
228
QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
229
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = isel->compile();
230
QV4::Function *vmf = compilationUnit->linkToEngine(v4);
232
return FunctionObject::createScriptFunction(v4->rootContext, vmf)->asReturnedValue();
235
// 15.3.1: This is equivalent to new Function(...)
236
ReturnedValue FunctionCtor::call(Managed *that, CallData *callData)
238
return construct(that, callData);
241
DEFINE_OBJECT_VTABLE(FunctionPrototype);
243
FunctionPrototype::Data::Data(InternalClass *ic)
244
: FunctionObject::Data(ic)
248
void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
251
ScopedObject o(scope);
253
ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1));
254
ctor->defineReadonlyProperty(engine->id_prototype, (o = this));
256
defineReadonlyProperty(engine->id_length, Primitive::fromInt32(0));
257
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
258
defineDefaultProperty(engine->id_toString, method_toString, 0);
259
defineDefaultProperty(QStringLiteral("apply"), method_apply, 2);
260
defineDefaultProperty(QStringLiteral("call"), method_call, 1);
261
defineDefaultProperty(QStringLiteral("bind"), method_bind, 1);
265
ReturnedValue FunctionPrototype::method_toString(CallContext *ctx)
267
FunctionObject *fun = ctx->d()->callData->thisObject.asFunctionObject();
269
return ctx->throwTypeError();
271
return ctx->d()->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue();
274
ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
277
FunctionObject *o = ctx->d()->callData->thisObject.asFunctionObject();
279
return ctx->throwTypeError();
281
ScopedValue arg(scope, ctx->argument(1));
283
ScopedObject arr(scope, arg);
288
if (!arg->isNullOrUndefined())
289
return ctx->throwTypeError();
291
len = arr->getLength();
294
ScopedCallData callData(scope, len);
297
if (arr->arrayType() != ArrayData::Simple || arr->protoHasArray() || arr->hasAccessorProperty()) {
298
for (quint32 i = 0; i < len; ++i)
299
callData->args[i] = arr->getIndexed(i);
301
uint alen = arr->arrayData() ? arr->arrayData()->length() : 0;
304
for (uint i = 0; i < alen; ++i)
305
callData->args[i] = static_cast<SimpleArrayData *>(arr->arrayData())->data(i);
306
for (quint32 i = alen; i < len; ++i)
307
callData->args[i] = Primitive::undefinedValue();
311
callData->thisObject = ctx->argument(0);
312
return o->call(callData);
315
ReturnedValue FunctionPrototype::method_call(CallContext *ctx)
319
FunctionObject *o = ctx->d()->callData->thisObject.asFunctionObject();
321
return ctx->throwTypeError();
323
ScopedCallData callData(scope, ctx->d()->callData->argc ? ctx->d()->callData->argc - 1 : 0);
324
if (ctx->d()->callData->argc) {
325
for (int i = 1; i < ctx->d()->callData->argc; ++i)
326
callData->args[i - 1] = ctx->d()->callData->args[i];
328
callData->thisObject = ctx->argument(0);
329
return o->call(callData);
332
ReturnedValue FunctionPrototype::method_bind(CallContext *ctx)
335
Scoped<FunctionObject> target(scope, ctx->d()->callData->thisObject);
337
return ctx->throwTypeError();
339
ScopedValue boundThis(scope, ctx->argument(0));
342
if (ctx->d()->callData->argc > 1) {
343
boundArgs.ensureIndex(scope.engine, ctx->d()->callData->argc - 1);
344
boundArgs.d()->d()->size = ctx->d()->callData->argc - 1;
345
memcpy(boundArgs.data(), ctx->d()->callData->args + 1, (ctx->d()->callData->argc - 1)*sizeof(Value));
347
ScopedValue protectBoundArgs(scope, boundArgs.d());
349
return BoundFunction::create(ctx->d()->engine->rootContext, target, boundThis, boundArgs)->asReturnedValue();
352
DEFINE_OBJECT_VTABLE(ScriptFunction);
354
ScriptFunction::Data::Data(ExecutionContext *scope, Function *function)
355
: SimpleScriptFunction::Data(scope, function, true)
357
setVTable(staticVTable());
360
ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
362
ExecutionEngine *v4 = that->engine();
363
if (v4->hasException)
364
return Encode::undefined();
365
CHECK_STACK_LIMITS(v4);
368
Scoped<ScriptFunction> f(scope, static_cast<ScriptFunction *>(that));
370
InternalClass *ic = f->internalClassForConstructor();
371
ScopedObject obj(scope, v4->newObject(ic));
373
ExecutionContext *context = v4->currentContext();
374
callData->thisObject = obj.asReturnedValue();
375
ExecutionContext *ctx = reinterpret_cast<ExecutionContext *>(context->newCallContext(f.getPointer(), callData));
377
ExecutionContextSaver ctxSaver(context);
378
ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function()));
380
if (f->function()->compiledFunction->hasQmlDependencies())
381
QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction);
383
if (v4->hasException)
384
return Encode::undefined();
386
if (result->isObject())
387
return result.asReturnedValue();
388
return obj.asReturnedValue();
391
ReturnedValue ScriptFunction::call(Managed *that, CallData *callData)
393
ScriptFunction *f = static_cast<ScriptFunction *>(that);
394
ExecutionEngine *v4 = f->engine();
395
if (v4->hasException)
396
return Encode::undefined();
397
CHECK_STACK_LIMITS(v4);
399
ExecutionContext *context = v4->currentContext();
400
Scope scope(context);
402
CallContext *ctx = reinterpret_cast<CallContext *>(context->newCallContext(f, callData));
404
ExecutionContextSaver ctxSaver(context);
405
ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function()));
407
if (f->function()->compiledFunction->hasQmlDependencies())
408
QmlContextWrapper::registerQmlDependencies(ctx->d()->engine, f->function()->compiledFunction);
410
return result.asReturnedValue();
413
DEFINE_OBJECT_VTABLE(SimpleScriptFunction);
415
SimpleScriptFunction::Data::Data(ExecutionContext *scope, Function *function, bool createProto)
416
: FunctionObject::Data(scope, function->name(), createProto)
418
setVTable(staticVTable());
420
this->function = function;
421
function->compilationUnit->addref();
423
Q_ASSERT(function->code);
425
needsActivation = function->needsActivation();
426
strictMode = function->isStrict();
433
ScopedFunctionObject f(s, this);
435
f->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(f->formalParameterCount()));
437
if (scope->d()->strictMode) {
438
Property pd(s.engine->thrower, s.engine->thrower);
439
f->insertMember(scope->d()->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
440
f->insertMember(scope->d()->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
444
ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
446
ExecutionEngine *v4 = that->engine();
447
if (v4->hasException)
448
return Encode::undefined();
449
CHECK_STACK_LIMITS(v4);
452
Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that));
454
InternalClass *ic = f->internalClassForConstructor();
455
callData->thisObject = v4->newObject(ic);
457
ExecutionContext *context = v4->currentContext();
458
ExecutionContextSaver ctxSaver(context);
460
CallContext::Data ctx(v4);
461
ctx.strictMode = f->strictMode();
462
ctx.callData = callData;
463
ctx.function = f.getPointer();
464
ctx.compilationUnit = f->function()->compilationUnit;
465
ctx.lookups = ctx.compilationUnit->runtimeLookups;
466
ctx.outer = f->scope();
467
ctx.locals = v4->stackPush(f->varCount());
468
while (callData->argc < (int)f->formalParameterCount()) {
469
callData->args[callData->argc] = Encode::undefined();
472
Q_ASSERT(v4->currentContext()->d() == &ctx);
474
Scoped<Object> result(scope, Q_V4_PROFILE(v4, reinterpret_cast<CallContext *>(&ctx), f->function()));
476
if (f->function()->compiledFunction->hasQmlDependencies())
477
QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction);
480
return callData->thisObject.asReturnedValue();
481
return result.asReturnedValue();
484
ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
486
ExecutionEngine *v4 = that->internalClass()->engine;
487
if (v4->hasException)
488
return Encode::undefined();
489
CHECK_STACK_LIMITS(v4);
491
SimpleScriptFunction *f = static_cast<SimpleScriptFunction *>(that);
494
ExecutionContext *context = v4->currentContext();
495
ExecutionContextSaver ctxSaver(context);
497
CallContext::Data ctx(v4);
498
ctx.strictMode = f->strictMode();
499
ctx.callData = callData;
501
ctx.compilationUnit = f->function()->compilationUnit;
502
ctx.lookups = ctx.compilationUnit->runtimeLookups;
503
ctx.outer = f->scope();
504
ctx.locals = v4->stackPush(f->varCount());
505
while (callData->argc < (int)f->formalParameterCount()) {
506
callData->args[callData->argc] = Encode::undefined();
509
Q_ASSERT(v4->currentContext()->d() == &ctx);
511
ScopedValue result(scope, Q_V4_PROFILE(v4, reinterpret_cast<CallContext *>(&ctx), f->function()));
513
if (f->function()->compiledFunction->hasQmlDependencies())
514
QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction);
516
return result.asReturnedValue();
519
InternalClass *SimpleScriptFunction::internalClassForConstructor()
521
ReturnedValue proto = protoProperty();
522
InternalClass *classForConstructor;
523
Scope scope(internalClass()->engine);
524
ScopedObject p(scope, proto);
526
classForConstructor = internalClass()->engine->constructClass->changePrototype(p.getPointer());
528
classForConstructor = scope.engine->objectClass;
530
return classForConstructor;
535
DEFINE_OBJECT_VTABLE(BuiltinFunction);
537
BuiltinFunction::Data::Data(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *))
538
: FunctionObject::Data(scope, name)
541
setVTable(staticVTable());
544
ReturnedValue BuiltinFunction::construct(Managed *f, CallData *)
546
return f->internalClass()->engine->currentContext()->throwTypeError();
549
ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
551
BuiltinFunction *f = static_cast<BuiltinFunction *>(that);
552
ExecutionEngine *v4 = f->internalClass()->engine;
553
if (v4->hasException)
554
return Encode::undefined();
555
CHECK_STACK_LIMITS(v4);
557
ExecutionContext *context = v4->currentContext();
558
ExecutionContextSaver ctxSaver(context);
560
CallContext::Data ctx(v4);
561
ctx.strictMode = f->scope()->d()->strictMode; // ### needed? scope or parent context?
562
ctx.callData = callData;
563
Q_ASSERT(v4->currentContext()->d() == &ctx);
565
return f->d()->code(reinterpret_cast<CallContext *>(&ctx));
568
ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData)
570
IndexedBuiltinFunction *f = static_cast<IndexedBuiltinFunction *>(that);
571
ExecutionEngine *v4 = f->internalClass()->engine;
572
if (v4->hasException)
573
return Encode::undefined();
574
CHECK_STACK_LIMITS(v4);
576
ExecutionContext *context = v4->currentContext();
577
ExecutionContextSaver ctxSaver(context);
579
CallContext::Data ctx(v4);
580
ctx.strictMode = f->scope()->d()->strictMode; // ### needed? scope or parent context?
581
ctx.callData = callData;
582
Q_ASSERT(v4->currentContext()->d() == &ctx);
584
return f->d()->code(reinterpret_cast<CallContext *>(&ctx), f->d()->index);
587
DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
589
DEFINE_OBJECT_VTABLE(BoundFunction);
591
BoundFunction::Data::Data(ExecutionContext *scope, FunctionObject *target, const ValueRef boundThis, const Members &boundArgs)
592
: FunctionObject::Data(scope, QStringLiteral("__bound function__"))
594
, boundArgs(boundArgs)
596
this->boundThis = boundThis;
597
setVTable(staticVTable());
598
subtype = FunctionObject::BoundFunction;
601
ScopedObject f(s, this);
603
ScopedValue l(s, target->get(s.engine->id_length));
604
int len = l->toUInt32();
605
len -= boundArgs.size();
608
f->defineReadonlyProperty(s.engine->id_length, Primitive::fromInt32(len));
610
ExecutionEngine *v4 = s.engine;
612
Property pd(v4->thrower, v4->thrower);
613
f->insertMember(s.engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
614
f->insertMember(s.engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
617
ReturnedValue BoundFunction::call(Managed *that, CallData *dd)
619
BoundFunction *f = static_cast<BoundFunction *>(that);
620
Scope scope(f->scope()->d()->engine);
621
if (scope.hasException())
622
return Encode::undefined();
624
ScopedCallData callData(scope, f->boundArgs().size() + dd->argc);
625
callData->thisObject = f->boundThis();
626
memcpy(callData->args, f->boundArgs().data(), f->boundArgs().size()*sizeof(Value));
627
memcpy(callData->args + f->boundArgs().size(), dd->args, dd->argc*sizeof(Value));
628
return f->target()->call(callData);
631
ReturnedValue BoundFunction::construct(Managed *that, CallData *dd)
633
BoundFunction *f = static_cast<BoundFunction *>(that);
634
Scope scope(f->scope()->d()->engine);
635
if (scope.hasException())
636
return Encode::undefined();
638
ScopedCallData callData(scope, f->boundArgs().size() + dd->argc);
639
memcpy(callData->args, f->boundArgs().data(), f->boundArgs().size()*sizeof(Value));
640
memcpy(callData->args + f->boundArgs().size(), dd->args, dd->argc*sizeof(Value));
641
return f->target()->construct(callData);
644
void BoundFunction::markObjects(Managed *that, ExecutionEngine *e)
646
BoundFunction *o = static_cast<BoundFunction *>(that);
647
o->target()->mark(e);
648
o->boundThis().mark(e);
649
o->boundArgs().mark(e);
650
FunctionObject::markObjects(that, e);