From: Erik Verbruggen Date: Thu, 29 Nov 2012 13:41:26 +0000 (+0100) Subject: Add some debugging infrastructure to the interpreter. X-Git-Tag: upstream/5.2.1~669^2~659^2~775 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a14e7549c4a3faece3474f059b2d04005cfc7cbf;p=platform%2Fupstream%2Fqtdeclarative.git Add some debugging infrastructure to the interpreter. This currently mainly intended to be useful in a C++ debugger. The infrastructure makes it a lot easier to access (parent) contexts, find function names, etc. Change-Id: I0493d3a3bd4bf5c3a03379c1a2b545ed76862cd5 Reviewed-by: Lars Knoll --- diff --git a/debugging.cpp b/debugging.cpp new file mode 100644 index 0000000..741d5da --- /dev/null +++ b/debugging.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "debugging.h" +#include "qmljs_objects.h" + +#include + +using namespace QQmlJS; +using namespace QQmlJS::Debugging; + +FunctionState::FunctionState(VM::ExecutionContext *context) + : _context(context) +{ + if (debugger()) + debugger()->enterFunction(this); +} + +FunctionState::~FunctionState() +{ + if (debugger()) + debugger()->leaveFunction(this); +} + +VM::Value *FunctionState::argument(unsigned idx) +{ + if (idx < _context->variableEnvironment->argumentCount) + return _context->variableEnvironment->arguments + idx; + else + return 0; +} + +VM::Value *FunctionState::local(unsigned idx) +{ + if (idx < _context->variableEnvironment->varCount) + return _context->variableEnvironment->locals + idx; + else + return 0; +} + +Debugger::Debugger(VM::ExecutionEngine *engine) + : _engine(engine) +{ +} + +Debugger::~Debugger() +{ + qDeleteAll(_functionInfo.values()); +} + +void Debugger::addFunction(IR::Function *function) +{ + _functionInfo.insert(function, new FunctionDebugInfo(function)); +} + +void Debugger::addaddBasicBlockOffset(IR::Function *function, IR::BasicBlock *block, ptrdiff_t blockOffset) +{ + _functionInfo[function]->addBasicBlockOffset(block, blockOffset); +} + +void Debugger::setSourceLocation(IR::Function *function, unsigned line, unsigned column) +{ + _functionInfo[function]->setSourceLocation(line, column); +} + +FunctionDebugInfo *Debugger::debugInfo(VM::FunctionObject *function) const +{ + if (!function) + return 0; + + if (VM::ScriptFunction *sf = function->asScriptFunction()) + return _functionInfo[sf->function]; + else + return 0; +} + +QString Debugger::name(VM::FunctionObject *function) const +{ + if (FunctionDebugInfo *i = debugInfo(function)) + if (i->function) + if (const QString *n = i->function->name) + return *n; + + return QString(); +} + +void Debugger::aboutToCall(VM::FunctionObject *function, VM::ExecutionContext *context) +{ + _callStack.append(CallInfo(context, function)); +} + +void Debugger::justLeft(VM::ExecutionContext *context) +{ + int idx = callIndex(context); + if (idx < 0) + qDebug() << "Oops, leaving a function that was not registered...?"; + else + _callStack.resize(idx); +} + +void Debugger::enterFunction(FunctionState *state) +{ + _callStack[callIndex(state->context())].state = state; + +#ifdef DO_TRACE_INSTR + QString n = name(_callStack[callIndex(state->context())].function); + std::cerr << "*** Entering \"" << qPrintable(n) << "\" with" << state->context()->variableEnvironment->argumentCount << "args" << std::endl; + for (unsigned i = 0; i < state->context()->variableEnvironment->argumentCount; ++i) + std::cerr << " " << i << ": " << currentArg(i) << std::endl; +#endif // DO_TRACE_INSTR +} + +void Debugger::leaveFunction(FunctionState *state) +{ + _callStack[callIndex(state->context())].state = 0; +} + +void Debugger::aboutToThrow(VM::Value *value) +{ + qDebug() << "*** We are about to throw...:" << value->toString(currentState()->context())->toQString(); +} + +FunctionState *Debugger::currentState() const +{ + if (_callStack.isEmpty()) + return 0; + else + return _callStack.last().state; +} + +const char *Debugger::currentArg(unsigned idx) const +{ + FunctionState *state = currentState(); + return qPrintable(state->argument(idx)->toString(state->context())->toQString()); +} + +const char *Debugger::currentLocal(unsigned idx) const +{ + FunctionState *state = currentState(); + return qPrintable(state->local(idx)->toString(state->context())->toQString()); +} + +const char *Debugger::currentTemp(unsigned idx) const +{ + FunctionState *state = currentState(); + return qPrintable(state->temp(idx)->toString(state->context())->toQString()); +} + +int Debugger::callIndex(VM::ExecutionContext *context) +{ + for (int idx = _callStack.size() - 1; idx >= 0; --idx) { + if (_callStack[idx].context == context) + return idx; + } + + return -1; +} diff --git a/debugging.h b/debugging.h new file mode 100644 index 0000000..7a0a27d --- /dev/null +++ b/debugging.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef DEBUGGING_H +#define DEBUGGING_H + +#include "qmljs_engine.h" +#include "qmljs_environment.h" + +#include + +namespace QQmlJS { + +namespace IR { +struct BasicBlock; +struct Function; +} // namespace IR + +namespace Debugging { + +class Debugger; + +struct FunctionDebugInfo { // TODO: use opaque d-pointers here + IR::Function *function; + QHash blockOffsets; + unsigned startLine, startColumn; + + FunctionDebugInfo(IR::Function *function): function(function), startLine(0), startColumn(0) {} + + void addBasicBlockOffset(IR::BasicBlock *block, ptrdiff_t offset) { + blockOffsets.insert(offset, block); + } + + void setSourceLocation(unsigned line, unsigned column) + { startLine = line; startColumn = column; } +}; + +class FunctionState +{ +public: + FunctionState(VM::ExecutionContext *context); + virtual ~FunctionState(); + + virtual VM::Value *argument(unsigned idx); + virtual VM::Value *local(unsigned idx); + virtual VM::Value *temp(unsigned idx) = 0; + + VM::ExecutionContext *context() const + { return _context; } + + Debugger *debugger() const + { return _context->engine->debugger; } + +private: + VM::ExecutionContext *_context; +}; + +struct CallInfo +{ + VM::ExecutionContext *context; + VM::FunctionObject *function; + FunctionState *state; + + CallInfo(VM::ExecutionContext *context = 0, VM::FunctionObject *function = 0, FunctionState *state = 0) + : context(context) + , function(function) + , state(state) + {} +}; + +class Debugger +{ +public: + Debugger(VM::ExecutionEngine *_engine); + ~Debugger(); + +public: // compile-time interface + void addFunction(IR::Function *function); + void addaddBasicBlockOffset(IR::Function *function, IR::BasicBlock *block, ptrdiff_t blockOffset); + void setSourceLocation(IR::Function *function, unsigned line, unsigned column); + +public: // run-time querying interface + FunctionDebugInfo *debugInfo(VM::FunctionObject *function) const; + QString name(VM::FunctionObject *function) const; + +public: // execution hooks + void aboutToCall(VM::FunctionObject *function, VM::ExecutionContext *context); + void justLeft(VM::ExecutionContext *context); + void enterFunction(FunctionState *state); + void leaveFunction(FunctionState *state); + void aboutToThrow(VM::Value *value); + +public: // debugging hooks + FunctionState *currentState() const; + const char *currentArg(unsigned idx) const; + const char *currentLocal(unsigned idx) const; + const char *currentTemp(unsigned idx) const; + +private: + int callIndex(VM::ExecutionContext *context); + +private: // TODO: use opaque d-pointers here + VM::ExecutionEngine *_engine; + QHash _functionInfo; + QVector _callStack; +}; + +} // namespace Debugging +} // namespace QQmlJS + +#endif // DEBUGGING_H diff --git a/main.cpp b/main.cpp index dccac7e..8418dc1 100644 --- a/main.cpp +++ b/main.cpp @@ -43,6 +43,7 @@ # include "qv4_llvm_p.h" #endif +#include "debugging.h" #include "qmljs_objects.h" #include "qmljs_runtime.h" #include "qv4codegen_p.h" @@ -183,7 +184,7 @@ int compile(const QString &fileName, const QString &source, QQmlJS::LLVMOutputTy using namespace AST; Program *program = AST::cast(parser.rootNode()); - Codegen cg; + Codegen cg(0); // FIXME: if the program is empty, we should we generate an empty %entry, or give an error? /*IR::Function *globalCode =*/ cg(program, &module); @@ -246,6 +247,14 @@ int main(int argc, char *argv[]) #ifndef QMLJS_NO_LLVM QQmlJS::LLVMOutputType fileType = QQmlJS::LLVMOutputObject; #endif // QMLJS_NO_LLVM + bool enableDebugging = false; + + if (!args.isEmpty()) { + if (args.first() == QLatin1String("-d") || args.first() == QLatin1String("--debug")) { + enableDebugging = true; + args.removeFirst(); + } + } if (!args.isEmpty()) { if (args.first() == QLatin1String("--jit")) { @@ -287,7 +296,7 @@ int main(int argc, char *argv[]) } #endif // QMLJS_NO_LLVM if (args.first() == QLatin1String("--help")) { - std::cerr << "Usage: v4 [|--jit|--interpret|--compile|--aot|--llvm-jit] file..." << std::endl; + std::cerr << "Usage: v4 [|--debug|-d] [|--jit|--interpret|--compile|--aot|--llvm-jit] file..." << std::endl; return EXIT_SUCCESS; } } @@ -314,7 +323,14 @@ int main(int argc, char *argv[]) iSelFactory.reset(new QQmlJS::Moth::ISelFactory); else iSelFactory.reset(new QQmlJS::MASM::ISelFactory); + QQmlJS::VM::ExecutionEngine vm(iSelFactory.data()); + + QScopedPointer debugger; + if (enableDebugging) + debugger.reset(new QQmlJS::Debugging::Debugger(&vm)); + vm.debugger = debugger.data(); + QQmlJS::VM::ExecutionContext *ctx = vm.rootContext; QQmlJS::VM::Object *globalObject = vm.globalObject.objectValue(); @@ -338,11 +354,15 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - QQmlJS::IR::Function *f = QQmlJS::VM::EvalFunction::parseSource(vm.rootContext, fn, code, QQmlJS::Codegen::GlobalCode); + QQmlJS::IR::Function *f = QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode); if (!f) continue; ctx->lexicalEnvironment->strictMode = f->isStrict; + if (debugger) + debugger->aboutToCall(0, ctx); QQmlJS::VM::Value result = f->code(ctx, f->codeData); + if (debugger) + debugger->justLeft(ctx); if (!result.isUndefined()) { if (! qgetenv("SHOW_EXIT_VALUE").isEmpty()) std::cout << "exit value: " << qPrintable(result.toString(ctx)->toQString()) << std::endl; diff --git a/moth/qv4isel_moth.cpp b/moth/qv4isel_moth.cpp index 94a06d3..482d063 100644 --- a/moth/qv4isel_moth.cpp +++ b/moth/qv4isel_moth.cpp @@ -1,6 +1,7 @@ #include "qv4isel_util_p.h" #include "qv4isel_moth_p.h" #include "qv4vme_moth_p.h" +#include "debugging.h" using namespace QQmlJS; using namespace QQmlJS::Moth; @@ -209,7 +210,10 @@ void InstructionSelection::operator()(IR::Function *function) addInstruction(push); foreach (_block, _function->basicBlocks) { + ptrdiff_t blockOffset = _ccode - _code; _addrs.insert(_block, _ccode - _code); + if (_engine->debugger) + _engine->debugger->addaddBasicBlockOffset(_function, _block, blockOffset); foreach (IR::Stmt *s, _block->statements) s->accept(this); diff --git a/moth/qv4vme_moth.cpp b/moth/qv4vme_moth.cpp index 87d50a3..92e7c7c 100644 --- a/moth/qv4vme_moth.cpp +++ b/moth/qv4vme_moth.cpp @@ -1,6 +1,9 @@ #include "qv4vme_moth_p.h" #include "qv4instr_moth_p.h" #include "qmljs_value.h" +#include "debugging.h" + +#include #ifdef DO_TRACE_INSTR # define TRACE_INSTR(I) fprintf(stderr, "executing a %s\n", #I); @@ -92,6 +95,22 @@ static inline VM::Value *tempValue(QQmlJS::VM::ExecutionContext *context, QVecto } } +class FunctionState: public Debugging::FunctionState +{ +public: + FunctionState(QQmlJS::VM::ExecutionContext *context, QVector *stack, const uchar **code) + : Debugging::FunctionState(context) + , stack(stack) + , code(code) + {} + + virtual VM::Value *temp(unsigned idx) { return stack->data() + idx; } + +private: + QVector *stack; + const uchar **code; +}; + #define TEMP(index) *tempValue(context, stack, index) VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *code @@ -114,6 +133,7 @@ VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *co #endif QVector stack; + FunctionState state(context, &stack, &code); #ifdef MOTH_THREADED_INTERPRETER const Instr *genericInstr = reinterpret_cast(code); diff --git a/qmljs_engine.cpp b/qmljs_engine.cpp index a1b3256..1609559 100644 --- a/qmljs_engine.cpp +++ b/qmljs_engine.cpp @@ -62,6 +62,7 @@ struct StringPool ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) : iselFactory(factory) + , debugger(0) { stringPool = new StringPool; diff --git a/qmljs_engine.h b/qmljs_engine.h index dcae173..9b91f01 100644 --- a/qmljs_engine.h +++ b/qmljs_engine.h @@ -47,6 +47,11 @@ #include namespace QQmlJS { + +namespace Debugging { +class Debugger; +} // namespace Debugging + namespace VM { struct Value; @@ -87,6 +92,8 @@ struct ExecutionEngine ExecutionContext *current; ExecutionContext *rootContext; + Debugging::Debugger *debugger; + Value globalObject; Value objectCtor; @@ -184,7 +191,6 @@ struct ExecutionEngine Object *newForEachIteratorObject(Object *o); }; - } // namespace VM } // namespace QQmlJS diff --git a/qmljs_environment.cpp b/qmljs_environment.cpp index 1b073ef..e9b55a8 100644 --- a/qmljs_environment.cpp +++ b/qmljs_environment.cpp @@ -38,6 +38,8 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + +#include "debugging.h" #include #include #include @@ -315,6 +317,9 @@ void ExecutionContext::initCallContext(ExecutionContext *parent, const Value tha lexicalEnvironment = variableEnvironment; thisObject = that; + + if (engine->debugger) + engine->debugger->aboutToCall(f, this); } void ExecutionContext::leaveCallContext() @@ -327,6 +332,9 @@ void ExecutionContext::leaveCallContext() delete variableEnvironment; variableEnvironment = 0; + + if (engine->debugger) + engine->debugger->justLeft(this); } void ExecutionContext::initConstructorContext(ExecutionContext *parent, Value that, FunctionObject *f, Value *args, unsigned argc) diff --git a/qmljs_objects.cpp b/qmljs_objects.cpp index 28932e3..302e574 100644 --- a/qmljs_objects.cpp +++ b/qmljs_objects.cpp @@ -39,7 +39,6 @@ ** ****************************************************************************/ - #include "qmljs_objects.h" #include "qv4ir_p.h" #include "qv4isel_p.h" @@ -564,7 +563,7 @@ QQmlJS::IR::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ct return 0; } - Codegen cg; + Codegen cg(ctx->engine->debugger); globalCode = cg(program, &module, mode); if (globalCode) { // only generate other functions if global code generation succeeded. diff --git a/qmljs_objects.h b/qmljs_objects.h index 957a562..4e0af58 100644 --- a/qmljs_objects.h +++ b/qmljs_objects.h @@ -516,6 +516,8 @@ struct FunctionObject: Object { Value construct(ExecutionContext *context, Value *args, int argc); virtual Value call(ExecutionContext *context, Value thisObject, Value *args, int argc); + virtual struct ScriptFunction *asScriptFunction() { return 0; } + protected: virtual Value call(ExecutionContext *ctx); virtual Value construct(ExecutionContext *ctx); @@ -537,6 +539,8 @@ struct ScriptFunction: FunctionObject { virtual Value call(ExecutionContext *ctx); virtual Value construct(ExecutionContext *ctx); + + virtual ScriptFunction *asScriptFunction() { return this; } }; struct EvalFunction : FunctionObject diff --git a/qmljs_runtime.cpp b/qmljs_runtime.cpp index 1aa3c94..6779f86 100644 --- a/qmljs_runtime.cpp +++ b/qmljs_runtime.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#include "debugging.h" #include "qmljs_runtime.h" #include "qmljs_objects.h" #include "qv4ir_p.h" @@ -777,6 +778,9 @@ void __qmljs_throw(Value value, ExecutionContext *context) { assert(!context->engine->unwindStack.isEmpty()); + if (context->engine->debugger) + context->engine->debugger->aboutToThrow(&value); + ExecutionEngine::ExceptionHandler &handler = context->engine->unwindStack.last(); // clean up call contexts diff --git a/qv4codegen.cpp b/qv4codegen.cpp index 0f3cedb..1980ed9 100644 --- a/qv4codegen.cpp +++ b/qv4codegen.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qv4codegen_p.h" +#include "debugging.h" #include #include @@ -352,7 +353,7 @@ protected: QStack _envStack; }; -Codegen::Codegen() +Codegen::Codegen(Debugging::Debugger *debugger) : _module(0) , _function(0) , _block(0) @@ -363,6 +364,7 @@ Codegen::Codegen() , _env(0) , _loop(0) , _labelledStatement(0) + , _debugger(debugger) { } @@ -377,6 +379,12 @@ IR::Function *Codegen::operator()(Program *node, IR::Module *module, Mode mode) scan(node); IR::Function *globalCode = defineFunction(QStringLiteral("%entry"), node, 0, node->elements, mode); + if (_debugger) { + if (node->elements->element) { + SourceLocation loc = node->elements->element->firstSourceLocation(); + _debugger->setSourceLocation(globalCode, loc.startLine, loc.startColumn); + } + } foreach (IR::Function *function, _module->functions) { linearize(function); @@ -397,6 +405,8 @@ IR::Function *Codegen::operator()(AST::FunctionExpression *ast, IR::Module *modu scan(ast); IR::Function *function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0); + if (_debugger) + _debugger->setSourceLocation(function, ast->functionToken.startLine, ast->functionToken.startColumn); foreach (IR::Function *function, _module->functions) { linearize(function); @@ -1168,6 +1178,8 @@ bool Codegen::visit(FieldMemberExpression *ast) bool Codegen::visit(FunctionExpression *ast) { IR::Function *function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0); + if (_debugger) + _debugger->setSourceLocation(function, ast->functionToken.startLine, ast->functionToken.startColumn); _expr.code = _block->CLOSURE(function); return false; } @@ -1570,6 +1582,8 @@ IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast, enterEnvironment(ast); IR::Function *function = _module->newFunction(name); + if (_debugger) + _debugger->addFunction(function); IR::BasicBlock *entryBlock = function->newBasicBlock(); IR::BasicBlock *exitBlock = function->newBasicBlock(IR::Function::DontInsertBlock); IR::BasicBlock *throwBlock = function->newBasicBlock(); @@ -1626,6 +1640,8 @@ IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast, foreach (AST::FunctionDeclaration *f, _env->functions) { IR::Function *function = defineFunction(f->name.toString(), f, f->formals, f->body ? f->body->elements : 0); + if (_debugger) + _debugger->setSourceLocation(function, f->functionToken.startLine, f->functionToken.startColumn); if (! _env->parent) move(_block->NAME(f->name.toString(), f->identifierToken.startLine, f->identifierToken.startColumn), _block->CLOSURE(function)); diff --git a/qv4codegen_p.h b/qv4codegen_p.h index 4952c69..27c910f 100644 --- a/qv4codegen_p.h +++ b/qv4codegen_p.h @@ -50,10 +50,14 @@ namespace AST { class UiParameterList; } +namespace Debugging { +class Debugger; +} // namespace Debugging + class Codegen: protected AST::Visitor { public: - Codegen(); + Codegen(Debugging::Debugger *debugger); enum Mode { GlobalCode, @@ -330,6 +334,7 @@ private: AST::LabelledStatement *_labelledStatement; QHash _envMap; QHash _functionMap; + Debugging::Debugger *_debugger; class ScanFunctions; }; diff --git a/qv4ecmaobjects.cpp b/qv4ecmaobjects.cpp index 9fd95b9..7adb16e 100644 --- a/qv4ecmaobjects.cpp +++ b/qv4ecmaobjects.cpp @@ -1892,7 +1892,7 @@ Value FunctionCtor::construct(ExecutionContext *ctx) IR::Module module; - Codegen cg; + Codegen cg(ctx->engine->debugger); IR::Function *irf = cg(fe, &module); EvalInstructionSelection *isel = ctx->engine->iselFactory->create(ctx->engine); diff --git a/qv4isel_llvm.cpp b/qv4isel_llvm.cpp index 80c55d2..5ea5df9 100644 --- a/qv4isel_llvm.cpp +++ b/qv4isel_llvm.cpp @@ -720,6 +720,7 @@ void LLVMInstructionSelection::visitClosure(IR::Closure *e) { llvm::Value *tmp = newLLVMTemp(_valueTy); llvm::Value *clos = getLLVMFunction(e->value); + assert("!broken: pass function name!"); CreateCall3(_llvmModule->getFunction("__qmljs_llvm_init_native_function"), _llvmFunction->arg_begin(), tmp, clos); _llvmValue = CreateLoad(tmp); diff --git a/v4.pro b/v4.pro index 1a6e2a4..24ab7c0 100644 --- a/v4.pro +++ b/v4.pro @@ -23,7 +23,8 @@ SOURCES += main.cpp \ qv4array.cpp \ qv4isel_masm.cpp \ llvm_runtime.cpp \ - qv4isel_p.cpp + qv4isel_p.cpp \ + debugging.cpp HEADERS += \ qv4codegen_p.h \ @@ -39,7 +40,8 @@ HEADERS += \ qv4array_p.h \ qv4isel_masm_p.h \ qv4isel_p.h \ - qv4isel_util_p.h + qv4isel_util_p.h \ + debugging.h llvm {