twisti@2047: /* stefank@2314: * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. twisti@2729: * Copyright 2008, 2009, 2010, 2011 Red Hat, Inc. twisti@2047: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. twisti@2047: * twisti@2047: * This code is free software; you can redistribute it and/or modify it twisti@2047: * under the terms of the GNU General Public License version 2 only, as twisti@2047: * published by the Free Software Foundation. twisti@2047: * twisti@2047: * This code is distributed in the hope that it will be useful, but WITHOUT twisti@2047: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or twisti@2047: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License twisti@2047: * version 2 for more details (a copy is included in the LICENSE file that twisti@2047: * accompanied this code). twisti@2047: * twisti@2047: * You should have received a copy of the GNU General Public License version twisti@2047: * 2 along with this work; if not, write to the Free Software Foundation, twisti@2047: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. twisti@2047: * twisti@2047: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA twisti@2047: * or visit www.oracle.com if you need additional information or have any twisti@2047: * questions. twisti@2047: * twisti@2047: */ twisti@2047: stefank@2314: #include "precompiled.hpp" stefank@2314: #include "ci/ciEnv.hpp" stefank@2314: #include "ci/ciMethod.hpp" stefank@2314: #include "code/debugInfoRec.hpp" stefank@2314: #include "code/dependencies.hpp" stefank@2314: #include "code/exceptionHandlerTable.hpp" stefank@2314: #include "code/oopRecorder.hpp" stefank@2314: #include "compiler/abstractCompiler.hpp" stefank@2314: #include "compiler/oopMap.hpp" stefank@2314: #include "shark/llvmHeaders.hpp" stefank@2314: #include "shark/sharkBuilder.hpp" stefank@2314: #include "shark/sharkCodeBuffer.hpp" stefank@2314: #include "shark/sharkCompiler.hpp" stefank@2314: #include "shark/sharkContext.hpp" stefank@2314: #include "shark/sharkEntry.hpp" stefank@2314: #include "shark/sharkFunction.hpp" stefank@2314: #include "shark/sharkMemoryManager.hpp" stefank@2314: #include "shark/sharkNativeWrapper.hpp" stefank@2314: #include "shark/shark_globals.hpp" stefank@2314: #include "utilities/debug.hpp" twisti@2047: twisti@2047: #include twisti@2047: twisti@2047: using namespace llvm; twisti@2047: twisti@2047: #if SHARK_LLVM_VERSION >= 27 twisti@2047: namespace { twisti@2047: cl::opt twisti@2047: MCPU("mcpu"); twisti@2047: twisti@2047: cl::list twisti@2047: MAttrs("mattr", twisti@2047: cl::CommaSeparated); twisti@2047: } twisti@2047: #endif twisti@2047: twisti@2047: SharkCompiler::SharkCompiler() twisti@2047: : AbstractCompiler() { twisti@2047: // Create the lock to protect the memory manager and execution engine twisti@2047: _execution_engine_lock = new Monitor(Mutex::leaf, "SharkExecutionEngineLock"); twisti@2047: MutexLocker locker(execution_engine_lock()); twisti@2047: twisti@2047: // Make LLVM safe for multithreading twisti@2047: if (!llvm_start_multithreaded()) twisti@2047: fatal("llvm_start_multithreaded() failed"); twisti@2047: twisti@2047: // Initialize the native target twisti@2047: InitializeNativeTarget(); twisti@2047: twisti@2047: // Create the two contexts which we'll use twisti@2047: _normal_context = new SharkContext("normal"); twisti@2047: _native_context = new SharkContext("native"); twisti@2047: twisti@2047: // Create the memory manager twisti@2047: _memory_manager = new SharkMemoryManager(); twisti@2047: twisti@2047: #if SHARK_LLVM_VERSION >= 27 twisti@2047: // Finetune LLVM for the current host CPU. twisti@2047: StringMap Features; twisti@2047: bool gotCpuFeatures = llvm::sys::getHostCPUFeatures(Features); twisti@2047: std::string cpu("-mcpu=" + llvm::sys::getHostCPUName()); twisti@2047: twisti@2047: std::vector args; twisti@2047: args.push_back(""); // program name twisti@2047: args.push_back(cpu.c_str()); twisti@2047: twisti@2047: std::string mattr("-mattr="); twisti@2047: if(gotCpuFeatures){ twisti@2047: for(StringMap::iterator I = Features.begin(), twisti@2047: E = Features.end(); I != E; ++I){ twisti@2047: if(I->second){ twisti@2047: std::string attr(I->first()); twisti@2047: mattr+="+"+attr+","; twisti@2047: } twisti@2047: } twisti@2047: args.push_back(mattr.c_str()); twisti@2047: } twisti@2047: twisti@2047: args.push_back(0); // terminator twisti@2047: cl::ParseCommandLineOptions(args.size() - 1, (char **) &args[0]); twisti@2047: twisti@2047: // Create the JIT twisti@2047: std::string ErrorMsg; twisti@2047: twisti@2047: EngineBuilder builder(_normal_context->module()); twisti@2047: builder.setMCPU(MCPU); twisti@2047: builder.setMAttrs(MAttrs); twisti@2047: builder.setJITMemoryManager(memory_manager()); twisti@2047: builder.setEngineKind(EngineKind::JIT); twisti@2047: builder.setErrorStr(&ErrorMsg); twisti@2047: _execution_engine = builder.create(); twisti@2047: twisti@2047: if (!execution_engine()) { twisti@2047: if (!ErrorMsg.empty()) twisti@2047: printf("Error while creating Shark JIT: %s\n",ErrorMsg.c_str()); twisti@2047: else twisti@2047: printf("Unknown error while creating Shark JIT\n"); twisti@2047: exit(1); twisti@2047: } twisti@2047: twisti@2047: execution_engine()->addModule( twisti@2047: _native_context->module()); twisti@2047: #else twisti@2047: _execution_engine = ExecutionEngine::createJIT( twisti@2047: _normal_context->module_provider(), twisti@2047: NULL, memory_manager(), CodeGenOpt::Default); twisti@2047: execution_engine()->addModuleProvider( twisti@2047: _native_context->module_provider()); twisti@2047: #endif twisti@2047: twisti@2047: // All done twisti@2047: mark_initialized(); twisti@2047: } twisti@2047: twisti@2047: void SharkCompiler::initialize() { twisti@2047: ShouldNotCallThis(); twisti@2047: } twisti@2047: twisti@2047: void SharkCompiler::compile_method(ciEnv* env, twisti@2047: ciMethod* target, twisti@2047: int entry_bci) { twisti@2047: assert(is_initialized(), "should be"); twisti@2047: ResourceMark rm; twisti@2047: const char *name = methodname( twisti@2047: target->holder()->name()->as_utf8(), target->name()->as_utf8()); twisti@2047: twisti@2047: // Do the typeflow analysis twisti@2047: ciTypeFlow *flow; twisti@2047: if (entry_bci == InvocationEntryBci) twisti@2047: flow = target->get_flow_analysis(); twisti@2047: else twisti@2047: flow = target->get_osr_flow_analysis(entry_bci); twisti@2047: if (flow->failing()) twisti@2047: return; twisti@2047: if (SharkPrintTypeflowOf != NULL) { twisti@2047: if (!fnmatch(SharkPrintTypeflowOf, name, 0)) twisti@2047: flow->print_on(tty); twisti@2047: } twisti@2047: twisti@2047: // Create the recorders twisti@2047: Arena arena; twisti@2047: env->set_oop_recorder(new OopRecorder(&arena)); twisti@2047: OopMapSet oopmaps; twisti@2047: env->set_debug_info(new DebugInformationRecorder(env->oop_recorder())); twisti@2047: env->debug_info()->set_oopmaps(&oopmaps); twisti@2047: env->set_dependencies(new Dependencies(env)); twisti@2047: twisti@2047: // Create the code buffer and builder twisti@2047: CodeBuffer hscb("Shark", 256 * K, 64 * K); twisti@2047: hscb.initialize_oop_recorder(env->oop_recorder()); twisti@2047: MacroAssembler *masm = new MacroAssembler(&hscb); twisti@2047: SharkCodeBuffer cb(masm); twisti@2047: SharkBuilder builder(&cb); twisti@2047: twisti@2047: // Emit the entry point twisti@2047: SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry)); twisti@2047: twisti@2047: // Build the LLVM IR for the method twisti@2047: Function *function = SharkFunction::build(env, &builder, flow, name); twisti@2047: twisti@2047: // Generate native code. It's unpleasant that we have to drop into twisti@2047: // the VM to do this -- it blocks safepoints -- but I can't see any twisti@2047: // other way to handle the locking. twisti@2047: { twisti@2047: ThreadInVMfromNative tiv(JavaThread::current()); twisti@2047: generate_native_code(entry, function, name); twisti@2047: } twisti@2047: twisti@2047: // Install the method into the VM twisti@2047: CodeOffsets offsets; twisti@2047: offsets.set_value(CodeOffsets::Deopt, 0); twisti@2047: offsets.set_value(CodeOffsets::Exceptions, 0); twisti@2047: offsets.set_value(CodeOffsets::Verified_Entry, twisti@2047: target->is_static() ? 0 : wordSize); twisti@2047: twisti@2047: ExceptionHandlerTable handler_table; twisti@2047: ImplicitExceptionTable inc_table; twisti@2047: twisti@2047: env->register_method(target, twisti@2047: entry_bci, twisti@2047: &offsets, twisti@2047: 0, twisti@2047: &hscb, twisti@2047: 0, twisti@2047: &oopmaps, twisti@2047: &handler_table, twisti@2047: &inc_table, twisti@2047: this, twisti@2047: env->comp_level(), twisti@2047: false, twisti@2047: false); twisti@2047: } twisti@2047: twisti@2047: nmethod* SharkCompiler::generate_native_wrapper(MacroAssembler* masm, twisti@2047: methodHandle target, twisti@2729: int compile_id, twisti@2047: BasicType* arg_types, twisti@2047: BasicType return_type) { twisti@2047: assert(is_initialized(), "should be"); twisti@2047: ResourceMark rm; twisti@2047: const char *name = methodname( twisti@2047: target->klass_name()->as_utf8(), target->name()->as_utf8()); twisti@2047: twisti@2047: // Create the code buffer and builder twisti@2047: SharkCodeBuffer cb(masm); twisti@2047: SharkBuilder builder(&cb); twisti@2047: twisti@2047: // Emit the entry point twisti@2047: SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry)); twisti@2047: twisti@2047: // Build the LLVM IR for the method twisti@2047: SharkNativeWrapper *wrapper = SharkNativeWrapper::build( twisti@2047: &builder, target, name, arg_types, return_type); twisti@2047: twisti@2047: // Generate native code twisti@2047: generate_native_code(entry, wrapper->function(), name); twisti@2047: twisti@2047: // Return the nmethod for installation in the VM twisti@2047: return nmethod::new_native_nmethod(target, twisti@2729: compile_id, twisti@2047: masm->code(), twisti@2047: 0, twisti@2047: 0, twisti@2047: wrapper->frame_size(), twisti@2047: wrapper->receiver_offset(), twisti@2047: wrapper->lock_offset(), twisti@2047: wrapper->oop_maps()); twisti@2047: } twisti@2047: twisti@2047: void SharkCompiler::generate_native_code(SharkEntry* entry, twisti@2047: Function* function, twisti@2047: const char* name) { twisti@2047: // Print the LLVM bitcode, if requested twisti@2047: if (SharkPrintBitcodeOf != NULL) { twisti@2047: if (!fnmatch(SharkPrintBitcodeOf, name, 0)) twisti@2047: function->dump(); twisti@2047: } twisti@2047: twisti@2047: // Compile to native code twisti@2047: address code = NULL; twisti@2047: context()->add_function(function); twisti@2047: { twisti@2047: MutexLocker locker(execution_engine_lock()); twisti@2047: free_queued_methods(); twisti@2047: twisti@2047: if (SharkPrintAsmOf != NULL) { twisti@2047: #if SHARK_LLVM_VERSION >= 27 twisti@2047: #ifndef NDEBUG twisti@2047: if (!fnmatch(SharkPrintAsmOf, name, 0)) { twisti@2047: llvm::SetCurrentDebugType(X86_ONLY("x86-emitter") NOT_X86("jit")); twisti@2047: llvm::DebugFlag = true; twisti@2047: } twisti@2047: else { twisti@2047: llvm::SetCurrentDebugType(""); twisti@2047: llvm::DebugFlag = false; twisti@2047: } twisti@2047: #endif // !NDEBUG twisti@2047: #else twisti@2047: // NB you need to patch LLVM with http://tinyurl.com/yf3baln for this twisti@2047: std::vector args; twisti@2047: args.push_back(""); // program name twisti@2047: if (!fnmatch(SharkPrintAsmOf, name, 0)) twisti@2047: args.push_back("-debug-only=x86-emitter"); twisti@2047: else twisti@2047: args.push_back("-debug-only=none"); twisti@2047: args.push_back(0); // terminator twisti@2047: cl::ParseCommandLineOptions(args.size() - 1, (char **) &args[0]); twisti@2047: #endif // SHARK_LLVM_VERSION twisti@2047: } twisti@2047: memory_manager()->set_entry_for_function(function, entry); twisti@2047: code = (address) execution_engine()->getPointerToFunction(function); twisti@2047: } twisti@2047: entry->set_entry_point(code); twisti@2047: entry->set_function(function); twisti@2047: entry->set_context(context()); twisti@2047: address code_start = entry->code_start(); twisti@2047: address code_limit = entry->code_limit(); twisti@2047: twisti@2047: // Register generated code for profiling, etc twisti@2047: if (JvmtiExport::should_post_dynamic_code_generated()) twisti@2047: JvmtiExport::post_dynamic_code_generated(name, code_start, code_limit); twisti@2047: twisti@2047: // Print debug information, if requested twisti@2047: if (SharkTraceInstalls) { twisti@2047: tty->print_cr( twisti@2047: " [%p-%p): %s (%d bytes code)", twisti@2047: code_start, code_limit, name, code_limit - code_start); twisti@2047: } twisti@2047: } twisti@2047: twisti@2047: void SharkCompiler::free_compiled_method(address code) { twisti@2047: // This method may only be called when the VM is at a safepoint. twisti@2047: // All _thread_in_vm threads will be waiting for the safepoint to twisti@2047: // finish with the exception of the VM thread, so we can consider twisti@2047: // ourself the owner of the execution engine lock even though we twisti@2047: // can't actually acquire it at this time. twisti@2047: assert(Thread::current()->is_VM_thread(), "must be called by VM thread"); twisti@2047: assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); twisti@2047: twisti@2047: SharkEntry *entry = (SharkEntry *) code; twisti@2047: entry->context()->push_to_free_queue(entry->function()); twisti@2047: } twisti@2047: twisti@2047: void SharkCompiler::free_queued_methods() { twisti@2047: // The free queue is protected by the execution engine lock twisti@2047: assert(execution_engine_lock()->owned_by_self(), "should be"); twisti@2047: twisti@2047: while (true) { twisti@2047: Function *function = context()->pop_from_free_queue(); twisti@2047: if (function == NULL) twisti@2047: break; twisti@2047: twisti@2047: execution_engine()->freeMachineCodeForFunction(function); twisti@2047: function->eraseFromParent(); twisti@2047: } twisti@2047: } twisti@2047: twisti@2047: const char* SharkCompiler::methodname(const char* klass, const char* method) { twisti@2047: char *buf = NEW_RESOURCE_ARRAY(char, strlen(klass) + 2 + strlen(method) + 1); twisti@2047: twisti@2047: char *dst = buf; twisti@2047: for (const char *c = klass; *c; c++) { twisti@2047: if (*c == '/') twisti@2047: *(dst++) = '.'; twisti@2047: else twisti@2047: *(dst++) = *c; twisti@2047: } twisti@2047: *(dst++) = ':'; twisti@2047: *(dst++) = ':'; twisti@2047: for (const char *c = method; *c; c++) { twisti@2047: *(dst++) = *c; twisti@2047: } twisti@2047: *(dst++) = '\0'; twisti@2047: return buf; twisti@2047: }