summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2017-06-30 08:44:09 +0200
committerErik Verbruggen <erik.verbruggen@qt.io>2017-06-30 11:35:29 +0000
commit3a9f4d3ae701c7119016a0bf8b4e65ceb17864b0 (patch)
tree760bd51b4775ecc3f48c3ca649699c952b841fbf
parent12ff47eb52fdaf01589b61a3f879d2f5edf7962f (diff)
Get rid of IR::Module and IR::Function
Fold the stuff from IR::Function into QQmlJS::Context, and add a QQmlJS::Module class to replace the last pieces of the old IR. Change-Id: Ic02a6738a4f1db67a0ddf97b6c93ca32be81789d Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp8
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h4
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp7
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h2
-rw-r--r--src/qml/compiler/qv4codegen.cpp178
-rw-r--r--src/qml/compiler/qv4codegen_p.h99
-rw-r--r--src/qml/compiler/qv4compiler.cpp57
-rw-r--r--src/qml/compiler/qv4compiler_p.h6
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4global_p.h4
-rw-r--r--src/qml/jsruntime/qv4script.cpp4
-rw-r--r--src/qml/jsruntime/qv4script_p.h2
-rw-r--r--src/qml/qml/qqmltypeloader.cpp2
13 files changed, 230 insertions, 145 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 6631452ca1..c6c6634a8c 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1552,7 +1552,7 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding
}
JSCodeGen::JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
- QV4::IR::Module *jsModule, QQmlJS::Engine *jsEngine,
+ QQmlJS::Module *jsModule, QQmlJS::Engine *jsEngine,
QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool)
: QQmlJS::Codegen(jsUnitGenerator, /*strict mode*/false)
, sourceCode(sourceCode)
@@ -1605,7 +1605,6 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
scan.leaveEnvironment();
_context = 0;
- _function = _module->functions.at(defineFunction(QStringLiteral("context scope"), qmlRoot, 0, 0));
for (int i = 0; i < functions.count(); ++i) {
const CompiledFunctionOrExpression &qmlFunction = functions.at(i);
@@ -1647,7 +1646,6 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
runtimeFunctionIndices[i] = idx;
}
- cgModule = QQmlJS::Module();
return runtimeFunctionIndices;
}
@@ -1959,8 +1957,8 @@ QQmlJS::Codegen::Reference JSCodeGen::fallbackNameLookup(const QString &name)
// Look for IDs first.
for (const IdMapping &mapping : qAsConst(_idObjects)) {
if (name == mapping.name) {
- if (_function->isQmlBinding)
- _function->idObjectDependencies.insert(mapping.idIndex);
+ if (_context->compilationMode == QQmlJS::QmlBinding)
+ _context->idObjectDependencies.insert(mapping.idIndex);
Reference result = Reference::fromTemp(this);
Instruction::LoadIdObject load;
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index b42ee39eca..80d0fdc306 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -428,7 +428,7 @@ struct Q_QML_PRIVATE_EXPORT Document
Document(bool debugMode);
QString code;
QQmlJS::Engine jsParserEngine;
- QV4::IR::Module jsModule;
+ QQmlJS::Module jsModule;
QList<const QV4::CompiledData::Import *> imports;
QList<Pragma*> pragmas;
QQmlJS::AST::UiProgram *program;
@@ -583,7 +583,7 @@ struct Q_QML_EXPORT PropertyResolver
struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QQmlJS::Codegen
{
- JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator, QV4::IR::Module *jsModule,
+ JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator, QQmlJS::Module *jsModule,
QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports,
const QV4::Compiler::StringTableGenerator *stringPool);
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 1f459f1d13..9a96dbcbfc 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -139,7 +139,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
sss.scan();
}
- document->jsModule.setFileName(typeData->finalUrlString());
+ document->jsModule.fileName = typeData->finalUrlString();
QmlIR::JSCodeGen v4CodeGenerator(document->code, &document->jsGenerator, &document->jsModule, &document->jsParserEngine, document->program, typeNameCache, &document->jsGenerator.stringTable);
v4CodeGenerator.setUseFastLookups(false);
// ### v4CodeGenerator.setUseTypeInference(true);
@@ -209,11 +209,6 @@ int QQmlTypeCompiler::registerString(const QString &str)
return document->jsGenerator.registerString(str);
}
-QV4::IR::Module *QQmlTypeCompiler::jsIRModule() const
-{
- return &document->jsModule;
-}
-
const QV4::CompiledData::Unit *QQmlTypeCompiler::qmlUnit() const
{
return document->javaScriptCompilationUnit->data;
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 76aa422fc5..a70ad77bfb 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -111,8 +111,6 @@ public:
int registerString(const QString &str);
- QV4::IR::Module *jsIRModule() const;
-
const QV4::CompiledData::Unit *qmlUnit() const;
QUrl url() const { return typeData->finalUrl(); }
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index bc3880b385..524c83705c 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -104,15 +104,16 @@ struct ControlFlow {
Codegen *cg;
ControlFlow *parent;
Type type;
+ bool needsLookupByName = false;
ControlFlow(Codegen *cg, Type type)
- : cg(cg), parent(cg->_controlFlow), type(type)
+ : cg(cg), parent(cg->_context->controlFlow), type(type)
{
- cg->_controlFlow = this;
+ cg->_context->controlFlow = this;
}
virtual ~ControlFlow() {
- cg->_controlFlow = parent;
+ cg->_context->controlFlow = parent;
}
void jumpToHandler(const Handler &h) {
@@ -290,6 +291,7 @@ struct ControlFlowWith : public ControlFlowUnwind
ControlFlowWith(Codegen *cg)
: ControlFlowUnwind(cg, With)
{
+ needsLookupByName = true;
generator()->setExceptionHandler(&unwindLabel);
}
@@ -340,7 +342,7 @@ struct ControlFlowCatch : public ControlFlowUnwind
~ControlFlowCatch() {
// emit code for unwinding
- ++cg->_function->insideWithOrCatch;
+ needsLookupByName = true;
insideCatch = true;
// exceptions inside the try block go here
@@ -355,8 +357,8 @@ struct ControlFlowCatch : public ControlFlowUnwind
cg->statement(catchExpression->statement);
- --cg->_function->insideWithOrCatch;
insideCatch = false;
+ needsLookupByName = false;
// exceptions inside catch and break/return statements go here
catchUnwindLabel.link();
@@ -495,7 +497,7 @@ void Codegen::ScanFunctions::operator()(Node *node)
void Codegen::ScanFunctions::enterEnvironment(Node *node, CompilationMode compilationMode)
{
- Context *e = _cg->cgModule.newContext(node, _variableEnvironment, compilationMode);
+ Context *e = _cg->_module->newContext(node, _variableEnvironment, compilationMode);
if (!e->isStrict)
e->isStrict = _cg->_strictMode;
_envStack.append(e);
@@ -799,7 +801,6 @@ bool Codegen::ScanFunctions::visit(Block *ast) {
void Codegen::ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, FunctionBody *body, FunctionExpression *expr, bool isExpression)
{
- bool wasStrict = false;
if (_variableEnvironment) {
_variableEnvironment->hasNestedFunctions = true;
// The identifier of a function expression cannot be referenced from the enclosing environment.
@@ -807,7 +808,6 @@ void Codegen::ScanFunctions::enterFunction(Node *ast, const QString &name, Forma
_variableEnvironment->enter(name, Context::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr);
if (name == QLatin1String("arguments"))
_variableEnvironment->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
- wasStrict = _variableEnvironment->isStrict;
}
enterEnvironment(ast, FunctionCode);
@@ -816,14 +816,13 @@ void Codegen::ScanFunctions::enterFunction(Node *ast, const QString &name, Forma
_variableEnvironment->isNamedFunctionExpression = isExpression && !name.isEmpty();
_variableEnvironment->formals = formals;
- if (body)
+ if (body && !_variableEnvironment->isStrict)
checkDirectivePrologue(body->elements);
- if (wasStrict || _variableEnvironment->isStrict) {
- QStringList args;
- for (FormalParameterList *it = formals; it; it = it->next) {
- QString arg = it->name.toString();
- if (args.contains(arg)) {
+ for (FormalParameterList *it = formals; it; it = it->next) {
+ QString arg = it->name.toString();
+ if (_variableEnvironment->isStrict) {
+ if (_variableEnvironment->arguments.contains(arg)) {
_cg->throwSyntaxError(it->identifierToken, QStringLiteral("Duplicate parameter name '%1' is not allowed in strict mode").arg(arg));
return;
}
@@ -831,18 +830,16 @@ void Codegen::ScanFunctions::enterFunction(Node *ast, const QString &name, Forma
_cg->throwSyntaxError(it->identifierToken, QStringLiteral("'%1' cannot be used as parameter name in strict mode").arg(arg));
return;
}
- args += arg;
}
+ _variableEnvironment->arguments += arg;
}
}
Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict)
: _module(0)
- , _function(0)
, _returnAddress(0)
, _context(0)
- , _controlFlow(0)
, _labelledStatement(0)
, jsUnitGenerator(jsUnitGenerator)
, _strictMode(strict)
@@ -854,7 +851,7 @@ Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict)
void Codegen::generateFromProgram(const QString &fileName,
const QString &sourceCode,
Program *node,
- QV4::IR::Module *module,
+ QQmlJS::Module *module,
CompilationMode mode)
{
Q_ASSERT(node);
@@ -862,22 +859,21 @@ void Codegen::generateFromProgram(const QString &fileName,
_module = module;
_context = 0;
- _module->setFileName(fileName);
+ _module->fileName = fileName;
ScanFunctions scan(this, sourceCode, mode);
scan(node);
defineFunction(QStringLiteral("%entry"), node, 0, node->elements);
- cgModule = QQmlJS::Module();
}
void Codegen::generateFromFunctionExpression(const QString &fileName,
const QString &sourceCode,
AST::FunctionExpression *ast,
- QV4::IR::Module *module)
+ QQmlJS::Module *module)
{
_module = module;
- _module->setFileName(fileName);
+ _module->fileName = fileName;
_context = 0;
ScanFunctions scan(this, sourceCode, GlobalCode);
@@ -886,21 +882,21 @@ void Codegen::generateFromFunctionExpression(const QString &fileName,
scan(ast);
scan.leaveEnvironment();
- defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0);
-
- cgModule = QQmlJS::Module();
+ int index = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0);
+ _module->rootContext = _module->functions.at(index);
}
void Codegen::enterContext(Node *node)
{
- _context = cgModule.contextMap.value(node);
+ _context = _module->contextMap.value(node);
Q_ASSERT(_context);
}
void Codegen::leaveContext()
{
Q_ASSERT(_context);
+ Q_ASSERT(!_context->controlFlow);
_context = _context->parent;
}
@@ -1902,35 +1898,33 @@ bool Codegen::visit(FunctionExpression *ast)
Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs)
{
uint scope = 0;
- Context *e = _context;
- IR::Function *f = _function;
+ Context *c = _context;
- while (f && e->parent) {
- if (f->insideWithOrCatch || (f->isNamedExpression && QStringRef(f->name) == name))
+ while (c->parent) {
+ if (c->forceLookupByName() || (c->isNamedFunctionExpression && c->name == name))
goto loadByName;
- int index = e->findMember(name);
- Q_ASSERT (index < e->members.size());
+ int index = c->findMember(name);
+ Q_ASSERT (index < c->members.size());
if (index != -1) {
Reference r = Reference::fromLocal(this, index, scope);
if (name == QLatin1String("arguments") || name == QLatin1String("eval")) {
r.isArgOrEval = true;
- if (isLhs && f->isStrict)
+ if (isLhs && c->isStrict)
// ### add correct source location
throwSyntaxError(SourceLocation(), QStringLiteral("Variable name may not be eval or arguments in strict mode"));
}
return r;
}
- const int argIdx = f->indexOfArgument(QStringRef(&name));
+ const int argIdx = c->findArgument(name);
if (argIdx != -1)
return Reference::fromArgument(this, argIdx, scope);
- if (!e->isStrict && e->hasDirectEval)
+ if (!c->isStrict && c->hasDirectEval)
goto loadByName;
++scope;
- e = e->parent;
- f = f->outer;
+ c = c->parent;
}
{
@@ -1940,8 +1934,7 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs)
return fallback;
}
- if (!e->parent && (!f || !f->insideWithOrCatch) &&
- _context->compilationMode != EvalCode && e->compilationMode != QmlBinding) {
+ if (!c->parent && !c->forceLookupByName() && _context->compilationMode != EvalCode && c->compilationMode != QmlBinding) {
Reference r = Reference::fromName(this, name);
r.global = true;
return r;
@@ -2397,25 +2390,17 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
AST::FormalParameterList *formals,
AST::SourceElements *body)
{
- ControlFlow *loop = 0;
- qSwap(_controlFlow, loop);
+ Q_UNUSED(formals);
enterContext(ast);
- IR::Function *function = _module->newFunction(name, _function);
- int functionIndex = _module->functions.count() - 1;
- function->hasDirectEval = _context->hasDirectEval || _context->compilationMode == EvalCode
- || _module->debugMode; // Conditional breakpoints are like eval in the function
- function->usesArgumentsObject = _context->parent && (_context->usesArgumentsObject == Context::ArgumentsObjectUsed);
- function->usesThis = _context->usesThis;
- function->maxNumberOfArguments = qMax(_context->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
- function->isStrict = _context->isStrict;
- function->isNamedExpression = _context->isNamedFunctionExpression;
- function->isQmlBinding = _context->compilationMode == QmlBinding;
+ _context->name = name;
+ _module->functions.append(_context);
+ int functionIndex = _module->functions.count() - 1;
- AST::SourceLocation loc = ast->firstSourceLocation();
- function->line = loc.startLine;
- function->column = loc.startColumn;
+ _context->hasDirectEval |= _context->compilationMode == EvalCode || _module->debugMode; // Conditional breakpoints are like eval in the function
+ // ### still needed?
+ _context->maxNumberOfArguments = qMax(_context->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
BytecodeGenerator bytecode;
BytecodeGenerator *savedBytecodeGenerator;
@@ -2423,7 +2408,10 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bytecodeGenerator = &bytecode;
unsigned returnAddress = bytecodeGenerator->newTemp();
- if (function->usesArgumentsObject)
+
+ if (!_context->parent || _context->usesArgumentsObject == Context::ArgumentsObjectUnknown)
+ _context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
+ if (_context->usesArgumentsObject == Context::ArgumentsObjectUsed)
_context->enter(QStringLiteral("arguments"), Context::VariableDeclaration, AST::VariableDeclaration::FunctionScope);
// variables in global code are properties of the global context object, not locals as with other functions.
@@ -2431,7 +2419,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
unsigned t = 0;
for (Context::MemberMap::iterator it = _context->members.begin(), end = _context->members.end(); it != end; ++it) {
const QString &local = it.key();
- function->LOCAL(local);
+ _context->locals.append(local);
(*it).index = t;
++t;
}
@@ -2448,14 +2436,9 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
auto exitBlock = bytecodeGenerator->newLabel();
- qSwap(_function, function);
qSwap(_exitBlock, exitBlock);
qSwap(_returnAddress, returnAddress);
- for (FormalParameterList *it = formals; it; it = it->next) {
- _function->RECEIVE(it->name.toString());
- }
-
for (const Context::Member &member : qAsConst(_context->members)) {
if (member.function) {
const int function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
@@ -2471,12 +2454,12 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
}
}
}
- if (_function->usesArgumentsObject) {
+ if (_context->usesArgumentsObject == Context::ArgumentsObjectUsed) {
Instruction::CallBuiltinSetupArgumentsObject setup;
setup.result = referenceForName(QStringLiteral("arguments"), false).asLValue();
bytecodeGenerator->addInstruction(setup);
}
- if (_function->usesThis && !_context->isStrict) {
+ if (_context->usesThis && !_context->isStrict) {
// make sure we convert this to an object
Instruction::CallBuiltinConvertThisToObject convert;
bytecodeGenerator->addInstruction(convert);
@@ -2495,18 +2478,16 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bytecodeGenerator->addInstruction(ret);
}
- _function->code = bytecodeGenerator->finalize();
+ _context->code = bytecodeGenerator->finalize();
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
if (showCode) {
- qDebug() << "=== Bytecode for" << *_function->name;
- QV4::Moth::dumpBytecode(_function->code);
+ qDebug() << "=== Bytecode for" << _context->name;
+ QV4::Moth::dumpBytecode(_context->code);
qDebug();
}
- qSwap(_function, function);
qSwap(_exitBlock, exitBlock);
qSwap(_returnAddress, returnAddress);
- qSwap(_controlFlow, loop);
leaveContext();
@@ -2551,12 +2532,12 @@ bool Codegen::visit(BreakStatement *ast)
if (hasError)
return false;
- if (!_controlFlow) {
+ if (!_context->controlFlow) {
throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Break outside of loop"));
return false;
}
- ControlFlow::Handler h = _controlFlow->getHandler(ControlFlow::Break, ast->label.toString());
+ ControlFlow::Handler h = _context->controlFlow->getHandler(ControlFlow::Break, ast->label.toString());
if (h.type == ControlFlow::Invalid) {
if (ast->label.isEmpty())
throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Break outside of loop"));
@@ -2565,7 +2546,7 @@ bool Codegen::visit(BreakStatement *ast)
return false;
}
- _controlFlow->jumpToHandler(h);
+ _context->controlFlow->jumpToHandler(h);
return false;
}
@@ -2577,12 +2558,12 @@ bool Codegen::visit(ContinueStatement *ast)
TempScope scope(this);
- if (!_controlFlow) {
+ if (!_context->controlFlow) {
throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Continue outside of loop"));
return false;
}
- ControlFlow::Handler h = _controlFlow->getHandler(ControlFlow::Continue, ast->label.toString());
+ ControlFlow::Handler h = _context->controlFlow->getHandler(ControlFlow::Continue, ast->label.toString());
if (h.type == ControlFlow::Invalid) {
if (ast->label.isEmpty())
throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Undefined label '%1'").arg(ast->label.toString()));
@@ -2591,7 +2572,7 @@ bool Codegen::visit(ContinueStatement *ast)
return false;
}
- _controlFlow->jumpToHandler(h);
+ _context->controlFlow->jumpToHandler(h);
return false;
}
@@ -2762,7 +2743,7 @@ bool Codegen::visit(LabelledStatement *ast)
TempScope scope(this);
// check that no outer loop contains the label
- ControlFlow *l = _controlFlow;
+ ControlFlow *l = _context->controlFlow;
while (l) {
if (l->label() == ast->label) {
QString error = QString(QStringLiteral("Label '%1' has already been declared")).arg(ast->label.toString());
@@ -2881,9 +2862,9 @@ bool Codegen::visit(ReturnStatement *ast)
Reference::fromTemp(this, _returnAddress).storeConsume(expr);
}
- if (_controlFlow) {
- ControlFlow::Handler h = _controlFlow->getHandler(ControlFlow::Return);
- _controlFlow->jumpToHandler(h);
+ if (_context->controlFlow) {
+ ControlFlow::Handler h = _context->controlFlow->getHandler(ControlFlow::Return);
+ _context->controlFlow->jumpToHandler(h);
} else {
bytecodeGenerator->jump().link(_exitBlock);
}
@@ -2971,8 +2952,8 @@ bool Codegen::visit(ThrowStatement *ast)
Reference expr = expression(ast->expression);
- if (_controlFlow) {
- _controlFlow->handleThrow(expr);
+ if (_context->controlFlow) {
+ _context->controlFlow->handleThrow(expr);
} else {
Instruction::CallBuiltinThrow instr;
instr.arg = expr.asRValue();
@@ -3021,7 +3002,7 @@ bool Codegen::visit(TryStatement *ast)
TempScope scope(this);
- _function->hasTry = true;
+ _context->hasTry = true;
if (ast->finallyExpression && ast->finallyExpression->statement) {
handleTryFinally(ast);
@@ -3069,7 +3050,7 @@ bool Codegen::visit(WithStatement *ast)
TempScope scope(this);
- _function->hasWith = true;
+ _context->hasWith = true;
Reference src = expression(ast->expression);
if (hasError)
@@ -3077,14 +3058,12 @@ bool Codegen::visit(WithStatement *ast)
src.asRValue(); // trigger load before we setup the exception handler, so exceptions here go to the right place
ControlFlowWith flow(this);
- ++_function->insideWithOrCatch;
Instruction::CallBuiltinPushScope pushScope;
pushScope.arg = src.asRValue();
bytecodeGenerator->addInstruction(pushScope);
statement(ast->statement);
- --_function->insideWithOrCatch;
return false;
}
@@ -3177,7 +3156,7 @@ QQmlRefPointer<CompiledData::CompilationUnit> Codegen::generateCompilationUnit(b
Moth::CompilationUnit *compilationUnit = new Moth::CompilationUnit;
compilationUnit->codeRefs.resize(_module->functions.size());
int i = 0;
- for (IR::Function *irFunction : qAsConst(_module->functions))
+ for (QQmlJS::Context *irFunction : qAsConst(_module->functions))
compilationUnit->codeRefs[i++] = irFunction->code;
if (generateUnitData)
@@ -3517,14 +3496,14 @@ void Codegen::Reference::load(uint tmp) const
load.propertyIndex = qmlCoreIndex;
load.result = temp;
codegen->bytecodeGenerator->addInstruction(load);
- codegen->_function->scopeObjectPropertyDependencies.insert(qmlCoreIndex, qmlNotifyIndex);
+ codegen->_context->scopeObjectPropertyDependencies.insert(qmlCoreIndex, qmlNotifyIndex);
} else if (type == QmlContextObject) {
Instruction::LoadContextObjectProperty load;
load.base = base;
load.propertyIndex = qmlCoreIndex;
load.result = temp;
codegen->bytecodeGenerator->addInstruction(load);
- codegen->_function->contextObjectPropertyDependencies.insert(qmlCoreIndex, qmlNotifyIndex);
+ codegen->_context->contextObjectPropertyDependencies.insert(qmlCoreIndex, qmlNotifyIndex);
} else if (type == This) {
Instruction::LoadThis load;
load.result = temp;
@@ -3538,6 +3517,31 @@ void Codegen::Reference::load(uint tmp) const
Context *Module::newContext(Node *node, Context *parent, CompilationMode compilationMode)
{
Context *c = new Context(parent, compilationMode);
+ if (node) {
+ SourceLocation loc = node->firstSourceLocation();
+ c->line = loc.startLine;
+ c->column = loc.startColumn;
+ }
+
contextMap.insert(node, c);
+
+ if (!parent)
+ rootContext = c;
+ else {
+ parent->nestedContexts.append(c);
+ c->isStrict = parent->isStrict;
+ }
+
return c;
}
+
+bool Context::forceLookupByName()
+{
+ QV4::ControlFlow *flow = controlFlow;
+ while (flow) {
+ if (flow->needsLookupByName)
+ return true;
+ flow = flow->parent;
+ }
+ return false;
+}
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index bac74149d4..c863159189 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -97,7 +97,9 @@ enum CompilationMode {
struct Context;
struct Module {
- Module() {}
+ Module(bool debugMode)
+ : debugMode(debugMode)
+ {}
~Module() {
qDeleteAll(contextMap);
}
@@ -105,11 +107,21 @@ struct Module {
Context *newContext(AST::Node *node, Context *parent, CompilationMode compilationMode);
QHash<AST::Node *, Context *> contextMap;
+ QList<Context *> functions;
+ Context *rootContext;
+ QString fileName;
+ QDateTime sourceTimeStamp;
+ uint unitFlags = 0; // flags merged into CompiledData::Unit::flags
+ bool debugMode = false;
+ QString targetABI; // ### seems unused currently
};
struct Context {
Context *parent;
+ QString name;
+ int line = 0;
+ int column = 0;
enum MemberType {
UndefinedMember,
@@ -130,12 +142,21 @@ struct Context {
MemberMap members;
AST::FormalParameterList *formals;
+ QStringList arguments;
+ QStringList locals;
+ QVector<Context *> nestedContexts;
+
+ QV4::ControlFlow *controlFlow = 0;
+ QByteArray code;
+
int maxNumberOfArguments;
bool hasDirectEval;
bool hasNestedFunctions;
bool isStrict;
bool isNamedFunctionExpression;
bool usesThis;
+ bool hasTry = false;
+ bool hasWith = false;
enum UsesArgumentsObject {
ArgumentsObjectUnknown,
ArgumentsObjectNotUsed,
@@ -146,6 +167,53 @@ struct Context {
CompilationMode compilationMode;
+ template <typename T>
+ class SmallSet: public QVarLengthArray<T, 8>
+ {
+ public:
+ void insert(int value)
+ {
+ for (auto it : *this) {
+ if (it == value)
+ return;
+ }
+ this->append(value);
+ }
+ };
+
+ // Map from meta property index (existence implies dependency) to notify signal index
+ struct KeyValuePair
+ {
+ quint32 _key;
+ quint32 _value;
+
+ KeyValuePair(): _key(0), _value(0) {}
+ KeyValuePair(quint32 key, quint32 value): _key(key), _value(value) {}
+
+ quint32 key() const { return _key; }
+ quint32 value() const { return _value; }
+ };
+
+ class PropertyDependencyMap: public QVarLengthArray<KeyValuePair, 8>
+ {
+ public:
+ void insert(quint32 key, quint32 value)
+ {
+ for (auto it = begin(), eit = end(); it != eit; ++it) {
+ if (it->_key == key) {
+ it->_value = value;
+ return;
+ }
+ }
+ append(KeyValuePair(key, value));
+ }
+ };
+
+ // Qml extension:
+ SmallSet<int> idObjectDependencies;
+ PropertyDependencyMap contextObjectPropertyDependencies;
+ PropertyDependencyMap scopeObjectPropertyDependencies;
+
Context(Context *parent, CompilationMode mode)
: parent(parent)
, formals(0)
@@ -162,6 +230,26 @@ struct Context {
isStrict = true;
}
+ bool forceLookupByName();
+
+
+ bool canUseSimpleCall() const {
+ return nestedContexts.isEmpty() &&
+ locals.isEmpty() && arguments.size() <= QV4::Global::ReservedArgumentCount &&
+ !hasTry && !hasWith && !isNamedFunctionExpression &&
+ usesArgumentsObject == ArgumentsObjectNotUsed && !hasDirectEval;
+ }
+
+ int findArgument(const QString &name) const
+ {
+ // search backwards to handle duplicate argument names correctly
+ for (int i = arguments.size() - 1; i >= 0; --i) {
+ if (arguments.at(i) == name)
+ return i;
+ }
+ return -1;
+ }
+
int findMember(const QString &name) const
{
MemberMap::const_iterator it = members.find(name);
@@ -238,12 +326,12 @@ public:
void generateFromProgram(const QString &fileName,
const QString &sourceCode,
AST::Program *ast,
- QV4::IR::Module *module,
+ QQmlJS::Module *module,
CompilationMode mode = GlobalCode);
void generateFromFunctionExpression(const QString &fileName,
const QString &sourceCode,
AST::FunctionExpression *ast,
- QV4::IR::Module *module);
+ QQmlJS::Module *module);
public:
struct Reference {
@@ -647,13 +735,10 @@ protected:
friend struct QV4::ControlFlowCatch;
friend struct QV4::ControlFlowFinally;
Result _expr;
- QV4::IR::Module *_module;
- QV4::IR::Function *_function;
+ Module *_module;
BytecodeGenerator::Label _exitBlock;
unsigned _returnAddress;
Context *_context;
- QV4::ControlFlow *_controlFlow;
- Module cgModule;
AST::LabelledStatement *_labelledStatement;
QV4::Compiler::JSUnitGenerator *jsUnitGenerator;
BytecodeGenerator *bytecodeGenerator = 0;
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 619993b874..2985e39765 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -39,6 +39,7 @@
#include <qv4compiler_p.h>
#include <qv4compileddata_p.h>
+#include <qv4codegen_p.h>
#include <private/qv4string_p.h>
#include <private/qv4value_p.h>
#include <private/qv4alloca_p.h>
@@ -99,8 +100,8 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
}
}
-QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::IR::Module *module)
- : irModule(module)
+QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QQmlJS::Module *module)
+ : module(module)
{
// Make sure the empty string always gets index 0
registerString(QString());
@@ -256,16 +257,16 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, CompiledData::JSC
QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option)
{
- registerString(irModule->fileName);
- for (QV4::IR::Function *f : qAsConst(irModule->functions)) {
- registerString(*f->name);
- for (int i = 0; i < f->formals.size(); ++i)
- registerString(*f->formals.at(i));
+ registerString(module->fileName);
+ for (QQmlJS::Context *f : qAsConst(module->functions)) {
+ registerString(f->name);
+ for (int i = 0; i < f->arguments.size(); ++i)
+ registerString(f->arguments.at(i));
for (int i = 0; i < f->locals.size(); ++i)
- registerString(*f->locals.at(i));
+ registerString(f->locals.at(i));
}
- Q_ALLOCA_VAR(CompiledData::LEUInt32, functionOffsets, irModule->functions.size() * sizeof(CompiledData::LEUInt32));
+ Q_ALLOCA_VAR(CompiledData::LEUInt32, functionOffsets, module->functions.size() * sizeof(CompiledData::LEUInt32));
uint jsClassDataOffset = 0;
char *dataPtr;
@@ -280,9 +281,9 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
memcpy(dataPtr + unit->offsetToFunctionTable, functionOffsets, unit->functionTableSize * sizeof(CompiledData::LEUInt32));
- for (int i = 0; i < irModule->functions.size(); ++i) {
- QV4::IR::Function *function = irModule->functions.at(i);
- if (function == irModule->rootFunction)
+ for (int i = 0; i < module->functions.size(); ++i) {
+ QQmlJS::Context *function = module->functions.at(i);
+ if (function == module->rootContext)
unit->indexOfRootFunction = i;
writeFunction(dataPtr + functionOffsets[i], function);
@@ -322,14 +323,14 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
return unit;
}
-void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *irFunction) const
+void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QQmlJS::Context *irFunction) const
{
QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
quint32 currentOffset = sizeof(QV4::CompiledData::Function);
currentOffset = (currentOffset + 7) & ~quint32(0x7);
- function->nameIndex = getStringId(*irFunction->name);
+ function->nameIndex = getStringId(irFunction->name);
function->flags = 0;
if (irFunction->hasDirectEval)
function->flags |= CompiledData::Function::HasDirectEval;
@@ -337,13 +338,13 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *i
function->flags |= CompiledData::Function::UsesArgumentsObject;
if (irFunction->isStrict)
function->flags |= CompiledData::Function::IsStrict;
- if (irFunction->isNamedExpression)
+ if (irFunction->isNamedFunctionExpression)
function->flags |= CompiledData::Function::IsNamedExpression;
if (irFunction->hasTry || irFunction->hasWith)
function->flags |= CompiledData::Function::HasCatchOrWith;
if (irFunction->canUseSimpleCall())
function->flags |= CompiledData::Function::CanUseSimpleCall;
- function->nFormals = irFunction->formals.size();
+ function->nFormals = irFunction->arguments.size();
function->formalsOffset = currentOffset;
currentOffset += function->nFormals * sizeof(quint32);
@@ -351,7 +352,7 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *i
function->localsOffset = currentOffset;
currentOffset += function->nLocals * sizeof(quint32);
- function->nInnerFunctions = irFunction->nestedFunctions.size();
+ function->nInnerFunctions = irFunction->nestedContexts.size();
function->nDependingIdObjects = 0;
function->nDependingContextProperties = 0;
@@ -383,13 +384,13 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *i
// write formals
quint32 *formals = (quint32 *)(f + function->formalsOffset);
- for (int i = 0; i < irFunction->formals.size(); ++i)
- formals[i] = getStringId(*irFunction->formals.at(i));
+ for (int i = 0; i < irFunction->arguments.size(); ++i)
+ formals[i] = getStringId(irFunction->arguments.at(i));
// write locals
quint32 *locals = (quint32 *)(f + function->localsOffset);
for (int i = 0; i < irFunction->locals.size(); ++i)
- locals[i] = getStringId(*irFunction->locals.at(i));
+ locals[i] = getStringId(irFunction->locals.at(i));
// write QML dependencies
quint32 *writtenDeps = (quint32 *)(f + function->dependingIdObjectsOffset);
@@ -417,17 +418,17 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
memset(&unit, 0, sizeof(unit));
memcpy(unit.magic, CompiledData::magic_str, sizeof(unit.magic));
unit.flags = QV4::CompiledData::Unit::IsJavascript;
- unit.flags |= irModule->unitFlags;
+ unit.flags |= module->unitFlags;
unit.version = QV4_DATA_STRUCTURE_VERSION;
unit.qtVersion = QT_VERSION;
memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum));
- unit.architectureIndex = registerString(irModule->targetABI.isEmpty() ? QSysInfo::buildAbi() : irModule->targetABI);
+ unit.architectureIndex = registerString(module->targetABI.isEmpty() ? QSysInfo::buildAbi() : module->targetABI);
unit.codeGeneratorIndex = registerString(codeGeneratorName);
memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum));
quint32 nextOffset = sizeof(CompiledData::Unit);
- unit.functionTableSize = irModule->functions.size();
+ unit.functionTableSize = module->functions.size();
unit.offsetToFunctionTable = nextOffset;
nextOffset += unit.functionTableSize * sizeof(uint);
@@ -453,13 +454,13 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
*jsClassDataOffset = nextOffset;
nextOffset += jsClassData.size();
- for (int i = 0; i < irModule->functions.size(); ++i) {
- QV4::IR::Function *f = irModule->functions.at(i);
+ for (int i = 0; i < module->functions.size(); ++i) {
+ QQmlJS::Context *f = module->functions.at(i);
functionOffsets[i] = nextOffset;
const int qmlIdDepsCount = f->idObjectDependencies.count();
const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
- nextOffset += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), qmlIdDepsCount, qmlPropertyDepsCount);
+ nextOffset += QV4::CompiledData::Function::calculateSize(f->arguments.size(), f->locals.size(), f->nestedContexts.size(), qmlIdDepsCount, qmlPropertyDepsCount);
}
if (option == GenerateWithStringTable) {
@@ -471,8 +472,8 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.offsetToStringTable = 0;
}
unit.indexOfRootFunction = -1;
- unit.sourceFileIndex = getStringId(irModule->fileName);
- unit.sourceTimeStamp = irModule->sourceTimeStamp.isValid() ? irModule->sourceTimeStamp.toMSecsSinceEpoch() : 0;
+ unit.sourceFileIndex = getStringId(module->fileName);
+ unit.sourceTimeStamp = module->sourceTimeStamp.isValid() ? module->sourceTimeStamp.toMSecsSinceEpoch() : 0;
unit.nImports = 0;
unit.offsetToImports = 0;
unit.nObjects = 0;
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 222b97ceb6..0ed03a4c2c 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -95,7 +95,7 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
bool isAccessor;
};
- JSUnitGenerator(IR::Module *module);
+ JSUnitGenerator(QQmlJS::Module *module);
int registerString(const QString &str) { return stringTable.registerString(str); }
int getStringId(const QString &string) const { return stringTable.getStringId(string); }
@@ -126,14 +126,14 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
QV4::CompiledData::Unit *generateUnit(GeneratorOption option = GenerateWithStringTable);
// Returns bytes written
- void writeFunction(char *f, IR::Function *irFunction) const;
+ void writeFunction(char *f, QQmlJS::Context *irFunction) const;
StringTableGenerator stringTable;
QString codeGeneratorName;
private:
CompiledData::Unit generateHeader(GeneratorOption option, QJsonPrivate::q_littleendian<quint32> *functionOffsets, uint *jsClassDataOffset);
- IR::Module *irModule;
+ QQmlJS::Module *module;
QList<CompiledData::Lookup> lookups;
QVector<CompiledData::RegExp> regexps;
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 17f92f5f7c..992701d0fb 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -217,7 +217,7 @@ void FunctionCtor::construct(const Managed *that, Scope &scope, CallData *callDa
return;
}
- IR::Module module(scope.engine->debugger() != 0);
+ QQmlJS::Module module(scope.engine->debugger() != 0);
Compiler::JSUnitGenerator jsGenerator(&module);
QQmlJS::RuntimeCodegen cg(scope.engine, &jsGenerator, f->strictMode());
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index b5b077124d..ab7ee17e68 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -147,6 +147,10 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
#endif
QT_BEGIN_NAMESPACE
+namespace QQmlJS {
+ struct Module;
+ struct Context;
+}
namespace QV4 {
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 7ea16020a5..13f84ccd0e 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -88,7 +88,7 @@ void Script::parse()
ExecutionEngine *v4 = scope->engine();
Scope valueScope(v4);
- IR::Module module(v4->debugger() != 0);
+ QQmlJS::Module module(v4->debugger() != 0);
QQmlJS::Engine ee, *engine = &ee;
Lexer lexer(engine);
@@ -176,7 +176,7 @@ Function *Script::function()
return vmFunction;
}
-QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator,
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QQmlJS::Module *module, Compiler::JSUnitGenerator *unitGenerator,
const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors,
QQmlJS::Directives *directivesCollector)
{
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index 25a9dbe3a1..760dad0060 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -139,7 +139,7 @@ struct Q_QML_EXPORT Script {
Function *function();
- static QQmlRefPointer<CompiledData::CompilationUnit> precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, const QUrl &url, const QString &source,
+ static QQmlRefPointer<CompiledData::CompilationUnit> precompile(QQmlJS::Module *module, Compiler::JSUnitGenerator *unitGenerator, const QUrl &url, const QString &source,
QList<QQmlError> *reportedErrors = 0, QQmlJS::Directives *directivesCollector = 0);
static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext);
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 5917d96293..e4fb8874e8 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2442,7 +2442,7 @@ void QQmlTypeData::restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit>
m_document.reset(new QmlIR::Document(isDebugging()));
QmlIR::IRLoader loader(unit->data, m_document.data());
loader.load();
- m_document->jsModule.setFileName(finalUrlString());
+ m_document->jsModule.fileName = finalUrlString();
m_document->javaScriptCompilationUnit = unit;
continueLoadFromIR();
}