formalParameterList[i] = scope->engine->identifier(*function->formals.at(i));
}
}
+
+ varCount = function->locals.size();
+ if (varCount) {
+ varList = new String*[varCount];
+ for (size_t i = 0; i < varCount; ++i) {
+ varList[i] = scope->engine->identifier(*function->locals.at(i));
+ }
+ }
}
ScriptFunction::~ScriptFunction()
{
delete[] formalParameterList;
+ delete[] varList;
}
void ScriptFunction::call(VM::Context *ctx)
Value *ArgumentsObject::getProperty(String *name, PropertyAttributes *attributes)
{
if (context) {
+ for (size_t i = 0; i < context->varCount; ++i) {
+ String *var = context->vars[i];
+ if (__qmljs_string_equal(context, var, name)) {
+ if (attributes)
+ *attributes = PropertyAttributes(*attributes | WritableAttribute);
+ return &context->locals[i];
+ }
+ }
for (size_t i = 0; i < context->formalCount; ++i) {
String *formal = context->formals[i];
if (__qmljs_string_equal(context, formal, name)) {
Context *scope;
String **formalParameterList;
size_t formalParameterCount;
+ String **varList;
+ size_t varCount;
bool needsActivation;
FunctionObject(Context *scope)
: scope(scope)
, formalParameterList(0)
, formalParameterCount(0)
+ , varList(0)
+ , varCount(0)
, needsActivation(true) {}
virtual FunctionObject *asFunctionObject() { return this; }
Value thisObject;
Value *arguments;
size_t argumentCount;
+ Value *locals;
Value result;
String **formals;
size_t formalCount;
+ String **vars;
+ size_t varCount;
bool calledAsConstructor;
Value *lookup(String *name) {
if (activation.is(OBJECT_TYPE)) {
- if (Value *prop = activation.objectValue->getProperty(name))
+ if (Value *prop = activation.objectValue->getProperty(name)) {
return prop;
+ }
}
return parent ? parent->lookup(name) : 0;
}
parent = 0;
arguments = 0;
argumentCount = 0;
+ locals = 0;
activation.type = NULL_TYPE;
thisObject.type = NULL_TYPE;
result.type = UNDEFINED_TYPE;
formals = 0;
formalCount = 0;
+ vars = 0;
+ varCount = 0;
calledAsConstructor = false;
}
};
ctx->arguments = new Value[argc];
std::copy(args, args + argc, ctx->arguments);
}
+ ctx->vars = f->varList;
+ ctx->varCount = f->varCount;
+ ctx->locals = 0;
f->call(ctx);
if (result)
__qmljs_copy(result, &ctx->result);
} while (changed);
}
-struct ScanFunctionBody: Visitor
+} // end of anonymous namespace
+
+struct Codegen::ScanFunctionBody: Visitor
{
using Visitor::visit;
// search for locals
+ Codegen::Environment *env;
QList<QStringRef> locals;
int maxNumberOfArguments;
bool hasDirectEval;
bool hasNestedFunctions;
ScanFunctionBody()
- : maxNumberOfArguments(0)
+ : env(0)
+ , maxNumberOfArguments(0)
, hasDirectEval(false)
, hasNestedFunctions(false)
{
}
- void operator()(Node *node) {
+ void operator()(Node *node, Environment *e)
+ {
+ env = e;
+ maxNumberOfArguments = 0;
hasDirectEval = false;
+ hasNestedFunctions = false;
locals.clear();
if (node)
node->accept(this);
virtual bool visit(VariableDeclaration *ast)
{
+ env->enter(ast->name);
if (! locals.contains(ast->name))
locals.append(ast->name);
return true;
virtual bool visit(FunctionExpression *ast)
{
+ env->enter(ast->name);
hasNestedFunctions = true;
if (! locals.contains(ast->name))
locals.append(ast->name);
virtual bool visit(FunctionDeclaration *ast)
{
+ env->enter(ast->name);
hasNestedFunctions = true;
if (! locals.contains(ast->name))
locals.append(ast->name);
}
};
-} // end of anonymous namespace
-
Codegen::Codegen()
- : _function(0)
+ : _module(0)
+ , _function(0)
, _block(0)
, _exitBlock(0)
, _returnAddress(0)
+ , _env(0)
{
}
{
_module = module;
+ Scope scope(this, newEnvironment());
ScanFunctionBody globalCodeInfo;
- globalCodeInfo(node);
+ globalCodeInfo(node, _env);
IR::Function *globalCode = _module->newFunction(QLatin1String("%entry"));
globalCode->hasDirectEval = globalCodeInfo.hasDirectEval;
foreach (IR::Function *function, _module->functions) {
linearize(function);
}
+
+ qDeleteAll(_allEnvironments);
+ _allEnvironments.clear();
}
IR::Expr *Codegen::member(IR::Expr *base, const QString *name)
move(_block->TEMP(-(index + 1)), *expr);
return;
}
+ Q_UNREACHABLE();
} else {
move(_block->NAME(ast->name.toString(), ast->identifierToken.startLine, ast->identifierToken.startColumn), *expr);
}
trace.append(exitBlock);
function->basicBlocks = trace;
+#ifndef QV4_NO_LIVENESS
liveness(function);
+#endif
static bool showCode = !qgetenv("SHOW_CODE").isNull();
if (showCode) {
s->dump(out, IR::Stmt::MIR);
out.flush();
+#ifndef QV4_NO_LIVENESS
for (int i = 60 - str.size(); i >= 0; --i)
str.append(' ');
qout << " %" << i;
}
}
+#else
+ qout << " " << str;
+#endif
qout << endl;
<< endl;
}
+#ifndef QV4_NO_LIVENESS
foreach (IR::BasicBlock *block, function->basicBlocks) {
foreach (IR::Stmt *s, block->statements)
s->destroyData();
}
+#endif
}
void Codegen::defineFunction(FunctionExpression *ast, bool /*isDeclaration*/)
{
+ Scope scope(this, newEnvironment());
ScanFunctionBody functionInfo;
- functionInfo(ast->body);
+ functionInfo(ast->body, _env);
IR::Function *function = _module->newFunction(ast->name.toString());
IR::BasicBlock *entryBlock = function->newBasicBlock();
}
};
+ struct Environment {
+ Environment *parent;
+ QHash<QStringRef, int> members;
+ int count;
+
+ Environment(Environment *parent = 0)
+ : parent(parent)
+ , count(0) {}
+
+ int findMember(const QStringRef &name) const
+ {
+ return members.value(name, -1);
+ }
+
+ bool lookupMember(const QStringRef &name, Environment **scope, int *index, int *distance)
+ {
+ Environment *it = this;
+ *distance = 0;
+ for (; it; it = it->parent, ++(*distance)) {
+ int idx = it->findMember(name);
+ if (idx != -1) {
+ *scope = it;
+ *index = idx;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void enter(const QStringRef &name)
+ {
+ int idx = members.value(name, -1);
+ if (idx == -1)
+ members.insert(name, count++);
+ }
+ };
+
+ Environment *newEnvironment()
+ {
+ Environment *scope = new Environment(_env);
+ return scope;
+ }
+
+ Environment *changeEnvironment(Environment *env)
+ {
+ qSwap(_env, env);
+ return env;
+ }
+
+ struct Scope {
+ Codegen *cg;
+ Environment *previous;
+ inline Scope(Codegen *cg, Environment *env) { previous = cg->changeEnvironment(env); }
+ inline ~Scope() { cg->changeEnvironment(previous); }
+
+ private:
+ Q_DISABLE_COPY(Scope)
+ };
+
struct UiMember {
};
IR::BasicBlock *_block;
IR::BasicBlock *_exitBlock;
unsigned _returnAddress;
+ QVector<Environment *> _allEnvironments;
+ Environment *_env;
+
+ struct ScanFunctionBody;
};
} // end of namespace QQmlJS
void Temp::dump(QTextStream &out)
{
- if (index < 0)
+ if (index < 0) {
out << '#' << -(index + 1); // negative and 1-based.
- else
+ } else {
out << '%' << index; // temp
+ }
}
void Closure::dump(QTextStream &out)
return function->tempCount++;
}
-Temp *BasicBlock::TEMP(unsigned index)
+Temp *BasicBlock::TEMP(int index)
{
Temp *e = function->New<Temp>();
e->init(IR::InvalidType, index);
unsigned newTemp();
- Temp *TEMP(unsigned index);
+ Temp *TEMP(int index);
Expr *CONST(Type type, double value);
Expr *STRING(const QString *value);
void InstructionSelection::operator()(IR::Function *function)
{
+ qSwap(_function, function);
+
_code = _codePtr;
_code = (uchar *) ((size_t(_code) + 15) & ~15);
- function->code = (void (*)(VM::Context *)) _code;
+ _function->code = (void (*)(VM::Context *)) _code;
_codePtr = _code;
- int locals = (function->tempCount + function->maxNumberOfArguments) * sizeof(Value);
+ int locals = (_function->tempCount + _function->maxNumberOfArguments) * sizeof(Value);
locals = (locals + 15) & ~15;
amd64_push_reg(_codePtr, AMD64_RBP);
amd64_alu_reg_reg(_codePtr, X86_XOR, AMD64_R15, AMD64_R15);
- foreach (IR::BasicBlock *block, function->basicBlocks) {
+ amd64_lea_membase(_codePtr, AMD64_RAX, AMD64_RSP, _function->maxNumberOfArguments * sizeof(Value));
+ amd64_mov_membase_reg(_codePtr, AMD64_R14, offsetof(Context, locals), AMD64_RAX, 8);
+
+
+ foreach (IR::BasicBlock *block, _function->basicBlocks) {
_block = block;
_addrs[block] = _codePtr;
foreach (IR::Stmt *s, block->statements) {
}
}
#endif
+ qSwap(_function, _function);
}
String *InstructionSelection::identifier(const QString &s)
amd64_mov_reg_membase(_codePtr, reg, AMD64_R14, offsetof(Context, arguments), 8);
amd64_lea_membase(_codePtr, reg, reg, sizeof(Value) * arg);
} else {
- amd64_lea_membase(_codePtr, reg, AMD64_RBP, sizeof(Value) * -t->index);
+ amd64_lea_membase(_codePtr, reg, AMD64_RSP, sizeof(Value) * (_function->maxNumberOfArguments + t->index));
}
}