Encapsulate and protect all accesses to the vtable of Heap objects
[platform/upstream/qtdeclarative.git] / src / qml / jsruntime / qv4functionobject.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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 The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
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.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33
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"
40 #include <private/qv4mm_p.h>
41
42 #include "qv4arrayobject_p.h"
43 #include "qv4scopedvalue_p.h"
44
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 <qv4codegen_p.h>
52 #include "private/qlocale_tools_p.h"
53 #include "private/qqmlbuiltinfunctions_p.h"
54
55 #include <QtCore/QDebug>
56 #include <algorithm>
57 #include "qv4alloca_p.h"
58 #include "qv4profiling_p.h"
59
60 using namespace QV4;
61
62
63 DEFINE_OBJECT_VTABLE(FunctionObject);
64
65 Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, QV4::String *name, bool createProto)
66     : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype())
67     , scope(scope->d())
68     , function(Q_NULLPTR)
69 {
70     Scope s(scope->engine());
71     ScopedFunctionObject f(s, this);
72     f->init(name, createProto);
73 }
74
75 Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, Function *function, bool createProto)
76     : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype())
77     , scope(scope->d())
78     , function(Q_NULLPTR)
79 {
80     Scope s(scope->engine());
81     ScopedString name(s, function->name());
82     ScopedFunctionObject f(s, this);
83     f->init(name, createProto);
84 }
85
86 Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const QString &name, bool createProto)
87     : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype())
88     , scope(scope->d())
89     , function(Q_NULLPTR)
90 {
91     Scope s(scope->engine());
92     ScopedFunctionObject f(s, this);
93     ScopedString n(s, s.engine->newString(name));
94     f->init(n, createProto);
95 }
96
97 Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto)
98     : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype())
99     , scope(scope)
100     , function(Q_NULLPTR)
101 {
102     Scope s(scope->engine);
103     ScopedFunctionObject f(s, this);
104     ScopedString n(s, s.engine->newString(name));
105     f->init(n, createProto);
106 }
107
108 Heap::FunctionObject::FunctionObject(QV4::ExecutionContext *scope, const ReturnedValue name)
109     : Heap::Object(scope->d()->engine->functionClass, scope->d()->engine->functionPrototype())
110     , scope(scope->d())
111     , function(Q_NULLPTR)
112 {
113     Scope s(scope);
114     ScopedFunctionObject f(s, this);
115     ScopedString n(s, name);
116     f->init(n, false);
117 }
118
119 Heap::FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValue name)
120     : Heap::Object(scope->engine->functionClass, scope->engine->functionPrototype())
121     , scope(scope)
122     , function(Q_NULLPTR)
123 {
124     Scope s(scope->engine);
125     ScopedFunctionObject f(s, this);
126     ScopedString n(s, name);
127     f->init(n, false);
128 }
129
130 Heap::FunctionObject::FunctionObject(InternalClass *ic, QV4::Object *prototype)
131     : Heap::Object(ic, prototype)
132     , scope(ic->engine->rootContext()->d())
133     , function(Q_NULLPTR)
134 {
135     Scope scope(ic->engine);
136     ScopedObject o(scope, this);
137     o->ensureMemberIndex(ic->engine, Index_Prototype);
138     memberData->data[Index_Prototype] = Encode::undefined();
139 }
140
141
142 Heap::FunctionObject::~FunctionObject()
143 {
144     if (function)
145         function->compilationUnit->release();
146 }
147
148 void FunctionObject::init(String *n, bool createProto)
149 {
150     Scope s(internalClass()->engine);
151     ScopedValue protectThis(s, this);
152
153     ensureMemberIndex(s.engine, Heap::FunctionObject::Index_Prototype);
154     if (createProto) {
155         ScopedObject proto(s, scope()->engine->newObject(s.engine->protoClass, s.engine->objectPrototype()));
156         proto->ensureMemberIndex(s.engine, Heap::FunctionObject::Index_ProtoConstructor);
157         proto->memberData()->data[Heap::FunctionObject::Index_ProtoConstructor] = this->asReturnedValue();
158         memberData()->data[Heap::FunctionObject::Index_Prototype] = proto.asReturnedValue();
159     } else {
160         memberData()->data[Heap::FunctionObject::Index_Prototype] = Encode::undefined();
161     }
162
163     ScopedValue v(s, n);
164     defineReadonlyProperty(s.engine->id_name(), v);
165 }
166
167 ReturnedValue FunctionObject::name() const
168 {
169     return get(scope()->engine->id_name());
170 }
171
172
173 ReturnedValue FunctionObject::newInstance()
174 {
175     Scope scope(internalClass()->engine);
176     ScopedCallData callData(scope);
177     return construct(callData);
178 }
179
180 ReturnedValue FunctionObject::construct(const Managed *that, CallData *)
181 {
182     return static_cast<const FunctionObject *>(that)->engine()->throwTypeError();
183 }
184
185 ReturnedValue FunctionObject::call(const Managed *, CallData *)
186 {
187     return Encode::undefined();
188 }
189
190 void FunctionObject::markObjects(Heap::Base *that, ExecutionEngine *e)
191 {
192     Heap::FunctionObject *o = static_cast<Heap::FunctionObject *>(that);
193     if (o->scope)
194         o->scope->mark(e);
195
196     Object::markObjects(that, e);
197 }
198
199 Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function, bool createProto)
200 {
201     if (function->needsActivation() ||
202         function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith ||
203         function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount ||
204         function->isNamedExpression())
205         return scope->d()->engine->memoryManager->alloc<ScriptFunction>(scope, function);
206     return scope->d()->engine->memoryManager->alloc<SimpleScriptFunction>(scope, function, createProto);
207 }
208
209 bool FunctionObject::isBinding() const
210 {
211     return d()->vtable() == QQmlBindingFunction::staticVTable();
212 }
213
214 bool FunctionObject::isBoundFunction() const
215 {
216     return d()->vtable() == BoundFunction::staticVTable();
217 }
218
219 QQmlSourceLocation FunctionObject::sourceLocation() const
220 {
221     if (isBinding()) {
222         Q_ASSERT(as<const QV4::QQmlBindingFunction>());
223         return static_cast<QV4::Heap::QQmlBindingFunction *>(d())->bindingLocation;
224     }
225     QV4::Function *function = d()->function;
226     Q_ASSERT(function);
227
228     return QQmlSourceLocation(function->sourceFile(), function->compiledFunction->location.line, function->compiledFunction->location.column);
229 }
230
231 DEFINE_OBJECT_VTABLE(FunctionCtor);
232
233 Heap::FunctionCtor::FunctionCtor(QV4::ExecutionContext *scope)
234     : Heap::FunctionObject(scope, QStringLiteral("Function"))
235 {
236 }
237
238 // 15.3.2
239 ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData)
240 {
241     Scope scope(static_cast<const Object *>(that)->engine());
242     Scoped<FunctionCtor> f(scope, static_cast<const FunctionCtor *>(that));
243     ScopedContext ctx(scope, scope.engine->currentContext());
244     QString arguments;
245     QString body;
246     if (callData->argc > 0) {
247         for (int i = 0; i < callData->argc - 1; ++i) {
248             if (i)
249                 arguments += QLatin1String(", ");
250             arguments += callData->args[i].toQString();
251         }
252         body = callData->args[callData->argc - 1].toQString();
253     }
254     if (ctx->d()->engine->hasException)
255         return Encode::undefined();
256
257     QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1String("}");
258
259     QQmlJS::Engine ee, *engine = &ee;
260     QQmlJS::Lexer lexer(engine);
261     lexer.setCode(function, 1, false);
262     QQmlJS::Parser parser(engine);
263
264     const bool parsed = parser.parseExpression();
265
266     if (!parsed)
267         return scope.engine->throwSyntaxError(QLatin1String("Parse error"));
268
269     using namespace QQmlJS::AST;
270     FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode());
271     if (!fe)
272         return scope.engine->throwSyntaxError(QLatin1String("Parse error"));
273
274     IR::Module module(scope.engine->debugger != 0);
275
276     QQmlJS::RuntimeCodegen cg(scope.engine, f->strictMode());
277     cg.generateFromFunctionExpression(QString(), function, fe, &module);
278
279     Compiler::JSUnitGenerator jsGenerator(&module);
280     QScopedPointer<EvalInstructionSelection> isel(scope.engine->iselFactory->create(QQmlEnginePrivate::get(scope.engine), scope.engine->executableAllocator, &module, &jsGenerator));
281     QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = isel->compile();
282     Function *vmf = compilationUnit->linkToEngine(scope.engine);
283
284     ScopedContext global(scope, scope.engine->rootContext());
285     return FunctionObject::createScriptFunction(global, vmf)->asReturnedValue();
286 }
287
288 // 15.3.1: This is equivalent to new Function(...)
289 ReturnedValue FunctionCtor::call(const Managed *that, CallData *callData)
290 {
291     return construct(that, callData);
292 }
293
294 DEFINE_OBJECT_VTABLE(FunctionPrototype);
295
296 Heap::FunctionPrototype::FunctionPrototype(InternalClass *ic, QV4::Object *prototype)
297     : Heap::FunctionObject(ic, prototype)
298 {
299 }
300
301 void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
302 {
303     Scope scope(engine);
304     ScopedObject o(scope);
305
306     ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
307     ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
308
309     defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(0));
310     defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
311     defineDefaultProperty(engine->id_toString(), method_toString, 0);
312     defineDefaultProperty(QStringLiteral("apply"), method_apply, 2);
313     defineDefaultProperty(QStringLiteral("call"), method_call, 1);
314     defineDefaultProperty(QStringLiteral("bind"), method_bind, 1);
315
316 }
317
318 ReturnedValue FunctionPrototype::method_toString(CallContext *ctx)
319 {
320     FunctionObject *fun = ctx->thisObject().as<FunctionObject>();
321     if (!fun)
322         return ctx->engine()->throwTypeError();
323
324     return ctx->d()->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue();
325 }
326
327 ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
328 {
329     Scope scope(ctx);
330     ScopedFunctionObject o(scope, ctx->thisObject().as<FunctionObject>());
331     if (!o)
332         return ctx->engine()->throwTypeError();
333
334     ScopedValue arg(scope, ctx->argument(1));
335
336     ScopedObject arr(scope, arg);
337
338     quint32 len;
339     if (!arr) {
340         len = 0;
341         if (!arg->isNullOrUndefined())
342             return ctx->engine()->throwTypeError();
343     } else {
344         len = arr->getLength();
345     }
346
347     ScopedCallData callData(scope, len);
348
349     if (len) {
350         if (arr->arrayType() != Heap::ArrayData::Simple || arr->protoHasArray()) {
351             for (quint32 i = 0; i < len; ++i)
352                 callData->args[i] = arr->getIndexed(i);
353         } else {
354             uint alen = arr->arrayData() ? arr->arrayData()->len : 0;
355             if (alen > len)
356                 alen = len;
357             for (uint i = 0; i < alen; ++i)
358                 callData->args[i] = static_cast<Heap::SimpleArrayData *>(arr->arrayData())->data(i);
359             for (quint32 i = alen; i < len; ++i)
360                 callData->args[i] = Primitive::undefinedValue();
361         }
362     }
363
364     callData->thisObject = ctx->argument(0);
365     return o->call(callData);
366 }
367
368 ReturnedValue FunctionPrototype::method_call(CallContext *ctx)
369 {
370     Scope scope(ctx);
371
372     ScopedFunctionObject o(scope, ctx->thisObject().as<FunctionObject>());
373     if (!o)
374         return ctx->engine()->throwTypeError();
375
376     ScopedCallData callData(scope, ctx->argc() ? ctx->argc() - 1 : 0);
377     if (ctx->argc()) {
378         for (int i = 1; i < ctx->argc(); ++i)
379             callData->args[i - 1] = ctx->args()[i];
380     }
381     callData->thisObject = ctx->argument(0);
382     return o->call(callData);
383 }
384
385 ReturnedValue FunctionPrototype::method_bind(CallContext *ctx)
386 {
387     Scope scope(ctx);
388     ScopedFunctionObject target(scope, ctx->thisObject());
389     if (!target)
390         return ctx->engine()->throwTypeError();
391
392     ScopedValue boundThis(scope, ctx->argument(0));
393     Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0);
394     if (ctx->argc() > 1) {
395         boundArgs = MemberData::reallocate(scope.engine, 0, ctx->argc() - 1);
396         boundArgs->d()->size = ctx->argc() - 1;
397         memcpy(boundArgs->data(), ctx->args() + 1, (ctx->argc() - 1)*sizeof(Value));
398     }
399
400     ScopedContext global(scope, scope.engine->rootContext());
401     return BoundFunction::create(global, target, boundThis, boundArgs)->asReturnedValue();
402 }
403
404 DEFINE_OBJECT_VTABLE(ScriptFunction);
405
406 Heap::ScriptFunction::ScriptFunction(QV4::ExecutionContext *scope, Function *function)
407     : Heap::SimpleScriptFunction(scope, function, true)
408 {
409 }
410
411 ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData)
412 {
413     ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
414     if (v4->hasException)
415         return Encode::undefined();
416     CHECK_STACK_LIMITS(v4);
417
418     Scope scope(v4);
419     Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that));
420
421     InternalClass *ic = scope.engine->emptyClass;
422     ScopedObject proto(scope, f->protoForConstructor());
423     ScopedObject obj(scope, v4->newObject(ic, proto));
424
425     ScopedContext context(scope, v4->currentContext());
426     callData->thisObject = obj.asReturnedValue();
427     Scoped<CallContext> ctx(scope, context->newCallContext(f, callData));
428
429     ExecutionContextSaver ctxSaver(scope, context);
430     ScopedValue result(scope, Q_V4_PROFILE(v4, f->function()));
431
432     if (f->function()->compiledFunction->hasQmlDependencies())
433         QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction);
434
435     if (v4->hasException)
436         return Encode::undefined();
437
438     if (result->isObject())
439         return result->asReturnedValue();
440     return obj.asReturnedValue();
441 }
442
443 ReturnedValue ScriptFunction::call(const Managed *that, CallData *callData)
444 {
445     ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
446     if (v4->hasException)
447         return Encode::undefined();
448     CHECK_STACK_LIMITS(v4);
449
450     Scope scope(v4);
451     Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that));
452     ScopedContext context(scope, v4->currentContext());
453
454     Scoped<CallContext> ctx(scope, context->newCallContext(f, callData));
455
456     ExecutionContextSaver ctxSaver(scope, context);
457     ScopedValue result(scope, Q_V4_PROFILE(v4, f->function()));
458
459     if (f->function()->compiledFunction->hasQmlDependencies())
460         QmlContextWrapper::registerQmlDependencies(scope.engine, f->function()->compiledFunction);
461
462     return result->asReturnedValue();
463 }
464
465 DEFINE_OBJECT_VTABLE(SimpleScriptFunction);
466
467 Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, Function *function, bool createProto)
468     : Heap::FunctionObject(function->compilationUnit->engine->simpleScriptFunctionClass, function->compilationUnit->engine->functionPrototype())
469 {
470     this->scope = scope->d();
471
472     this->function = function;
473     function->compilationUnit->addref();
474     Q_ASSERT(function);
475     Q_ASSERT(function->code);
476
477     Scope s(scope);
478     ScopedFunctionObject f(s, this);
479
480     if (createProto) {
481         ScopedString name(s, function->name());
482         f->init(name, createProto);
483         f->defineReadonlyProperty(scope->d()->engine->id_length(), Primitive::fromInt32(f->formalParameterCount()));
484     } else {
485         f->ensureMemberIndex(s.engine, Index_Length);
486         memberData->data[Index_Name] = function->name();
487         memberData->data[Index_Length] = Primitive::fromInt32(f->formalParameterCount());
488     }
489
490     if (scope->d()->strictMode) {
491         ScopedProperty pd(s);
492         pd->value = s.engine->thrower();
493         pd->set = s.engine->thrower();
494         f->insertMember(scope->d()->engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
495         f->insertMember(scope->d()->engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
496     }
497 }
498
499 ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *callData)
500 {
501     ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
502     if (v4->hasException)
503         return Encode::undefined();
504     CHECK_STACK_LIMITS(v4);
505
506     Scope scope(v4);
507     Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that));
508
509     InternalClass *ic = scope.engine->emptyClass;
510     ScopedObject proto(scope, f->protoForConstructor());
511     callData->thisObject = v4->newObject(ic, proto);
512
513     ExecutionContextSaver ctxSaver(scope, v4->currentContext());
514
515     CallContext::Data ctx(v4);
516 #ifndef QT_NO_DEBUG
517     ctx.mm_data = 0; // make sure we don't run into the assertion in setVTable when allocating a context on the stack
518 #endif
519     ctx.setVtable(CallContext::staticVTable());
520     ctx.strictMode = f->strictMode();
521     ctx.callData = callData;
522     ctx.function = f->d();
523     ctx.compilationUnit = f->function()->compilationUnit;
524     ctx.lookups = ctx.compilationUnit->runtimeLookups;
525     ctx.outer = f->scope();
526     ctx.locals = scope.alloc(f->varCount());
527     for (int i = callData->argc; i < (int)f->formalParameterCount(); ++i)
528         callData->args[i] = Encode::undefined();
529     Q_ASSERT(v4->currentContext() == &ctx);
530
531     ScopedObject result(scope, Q_V4_PROFILE(v4, f->function()));
532
533     if (f->function()->compiledFunction->hasQmlDependencies())
534         QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction);
535
536     if (!result)
537         return callData->thisObject.asReturnedValue();
538     return result.asReturnedValue();
539 }
540
541 ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData)
542 {
543     ExecutionEngine *v4 = static_cast<const SimpleScriptFunction *>(that)->internalClass()->engine;
544     if (v4->hasException)
545         return Encode::undefined();
546     CHECK_STACK_LIMITS(v4);
547
548     Scope scope(v4);
549     Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that));
550
551     ExecutionContextSaver ctxSaver(scope, v4->currentContext());
552
553     CallContext::Data ctx(v4);
554 #ifndef QT_NO_DEBUG
555     ctx.mm_data = 0; // make sure we don't run into the assertion in setVTable when allocating a context on the stack
556 #endif
557     ctx.setVtable(CallContext::staticVTable());
558     ctx.strictMode = f->strictMode();
559     ctx.callData = callData;
560     ctx.function = f->d();
561     ctx.compilationUnit = f->function()->compilationUnit;
562     ctx.lookups = ctx.compilationUnit->runtimeLookups;
563     ctx.outer = f->scope();
564     ctx.locals = scope.alloc(f->varCount());
565     for (int i = callData->argc; i < (int)f->formalParameterCount(); ++i)
566         callData->args[i] = Encode::undefined();
567     Q_ASSERT(v4->currentContext() == &ctx);
568
569     ScopedValue result(scope, Q_V4_PROFILE(v4, f->function()));
570
571     if (f->function()->compiledFunction->hasQmlDependencies())
572         QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction);
573
574     return result->asReturnedValue();
575 }
576
577 Heap::Object *SimpleScriptFunction::protoForConstructor()
578 {
579     Scope scope(engine());
580     ScopedObject p(scope, protoProperty());
581     if (p)
582         return p->d();
583     return scope.engine->objectPrototype()->d();
584 }
585
586
587
588 DEFINE_OBJECT_VTABLE(BuiltinFunction);
589
590 Heap::BuiltinFunction::BuiltinFunction(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *))
591     : Heap::FunctionObject(scope, name)
592     , code(code)
593 {
594 }
595
596 ReturnedValue BuiltinFunction::construct(const Managed *f, CallData *)
597 {
598     return static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
599 }
600
601 ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData)
602 {
603     const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that);
604     ExecutionEngine *v4 = f->internalClass()->engine;
605     if (v4->hasException)
606         return Encode::undefined();
607     CHECK_STACK_LIMITS(v4);
608
609     Scope scope(v4);
610     ExecutionContextSaver ctxSaver(scope, v4->currentContext());
611
612     CallContext::Data ctx(v4);
613 #ifndef QT_NO_DEBUG
614     ctx.mm_data = 0; // make sure we don't run into the assertion in setVTable when allocating a context on the stack
615 #endif
616     ctx.setVtable(CallContext::staticVTable());
617     ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
618     ctx.callData = callData;
619     Q_ASSERT(v4->currentContext() == &ctx);
620     Scoped<CallContext> sctx(scope, &ctx);
621
622     return f->d()->code(sctx);
623 }
624
625 ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callData)
626 {
627     const IndexedBuiltinFunction *f = static_cast<const IndexedBuiltinFunction *>(that);
628     ExecutionEngine *v4 = f->internalClass()->engine;
629     if (v4->hasException)
630         return Encode::undefined();
631     CHECK_STACK_LIMITS(v4);
632
633     Scope scope(v4);
634     ExecutionContextSaver ctxSaver(scope, v4->currentContext());
635
636     CallContext::Data ctx(v4);
637 #ifndef QT_NO_DEBUG
638     ctx.mm_data = 0; // make sure we don't run into the assertion in setVTable when allocating a context on the stack
639 #endif
640     ctx.setVtable(CallContext::staticVTable());
641     ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
642     ctx.callData = callData;
643     Q_ASSERT(v4->currentContext() == &ctx);
644     Scoped<CallContext> sctx(scope, &ctx);
645
646     return f->d()->code(sctx, f->d()->index);
647 }
648
649 DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
650
651 DEFINE_OBJECT_VTABLE(BoundFunction);
652
653 Heap::BoundFunction::BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionObject *target,
654                                    const Value &boundThis, QV4::MemberData *boundArgs)
655     : Heap::FunctionObject(scope, QStringLiteral("__bound function__"))
656     , target(target->d())
657     , boundArgs(boundArgs ? boundArgs->d() : 0)
658 {
659     this->boundThis = boundThis;
660
661     Scope s(scope);
662     ScopedObject f(s, this);
663
664     ScopedValue l(s, target->get(s.engine->id_length()));
665     int len = l->toUInt32();
666     if (boundArgs)
667         len -= boundArgs->size();
668     if (len < 0)
669         len = 0;
670     f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(len));
671
672     ScopedProperty pd(s);
673     pd->value = s.engine->thrower();
674     pd->set = s.engine->thrower();
675     f->insertMember(s.engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
676     f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
677 }
678
679 ReturnedValue BoundFunction::call(const Managed *that, CallData *dd)
680 {
681     const BoundFunction *f = static_cast<const BoundFunction *>(that);
682     Scope scope(f->engine());
683     if (scope.hasException())
684         return Encode::undefined();
685
686     Scoped<MemberData> boundArgs(scope, f->boundArgs());
687     ScopedCallData callData(scope, (boundArgs ? boundArgs->size() : 0) + dd->argc);
688     callData->thisObject = f->boundThis();
689     Value *argp = callData->args;
690     if (boundArgs) {
691         memcpy(argp, boundArgs->data(), boundArgs->size()*sizeof(Value));
692         argp += boundArgs->size();
693     }
694     memcpy(argp, dd->args, dd->argc*sizeof(Value));
695     ScopedFunctionObject t(scope, f->target());
696     return t->call(callData);
697 }
698
699 ReturnedValue BoundFunction::construct(const Managed *that, CallData *dd)
700 {
701     const BoundFunction *f = static_cast<const BoundFunction *>(that);
702     Scope scope(f->engine());
703     if (scope.hasException())
704         return Encode::undefined();
705
706     Scoped<MemberData> boundArgs(scope, f->boundArgs());
707     ScopedCallData callData(scope, (boundArgs ? boundArgs->size() : 0) + dd->argc);
708     Value *argp = callData->args;
709     if (boundArgs) {
710         memcpy(argp, boundArgs->data(), boundArgs->size()*sizeof(Value));
711         argp += boundArgs->size();
712     }
713     memcpy(argp, dd->args, dd->argc*sizeof(Value));
714     ScopedFunctionObject t(scope, f->target());
715     return t->construct(callData);
716 }
717
718 void BoundFunction::markObjects(Heap::Base *that, ExecutionEngine *e)
719 {
720     BoundFunction::Data *o = static_cast<BoundFunction::Data *>(that);
721     o->target->mark(e);
722     o->boundThis.mark(e);
723     if (o->boundArgs)
724         o->boundArgs->mark(e);
725     FunctionObject::markObjects(that, e);
726 }