diff a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp
--- a/src/hotspot/share/ci/ciMethod.cpp
+++ b/src/hotspot/share/ci/ciMethod.cpp
@@ -21,10 +21,11 @@
  * questions.
  *
  */
 
 #include "precompiled.hpp"
+#include "cds/classPreloader.hpp"
 #include "ci/ciCallProfile.hpp"
 #include "ci/ciExceptionHandler.hpp"
 #include "ci/ciInstanceKlass.hpp"
 #include "ci/ciMethod.hpp"
 #include "ci/ciMethodBlocks.hpp"
@@ -32,10 +33,11 @@
 #include "ci/ciStreams.hpp"
 #include "ci/ciSymbol.hpp"
 #include "ci/ciReplay.hpp"
 #include "ci/ciSymbols.hpp"
 #include "ci/ciUtilities.inline.hpp"
+#include "compiler/compileTask.hpp"
 #include "compiler/abstractCompiler.hpp"
 #include "compiler/compilerDefinitions.inline.hpp"
 #include "compiler/compilerOracle.hpp"
 #include "compiler/methodLiveness.hpp"
 #include "interpreter/interpreter.hpp"
@@ -46,10 +48,11 @@
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/generateOopMap.hpp"
 #include "oops/method.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/trainingData.hpp"
 #include "prims/methodHandles.hpp"
 #include "runtime/deoptimization.hpp"
 #include "runtime/handles.inline.hpp"
 #include "utilities/bitMap.inline.hpp"
 #include "utilities/xmlstream.hpp"
@@ -141,10 +144,11 @@
   _name = env->get_symbol(h_m->name());
   ciSymbol* sig_symbol = env->get_symbol(h_m->signature());
   constantPoolHandle cpool(Thread::current(), h_m->constants());
   _signature = new (env->arena()) ciSignature(_holder, cpool, sig_symbol);
   _method_data = nullptr;
+  _method_data_recorded = nullptr;
   // Take a snapshot of these values, so they will be commensurate with the MDO.
   if (ProfileInterpreter || CompilerConfig::is_c1_profiling()) {
     int invcnt = h_m->interpreter_invocation_count();
     // if the value overflowed report it as max int
     _interpreter_invocation_count = invcnt < 0 ? max_jint : invcnt ;
@@ -157,10 +161,26 @@
     _interpreter_invocation_count = 1;
   _inline_instructions_size = -1;
   if (ReplayCompiles) {
     ciReplay::initialize(this);
   }
+  DirectiveSet* directives = DirectivesStack::getMatchingDirective(h_m, CURRENT_ENV->task()->compiler());
+  ccstrlist bci_list = directives->TooManyTrapsAtBCIOption;
+  int len = (int)strlen(bci_list);
+  Arena* arena = CURRENT_ENV->arena();
+  _has_trap_at_bci = new (arena) GrowableArray<int>(arena, 2, 0, 0);
+  for (int i = 0; i < len; i++) {
+    int v = -1;
+    int read;
+    if (sscanf(bci_list + i, "%i%n", &v, &read) != 1) {
+      warning("wrong format for TooManyTrapsAtBCI option: \"%s\"", bci_list);
+      break;
+    }
+    assert(v >= 0 && v < (1<<16), "%i", v);
+    _has_trap_at_bci->append_if_missing(v);
+    i += read;
+  }
 }
 
 
 // ------------------------------------------------------------------
 // ciMethod::ciMethod
@@ -172,15 +192,17 @@
                    ciInstanceKlass* accessor) :
   ciMetadata((Metadata*)nullptr),
   _name(                   name),
   _holder(                 holder),
   _method_data(            nullptr),
+  _method_data_recorded(   nullptr),
   _method_blocks(          nullptr),
   _intrinsic_id(           vmIntrinsics::_none),
   _inline_instructions_size(-1),
   _can_be_statically_bound(false),
   _can_omit_stack_trace(true),
+  _has_trap_at_bci(        nullptr),
   _liveness(               nullptr)
 #if defined(COMPILER2)
   ,
   _flow(                   nullptr),
   _bcea(                   nullptr)
@@ -982,19 +1004,23 @@
 // ------------------------------------------------------------------
 // ciMethod::ensure_method_data
 //
 // Generate new MethodData* objects at compile time.
 // Return true if allocation was successful or no MDO is required.
-bool ciMethod::ensure_method_data(const methodHandle& h_m) {
+bool ciMethod::ensure_method_data(const methodHandle& h_m, bool training_data_only) {
   EXCEPTION_CONTEXT;
   if (is_native() || is_abstract() || h_m()->is_accessor()) {
     return true;
   }
   if (h_m()->method_data() == nullptr) {
-    Method::build_profiling_method_data(h_m, THREAD);
-    if (HAS_PENDING_EXCEPTION) {
-      CLEAR_PENDING_EXCEPTION;
+    if (training_data_only) {
+      Method::install_training_method_data(h_m);
+    } else {
+      Method::build_profiling_method_data(h_m, THREAD);
+      if (HAS_PENDING_EXCEPTION) {
+        CLEAR_PENDING_EXCEPTION;
+      }
     }
   }
   if (h_m()->method_data() != nullptr) {
     _method_data = CURRENT_ENV->get_method_data(h_m()->method_data());
     return _method_data->load_data();
@@ -1003,42 +1029,73 @@
     return false;
   }
 }
 
 // public, retroactive version
-bool ciMethod::ensure_method_data() {
+bool ciMethod::ensure_method_data(bool training_data_only) {
   bool result = true;
   if (_method_data == nullptr || _method_data->is_empty()) {
     GUARDED_VM_ENTRY({
       methodHandle mh(Thread::current(), get_Method());
-      result = ensure_method_data(mh);
+      result = ensure_method_data(mh, training_data_only);
     });
   }
   return result;
 }
 
 
 // ------------------------------------------------------------------
 // ciMethod::method_data
 //
 ciMethodData* ciMethod::method_data() {
-  if (_method_data != nullptr) {
-    return _method_data;
-  }
-  VM_ENTRY_MARK;
-  ciEnv* env = CURRENT_ENV;
-  Thread* my_thread = JavaThread::current();
-  methodHandle h_m(my_thread, get_Method());
-
-  if (h_m()->method_data() != nullptr) {
-    _method_data = CURRENT_ENV->get_method_data(h_m()->method_data());
-    _method_data->load_data();
+  if (CURRENT_ENV->task()->is_precompiled() && CURRENT_ENV->task()->comp_level() == CompLevel_full_optimization) {
+    if (_method_data_recorded == nullptr) {
+      VM_ENTRY_MARK;
+      methodHandle h_m(thread, get_Method());
+      MethodTrainingData* mtd = TrainingData::lookup_for(h_m());
+      MethodData* mdo = (mtd != nullptr ? mtd->final_profile() : nullptr);
+      DirectiveSet* directives = DirectivesStack::getMatchingDirective(h_m, CURRENT_ENV->task()->compiler());
+      if (mdo == nullptr || directives->IgnoreRecordedProfileOption) {
+        if (directives->IgnoreRecordedProfileOption) {
+          ResourceMark rm;
+          log_debug(precompile)("Ignore recorded profile for %s", h_m->name_and_sig_as_C_string());
+        } else {
+          ResourceMark rm;
+          log_debug(precompile)("No profile for %s", h_m->name_and_sig_as_C_string());
+        }
+        _method_data_recorded = CURRENT_ENV->get_empty_methodData();
+      } else {
+        if (mdo->extra_data_lock() == nullptr) {
+          assert(!HAS_PENDING_EXCEPTION, "");
+          mdo->restore_unshareable_info(thread);
+          assert(!HAS_PENDING_EXCEPTION, "");
+        }
+        _method_data_recorded = CURRENT_ENV->get_method_data(mdo);
+        _method_data_recorded->load_data();
+        {
+          ResourceMark rm;
+          log_debug(precompile)("Recorded profile " PTR_FORMAT " for %s", p2i(mdo), h_m->name_and_sig_as_C_string());
+        }
+      }
+    }
+    assert(_method_data_recorded != nullptr, "");
+    return _method_data_recorded;
   } else {
-    _method_data = CURRENT_ENV->get_empty_methodData();
+    if (_method_data != nullptr) {
+      return _method_data;
+    }
+    VM_ENTRY_MARK;
+    methodHandle h_m(thread, get_Method());
+    MethodData* mdo = h_m()->method_data();
+    if (mdo != nullptr) {
+      _method_data = CURRENT_ENV->get_method_data(mdo);
+      _method_data->load_data();
+    } else {
+      _method_data = CURRENT_ENV->get_empty_methodData();
+    }
+    return _method_data;
   }
-  return _method_data;
-
 }
 
 // ------------------------------------------------------------------
 // ciMethod::method_data_or_null
 // Returns a pointer to ciMethodData if MDO exists on the VM side,
@@ -1089,10 +1146,17 @@
   check_is_loaded();
   ciEnv* env = CURRENT_ENV;
   if (is_c1_compile(env->comp_level())) {
     return _is_c1_compilable;
   }
+
+#if INCLUDE_JVMCI
+  if (EnableJVMCI && UseJVMCICompiler &&
+      env->comp_level() == CompLevel_full_optimization && !ClassPreloader::class_preloading_finished()) {
+    return false;
+  }
+#endif
   return _is_c2_compilable;
 }
 
 // ------------------------------------------------------------------
 // ciMethod::has_compiled_code
@@ -1128,19 +1192,49 @@
 // not highly relevant to an inlined method.  So we use the more
 // specific accessor nmethod::insts_size.
 // Also some instructions inside the code are excluded from inline
 // heuristic (e.g. post call nop instructions; see InlineSkippedInstructionsCounter)
 int ciMethod::inline_instructions_size() {
+  if (_inline_instructions_size == -1) {
+    if (TrainingData::have_data()) {
+      GUARDED_VM_ENTRY(
+        CompLevel level = static_cast<CompLevel>(CURRENT_ENV->comp_level());
+        methodHandle top_level_mh(Thread::current(), CURRENT_ENV->task()->method());
+        MethodTrainingData* mtd = MethodTrainingData::find(top_level_mh);
+        if (mtd != nullptr) {
+          CompileTrainingData* ctd = mtd->last_toplevel_compile(level);
+          if (ctd != nullptr) {
+            methodHandle mh(Thread::current(), get_Method());
+            MethodTrainingData* this_mtd = MethodTrainingData::find(mh);
+            if (this_mtd != nullptr) {
+              auto r = ctd->ci_records().ciMethod__inline_instructions_size.find(this_mtd);
+              if (r.is_valid()) {
+                _inline_instructions_size = r.result();
+              }
+            }
+          }
+        }
+      );
+    }
+  }
   if (_inline_instructions_size == -1) {
     GUARDED_VM_ENTRY(
       nmethod* code = get_Method()->code();
-      if (code != nullptr && (code->comp_level() == CompLevel_full_optimization)) {
+      if (code != nullptr && !code->is_scc() && (code->comp_level() == CompLevel_full_optimization)) {
         int isize = code->insts_end() - code->verified_entry_point() - code->skipped_instructions_size();
         _inline_instructions_size = isize > 0 ? isize : 0;
       } else {
         _inline_instructions_size = 0;
       }
+      if (TrainingData::need_data()) {
+        CompileTrainingData* ctd = CURRENT_ENV->task()->training_data();
+        if (ctd != nullptr) {
+          methodHandle mh(Thread::current(), get_Method());
+          MethodTrainingData* this_mtd = MethodTrainingData::make(mh);
+          ctd->ci_records().ciMethod__inline_instructions_size.append_if_missing(_inline_instructions_size, this_mtd);
+        }
+      }
     );
   }
   return _inline_instructions_size;
 }
 
@@ -1165,10 +1259,21 @@
 }
 
 // ------------------------------------------------------------------
 // ciMethod::was_never_executed
 bool ciMethod::was_executed_more_than(int times) {
+  // Invocation counter is reset when the Method* is compiled.
+  // If the method has compiled code we therefore assume it has
+  // be executed more than n times.
+  if (is_accessor() || is_empty() || has_compiled_code()) {
+    // interpreter doesn't bump invocation counter of trivial methods
+    // compiler does not bump invocation counter of compiled methods
+    return true;
+  }
+  if (!method_data()->is_empty()) {
+    return (method_data()->invocation_count() > times);
+  }
   VM_ENTRY_MARK;
   return get_Method()->was_executed_more_than(times);
 }
 
 // ------------------------------------------------------------------
