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[2];
  40     args.version = JNI_VERSION_1_8;
  41     args.nOptions = 2;
  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 = argTLS;
  47     args.options = &options[0];
  48     args.ignoreUnrecognized = 0;
  49     int rv;
  50     rv = JNI_CreateJavaVM(jvm, (void**)&env, &args);
  51     if (rv < 0) return NULL;
  52     return env;
  53 }
  54 
  55 int run(jboolean addTLS) {
  56     JavaVM *jvm;
  57     jclass testClass;
  58     jmethodID runMethod;
  59     char* argTLS;
  60     int res = -1;
  61 
  62     if (addTLS) {
  63       argTLS = "-XX:+AdjustStackSizeForTLS";
  64     } else {
  65       argTLS = "-XX:-AdjustStackSizeForTLS"; // default
  66     }
  67     printf("Running test with %s ...\n", argTLS);
  68     JNIEnv *env = create_vm(&jvm, argTLS);
  69 
  70     // Run T.run() and check result:
  71     // - Expect T.run() to return 'true' when stack size is adjusted for TLS,
  72     //   return 0 if so
  73     // - Expect T.run() to return 'false' if stack size is not adjusted for
  74     //   TLS, return 0 if so
  75     // Return -1 (fail) for other cases
  76     testClass = (*env)->FindClass(env, "T");
  77     runMethod = (*env)->GetStaticMethodID(env, testClass, "run", "()Z");
  78     if ((*env)->CallStaticBooleanMethod(env, testClass, runMethod, NULL)) {
  79       if (addTLS) {
  80         // expect T.run() to return 'true'
  81         res = 0; 
  82       }
  83     } else {
  84       if (!addTLS) {
  85         // expect T.run() to return 'false'
  86         res = 0;
  87       }
  88     }
  89 
  90     if (res == 0) {
  91       printf("Test passed with %s\n", argTLS);
  92     } else {
  93       printf("Test failed with %s\n", argTLS);
  94     }
  95     return res;
  96 }
  97 
  98 int main(int argc, char **argv) {
  99     if (argc == 2) {
 100       if (strcmp(argv[1], "-add_tls") == 0) {
 101         return run(JNI_TRUE);
 102       } else if (strcmp(argv[1], "-no_tls") == 0) {
 103         return run(JNI_FALSE);
 104       }
 105     }
 106 
 107     printf("Invalid argument. Please run with -add_tls or -no_tls\n");
 108     return -1;
 109 }