src/share/vm/shark/sharkCompiler.cpp

changeset 0
f90c822e73f8
child 6876
710a3c8b516e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/vm/shark/sharkCompiler.cpp	Wed Apr 27 01:25:04 2016 +0800
     1.3 @@ -0,0 +1,366 @@
     1.4 +/*
     1.5 + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
     1.6 + * Copyright 2008, 2009, 2010, 2011 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 "precompiled.hpp"
    1.30 +#include "ci/ciEnv.hpp"
    1.31 +#include "ci/ciMethod.hpp"
    1.32 +#include "code/debugInfoRec.hpp"
    1.33 +#include "code/dependencies.hpp"
    1.34 +#include "code/exceptionHandlerTable.hpp"
    1.35 +#include "code/oopRecorder.hpp"
    1.36 +#include "compiler/abstractCompiler.hpp"
    1.37 +#include "compiler/oopMap.hpp"
    1.38 +#include "shark/llvmHeaders.hpp"
    1.39 +#include "shark/sharkBuilder.hpp"
    1.40 +#include "shark/sharkCodeBuffer.hpp"
    1.41 +#include "shark/sharkCompiler.hpp"
    1.42 +#include "shark/sharkContext.hpp"
    1.43 +#include "shark/sharkEntry.hpp"
    1.44 +#include "shark/sharkFunction.hpp"
    1.45 +#include "shark/sharkMemoryManager.hpp"
    1.46 +#include "shark/sharkNativeWrapper.hpp"
    1.47 +#include "shark/shark_globals.hpp"
    1.48 +#include "utilities/debug.hpp"
    1.49 +
    1.50 +#include <fnmatch.h>
    1.51 +
    1.52 +using namespace llvm;
    1.53 +
    1.54 +namespace {
    1.55 +  cl::opt<std::string>
    1.56 +  MCPU("mcpu");
    1.57 +
    1.58 +  cl::list<std::string>
    1.59 +  MAttrs("mattr",
    1.60 +         cl::CommaSeparated);
    1.61 +}
    1.62 +
    1.63 +SharkCompiler::SharkCompiler()
    1.64 +  : AbstractCompiler() {
    1.65 +  // Create the lock to protect the memory manager and execution engine
    1.66 +  _execution_engine_lock = new Monitor(Mutex::leaf, "SharkExecutionEngineLock");
    1.67 +  MutexLocker locker(execution_engine_lock());
    1.68 +
    1.69 +  // Make LLVM safe for multithreading
    1.70 +  if (!llvm_start_multithreaded())
    1.71 +    fatal("llvm_start_multithreaded() failed");
    1.72 +
    1.73 +  // Initialize the native target
    1.74 +  InitializeNativeTarget();
    1.75 +
    1.76 +  // MCJIT require a native AsmPrinter
    1.77 +  InitializeNativeTargetAsmPrinter();
    1.78 +
    1.79 +  // Create the two contexts which we'll use
    1.80 +  _normal_context = new SharkContext("normal");
    1.81 +  _native_context = new SharkContext("native");
    1.82 +
    1.83 +  // Create the memory manager
    1.84 +  _memory_manager = new SharkMemoryManager();
    1.85 +
    1.86 +  // Finetune LLVM for the current host CPU.
    1.87 +  StringMap<bool> Features;
    1.88 +  bool gotCpuFeatures = llvm::sys::getHostCPUFeatures(Features);
    1.89 +  std::string cpu("-mcpu=" + llvm::sys::getHostCPUName());
    1.90 +
    1.91 +  std::vector<const char*> args;
    1.92 +  args.push_back(""); // program name
    1.93 +  args.push_back(cpu.c_str());
    1.94 +
    1.95 +  std::string mattr("-mattr=");
    1.96 +  if(gotCpuFeatures){
    1.97 +    for(StringMap<bool>::iterator I = Features.begin(),
    1.98 +      E = Features.end(); I != E; ++I){
    1.99 +      if(I->second){
   1.100 +        std::string attr(I->first());
   1.101 +        mattr+="+"+attr+",";
   1.102 +      }
   1.103 +    }
   1.104 +    args.push_back(mattr.c_str());
   1.105 +  }
   1.106 +
   1.107 +  args.push_back(0);  // terminator
   1.108 +  cl::ParseCommandLineOptions(args.size() - 1, (char **) &args[0]);
   1.109 +
   1.110 +  // Create the JIT
   1.111 +  std::string ErrorMsg;
   1.112 +
   1.113 +  EngineBuilder builder(_normal_context->module());
   1.114 +  builder.setMCPU(MCPU);
   1.115 +  builder.setMAttrs(MAttrs);
   1.116 +  builder.setJITMemoryManager(memory_manager());
   1.117 +  builder.setEngineKind(EngineKind::JIT);
   1.118 +  builder.setErrorStr(&ErrorMsg);
   1.119 +  if (! fnmatch(SharkOptimizationLevel, "None", 0)) {
   1.120 +    tty->print_cr("Shark optimization level set to: None");
   1.121 +    builder.setOptLevel(llvm::CodeGenOpt::None);
   1.122 +  } else if (! fnmatch(SharkOptimizationLevel, "Less", 0)) {
   1.123 +    tty->print_cr("Shark optimization level set to: Less");
   1.124 +    builder.setOptLevel(llvm::CodeGenOpt::Less);
   1.125 +  } else if (! fnmatch(SharkOptimizationLevel, "Aggressive", 0)) {
   1.126 +    tty->print_cr("Shark optimization level set to: Aggressive");
   1.127 +    builder.setOptLevel(llvm::CodeGenOpt::Aggressive);
   1.128 +  } // else Default is selected by, well, default :-)
   1.129 +  _execution_engine = builder.create();
   1.130 +
   1.131 +  if (!execution_engine()) {
   1.132 +    if (!ErrorMsg.empty())
   1.133 +      printf("Error while creating Shark JIT: %s\n",ErrorMsg.c_str());
   1.134 +    else
   1.135 +      printf("Unknown error while creating Shark JIT\n");
   1.136 +    exit(1);
   1.137 +  }
   1.138 +
   1.139 +  execution_engine()->addModule(_native_context->module());
   1.140 +
   1.141 +  // All done
   1.142 +  set_state(initialized);
   1.143 +}
   1.144 +
   1.145 +void SharkCompiler::initialize() {
   1.146 +  ShouldNotCallThis();
   1.147 +}
   1.148 +
   1.149 +void SharkCompiler::compile_method(ciEnv*    env,
   1.150 +                                   ciMethod* target,
   1.151 +                                   int       entry_bci) {
   1.152 +  assert(is_initialized(), "should be");
   1.153 +  ResourceMark rm;
   1.154 +  const char *name = methodname(
   1.155 +    target->holder()->name()->as_utf8(), target->name()->as_utf8());
   1.156 +
   1.157 +  // Do the typeflow analysis
   1.158 +  ciTypeFlow *flow;
   1.159 +  if (entry_bci == InvocationEntryBci)
   1.160 +    flow = target->get_flow_analysis();
   1.161 +  else
   1.162 +    flow = target->get_osr_flow_analysis(entry_bci);
   1.163 +  if (flow->failing())
   1.164 +    return;
   1.165 +  if (SharkPrintTypeflowOf != NULL) {
   1.166 +    if (!fnmatch(SharkPrintTypeflowOf, name, 0))
   1.167 +      flow->print_on(tty);
   1.168 +  }
   1.169 +
   1.170 +  // Create the recorders
   1.171 +  Arena arena;
   1.172 +  env->set_oop_recorder(new OopRecorder(&arena));
   1.173 +  OopMapSet oopmaps;
   1.174 +  env->set_debug_info(new DebugInformationRecorder(env->oop_recorder()));
   1.175 +  env->debug_info()->set_oopmaps(&oopmaps);
   1.176 +  env->set_dependencies(new Dependencies(env));
   1.177 +
   1.178 +  // Create the code buffer and builder
   1.179 +  CodeBuffer hscb("Shark", 256 * K, 64 * K);
   1.180 +  hscb.initialize_oop_recorder(env->oop_recorder());
   1.181 +  MacroAssembler *masm = new MacroAssembler(&hscb);
   1.182 +  SharkCodeBuffer cb(masm);
   1.183 +  SharkBuilder builder(&cb);
   1.184 +
   1.185 +  // Emit the entry point
   1.186 +  SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry));
   1.187 +
   1.188 +  // Build the LLVM IR for the method
   1.189 +  Function *function = SharkFunction::build(env, &builder, flow, name);
   1.190 +  if (env->failing()) {
   1.191 +    return;
   1.192 +  }
   1.193 +
   1.194 +  // Generate native code.  It's unpleasant that we have to drop into
   1.195 +  // the VM to do this -- it blocks safepoints -- but I can't see any
   1.196 +  // other way to handle the locking.
   1.197 +  {
   1.198 +    ThreadInVMfromNative tiv(JavaThread::current());
   1.199 +    generate_native_code(entry, function, name);
   1.200 +  }
   1.201 +
   1.202 +  // Install the method into the VM
   1.203 +  CodeOffsets offsets;
   1.204 +  offsets.set_value(CodeOffsets::Deopt, 0);
   1.205 +  offsets.set_value(CodeOffsets::Exceptions, 0);
   1.206 +  offsets.set_value(CodeOffsets::Verified_Entry,
   1.207 +                    target->is_static() ? 0 : wordSize);
   1.208 +
   1.209 +  ExceptionHandlerTable handler_table;
   1.210 +  ImplicitExceptionTable inc_table;
   1.211 +
   1.212 +  env->register_method(target,
   1.213 +                       entry_bci,
   1.214 +                       &offsets,
   1.215 +                       0,
   1.216 +                       &hscb,
   1.217 +                       0,
   1.218 +                       &oopmaps,
   1.219 +                       &handler_table,
   1.220 +                       &inc_table,
   1.221 +                       this,
   1.222 +                       env->comp_level(),
   1.223 +                       false,
   1.224 +                       false);
   1.225 +}
   1.226 +
   1.227 +nmethod* SharkCompiler::generate_native_wrapper(MacroAssembler* masm,
   1.228 +                                                methodHandle    target,
   1.229 +                                                int             compile_id,
   1.230 +                                                BasicType*      arg_types,
   1.231 +                                                BasicType       return_type) {
   1.232 +  assert(is_initialized(), "should be");
   1.233 +  ResourceMark rm;
   1.234 +  const char *name = methodname(
   1.235 +    target->klass_name()->as_utf8(), target->name()->as_utf8());
   1.236 +
   1.237 +  // Create the code buffer and builder
   1.238 +  SharkCodeBuffer cb(masm);
   1.239 +  SharkBuilder builder(&cb);
   1.240 +
   1.241 +  // Emit the entry point
   1.242 +  SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry));
   1.243 +
   1.244 +  // Build the LLVM IR for the method
   1.245 +  SharkNativeWrapper *wrapper = SharkNativeWrapper::build(
   1.246 +    &builder, target, name, arg_types, return_type);
   1.247 +
   1.248 +  // Generate native code
   1.249 +  generate_native_code(entry, wrapper->function(), name);
   1.250 +
   1.251 +  // Return the nmethod for installation in the VM
   1.252 +  return nmethod::new_native_nmethod(target,
   1.253 +                                     compile_id,
   1.254 +                                     masm->code(),
   1.255 +                                     0,
   1.256 +                                     0,
   1.257 +                                     wrapper->frame_size(),
   1.258 +                                     wrapper->receiver_offset(),
   1.259 +                                     wrapper->lock_offset(),
   1.260 +                                     wrapper->oop_maps());
   1.261 +}
   1.262 +
   1.263 +void SharkCompiler::generate_native_code(SharkEntry* entry,
   1.264 +                                         Function*   function,
   1.265 +                                         const char* name) {
   1.266 +  // Print the LLVM bitcode, if requested
   1.267 +  if (SharkPrintBitcodeOf != NULL) {
   1.268 +    if (!fnmatch(SharkPrintBitcodeOf, name, 0))
   1.269 +      function->dump();
   1.270 +  }
   1.271 +
   1.272 +  if (SharkVerifyFunction != NULL) {
   1.273 +    if (!fnmatch(SharkVerifyFunction, name, 0)) {
   1.274 +      verifyFunction(*function);
   1.275 +    }
   1.276 +  }
   1.277 +
   1.278 +  // Compile to native code
   1.279 +  address code = NULL;
   1.280 +  context()->add_function(function);
   1.281 +  {
   1.282 +    MutexLocker locker(execution_engine_lock());
   1.283 +    free_queued_methods();
   1.284 +
   1.285 +#ifndef NDEBUG
   1.286 +#if SHARK_LLVM_VERSION <= 31
   1.287 +#define setCurrentDebugType SetCurrentDebugType
   1.288 +#endif
   1.289 +    if (SharkPrintAsmOf != NULL) {
   1.290 +      if (!fnmatch(SharkPrintAsmOf, name, 0)) {
   1.291 +        llvm::setCurrentDebugType(X86_ONLY("x86-emitter") NOT_X86("jit"));
   1.292 +        llvm::DebugFlag = true;
   1.293 +      }
   1.294 +      else {
   1.295 +        llvm::setCurrentDebugType("");
   1.296 +        llvm::DebugFlag = false;
   1.297 +      }
   1.298 +    }
   1.299 +#ifdef setCurrentDebugType
   1.300 +#undef setCurrentDebugType
   1.301 +#endif
   1.302 +#endif // !NDEBUG
   1.303 +    memory_manager()->set_entry_for_function(function, entry);
   1.304 +    code = (address) execution_engine()->getPointerToFunction(function);
   1.305 +  }
   1.306 +  assert(code != NULL, "code must be != NULL");
   1.307 +  entry->set_entry_point(code);
   1.308 +  entry->set_function(function);
   1.309 +  entry->set_context(context());
   1.310 +  address code_start = entry->code_start();
   1.311 +  address code_limit = entry->code_limit();
   1.312 +
   1.313 +  // Register generated code for profiling, etc
   1.314 +  if (JvmtiExport::should_post_dynamic_code_generated())
   1.315 +    JvmtiExport::post_dynamic_code_generated(name, code_start, code_limit);
   1.316 +
   1.317 +  // Print debug information, if requested
   1.318 +  if (SharkTraceInstalls) {
   1.319 +    tty->print_cr(
   1.320 +      " [%p-%p): %s (%d bytes code)",
   1.321 +      code_start, code_limit, name, code_limit - code_start);
   1.322 +  }
   1.323 +}
   1.324 +
   1.325 +void SharkCompiler::free_compiled_method(address code) {
   1.326 +  // This method may only be called when the VM is at a safepoint.
   1.327 +  // All _thread_in_vm threads will be waiting for the safepoint to
   1.328 +  // finish with the exception of the VM thread, so we can consider
   1.329 +  // ourself the owner of the execution engine lock even though we
   1.330 +  // can't actually acquire it at this time.
   1.331 +  assert(Thread::current()->is_Compiler_thread(), "must be called by compiler thread");
   1.332 +  assert_locked_or_safepoint(CodeCache_lock);
   1.333 +
   1.334 +  SharkEntry *entry = (SharkEntry *) code;
   1.335 +  entry->context()->push_to_free_queue(entry->function());
   1.336 +}
   1.337 +
   1.338 +void SharkCompiler::free_queued_methods() {
   1.339 +  // The free queue is protected by the execution engine lock
   1.340 +  assert(execution_engine_lock()->owned_by_self(), "should be");
   1.341 +
   1.342 +  while (true) {
   1.343 +    Function *function = context()->pop_from_free_queue();
   1.344 +    if (function == NULL)
   1.345 +      break;
   1.346 +
   1.347 +    execution_engine()->freeMachineCodeForFunction(function);
   1.348 +    function->eraseFromParent();
   1.349 +  }
   1.350 +}
   1.351 +
   1.352 +const char* SharkCompiler::methodname(const char* klass, const char* method) {
   1.353 +  char *buf = NEW_RESOURCE_ARRAY(char, strlen(klass) + 2 + strlen(method) + 1);
   1.354 +
   1.355 +  char *dst = buf;
   1.356 +  for (const char *c = klass; *c; c++) {
   1.357 +    if (*c == '/')
   1.358 +      *(dst++) = '.';
   1.359 +    else
   1.360 +      *(dst++) = *c;
   1.361 +  }
   1.362 +  *(dst++) = ':';
   1.363 +  *(dst++) = ':';
   1.364 +  for (const char *c = method; *c; c++) {
   1.365 +    *(dst++) = *c;
   1.366 +  }
   1.367 +  *(dst++) = '\0';
   1.368 +  return buf;
   1.369 +}

mercurial