1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qv4object_p.h"
41 #include "qv4objectproto_p.h"
42 #include "qv4stringobject_p.h"
43 #include "qv4function_p.h"
44 #include "qv4symbol_p.h"
45 #include <private/qv4mm_p.h>
46 
47 #include "qv4arrayobject_p.h"
48 #include "qv4scopedvalue_p.h"
49 #include "qv4argumentsobject_p.h"
50 
51 #include <private/qqmljsengine_p.h>
52 #include <private/qqmljslexer_p.h>
53 #include <private/qqmljsparser_p.h>
54 #include <private/qqmljsast_p.h>
55 #include <private/qqmljavascriptexpression_p.h>
56 #include <private/qqmlengine_p.h>
57 #include <qv4runtimecodegen_p.h>
58 #include "private/qlocale_tools_p.h"
59 #include "private/qqmlbuiltinfunctions_p.h"
60 #include <private/qv4jscall_p.h>
61 #include <private/qv4vme_moth_p.h>
62 #include <private/qv4alloca_p.h>
63 
64 #include <QtCore/QDebug>
65 #include <algorithm>
66 #include "qv4profiling_p.h"
67 
68 using namespace QV4;
69 
70 
71 DEFINE_OBJECT_VTABLE(FunctionObject);
72 
init(QV4::ExecutionContext * scope,QV4::String * name,VTable::Call call)73 void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, VTable::Call call)
74 {
75     jsCall = call;
76     jsConstruct = nullptr;
77 
78     Object::init();
79     this->scope.set(scope->engine(), scope->d());
80     Scope s(scope->engine());
81     ScopedFunctionObject f(s, this);
82     if (name)
83         f->setName(name);
84 }
85 
init(QV4::ExecutionContext * scope,QV4::String * name)86 void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name)
87 {
88     ExecutionEngine *e = scope->engine();
89 
90     jsCall = vtable()->call;
91     jsConstruct = vtable()->callAsConstructor;
92 
93     Object::init();
94     this->scope.set(scope->engine(), scope->d());
95     Scope s(e);
96     ScopedFunctionObject f(s, this);
97     if (name)
98         f->setName(name);
99 }
100 
101 
102 
init(QV4::ExecutionContext * scope,Function * function,QV4::String * n)103 void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n)
104 {
105     jsCall = vtable()->call;
106     jsConstruct = vtable()->callAsConstructor;
107 
108     Object::init();
109     setFunction(function);
110     this->scope.set(scope->engine(), scope->d());
111     Scope s(scope->engine());
112     ScopedString name(s, n ? n->d() : function->name());
113     ScopedFunctionObject f(s, this);
114     if (name)
115         f->setName(name);
116 }
117 
init(QV4::ExecutionContext * scope,const QString & name)118 void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const QString &name)
119 {
120     Scope valueScope(scope);
121     ScopedString s(valueScope, valueScope.engine->newString(name));
122     init(scope, s);
123 }
124 
init()125 void Heap::FunctionObject::init()
126 {
127     jsCall = vtable()->call;
128     jsConstruct = vtable()->callAsConstructor;
129 
130     Object::init();
131     this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d());
132 }
133 
setFunction(Function * f)134 void Heap::FunctionObject::setFunction(Function *f)
135 {
136     if (f) {
137         function = f;
138         function->executableCompilationUnit()->addref();
139     }
140 }
destroy()141 void Heap::FunctionObject::destroy()
142 {
143     if (function)
144         function->executableCompilationUnit()->release();
145     Object::destroy();
146 }
147 
createDefaultPrototypeProperty(uint protoConstructorSlot)148 void FunctionObject::createDefaultPrototypeProperty(uint protoConstructorSlot)
149 {
150     Scope s(this);
151 
152     Q_ASSERT(s.engine->internalClasses(EngineBase::Class_ObjectProto)->verifyIndex(s.engine->id_constructor()->propertyKey(), protoConstructorSlot));
153 
154     ScopedObject proto(s, s.engine->newObject(s.engine->internalClasses(EngineBase::Class_ObjectProto)));
155     proto->setProperty(protoConstructorSlot, d());
156     defineDefaultProperty(s.engine->id_prototype(), proto, Attr_NotEnumerable|Attr_NotConfigurable);
157 }
158 
name() const159 ReturnedValue FunctionObject::name() const
160 {
161     return get(scope()->internalClass->engine->id_name());
162 }
163 
virtualCall(const FunctionObject *,const Value *,const Value *,int)164 ReturnedValue FunctionObject::virtualCall(const FunctionObject *, const Value *, const Value *, int)
165 {
166     return Encode::undefined();
167 }
168 
createScriptFunction(ExecutionContext * scope,Function * function)169 Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function)
170 {
171     if (function->isArrowFunction())
172         return scope->engine()->memoryManager->allocate<ArrowFunction>(scope, function);
173     return scope->engine()->memoryManager->allocate<ScriptFunction>(scope, function);
174 }
175 
createConstructorFunction(ExecutionContext * scope,Function * function,Object * homeObject,bool isDerivedConstructor)176 Heap::FunctionObject *FunctionObject::createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor)
177 {
178     if (!function) {
179         Heap::DefaultClassConstructorFunction *c = scope->engine()->memoryManager->allocate<DefaultClassConstructorFunction>(scope);
180         c->isDerivedConstructor = isDerivedConstructor;
181         return c;
182     }
183     Heap::ConstructorFunction *c = scope->engine()->memoryManager->allocate<ConstructorFunction>(scope, function);
184     c->homeObject.set(scope->engine(), homeObject->d());
185     c->isDerivedConstructor = isDerivedConstructor;
186     return c;
187 }
188 
createMemberFunction(ExecutionContext * scope,Function * function,Object * homeObject,QV4::String * name)189 Heap::FunctionObject *FunctionObject::createMemberFunction(ExecutionContext *scope, Function *function, Object *homeObject, QV4::String *name)
190 {
191     Heap::MemberFunction *m = scope->engine()->memoryManager->allocate<MemberFunction>(scope, function, name);
192     m->homeObject.set(scope->engine(), homeObject->d());
193     return m;
194 }
195 
createBuiltinFunction(ExecutionEngine * engine,StringOrSymbol * nameOrSymbol,VTable::Call code,int argumentCount)196 Heap::FunctionObject *FunctionObject::createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount)
197 {
198     Scope scope(engine);
199     ScopedString name(scope, nameOrSymbol);
200     if (!name)
201         name = engine->newString(QChar::fromLatin1('[') + nameOrSymbol->toQString().midRef(1) + QChar::fromLatin1(']'));
202 
203     ScopedFunctionObject function(scope, engine->memoryManager->allocate<FunctionObject>(engine->rootContext(), name, code));
204     function->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(argumentCount));
205     return function->d();
206 }
207 
getHomeObject() const208 ReturnedValue FunctionObject::getHomeObject() const
209 {
210     const MemberFunction *m = as<MemberFunction>();
211     if (m)
212         return m->d()->homeObject->asReturnedValue();
213     const ConstructorFunction *c = as<ConstructorFunction>();
214     if (c)
215         return c->d()->homeObject->asReturnedValue();
216     return Encode::undefined();
217 }
218 
sourceLocation() const219 QQmlSourceLocation FunctionObject::sourceLocation() const
220 {
221     return d()->function->sourceLocation();
222 }
223 
224 DEFINE_OBJECT_VTABLE(FunctionCtor);
225 
init(QV4::ExecutionContext * scope)226 void Heap::FunctionCtor::init(QV4::ExecutionContext *scope)
227 {
228     Heap::FunctionObject::init(scope, QStringLiteral("Function"));
229 }
230 
231 // 15.3.2
parse(ExecutionEngine * engine,const Value * argv,int argc,Type t)232 QQmlRefPointer<ExecutableCompilationUnit> FunctionCtor::parse(ExecutionEngine *engine, const Value *argv, int argc, Type t)
233 {
234     QString arguments;
235     QString body;
236     if (argc > 0) {
237         for (int i = 0, ei = argc - 1; i < ei; ++i) {
238             if (i)
239                 arguments += QLatin1String(", ");
240             arguments += argv[i].toQString();
241         }
242         body = argv[argc - 1].toQString();
243     }
244     if (engine->hasException)
245         return nullptr;
246 
247     QString function = (t == Type_Function ? QLatin1String("function anonymous(") : QLatin1String("function* anonymous(")) + arguments + QLatin1String("\n){") + body + QLatin1String("\n}");
248 
249     QQmlJS::Engine ee;
250     QQmlJS::Lexer lexer(&ee);
251     lexer.setCode(function, 1, false);
252     QQmlJS::Parser parser(&ee);
253 
254     const bool parsed = parser.parseExpression();
255 
256     if (!parsed) {
257         engine->throwSyntaxError(QLatin1String("Parse error"));
258         return nullptr;
259     }
260 
261     QQmlJS::AST::FunctionExpression *fe = QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression *>(parser.rootNode());
262     if (!fe) {
263         engine->throwSyntaxError(QLatin1String("Parse error"));
264         return nullptr;
265     }
266 
267     Compiler::Module module(engine->debugger() != nullptr);
268 
269     Compiler::JSUnitGenerator jsGenerator(&module);
270     RuntimeCodegen cg(engine, &jsGenerator, false);
271     cg.generateFromFunctionExpression(QString(), function, fe, &module);
272 
273     if (engine->hasException)
274         return nullptr;
275 
276     return ExecutableCompilationUnit::create(cg.generateCompilationUnit());
277 }
278 
virtualCallAsConstructor(const FunctionObject * f,const Value * argv,int argc,const Value * newTarget)279 ReturnedValue FunctionCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
280 {
281     ExecutionEngine *engine = f->engine();
282 
283     QQmlRefPointer<ExecutableCompilationUnit> compilationUnit
284             = parse(engine, argv, argc, Type_Function);
285     if (engine->hasException)
286         return Encode::undefined();
287 
288     Function *vmf = compilationUnit->linkToEngine(engine);
289     ExecutionContext *global = engine->scriptContext();
290     ReturnedValue o = Encode(FunctionObject::createScriptFunction(global, vmf));
291 
292     if (!newTarget)
293         return o;
294     Scope scope(engine);
295     ScopedObject obj(scope, o);
296     obj->setProtoFromNewTarget(newTarget);
297     return obj->asReturnedValue();
298 }
299 
300 // 15.3.1: This is equivalent to new Function(...)
virtualCall(const FunctionObject * f,const Value *,const Value * argv,int argc)301 ReturnedValue FunctionCtor::virtualCall(const FunctionObject *f, const Value *, const Value *argv, int argc)
302 {
303     return virtualCallAsConstructor(f, argv, argc, f);
304 }
305 
306 DEFINE_OBJECT_VTABLE(FunctionPrototype);
307 
init()308 void Heap::FunctionPrototype::init()
309 {
310     Heap::FunctionObject::init();
311 }
312 
init(ExecutionEngine * engine,Object * ctor)313 void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
314 {
315     Scope scope(engine);
316     ScopedObject o(scope);
317 
318     ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(1));
319     ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
320 
321     defineReadonlyConfigurableProperty(engine->id_name(), *engine->id_empty());
322     defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(0));
323     defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
324     defineDefaultProperty(engine->id_toString(), method_toString, 0);
325     defineDefaultProperty(QStringLiteral("apply"), method_apply, 2);
326     defineDefaultProperty(QStringLiteral("call"), method_call, 1);
327     defineDefaultProperty(QStringLiteral("bind"), method_bind, 1);
328     defineDefaultProperty(engine->symbol_hasInstance(), method_hasInstance, 1, Attr_ReadOnly);
329 }
330 
method_toString(const FunctionObject * b,const Value * thisObject,const Value *,int)331 ReturnedValue FunctionPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
332 {
333     ExecutionEngine *v4 = b->engine();
334     const FunctionObject *fun = thisObject->as<FunctionObject>();
335     if (!fun)
336         return v4->throwTypeError();
337 
338     const Scope scope(fun->engine());
339     const ScopedString scopedFunctionName(scope, fun->name());
340     const QString functionName(scopedFunctionName ? scopedFunctionName->toQString() : QString());
341     QString functionAsString = QStringLiteral("function");
342 
343     // If fun->name() is empty, then there is no function name
344     // to append because the function is anonymous.
345     if (!functionName.isEmpty())
346         functionAsString.append(QLatin1Char(' ') + functionName);
347 
348     functionAsString.append(QStringLiteral("() { [native code] }"));
349 
350     return Encode(v4->newString(functionAsString));
351 }
352 
method_apply(const QV4::FunctionObject * b,const Value * thisObject,const Value * argv,int argc)353 ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
354 {
355     ExecutionEngine *v4 = b->engine();
356     const FunctionObject *f = thisObject->as<FunctionObject>();
357     if (!f)
358         return v4->throwTypeError();
359     thisObject = argc ? argv : nullptr;
360     if (argc < 2 || argv[1].isNullOrUndefined())
361         return checkedResult(v4, f->call(thisObject, argv, 0));
362 
363     Object *arr = argv[1].objectValue();
364     if (!arr)
365         return v4->throwTypeError();
366 
367     const qint64 len64 = arr->getLength();
368     if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max()))
369         return v4->throwRangeError(QStringLiteral("Invalid array length."));
370     if (len64 > qint64(v4->jsStackLimit - v4->jsStackTop))
371         return v4->throwRangeError(QStringLiteral("Array too large for apply()."));
372 
373     const uint len = uint(len64);
374 
375     Scope scope(v4);
376     Value *arguments = scope.alloc<Scope::Uninitialized>(len);
377     if (len) {
378         if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
379             QV4::ArgumentsObject *a = arr->cast<ArgumentsObject>();
380             int l = qMin(len, (uint)a->d()->context->argc());
381             memcpy(arguments, a->d()->context->args(), l*sizeof(Value));
382             for (quint32 i = l; i < len; ++i)
383                 arguments[i] = Value::undefinedValue();
384         } else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) {
385             auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData());
386             uint alen = sad ? sad->values.size : 0;
387             if (alen > len)
388                 alen = len;
389             for (uint i = 0; i < alen; ++i)
390                 arguments[i] = sad->data(i);
391             for (quint32 i = alen; i < len; ++i)
392                 arguments[i] = Value::undefinedValue();
393         } else {
394             // need to init the arguments array, as the get() calls below can have side effects
395             memset(arguments, 0, len*sizeof(Value));
396             for (quint32 i = 0; i < len; ++i)
397                 arguments[i] = arr->get(i);
398         }
399     }
400 
401     return checkedResult(v4, f->call(thisObject, arguments, len));
402 }
403 
method_call(const QV4::FunctionObject * b,const Value * thisObject,const Value * argv,int argc)404 ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
405 {
406     QV4::ExecutionEngine *v4 = b->engine();
407     if (!thisObject->isFunctionObject())
408         return v4->throwTypeError();
409 
410     const FunctionObject *f = static_cast<const FunctionObject *>(thisObject);
411 
412     thisObject = argc ? argv : nullptr;
413     if (argc) {
414         ++argv;
415         --argc;
416     }
417     return checkedResult(v4, f->call(thisObject, argv, argc));
418 }
419 
method_bind(const FunctionObject * b,const Value * thisObject,const Value * argv,int argc)420 ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
421 {
422     QV4::Scope scope(b);
423     ScopedFunctionObject target(scope, thisObject);
424     if (!target || target->isBinding())
425         return scope.engine->throwTypeError();
426 
427     ScopedValue boundThis(scope, argc ? argv[0] : Value::undefinedValue());
428     Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)nullptr);
429 
430     int nArgs = (argc - 1 >= 0) ? argc - 1 : 0;
431     if (target->isBoundFunction()) {
432         BoundFunction *bound = static_cast<BoundFunction *>(target.getPointer());
433         Scoped<MemberData> oldArgs(scope, bound->boundArgs());
434         boundThis = bound->boundThis();
435         int oldSize = !oldArgs ? 0 : oldArgs->size();
436         if (oldSize + nArgs) {
437             boundArgs = MemberData::allocate(scope.engine, oldSize + nArgs);
438             boundArgs->d()->values.size = oldSize + nArgs;
439             for (uint i = 0; i < static_cast<uint>(oldSize); ++i)
440                 boundArgs->set(scope.engine, i, oldArgs->data()[i]);
441             for (uint i = 0; i < static_cast<uint>(nArgs); ++i)
442                 boundArgs->set(scope.engine, oldSize + i, argv[i + 1]);
443         }
444         target = bound->target();
445     } else if (nArgs) {
446         boundArgs = MemberData::allocate(scope.engine, nArgs);
447         boundArgs->d()->values.size = nArgs;
448         for (uint i = 0, ei = static_cast<uint>(nArgs); i < ei; ++i)
449             boundArgs->set(scope.engine, i, argv[i + 1]);
450     }
451 
452     ScopedContext ctx(scope, target->scope());
453     Heap::BoundFunction *bound = BoundFunction::create(ctx, target, boundThis, boundArgs);
454     bound->setFunction(target->function());
455     return bound->asReturnedValue();
456 }
457 
method_hasInstance(const FunctionObject *,const Value * thisObject,const Value * argv,int argc)458 ReturnedValue FunctionPrototype::method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
459 {
460     if (!argc)
461         return Encode(false);
462     const Object *o = thisObject->as<Object>();
463     if (!o)
464         return Encode(false);
465 
466     return Object::virtualInstanceOf(o, argv[0]);
467 }
468 
469 DEFINE_OBJECT_VTABLE(ScriptFunction);
470 
virtualCallAsConstructor(const FunctionObject * fo,const Value * argv,int argc,const Value * newTarget)471 ReturnedValue ScriptFunction::virtualCallAsConstructor(const FunctionObject *fo, const Value *argv, int argc, const Value *newTarget)
472 {
473     ExecutionEngine *v4 = fo->engine();
474     const ScriptFunction *f = static_cast<const ScriptFunction *>(fo);
475     Q_ASSERT(newTarget->isFunctionObject());
476     const FunctionObject *nt = static_cast<const FunctionObject *>(newTarget);
477 
478     Scope scope(v4);
479     Scoped<InternalClass> ic(scope);
480     if (nt->d() == f->d()) {
481         ic = f->classForConstructor();
482     } else {
483         ScopedObject o(scope, nt->protoProperty());
484         ic = scope.engine->internalClasses(EngineBase::Class_Object);
485         if (o)
486             ic = ic->changePrototype(o->d());
487     }
488     ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(ic));
489 
490     CppStackFrame frame;
491     frame.init(v4, f->function(), argv, argc);
492     frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
493                        thisObject,
494                        newTarget ? *newTarget : Value::undefinedValue());
495 
496     frame.push();
497     v4->jsStackTop += frame.requiredJSStackFrameSize();
498 
499     ReturnedValue result = Moth::VME::exec(&frame, v4);
500 
501     frame.pop();
502 
503     if (Q_UNLIKELY(v4->hasException))
504         return Encode::undefined();
505     else if (!Value::fromReturnedValue(result).isObject())
506         return thisObject->asReturnedValue();
507     return result;
508 }
509 
510 DEFINE_OBJECT_VTABLE(ArrowFunction);
511 
virtualCall(const FunctionObject * fo,const Value * thisObject,const Value * argv,int argc)512 ReturnedValue ArrowFunction::virtualCall(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc)
513 {
514     ExecutionEngine *engine = fo->engine();
515     CppStackFrame frame;
516     frame.init(engine, fo->function(), argv, argc, true);
517     frame.setupJSFrame(engine->jsStackTop, *fo, fo->scope(),
518                        thisObject ? *thisObject : Value::undefinedValue(),
519                        Value::undefinedValue());
520 
521     frame.push();
522     engine->jsStackTop += frame.requiredJSStackFrameSize();
523 
524     ReturnedValue result;
525 
526     do {
527         frame.pendingTailCall = false;
528         result = Moth::VME::exec(&frame, engine);
529         frame.isTailCalling = true;
530     } while (frame.pendingTailCall);
531 
532     frame.pop();
533 
534     return result;
535 }
536 
init(QV4::ExecutionContext * scope,Function * function,QV4::String * n)537 void Heap::ArrowFunction::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n)
538 {
539     FunctionObject::init();
540     this->scope.set(scope->engine(), scope->d());
541 
542     setFunction(function);
543     Q_ASSERT(function);
544 
545     Scope s(scope);
546     ScopedFunctionObject f(s, this);
547 
548     ScopedString name(s, n ? n->d() : function->name());
549     if (name)
550         f->setName(name);
551 
552     Q_ASSERT(internalClass && internalClass->verifyIndex(s.engine->id_length()->propertyKey(), Index_Length));
553     setProperty(s.engine, Index_Length, Value::fromInt32(int(function->compiledFunction->length)));
554     canBeTailCalled = true;
555 }
556 
init(QV4::ExecutionContext * scope,Function * function)557 void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function)
558 {
559     ArrowFunction::init(scope, function);
560     Q_ASSERT(!function->isArrowFunction());
561 
562     Scope s(scope);
563     ScopedFunctionObject f(s, this);
564     f->createDefaultPrototypeProperty(Heap::FunctionObject::Index_ProtoConstructor);
565 }
566 
classForConstructor() const567 Heap::InternalClass *ScriptFunction::classForConstructor() const
568 {
569     Scope scope(engine());
570     ScopedValue o(scope, protoProperty());
571     if (d()->cachedClassForConstructor && d()->cachedClassForConstructor->prototype == o->heapObject())
572         return d()->cachedClassForConstructor;
573 
574     Scoped<InternalClass> ic(scope, engine()->internalClasses(EngineBase::Class_Object));
575     ScopedObject p(scope, o);
576     if (p)
577         ic = ic->changePrototype(p->d());
578     d()->cachedClassForConstructor.set(scope.engine, ic->d());
579 
580     return ic->d();
581 }
582 
583 DEFINE_OBJECT_VTABLE(ConstructorFunction);
584 
virtualCallAsConstructor(const FunctionObject * f,const Value * argv,int argc,const Value * newTarget)585 ReturnedValue ConstructorFunction::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
586 {
587     const ConstructorFunction *c = static_cast<const ConstructorFunction *>(f);
588     if (!c->d()->isDerivedConstructor)
589         return ScriptFunction::virtualCallAsConstructor(f, argv, argc, newTarget);
590 
591     ExecutionEngine *v4 = f->engine();
592 
593     CppStackFrame frame;
594     frame.init(v4, f->function(), argv, argc);
595     frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
596                        Value::emptyValue(),
597                        newTarget ? *newTarget : Value::undefinedValue());
598 
599     frame.push();
600     v4->jsStackTop += frame.requiredJSStackFrameSize();
601 
602     ReturnedValue result = Moth::VME::exec(&frame, v4);
603     ReturnedValue thisObject = frame.jsFrame->thisObject.asReturnedValue();
604 
605     frame.pop();
606 
607     if (Q_UNLIKELY(v4->hasException))
608         return Encode::undefined();
609     else if (Value::fromReturnedValue(result).isObject())
610         return result;
611     else if (!Value::fromReturnedValue(result).isUndefined())
612         return v4->throwTypeError();
613     else if (Value::fromReturnedValue(thisObject).isEmpty()) {
614         Scope scope(v4);
615         ScopedString s(scope, v4->newString(QStringLiteral("this")));
616         return v4->throwReferenceError(s);
617     }
618     return thisObject;
619 }
620 
virtualCall(const FunctionObject * f,const Value *,const Value *,int)621 ReturnedValue ConstructorFunction::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
622 {
623     return f->engine()->throwTypeError(QStringLiteral("Cannot call a class constructor without |new|"));
624 }
625 
626 DEFINE_OBJECT_VTABLE(MemberFunction);
627 
628 DEFINE_OBJECT_VTABLE(DefaultClassConstructorFunction);
629 
virtualCallAsConstructor(const FunctionObject * f,const Value * argv,int argc,const Value * newTarget)630 ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
631 {
632     const DefaultClassConstructorFunction *c = static_cast<const DefaultClassConstructorFunction *>(f);
633     ExecutionEngine *v4 = f->engine();
634 
635     Scope scope(v4);
636 
637     if (!c->d()->isDerivedConstructor) {
638         ScopedObject proto(scope, static_cast<const Object *>(newTarget)->get(scope.engine->id_prototype()));
639         ScopedObject c(scope, scope.engine->newObject());
640         c->setPrototypeUnchecked(proto);
641         return c->asReturnedValue();
642     }
643 
644     ScopedFunctionObject super(scope, f->getPrototypeOf());
645     Q_ASSERT(super->isFunctionObject());
646 
647     CppStackFrame frame;
648     frame.init(v4, nullptr, argv, argc);
649     frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
650                        Value::undefinedValue(),
651                        newTarget ? *newTarget : Value::undefinedValue(), argc, argc);
652 
653     frame.push();
654     v4->jsStackTop += frame.requiredJSStackFrameSize(argc);
655 
656     // Do a super call
657     ReturnedValue result = super->callAsConstructor(argv, argc, newTarget);
658     ReturnedValue thisObject = frame.jsFrame->thisObject.asReturnedValue();
659 
660     frame.pop();
661 
662     if (Q_UNLIKELY(v4->hasException))
663         return Encode::undefined();
664     else if (Value::fromReturnedValue(result).isObject())
665         return result;
666     else if (!Value::fromReturnedValue(result).isUndefined())
667         return v4->throwTypeError();
668     else if (Value::fromReturnedValue(thisObject).isEmpty()) {
669         Scope scope(v4);
670         ScopedString s(scope, v4->newString(QStringLiteral("this")));
671         return v4->throwReferenceError(s);
672     }
673 
674     return thisObject;
675 }
676 
virtualCall(const FunctionObject * f,const Value *,const Value *,int)677 ReturnedValue DefaultClassConstructorFunction::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
678 {
679     return f->engine()->throwTypeError(QStringLiteral("Cannot call a class constructor without |new|"));
680 }
681 
682 DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
683 
684 DEFINE_OBJECT_VTABLE(BoundFunction);
685 
init(QV4::ExecutionContext * scope,QV4::FunctionObject * target,const Value & boundThis,QV4::MemberData * boundArgs)686 void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject *target,
687                                const Value &boundThis, QV4::MemberData *boundArgs)
688 {
689     Scope s(scope);
690     Heap::FunctionObject::init(scope, QStringLiteral("__bound function__"));
691     this->target.set(s.engine, target->d());
692     this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : nullptr);
693     this->boundThis.set(scope->engine(), boundThis);
694 
695     if (!target->isConstructor())
696         jsConstruct = nullptr;
697 
698     ScopedObject f(s, this);
699 
700     ScopedValue l(s, target->get(s.engine->id_length()));
701     int len = l->toUInt32();
702     if (boundArgs)
703         len -= boundArgs->size();
704     if (len < 0)
705         len = 0;
706     f->defineReadonlyConfigurableProperty(s.engine->id_length(), Value::fromInt32(len));
707 
708     ScopedProperty pd(s);
709     pd->value = s.engine->thrower();
710     pd->set = s.engine->thrower();
711     f->insertMember(s.engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
712     f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
713 }
714 
virtualCall(const FunctionObject * fo,const Value *,const Value * argv,int argc)715 ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *, const Value *argv, int argc)
716 {
717     QV4::ExecutionEngine *v4 = fo->engine();
718     if (v4->hasException)
719         return Encode::undefined();
720 
721     const BoundFunction *f = static_cast<const BoundFunction *>(fo);
722     Scope scope(v4);
723     Scoped<MemberData> boundArgs(scope, f->boundArgs());
724     ScopedFunctionObject target(scope, f->target());
725     JSCallData jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc);
726     *jsCallData->thisObject = f->boundThis();
727     Value *argp = jsCallData->args;
728     if (boundArgs) {
729         memcpy(argp, boundArgs->data(), boundArgs->size()*sizeof(Value));
730         argp += boundArgs->size();
731     }
732     memcpy(argp, argv, argc*sizeof(Value));
733     return checkedResult(v4, target->call(jsCallData));
734 }
735 
virtualCallAsConstructor(const FunctionObject * fo,const Value * argv,int argc,const Value *)736 ReturnedValue BoundFunction::virtualCallAsConstructor(const FunctionObject *fo, const Value *argv, int argc, const Value *)
737 {
738     const BoundFunction *f = static_cast<const BoundFunction *>(fo);
739     Scope scope(f->engine());
740 
741     if (scope.hasException())
742         return Encode::undefined();
743 
744     Scoped<MemberData> boundArgs(scope, f->boundArgs());
745     ScopedFunctionObject target(scope, f->target());
746     JSCallData jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc);
747     Value *argp = jsCallData->args;
748     if (boundArgs) {
749         memcpy(argp, boundArgs->data(), boundArgs->size()*sizeof(Value));
750         argp += boundArgs->size();
751     }
752     memcpy(argp, argv, argc*sizeof(Value));
753     return target->callAsConstructor(jsCallData);
754 }
755