1 /*
   2  * Copyright (c) 2019, Google Inc. All rights reserved.
   3  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 #include <jni.h>
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 
  30 // Declare the thread local variable(s) in the main executable. This can be
  31 // used to demonstrate the issues associated with the on-stack static TLS blocks
  32 // that may cause insufficient stack space. The dynamic TLS blocks for shared 
  33 // objects (such as a JNI library) loaded via dlopen are not allocated on stack.
  34 __thread int tls[128 * 1024];
  35 
  36 JNIEnv* create_vm(JavaVM **jvm, char* argTLS) {
  37     JNIEnv* env;
  38     JavaVMInitArgs args;
  39     JavaVMOption options[3];
  40     args.version = JNI_VERSION_1_8;
  41     args.nOptions = 3;
  42     char classpath[4096];
  43     snprintf(classpath, sizeof classpath,
  44              "-Djava.class.path=%s", getenv("CLASSPATH"));
  45     options[0].optionString = classpath;
  46     options[1].optionString = "-Xlog:os+thread=info";
  47     options[2].optionString = argTLS;
  48     args.options = &options[0];
  49     args.ignoreUnrecognized = 0;
  50     int rv;
  51     rv = JNI_CreateJavaVM(jvm, (void**)&env, &args);
  52     if (rv < 0) return NULL;
  53     return env;
  54 }
  55 
  56 int run(jboolean addTLS) {
  57     JavaVM *jvm;
  58     jclass testClass;
  59     jmethodID runMethod;
  60     char* argTLS;
  61     int res = -1;
  62 
  63     if (addTLS) {
  64       argTLS = "-XX:+AdjustStackSizeForTLS";
  65     } else {
  66       argTLS = "-XX:-AdjustStackSizeForTLS"; // default
  67     }
  68     printf("Running test with %s ...\n", argTLS);
  69     JNIEnv *env = create_vm(&jvm, argTLS);
  70 
  71     // Run T.run() and check result:
  72     // - Expect T.run() to return 'true' when stack size is adjusted for TLS,
  73     //   return 0 if so
  74     // - Expect T.run() to return 'false' if stack size is not adjusted for
  75     //   TLS, return 0 if so
  76     // Return -1 (fail) for other cases
  77     testClass = (*env)->FindClass(env, "T");
  78     runMethod = (*env)->GetStaticMethodID(env, testClass, "run", "()Z");
  79     if ((*env)->CallStaticBooleanMethod(env, testClass, runMethod, NULL)) {
  80       if (addTLS) {
  81         // expect T.run() to return 'true'
  82         res = 0; 
  83       }
  84     } else {
  85       if (!addTLS) {
  86         // expect T.run() to return 'false'
  87         res = 0;
  88       }
  89     }
  90 
  91     if (res == 0) {
  92       printf("Test passed with %s\n", argTLS);
  93     } else {
  94       printf("Test failed with %s\n", argTLS);
  95     }
  96     return res;
  97 }
  98 
  99 int main(int argc, char **argv) {
 100     if (argc == 2 && strcmp(argv[1], "-add_tls") == 0) {
 101       return run(JNI_TRUE);
 102     } else {
 103       return run(JNI_FALSE);
 104     }
 105 }