1 /*
  2  * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #ifndef SHARE_COMPILER_ABSTRACTCOMPILER_HPP
 26 #define SHARE_COMPILER_ABSTRACTCOMPILER_HPP
 27 
 28 #include "ci/compilerInterface.hpp"
 29 #include "compiler/compilerDefinitions.hpp"
 30 #include "compiler/compilerDirectives.hpp"
 31 
 32 typedef void (*initializer)(void);
 33 
 34 // Per-compiler statistics
 35 class CompilerStatistics {
 36   friend class VMStructs;
 37 
 38  public:
 39   class Data {
 40     friend class VMStructs;
 41   public:
 42     elapsedTimer _time;  // time spent compiling
 43     uint _bytes;         // number of bytecodes compiled, including inlined bytecodes
 44     uint _count;         // number of compilations
 45     Data() : _bytes(0), _count(0) {}
 46     void update(elapsedTimer time, int bytes) {
 47       _time.add(&time);
 48       _bytes += bytes;
 49       _count++;
 50     }
 51     void reset() {
 52       _time.reset();
 53     }
 54   };
 55 
 56  public:
 57   Data _standard;  // stats for non-OSR compilations
 58   Data _osr;       // stats for OSR compilations
 59   Data _bailout;
 60   Data _invalidated;
 61   Data _made_not_entrant;
 62   uint _nmethods_size; //
 63   uint _nmethods_code_size;
 64 
 65   double total_time() { return _standard._time.seconds() + _osr._time.seconds(); }
 66 
 67   double bytes_per_second() {
 68     uint bytes = _standard._bytes + _osr._bytes;
 69     if (bytes == 0) {
 70       return 0.0;
 71     }
 72     double seconds = total_time();
 73     return seconds == 0.0 ? 0.0 : (bytes / seconds);
 74   }
 75 
 76   CompilerStatistics() : _nmethods_size(0), _nmethods_code_size(0) {}
 77 };
 78 
 79 class AbstractCompiler : public CHeapObj<mtCompiler> {
 80  private:
 81   volatile int _num_compiler_threads;
 82 
 83  protected:
 84   volatile int _compiler_state;
 85   // Used for tracking global state of compiler runtime initialization
 86   enum { uninitialized, initializing, initialized, failed, shut_down };
 87 
 88   // This method returns true for the first compiler thread that reaches that methods.
 89   // This thread will initialize the compiler runtime.
 90   bool should_perform_init();
 91 
 92  private:
 93   const CompilerType _type;
 94 
 95   CompilerStatistics _stats;
 96 
 97  public:
 98   AbstractCompiler(CompilerType type) : _num_compiler_threads(0), _compiler_state(uninitialized), _type(type) {}
 99 
100   // This function determines the compiler thread that will perform the
101   // shutdown of the corresponding compiler runtime.
102   bool should_perform_shutdown();
103 
104   // Name of this compiler
105   virtual const char* name() = 0;
106 
107   // Determine if the current compiler provides an intrinsic
108   // for method 'method'. An intrinsic is available if:
109   //  - the intrinsic is enabled (by using the appropriate command-line flag,
110   //    the command-line compile ommand, or a compiler directive)
111   //  - the platform on which the VM is running supports the intrinsic
112   //    (i.e., the platform provides the instructions necessary for the compiler
113   //    to generate the intrinsic code).
114   //
115   // The directive provides the compilation context and includes pre-evaluated values
116   // dependent on VM flags, compile commands, and compiler directives.
117   //
118   // Usually, the compilation context is the caller of the method 'method'.
119   // The only case when for a non-recursive method 'method' the compilation context
120   // is not the caller of the 'method' (but it is the method itself) is
121   // java.lang.ref.Reference::get.
122   // For java.lang.ref.Reference::get, the intrinsic version is used
123   // instead of the compiled version so that the value in the referent
124   // field can be registered by the G1 pre-barrier code. The intrinsified
125   // version of Reference::get also adds a memory barrier to prevent
126   // commoning reads from the referent field across safepoint since GC
127   // can change the referent field's value. See Compile::Compile()
128   // in src/share/vm/opto/compile.cpp or
129   // GraphBuilder::GraphBuilder() in src/share/vm/c1/c1_GraphBuilder.cpp
130   // for more details.
131 
132   bool is_intrinsic_available(const methodHandle& method, DirectiveSet* directive) {
133     vmIntrinsics::ID id = method->intrinsic_id();
134     assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
135     return is_intrinsic_supported(method) &&
136            vmIntrinsics::is_intrinsic_available(id) &&
137            !directive->is_intrinsic_disabled(id);
138   }
139 
140   // Determines if an intrinsic is supported by the compiler, that is,
141   // the compiler provides the instructions necessary to generate
142   // the intrinsic code for method 'method'.
143   //
144   // The 'is_intrinsic_supported' method is an allow-list, that is,
145   // by default no intrinsics are supported by a compiler except
146   // the ones listed in the method. Overriding methods should conform
147   // to this behavior.
148   virtual bool is_intrinsic_supported(const methodHandle& method) {
149     return false;
150   }
151 
152   // Compiler type queries.
153   bool is_c1() const                     { return _type == compiler_c1; }
154   bool is_c2() const                     { return _type == compiler_c2; }
155   bool is_jvmci() const                  { return _type == compiler_jvmci; }
156   CompilerType type() const              { return _type; }
157 
158   // Compiler threads are hidden by default.
159   virtual bool is_hidden_from_external_view() const { return true; }
160 
161   // Customization
162   virtual void initialize () = 0;
163 
164   void set_num_compiler_threads(int num) { _num_compiler_threads = num;  }
165   int num_compiler_threads()             { return _num_compiler_threads; }
166 
167   // Get/set state of compiler objects
168   bool is_initialized()           { return _compiler_state == initialized; }
169   bool is_failed     ()           { return _compiler_state == failed;}
170   void set_state     (int state);
171   void set_shut_down ()           { set_state(shut_down); }
172   // Compilation entry point for methods
173   virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci, bool install_code, DirectiveSet* directive) {
174     ShouldNotReachHere();
175   }
176 
177   // Notifies this compiler that the current thread (`current`) is about to stop.
178   // The current thread currently holds the CompileThread_lock.
179   virtual void stopping_compiler_thread(CompilerThread* current) {
180     // Do nothing
181   }
182 
183   // Notifies this compiler that queue is empty just prior to waiting on
184   // MethodCompileQueue_lock which is held by the current thread (`thread`).
185   virtual void on_empty_queue(CompileQueue* queue, CompilerThread* thread) {
186     // Do nothing
187   }
188 
189   // Print compilation timers and statistics
190   virtual void print_timers() {
191     ShouldNotReachHere();
192   }
193 
194   CompilerStatistics* stats() { return &_stats; }
195 };
196 
197 #endif // SHARE_COMPILER_ABSTRACTCOMPILER_HPP