jvmciRuntime.cpp revision 9737:e286c9ccd58d
1169691Skan/*
2169691Skan * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
3169691Skan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4169691Skan *
5169691Skan * This code is free software; you can redistribute it and/or modify it
6169691Skan * under the terms of the GNU General Public License version 2 only, as
7169691Skan * published by the Free Software Foundation.
8169691Skan *
9169691Skan * This code is distributed in the hope that it will be useful, but WITHOUT
10169691Skan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11169691Skan * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12169691Skan * version 2 for more details (a copy is included in the LICENSE file that
13169691Skan * accompanied this code).
14169691Skan *
15169691Skan * You should have received a copy of the GNU General Public License version
16169691Skan * 2 along with this work; if not, write to the Free Software Foundation,
17169691Skan * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18169691Skan *
19169691Skan * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20169691Skan * or visit www.oracle.com if you need additional information or have any
21169691Skan * questions.
22169691Skan */
23169691Skan
24169691Skan#include "precompiled.hpp"
25169691Skan#include "asm/codeBuffer.hpp"
26169691Skan#include "code/codeCache.hpp"
27169691Skan#include "compiler/compileBroker.hpp"
28169691Skan#include "compiler/disassembler.hpp"
29169691Skan#include "jvmci/jvmciRuntime.hpp"
30169691Skan#include "jvmci/jvmciCompilerToVM.hpp"
31169691Skan#include "jvmci/jvmciCompiler.hpp"
32169691Skan#include "jvmci/jvmciJavaClasses.hpp"
33169691Skan#include "jvmci/jvmciEnv.hpp"
34169691Skan#include "memory/oopFactory.hpp"
35169691Skan#include "oops/oop.inline.hpp"
36169691Skan#include "oops/objArrayOop.inline.hpp"
37169691Skan#include "prims/jvm.h"
38169691Skan#include "runtime/biasedLocking.hpp"
39169691Skan#include "runtime/interfaceSupport.hpp"
40169691Skan#include "runtime/reflection.hpp"
41169691Skan#include "runtime/sharedRuntime.hpp"
42169691Skan#include "utilities/debug.hpp"
43169691Skan#include "utilities/defaultStream.hpp"
44169691Skan
45169691Skan#if defined(_MSC_VER)
46169691Skan#define strtoll _strtoi64
47169691Skan#endif
48169691Skan
49169691Skanjobject JVMCIRuntime::_HotSpotJVMCIRuntime_instance = NULL;
50169691Skanbool JVMCIRuntime::_HotSpotJVMCIRuntime_initialized = false;
51169691Skanbool JVMCIRuntime::_well_known_classes_initialized = false;
52169691Skanconst char* JVMCIRuntime::_compiler = NULL;
53169691Skanint JVMCIRuntime::_options_count = 0;
54169691SkanSystemProperty** JVMCIRuntime::_options = NULL;
55169691Skanint JVMCIRuntime::_trivial_prefixes_count = 0;
56169691Skanchar** JVMCIRuntime::_trivial_prefixes = NULL;
57169691Skanbool JVMCIRuntime::_shutdown_called = false;
58169691Skan
59169691Skanstatic const char* OPTION_PREFIX = "jvmci.option.";
60169691Skanstatic const size_t OPTION_PREFIX_LEN = strlen(OPTION_PREFIX);
61169691Skan
62169691SkanBasicType JVMCIRuntime::kindToBasicType(Handle kind, TRAPS) {
63169691Skan  if (kind.is_null()) {
64169691Skan    THROW_(vmSymbols::java_lang_NullPointerException(), T_ILLEGAL);
65169691Skan  }
66169691Skan  jchar ch = JavaKind::typeChar(kind);
67169691Skan  switch(ch) {
68169691Skan    case 'z': return T_BOOLEAN;
69169691Skan    case 'b': return T_BYTE;
70169691Skan    case 's': return T_SHORT;
71169691Skan    case 'c': return T_CHAR;
72169691Skan    case 'i': return T_INT;
73169691Skan    case 'f': return T_FLOAT;
74169691Skan    case 'j': return T_LONG;
75169691Skan    case 'd': return T_DOUBLE;
76169691Skan    case 'a': return T_OBJECT;
77169691Skan    case '-': return T_ILLEGAL;
78169691Skan    default:
79169691Skan      JVMCI_ERROR_(T_ILLEGAL, "unexpected Kind: %c", ch);
80169691Skan  }
81169691Skan}
82169691Skan
83169691Skan// Simple helper to see if the caller of a runtime stub which
84169691Skan// entered the VM has been deoptimized
85169691Skan
86169691Skanstatic bool caller_is_deopted() {
87169691Skan  JavaThread* thread = JavaThread::current();
88169691Skan  RegisterMap reg_map(thread, false);
89169691Skan  frame runtime_frame = thread->last_frame();
90169691Skan  frame caller_frame = runtime_frame.sender(&reg_map);
91169691Skan  assert(caller_frame.is_compiled_frame(), "must be compiled");
92169691Skan  return caller_frame.is_deoptimized_frame();
93169691Skan}
94169691Skan
95169691Skan// Stress deoptimization
96169691Skanstatic void deopt_caller() {
97169691Skan  if ( !caller_is_deopted()) {
98169691Skan    JavaThread* thread = JavaThread::current();
99169691Skan    RegisterMap reg_map(thread, false);
100169691Skan    frame runtime_frame = thread->last_frame();
101169691Skan    frame caller_frame = runtime_frame.sender(&reg_map);
102169691Skan    Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint);
103169691Skan    assert(caller_is_deopted(), "Must be deoptimized");
104169691Skan  }
105169691Skan}
106169691Skan
107169691SkanJRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance(JavaThread* thread, Klass* klass))
108169691Skan  JRT_BLOCK;
109169691Skan  assert(klass->is_klass(), "not a class");
110169691Skan  instanceKlassHandle h(thread, klass);
111169691Skan  h->check_valid_for_instantiation(true, CHECK);
112169691Skan  // make sure klass is initialized
113169691Skan  h->initialize(CHECK);
114169691Skan  // allocate instance and return via TLS
115169691Skan  oop obj = h->allocate_instance(CHECK);
116169691Skan  thread->set_vm_result(obj);
117169691Skan  JRT_BLOCK_END;
118169691Skan
119169691Skan  if (ReduceInitialCardMarks) {
120169691Skan    new_store_pre_barrier(thread);
121169691Skan  }
122169691SkanJRT_END
123169691Skan
124169691SkanJRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array(JavaThread* thread, Klass* array_klass, jint length))
125169691Skan  JRT_BLOCK;
126169691Skan  // Note: no handle for klass needed since they are not used
127169691Skan  //       anymore after new_objArray() and no GC can happen before.
128169691Skan  //       (This may have to change if this code changes!)
129169691Skan  assert(array_klass->is_klass(), "not a class");
130169691Skan  oop obj;
131169691Skan  if (array_klass->is_typeArray_klass()) {
132169691Skan    BasicType elt_type = TypeArrayKlass::cast(array_klass)->element_type();
133    obj = oopFactory::new_typeArray(elt_type, length, CHECK);
134  } else {
135    Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass();
136    obj = oopFactory::new_objArray(elem_klass, length, CHECK);
137  }
138  thread->set_vm_result(obj);
139  // This is pretty rare but this runtime patch is stressful to deoptimization
140  // if we deoptimize here so force a deopt to stress the path.
141  if (DeoptimizeALot) {
142    static int deopts = 0;
143    // Alternate between deoptimizing and raising an error (which will also cause a deopt)
144    if (deopts++ % 2 == 0) {
145      ResourceMark rm(THREAD);
146      THROW(vmSymbols::java_lang_OutOfMemoryError());
147    } else {
148      deopt_caller();
149    }
150  }
151  JRT_BLOCK_END;
152
153  if (ReduceInitialCardMarks) {
154    new_store_pre_barrier(thread);
155  }
156JRT_END
157
158void JVMCIRuntime::new_store_pre_barrier(JavaThread* thread) {
159  // After any safepoint, just before going back to compiled code,
160  // we inform the GC that we will be doing initializing writes to
161  // this object in the future without emitting card-marks, so
162  // GC may take any compensating steps.
163  // NOTE: Keep this code consistent with GraphKit::store_barrier.
164
165  oop new_obj = thread->vm_result();
166  if (new_obj == NULL)  return;
167
168  assert(Universe::heap()->can_elide_tlab_store_barriers(),
169         "compiler must check this first");
170  // GC may decide to give back a safer copy of new_obj.
171  new_obj = Universe::heap()->new_store_pre_barrier(thread, new_obj);
172  thread->set_vm_result(new_obj);
173}
174
175JRT_ENTRY(void, JVMCIRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims))
176  assert(klass->is_klass(), "not a class");
177  assert(rank >= 1, "rank must be nonzero");
178  oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK);
179  thread->set_vm_result(obj);
180JRT_END
181
182JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length))
183  oop obj = Reflection::reflect_new_array(element_mirror, length, CHECK);
184  thread->set_vm_result(obj);
185JRT_END
186
187JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror))
188  instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(type_mirror));
189
190  if (klass == NULL) {
191    ResourceMark rm(THREAD);
192    THROW(vmSymbols::java_lang_InstantiationException());
193  }
194
195  // Create new instance (the receiver)
196  klass->check_valid_for_instantiation(false, CHECK);
197
198  // Make sure klass gets initialized
199  klass->initialize(CHECK);
200
201  oop obj = klass->allocate_instance(CHECK);
202  thread->set_vm_result(obj);
203JRT_END
204
205extern void vm_exit(int code);
206
207// Enter this method from compiled code handler below. This is where we transition
208// to VM mode. This is done as a helper routine so that the method called directly
209// from compiled code does not have to transition to VM. This allows the entry
210// method to see if the nmethod that we have just looked up a handler for has
211// been deoptimized while we were in the vm. This simplifies the assembly code
212// cpu directories.
213//
214// We are entering here from exception stub (via the entry method below)
215// If there is a compiled exception handler in this method, we will continue there;
216// otherwise we will unwind the stack and continue at the caller of top frame method
217// Note: we enter in Java using a special JRT wrapper. This wrapper allows us to
218// control the area where we can allow a safepoint. After we exit the safepoint area we can
219// check to see if the handler we are going to return is now in a nmethod that has
220// been deoptimized. If that is the case we return the deopt blob
221// unpack_with_exception entry instead. This makes life for the exception blob easier
222// because making that same check and diverting is painful from assembly language.
223JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* thread, oopDesc* ex, address pc, nmethod*& nm))
224  // Reset method handle flag.
225  thread->set_is_method_handle_return(false);
226
227  Handle exception(thread, ex);
228  nm = CodeCache::find_nmethod(pc);
229  assert(nm != NULL, "this is not a compiled method");
230  // Adjust the pc as needed/
231  if (nm->is_deopt_pc(pc)) {
232    RegisterMap map(thread, false);
233    frame exception_frame = thread->last_frame().sender(&map);
234    // if the frame isn't deopted then pc must not correspond to the caller of last_frame
235    assert(exception_frame.is_deoptimized_frame(), "must be deopted");
236    pc = exception_frame.pc();
237  }
238#ifdef ASSERT
239  assert(exception.not_null(), "NULL exceptions should be handled by throw_exception");
240  assert(exception->is_oop(), "just checking");
241  // Check that exception is a subclass of Throwable, otherwise we have a VerifyError
242  if (!(exception->is_a(SystemDictionary::Throwable_klass()))) {
243    if (ExitVMOnVerifyError) vm_exit(-1);
244    ShouldNotReachHere();
245  }
246#endif
247
248  // Check the stack guard pages and reenable them if necessary and there is
249  // enough space on the stack to do so.  Use fast exceptions only if the guard
250  // pages are enabled.
251  bool guard_pages_enabled = thread->stack_guards_enabled();
252  if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack();
253
254  if (JvmtiExport::can_post_on_exceptions()) {
255    // To ensure correct notification of exception catches and throws
256    // we have to deoptimize here.  If we attempted to notify the
257    // catches and throws during this exception lookup it's possible
258    // we could deoptimize on the way out of the VM and end back in
259    // the interpreter at the throw site.  This would result in double
260    // notifications since the interpreter would also notify about
261    // these same catches and throws as it unwound the frame.
262
263    RegisterMap reg_map(thread);
264    frame stub_frame = thread->last_frame();
265    frame caller_frame = stub_frame.sender(&reg_map);
266
267    // We don't really want to deoptimize the nmethod itself since we
268    // can actually continue in the exception handler ourselves but I
269    // don't see an easy way to have the desired effect.
270    Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint);
271    assert(caller_is_deopted(), "Must be deoptimized");
272
273    return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
274  }
275
276  // ExceptionCache is used only for exceptions at call sites and not for implicit exceptions
277  if (guard_pages_enabled) {
278    address fast_continuation = nm->handler_for_exception_and_pc(exception, pc);
279    if (fast_continuation != NULL) {
280      // Set flag if return address is a method handle call site.
281      thread->set_is_method_handle_return(nm->is_method_handle_return(pc));
282      return fast_continuation;
283    }
284  }
285
286  // If the stack guard pages are enabled, check whether there is a handler in
287  // the current method.  Otherwise (guard pages disabled), force an unwind and
288  // skip the exception cache update (i.e., just leave continuation==NULL).
289  address continuation = NULL;
290  if (guard_pages_enabled) {
291
292    // New exception handling mechanism can support inlined methods
293    // with exception handlers since the mappings are from PC to PC
294
295    // debugging support
296    // tracing
297    if (TraceExceptions) {
298      ttyLocker ttyl;
299      ResourceMark rm;
300      tty->print_cr("Exception <%s> (" INTPTR_FORMAT ") thrown in compiled method <%s> at PC " INTPTR_FORMAT " for thread " INTPTR_FORMAT "",
301                    exception->print_value_string(), p2i((address)exception()), nm->method()->print_value_string(), p2i(pc), p2i(thread));
302    }
303    // for AbortVMOnException flag
304    NOT_PRODUCT(Exceptions::debug_check_abort(exception));
305
306    // Clear out the exception oop and pc since looking up an
307    // exception handler can cause class loading, which might throw an
308    // exception and those fields are expected to be clear during
309    // normal bytecode execution.
310    thread->clear_exception_oop_and_pc();
311
312    continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false);
313    // If an exception was thrown during exception dispatch, the exception oop may have changed
314    thread->set_exception_oop(exception());
315    thread->set_exception_pc(pc);
316
317    // the exception cache is used only by non-implicit exceptions
318    if (continuation != NULL && !SharedRuntime::deopt_blob()->contains(continuation)) {
319      nm->add_handler_for_exception_and_pc(exception, pc, continuation);
320    }
321  }
322
323  // Set flag if return address is a method handle call site.
324  thread->set_is_method_handle_return(nm->is_method_handle_return(pc));
325
326  if (TraceExceptions) {
327    ttyLocker ttyl;
328    ResourceMark rm;
329    tty->print_cr("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT " for exception thrown at PC " PTR_FORMAT,
330                  p2i(thread), p2i(continuation), p2i(pc));
331  }
332
333  return continuation;
334JRT_END
335
336// Enter this method from compiled code only if there is a Java exception handler
337// in the method handling the exception.
338// We are entering here from exception stub. We don't do a normal VM transition here.
339// We do it in a helper. This is so we can check to see if the nmethod we have just
340// searched for an exception handler has been deoptimized in the meantime.
341address JVMCIRuntime::exception_handler_for_pc(JavaThread* thread) {
342  oop exception = thread->exception_oop();
343  address pc = thread->exception_pc();
344  // Still in Java mode
345  DEBUG_ONLY(ResetNoHandleMark rnhm);
346  nmethod* nm = NULL;
347  address continuation = NULL;
348  {
349    // Enter VM mode by calling the helper
350    ResetNoHandleMark rnhm;
351    continuation = exception_handler_for_pc_helper(thread, exception, pc, nm);
352  }
353  // Back in JAVA, use no oops DON'T safepoint
354
355  // Now check to see if the compiled method we were called from is now deoptimized.
356  // If so we must return to the deopt blob and deoptimize the nmethod
357  if (nm != NULL && caller_is_deopted()) {
358    continuation = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
359  }
360
361  assert(continuation != NULL, "no handler found");
362  return continuation;
363}
364
365JRT_ENTRY(void, JVMCIRuntime::create_null_exception(JavaThread* thread))
366  SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_NullPointerException());
367  thread->set_vm_result(PENDING_EXCEPTION);
368  CLEAR_PENDING_EXCEPTION;
369JRT_END
370
371JRT_ENTRY(void, JVMCIRuntime::create_out_of_bounds_exception(JavaThread* thread, jint index))
372  char message[jintAsStringSize];
373  sprintf(message, "%d", index);
374  SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message);
375  thread->set_vm_result(PENDING_EXCEPTION);
376  CLEAR_PENDING_EXCEPTION;
377JRT_END
378
379JRT_ENTRY_NO_ASYNC(void, JVMCIRuntime::monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock))
380  IF_TRACE_jvmci_3 {
381    char type[O_BUFLEN];
382    obj->klass()->name()->as_C_string(type, O_BUFLEN);
383    markOop mark = obj->mark();
384    TRACE_jvmci_3("%s: entered locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), p2i(obj), type, p2i(mark), p2i(lock));
385    tty->flush();
386  }
387#ifdef ASSERT
388  if (PrintBiasedLockingStatistics) {
389    Atomic::inc(BiasedLocking::slow_path_entry_count_addr());
390  }
391#endif
392  Handle h_obj(thread, obj);
393  assert(h_obj()->is_oop(), "must be NULL or an object");
394  if (UseBiasedLocking) {
395    // Retry fast entry if bias is revoked to avoid unnecessary inflation
396    ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK);
397  } else {
398    if (JVMCIUseFastLocking) {
399      // When using fast locking, the compiled code has already tried the fast case
400      ObjectSynchronizer::slow_enter(h_obj, lock, THREAD);
401    } else {
402      ObjectSynchronizer::fast_enter(h_obj, lock, false, THREAD);
403    }
404  }
405  TRACE_jvmci_3("%s: exiting locking slow with obj=" INTPTR_FORMAT, thread->name(), p2i(obj));
406JRT_END
407
408JRT_LEAF(void, JVMCIRuntime::monitorexit(JavaThread* thread, oopDesc* obj, BasicLock* lock))
409  assert(thread == JavaThread::current(), "threads must correspond");
410  assert(thread->last_Java_sp(), "last_Java_sp must be set");
411  // monitorexit is non-blocking (leaf routine) => no exceptions can be thrown
412  EXCEPTION_MARK;
413
414#ifdef DEBUG
415  if (!obj->is_oop()) {
416    ResetNoHandleMark rhm;
417    nmethod* method = thread->last_frame().cb()->as_nmethod_or_null();
418    if (method != NULL) {
419      tty->print_cr("ERROR in monitorexit in method %s wrong obj " INTPTR_FORMAT, method->name(), p2i(obj));
420    }
421    thread->print_stack_on(tty);
422    assert(false, "invalid lock object pointer dected");
423  }
424#endif
425
426  if (JVMCIUseFastLocking) {
427    // When using fast locking, the compiled code has already tried the fast case
428    ObjectSynchronizer::slow_exit(obj, lock, THREAD);
429  } else {
430    ObjectSynchronizer::fast_exit(obj, lock, THREAD);
431  }
432  IF_TRACE_jvmci_3 {
433    char type[O_BUFLEN];
434    obj->klass()->name()->as_C_string(type, O_BUFLEN);
435    TRACE_jvmci_3("%s: exited locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), p2i(obj), type, p2i(obj->mark()), p2i(lock));
436    tty->flush();
437  }
438JRT_END
439
440JRT_LEAF(void, JVMCIRuntime::log_object(JavaThread* thread, oopDesc* obj, bool as_string, bool newline))
441  ttyLocker ttyl;
442
443  if (obj == NULL) {
444    tty->print("NULL");
445  } else if (obj->is_oop_or_null(true) && (!as_string || !java_lang_String::is_instance(obj))) {
446    if (obj->is_oop_or_null(true)) {
447      char buf[O_BUFLEN];
448      tty->print("%s@" INTPTR_FORMAT, obj->klass()->name()->as_C_string(buf, O_BUFLEN), p2i(obj));
449    } else {
450      tty->print(INTPTR_FORMAT, p2i(obj));
451    }
452  } else {
453    ResourceMark rm;
454    assert(obj != NULL && java_lang_String::is_instance(obj), "must be");
455    char *buf = java_lang_String::as_utf8_string(obj);
456    tty->print_raw(buf);
457  }
458  if (newline) {
459    tty->cr();
460  }
461JRT_END
462
463JRT_LEAF(void, JVMCIRuntime::write_barrier_pre(JavaThread* thread, oopDesc* obj))
464  thread->satb_mark_queue().enqueue(obj);
465JRT_END
466
467JRT_LEAF(void, JVMCIRuntime::write_barrier_post(JavaThread* thread, void* card_addr))
468  thread->dirty_card_queue().enqueue(card_addr);
469JRT_END
470
471JRT_LEAF(jboolean, JVMCIRuntime::validate_object(JavaThread* thread, oopDesc* parent, oopDesc* child))
472  bool ret = true;
473  if(!Universe::heap()->is_in_closed_subset(parent)) {
474    tty->print_cr("Parent Object " INTPTR_FORMAT " not in heap", p2i(parent));
475    parent->print();
476    ret=false;
477  }
478  if(!Universe::heap()->is_in_closed_subset(child)) {
479    tty->print_cr("Child Object " INTPTR_FORMAT " not in heap", p2i(child));
480    child->print();
481    ret=false;
482  }
483  return (jint)ret;
484JRT_END
485
486JRT_ENTRY(void, JVMCIRuntime::vm_error(JavaThread* thread, jlong where, jlong format, jlong value))
487  ResourceMark rm;
488  const char *error_msg = where == 0L ? "<internal JVMCI error>" : (char*) (address) where;
489  char *detail_msg = NULL;
490  if (format != 0L) {
491    const char* buf = (char*) (address) format;
492    size_t detail_msg_length = strlen(buf) * 2;
493    detail_msg = (char *) NEW_RESOURCE_ARRAY(u_char, detail_msg_length);
494    jio_snprintf(detail_msg, detail_msg_length, buf, value);
495    report_vm_error(__FILE__, __LINE__, error_msg, "%s", detail_msg);
496  } else {
497    report_vm_error(__FILE__, __LINE__, error_msg);
498  }
499JRT_END
500
501JRT_LEAF(oopDesc*, JVMCIRuntime::load_and_clear_exception(JavaThread* thread))
502  oop exception = thread->exception_oop();
503  assert(exception != NULL, "npe");
504  thread->set_exception_oop(NULL);
505  thread->set_exception_pc(0);
506  return exception;
507JRT_END
508
509PRAGMA_DIAG_PUSH
510PRAGMA_FORMAT_NONLITERAL_IGNORED
511JRT_LEAF(void, JVMCIRuntime::log_printf(JavaThread* thread, oopDesc* format, jlong v1, jlong v2, jlong v3))
512  ResourceMark rm;
513  assert(format != NULL && java_lang_String::is_instance(format), "must be");
514  char *buf = java_lang_String::as_utf8_string(format);
515  tty->print((const char*)buf, v1, v2, v3);
516JRT_END
517PRAGMA_DIAG_POP
518
519static void decipher(jlong v, bool ignoreZero) {
520  if (v != 0 || !ignoreZero) {
521    void* p = (void *)(address) v;
522    CodeBlob* cb = CodeCache::find_blob(p);
523    if (cb) {
524      if (cb->is_nmethod()) {
525        char buf[O_BUFLEN];
526        tty->print("%s [" INTPTR_FORMAT "+" JLONG_FORMAT "]", cb->as_nmethod_or_null()->method()->name_and_sig_as_C_string(buf, O_BUFLEN), p2i(cb->code_begin()), (jlong)((address)v - cb->code_begin()));
527        return;
528      }
529      cb->print_value_on(tty);
530      return;
531    }
532    if (Universe::heap()->is_in(p)) {
533      oop obj = oop(p);
534      obj->print_value_on(tty);
535      return;
536    }
537    tty->print(INTPTR_FORMAT " [long: " JLONG_FORMAT ", double %lf, char %c]",p2i((void *)v), (jlong)v, (jdouble)v, (char)v);
538  }
539}
540
541PRAGMA_DIAG_PUSH
542PRAGMA_FORMAT_NONLITERAL_IGNORED
543JRT_LEAF(void, JVMCIRuntime::vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3))
544  ResourceMark rm;
545  const char *buf = (const char*) (address) format;
546  if (vmError) {
547    if (buf != NULL) {
548      fatal(buf, v1, v2, v3);
549    } else {
550      fatal("<anonymous error>");
551    }
552  } else if (buf != NULL) {
553    tty->print(buf, v1, v2, v3);
554  } else {
555    assert(v2 == 0, "v2 != 0");
556    assert(v3 == 0, "v3 != 0");
557    decipher(v1, false);
558  }
559JRT_END
560PRAGMA_DIAG_POP
561
562JRT_LEAF(void, JVMCIRuntime::log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline))
563  union {
564      jlong l;
565      jdouble d;
566      jfloat f;
567  } uu;
568  uu.l = value;
569  switch (typeChar) {
570    case 'z': tty->print(value == 0 ? "false" : "true"); break;
571    case 'b': tty->print("%d", (jbyte) value); break;
572    case 'c': tty->print("%c", (jchar) value); break;
573    case 's': tty->print("%d", (jshort) value); break;
574    case 'i': tty->print("%d", (jint) value); break;
575    case 'f': tty->print("%f", uu.f); break;
576    case 'j': tty->print(JLONG_FORMAT, value); break;
577    case 'd': tty->print("%lf", uu.d); break;
578    default: assert(false, "unknown typeChar"); break;
579  }
580  if (newline) {
581    tty->cr();
582  }
583JRT_END
584
585JRT_ENTRY(jint, JVMCIRuntime::identity_hash_code(JavaThread* thread, oopDesc* obj))
586  return (jint) obj->identity_hash();
587JRT_END
588
589JRT_ENTRY(jboolean, JVMCIRuntime::thread_is_interrupted(JavaThread* thread, oopDesc* receiver, jboolean clear_interrupted))
590  // Ensure that the C++ Thread and OSThread structures aren't freed before we operate.
591  // This locking requires thread_in_vm which is why this method cannot be JRT_LEAF.
592  Handle receiverHandle(thread, receiver);
593  MutexLockerEx ml(thread->threadObj() == (void*)receiver ? NULL : Threads_lock);
594  JavaThread* receiverThread = java_lang_Thread::thread(receiverHandle());
595  if (receiverThread == NULL) {
596    // The other thread may exit during this process, which is ok so return false.
597    return JNI_FALSE;
598  } else {
599    return (jint) Thread::is_interrupted(receiverThread, clear_interrupted != 0);
600  }
601JRT_END
602
603JRT_ENTRY(jint, JVMCIRuntime::test_deoptimize_call_int(JavaThread* thread, int value))
604  deopt_caller();
605  return value;
606JRT_END
607
608// private static JVMCIRuntime JVMCI.initializeRuntime()
609JVM_ENTRY(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c))
610  if (!EnableJVMCI) {
611    THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVMCI is not enabled")
612  }
613  JVMCIRuntime::initialize_HotSpotJVMCIRuntime(CHECK_NULL);
614  jobject ret = JVMCIRuntime::get_HotSpotJVMCIRuntime_jobject(CHECK_NULL);
615  return ret;
616JVM_END
617
618Handle JVMCIRuntime::callStatic(const char* className, const char* methodName, const char* signature, JavaCallArguments* args, TRAPS) {
619  guarantee(!_HotSpotJVMCIRuntime_initialized, "cannot reinitialize HotSpotJVMCIRuntime");
620
621  TempNewSymbol name = SymbolTable::new_symbol(className, CHECK_(Handle()));
622  KlassHandle klass = SystemDictionary::resolve_or_fail(name, true, CHECK_(Handle()));
623  TempNewSymbol runtime = SymbolTable::new_symbol(methodName, CHECK_(Handle()));
624  TempNewSymbol sig = SymbolTable::new_symbol(signature, CHECK_(Handle()));
625  JavaValue result(T_OBJECT);
626  if (args == NULL) {
627    JavaCalls::call_static(&result, klass, runtime, sig, CHECK_(Handle()));
628  } else {
629    JavaCalls::call_static(&result, klass, runtime, sig, args, CHECK_(Handle()));
630  }
631  return Handle((oop)result.get_jobject());
632}
633
634static bool jvmci_options_file_exists() {
635  const char* home = Arguments::get_java_home();
636  size_t path_len = strlen(home) + strlen("/lib/jvmci.options") + 1;
637  char path[JVM_MAXPATHLEN];
638  char sep = os::file_separator()[0];
639  jio_snprintf(path, JVM_MAXPATHLEN, "%s%clib%cjvmci.options", home, sep, sep);
640  struct stat st;
641  return os::stat(path, &st) == 0;
642}
643
644void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(TRAPS) {
645  if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) {
646#ifdef ASSERT
647    // This should only be called in the context of the JVMCI class being initialized
648    TempNewSymbol name = SymbolTable::new_symbol("jdk/vm/ci/runtime/JVMCI", CHECK);
649    Klass* k = SystemDictionary::resolve_or_null(name, CHECK);
650    instanceKlassHandle klass = InstanceKlass::cast(k);
651    assert(klass->is_being_initialized() && klass->is_reentrant_initialization(THREAD),
652           "HotSpotJVMCIRuntime initialization should only be triggered through JVMCI initialization");
653#endif
654
655    bool parseOptionsFile = jvmci_options_file_exists();
656    if (_options != NULL || parseOptionsFile) {
657      JavaCallArguments args;
658      objArrayOop options;
659      if (_options != NULL) {
660        options = oopFactory::new_objArray(SystemDictionary::String_klass(), _options_count * 2, CHECK);
661        for (int i = 0; i < _options_count; i++) {
662          SystemProperty* prop = _options[i];
663          oop name = java_lang_String::create_oop_from_str(prop->key() + OPTION_PREFIX_LEN, CHECK);
664          const char* prop_value = prop->value() != NULL ? prop->value() : "";
665          oop value = java_lang_String::create_oop_from_str(prop_value, CHECK);
666          options->obj_at_put(i * 2, name);
667          options->obj_at_put((i * 2) + 1, value);
668        }
669      } else {
670        options = NULL;
671      }
672      args.push_oop(options);
673      args.push_int(parseOptionsFile);
674      callStatic("jdk/vm/ci/options/OptionsParser",
675                 "parseOptionsFromVM",
676                 "([Ljava/lang/String;Z)Ljava/lang/Boolean;", &args, CHECK);
677    }
678
679    if (_compiler != NULL) {
680      JavaCallArguments args;
681      oop compiler = java_lang_String::create_oop_from_str(_compiler, CHECK);
682      args.push_oop(compiler);
683      callStatic("jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig",
684                 "selectCompiler",
685                 "(Ljava/lang/String;)Ljava/lang/Boolean;", &args, CHECK);
686    }
687
688    Handle result = callStatic("jdk/vm/ci/hotspot/HotSpotJVMCIRuntime",
689                               "runtime",
690                               "()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;", NULL, CHECK);
691    objArrayOop trivial_prefixes = HotSpotJVMCIRuntime::trivialPrefixes(result);
692    if (trivial_prefixes != NULL) {
693      char** prefixes = NEW_C_HEAP_ARRAY(char*, trivial_prefixes->length(), mtCompiler);
694      for (int i = 0; i < trivial_prefixes->length(); i++) {
695        oop str = trivial_prefixes->obj_at(i);
696        if (str == NULL) {
697          THROW(vmSymbols::java_lang_NullPointerException());
698        } else {
699          prefixes[i] = strdup(java_lang_String::as_utf8_string(str));
700        }
701      }
702      _trivial_prefixes = prefixes;
703      _trivial_prefixes_count = trivial_prefixes->length();
704    }
705    _HotSpotJVMCIRuntime_initialized = true;
706    _HotSpotJVMCIRuntime_instance = JNIHandles::make_global(result());
707  }
708}
709
710void JVMCIRuntime::initialize_JVMCI(TRAPS) {
711  if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) {
712    callStatic("jdk/vm/ci/runtime/JVMCI",
713               "getRuntime",
714               "()Ljdk/vm/ci/runtime/JVMCIRuntime;", NULL, CHECK);
715  }
716  assert(_HotSpotJVMCIRuntime_initialized == true, "what?");
717}
718
719void JVMCIRuntime::initialize_well_known_classes(TRAPS) {
720  if (JVMCIRuntime::_well_known_classes_initialized == false) {
721    SystemDictionary::WKID scan = SystemDictionary::FIRST_JVMCI_WKID;
722    SystemDictionary::initialize_wk_klasses_through(SystemDictionary::LAST_JVMCI_WKID, scan, CHECK);
723    JVMCIJavaClasses::compute_offsets(CHECK);
724    JVMCIRuntime::_well_known_classes_initialized = true;
725  }
726}
727
728void JVMCIRuntime::metadata_do(void f(Metadata*)) {
729  // For simplicity, the existence of HotSpotJVMCIMetaAccessContext in
730  // the SystemDictionary well known classes should ensure the other
731  // classes have already been loaded, so make sure their order in the
732  // table enforces that.
733  assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl) <
734         SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier");
735  assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotConstantPool) <
736         SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier");
737  assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl) <
738         SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier");
739
740  if (HotSpotJVMCIMetaAccessContext::klass() == NULL ||
741      !HotSpotJVMCIMetaAccessContext::klass()->is_linked()) {
742    // Nothing could be registered yet
743    return;
744  }
745
746  // WeakReference<HotSpotJVMCIMetaAccessContext>[]
747  objArrayOop allContexts = HotSpotJVMCIMetaAccessContext::allContexts();
748  if (allContexts == NULL) {
749    return;
750  }
751
752  // These must be loaded at this point but the linking state doesn't matter.
753  assert(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass() != NULL, "must be loaded");
754  assert(SystemDictionary::HotSpotConstantPool_klass() != NULL, "must be loaded");
755  assert(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass() != NULL, "must be loaded");
756
757  for (int i = 0; i < allContexts->length(); i++) {
758    oop ref = allContexts->obj_at(i);
759    if (ref != NULL) {
760      oop referent = java_lang_ref_Reference::referent(ref);
761      if (referent != NULL) {
762        // Chunked Object[] with last element pointing to next chunk
763        objArrayOop metadataRoots = HotSpotJVMCIMetaAccessContext::metadataRoots(referent);
764        while (metadataRoots != NULL) {
765          for (int typeIndex = 0; typeIndex < metadataRoots->length() - 1; typeIndex++) {
766            oop reference = metadataRoots->obj_at(typeIndex);
767            if (reference == NULL) {
768              continue;
769            }
770            oop metadataRoot = java_lang_ref_Reference::referent(reference);
771            if (metadataRoot == NULL) {
772              continue;
773            }
774            if (metadataRoot->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) {
775              Method* method = CompilerToVM::asMethod(metadataRoot);
776              f(method);
777            } else if (metadataRoot->is_a(SystemDictionary::HotSpotConstantPool_klass())) {
778              ConstantPool* constantPool = CompilerToVM::asConstantPool(metadataRoot);
779              f(constantPool);
780            } else if (metadataRoot->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) {
781              Klass* klass = CompilerToVM::asKlass(metadataRoot);
782              f(klass);
783            } else {
784              metadataRoot->print();
785              ShouldNotReachHere();
786            }
787          }
788          metadataRoots = (objArrayOop)metadataRoots->obj_at(metadataRoots->length() - 1);
789          assert(metadataRoots == NULL || metadataRoots->is_objArray(), "wrong type");
790        }
791      }
792    }
793  }
794}
795
796// private static void CompilerToVM.registerNatives()
797JVM_ENTRY(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass))
798  if (!EnableJVMCI) {
799    THROW_MSG(vmSymbols::java_lang_InternalError(), "JVMCI is not enabled");
800  }
801
802#ifdef _LP64
803#ifndef TARGET_ARCH_sparc
804  uintptr_t heap_end = (uintptr_t) Universe::heap()->reserved_region().end();
805  uintptr_t allocation_end = heap_end + ((uintptr_t)16) * 1024 * 1024 * 1024;
806  guarantee(heap_end < allocation_end, "heap end too close to end of address space (might lead to erroneous TLAB allocations)");
807#endif // TARGET_ARCH_sparc
808#else
809  fatal("check TLAB allocation code for address space conflicts");
810#endif
811
812  JVMCIRuntime::initialize_well_known_classes(CHECK);
813
814  {
815    ThreadToNativeFromVM trans(thread);
816
817    // Ensure _non_oop_bits is initialized
818    Universe::non_oop_word();
819
820    env->RegisterNatives(c2vmClass, CompilerToVM::methods, CompilerToVM::methods_count());
821  }
822JVM_END
823
824/**
825 * Closure for parsing a line from a *.properties file in jre/lib/jvmci/properties.
826 * The line must match the regular expression "[^=]+=.*". That is one or more
827 * characters other than '=' followed by '=' followed by zero or more characters.
828 * Everything before the '=' is the property name and everything after '=' is the value.
829 * Lines that start with '#' are treated as comments and ignored.
830 * No special processing of whitespace or any escape characters is performed.
831 * The last definition of a property "wins" (i.e., it overrides all earlier
832 * definitions of the property).
833 */
834class JVMCIPropertiesFileClosure : public ParseClosure {
835  SystemProperty** _plist;
836public:
837  JVMCIPropertiesFileClosure(SystemProperty** plist) : _plist(plist) {}
838  void do_line(char* line) {
839    if (line[0] == '#') {
840      // skip comment
841      return;
842    }
843    size_t len = strlen(line);
844    char* sep = strchr(line, '=');
845    if (sep == NULL) {
846      warn_and_abort("invalid format: could not find '=' character");
847      return;
848    }
849    if (sep == line) {
850      warn_and_abort("invalid format: name cannot be empty");
851      return;
852    }
853    *sep = '\0';
854    const char* name = line;
855    char* value = sep + 1;
856    Arguments::PropertyList_unique_add(_plist, name, value);
857  }
858};
859
860void JVMCIRuntime::init_system_properties(SystemProperty** plist) {
861  char jvmciDir[JVM_MAXPATHLEN];
862  const char* fileSep = os::file_separator();
863  jio_snprintf(jvmciDir, sizeof(jvmciDir), "%s%slib%sjvmci",
864               Arguments::get_java_home(), fileSep, fileSep, fileSep);
865  DIR* dir = os::opendir(jvmciDir);
866  if (dir != NULL) {
867    struct dirent *entry;
868    char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(jvmciDir), mtInternal);
869    JVMCIPropertiesFileClosure closure(plist);
870    const unsigned suffix_len = (unsigned)strlen(".properties");
871    while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL && !closure.is_aborted()) {
872      const char* name = entry->d_name;
873      if (strlen(name) > suffix_len && strcmp(name + strlen(name) - suffix_len, ".properties") == 0) {
874        char propertiesFilePath[JVM_MAXPATHLEN];
875        jio_snprintf(propertiesFilePath, sizeof(propertiesFilePath), "%s%s%s",jvmciDir, fileSep, name);
876        JVMCIRuntime::parse_lines(propertiesFilePath, &closure, false);
877      }
878    }
879    FREE_C_HEAP_ARRAY(char, dbuf);
880    os::closedir(dir);
881  }
882}
883
884#define CHECK_WARN_ABORT_(message) THREAD); \
885  if (HAS_PENDING_EXCEPTION) { \
886    warning(message); \
887    char buf[512]; \
888    jio_snprintf(buf, 512, "Uncaught exception at %s:%d", __FILE__, __LINE__); \
889    JVMCIRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \
890    return; \
891  } \
892  (void)(0
893
894void JVMCIRuntime::save_compiler(const char* compiler) {
895  assert(compiler != NULL, "npe");
896  assert(_compiler == NULL, "cannot reassign JVMCI compiler");
897  _compiler = compiler;
898}
899
900void JVMCIRuntime::maybe_print_flags(TRAPS) {
901  if (_options != NULL) {
902    for (int i = 0; i < _options_count; i++) {
903      SystemProperty* p = _options[i];
904      const char* name = p->key() + OPTION_PREFIX_LEN;
905      if (strcmp(name, "PrintFlags") == 0 || strcmp(name, "ShowFlags") == 0) {
906        JVMCIRuntime::initialize_well_known_classes(CHECK);
907        HandleMark hm;
908        ResourceMark rm;
909        JVMCIRuntime::get_HotSpotJVMCIRuntime(CHECK);
910        return;
911      }
912    }
913  }
914}
915
916void JVMCIRuntime::save_options(SystemProperty* props) {
917  int count = 0;
918  SystemProperty* first = NULL;
919  for (SystemProperty* p = props; p != NULL; p = p->next()) {
920    if (strncmp(p->key(), OPTION_PREFIX, OPTION_PREFIX_LEN) == 0) {
921      if (first == NULL) {
922        first = p;
923      }
924      count++;
925    }
926  }
927  if (count != 0) {
928    _options_count = count;
929    _options = NEW_C_HEAP_ARRAY(SystemProperty*, count, mtCompiler);
930    _options[0] = first;
931    SystemProperty** insert_pos = _options + 1;
932    for (SystemProperty* p = first->next(); p != NULL; p = p->next()) {
933      if (strncmp(p->key(), OPTION_PREFIX, OPTION_PREFIX_LEN) == 0) {
934        *insert_pos = p;
935        insert_pos++;
936      }
937    }
938    assert (insert_pos - _options == count, "must be");
939  }
940}
941
942void JVMCIRuntime::shutdown() {
943  if (_HotSpotJVMCIRuntime_instance != NULL) {
944    _shutdown_called = true;
945    JavaThread* THREAD = JavaThread::current();
946    HandleMark hm(THREAD);
947    Handle receiver = get_HotSpotJVMCIRuntime(CHECK_ABORT);
948    JavaValue result(T_VOID);
949    JavaCallArguments args;
950    args.push_oop(receiver);
951    JavaCalls::call_special(&result, receiver->klass(), vmSymbols::shutdown_method_name(), vmSymbols::void_method_signature(), &args, CHECK_ABORT);
952  }
953}
954
955bool JVMCIRuntime::treat_as_trivial(Method* method) {
956  if (_HotSpotJVMCIRuntime_initialized) {
957    oop loader = method->method_holder()->class_loader();
958    if (loader == NULL) {
959      for (int i = 0; i < _trivial_prefixes_count; i++) {
960        if (method->method_holder()->name()->starts_with(_trivial_prefixes[i])) {
961          return true;
962        }
963      }
964    }
965  }
966  return false;
967}
968
969void JVMCIRuntime::call_printStackTrace(Handle exception, Thread* thread) {
970  assert(exception->is_a(SystemDictionary::Throwable_klass()), "Throwable instance expected");
971  JavaValue result(T_VOID);
972  JavaCalls::call_virtual(&result,
973                          exception,
974                          KlassHandle(thread,
975                          SystemDictionary::Throwable_klass()),
976                          vmSymbols::printStackTrace_name(),
977                          vmSymbols::void_method_signature(),
978                          thread);
979}
980
981void JVMCIRuntime::abort_on_pending_exception(Handle exception, const char* message, bool dump_core) {
982  Thread* THREAD = Thread::current();
983  CLEAR_PENDING_EXCEPTION;
984  tty->print_raw_cr(message);
985  call_printStackTrace(exception, THREAD);
986
987  // Give other aborting threads to also print their stack traces.
988  // This can be very useful when debugging class initialization
989  // failures.
990  os::sleep(THREAD, 200, false);
991
992  vm_abort(dump_core);
993}
994
995void JVMCIRuntime::parse_lines(char* path, ParseClosure* closure, bool warnStatFailure) {
996  struct stat st;
997  if (::stat(path, &st) == 0 && (st.st_mode & S_IFREG) == S_IFREG) { // exists & is regular file
998    int file_handle = ::open(path, os::default_file_open_flags(), 0);
999    if (file_handle != -1) {
1000      char* buffer = NEW_C_HEAP_ARRAY(char, st.st_size + 1, mtInternal);
1001      int num_read;
1002      num_read = (int) ::read(file_handle, (char*) buffer, st.st_size);
1003      if (num_read == -1) {
1004        warning("Error reading file %s due to %s", path, strerror(errno));
1005      } else if (num_read != st.st_size) {
1006        warning("Only read %d of " SIZE_FORMAT " bytes from %s", num_read, (size_t) st.st_size, path);
1007      }
1008      ::close(file_handle);
1009      closure->set_filename(path);
1010      if (num_read == st.st_size) {
1011        buffer[num_read] = '\0';
1012
1013        char* line = buffer;
1014        while (line - buffer < num_read && !closure->is_aborted()) {
1015          // find line end (\r, \n or \r\n)
1016          char* nextline = NULL;
1017          char* cr = strchr(line, '\r');
1018          char* lf = strchr(line, '\n');
1019          if (cr != NULL && lf != NULL) {
1020            char* min = MIN2(cr, lf);
1021            *min = '\0';
1022            if (lf == cr + 1) {
1023              nextline = lf + 1;
1024            } else {
1025              nextline = min + 1;
1026            }
1027          } else if (cr != NULL) {
1028            *cr = '\0';
1029            nextline = cr + 1;
1030          } else if (lf != NULL) {
1031            *lf = '\0';
1032            nextline = lf + 1;
1033          }
1034          // trim left
1035          while (*line == ' ' || *line == '\t') line++;
1036          char* end = line + strlen(line);
1037          // trim right
1038          while (end > line && (*(end -1) == ' ' || *(end -1) == '\t')) end--;
1039          *end = '\0';
1040          // skip comments and empty lines
1041          if (*line != '#' && strlen(line) > 0) {
1042            closure->parse_line(line);
1043          }
1044          if (nextline != NULL) {
1045            line = nextline;
1046          } else {
1047            // File without newline at the end
1048            break;
1049          }
1050        }
1051      }
1052      FREE_C_HEAP_ARRAY(char, buffer);
1053    } else {
1054      warning("Error opening file %s due to %s", path, strerror(errno));
1055    }
1056  } else if (warnStatFailure) {
1057    warning("Could not stat file %s due to %s", path, strerror(errno));
1058  }
1059}
1060