src/share/vm/shark/sharkCompiler.cpp

changeset 2047
d2ede61b7a12
child 2314
f95d63e2154a
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/vm/shark/sharkCompiler.cpp	Wed Aug 11 05:51:21 2010 -0700
     1.3 @@ -0,0 +1,340 @@
     1.4 +/*
     1.5 + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
     1.6 + * Copyright 2008, 2009, 2010 Red Hat, Inc.
     1.7 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.8 + *
     1.9 + * This code is free software; you can redistribute it and/or modify it
    1.10 + * under the terms of the GNU General Public License version 2 only, as
    1.11 + * published by the Free Software Foundation.
    1.12 + *
    1.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.16 + * version 2 for more details (a copy is included in the LICENSE file that
    1.17 + * accompanied this code).
    1.18 + *
    1.19 + * You should have received a copy of the GNU General Public License version
    1.20 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.22 + *
    1.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.24 + * or visit www.oracle.com if you need additional information or have any
    1.25 + * questions.
    1.26 + *
    1.27 + */
    1.28 +
    1.29 +#include "incls/_precompiled.incl"
    1.30 +#include "incls/_sharkCompiler.cpp.incl"
    1.31 +
    1.32 +#include <fnmatch.h>
    1.33 +
    1.34 +using namespace llvm;
    1.35 +
    1.36 +#if SHARK_LLVM_VERSION >= 27
    1.37 +namespace {
    1.38 +  cl::opt<std::string>
    1.39 +  MCPU("mcpu");
    1.40 +
    1.41 +  cl::list<std::string>
    1.42 +  MAttrs("mattr",
    1.43 +         cl::CommaSeparated);
    1.44 +}
    1.45 +#endif
    1.46 +
    1.47 +SharkCompiler::SharkCompiler()
    1.48 +  : AbstractCompiler() {
    1.49 +  // Create the lock to protect the memory manager and execution engine
    1.50 +  _execution_engine_lock = new Monitor(Mutex::leaf, "SharkExecutionEngineLock");
    1.51 +  MutexLocker locker(execution_engine_lock());
    1.52 +
    1.53 +  // Make LLVM safe for multithreading
    1.54 +  if (!llvm_start_multithreaded())
    1.55 +    fatal("llvm_start_multithreaded() failed");
    1.56 +
    1.57 +  // Initialize the native target
    1.58 +  InitializeNativeTarget();
    1.59 +
    1.60 +  // Create the two contexts which we'll use
    1.61 +  _normal_context = new SharkContext("normal");
    1.62 +  _native_context = new SharkContext("native");
    1.63 +
    1.64 +  // Create the memory manager
    1.65 +  _memory_manager = new SharkMemoryManager();
    1.66 +
    1.67 +#if SHARK_LLVM_VERSION >= 27
    1.68 +  // Finetune LLVM for the current host CPU.
    1.69 +  StringMap<bool> Features;
    1.70 +  bool gotCpuFeatures = llvm::sys::getHostCPUFeatures(Features);
    1.71 +  std::string cpu("-mcpu=" + llvm::sys::getHostCPUName());
    1.72 +
    1.73 +  std::vector<const char*> args;
    1.74 +  args.push_back(""); // program name
    1.75 +  args.push_back(cpu.c_str());
    1.76 +
    1.77 +  std::string mattr("-mattr=");
    1.78 +  if(gotCpuFeatures){
    1.79 +    for(StringMap<bool>::iterator I = Features.begin(),
    1.80 +      E = Features.end(); I != E; ++I){
    1.81 +      if(I->second){
    1.82 +        std::string attr(I->first());
    1.83 +        mattr+="+"+attr+",";
    1.84 +      }
    1.85 +    }
    1.86 +    args.push_back(mattr.c_str());
    1.87 +  }
    1.88 +
    1.89 +  args.push_back(0);  // terminator
    1.90 +  cl::ParseCommandLineOptions(args.size() - 1, (char **) &args[0]);
    1.91 +
    1.92 +  // Create the JIT
    1.93 +  std::string ErrorMsg;
    1.94 +
    1.95 +  EngineBuilder builder(_normal_context->module());
    1.96 +  builder.setMCPU(MCPU);
    1.97 +  builder.setMAttrs(MAttrs);
    1.98 +  builder.setJITMemoryManager(memory_manager());
    1.99 +  builder.setEngineKind(EngineKind::JIT);
   1.100 +  builder.setErrorStr(&ErrorMsg);
   1.101 +  _execution_engine = builder.create();
   1.102 +
   1.103 +  if (!execution_engine()) {
   1.104 +    if (!ErrorMsg.empty())
   1.105 +      printf("Error while creating Shark JIT: %s\n",ErrorMsg.c_str());
   1.106 +    else
   1.107 +      printf("Unknown error while creating Shark JIT\n");
   1.108 +    exit(1);
   1.109 +  }
   1.110 +
   1.111 +  execution_engine()->addModule(
   1.112 +    _native_context->module());
   1.113 +#else
   1.114 +  _execution_engine = ExecutionEngine::createJIT(
   1.115 +    _normal_context->module_provider(),
   1.116 +    NULL, memory_manager(), CodeGenOpt::Default);
   1.117 +  execution_engine()->addModuleProvider(
   1.118 +    _native_context->module_provider());
   1.119 +#endif
   1.120 +
   1.121 +  // All done
   1.122 +  mark_initialized();
   1.123 +}
   1.124 +
   1.125 +void SharkCompiler::initialize() {
   1.126 +  ShouldNotCallThis();
   1.127 +}
   1.128 +
   1.129 +void SharkCompiler::compile_method(ciEnv*    env,
   1.130 +                                   ciMethod* target,
   1.131 +                                   int       entry_bci) {
   1.132 +  assert(is_initialized(), "should be");
   1.133 +  ResourceMark rm;
   1.134 +  const char *name = methodname(
   1.135 +    target->holder()->name()->as_utf8(), target->name()->as_utf8());
   1.136 +
   1.137 +  // Do the typeflow analysis
   1.138 +  ciTypeFlow *flow;
   1.139 +  if (entry_bci == InvocationEntryBci)
   1.140 +    flow = target->get_flow_analysis();
   1.141 +  else
   1.142 +    flow = target->get_osr_flow_analysis(entry_bci);
   1.143 +  if (flow->failing())
   1.144 +    return;
   1.145 +  if (SharkPrintTypeflowOf != NULL) {
   1.146 +    if (!fnmatch(SharkPrintTypeflowOf, name, 0))
   1.147 +      flow->print_on(tty);
   1.148 +  }
   1.149 +
   1.150 +  // Create the recorders
   1.151 +  Arena arena;
   1.152 +  env->set_oop_recorder(new OopRecorder(&arena));
   1.153 +  OopMapSet oopmaps;
   1.154 +  env->set_debug_info(new DebugInformationRecorder(env->oop_recorder()));
   1.155 +  env->debug_info()->set_oopmaps(&oopmaps);
   1.156 +  env->set_dependencies(new Dependencies(env));
   1.157 +
   1.158 +  // Create the code buffer and builder
   1.159 +  CodeBuffer hscb("Shark", 256 * K, 64 * K);
   1.160 +  hscb.initialize_oop_recorder(env->oop_recorder());
   1.161 +  MacroAssembler *masm = new MacroAssembler(&hscb);
   1.162 +  SharkCodeBuffer cb(masm);
   1.163 +  SharkBuilder builder(&cb);
   1.164 +
   1.165 +  // Emit the entry point
   1.166 +  SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry));
   1.167 +
   1.168 +  // Build the LLVM IR for the method
   1.169 +  Function *function = SharkFunction::build(env, &builder, flow, name);
   1.170 +
   1.171 +  // Generate native code.  It's unpleasant that we have to drop into
   1.172 +  // the VM to do this -- it blocks safepoints -- but I can't see any
   1.173 +  // other way to handle the locking.
   1.174 +  {
   1.175 +    ThreadInVMfromNative tiv(JavaThread::current());
   1.176 +    generate_native_code(entry, function, name);
   1.177 +  }
   1.178 +
   1.179 +  // Install the method into the VM
   1.180 +  CodeOffsets offsets;
   1.181 +  offsets.set_value(CodeOffsets::Deopt, 0);
   1.182 +  offsets.set_value(CodeOffsets::Exceptions, 0);
   1.183 +  offsets.set_value(CodeOffsets::Verified_Entry,
   1.184 +                    target->is_static() ? 0 : wordSize);
   1.185 +
   1.186 +  ExceptionHandlerTable handler_table;
   1.187 +  ImplicitExceptionTable inc_table;
   1.188 +
   1.189 +  env->register_method(target,
   1.190 +                       entry_bci,
   1.191 +                       &offsets,
   1.192 +                       0,
   1.193 +                       &hscb,
   1.194 +                       0,
   1.195 +                       &oopmaps,
   1.196 +                       &handler_table,
   1.197 +                       &inc_table,
   1.198 +                       this,
   1.199 +                       env->comp_level(),
   1.200 +                       false,
   1.201 +                       false);
   1.202 +}
   1.203 +
   1.204 +nmethod* SharkCompiler::generate_native_wrapper(MacroAssembler* masm,
   1.205 +                                                methodHandle    target,
   1.206 +                                                BasicType*      arg_types,
   1.207 +                                                BasicType       return_type) {
   1.208 +  assert(is_initialized(), "should be");
   1.209 +  ResourceMark rm;
   1.210 +  const char *name = methodname(
   1.211 +    target->klass_name()->as_utf8(), target->name()->as_utf8());
   1.212 +
   1.213 +  // Create the code buffer and builder
   1.214 +  SharkCodeBuffer cb(masm);
   1.215 +  SharkBuilder builder(&cb);
   1.216 +
   1.217 +  // Emit the entry point
   1.218 +  SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry));
   1.219 +
   1.220 +  // Build the LLVM IR for the method
   1.221 +  SharkNativeWrapper *wrapper = SharkNativeWrapper::build(
   1.222 +    &builder, target, name, arg_types, return_type);
   1.223 +
   1.224 +  // Generate native code
   1.225 +  generate_native_code(entry, wrapper->function(), name);
   1.226 +
   1.227 +  // Return the nmethod for installation in the VM
   1.228 +  return nmethod::new_native_nmethod(target,
   1.229 +                                     masm->code(),
   1.230 +                                     0,
   1.231 +                                     0,
   1.232 +                                     wrapper->frame_size(),
   1.233 +                                     wrapper->receiver_offset(),
   1.234 +                                     wrapper->lock_offset(),
   1.235 +                                     wrapper->oop_maps());
   1.236 +}
   1.237 +
   1.238 +void SharkCompiler::generate_native_code(SharkEntry* entry,
   1.239 +                                         Function*   function,
   1.240 +                                         const char* name) {
   1.241 +  // Print the LLVM bitcode, if requested
   1.242 +  if (SharkPrintBitcodeOf != NULL) {
   1.243 +    if (!fnmatch(SharkPrintBitcodeOf, name, 0))
   1.244 +      function->dump();
   1.245 +  }
   1.246 +
   1.247 +  // Compile to native code
   1.248 +  address code = NULL;
   1.249 +  context()->add_function(function);
   1.250 +  {
   1.251 +    MutexLocker locker(execution_engine_lock());
   1.252 +    free_queued_methods();
   1.253 +
   1.254 +    if (SharkPrintAsmOf != NULL) {
   1.255 +#if SHARK_LLVM_VERSION >= 27
   1.256 +#ifndef NDEBUG
   1.257 +      if (!fnmatch(SharkPrintAsmOf, name, 0)) {
   1.258 +        llvm::SetCurrentDebugType(X86_ONLY("x86-emitter") NOT_X86("jit"));
   1.259 +        llvm::DebugFlag = true;
   1.260 +      }
   1.261 +      else {
   1.262 +        llvm::SetCurrentDebugType("");
   1.263 +        llvm::DebugFlag = false;
   1.264 +      }
   1.265 +#endif // !NDEBUG
   1.266 +#else
   1.267 +      // NB you need to patch LLVM with http://tinyurl.com/yf3baln for this
   1.268 +      std::vector<const char*> args;
   1.269 +      args.push_back(""); // program name
   1.270 +      if (!fnmatch(SharkPrintAsmOf, name, 0))
   1.271 +        args.push_back("-debug-only=x86-emitter");
   1.272 +      else
   1.273 +        args.push_back("-debug-only=none");
   1.274 +      args.push_back(0);  // terminator
   1.275 +      cl::ParseCommandLineOptions(args.size() - 1, (char **) &args[0]);
   1.276 +#endif // SHARK_LLVM_VERSION
   1.277 +    }
   1.278 +    memory_manager()->set_entry_for_function(function, entry);
   1.279 +    code = (address) execution_engine()->getPointerToFunction(function);
   1.280 +  }
   1.281 +  entry->set_entry_point(code);
   1.282 +  entry->set_function(function);
   1.283 +  entry->set_context(context());
   1.284 +  address code_start = entry->code_start();
   1.285 +  address code_limit = entry->code_limit();
   1.286 +
   1.287 +  // Register generated code for profiling, etc
   1.288 +  if (JvmtiExport::should_post_dynamic_code_generated())
   1.289 +    JvmtiExport::post_dynamic_code_generated(name, code_start, code_limit);
   1.290 +
   1.291 +  // Print debug information, if requested
   1.292 +  if (SharkTraceInstalls) {
   1.293 +    tty->print_cr(
   1.294 +      " [%p-%p): %s (%d bytes code)",
   1.295 +      code_start, code_limit, name, code_limit - code_start);
   1.296 +  }
   1.297 +}
   1.298 +
   1.299 +void SharkCompiler::free_compiled_method(address code) {
   1.300 +  // This method may only be called when the VM is at a safepoint.
   1.301 +  // All _thread_in_vm threads will be waiting for the safepoint to
   1.302 +  // finish with the exception of the VM thread, so we can consider
   1.303 +  // ourself the owner of the execution engine lock even though we
   1.304 +  // can't actually acquire it at this time.
   1.305 +  assert(Thread::current()->is_VM_thread(), "must be called by VM thread");
   1.306 +  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
   1.307 +
   1.308 +  SharkEntry *entry = (SharkEntry *) code;
   1.309 +  entry->context()->push_to_free_queue(entry->function());
   1.310 +}
   1.311 +
   1.312 +void SharkCompiler::free_queued_methods() {
   1.313 +  // The free queue is protected by the execution engine lock
   1.314 +  assert(execution_engine_lock()->owned_by_self(), "should be");
   1.315 +
   1.316 +  while (true) {
   1.317 +    Function *function = context()->pop_from_free_queue();
   1.318 +    if (function == NULL)
   1.319 +      break;
   1.320 +
   1.321 +    execution_engine()->freeMachineCodeForFunction(function);
   1.322 +    function->eraseFromParent();
   1.323 +  }
   1.324 +}
   1.325 +
   1.326 +const char* SharkCompiler::methodname(const char* klass, const char* method) {
   1.327 +  char *buf = NEW_RESOURCE_ARRAY(char, strlen(klass) + 2 + strlen(method) + 1);
   1.328 +
   1.329 +  char *dst = buf;
   1.330 +  for (const char *c = klass; *c; c++) {
   1.331 +    if (*c == '/')
   1.332 +      *(dst++) = '.';
   1.333 +    else
   1.334 +      *(dst++) = *c;
   1.335 +  }
   1.336 +  *(dst++) = ':';
   1.337 +  *(dst++) = ':';
   1.338 +  for (const char *c = method; *c; c++) {
   1.339 +    *(dst++) = *c;
   1.340 +  }
   1.341 +  *(dst++) = '\0';
   1.342 +  return buf;
   1.343 +}

mercurial