1 /*
   2  * Copyright (c) 2019, 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 package jdk.internal.vm.compiler.libgraal;
  26 
  27 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
  28 
  29 /**
  30  * Scope for calling CEntryPoints in libgraal. {@linkplain #LibGraalScope(HotSpotJVMCIRuntime)
  31  * Opening} a scope attaches the current thread to libgraal and {@linkplain #close() closing} it
  32  * detaches the current thread.
  33  */
  34 public final class LibGraalScope implements AutoCloseable {
  35 
  36     static final ThreadLocal<LibGraalScope> currentScope = new ThreadLocal<>();
  37 
  38     private final LibGraalScope parent;
  39     private final boolean topLevel;
  40     private final HotSpotJVMCIRuntime runtime;
  41     private final long isolateThread;
  42 
  43     /**
  44      * Gets the isolate thread associated with the current thread. The current thread must be in an
  45      * {@linkplain #LibGraalScope(HotSpotJVMCIRuntime) opened} scope.
  46      *
  47      * @returns a value that can be used for the IsolateThreadContext argument of a {@code native}
  48      *          method {@link LibGraal#registerNativeMethods linked} to a CEntryPoint function in
  49      *          libgraal
  50      * @throws IllegalStateException if not the current thread is not attached to libgraal
  51      */
  52     public static long getIsolateThread() {
  53         LibGraalScope scope = currentScope.get();
  54         if (scope == null) {
  55             throw new IllegalStateException("Cannot get isolate thread outside of a " + LibGraalScope.class.getSimpleName());
  56         }
  57         return scope.isolateThread;
  58     }
  59 
  60     /**
  61      * Enters a scope for making calls into libgraal. If there is no existing libgraal scope for the
  62      * current thread, the current thread is attached to libgraal. When the outer most scope is
  63      * closed, the current thread is detached from libgraal.
  64      *
  65      * This must be used in a try-with-resources statement.
  66      *
  67      * This cannot be called from {@linkplain LibGraal#inLibGraal() within} libgraal.
  68      *
  69      * @throws IllegalStateException if libgraal is {@linkplain LibGraal#isAvailable() unavailable}
  70      *             or {@link LibGraal#inLibGraal()} returns true
  71      */
  72     public LibGraalScope(HotSpotJVMCIRuntime runtime) {
  73         if (LibGraal.inLibGraal() || !LibGraal.isAvailable()) {
  74             throw new IllegalStateException();
  75         }
  76         this.runtime = runtime;
  77         parent = currentScope.get();
  78         boolean top = false;
  79         if (parent == null) {
  80             top = LibGraal.attachCurrentThread(runtime);
  81             isolateThread = LibGraal.getCurrentIsolateThread(LibGraal.isolate);
  82         } else {
  83             isolateThread = parent.isolateThread;
  84         }
  85         topLevel = top;
  86         currentScope.set(this);
  87     }
  88 
  89     @Override
  90     public void close() {
  91         if (topLevel) {
  92             LibGraal.detachCurrentThread(runtime);
  93         }
  94         currentScope.set(parent);
  95     }
  96 }