1 /*
  2  *  Copyright (c) 2020, 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.  Oracle designates this
  8  *  particular file as subject to the "Classpath" exception as provided
  9  *  by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  *  This code is distributed in the hope that it will be useful, but WITHOUT
 12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  *  version 2 for more details (a copy is included in the LICENSE file that
 15  *  accompanied this code).
 16  *
 17  *  You should have received a copy of the GNU General Public License version
 18  *  2 along with this work; if not, write to the Free Software Foundation,
 19  *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  *  or visit www.oracle.com if you need additional information or have any
 23  *  questions.
 24  *
 25  */
 26 package jdk.internal.clang;
 27 
 28 import jdk.incubator.foreign.Addressable;
 29 import jdk.incubator.foreign.CLinker;
 30 import jdk.incubator.foreign.FunctionDescriptor;
 31 import jdk.incubator.foreign.MemoryAddress;
 32 import jdk.incubator.foreign.MemorySegment;
 33 import jdk.incubator.foreign.ResourceScope;
 34 import jdk.incubator.foreign.SegmentAllocator;
 35 import jdk.internal.clang.libclang.CXString;
 36 import jdk.internal.clang.libclang.Index_h;
 37 
 38 import java.lang.invoke.MethodHandle;
 39 import java.lang.invoke.MethodType;
 40 import java.util.function.Function;
 41 import java.util.function.Supplier;
 42 
 43 import static jdk.internal.clang.libclang.Index_h.C_INT;
 44 import static jdk.internal.clang.libclang.Index_h.C_POINTER;
 45 
 46 public class LibClang {
 47     private static final boolean DEBUG = Boolean.getBoolean("libclang.debug");
 48     private static final boolean CRASH_RECOVERY = Boolean.getBoolean("libclang.crash_recovery");
 49     private static final boolean IS_WINDOWS = System.getProperty("os.name").startsWith("Windows");
 50 
 51     final static SegmentAllocator IMPLICIT_ALLOCATOR =
 52             (size, align) -> MemorySegment.allocateNative(size, align, ResourceScope.newImplicitScope());
 53 
 54     private final static MemorySegment disableCrashRecovery =
 55             IMPLICIT_ALLOCATOR.allocateUtf8String("LIBCLANG_DISABLE_CRASH_RECOVERY=" + CRASH_RECOVERY);
 56 
 57     static {
 58         if (!CRASH_RECOVERY) {
 59             //this is an hack - needed because clang_toggleCrashRecovery only takes effect _after_ the
 60             //first call to createIndex.
 61             try {
 62                 CLinker linker = CLinker.systemCLinker();
 63                 String putenv = IS_WINDOWS ? "_putenv" : "putenv";
 64                 MethodHandle PUT_ENV = linker.downcallHandle(linker.lookup(putenv).get(),
 65                                 FunctionDescriptor.of(C_INT, C_POINTER));
 66                 int res = (int) PUT_ENV.invokeExact((Addressable)disableCrashRecovery);
 67             } catch (Throwable ex) {
 68                 throw new ExceptionInInitializerError(ex);
 69             }
 70         }
 71     }
 72 
 73     public static Index createIndex(boolean local) {
 74         Index index = new Index(Index_h.clang_createIndex(local ? 1 : 0, 0));
 75         if (DEBUG) {
 76             System.err.println("LibClang crash recovery " + (CRASH_RECOVERY ? "enabled" : "disabled"));
 77         }
 78         return index;
 79     }
 80 
 81     public static String CXStrToString(Function<SegmentAllocator, MemorySegment> segmentSupplier) {
 82         MemorySegment cxstr = segmentSupplier.apply(STRING_ALLOCATOR);
 83         MemoryAddress buf = Index_h.clang_getCString(cxstr);
 84         String str = buf.getUtf8String(0);
 85         Index_h.clang_disposeString(cxstr);
 86         return str;
 87     }
 88 
 89     /**
 90      * This is an allocator for temporary CXString structs. CXStrToString needs to save the CXString somewhere,
 91      * so that we can extract a Java string out of it. Once that's done, we can dispose the CXString, and the
 92      * associated segment. Since jextract is single-threaded, we can use a prefix allocator, to speed up string
 93      * conversion. The size of the prefix segment is set to 256, which should be enough to hold a CXString.
 94      */
 95     private final static SegmentAllocator STRING_ALLOCATOR = SegmentAllocator.prefixAllocator(
 96             MemorySegment.allocateNative(CXString.sizeof(), 8, ResourceScope.newImplicitScope()));
 97 
 98     public static String version() {
 99         return CXStrToString(Index_h::clang_getClangVersion);
100     }
101 }