aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-06-30 19:19:18 +0200
committerLars Knoll <lars.knoll@qt.io>2018-07-03 08:09:05 +0000
commit6d8dbba4624c8a453ba13ff009f011f2946422bb (patch)
treeec1aec45c122a31d7e5c1c19daa9ba5d4f824355
parentdeaa99f66ddedc2ea79e6902c665925b04665e68 (diff)
Add support for super calls
Implement super call support for class constructor functions. Change-Id: I3c64276234689cf4f644b095e0fc8ca1c634ac53 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/compiler/qv4bytecodehandler.cpp3
-rw-r--r--src/qml/compiler/qv4codegen.cpp97
-rw-r--r--src/qml/compiler/qv4codegen_p.h6
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp3
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h2
-rw-r--r--src/qml/jit/qv4baselinejit.cpp9
-rw-r--r--src/qml/jit/qv4baselinejit_p.h1
-rw-r--r--src/qml/jit/qv4jithelpers.cpp9
-rw-r--r--src/qml/jit/qv4jithelpers_p.h1
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp97
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h5
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp6
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp11
-rw-r--r--src/qml/jsruntime/qv4stackframe_p.h16
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp10
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations69
16 files changed, 225 insertions, 120 deletions
diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp
index 3e683cc8bf..b96c04dc01 100644
--- a/src/qml/compiler/qv4bytecodehandler.cpp
+++ b/src/qml/compiler/qv4bytecodehandler.cpp
@@ -364,6 +364,9 @@ std::vector<int> ByteCodeHandler::collectLabelsInBytecode(const char *code, uint
COLLECTOR_BEGIN_INSTR(ConvertThisToObject)
COLLECTOR_END_INSTR(ConvertThisToObject)
+ COLLECTOR_BEGIN_INSTR(LoadSuperConstructor)
+ COLLECTOR_END_INSTR(LoadSuperConstructor)
+
COLLECTOR_BEGIN_INSTR(ToObject)
COLLECTOR_END_INSTR(ToObject)
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 40aac8f7bb..36f959b301 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1108,6 +1108,8 @@ bool Codegen::visit(ArrayMemberExpression *ast)
if (hasError)
return false;
base = base.storeOnStack();
+ if (hasError)
+ return false;
if (AST::StringLiteral *str = AST::cast<AST::StringLiteral *>(ast->expression)) {
QString s = str->value.toString();
uint arrayIndex = QV4::String::toArrayIndex(s);
@@ -1736,6 +1738,9 @@ bool Codegen::visit(CallExpression *ast)
break;
case Reference::Name:
break;
+ case Reference::Super:
+ handleConstruct(base, ast->arguments);
+ return false;
default:
base = base.storeOnStack();
break;
@@ -2015,12 +2020,12 @@ bool Codegen::visit(FalseLiteral *)
return false;
}
-bool Codegen::visit(SuperLiteral *ast)
+bool Codegen::visit(SuperLiteral *)
{
if (hasError)
return false;
- throwSyntaxError(ast->superToken, QLatin1String("Support for 'super' keyword not implemented"));
+ _expr.setResult(Reference::fromSuper(this));
return false;
}
@@ -2207,6 +2212,43 @@ bool Codegen::visit(NestedExpression *ast)
return false;
}
+void Codegen::handleConstruct(const Reference &base, ArgumentList *arguments)
+{
+ Reference constructor;
+ if (base.isSuper()) {
+ Instruction::LoadSuperConstructor super;
+ bytecodeGenerator->addInstruction(super);
+ constructor = Reference::fromAccumulator(this).storeOnStack();
+ } else {
+ constructor = base.storeOnStack();
+ }
+
+ auto calldata = pushArgs(arguments);
+ if (hasError)
+ return;
+
+ if (base.isSuper()) {
+ Reference::fromStackSlot(this, CallData::Function).loadInAccumulator();
+ } else {
+ constructor.loadInAccumulator();
+ }
+
+ if (calldata.hasSpread) {
+ Instruction::ConstructWithSpread create;
+ create.func = constructor.stackSlot();
+ create.argc = calldata.argc;
+ create.argv = calldata.argv;
+ bytecodeGenerator->addInstruction(create);
+ } else {
+ Instruction::Construct create;
+ create.func = constructor.stackSlot();
+ create.argc = calldata.argc;
+ create.argv = calldata.argv;
+ bytecodeGenerator->addInstruction(create);
+ }
+ _expr.setResult(Reference::fromAccumulator(this));
+}
+
bool Codegen::visit(NewExpression *ast)
{
if (hasError)
@@ -2217,16 +2259,12 @@ bool Codegen::visit(NewExpression *ast)
Reference base = expression(ast->expression);
if (hasError)
return false;
+ if (base.isSuper()) {
+ throwSyntaxError(ast->expression->firstSourceLocation(), QStringLiteral("Cannot use new with super."));
+ return false;
+ }
- base = base.storeOnStack();
- base.loadInAccumulator();
-
- Instruction::Construct create;
- create.func = base.stackSlot();
- create.argc = 0;
- create.argv = 0;
- bytecodeGenerator->addInstruction(create);
- _expr.setResult(Reference::fromAccumulator(this));
+ handleConstruct(base, nullptr);
return false;
}
@@ -2240,28 +2278,12 @@ bool Codegen::visit(NewMemberExpression *ast)
Reference base = expression(ast->base);
if (hasError)
return false;
- base = base.storeOnStack();
-
- auto calldata = pushArgs(ast->arguments);
- if (hasError)
+ if (base.isSuper()) {
+ throwSyntaxError(ast->base->firstSourceLocation(), QStringLiteral("Cannot use new with super."));
return false;
-
- base.loadInAccumulator();
-
- if (calldata.hasSpread) {
- Instruction::ConstructWithSpread create;
- create.func = base.stackSlot();
- create.argc = calldata.argc;
- create.argv = calldata.argv;
- bytecodeGenerator->addInstruction(create);
- } else {
- Instruction::Construct create;
- create.func = base.stackSlot();
- create.argc = calldata.argc;
- create.argv = calldata.argv;
- bytecodeGenerator->addInstruction(create);
}
- _expr.setResult(Reference::fromAccumulator(this));
+
+ handleConstruct(base, ast->arguments);
return false;
}
@@ -3684,6 +3706,8 @@ Codegen::Reference &Codegen::Reference::operator =(const Reference &other)
case Invalid:
case Accumulator:
break;
+ case Super:
+ break;
case StackSlot:
theStackSlot = other.theStackSlot;
break;
@@ -3733,6 +3757,8 @@ bool Codegen::Reference::operator==(const Codegen::Reference &other) const
case Invalid:
case Accumulator:
break;
+ case Super:
+ return true;
case StackSlot:
return theStackSlot == other.theStackSlot;
case ScopedLocal:
@@ -3776,6 +3802,9 @@ Codegen::Reference Codegen::Reference::asLValue() const
case Invalid:
case Accumulator:
Q_UNREACHABLE();
+ case Super:
+ codegen->throwSyntaxError(AST::SourceLocation(), QStringLiteral("Super lvalues not implemented."));
+ return *this;
case Member:
if (!propertyBase.isStackSlot()) {
Reference r = *this;
@@ -3909,6 +3938,9 @@ void Codegen::Reference::storeAccumulator() const
return;
}
switch (type) {
+ case Super:
+ codegen->throwSyntaxError(SourceLocation(), QStringLiteral("storing super properties not implemented."));
+ return;
case StackSlot: {
Instruction::StoreReg store;
store.reg = theStackSlot;
@@ -3986,6 +4018,9 @@ void Codegen::Reference::loadInAccumulator() const
switch (type) {
case Accumulator:
return;
+ case Super:
+ codegen->throwSyntaxError(AST::SourceLocation(), QStringLiteral("Super property access not implemented."));
+ return;
case Const: {
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // the loads below are empty structs.
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index cac8da4e71..814754aea2 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -179,6 +179,7 @@ public:
enum Type {
Invalid,
Accumulator,
+ Super,
StackSlot,
ScopedLocal,
Name,
@@ -215,6 +216,7 @@ public:
}
bool isConstant() const { return type == Const; }
bool isAccumulator() const { return type == Accumulator; }
+ bool isSuper() const { return type == Super; }
bool isStackSlot() const { return type == StackSlot; }
bool isRegister() const {
return isStackSlot();
@@ -245,6 +247,9 @@ public:
static Reference fromAccumulator(Codegen *cg) {
return Reference(cg, Accumulator);
}
+ static Reference fromSuper(Codegen *cg) {
+ return Reference(cg, Super);
+ }
static Reference fromStackSlot(Codegen *cg, int tempIndex = -1, bool isLocal = false) {
Reference r(cg, StackSlot);
if (tempIndex == -1)
@@ -704,6 +709,7 @@ protected:
private:
VolatileMemoryLocations scanVolatileMemoryLocations(AST::Node *ast) const;
+ void handleConstruct(const Reference &base, AST::ArgumentList *args);
};
}
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 2d2f7bc27f..2ce06c9552 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -504,6 +504,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(ConvertThisToObject)
MOTH_END_INSTR(ConvertThisToObject)
+ MOTH_BEGIN_INSTR(LoadSuperConstructor)
+ MOTH_END_INSTR(LoadSuperConstructor)
+
MOTH_BEGIN_INSTR(ToObject)
MOTH_END_INSTR(ToObject)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 3bd60288c3..00ed76e6c2 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -142,6 +142,7 @@ QT_BEGIN_NAMESPACE
#define INSTR_CreateUnmappedArgumentsObject(op) INSTRUCTION(op, CreateUnmappedArgumentsObject, 0)
#define INSTR_CreateRestParameter(op) INSTRUCTION(op, CreateRestParameter, 1, argIndex)
#define INSTR_ConvertThisToObject(op) INSTRUCTION(op, ConvertThisToObject, 0)
+#define INSTR_LoadSuperConstructor(op) INSTRUCTION(op, LoadSuperConstructor, 0)
#define INSTR_ToObject(op) INSTRUCTION(op, ToObject, 0)
#define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, offset)
#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 1, offset)
@@ -271,6 +272,7 @@ QT_BEGIN_NAMESPACE
F(CreateUnmappedArgumentsObject) \
F(CreateRestParameter) \
F(ConvertThisToObject) \
+ F(LoadSuperConstructor) \
F(ToObject) \
F(Jump) \
F(JumpTrue) \
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index 23df04f127..b52350a729 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -787,6 +787,15 @@ void BaselineJIT::generate_ConvertThisToObject()
as->checkException();
}
+void BaselineJIT::generate_LoadSuperConstructor()
+{
+ as->prepareCallWithArgCount(2);
+ as->passRegAsArg(CallData::Function, 1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Helpers::loadSuperConstructor, Assembler::ResultInAccumulator);
+ as->checkException();
+}
+
void BaselineJIT::generate_ToObject()
{
STORE_ACC();
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index 9fa4aa2cda..26da3d5da3 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -159,6 +159,7 @@ public:
void generate_CreateUnmappedArgumentsObject() override;
void generate_CreateRestParameter(int argIndex) override;
void generate_ConvertThisToObject() override;
+ void generate_LoadSuperConstructor() override;
void generate_ToObject() override;
void generate_Jump(int offset) override;
void generate_JumpTrue(int offset) override;
diff --git a/src/qml/jit/qv4jithelpers.cpp b/src/qml/jit/qv4jithelpers.cpp
index f644d8c782..23e3095a85 100644
--- a/src/qml/jit/qv4jithelpers.cpp
+++ b/src/qml/jit/qv4jithelpers.cpp
@@ -69,6 +69,15 @@ ReturnedValue loadGlobalLookup(ExecutionEngine *engine, Function *f, int index)
return l->globalGetter(l, engine);
}
+ReturnedValue loadSuperConstructor(ExecutionEngine *engine, const Value *t)
+{
+ if (!t->isObject()) {
+ engine->throwTypeError();
+ return Encode::undefined();
+ }
+ return static_cast<const Object *>(t)->getPrototypeOf()->asReturnedValue();
+}
+
ReturnedValue toObject(ExecutionEngine *engine, const Value &obj)
{
if (obj.isObject())
diff --git a/src/qml/jit/qv4jithelpers_p.h b/src/qml/jit/qv4jithelpers_p.h
index bb10d5722b..e0dfdc47d9 100644
--- a/src/qml/jit/qv4jithelpers_p.h
+++ b/src/qml/jit/qv4jithelpers_p.h
@@ -66,6 +66,7 @@ namespace Helpers {
void convertThisToObject(ExecutionEngine *engine, Value *t);
ReturnedValue loadGlobalLookup(ExecutionEngine *engine, Function *f, int index);
+ReturnedValue loadSuperConstructor(ExecutionEngine *engine, const Value *t);
ReturnedValue toObject(ExecutionEngine *engine, const Value &obj);
ReturnedValue exp(const Value &base, const Value &exp);
ReturnedValue getLookup(ExecutionEngine *engine, Function *f, int index, const Value &base);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index e88b81bd29..2aca7c2849 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -184,9 +184,16 @@ Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *sco
return scope->engine()->memoryManager->allocate<ScriptFunction>(scope, function);
}
-Heap::FunctionObject *FunctionObject::createConstructorFunction(ExecutionContext *scope, Function *function)
+Heap::FunctionObject *FunctionObject::createConstructorFunction(ExecutionContext *scope, Function *function, bool isDerivedConstructor)
{
- return scope->engine()->memoryManager->allocate<ConstructorFunction>(scope, function);
+ if (!function) {
+ Heap::DefaultClassConstructorFunction *c = scope->engine()->memoryManager->allocate<DefaultClassConstructorFunction>(scope);
+ c->isDerivedConstructor = isDerivedConstructor;
+ return c;
+ }
+ Heap::ConstructorFunction *c = scope->engine()->memoryManager->allocate<ConstructorFunction>(scope, function);
+ c->isDerivedConstructor = isDerivedConstructor;
+ return c;
}
Heap::FunctionObject *FunctionObject::createMemberFunction(ExecutionContext *scope, Function *function)
@@ -455,9 +462,20 @@ ReturnedValue ScriptFunction::virtualCallAsConstructor(const FunctionObject *fo,
{
ExecutionEngine *v4 = fo->engine();
const ScriptFunction *f = static_cast<const ScriptFunction *>(fo);
+ Q_ASSERT(newTarget->isFunctionObject());
+ const FunctionObject *nt = static_cast<const FunctionObject *>(newTarget);
Scope scope(v4);
- ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(f->classForConstructor()));
+ Scoped<InternalClass> ic(scope);
+ if (nt->d() == f->d()) {
+ ic = f->classForConstructor();
+ } else {
+ const Object *o = nt->d()->protoProperty();
+ ic = scope.engine->internalClasses(EngineBase::Class_Object);
+ if (o)
+ ic = ic->changePrototype(o->d());
+ }
+ ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(ic));
CppStackFrame frame;
frame.init(v4, f->function(), argv, argc);
@@ -535,6 +553,36 @@ Heap::InternalClass *ScriptFunction::classForConstructor() const
DEFINE_OBJECT_VTABLE(ConstructorFunction);
+ReturnedValue ConstructorFunction::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
+{
+ const ConstructorFunction *c = static_cast<const ConstructorFunction *>(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(),
+ Primitive::undefinedValue(),
+ newTarget ? *newTarget : Primitive::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 result;
+ else if (!Value::fromReturnedValue(result).isUndefined())
+ return v4->throwTypeError();
+ return frame.jsFrame->thisObject.asReturnedValue();
+}
+
ReturnedValue ConstructorFunction::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
{
return f->engine()->throwTypeError(QStringLiteral("Cannot call a class constructor without |new|"));
@@ -549,13 +597,44 @@ ReturnedValue MemberFunction::virtualCallAsConstructor(const FunctionObject *f,
DEFINE_OBJECT_VTABLE(DefaultClassConstructorFunction);
-ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const FunctionObject *f, const Value *, int, const Value *)
+ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
{
- Scope scope(f);
- ScopedObject proto(scope, f->get(scope.engine->id_prototype()));
- ScopedObject c(scope, scope.engine->newObject());
- c->setPrototypeUnchecked(proto);
- return c->asReturnedValue();
+ const DefaultClassConstructorFunction *c = static_cast<const DefaultClassConstructorFunction *>(f);
+ ExecutionEngine *v4 = f->engine();
+
+ Scope scope(v4);
+
+ if (!c->d()->isDerivedConstructor) {
+ ScopedObject proto(scope, static_cast<const Object *>(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(),
+ Primitive::undefinedValue(),
+ newTarget ? *newTarget : Primitive::undefinedValue(), argc, argc);
+
+ frame.push();
+ v4->jsStackTop += frame.requiredJSStackFrameSize(argc);
+
+ // Do a super call
+ ReturnedValue result = super->callAsConstructor(argv, argc, newTarget);
+
+ 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();
+ return frame.jsFrame->thisObject.asReturnedValue();
}
ReturnedValue DefaultClassConstructorFunction::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index d2af7fa432..1acb1df0b4 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -122,6 +122,7 @@ DECLARE_HEAP_OBJECT(ScriptFunction, FunctionObject) {
struct ConstructorFunction : ScriptFunction
{
+ bool isDerivedConstructor;
};
struct MemberFunction : ScriptFunction
@@ -130,6 +131,7 @@ struct MemberFunction : ScriptFunction
struct DefaultClassConstructorFunction : FunctionObject
{
+ bool isDerivedConstructor;
};
#define BoundFunctionMembers(class, Member) \
@@ -180,7 +182,7 @@ struct Q_QML_EXPORT FunctionObject: Object {
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function);
- static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function);
+ static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function, bool isDerivedConstructor);
static Heap::FunctionObject *createMemberFunction(ExecutionContext *scope, Function *function);
static Heap::FunctionObject *createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount);
@@ -252,6 +254,7 @@ struct ScriptFunction : FunctionObject {
struct ConstructorFunction : ScriptFunction {
V4_OBJECT2(ConstructorFunction, ScriptFunction)
V4_INTERNALCLASS(ConstructorFunction)
+ static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 2c8227887f..65e9b836d1 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -63,14 +63,14 @@ void Heap::ObjectCtor::init(QV4::ExecutionContext *scope)
Heap::FunctionObject::init(scope, QStringLiteral("Object"));
}
-ReturnedValue ObjectCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *)
+ReturnedValue ObjectCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
{
ExecutionEngine *v4 = f->engine();
- const ObjectCtor *ctor = static_cast<const ObjectCtor *>(f);
+ const ObjectCtor *nt = static_cast<const ObjectCtor *>(newTarget);
if (!argc || argv[0].isUndefined() || argv[0].isNull()) {
Scope scope(v4);
ScopedObject obj(scope, scope.engine->newObject());
- ScopedObject proto(scope, ctor->get(scope.engine->id_prototype()));
+ ScopedObject proto(scope, nt->get(scope.engine->id_prototype()));
if (!!proto)
obj->setPrototypeOf(proto);
return obj.asReturnedValue();
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 0fd3787730..eeb66509e3 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1306,7 +1306,6 @@ ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &fu
{
if (!function.isFunctionObject())
return engine->throwTypeError();
- Q_ASSERT(function.sameValue(newTarget));
return static_cast<const FunctionObject &>(function).callAsConstructor(argv, argc, &newTarget);
}
@@ -1316,7 +1315,6 @@ ReturnedValue Runtime::method_constructWithSpread(ExecutionEngine *engine, const
Q_UNIMPLEMENTED();
if (!function.isFunctionObject())
return engine->throwTypeError();
- Q_ASSERT(function.sameValue(newTarget));
Scope scope(engine);
CallArgs arguments = createSpreadArguments(scope, argv, argc);
@@ -1508,13 +1506,8 @@ ReturnedValue Runtime::method_createClass(ExecutionEngine *engine, int classInde
ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
ScopedFunctionObject constructor(scope);
- if (cls->constructorFunction != UINT_MAX) {
- QV4::Function *f = unit->runtimeFunctions[cls->constructorFunction];
- Q_ASSERT(f);
- constructor = FunctionObject::createConstructorFunction(current, f)->asReturnedValue();
- } else {
- constructor = engine->memoryManager->allocate<DefaultClassConstructorFunction>();
- }
+ QV4::Function *f = cls->constructorFunction != UINT_MAX ? unit->runtimeFunctions[cls->constructorFunction] : nullptr;
+ constructor = FunctionObject::createConstructorFunction(current, f, !superClass.isEmpty())->asReturnedValue();
constructor->setPrototypeUnchecked(constructorParent);
constructor->defineDefaultProperty(engine->id_prototype(), proto);
proto->defineDefaultProperty(engine->id_constructor(), constructor);
diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h
index 68301eb097..4966a5637d 100644
--- a/src/qml/jsruntime/qv4stackframe_p.h
+++ b/src/qml/jsruntime/qv4stackframe_p.h
@@ -129,6 +129,9 @@ struct Q_QML_EXPORT CppStackFrame {
}
#ifndef V4_BOOTSTRAP
+ static uint requiredJSStackFrameSize(uint nRegisters) {
+ return CallData::HeaderSize() + nRegisters;
+ }
static uint requiredJSStackFrameSize(Function *v4Function) {
return CallData::HeaderSize() + v4Function->compiledFunction->nRegisters;
}
@@ -136,7 +139,12 @@ struct Q_QML_EXPORT CppStackFrame {
return requiredJSStackFrameSize(v4Function);
}
void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
- const Value &thisObject, const Value &newTarget = Primitive::undefinedValue())
+ const Value &thisObject, const Value &newTarget = Primitive::undefinedValue()) {
+ setupJSFrame(stackSpace, function, scope, thisObject, newTarget,
+ v4Function->nFormals, v4Function->compiledFunction->nRegisters);
+ }
+ void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
+ const Value &thisObject, const Value &newTarget, uint nFormals, uint nRegisters)
{
jsFrame = reinterpret_cast<CallData *>(stackSpace);
jsFrame->function = function;
@@ -146,12 +154,12 @@ struct Q_QML_EXPORT CppStackFrame {
jsFrame->newTarget = newTarget;
uint argc = uint(originalArgumentsCount);
- if (argc > v4Function->nFormals)
- argc = v4Function->nFormals;
+ if (argc > nFormals)
+ argc = nFormals;
jsFrame->setArgc(argc);
memcpy(jsFrame->args, originalArguments, argc*sizeof(Value));
- const Value *end = jsFrame->args + v4Function->compiledFunction->nRegisters;
+ const Value *end = jsFrame->args + nRegisters;
for (Value *v = jsFrame->args + argc; v < end; ++v)
*v = Encode::undefined();
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 4f0f9f27ec..39eaa3a25c 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -936,6 +936,16 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
}
MOTH_END_INSTR(ConvertThisToObject)
+ MOTH_BEGIN_INSTR(LoadSuperConstructor)
+ const Value *f = &stack[CallData::Function];
+ if (!f->isFunctionObject()) {
+ engine->throwTypeError();
+ } else {
+ acc = static_cast<const Object *>(f)->getPrototypeOf()->asReturnedValue();
+ }
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(LoadSuperConstructor)
+
MOTH_BEGIN_INSTR(ToObject)
acc = ACC.toObject(engine)->asReturnedValue();
CHECK_EXCEPTION;
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index cb35aaa3c7..ba69e76a1a 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -130,8 +130,6 @@ built-ins/Array/prototype/unshift/clamps-to-integer-limit.js fails
built-ins/Array/prototype/unshift/length-near-integer-limit.js fails
built-ins/Array/prototype/unshift/throws-if-integer-limit-exceeded.js fails
built-ins/ArrayBuffer/data-allocation-after-object-creation.js fails
-built-ins/ArrayBuffer/isView/arg-is-dataview-subclass-instance.js fails
-built-ins/ArrayBuffer/isView/arg-is-typedarray-subclass-instance.js fails
built-ins/ArrayBuffer/proto-from-ctor-realm.js fails
built-ins/ArrayBuffer/prototype-from-newtarget.js fails
built-ins/ArrayBuffer/prototype/byteLength/detached-buffer.js fails
@@ -407,7 +405,6 @@ built-ins/Function/internals/Call/class-ctor-realm.js fails
built-ins/Function/internals/Construct/base-ctor-revoked-proxy-realm.js fails
built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js fails
built-ins/Function/internals/Construct/derived-return-val-realm.js fails
-built-ins/Function/internals/Construct/derived-return-val.js fails
built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js fails
built-ins/Function/internals/Construct/derived-this-uninitialized.js fails
built-ins/Function/proto-from-ctor-realm.js fails
@@ -1962,6 +1959,10 @@ language/eval-code/direct/non-definable-function-with-function.js sloppyFails
language/eval-code/direct/non-definable-function-with-variable.js sloppyFails
language/eval-code/direct/non-definable-global-function.js sloppyFails
language/eval-code/direct/non-definable-global-generator.js sloppyFails
+language/eval-code/direct/super-call-arrow.js fails
+language/eval-code/direct/super-call-fn.js fails
+language/eval-code/direct/super-call-method.js fails
+language/eval-code/direct/super-call.js fails
language/eval-code/direct/super-prop-method.js fails
language/eval-code/direct/this-value-func-strict-source.js sloppyFails
language/eval-code/direct/var-env-func-init-global-update-configurable.js sloppyFails
@@ -1978,6 +1979,7 @@ language/eval-code/indirect/non-definable-function-with-variable.js sloppyFails
language/eval-code/indirect/non-definable-global-function.js fails
language/eval-code/indirect/non-definable-global-generator.js fails
language/eval-code/indirect/realm.js fails
+language/eval-code/indirect/super-call.js fails
language/eval-code/indirect/this-value-func.js strictFails
language/eval-code/indirect/var-env-func-init-global-new.js strictFails
language/eval-code/indirect/var-env-func-init-global-update-configurable.js fails
@@ -3045,35 +3047,10 @@ language/expressions/prefix-increment/S11.4.4_A5_T3.js sloppyFails
language/expressions/prefix-increment/S11.4.4_A5_T4.js sloppyFails
language/expressions/prefix-increment/S11.4.4_A5_T5.js fails
language/expressions/prefix-increment/S11.4.4_A6_T3.js fails
-language/expressions/super/call-arg-evaluation-err.js fails
language/expressions/super/call-bind-this-value-twice.js fails
language/expressions/super/call-bind-this-value.js fails
-language/expressions/super/call-construct-error.js fails
language/expressions/super/call-construct-invocation.js fails
-language/expressions/super/call-expr-value.js fails
language/expressions/super/call-proto-not-ctor.js fails
-language/expressions/super/call-spread-err-mult-err-expr-throws.js fails
-language/expressions/super/call-spread-err-mult-err-iter-get-value.js fails
-language/expressions/super/call-spread-err-mult-err-itr-get-call.js fails
-language/expressions/super/call-spread-err-mult-err-itr-get-get.js fails
-language/expressions/super/call-spread-err-mult-err-itr-step.js fails
-language/expressions/super/call-spread-err-mult-err-itr-value.js fails
-language/expressions/super/call-spread-err-mult-err-unresolvable.js fails
-language/expressions/super/call-spread-err-sngl-err-expr-throws.js fails
-language/expressions/super/call-spread-err-sngl-err-itr-get-call.js fails
-language/expressions/super/call-spread-err-sngl-err-itr-get-get.js fails
-language/expressions/super/call-spread-err-sngl-err-itr-get-value.js fails
-language/expressions/super/call-spread-err-sngl-err-itr-step.js fails
-language/expressions/super/call-spread-err-sngl-err-itr-value.js fails
-language/expressions/super/call-spread-err-sngl-err-unresolvable.js fails
-language/expressions/super/call-spread-mult-empty.js fails
-language/expressions/super/call-spread-mult-expr.js fails
-language/expressions/super/call-spread-mult-iter.js fails
-language/expressions/super/call-spread-mult-literal.js fails
-language/expressions/super/call-spread-sngl-empty.js fails
-language/expressions/super/call-spread-sngl-expr.js fails
-language/expressions/super/call-spread-sngl-iter.js fails
-language/expressions/super/call-spread-sngl-literal.js fails
language/expressions/super/prop-dot-cls-null-proto.js fails
language/expressions/super/prop-dot-cls-ref-strict.js fails
language/expressions/super/prop-dot-cls-ref-this.js fails
@@ -3273,8 +3250,6 @@ language/statements/async-function/evaluation-body.js fails
language/statements/async-function/syntax-declaration-line-terminators-allowed.js fails
language/statements/block/tco-stmt-list.js strictFails
language/statements/block/tco-stmt.js strictFails
-language/statements/class/arguments/access.js fails
-language/statements/class/arguments/default-constructor.js fails
language/statements/class/constructor-inferred-observable-iteration.js fails
language/statements/class/cptn-decl.js fails
language/statements/class/definition/accessors.js fails
@@ -3588,30 +3563,18 @@ language/statements/class/static-method-gen-non-configurable-err.js fails
language/statements/class/static-method-non-configurable-err.js fails
language/statements/class/strict-mode/arguments-callee.js fails
language/statements/class/subclass/binding.js fails
+language/statements/class/subclass/bound-function.js fails
language/statements/class/subclass/builtin-objects/Array/contructor-calls-super-multiple-arguments.js fails
language/statements/class/subclass/builtin-objects/Array/contructor-calls-super-single-argument.js fails
-language/statements/class/subclass/builtin-objects/Array/length.js fails
-language/statements/class/subclass/builtin-objects/Array/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/Array/super-must-be-called.js fails
language/statements/class/subclass/builtin-objects/ArrayBuffer/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/ArrayBuffer/super-must-be-called.js fails
-language/statements/class/subclass/builtin-objects/Boolean/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/Boolean/super-must-be-called.js fails
-language/statements/class/subclass/builtin-objects/DataView/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/DataView/super-must-be-called.js fails
-language/statements/class/subclass/builtin-objects/Date/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/Date/super-must-be-called.js fails
language/statements/class/subclass/builtin-objects/Error/message-property-assignment.js fails
-language/statements/class/subclass/builtin-objects/Error/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/Error/super-must-be-called.js fails
-language/statements/class/subclass/builtin-objects/Function/instance-length.js fails
-language/statements/class/subclass/builtin-objects/Function/instance-name.js fails
-language/statements/class/subclass/builtin-objects/Function/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/Function/super-must-be-called.js fails
-language/statements/class/subclass/builtin-objects/GeneratorFunction/instance-length.js fails
-language/statements/class/subclass/builtin-objects/GeneratorFunction/instance-name.js fails
-language/statements/class/subclass/builtin-objects/GeneratorFunction/instance-prototype.js fails
-language/statements/class/subclass/builtin-objects/GeneratorFunction/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/GeneratorFunction/super-must-be-called.js fails
language/statements/class/subclass/builtin-objects/Map/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/Map/super-must-be-called.js fails
@@ -3627,43 +3590,24 @@ language/statements/class/subclass/builtin-objects/NativeError/TypeError-message
language/statements/class/subclass/builtin-objects/NativeError/TypeError-super.js fails
language/statements/class/subclass/builtin-objects/NativeError/URIError-message.js fails
language/statements/class/subclass/builtin-objects/NativeError/URIError-super.js fails
-language/statements/class/subclass/builtin-objects/Number/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/Number/super-must-be-called.js fails
language/statements/class/subclass/builtin-objects/Object/constructor-return-undefined-throws.js fails
-language/statements/class/subclass/builtin-objects/Object/constructor-returns-non-object.js fails
language/statements/class/subclass/builtin-objects/Promise/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/Promise/super-must-be-called.js fails
-language/statements/class/subclass/builtin-objects/RegExp/lastIndex.js fails
-language/statements/class/subclass/builtin-objects/RegExp/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/RegExp/super-must-be-called.js fails
-language/statements/class/subclass/builtin-objects/Set/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/Set/super-must-be-called.js fails
-language/statements/class/subclass/builtin-objects/String/length.js fails
-language/statements/class/subclass/builtin-objects/String/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/String/super-must-be-called.js fails
-language/statements/class/subclass/builtin-objects/Symbol/new-symbol-with-super-throws.js fails
-language/statements/class/subclass/builtin-objects/TypedArray/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/TypedArray/super-must-be-called.js fails
language/statements/class/subclass/builtin-objects/WeakMap/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/WeakMap/super-must-be-called.js fails
language/statements/class/subclass/builtin-objects/WeakSet/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/WeakSet/super-must-be-called.js fails
language/statements/class/subclass/builtins.js fails
-language/statements/class/subclass/class-definition-evaluation-empty-constructor-heritage-present.js fails
language/statements/class/subclass/class-definition-null-proto-super.js fails
language/statements/class/subclass/class-definition-null-proto-this.js fails
-language/statements/class/subclass/class-definition-parent-proto-null.js fails
language/statements/class/subclass/class-definition-superclass-generator.js fails
-language/statements/class/subclass/default-constructor-2.js fails
language/statements/class/subclass/default-constructor-spread-override.js fails
-language/statements/class/subclass/default-constructor.js fails
-language/statements/class/subclass/derived-class-return-override-with-boolean.js fails
language/statements/class/subclass/derived-class-return-override-with-empty.js fails
-language/statements/class/subclass/derived-class-return-override-with-null.js fails
-language/statements/class/subclass/derived-class-return-override-with-number.js fails
-language/statements/class/subclass/derived-class-return-override-with-object.js fails
-language/statements/class/subclass/derived-class-return-override-with-string.js fails
-language/statements/class/subclass/derived-class-return-override-with-symbol.js fails
language/statements/class/subclass/derived-class-return-override-with-this.js fails
language/statements/class/subclass/derived-class-return-override-with-undefined.js fails
language/statements/class/super/in-constructor.js fails
@@ -3673,7 +3617,6 @@ language/statements/class/super/in-setter.js fails
language/statements/class/super/in-static-getter.js fails
language/statements/class/super/in-static-methods.js fails
language/statements/class/super/in-static-setter.js fails
-language/statements/class/syntax/class-body-has-direct-super-class-heritage.js fails
language/statements/class/syntax/class-body-method-definition-super-property.js fails
language/statements/class/syntax/class-expression-heritage-identifier-reference.js fails
language/statements/class/syntax/class-expression.js fails