Mon, 04 Apr 2011 03:02:00 -0700
7032458: Zero and Shark fixes
Reviewed-by: twisti
Contributed-by: Gary Benson <gbenson@redhat.com>
twisti@2047 | 1 | /* |
stefank@2314 | 2 | * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. |
twisti@2729 | 3 | * Copyright 2008, 2009, 2010, 2011 Red Hat, Inc. |
twisti@2047 | 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
twisti@2047 | 5 | * |
twisti@2047 | 6 | * This code is free software; you can redistribute it and/or modify it |
twisti@2047 | 7 | * under the terms of the GNU General Public License version 2 only, as |
twisti@2047 | 8 | * published by the Free Software Foundation. |
twisti@2047 | 9 | * |
twisti@2047 | 10 | * This code is distributed in the hope that it will be useful, but WITHOUT |
twisti@2047 | 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
twisti@2047 | 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
twisti@2047 | 13 | * version 2 for more details (a copy is included in the LICENSE file that |
twisti@2047 | 14 | * accompanied this code). |
twisti@2047 | 15 | * |
twisti@2047 | 16 | * You should have received a copy of the GNU General Public License version |
twisti@2047 | 17 | * 2 along with this work; if not, write to the Free Software Foundation, |
twisti@2047 | 18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
twisti@2047 | 19 | * |
twisti@2047 | 20 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
twisti@2047 | 21 | * or visit www.oracle.com if you need additional information or have any |
twisti@2047 | 22 | * questions. |
twisti@2047 | 23 | * |
twisti@2047 | 24 | */ |
twisti@2047 | 25 | |
stefank@2314 | 26 | #include "precompiled.hpp" |
stefank@2314 | 27 | #include "ci/ciEnv.hpp" |
stefank@2314 | 28 | #include "ci/ciMethod.hpp" |
stefank@2314 | 29 | #include "code/debugInfoRec.hpp" |
stefank@2314 | 30 | #include "code/dependencies.hpp" |
stefank@2314 | 31 | #include "code/exceptionHandlerTable.hpp" |
stefank@2314 | 32 | #include "code/oopRecorder.hpp" |
stefank@2314 | 33 | #include "compiler/abstractCompiler.hpp" |
stefank@2314 | 34 | #include "compiler/oopMap.hpp" |
stefank@2314 | 35 | #include "shark/llvmHeaders.hpp" |
stefank@2314 | 36 | #include "shark/sharkBuilder.hpp" |
stefank@2314 | 37 | #include "shark/sharkCodeBuffer.hpp" |
stefank@2314 | 38 | #include "shark/sharkCompiler.hpp" |
stefank@2314 | 39 | #include "shark/sharkContext.hpp" |
stefank@2314 | 40 | #include "shark/sharkEntry.hpp" |
stefank@2314 | 41 | #include "shark/sharkFunction.hpp" |
stefank@2314 | 42 | #include "shark/sharkMemoryManager.hpp" |
stefank@2314 | 43 | #include "shark/sharkNativeWrapper.hpp" |
stefank@2314 | 44 | #include "shark/shark_globals.hpp" |
stefank@2314 | 45 | #include "utilities/debug.hpp" |
twisti@2047 | 46 | |
twisti@2047 | 47 | #include <fnmatch.h> |
twisti@2047 | 48 | |
twisti@2047 | 49 | using namespace llvm; |
twisti@2047 | 50 | |
twisti@2047 | 51 | #if SHARK_LLVM_VERSION >= 27 |
twisti@2047 | 52 | namespace { |
twisti@2047 | 53 | cl::opt<std::string> |
twisti@2047 | 54 | MCPU("mcpu"); |
twisti@2047 | 55 | |
twisti@2047 | 56 | cl::list<std::string> |
twisti@2047 | 57 | MAttrs("mattr", |
twisti@2047 | 58 | cl::CommaSeparated); |
twisti@2047 | 59 | } |
twisti@2047 | 60 | #endif |
twisti@2047 | 61 | |
twisti@2047 | 62 | SharkCompiler::SharkCompiler() |
twisti@2047 | 63 | : AbstractCompiler() { |
twisti@2047 | 64 | // Create the lock to protect the memory manager and execution engine |
twisti@2047 | 65 | _execution_engine_lock = new Monitor(Mutex::leaf, "SharkExecutionEngineLock"); |
twisti@2047 | 66 | MutexLocker locker(execution_engine_lock()); |
twisti@2047 | 67 | |
twisti@2047 | 68 | // Make LLVM safe for multithreading |
twisti@2047 | 69 | if (!llvm_start_multithreaded()) |
twisti@2047 | 70 | fatal("llvm_start_multithreaded() failed"); |
twisti@2047 | 71 | |
twisti@2047 | 72 | // Initialize the native target |
twisti@2047 | 73 | InitializeNativeTarget(); |
twisti@2047 | 74 | |
twisti@2047 | 75 | // Create the two contexts which we'll use |
twisti@2047 | 76 | _normal_context = new SharkContext("normal"); |
twisti@2047 | 77 | _native_context = new SharkContext("native"); |
twisti@2047 | 78 | |
twisti@2047 | 79 | // Create the memory manager |
twisti@2047 | 80 | _memory_manager = new SharkMemoryManager(); |
twisti@2047 | 81 | |
twisti@2047 | 82 | #if SHARK_LLVM_VERSION >= 27 |
twisti@2047 | 83 | // Finetune LLVM for the current host CPU. |
twisti@2047 | 84 | StringMap<bool> Features; |
twisti@2047 | 85 | bool gotCpuFeatures = llvm::sys::getHostCPUFeatures(Features); |
twisti@2047 | 86 | std::string cpu("-mcpu=" + llvm::sys::getHostCPUName()); |
twisti@2047 | 87 | |
twisti@2047 | 88 | std::vector<const char*> args; |
twisti@2047 | 89 | args.push_back(""); // program name |
twisti@2047 | 90 | args.push_back(cpu.c_str()); |
twisti@2047 | 91 | |
twisti@2047 | 92 | std::string mattr("-mattr="); |
twisti@2047 | 93 | if(gotCpuFeatures){ |
twisti@2047 | 94 | for(StringMap<bool>::iterator I = Features.begin(), |
twisti@2047 | 95 | E = Features.end(); I != E; ++I){ |
twisti@2047 | 96 | if(I->second){ |
twisti@2047 | 97 | std::string attr(I->first()); |
twisti@2047 | 98 | mattr+="+"+attr+","; |
twisti@2047 | 99 | } |
twisti@2047 | 100 | } |
twisti@2047 | 101 | args.push_back(mattr.c_str()); |
twisti@2047 | 102 | } |
twisti@2047 | 103 | |
twisti@2047 | 104 | args.push_back(0); // terminator |
twisti@2047 | 105 | cl::ParseCommandLineOptions(args.size() - 1, (char **) &args[0]); |
twisti@2047 | 106 | |
twisti@2047 | 107 | // Create the JIT |
twisti@2047 | 108 | std::string ErrorMsg; |
twisti@2047 | 109 | |
twisti@2047 | 110 | EngineBuilder builder(_normal_context->module()); |
twisti@2047 | 111 | builder.setMCPU(MCPU); |
twisti@2047 | 112 | builder.setMAttrs(MAttrs); |
twisti@2047 | 113 | builder.setJITMemoryManager(memory_manager()); |
twisti@2047 | 114 | builder.setEngineKind(EngineKind::JIT); |
twisti@2047 | 115 | builder.setErrorStr(&ErrorMsg); |
twisti@2047 | 116 | _execution_engine = builder.create(); |
twisti@2047 | 117 | |
twisti@2047 | 118 | if (!execution_engine()) { |
twisti@2047 | 119 | if (!ErrorMsg.empty()) |
twisti@2047 | 120 | printf("Error while creating Shark JIT: %s\n",ErrorMsg.c_str()); |
twisti@2047 | 121 | else |
twisti@2047 | 122 | printf("Unknown error while creating Shark JIT\n"); |
twisti@2047 | 123 | exit(1); |
twisti@2047 | 124 | } |
twisti@2047 | 125 | |
twisti@2047 | 126 | execution_engine()->addModule( |
twisti@2047 | 127 | _native_context->module()); |
twisti@2047 | 128 | #else |
twisti@2047 | 129 | _execution_engine = ExecutionEngine::createJIT( |
twisti@2047 | 130 | _normal_context->module_provider(), |
twisti@2047 | 131 | NULL, memory_manager(), CodeGenOpt::Default); |
twisti@2047 | 132 | execution_engine()->addModuleProvider( |
twisti@2047 | 133 | _native_context->module_provider()); |
twisti@2047 | 134 | #endif |
twisti@2047 | 135 | |
twisti@2047 | 136 | // All done |
twisti@2047 | 137 | mark_initialized(); |
twisti@2047 | 138 | } |
twisti@2047 | 139 | |
twisti@2047 | 140 | void SharkCompiler::initialize() { |
twisti@2047 | 141 | ShouldNotCallThis(); |
twisti@2047 | 142 | } |
twisti@2047 | 143 | |
twisti@2047 | 144 | void SharkCompiler::compile_method(ciEnv* env, |
twisti@2047 | 145 | ciMethod* target, |
twisti@2047 | 146 | int entry_bci) { |
twisti@2047 | 147 | assert(is_initialized(), "should be"); |
twisti@2047 | 148 | ResourceMark rm; |
twisti@2047 | 149 | const char *name = methodname( |
twisti@2047 | 150 | target->holder()->name()->as_utf8(), target->name()->as_utf8()); |
twisti@2047 | 151 | |
twisti@2047 | 152 | // Do the typeflow analysis |
twisti@2047 | 153 | ciTypeFlow *flow; |
twisti@2047 | 154 | if (entry_bci == InvocationEntryBci) |
twisti@2047 | 155 | flow = target->get_flow_analysis(); |
twisti@2047 | 156 | else |
twisti@2047 | 157 | flow = target->get_osr_flow_analysis(entry_bci); |
twisti@2047 | 158 | if (flow->failing()) |
twisti@2047 | 159 | return; |
twisti@2047 | 160 | if (SharkPrintTypeflowOf != NULL) { |
twisti@2047 | 161 | if (!fnmatch(SharkPrintTypeflowOf, name, 0)) |
twisti@2047 | 162 | flow->print_on(tty); |
twisti@2047 | 163 | } |
twisti@2047 | 164 | |
twisti@2047 | 165 | // Create the recorders |
twisti@2047 | 166 | Arena arena; |
twisti@2047 | 167 | env->set_oop_recorder(new OopRecorder(&arena)); |
twisti@2047 | 168 | OopMapSet oopmaps; |
twisti@2047 | 169 | env->set_debug_info(new DebugInformationRecorder(env->oop_recorder())); |
twisti@2047 | 170 | env->debug_info()->set_oopmaps(&oopmaps); |
twisti@2047 | 171 | env->set_dependencies(new Dependencies(env)); |
twisti@2047 | 172 | |
twisti@2047 | 173 | // Create the code buffer and builder |
twisti@2047 | 174 | CodeBuffer hscb("Shark", 256 * K, 64 * K); |
twisti@2047 | 175 | hscb.initialize_oop_recorder(env->oop_recorder()); |
twisti@2047 | 176 | MacroAssembler *masm = new MacroAssembler(&hscb); |
twisti@2047 | 177 | SharkCodeBuffer cb(masm); |
twisti@2047 | 178 | SharkBuilder builder(&cb); |
twisti@2047 | 179 | |
twisti@2047 | 180 | // Emit the entry point |
twisti@2047 | 181 | SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry)); |
twisti@2047 | 182 | |
twisti@2047 | 183 | // Build the LLVM IR for the method |
twisti@2047 | 184 | Function *function = SharkFunction::build(env, &builder, flow, name); |
twisti@2047 | 185 | |
twisti@2047 | 186 | // Generate native code. It's unpleasant that we have to drop into |
twisti@2047 | 187 | // the VM to do this -- it blocks safepoints -- but I can't see any |
twisti@2047 | 188 | // other way to handle the locking. |
twisti@2047 | 189 | { |
twisti@2047 | 190 | ThreadInVMfromNative tiv(JavaThread::current()); |
twisti@2047 | 191 | generate_native_code(entry, function, name); |
twisti@2047 | 192 | } |
twisti@2047 | 193 | |
twisti@2047 | 194 | // Install the method into the VM |
twisti@2047 | 195 | CodeOffsets offsets; |
twisti@2047 | 196 | offsets.set_value(CodeOffsets::Deopt, 0); |
twisti@2047 | 197 | offsets.set_value(CodeOffsets::Exceptions, 0); |
twisti@2047 | 198 | offsets.set_value(CodeOffsets::Verified_Entry, |
twisti@2047 | 199 | target->is_static() ? 0 : wordSize); |
twisti@2047 | 200 | |
twisti@2047 | 201 | ExceptionHandlerTable handler_table; |
twisti@2047 | 202 | ImplicitExceptionTable inc_table; |
twisti@2047 | 203 | |
twisti@2047 | 204 | env->register_method(target, |
twisti@2047 | 205 | entry_bci, |
twisti@2047 | 206 | &offsets, |
twisti@2047 | 207 | 0, |
twisti@2047 | 208 | &hscb, |
twisti@2047 | 209 | 0, |
twisti@2047 | 210 | &oopmaps, |
twisti@2047 | 211 | &handler_table, |
twisti@2047 | 212 | &inc_table, |
twisti@2047 | 213 | this, |
twisti@2047 | 214 | env->comp_level(), |
twisti@2047 | 215 | false, |
twisti@2047 | 216 | false); |
twisti@2047 | 217 | } |
twisti@2047 | 218 | |
twisti@2047 | 219 | nmethod* SharkCompiler::generate_native_wrapper(MacroAssembler* masm, |
twisti@2047 | 220 | methodHandle target, |
twisti@2729 | 221 | int compile_id, |
twisti@2047 | 222 | BasicType* arg_types, |
twisti@2047 | 223 | BasicType return_type) { |
twisti@2047 | 224 | assert(is_initialized(), "should be"); |
twisti@2047 | 225 | ResourceMark rm; |
twisti@2047 | 226 | const char *name = methodname( |
twisti@2047 | 227 | target->klass_name()->as_utf8(), target->name()->as_utf8()); |
twisti@2047 | 228 | |
twisti@2047 | 229 | // Create the code buffer and builder |
twisti@2047 | 230 | SharkCodeBuffer cb(masm); |
twisti@2047 | 231 | SharkBuilder builder(&cb); |
twisti@2047 | 232 | |
twisti@2047 | 233 | // Emit the entry point |
twisti@2047 | 234 | SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry)); |
twisti@2047 | 235 | |
twisti@2047 | 236 | // Build the LLVM IR for the method |
twisti@2047 | 237 | SharkNativeWrapper *wrapper = SharkNativeWrapper::build( |
twisti@2047 | 238 | &builder, target, name, arg_types, return_type); |
twisti@2047 | 239 | |
twisti@2047 | 240 | // Generate native code |
twisti@2047 | 241 | generate_native_code(entry, wrapper->function(), name); |
twisti@2047 | 242 | |
twisti@2047 | 243 | // Return the nmethod for installation in the VM |
twisti@2047 | 244 | return nmethod::new_native_nmethod(target, |
twisti@2729 | 245 | compile_id, |
twisti@2047 | 246 | masm->code(), |
twisti@2047 | 247 | 0, |
twisti@2047 | 248 | 0, |
twisti@2047 | 249 | wrapper->frame_size(), |
twisti@2047 | 250 | wrapper->receiver_offset(), |
twisti@2047 | 251 | wrapper->lock_offset(), |
twisti@2047 | 252 | wrapper->oop_maps()); |
twisti@2047 | 253 | } |
twisti@2047 | 254 | |
twisti@2047 | 255 | void SharkCompiler::generate_native_code(SharkEntry* entry, |
twisti@2047 | 256 | Function* function, |
twisti@2047 | 257 | const char* name) { |
twisti@2047 | 258 | // Print the LLVM bitcode, if requested |
twisti@2047 | 259 | if (SharkPrintBitcodeOf != NULL) { |
twisti@2047 | 260 | if (!fnmatch(SharkPrintBitcodeOf, name, 0)) |
twisti@2047 | 261 | function->dump(); |
twisti@2047 | 262 | } |
twisti@2047 | 263 | |
twisti@2047 | 264 | // Compile to native code |
twisti@2047 | 265 | address code = NULL; |
twisti@2047 | 266 | context()->add_function(function); |
twisti@2047 | 267 | { |
twisti@2047 | 268 | MutexLocker locker(execution_engine_lock()); |
twisti@2047 | 269 | free_queued_methods(); |
twisti@2047 | 270 | |
twisti@2047 | 271 | if (SharkPrintAsmOf != NULL) { |
twisti@2047 | 272 | #if SHARK_LLVM_VERSION >= 27 |
twisti@2047 | 273 | #ifndef NDEBUG |
twisti@2047 | 274 | if (!fnmatch(SharkPrintAsmOf, name, 0)) { |
twisti@2047 | 275 | llvm::SetCurrentDebugType(X86_ONLY("x86-emitter") NOT_X86("jit")); |
twisti@2047 | 276 | llvm::DebugFlag = true; |
twisti@2047 | 277 | } |
twisti@2047 | 278 | else { |
twisti@2047 | 279 | llvm::SetCurrentDebugType(""); |
twisti@2047 | 280 | llvm::DebugFlag = false; |
twisti@2047 | 281 | } |
twisti@2047 | 282 | #endif // !NDEBUG |
twisti@2047 | 283 | #else |
twisti@2047 | 284 | // NB you need to patch LLVM with http://tinyurl.com/yf3baln for this |
twisti@2047 | 285 | std::vector<const char*> args; |
twisti@2047 | 286 | args.push_back(""); // program name |
twisti@2047 | 287 | if (!fnmatch(SharkPrintAsmOf, name, 0)) |
twisti@2047 | 288 | args.push_back("-debug-only=x86-emitter"); |
twisti@2047 | 289 | else |
twisti@2047 | 290 | args.push_back("-debug-only=none"); |
twisti@2047 | 291 | args.push_back(0); // terminator |
twisti@2047 | 292 | cl::ParseCommandLineOptions(args.size() - 1, (char **) &args[0]); |
twisti@2047 | 293 | #endif // SHARK_LLVM_VERSION |
twisti@2047 | 294 | } |
twisti@2047 | 295 | memory_manager()->set_entry_for_function(function, entry); |
twisti@2047 | 296 | code = (address) execution_engine()->getPointerToFunction(function); |
twisti@2047 | 297 | } |
twisti@2047 | 298 | entry->set_entry_point(code); |
twisti@2047 | 299 | entry->set_function(function); |
twisti@2047 | 300 | entry->set_context(context()); |
twisti@2047 | 301 | address code_start = entry->code_start(); |
twisti@2047 | 302 | address code_limit = entry->code_limit(); |
twisti@2047 | 303 | |
twisti@2047 | 304 | // Register generated code for profiling, etc |
twisti@2047 | 305 | if (JvmtiExport::should_post_dynamic_code_generated()) |
twisti@2047 | 306 | JvmtiExport::post_dynamic_code_generated(name, code_start, code_limit); |
twisti@2047 | 307 | |
twisti@2047 | 308 | // Print debug information, if requested |
twisti@2047 | 309 | if (SharkTraceInstalls) { |
twisti@2047 | 310 | tty->print_cr( |
twisti@2047 | 311 | " [%p-%p): %s (%d bytes code)", |
twisti@2047 | 312 | code_start, code_limit, name, code_limit - code_start); |
twisti@2047 | 313 | } |
twisti@2047 | 314 | } |
twisti@2047 | 315 | |
twisti@2047 | 316 | void SharkCompiler::free_compiled_method(address code) { |
twisti@2047 | 317 | // This method may only be called when the VM is at a safepoint. |
twisti@2047 | 318 | // All _thread_in_vm threads will be waiting for the safepoint to |
twisti@2047 | 319 | // finish with the exception of the VM thread, so we can consider |
twisti@2047 | 320 | // ourself the owner of the execution engine lock even though we |
twisti@2047 | 321 | // can't actually acquire it at this time. |
twisti@2047 | 322 | assert(Thread::current()->is_VM_thread(), "must be called by VM thread"); |
twisti@2047 | 323 | assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); |
twisti@2047 | 324 | |
twisti@2047 | 325 | SharkEntry *entry = (SharkEntry *) code; |
twisti@2047 | 326 | entry->context()->push_to_free_queue(entry->function()); |
twisti@2047 | 327 | } |
twisti@2047 | 328 | |
twisti@2047 | 329 | void SharkCompiler::free_queued_methods() { |
twisti@2047 | 330 | // The free queue is protected by the execution engine lock |
twisti@2047 | 331 | assert(execution_engine_lock()->owned_by_self(), "should be"); |
twisti@2047 | 332 | |
twisti@2047 | 333 | while (true) { |
twisti@2047 | 334 | Function *function = context()->pop_from_free_queue(); |
twisti@2047 | 335 | if (function == NULL) |
twisti@2047 | 336 | break; |
twisti@2047 | 337 | |
twisti@2047 | 338 | execution_engine()->freeMachineCodeForFunction(function); |
twisti@2047 | 339 | function->eraseFromParent(); |
twisti@2047 | 340 | } |
twisti@2047 | 341 | } |
twisti@2047 | 342 | |
twisti@2047 | 343 | const char* SharkCompiler::methodname(const char* klass, const char* method) { |
twisti@2047 | 344 | char *buf = NEW_RESOURCE_ARRAY(char, strlen(klass) + 2 + strlen(method) + 1); |
twisti@2047 | 345 | |
twisti@2047 | 346 | char *dst = buf; |
twisti@2047 | 347 | for (const char *c = klass; *c; c++) { |
twisti@2047 | 348 | if (*c == '/') |
twisti@2047 | 349 | *(dst++) = '.'; |
twisti@2047 | 350 | else |
twisti@2047 | 351 | *(dst++) = *c; |
twisti@2047 | 352 | } |
twisti@2047 | 353 | *(dst++) = ':'; |
twisti@2047 | 354 | *(dst++) = ':'; |
twisti@2047 | 355 | for (const char *c = method; *c; c++) { |
twisti@2047 | 356 | *(dst++) = *c; |
twisti@2047 | 357 | } |
twisti@2047 | 358 | *(dst++) = '\0'; |
twisti@2047 | 359 | return buf; |
twisti@2047 | 360 | } |