Thu, 10 Oct 2013 15:44:12 +0200
8023014: CodeSweeperSweepNoFlushTest.java fails with HS crash
Summary: Ensure ensure correct initialization of compiler runtime
Reviewed-by: kvn, twisti
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 | namespace { |
twisti@2047 | 52 | cl::opt<std::string> |
twisti@2047 | 53 | MCPU("mcpu"); |
twisti@2047 | 54 | |
twisti@2047 | 55 | cl::list<std::string> |
twisti@2047 | 56 | MAttrs("mattr", |
twisti@2047 | 57 | cl::CommaSeparated); |
twisti@2047 | 58 | } |
twisti@2047 | 59 | |
twisti@2047 | 60 | SharkCompiler::SharkCompiler() |
twisti@2047 | 61 | : AbstractCompiler() { |
twisti@2047 | 62 | // Create the lock to protect the memory manager and execution engine |
twisti@2047 | 63 | _execution_engine_lock = new Monitor(Mutex::leaf, "SharkExecutionEngineLock"); |
twisti@2047 | 64 | MutexLocker locker(execution_engine_lock()); |
twisti@2047 | 65 | |
twisti@2047 | 66 | // Make LLVM safe for multithreading |
twisti@2047 | 67 | if (!llvm_start_multithreaded()) |
twisti@2047 | 68 | fatal("llvm_start_multithreaded() failed"); |
twisti@2047 | 69 | |
twisti@2047 | 70 | // Initialize the native target |
twisti@2047 | 71 | InitializeNativeTarget(); |
twisti@2047 | 72 | |
twisti@4314 | 73 | // MCJIT require a native AsmPrinter |
twisti@4314 | 74 | InitializeNativeTargetAsmPrinter(); |
twisti@4314 | 75 | |
twisti@2047 | 76 | // Create the two contexts which we'll use |
twisti@2047 | 77 | _normal_context = new SharkContext("normal"); |
twisti@2047 | 78 | _native_context = new SharkContext("native"); |
twisti@2047 | 79 | |
twisti@2047 | 80 | // Create the memory manager |
twisti@2047 | 81 | _memory_manager = new SharkMemoryManager(); |
twisti@2047 | 82 | |
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@4314 | 116 | if (! fnmatch(SharkOptimizationLevel, "None", 0)) { |
twisti@4314 | 117 | tty->print_cr("Shark optimization level set to: None"); |
twisti@4314 | 118 | builder.setOptLevel(llvm::CodeGenOpt::None); |
twisti@4314 | 119 | } else if (! fnmatch(SharkOptimizationLevel, "Less", 0)) { |
twisti@4314 | 120 | tty->print_cr("Shark optimization level set to: Less"); |
twisti@4314 | 121 | builder.setOptLevel(llvm::CodeGenOpt::Less); |
twisti@4314 | 122 | } else if (! fnmatch(SharkOptimizationLevel, "Aggressive", 0)) { |
twisti@4314 | 123 | tty->print_cr("Shark optimization level set to: Aggressive"); |
twisti@4314 | 124 | builder.setOptLevel(llvm::CodeGenOpt::Aggressive); |
twisti@4314 | 125 | } // else Default is selected by, well, default :-) |
twisti@2047 | 126 | _execution_engine = builder.create(); |
twisti@2047 | 127 | |
twisti@2047 | 128 | if (!execution_engine()) { |
twisti@2047 | 129 | if (!ErrorMsg.empty()) |
twisti@2047 | 130 | printf("Error while creating Shark JIT: %s\n",ErrorMsg.c_str()); |
twisti@2047 | 131 | else |
twisti@2047 | 132 | printf("Unknown error while creating Shark JIT\n"); |
twisti@2047 | 133 | exit(1); |
twisti@2047 | 134 | } |
twisti@2047 | 135 | |
anoll@5919 | 136 | execution_engine()->addModule(_native_context->module()); |
twisti@2047 | 137 | |
twisti@2047 | 138 | // All done |
anoll@5919 | 139 | set_state(initialized); |
twisti@2047 | 140 | } |
twisti@2047 | 141 | |
twisti@2047 | 142 | void SharkCompiler::initialize() { |
twisti@2047 | 143 | ShouldNotCallThis(); |
twisti@2047 | 144 | } |
twisti@2047 | 145 | |
twisti@2047 | 146 | void SharkCompiler::compile_method(ciEnv* env, |
twisti@2047 | 147 | ciMethod* target, |
twisti@2047 | 148 | int entry_bci) { |
twisti@2047 | 149 | assert(is_initialized(), "should be"); |
twisti@2047 | 150 | ResourceMark rm; |
twisti@2047 | 151 | const char *name = methodname( |
twisti@2047 | 152 | target->holder()->name()->as_utf8(), target->name()->as_utf8()); |
twisti@2047 | 153 | |
twisti@2047 | 154 | // Do the typeflow analysis |
twisti@2047 | 155 | ciTypeFlow *flow; |
twisti@2047 | 156 | if (entry_bci == InvocationEntryBci) |
twisti@2047 | 157 | flow = target->get_flow_analysis(); |
twisti@2047 | 158 | else |
twisti@2047 | 159 | flow = target->get_osr_flow_analysis(entry_bci); |
twisti@2047 | 160 | if (flow->failing()) |
twisti@2047 | 161 | return; |
twisti@2047 | 162 | if (SharkPrintTypeflowOf != NULL) { |
twisti@2047 | 163 | if (!fnmatch(SharkPrintTypeflowOf, name, 0)) |
twisti@2047 | 164 | flow->print_on(tty); |
twisti@2047 | 165 | } |
twisti@2047 | 166 | |
twisti@2047 | 167 | // Create the recorders |
twisti@2047 | 168 | Arena arena; |
twisti@2047 | 169 | env->set_oop_recorder(new OopRecorder(&arena)); |
twisti@2047 | 170 | OopMapSet oopmaps; |
twisti@2047 | 171 | env->set_debug_info(new DebugInformationRecorder(env->oop_recorder())); |
twisti@2047 | 172 | env->debug_info()->set_oopmaps(&oopmaps); |
twisti@2047 | 173 | env->set_dependencies(new Dependencies(env)); |
twisti@2047 | 174 | |
twisti@2047 | 175 | // Create the code buffer and builder |
twisti@2047 | 176 | CodeBuffer hscb("Shark", 256 * K, 64 * K); |
twisti@2047 | 177 | hscb.initialize_oop_recorder(env->oop_recorder()); |
twisti@2047 | 178 | MacroAssembler *masm = new MacroAssembler(&hscb); |
twisti@2047 | 179 | SharkCodeBuffer cb(masm); |
twisti@2047 | 180 | SharkBuilder builder(&cb); |
twisti@2047 | 181 | |
twisti@2047 | 182 | // Emit the entry point |
twisti@2047 | 183 | SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry)); |
twisti@2047 | 184 | |
twisti@2047 | 185 | // Build the LLVM IR for the method |
twisti@2047 | 186 | Function *function = SharkFunction::build(env, &builder, flow, name); |
twisti@4443 | 187 | if (env->failing()) { |
twisti@4443 | 188 | return; |
twisti@4443 | 189 | } |
twisti@2047 | 190 | |
twisti@2047 | 191 | // Generate native code. It's unpleasant that we have to drop into |
twisti@2047 | 192 | // the VM to do this -- it blocks safepoints -- but I can't see any |
twisti@2047 | 193 | // other way to handle the locking. |
twisti@2047 | 194 | { |
twisti@2047 | 195 | ThreadInVMfromNative tiv(JavaThread::current()); |
twisti@2047 | 196 | generate_native_code(entry, function, name); |
twisti@2047 | 197 | } |
twisti@2047 | 198 | |
twisti@2047 | 199 | // Install the method into the VM |
twisti@2047 | 200 | CodeOffsets offsets; |
twisti@2047 | 201 | offsets.set_value(CodeOffsets::Deopt, 0); |
twisti@2047 | 202 | offsets.set_value(CodeOffsets::Exceptions, 0); |
twisti@2047 | 203 | offsets.set_value(CodeOffsets::Verified_Entry, |
twisti@2047 | 204 | target->is_static() ? 0 : wordSize); |
twisti@2047 | 205 | |
twisti@2047 | 206 | ExceptionHandlerTable handler_table; |
twisti@2047 | 207 | ImplicitExceptionTable inc_table; |
twisti@2047 | 208 | |
twisti@2047 | 209 | env->register_method(target, |
twisti@2047 | 210 | entry_bci, |
twisti@2047 | 211 | &offsets, |
twisti@2047 | 212 | 0, |
twisti@2047 | 213 | &hscb, |
twisti@2047 | 214 | 0, |
twisti@2047 | 215 | &oopmaps, |
twisti@2047 | 216 | &handler_table, |
twisti@2047 | 217 | &inc_table, |
twisti@2047 | 218 | this, |
twisti@2047 | 219 | env->comp_level(), |
twisti@2047 | 220 | false, |
twisti@2047 | 221 | false); |
twisti@2047 | 222 | } |
twisti@2047 | 223 | |
twisti@2047 | 224 | nmethod* SharkCompiler::generate_native_wrapper(MacroAssembler* masm, |
twisti@2047 | 225 | methodHandle target, |
twisti@2729 | 226 | int compile_id, |
twisti@2047 | 227 | BasicType* arg_types, |
twisti@2047 | 228 | BasicType return_type) { |
twisti@2047 | 229 | assert(is_initialized(), "should be"); |
twisti@2047 | 230 | ResourceMark rm; |
twisti@2047 | 231 | const char *name = methodname( |
twisti@2047 | 232 | target->klass_name()->as_utf8(), target->name()->as_utf8()); |
twisti@2047 | 233 | |
twisti@2047 | 234 | // Create the code buffer and builder |
twisti@2047 | 235 | SharkCodeBuffer cb(masm); |
twisti@2047 | 236 | SharkBuilder builder(&cb); |
twisti@2047 | 237 | |
twisti@2047 | 238 | // Emit the entry point |
twisti@2047 | 239 | SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry)); |
twisti@2047 | 240 | |
twisti@2047 | 241 | // Build the LLVM IR for the method |
twisti@2047 | 242 | SharkNativeWrapper *wrapper = SharkNativeWrapper::build( |
twisti@2047 | 243 | &builder, target, name, arg_types, return_type); |
twisti@2047 | 244 | |
twisti@2047 | 245 | // Generate native code |
twisti@2047 | 246 | generate_native_code(entry, wrapper->function(), name); |
twisti@2047 | 247 | |
twisti@2047 | 248 | // Return the nmethod for installation in the VM |
twisti@2047 | 249 | return nmethod::new_native_nmethod(target, |
twisti@2729 | 250 | compile_id, |
twisti@2047 | 251 | masm->code(), |
twisti@2047 | 252 | 0, |
twisti@2047 | 253 | 0, |
twisti@2047 | 254 | wrapper->frame_size(), |
twisti@2047 | 255 | wrapper->receiver_offset(), |
twisti@2047 | 256 | wrapper->lock_offset(), |
twisti@2047 | 257 | wrapper->oop_maps()); |
twisti@2047 | 258 | } |
twisti@2047 | 259 | |
twisti@2047 | 260 | void SharkCompiler::generate_native_code(SharkEntry* entry, |
twisti@2047 | 261 | Function* function, |
twisti@2047 | 262 | const char* name) { |
twisti@2047 | 263 | // Print the LLVM bitcode, if requested |
twisti@2047 | 264 | if (SharkPrintBitcodeOf != NULL) { |
twisti@2047 | 265 | if (!fnmatch(SharkPrintBitcodeOf, name, 0)) |
twisti@2047 | 266 | function->dump(); |
twisti@2047 | 267 | } |
twisti@2047 | 268 | |
twisti@4314 | 269 | if (SharkVerifyFunction != NULL) { |
twisti@4314 | 270 | if (!fnmatch(SharkVerifyFunction, name, 0)) { |
twisti@4314 | 271 | verifyFunction(*function); |
twisti@4314 | 272 | } |
twisti@4314 | 273 | } |
twisti@4314 | 274 | |
twisti@2047 | 275 | // Compile to native code |
twisti@2047 | 276 | address code = NULL; |
twisti@2047 | 277 | context()->add_function(function); |
twisti@2047 | 278 | { |
twisti@2047 | 279 | MutexLocker locker(execution_engine_lock()); |
twisti@2047 | 280 | free_queued_methods(); |
twisti@2047 | 281 | |
twisti@4314 | 282 | #ifndef NDEBUG |
twisti@4314 | 283 | #if SHARK_LLVM_VERSION <= 31 |
twisti@4314 | 284 | #define setCurrentDebugType SetCurrentDebugType |
twisti@4314 | 285 | #endif |
twisti@2047 | 286 | if (SharkPrintAsmOf != NULL) { |
twisti@2047 | 287 | if (!fnmatch(SharkPrintAsmOf, name, 0)) { |
twisti@4314 | 288 | llvm::setCurrentDebugType(X86_ONLY("x86-emitter") NOT_X86("jit")); |
twisti@2047 | 289 | llvm::DebugFlag = true; |
twisti@2047 | 290 | } |
twisti@2047 | 291 | else { |
twisti@4314 | 292 | llvm::setCurrentDebugType(""); |
twisti@2047 | 293 | llvm::DebugFlag = false; |
twisti@2047 | 294 | } |
twisti@4314 | 295 | } |
twisti@4314 | 296 | #ifdef setCurrentDebugType |
twisti@4314 | 297 | #undef setCurrentDebugType |
twisti@4314 | 298 | #endif |
twisti@2047 | 299 | #endif // !NDEBUG |
twisti@2047 | 300 | memory_manager()->set_entry_for_function(function, entry); |
twisti@2047 | 301 | code = (address) execution_engine()->getPointerToFunction(function); |
twisti@2047 | 302 | } |
twisti@4314 | 303 | assert(code != NULL, "code must be != NULL"); |
twisti@2047 | 304 | entry->set_entry_point(code); |
twisti@2047 | 305 | entry->set_function(function); |
twisti@2047 | 306 | entry->set_context(context()); |
twisti@2047 | 307 | address code_start = entry->code_start(); |
twisti@2047 | 308 | address code_limit = entry->code_limit(); |
twisti@2047 | 309 | |
twisti@2047 | 310 | // Register generated code for profiling, etc |
twisti@2047 | 311 | if (JvmtiExport::should_post_dynamic_code_generated()) |
twisti@2047 | 312 | JvmtiExport::post_dynamic_code_generated(name, code_start, code_limit); |
twisti@2047 | 313 | |
twisti@2047 | 314 | // Print debug information, if requested |
twisti@2047 | 315 | if (SharkTraceInstalls) { |
twisti@2047 | 316 | tty->print_cr( |
twisti@2047 | 317 | " [%p-%p): %s (%d bytes code)", |
twisti@2047 | 318 | code_start, code_limit, name, code_limit - code_start); |
twisti@2047 | 319 | } |
twisti@2047 | 320 | } |
twisti@2047 | 321 | |
twisti@2047 | 322 | void SharkCompiler::free_compiled_method(address code) { |
twisti@2047 | 323 | // This method may only be called when the VM is at a safepoint. |
twisti@2047 | 324 | // All _thread_in_vm threads will be waiting for the safepoint to |
twisti@2047 | 325 | // finish with the exception of the VM thread, so we can consider |
twisti@2047 | 326 | // ourself the owner of the execution engine lock even though we |
twisti@2047 | 327 | // can't actually acquire it at this time. |
twisti@4314 | 328 | assert(Thread::current()->is_Compiler_thread(), "must be called by compiler thread"); |
twisti@4314 | 329 | assert_locked_or_safepoint(CodeCache_lock); |
twisti@2047 | 330 | |
twisti@2047 | 331 | SharkEntry *entry = (SharkEntry *) code; |
twisti@2047 | 332 | entry->context()->push_to_free_queue(entry->function()); |
twisti@2047 | 333 | } |
twisti@2047 | 334 | |
twisti@2047 | 335 | void SharkCompiler::free_queued_methods() { |
twisti@2047 | 336 | // The free queue is protected by the execution engine lock |
twisti@2047 | 337 | assert(execution_engine_lock()->owned_by_self(), "should be"); |
twisti@2047 | 338 | |
twisti@2047 | 339 | while (true) { |
twisti@2047 | 340 | Function *function = context()->pop_from_free_queue(); |
twisti@2047 | 341 | if (function == NULL) |
twisti@2047 | 342 | break; |
twisti@2047 | 343 | |
twisti@2047 | 344 | execution_engine()->freeMachineCodeForFunction(function); |
twisti@2047 | 345 | function->eraseFromParent(); |
twisti@2047 | 346 | } |
twisti@2047 | 347 | } |
twisti@2047 | 348 | |
twisti@2047 | 349 | const char* SharkCompiler::methodname(const char* klass, const char* method) { |
twisti@2047 | 350 | char *buf = NEW_RESOURCE_ARRAY(char, strlen(klass) + 2 + strlen(method) + 1); |
twisti@2047 | 351 | |
twisti@2047 | 352 | char *dst = buf; |
twisti@2047 | 353 | for (const char *c = klass; *c; c++) { |
twisti@2047 | 354 | if (*c == '/') |
twisti@2047 | 355 | *(dst++) = '.'; |
twisti@2047 | 356 | else |
twisti@2047 | 357 | *(dst++) = *c; |
twisti@2047 | 358 | } |
twisti@2047 | 359 | *(dst++) = ':'; |
twisti@2047 | 360 | *(dst++) = ':'; |
twisti@2047 | 361 | for (const char *c = method; *c; c++) { |
twisti@2047 | 362 | *(dst++) = *c; |
twisti@2047 | 363 | } |
twisti@2047 | 364 | *(dst++) = '\0'; |
twisti@2047 | 365 | return buf; |
twisti@2047 | 366 | } |