/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qv4object_p.h" #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" #include "qv4function_p.h" #include "qv4symbol_p.h" #include #include "qv4arrayobject_p.h" #include "qv4scopedvalue_p.h" #include "qv4argumentsobject_p.h" #include #include #include #include #include #include #include #include "private/qlocale_tools_p.h" #include "private/qqmlbuiltinfunctions_p.h" #include #include #include #include #include #include "qv4profiling_p.h" using namespace QV4; DEFINE_OBJECT_VTABLE(FunctionObject); void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, VTable::Call call) { jsCall = call; jsConstruct = nullptr; Object::init(); this->scope.set(scope->engine(), scope->d()); Scope s(scope->engine()); ScopedFunctionObject f(s, this); if (name) f->setName(name); } void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name) { ExecutionEngine *e = scope->engine(); jsCall = vtable()->call; jsConstruct = vtable()->callAsConstructor; Object::init(); this->scope.set(scope->engine(), scope->d()); Scope s(e); ScopedFunctionObject f(s, this); if (name) f->setName(name); } void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n) { jsCall = vtable()->call; jsConstruct = vtable()->callAsConstructor; Object::init(); setFunction(function); this->scope.set(scope->engine(), scope->d()); Scope s(scope->engine()); ScopedString name(s, n ? n->d() : function->name()); ScopedFunctionObject f(s, this); if (name) f->setName(name); } void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const QString &name) { Scope valueScope(scope); ScopedString s(valueScope, valueScope.engine->newString(name)); init(scope, s); } void Heap::FunctionObject::init() { jsCall = vtable()->call; jsConstruct = vtable()->callAsConstructor; Object::init(); this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d()); } void Heap::FunctionObject::setFunction(Function *f) { if (f) { function = f; function->executableCompilationUnit()->addref(); } } void Heap::FunctionObject::destroy() { if (function) function->executableCompilationUnit()->release(); Object::destroy(); } void FunctionObject::createDefaultPrototypeProperty(uint protoConstructorSlot) { Scope s(this); Q_ASSERT(s.engine->internalClasses(EngineBase::Class_ObjectProto)->verifyIndex(s.engine->id_constructor()->propertyKey(), protoConstructorSlot)); ScopedObject proto(s, s.engine->newObject(s.engine->internalClasses(EngineBase::Class_ObjectProto))); proto->setProperty(protoConstructorSlot, d()); defineDefaultProperty(s.engine->id_prototype(), proto, Attr_NotEnumerable|Attr_NotConfigurable); } ReturnedValue FunctionObject::name() const { return get(scope()->internalClass->engine->id_name()); } ReturnedValue FunctionObject::virtualCall(const FunctionObject *, const Value *, const Value *, int) { return Encode::undefined(); } Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function) { if (function->isArrowFunction()) return scope->engine()->memoryManager->allocate(scope, function); return scope->engine()->memoryManager->allocate(scope, function); } Heap::FunctionObject *FunctionObject::createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor) { if (!function) { Heap::DefaultClassConstructorFunction *c = scope->engine()->memoryManager->allocate(scope); c->isDerivedConstructor = isDerivedConstructor; return c; } Heap::ConstructorFunction *c = scope->engine()->memoryManager->allocate(scope, function); c->homeObject.set(scope->engine(), homeObject->d()); c->isDerivedConstructor = isDerivedConstructor; return c; } Heap::FunctionObject *FunctionObject::createMemberFunction(ExecutionContext *scope, Function *function, Object *homeObject, QV4::String *name) { Heap::MemberFunction *m = scope->engine()->memoryManager->allocate(scope, function, name); m->homeObject.set(scope->engine(), homeObject->d()); return m; } Heap::FunctionObject *FunctionObject::createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount) { Scope scope(engine); ScopedString name(scope, nameOrSymbol); if (!name) name = engine->newString(QChar::fromLatin1('[') + QStringView{nameOrSymbol->toQString()}.mid(1) + QChar::fromLatin1(']')); ScopedFunctionObject function(scope, engine->memoryManager->allocate(engine->rootContext(), name, code)); function->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(argumentCount)); return function->d(); } ReturnedValue FunctionObject::getHomeObject() const { const MemberFunction *m = as(); if (m) return m->d()->homeObject->asReturnedValue(); const ConstructorFunction *c = as(); if (c) return c->d()->homeObject->asReturnedValue(); return Encode::undefined(); } QQmlSourceLocation FunctionObject::sourceLocation() const { return d()->function->sourceLocation(); } DEFINE_OBJECT_VTABLE(FunctionCtor); void Heap::FunctionCtor::init(QV4::ExecutionContext *scope) { Heap::FunctionObject::init(scope, QStringLiteral("Function")); } // 15.3.2 QQmlRefPointer FunctionCtor::parse(ExecutionEngine *engine, const Value *argv, int argc, Type t) { QString arguments; QString body; if (argc > 0) { for (int i = 0, ei = argc - 1; i < ei; ++i) { if (i) arguments += QLatin1String(", "); arguments += argv[i].toQString(); } body = argv[argc - 1].toQString(); } if (engine->hasException) return nullptr; QString function = (t == Type_Function ? QLatin1String("function anonymous(") : QLatin1String("function* anonymous(")) + arguments + QLatin1String("\n){") + body + QLatin1String("\n}"); QQmlJS::Engine ee; QQmlJS::Lexer lexer(&ee); lexer.setCode(function, 1, false); QQmlJS::Parser parser(&ee); const bool parsed = parser.parseExpression(); if (!parsed) { engine->throwSyntaxError(QLatin1String("Parse error")); return nullptr; } QQmlJS::AST::FunctionExpression *fe = QQmlJS::AST::cast(parser.rootNode()); if (!fe) { engine->throwSyntaxError(QLatin1String("Parse error")); return nullptr; } Compiler::Module module(engine->debugger() != nullptr); Compiler::JSUnitGenerator jsGenerator(&module); RuntimeCodegen cg(engine, &jsGenerator, false); cg.generateFromFunctionExpression(QString(), function, fe, &module); if (engine->hasException) return nullptr; return ExecutableCompilationUnit::create(cg.generateCompilationUnit()); } ReturnedValue FunctionCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { ExecutionEngine *engine = f->engine(); QQmlRefPointer compilationUnit = parse(engine, argv, argc, Type_Function); if (engine->hasException) return Encode::undefined(); Function *vmf = compilationUnit->linkToEngine(engine); ExecutionContext *global = engine->scriptContext(); ReturnedValue o = Encode(FunctionObject::createScriptFunction(global, vmf)); if (!newTarget) return o; Scope scope(engine); ScopedObject obj(scope, o); obj->setProtoFromNewTarget(newTarget); return obj->asReturnedValue(); } // 15.3.1: This is equivalent to new Function(...) ReturnedValue FunctionCtor::virtualCall(const FunctionObject *f, const Value *, const Value *argv, int argc) { return virtualCallAsConstructor(f, argv, argc, f); } DEFINE_OBJECT_VTABLE(FunctionPrototype); void Heap::FunctionPrototype::init() { Heap::FunctionObject::init(); } void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(1)); ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); defineReadonlyConfigurableProperty(engine->id_name(), *engine->id_empty()); defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(0)); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("apply"), method_apply, 2); defineDefaultProperty(QStringLiteral("call"), method_call, 1); defineDefaultProperty(QStringLiteral("bind"), method_bind, 1); defineDefaultProperty(engine->symbol_hasInstance(), method_hasInstance, 1, Attr_ReadOnly); } ReturnedValue FunctionPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int) { ExecutionEngine *v4 = b->engine(); const FunctionObject *fun = thisObject->as(); if (!fun) return v4->throwTypeError(); const Scope scope(fun->engine()); const ScopedString scopedFunctionName(scope, fun->name()); const QString functionName(scopedFunctionName ? scopedFunctionName->toQString() : QString()); QString functionAsString = QStringLiteral("function"); // If fun->name() is empty, then there is no function name // to append because the function is anonymous. if (!functionName.isEmpty()) functionAsString.append(QLatin1Char(' ') + functionName); functionAsString.append(QStringLiteral("() { [native code] }")); return Encode(v4->newString(functionAsString)); } ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { ExecutionEngine *v4 = b->engine(); const FunctionObject *f = thisObject->as(); if (!f) return v4->throwTypeError(); thisObject = argc ? argv : nullptr; if (argc < 2 || argv[1].isNullOrUndefined()) return checkedResult(v4, f->call(thisObject, argv, 0)); Object *arr = argv[1].objectValue(); if (!arr) return v4->throwTypeError(); const qint64 len64 = arr->getLength(); if (len64 < 0ll || len64 > qint64(std::numeric_limits::max())) return v4->throwRangeError(QStringLiteral("Invalid array length.")); if (len64 > qint64(v4->jsStackLimit - v4->jsStackTop)) return v4->throwRangeError(QStringLiteral("Array too large for apply().")); const uint len = uint(len64); Scope scope(v4); Value *arguments = scope.alloc(len); if (len) { if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast()->fullyCreated()) { QV4::ArgumentsObject *a = arr->cast(); int l = qMin(len, (uint)a->d()->context->argc()); memcpy(arguments, a->d()->context->args(), l*sizeof(Value)); for (quint32 i = l; i < len; ++i) arguments[i] = Value::undefinedValue(); } else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) { auto sad = static_cast(arr->arrayData()); uint alen = sad ? sad->values.size : 0; if (alen > len) alen = len; for (uint i = 0; i < alen; ++i) arguments[i] = sad->data(i); for (quint32 i = alen; i < len; ++i) arguments[i] = Value::undefinedValue(); } else { // need to init the arguments array, as the get() calls below can have side effects memset(arguments, 0, len*sizeof(Value)); for (quint32 i = 0; i < len; ++i) arguments[i] = arr->get(i); } } return checkedResult(v4, f->call(thisObject, arguments, len)); } ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { QV4::ExecutionEngine *v4 = b->engine(); if (!thisObject->isFunctionObject()) return v4->throwTypeError(); const FunctionObject *f = static_cast(thisObject); thisObject = argc ? argv : nullptr; if (argc) { ++argv; --argc; } return checkedResult(v4, f->call(thisObject, argv, argc)); } ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { QV4::Scope scope(b); ScopedFunctionObject target(scope, thisObject); if (!target || target->isBinding()) return scope.engine->throwTypeError(); ScopedValue boundThis(scope, argc ? argv[0] : Value::undefinedValue()); Scoped boundArgs(scope, (Heap::MemberData *)nullptr); int nArgs = (argc - 1 >= 0) ? argc - 1 : 0; if (target->isBoundFunction()) { BoundFunction *bound = static_cast(target.getPointer()); Scoped oldArgs(scope, bound->boundArgs()); boundThis = bound->boundThis(); int oldSize = !oldArgs ? 0 : oldArgs->size(); if (oldSize + nArgs) { boundArgs = MemberData::allocate(scope.engine, oldSize + nArgs); boundArgs->d()->values.size = oldSize + nArgs; for (uint i = 0; i < static_cast(oldSize); ++i) boundArgs->set(scope.engine, i, oldArgs->data()[i]); for (uint i = 0; i < static_cast(nArgs); ++i) boundArgs->set(scope.engine, oldSize + i, argv[i + 1]); } target = bound->target(); } else if (nArgs) { boundArgs = MemberData::allocate(scope.engine, nArgs); boundArgs->d()->values.size = nArgs; for (uint i = 0, ei = static_cast(nArgs); i < ei; ++i) boundArgs->set(scope.engine, i, argv[i + 1]); } ScopedContext ctx(scope, target->scope()); Heap::BoundFunction *bound = BoundFunction::create(ctx, target, boundThis, boundArgs); bound->setFunction(target->function()); return bound->asReturnedValue(); } ReturnedValue FunctionPrototype::method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc) { if (!argc) return Encode(false); const Object *o = thisObject->as(); if (!o) return Encode(false); return Object::virtualInstanceOf(o, argv[0]); } DEFINE_OBJECT_VTABLE(ScriptFunction); ReturnedValue ScriptFunction::virtualCallAsConstructor(const FunctionObject *fo, const Value *argv, int argc, const Value *newTarget) { ExecutionEngine *v4 = fo->engine(); const ScriptFunction *f = static_cast(fo); Q_ASSERT(newTarget->isFunctionObject()); const FunctionObject *nt = static_cast(newTarget); Scope scope(v4); Scoped ic(scope); if (nt->d() == f->d()) { ic = f->classForConstructor(); } else { ScopedObject o(scope, nt->protoProperty()); ic = scope.engine->internalClasses(EngineBase::Class_Object); if (o) ic = ic->changePrototype(o->d()); } ScopedValue thisObject(scope, v4->memoryManager->allocObject(ic)); CppStackFrame frame; frame.init(v4, f->function(), argv, argc); frame.setupJSFrame(v4->jsStackTop, *f, f->scope(), thisObject, newTarget ? *newTarget : Value::undefinedValue()); frame.push(); v4->jsStackTop += frame.requiredJSStackFrameSize(); ReturnedValue result = Moth::VME::exec(&frame, v4); frame.pop(); if (Q_UNLIKELY(v4->hasException)) return Encode::undefined(); else if (!Value::fromReturnedValue(result).isObject()) return thisObject->asReturnedValue(); return result; } DEFINE_OBJECT_VTABLE(ArrowFunction); ReturnedValue ArrowFunction::virtualCall(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc) { ExecutionEngine *engine = fo->engine(); CppStackFrame frame; frame.init(engine, fo->function(), argv, argc, true); frame.setupJSFrame(engine->jsStackTop, *fo, fo->scope(), thisObject ? *thisObject : Value::undefinedValue(), Value::undefinedValue()); frame.push(); engine->jsStackTop += frame.requiredJSStackFrameSize(); ReturnedValue result; do { frame.pendingTailCall = false; result = Moth::VME::exec(&frame, engine); frame.isTailCalling = true; } while (frame.pendingTailCall); frame.pop(); return result; } void Heap::ArrowFunction::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n) { FunctionObject::init(); this->scope.set(scope->engine(), scope->d()); setFunction(function); Q_ASSERT(function); Scope s(scope); ScopedFunctionObject f(s, this); ScopedString name(s, n ? n->d() : function->name()); if (name) f->setName(name); Q_ASSERT(internalClass && internalClass->verifyIndex(s.engine->id_length()->propertyKey(), Index_Length)); setProperty(s.engine, Index_Length, Value::fromInt32(int(function->compiledFunction->length))); canBeTailCalled = true; } void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function) { ArrowFunction::init(scope, function); Q_ASSERT(!function->isArrowFunction()); Scope s(scope); ScopedFunctionObject f(s, this); f->createDefaultPrototypeProperty(Heap::FunctionObject::Index_ProtoConstructor); } Heap::InternalClass *ScriptFunction::classForConstructor() const { Scope scope(engine()); ScopedValue o(scope, protoProperty()); if (d()->cachedClassForConstructor && d()->cachedClassForConstructor->prototype == o->heapObject()) return d()->cachedClassForConstructor; Scoped ic(scope, engine()->internalClasses(EngineBase::Class_Object)); ScopedObject p(scope, o); if (p) ic = ic->changePrototype(p->d()); d()->cachedClassForConstructor.set(scope.engine, ic->d()); return ic->d(); } DEFINE_OBJECT_VTABLE(ConstructorFunction); ReturnedValue ConstructorFunction::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { const ConstructorFunction *c = static_cast(f); if (!c->d()->isDerivedConstructor) return ScriptFunction::virtualCallAsConstructor(f, argv, argc, newTarget); ExecutionEngine *v4 = f->engine(); CppStackFrame frame; frame.init(v4, f->function(), argv, argc); frame.setupJSFrame(v4->jsStackTop, *f, f->scope(), Value::emptyValue(), newTarget ? *newTarget : Value::undefinedValue()); frame.push(); v4->jsStackTop += frame.requiredJSStackFrameSize(); ReturnedValue result = Moth::VME::exec(&frame, v4); ReturnedValue thisObject = frame.jsFrame->thisObject.asReturnedValue(); frame.pop(); if (Q_UNLIKELY(v4->hasException)) return Encode::undefined(); else if (Value::fromReturnedValue(result).isObject()) return result; else if (!Value::fromReturnedValue(result).isUndefined()) return v4->throwTypeError(); else if (Value::fromReturnedValue(thisObject).isEmpty()) { Scope scope(v4); ScopedString s(scope, v4->newString(QStringLiteral("this"))); return v4->throwReferenceError(s); } return thisObject; } ReturnedValue ConstructorFunction::virtualCall(const FunctionObject *f, const Value *, const Value *, int) { return f->engine()->throwTypeError(QStringLiteral("Cannot call a class constructor without |new|")); } DEFINE_OBJECT_VTABLE(MemberFunction); DEFINE_OBJECT_VTABLE(DefaultClassConstructorFunction); ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { const DefaultClassConstructorFunction *c = static_cast(f); ExecutionEngine *v4 = f->engine(); Scope scope(v4); if (!c->d()->isDerivedConstructor) { ScopedObject proto(scope, static_cast(newTarget)->get(scope.engine->id_prototype())); ScopedObject c(scope, scope.engine->newObject()); c->setPrototypeUnchecked(proto); return c->asReturnedValue(); } ScopedFunctionObject super(scope, f->getPrototypeOf()); Q_ASSERT(super->isFunctionObject()); CppStackFrame frame; frame.init(v4, nullptr, argv, argc); frame.setupJSFrame(v4->jsStackTop, *f, f->scope(), Value::undefinedValue(), newTarget ? *newTarget : Value::undefinedValue(), argc, argc); frame.push(); v4->jsStackTop += frame.requiredJSStackFrameSize(argc); // Do a super call ReturnedValue result = super->callAsConstructor(argv, argc, newTarget); ReturnedValue thisObject = frame.jsFrame->thisObject.asReturnedValue(); frame.pop(); if (Q_UNLIKELY(v4->hasException)) return Encode::undefined(); else if (Value::fromReturnedValue(result).isObject()) return result; else if (!Value::fromReturnedValue(result).isUndefined()) return v4->throwTypeError(); else if (Value::fromReturnedValue(thisObject).isEmpty()) { Scope scope(v4); ScopedString s(scope, v4->newString(QStringLiteral("this"))); return v4->throwReferenceError(s); } return thisObject; } ReturnedValue DefaultClassConstructorFunction::virtualCall(const FunctionObject *f, const Value *, const Value *, int) { return f->engine()->throwTypeError(QStringLiteral("Cannot call a class constructor without |new|")); } DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction); DEFINE_OBJECT_VTABLE(BoundFunction); void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs) { Scope s(scope); Heap::FunctionObject::init(scope, QStringLiteral("__bound function__")); this->target.set(s.engine, target->d()); this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : nullptr); this->boundThis.set(scope->engine(), boundThis); if (!target->isConstructor()) jsConstruct = nullptr; ScopedObject f(s, this); ScopedValue l(s, target->get(s.engine->id_length())); int len = l->toUInt32(); if (boundArgs) len -= boundArgs->size(); if (len < 0) len = 0; f->defineReadonlyConfigurableProperty(s.engine->id_length(), Value::fromInt32(len)); ScopedProperty pd(s); pd->value = s.engine->thrower(); pd->set = s.engine->thrower(); f->insertMember(s.engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); } ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *, const Value *argv, int argc) { QV4::ExecutionEngine *v4 = fo->engine(); if (v4->hasException) return Encode::undefined(); const BoundFunction *f = static_cast(fo); Scope scope(v4); Scoped boundArgs(scope, f->boundArgs()); ScopedFunctionObject target(scope, f->target()); JSCallData jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc); *jsCallData->thisObject = f->boundThis(); Value *argp = jsCallData->args; if (boundArgs) { memcpy(argp, boundArgs->data(), boundArgs->size()*sizeof(Value)); argp += boundArgs->size(); } memcpy(argp, argv, argc*sizeof(Value)); return checkedResult(v4, target->call(jsCallData)); } ReturnedValue BoundFunction::virtualCallAsConstructor(const FunctionObject *fo, const Value *argv, int argc, const Value *) { const BoundFunction *f = static_cast(fo); Scope scope(f->engine()); if (scope.hasException()) return Encode::undefined(); Scoped boundArgs(scope, f->boundArgs()); ScopedFunctionObject target(scope, f->target()); JSCallData jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc); Value *argp = jsCallData->args; if (boundArgs) { memcpy(argp, boundArgs->data(), boundArgs->size()*sizeof(Value)); argp += boundArgs->size(); } memcpy(argp, argv, argc*sizeof(Value)); return target->callAsConstructor(jsCallData); }