bool bailed_out() const { return compilation()->bailed_out(); }
// unified bailout support void bailout(const char* msg) const { compilation()->bailout(msg); }
void increment_invocation_counter(CodeEmitInfo *info) { if (compilation()->count_invocations()) { increment_event_counter(info, InvocationEntryBci, false); } }
void increment_backedge_counter(CodeEmitInfo* info, int bci) { if (compilation()->count_backedges()) { increment_event_counter(info, bci, true); } }
void LIR_Assembler::emit_op1(LIR_Op1* op) { switch (op->code()) { case lir_move: if (op->move_kind() == lir_move_volatile) { assert(op->patch_code() == lir_patch_none, "can't patch volatiles"); volatile_move_op(op->in_opr(), op->result_opr(), op->type(), op->info()); } else { move_op(op->in_opr(), op->result_opr(), op->type(), op->patch_code(), op->info(), op->pop_fpu_stack(), op->move_kind() == lir_move_unaligned, op->move_kind() == lir_move_wide); } break; case lir_roundfp: { LIR_OpRoundFP* round_op = op->as_OpRoundFP(); roundfp_op(round_op->in_opr(), round_op->tmp(), round_op->result_opr(), round_op->pop_fpu_stack()); break; } case lir_return: return_op(op->in_opr()); break; case lir_safepoint: if (compilation()->debug_info_recorder()->last_pc_offset() == code_offset()) { _masm->nop(); } safepoint_poll(op->in_opr(), op->info()); break; case lir_fxch: fxch(op->in_opr()->as_jint()); break; case lir_fld: fld(op->in_opr()->as_jint()); break; case lir_ffree: ffree(op->in_opr()->as_jint()); break; case lir_branch: break; case lir_push: push(op->in_opr()); break; case lir_pop: pop(op->in_opr()); break; case lir_neg: negate(op->in_opr(), op->result_opr()); break; case lir_leal: leal(op->in_opr(), op->result_opr()); break; case lir_null_check: if (GenerateCompilerNullChecks) { ImplicitNullCheckStub* stub = add_debug_info_for_null_check_here(op->info()); if (op->in_opr()->is_single_cpu()) { _masm->null_check(op->in_opr()->as_register(), stub->entry()); } else { Unimplemented(); } } break; case lir_monaddr: monitor_address(op->in_opr()->as_constant_ptr()->as_jint(), op->result_opr()); break; #ifdef SPARC case lir_pack64: pack64(op->in_opr(), op->result_opr()); break; case lir_unpack64: unpack64(op->in_opr(), op->result_opr()); break; #endif case lir_unwind: unwind_op(op->in_opr()); break; default: Unimplemented(); break; } }
void LIR_Assembler::emit_op0(LIR_Op0* op) { switch (op->code()) { case lir_word_align: { _masm->align(BytesPerWord); break; } case lir_nop: assert(op->info() == NULL, "not supported"); _masm->nop(); break; case lir_label: Unimplemented(); break; case lir_build_frame: build_frame(); break; case lir_std_entry: // init offsets offsets()->set_value(CodeOffsets::OSR_Entry, _masm->offset()); _masm->align(CodeEntryAlignment); if (needs_icache(compilation()->method())) { check_icache(); } offsets()->set_value(CodeOffsets::Verified_Entry, _masm->offset()); _masm->verified_entry(); build_frame(); offsets()->set_value(CodeOffsets::Frame_Complete, _masm->offset()); break; case lir_osr_entry: offsets()->set_value(CodeOffsets::OSR_Entry, _masm->offset()); osr_entry(); break; case lir_24bit_FPU: set_24bit_FPU(); break; case lir_reset_FPU: reset_FPU(); break; case lir_breakpoint: breakpoint(); break; case lir_fpop_raw: fpop(); break; case lir_membar: membar(); break; case lir_membar_acquire: membar_acquire(); break; case lir_membar_release: membar_release(); break; case lir_membar_loadload: membar_loadload(); break; case lir_membar_storestore: membar_storestore(); break; case lir_membar_loadstore: membar_loadstore(); break; case lir_membar_storeload: membar_storeload(); break; case lir_get_thread: get_thread(op->result_opr()); break; default: ShouldNotReachHere(); break; } }
bool CompilerEngine::compileCode(const QString &pCode) { // Reset our compiler engine reset(); // Determine our target triple // Note: normally, we would call llvm::sys::getProcessTriple(), but this // returns the information about the system on which LLVM was built. // In most cases it is fine, but on OS X it may be a problem. Indeed, // with OS X 10.9, Apple decided to extend the C standard by adding // some functions (e.g. __exp10()). So, if the given code needs one of // those functions, then OpenCOR will crash if run on an 'old' version // of OS X. So, to avoid this issue, we set the target triple // ourselves, based on the system on which OpenCOR is being used... std::string targetTriple; #if defined(Q_OS_WIN) targetTriple = (sizeof(void *) == 4)?"i686-pc-windows-msvc-elf":"x86_64-pc-windows-msvc-elf"; // Note: MCJIT currently works only through the ELF object format, hence we // are appending "-elf"... #elif defined(Q_OS_LINUX) targetTriple = (sizeof(void *) == 4)?"i686-pc-linux-gnu":"x86_64-pc-linux-gnu"; #elif defined(Q_OS_MAC) targetTriple = "x86_64-apple-darwin"+std::to_string(QSysInfo::MacintoshVersion+2); #else #error Unsupported platform #endif // Get a driver to compile our code #ifdef QT_DEBUG llvm::raw_ostream &outputStream = llvm::outs(); #else llvm::raw_ostream &outputStream = llvm::nulls(); #endif llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagnosticOptions = new clang::DiagnosticOptions(); clang::DiagnosticsEngine diagnosticsEngine(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(new clang::DiagnosticIDs()), &*diagnosticOptions, new clang::TextDiagnosticPrinter(outputStream, &*diagnosticOptions)); clang::driver::Driver driver("clang", targetTriple, diagnosticsEngine); driver.setCheckInputsExist(false); // Get a compilation object to which we pass some arguments llvm::StringRef dummyFileName("dummyFile.c"); llvm::SmallVector<const char *, 16> compilationArguments; compilationArguments.push_back("clang"); compilationArguments.push_back("-fsyntax-only"); compilationArguments.push_back("-O3"); compilationArguments.push_back("-ffast-math"); compilationArguments.push_back("-Werror"); compilationArguments.push_back(dummyFileName.data()); std::unique_ptr<clang::driver::Compilation> compilation(driver.BuildCompilation(compilationArguments)); if (!compilation) { mError = tr("the compilation object could not be created"); return false; } // The compilation object should have only one command, so if it doesn't // then something went wrong const clang::driver::JobList &jobList = compilation->getJobs(); if ( (jobList.size() != 1) || !llvm::isa<clang::driver::Command>(*jobList.begin())) { mError = tr("the compilation object must contain only one command"); return false; } // Retrieve the command job const clang::driver::Command &command = llvm::cast<clang::driver::Command>(*jobList.begin()); QString commandName = command.getCreator().getName(); if (commandName.compare("clang")) { mError = tr("a <strong>clang</strong> command was expected, but a <strong>%1</strong> command was found instead").arg(commandName); return false; } // Create a compiler invocation using our command's arguments const clang::driver::ArgStringList &commandArguments = command.getArguments(); std::unique_ptr<clang::CompilerInvocation> compilerInvocation(new clang::CompilerInvocation()); clang::CompilerInvocation::CreateFromArgs(*compilerInvocation, commandArguments.data(), commandArguments.data()+commandArguments.size(), diagnosticsEngine); // Map our dummy file to a memory buffer QByteArray codeByteArray = pCode.toUtf8(); compilerInvocation->getPreprocessorOpts().addRemappedFile(dummyFileName, llvm::MemoryBuffer::getMemBuffer(codeByteArray.constData()).release()); // Create a compiler instance to handle the actual work clang::CompilerInstance compilerInstance; compilerInstance.setInvocation(compilerInvocation.release()); // Create the compiler instance's diagnostics engine compilerInstance.createDiagnostics(); if (!compilerInstance.hasDiagnostics()) { mError = tr("the diagnostics engine could not be created"); return false; } // Create and execute the frontend to generate an LLVM bitcode module // Note: the LLVM team has been meaning to modify // CompilerInstance::ExecuteAction() so that we could specify the // output stream we want to use (rather than always use llvm::errs()), // but they have yet to actually do it, so we modified it ourselves... std::unique_ptr<clang::CodeGenAction> codeGenerationAction(new clang::EmitLLVMOnlyAction(&llvm::getGlobalContext())); if (!compilerInstance.ExecuteAction(*codeGenerationAction, outputStream)) { mError = tr("the code could not be compiled"); reset(false); return false; } // Retrieve the LLVM bitcode module std::unique_ptr<llvm::Module> module = codeGenerationAction->takeModule(); // Initialise the native target (and its ASM printer), so not only can we // then create an execution engine, but more importantly its data layout // will match that of our target platform llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); // Create and keep track of an execution engine mExecutionEngine = std::unique_ptr<llvm::ExecutionEngine>(llvm::EngineBuilder(std::move(module)).setEngineKind(llvm::EngineKind::JIT).create()); if (!mExecutionEngine) { mError = tr("the execution engine could not be created"); delete module.release(); return false; } return true; }
ciMethod* method() const { return compilation()->method(); }
ValueStack* copy_state_if_bb(bool is_bb) { return (is_bb || compilation()->is_optimistic()) ? copy_state_before() : NULL; }
ValueStack* copy_state_indexed_access() { return compilation()->is_optimistic() ? copy_state_before() : copy_state_for_exception(); }
void LIRGenerator::do_Base(Base* x) { emit()->std_entry(scope(), compilation()->get_init_vars(), receiverRInfo(), icKlassRInfo()); }
// Compute a CPData offset for the current method & bci int find_cpdoff() const { return compilation()->get_cpdata() + sizeof(CodeProfile) + method()->bci2cpd_map()->bci_to_cpdoff(bci()); }
void LIR_Assembler::add_debug_info_for_branch(CodeEmitInfo* info) { masm()->add_dbg( code_offset(), info->debug_scope() ); if (info->exception_handlers() != NULL) { compilation()->add_exception_handlers_for_pco(code_offset(),info->exception_handlers()); } }
bool Compiler::addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors) { Q_D(Compiler); const QString &importUri = stringAt(import->uriIndex); const QString &importQualifier = stringAt(import->qualifierIndex); if (import->type == QV4::CompiledData::Import::ImportScript) { // TBD: qqmltypeloader.cpp:1320 QmlCompilation::ScriptReference scriptRef; scriptRef.location = import->location; scriptRef.qualifier = importQualifier; scriptRef.compilation = NULL; d->compilation->scripts.append(scriptRef); } else if (import->type == QV4::CompiledData::Import::ImportLibrary) { QString qmldirFilePath; QString qmldirUrl; if (QQmlMetaType::isLockedModule(importUri, import->majorVersion)) { //Locked modules are checked first, to save on filesystem checks if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, QString(), QString(), false, errors)) return false; } else if (d->compilation->importCache->locateQmldir(d->compilation->importDatabase, importUri, import->majorVersion, import->minorVersion, &qmldirFilePath, &qmldirUrl)) { // This is a local library import if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, qmldirFilePath, qmldirUrl, false, errors)) return false; if (!importQualifier.isEmpty()) { // Does this library contain any qualified scripts? QUrl libraryUrl(qmldirUrl); QQmlTypeLoader* typeLoader = &QQmlEnginePrivate::get(d->compilation->engine)->typeLoader; const QQmlTypeLoader::QmldirContent *qmldir = typeLoader->qmldirContent(qmldirFilePath, qmldirUrl); // File loading will import the dependency and takes care of // everything there. Adding a script reference here just seems // to add an unnecessary reference that might actually be a bug. // In case something is needed, see: qqmltypeloader.cpp:1343 } } else { // Is this a module? qDebug() << "Importing local module" << importUri; if (QQmlMetaType::isAnyModule(importUri)) { if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, QString(), QString(), false, errors)) return false; } else { QQmlError error; error.setDescription("Unresolved import " + importUri); error.setLine(import->location.line); error.setColumn(import->location.column); error.setUrl(d->compilation->url); appendError(error); return false; // TBD: else add to unresolved imports qqmltypeloader.cpp:1356 } } } else { // qqmltypeloader.cpp:1383 Q_ASSERT(import->type == QV4::CompiledData::Import::ImportFile); QUrl qmldirUrl; if (importQualifier.isEmpty()) { qmldirUrl = compilation()->loadUrl.resolved(QUrl(importUri + QLatin1String("/qmldir"))); if (!QQmlImports::isLocal(qmldirUrl)) { qDebug() << "File import from network not supported"; QQmlError error; error.setDescription("File import from network not supported"); errors->append(error); return false; } } if (!compilation()->importCache->addFileImport(compilation()->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, /*incomplete*/ false, errors)) return false; } return true; }
bool CompilerEngine::compileCode(const QString &pCode) { // Prepend all the external functions that may, or not, be needed by the // given code // Note: indeed, we cannot include header files since we don't (and don't // want in order to avoid complications) deploy them with OpenCOR. So, // instead, we must declare as external functions all the functions // that we would normally use through header files... QString code = "extern double fabs(double);\n" "\n" "extern double log(double);\n" "extern double exp(double);\n" "\n" "extern double floor(double);\n" "extern double ceil(double);\n" "\n" "extern double factorial(double);\n" "\n" "extern double sin(double);\n" "extern double sinh(double);\n" "extern double asin(double);\n" "extern double asinh(double);\n" "\n" "extern double cos(double);\n" "extern double cosh(double);\n" "extern double acos(double);\n" "extern double acosh(double);\n" "\n" "extern double tan(double);\n" "extern double tanh(double);\n" "extern double atan(double);\n" "extern double atanh(double);\n" "\n" "extern double sec(double);\n" "extern double sech(double);\n" "extern double asec(double);\n" "extern double asech(double);\n" "\n" "extern double csc(double);\n" "extern double csch(double);\n" "extern double acsc(double);\n" "extern double acsch(double);\n" "\n" "extern double cot(double);\n" "extern double coth(double);\n" "extern double acot(double);\n" "extern double acoth(double);\n" "\n" "extern double arbitrary_log(double, double);\n" "\n" "extern double pow(double, double);\n" "\n" "extern double multi_min(int, ...);\n" "extern double multi_max(int, ...);\n" "\n" "extern double gcd_multi(int, ...);\n" "extern double lcm_multi(int, ...);\n" "\n" +pCode; // Reset our compiler engine reset(); // Determine our target triple // Note: normally, we would call llvm::sys::getProcessTriple(), but this // returns the information about the system on which LLVM was built. // In most cases it is fine, but on OS X it may be a problem. Indeed, // with OS X 10.9, Apple decided to extend the C standard by adding // some functions (e.g. __exp10()). So, if the given code needs one of // those functions, then OpenCOR will crash if run on an 'old' version // of OS X. So, to avoid this issue, we set the target triple // ourselves, based on the system on which OpenCOR is to be used... std::string targetTriple; #if defined(Q_OS_WIN) targetTriple = "x86_64-pc-windows-msvc-elf"; // Note: MCJIT currently works only through the ELF object format, hence we // are appending "-elf"... #elif defined(Q_OS_LINUX) targetTriple = "x86_64-pc-linux-gnu"; #elif defined(Q_OS_MAC) targetTriple = "x86_64-apple-darwin"+std::to_string(QSysInfo::MacintoshVersion+2); #else #error Unsupported platform #endif // Get a driver to compile our code llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagnosticOptions = new clang::DiagnosticOptions(); clang::DiagnosticsEngine diagnosticsEngine(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(new clang::DiagnosticIDs()), &*diagnosticOptions); clang::driver::Driver driver("clang", targetTriple, diagnosticsEngine); driver.setCheckInputsExist(false); // Get a compilation object to which we pass some arguments llvm::StringRef dummyFileName("dummyFile.c"); llvm::SmallVector<const char *, 16> compilationArguments; compilationArguments.push_back("clang"); compilationArguments.push_back("-fsyntax-only"); compilationArguments.push_back("-O3"); compilationArguments.push_back("-ffast-math"); compilationArguments.push_back("-Werror"); compilationArguments.push_back(dummyFileName.data()); std::unique_ptr<clang::driver::Compilation> compilation(driver.BuildCompilation(compilationArguments)); if (!compilation) { mError = tr("the compilation object could not be created"); return false; } // The compilation object should have only one command, so if it doesn't // then something went wrong const clang::driver::JobList &jobList = compilation->getJobs(); if ( (jobList.size() != 1) || !llvm::isa<clang::driver::Command>(*jobList.begin())) { mError = tr("the compilation object must contain only one command"); return false; } // Retrieve the command job const clang::driver::Command &command = llvm::cast<clang::driver::Command>(*jobList.begin()); QString commandName = command.getCreator().getName(); if (commandName.compare("clang")) { mError = tr("a <strong>clang</strong> command was expected, but a <strong>%1</strong> command was found instead").arg(commandName); return false; } // Create a compiler invocation using our command's arguments const clang::driver::ArgStringList &commandArguments = command.getArguments(); std::unique_ptr<clang::CompilerInvocation> compilerInvocation(new clang::CompilerInvocation()); clang::CompilerInvocation::CreateFromArgs(*compilerInvocation, commandArguments.data(), commandArguments.data()+commandArguments.size(), diagnosticsEngine); // Map our dummy file to a memory buffer QByteArray codeByteArray = code.toUtf8(); compilerInvocation->getPreprocessorOpts().addRemappedFile(dummyFileName, llvm::MemoryBuffer::getMemBuffer(codeByteArray.constData()).release()); // Create a compiler instance to handle the actual work clang::CompilerInstance compilerInstance; compilerInstance.setInvocation(compilerInvocation.release()); // Create the compiler instance's diagnostics engine compilerInstance.createDiagnostics(); if (!compilerInstance.hasDiagnostics()) { mError = tr("the diagnostics engine could not be created"); return false; } // Create and execute the frontend to generate an LLVM bitcode module std::unique_ptr<clang::CodeGenAction> codeGenerationAction(new clang::EmitLLVMOnlyAction(&llvm::getGlobalContext())); if (!compilerInstance.ExecuteAction(*codeGenerationAction)) { mError = tr("the code could not be compiled"); reset(false); return false; } // Retrieve the LLVM bitcode module std::unique_ptr<llvm::Module> module = codeGenerationAction->takeModule(); // Initialise the native target (and its ASM printer), so not only can we // then create an execution engine, but more importantly its data layout // will match that of our target platform llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); // Create and keep track of an execution engine mExecutionEngine = std::unique_ptr<llvm::ExecutionEngine>(llvm::EngineBuilder(std::move(module)).setEngineKind(llvm::EngineKind::JIT).create()); if (!mExecutionEngine) { mError = tr("the execution engine could not be created"); delete module.release(); return false; } // Map all the external functions that may, or not, be needed by the given // code #if defined(Q_OS_WIN) || defined(Q_OS_LINUX) #define FUNCTION_NAME(x) (x) #elif defined(Q_OS_MAC) #define FUNCTION_NAME(x) (std::string(std::string("_")+(x)).c_str()) #else #error Unsupported platform #endif mExecutionEngine->addGlobalMapping(FUNCTION_NAME("fabs"), (uint64_t) compiler_fabs); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("log"), (uint64_t) compiler_log); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("exp"), (uint64_t) compiler_exp); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("floor"), (uint64_t) compiler_floor); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("ceil"), (uint64_t) compiler_ceil); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("factorial"), (uint64_t) compiler_factorial); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("sin"), (uint64_t) compiler_sin); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("sinh"), (uint64_t) compiler_sinh); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("asin"), (uint64_t) compiler_asin); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("asinh"), (uint64_t) compiler_asinh); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("cos"), (uint64_t) compiler_cos); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("cosh"), (uint64_t) compiler_cosh); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("acos"), (uint64_t) compiler_acos); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("acosh"), (uint64_t) compiler_acosh); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("tan"), (uint64_t) compiler_tan); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("tanh"), (uint64_t) compiler_tanh); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("atan"), (uint64_t) compiler_atan); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("atanh"), (uint64_t) compiler_atanh); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("sec"), (uint64_t) compiler_sec); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("sech"), (uint64_t) compiler_sech); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("asec"), (uint64_t) compiler_asec); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("asech"), (uint64_t) compiler_asech); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("csc"), (uint64_t) compiler_csc); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("csch"), (uint64_t) compiler_csch); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("acsc"), (uint64_t) compiler_acsc); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("acsch"), (uint64_t) compiler_acsch); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("cot"), (uint64_t) compiler_cot); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("coth"), (uint64_t) compiler_coth); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("acot"), (uint64_t) compiler_acot); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("acoth"), (uint64_t) compiler_acoth); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("arbitrary_log"), (uint64_t) compiler_arbitrary_log); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("pow"), (uint64_t) compiler_pow); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("multi_min"), (uint64_t) compiler_multi_min); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("multi_max"), (uint64_t) compiler_multi_max); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("gcd_multi"), (uint64_t) compiler_gcd_multi); mExecutionEngine->addGlobalMapping(FUNCTION_NAME("lcm_multi"), (uint64_t) compiler_lcm_multi); return true; }