From 1d3025cdf04a8f15190e7e09ac5f7add7a61032e Mon Sep 17 00:00:00 2001
From: Esteban Ginez <esteban.ginez@oracle.com>
Date: Mon, 9 Mar 2020 12:30:17 -0700
Subject: [PATCH 01/13] [GR-21741] Adds support for custom timezones through
 the IncludeTimeZones flag

---
 .../oracle/svm/core/jdk/TimeZoneSubstitutions.java   | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
index 1fca7379397a..ef287cee62c4 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
@@ -29,6 +29,7 @@
 import java.util.Arrays;
 import java.util.Map;
 import java.util.TimeZone;
+import java.util.function.Function;
 
 import org.graalvm.compiler.options.Option;
 import org.graalvm.nativeimage.hosted.Feature;
@@ -82,7 +83,7 @@ static class Options {
         public static final HostedOptionKey<Boolean> IncludeAllTimeZones = new HostedOptionKey<>(false);
 
         @Option(help = "The time zones, in addition to the default zone of the host, that will be pre-initialized in the image.")//
-        public static final HostedOptionKey<String[]> IncludeTimeZones = new HostedOptionKey<>(new String[]{"GMT", "UTC", defaultZone.getID()});
+        public static final HostedOptionKey<String> IncludeTimeZones = new HostedOptionKey<>("GMT,UTC," + defaultZone.getID());
     }
 
     @Override
@@ -91,11 +92,14 @@ public void afterRegistration(AfterRegistrationAccess access) {
         if (Options.IncludeAllTimeZones.getValue()) {
             supportedZoneIDs = TimeZone.getAvailableIDs();
         } else {
-            supportedZoneIDs = Options.IncludeTimeZones.getValue();
+            supportedZoneIDs = Options.IncludeTimeZones.getValue().split(",");
         }
         Map<String, TimeZone> supportedZones = Arrays.stream(supportedZoneIDs)
-                        .map(TimeZone::getTimeZone)
-                        .collect(toMap(TimeZone::getID, tz -> tz, (tz1, tz2) -> tz1));
+                        .collect(toMap(Function.identity(), TimeZone::getTimeZone, (tz1, tz2) -> tz1));
+
+        // In al cases put "GMT", "UTC" and default. The JDK returns the GMT time zone for missing
+        // time zone ids
+        Arrays.asList("GMT", "UTC", Options.defaultZone.getID()).forEach(id -> supportedZones.putIfAbsent(id, TimeZone.getTimeZone(id)));
         ImageSingletons.add(TimeZoneSupport.class, new TimeZoneSupport(supportedZones, Options.defaultZone));
     }
 }

From fcc93ff69217d7064f2579e1dd06de9cb1288c73 Mon Sep 17 00:00:00 2001
From: Esteban Ginez <esteban.ginez@oracle.com>
Date: Tue, 10 Mar 2020 12:23:34 -0700
Subject: [PATCH 02/13] [GR-21741] Deleting TimeZoneSubstitutions

---
 .../svm/core/jdk/TimeZoneSubstitutions.java   | 111 ------------------
 .../src/JvmFuncs.c                            |  12 ++
 .../src/JvmFuncs.c                            |  12 ++
 3 files changed, 24 insertions(+), 111 deletions(-)
 delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
deleted file mode 100644
index ef287cee62c4..000000000000
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.svm.core.jdk;
-
-import static java.util.stream.Collectors.toMap;
-
-import java.util.Arrays;
-import java.util.Map;
-import java.util.TimeZone;
-import java.util.function.Function;
-
-import org.graalvm.compiler.options.Option;
-import org.graalvm.nativeimage.hosted.Feature;
-import org.graalvm.nativeimage.ImageSingletons;
-
-import com.oracle.svm.core.annotate.AutomaticFeature;
-import com.oracle.svm.core.annotate.Substitute;
-import com.oracle.svm.core.annotate.TargetClass;
-import com.oracle.svm.core.option.HostedOptionKey;
-
-final class TimeZoneSupport {
-
-    final Map<String, TimeZone> zones;
-    TimeZone defaultZone;
-
-    TimeZoneSupport(Map<String, TimeZone> zones, TimeZone defaultZone) {
-        this.zones = zones;
-        this.defaultZone = defaultZone;
-    }
-
-    public static TimeZoneSupport instance() {
-        return ImageSingletons.lookup(TimeZoneSupport.class);
-    }
-}
-
-@TargetClass(java.util.TimeZone.class)
-final class Target_java_util_TimeZone {
-
-    @Substitute
-    private static TimeZone getDefaultRef() {
-        return TimeZoneSupport.instance().defaultZone;
-    }
-
-    @Substitute
-    private static void setDefault(TimeZone zone) {
-        TimeZoneSupport.instance().defaultZone = zone;
-    }
-
-    @Substitute
-    public static TimeZone getTimeZone(String id) {
-        return TimeZoneSupport.instance().zones.getOrDefault(id, TimeZoneSupport.instance().zones.get("GMT"));
-    }
-}
-
-@AutomaticFeature
-final class TimeZoneFeature implements Feature {
-    static class Options {
-        private static final TimeZone defaultZone = TimeZone.getDefault();
-
-        @Option(help = "When true, all time zones will be pre-initialized in the image.")//
-        public static final HostedOptionKey<Boolean> IncludeAllTimeZones = new HostedOptionKey<>(false);
-
-        @Option(help = "The time zones, in addition to the default zone of the host, that will be pre-initialized in the image.")//
-        public static final HostedOptionKey<String> IncludeTimeZones = new HostedOptionKey<>("GMT,UTC," + defaultZone.getID());
-    }
-
-    @Override
-    public void afterRegistration(AfterRegistrationAccess access) {
-        final String[] supportedZoneIDs;
-        if (Options.IncludeAllTimeZones.getValue()) {
-            supportedZoneIDs = TimeZone.getAvailableIDs();
-        } else {
-            supportedZoneIDs = Options.IncludeTimeZones.getValue().split(",");
-        }
-        Map<String, TimeZone> supportedZones = Arrays.stream(supportedZoneIDs)
-                        .collect(toMap(Function.identity(), TimeZone::getTimeZone, (tz1, tz2) -> tz1));
-
-        // In al cases put "GMT", "UTC" and default. The JDK returns the GMT time zone for missing
-        // time zone ids
-        Arrays.asList("GMT", "UTC", Options.defaultZone.getID()).forEach(id -> supportedZones.putIfAbsent(id, TimeZone.getTimeZone(id)));
-        ImageSingletons.add(TimeZoneSupport.class, new TimeZoneSupport(supportedZones, Options.defaultZone));
-    }
-}
-
-/**
- * This whole file should be eventually removed: GR-11844.
- */
-public class TimeZoneSubstitutions {
-}
diff --git a/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c b/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c
index d2e78ee02034..1ae558a4b783 100644
--- a/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c
+++ b/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c
@@ -244,6 +244,18 @@ int jio_vsnprintf(char *str, size_t count, const char *fmt, va_list args) {
   return result;
 }
 
+int jio_fprintf(FILE *fp, const char *fmt, ...)
+{
+    int len;
+
+    va_list args;
+    va_start(args, fmt);
+    len = jio_vfprintf(fp, fmt, args);
+    va_end(args);
+
+    return len;
+}
+
 #ifdef JNI_VERSION_9
 int jio_snprintf(char *str, size_t count, const char *fmt, ...) {
   va_list args;
diff --git a/substratevm/src/com.oracle.svm.native.jvm.windows/src/JvmFuncs.c b/substratevm/src/com.oracle.svm.native.jvm.windows/src/JvmFuncs.c
index a6349f727999..9d23098038bb 100644
--- a/substratevm/src/com.oracle.svm.native.jvm.windows/src/JvmFuncs.c
+++ b/substratevm/src/com.oracle.svm.native.jvm.windows/src/JvmFuncs.c
@@ -260,6 +260,18 @@ int jio_vsnprintf(char *str, size_t count, const char *fmt, va_list args) {
   return result;
 }
 
+int jio_fprintf(FILE *fp, const char *fmt, ...)
+{
+    int len;
+
+    va_list args;
+    va_start(args, fmt);
+    len = jio_vfprintf(fp, fmt, args);
+    va_end(args);
+
+    return len;
+}
+
 #ifdef JNI_VERSION_9
 int jio_snprintf(char *str, size_t count, const char *fmt, ...) {
   va_list args;

From f4e8511da9dffa3afcda6427209e8c0e4b87c591 Mon Sep 17 00:00:00 2001
From: Esteban Ginez <esteban.ginez@oracle.com>
Date: Tue, 10 Mar 2020 16:12:38 -0700
Subject: [PATCH 03/13] [GR-21741] Adding substituition back, mainting JDK code
 for timezones

---
 .../svm/core/jdk/TimeZoneSubstitutions.java   | 143 ++++++++++++++++++
 .../src/JvmFuncs.c                            |  20 +--
 .../src/JvmFuncs.c                            |  20 +--
 3 files changed, 163 insertions(+), 20 deletions(-)
 create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
new file mode 100644
index 000000000000..aa5382ced104
--- /dev/null
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.svm.core.jdk;
+
+import com.oracle.svm.core.annotate.Alias;
+import com.oracle.svm.core.annotate.RecomputeFieldValue;
+import com.oracle.svm.core.annotate.Substitute;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionKey;
+
+import com.oracle.svm.core.annotate.TargetClass;
+import com.oracle.svm.core.option.HostedOptionKey;
+//Checkstyle: stop
+import sun.security.action.GetPropertyAction;
+//Checkstyle: resume
+
+import java.security.AccessController;
+import java.util.Properties;
+import java.util.TimeZone;
+
+@TargetClass(java.util.TimeZone.class)
+@SuppressWarnings("unused")
+final class Target_java_util_TimeZone {
+
+    @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) private static volatile TimeZone defaultTimeZone;
+
+    @Alias
+    // Checkstyle: stop
+    private static String GMT_ID;
+    // Checkstyle: resume
+
+    @Alias
+    static native TimeZone getDefaultRef();
+
+    @Alias
+    static native String getSystemTimeZoneID(String javaHome);
+
+    @Alias
+    private static native TimeZone getTimeZone(String id, boolean fallback);
+
+    @Alias
+    private static native String getSystemGMTOffsetID();
+
+    @SuppressWarnings("checkstyle:IllegalToken")
+    @Substitute
+    // Checkstyle: stop
+    private static synchronized TimeZone setDefaultZone() {
+        // Checkstyle: resume
+        TimeZone tz;
+        // get the time zone ID from the system properties
+        Properties props = System.getProperties();
+        String zoneID = AccessController.doPrivileged(
+                        new GetPropertyAction("user.timezone"));
+
+        // if the time zone ID is not set (yet), perform the
+        // platform to Java time zone ID mapping.
+        if (zoneID == null || zoneID.isEmpty()) {
+            try {
+                // This is only different part from the JDK
+                // because native-image java.home property is null
+                zoneID = getSystemTimeZoneID("");
+                if (zoneID == null) {
+                    zoneID = GMT_ID;
+                }
+            } catch (NullPointerException e) {
+                zoneID = GMT_ID;
+            }
+        }
+
+        // Get the time zone for zoneID. But not fall back to
+        // "GMT" here.
+        tz = getTimeZone(zoneID, false);
+
+        if (tz == null) {
+            // If the given zone ID is unknown in Java, try to
+            // get the GMT-offset-based time zone ID,
+            // a.k.a. custom time zone ID (e.g., "GMT-08:00").
+            String gmtOffsetID = getSystemGMTOffsetID();
+            if (gmtOffsetID != null) {
+                zoneID = gmtOffsetID;
+            }
+            tz = getTimeZone(zoneID, true);
+        }
+        assert tz != null;
+
+        final String id = zoneID;
+        props.setProperty("user.timezone", id);
+
+        defaultTimeZone = tz;
+        return tz;
+    }
+}
+
+public class TimeZoneSubstitutions {
+    static class Options {
+        @Option(help = "When true, all time zones will be pre-initialized in the image.")//
+        public static final HostedOptionKey<Boolean> IncludeAllTimeZones = new HostedOptionKey<Boolean>(false) {
+            @Override
+            protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean oldValue, Boolean newValue) {
+                super.onValueUpdate(values, oldValue, newValue);
+                printWarning("-H:IncludeAllTimeZones and -H:IncludeTimeZones are deprecated");
+            }
+        };
+
+        @Option(help = "The time zones, in addition to the default zone of the host, that will be pre-initialized in the image.")//
+        public static final HostedOptionKey<String> IncludeTimeZones = new HostedOptionKey<String>("") {
+            @Override
+            protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, String oldValue, String newValue) {
+                super.onValueUpdate(values, oldValue, newValue);
+                printWarning("-H:IncludeAllTimeZones and -H:IncludeTimeZones are deprecated");
+            }
+        };
+
+        private static void printWarning(String warning) {
+            // Checkstyle: stop
+            System.err.println(warning);
+            // Checkstyle: resume
+        }
+    }
+}
diff --git a/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c b/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c
index 1ae558a4b783..4ad73b8be781 100644
--- a/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c
+++ b/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c
@@ -244,6 +244,16 @@ int jio_vsnprintf(char *str, size_t count, const char *fmt, va_list args) {
   return result;
 }
 
+#ifdef JNI_VERSION_9
+int jio_snprintf(char *str, size_t count, const char *fmt, ...) {
+  va_list args;
+  int len;
+  va_start(args, fmt);
+  len = jio_vsnprintf(str, count, fmt, args);
+  va_end(args);
+  return len;
+}
+
 int jio_fprintf(FILE *fp, const char *fmt, ...)
 {
     int len;
@@ -255,14 +265,4 @@ int jio_fprintf(FILE *fp, const char *fmt, ...)
 
     return len;
 }
-
-#ifdef JNI_VERSION_9
-int jio_snprintf(char *str, size_t count, const char *fmt, ...) {
-  va_list args;
-  int len;
-  va_start(args, fmt);
-  len = jio_vsnprintf(str, count, fmt, args);
-  va_end(args);
-  return len;
-}
 #endif
diff --git a/substratevm/src/com.oracle.svm.native.jvm.windows/src/JvmFuncs.c b/substratevm/src/com.oracle.svm.native.jvm.windows/src/JvmFuncs.c
index 9d23098038bb..437b3cf1dd3b 100644
--- a/substratevm/src/com.oracle.svm.native.jvm.windows/src/JvmFuncs.c
+++ b/substratevm/src/com.oracle.svm.native.jvm.windows/src/JvmFuncs.c
@@ -260,6 +260,16 @@ int jio_vsnprintf(char *str, size_t count, const char *fmt, va_list args) {
   return result;
 }
 
+#ifdef JNI_VERSION_9
+int jio_snprintf(char *str, size_t count, const char *fmt, ...) {
+  va_list args;
+  int len;
+  va_start(args, fmt);
+  len = jio_vsnprintf(str, count, fmt, args);
+  va_end(args);
+  return len;
+}
+
 int jio_fprintf(FILE *fp, const char *fmt, ...)
 {
     int len;
@@ -271,16 +281,6 @@ int jio_fprintf(FILE *fp, const char *fmt, ...)
 
     return len;
 }
-
-#ifdef JNI_VERSION_9
-int jio_snprintf(char *str, size_t count, const char *fmt, ...) {
-  va_list args;
-  int len;
-  va_start(args, fmt);
-  len = jio_vsnprintf(str, count, fmt, args);
-  va_end(args);
-  return len;
-}
 #endif
 
 /*

From c94bbb80c41400e8f6f2a2f958953479b2fa1348 Mon Sep 17 00:00:00 2001
From: Esteban Ginez <esteban.ginez@oracle.com>
Date: Fri, 13 Mar 2020 17:40:47 -0700
Subject: [PATCH 04/13] [GR-21741] Adds implementation for time zone mappings
 for native method in windows

---
 .../src/com/oracle/svm/core/LibCHelper.java   |   4 +
 .../svm/core/jdk/TimeZoneSubstitutions.java   | 148 +++--
 .../src/timeZone.c                            | 573 ++++++++++++++++++
 3 files changed, 670 insertions(+), 55 deletions(-)
 create mode 100644 substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java
index bdc3ce3bee49..02c87d197bf9 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java
@@ -27,6 +27,7 @@
 import org.graalvm.nativeimage.c.function.CFunction;
 import org.graalvm.nativeimage.c.function.CFunction.Transition;
 import org.graalvm.nativeimage.c.function.CLibrary;
+import org.graalvm.nativeimage.c.type.CCharPointer;
 import org.graalvm.nativeimage.c.type.CCharPointerPointer;
 
 @CLibrary(value = "libchelper", requireStatic = true)
@@ -34,4 +35,7 @@ public class LibCHelper {
     @CFunction(transition = Transition.NO_TRANSITION)
     public static native CCharPointerPointer getEnviron();
 
+    @CFunction(transition = Transition.NO_TRANSITION)
+    public static native CCharPointer customFindJavaTZmd(CCharPointer tzmappings);
+
 }
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
index aa5382ced104..417f83853958 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
@@ -24,9 +24,14 @@
  */
 package com.oracle.svm.core.jdk;
 
+import com.oracle.svm.core.LibCHelper;
+import com.oracle.svm.core.OS;
+import com.oracle.svm.core.SubstrateUtil;
 import com.oracle.svm.core.annotate.Alias;
+import com.oracle.svm.core.annotate.AutomaticFeature;
 import com.oracle.svm.core.annotate.RecomputeFieldValue;
 import com.oracle.svm.core.annotate.Substitute;
+import com.oracle.svm.core.util.VMError;
 import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
@@ -34,9 +39,20 @@
 import com.oracle.svm.core.annotate.TargetClass;
 import com.oracle.svm.core.option.HostedOptionKey;
 //Checkstyle: stop
+import org.graalvm.nativeimage.ImageSingletons;
+import org.graalvm.nativeimage.Platform;
+import org.graalvm.nativeimage.c.type.CCharPointer;
+import org.graalvm.nativeimage.c.type.CTypeConversion;
+import org.graalvm.nativeimage.hosted.Feature;
 import sun.security.action.GetPropertyAction;
 //Checkstyle: resume
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.security.AccessController;
 import java.util.Properties;
 import java.util.TimeZone;
@@ -45,6 +61,18 @@
 @SuppressWarnings("unused")
 final class Target_java_util_TimeZone {
 
+    static final class TimeZoneSupport {
+        final byte[] tzMappingsContent;
+
+        TimeZoneSupport(final byte[] content) {
+            this.tzMappingsContent = content;
+        }
+
+        public byte[] getTzMappingsContent() {
+            return tzMappingsContent;
+        }
+    }
+
     @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) private static volatile TimeZone defaultTimeZone;
 
     @Alias
@@ -55,66 +83,58 @@ final class Target_java_util_TimeZone {
     @Alias
     static native TimeZone getDefaultRef();
 
-    @Alias
-    static native String getSystemTimeZoneID(String javaHome);
-
-    @Alias
-    private static native TimeZone getTimeZone(String id, boolean fallback);
-
-    @Alias
-    private static native String getSystemGMTOffsetID();
-
-    @SuppressWarnings("checkstyle:IllegalToken")
     @Substitute
-    // Checkstyle: stop
-    private static synchronized TimeZone setDefaultZone() {
-        // Checkstyle: resume
-        TimeZone tz;
-        // get the time zone ID from the system properties
-        Properties props = System.getProperties();
-        String zoneID = AccessController.doPrivileged(
-                        new GetPropertyAction("user.timezone"));
-
-        // if the time zone ID is not set (yet), perform the
-        // platform to Java time zone ID mapping.
-        if (zoneID == null || zoneID.isEmpty()) {
-            try {
-                // This is only different part from the JDK
-                // because native-image java.home property is null
-                zoneID = getSystemTimeZoneID("");
-                if (zoneID == null) {
-                    zoneID = GMT_ID;
-                }
-            } catch (NullPointerException e) {
-                zoneID = GMT_ID;
-            }
+    private static String getSystemTimeZoneID(String javaHome) {
+        // in windows call the custom function
+        // in unix call the normal function, can I call the jdk native function
+        TimeZoneSupport timeZoneSupport = ImageSingletons.lookup(TimeZoneSupport.class);
+        final byte[] content = timeZoneSupport.getTzMappingsContent();
+        String tzmappings = new String(content);
+        try (CTypeConversion.CCharPointerHolder tzMappingsHolder = CTypeConversion.toCString(tzmappings)) {
+            CCharPointer tzMappings = tzMappingsHolder.get();
+            CCharPointer tzId = LibCHelper.customFindJavaTZmd(tzMappings);
+            return CTypeConversion.toJavaString(tzId);
         }
-
-        // Get the time zone for zoneID. But not fall back to
-        // "GMT" here.
-        tz = getTimeZone(zoneID, false);
-
-        if (tz == null) {
-            // If the given zone ID is unknown in Java, try to
-            // get the GMT-offset-based time zone ID,
-            // a.k.a. custom time zone ID (e.g., "GMT-08:00").
-            String gmtOffsetID = getSystemGMTOffsetID();
-            if (gmtOffsetID != null) {
-                zoneID = gmtOffsetID;
-            }
-            tz = getTimeZone(zoneID, true);
-        }
-        assert tz != null;
-
-        final String id = zoneID;
-        props.setProperty("user.timezone", id);
-
-        defaultTimeZone = tz;
-        return tz;
     }
+
+    /*
+     * @Alias private static native TimeZone getTimeZone(String id, boolean fallback);
+     * 
+     * @Alias private static native String getSystemGMTOffsetID();
+     * 
+     * @Substitute // Checkstyle: stop private static synchronized TimeZone setDefaultZone() { //
+     * Checkstyle: resume TimeZone tz; // get the time zone ID from the system properties Properties
+     * props = System.getProperties(); String zoneID = AccessController.doPrivileged( new
+     * GetPropertyAction("user.timezone"));
+     * 
+     * // if the time zone ID is not set (yet), perform the // platform to Java time zone ID
+     * mapping. if (zoneID == null || zoneID.isEmpty()) { try { // This is only different part from
+     * the JDK // because native-image java.home property is null zoneID = getSystemTimeZoneID("");
+     * if (zoneID == null) { zoneID = GMT_ID; } } catch (NullPointerException e) { zoneID = GMT_ID;
+     * } }
+     * 
+     * // Get the time zone for zoneID. But not fall back to // "GMT" here. tz = getTimeZone(zoneID,
+     * false);
+     * 
+     * if (tz == null) { // If the given zone ID is unknown in Java, try to // get the
+     * GMT-offset-based time zone ID, // a.k.a. custom time zone ID (e.g., "GMT-08:00"). String
+     * gmtOffsetID = getSystemGMTOffsetID(); if (gmtOffsetID != null) { zoneID = gmtOffsetID; } tz =
+     * getTimeZone(zoneID, true); } assert tz != null;
+     * 
+     * final String id = zoneID; props.setProperty("user.timezone", id);
+     * 
+     * defaultTimeZone = tz; return tz; }
+     */
 }
 
-public class TimeZoneSubstitutions {
+// Add feature again
+// Replace Java_java_util_TimeZone_getSystemTimeZoneID with and call a CFunction
+// it seems like I am going to have to pull in also all function that calls
+// the jdk8 and jdk 11 implementations are different
+// it brings functions from libjvm
+
+@AutomaticFeature
+final class TimeZoneFeature implements Feature {
     static class Options {
         @Option(help = "When true, all time zones will be pre-initialized in the image.")//
         public static final HostedOptionKey<Boolean> IncludeAllTimeZones = new HostedOptionKey<Boolean>(false) {
@@ -140,4 +160,22 @@ private static void printWarning(String warning) {
             // Checkstyle: resume
         }
     }
+
+    @Override
+    public void afterRegistration(AfterRegistrationAccess access) {
+
+        if (OS.getCurrent() != OS.WINDOWS) {
+            return;
+        }
+
+        // read tzmappings on windows
+        Path tzMappingsPath = Paths.get(System.getProperty("java.home"), "lib", "tzmappings");
+        try {
+            byte[] content = Files.readAllBytes(tzMappingsPath);
+            ImageSingletons.add(Target_java_util_TimeZone.TimeZoneSupport.class, new Target_java_util_TimeZone.TimeZoneSupport(content));
+        } catch (IOException e) {
+            VMError.shouldNotReachHere("Failed to read time zone mappings. The time zone mappings should be part" +
+                            "of your JDK usually found: " + tzMappingsPath.toAbsolutePath(), e);
+        }
+    }
 }
diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c b/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
new file mode 100644
index 000000000000..f9a8f176602d
--- /dev/null
+++ b/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
@@ -0,0 +1,573 @@
+/*
+ * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifdef _WIN64
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+//#include "jvm.h"
+
+#define VALUE_UNKNOWN           0
+#define VALUE_KEY               1
+#define VALUE_MAPID             2
+#define VALUE_GMTOFFSET         3
+
+#define MAX_ZONE_CHAR           256
+#define MAX_MAPID_LENGTH        32
+#define MAX_REGION_LENGTH       4
+
+#define NT_TZ_KEY               "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"
+#define WIN_TZ_KEY              "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones"
+#define WIN_CURRENT_TZ_KEY      "System\\CurrentControlSet\\Control\\TimeZoneInformation"
+
+typedef struct _TziValue {
+    LONG        bias;
+    LONG        stdBias;
+    LONG        dstBias;
+    SYSTEMTIME  stdDate;
+    SYSTEMTIME  dstDate;
+} TziValue;
+
+/*
+ * Registry key names
+ */
+static void *keyNames[] = {
+    (void *) L"StandardName",
+    (void *) "StandardName",
+    (void *) L"Std",
+    (void *) "Std"
+};
+
+/*
+ * Indices to keyNames[]
+ */
+#define STANDARD_NAME           0
+#define STD_NAME                2
+
+/*
+ * Calls RegQueryValueEx() to get the value for the specified key. If
+ * the platform is NT, 2000 or XP, it calls the Unicode
+ * version. Otherwise, it calls the ANSI version and converts the
+ * value to Unicode. In this case, it assumes that the current ANSI
+ * Code Page is the same as the native platform code page (e.g., Code
+ * Page 932 for the Japanese Windows systems.
+ *
+ * `keyIndex' is an index value to the keyNames in Unicode
+ * (WCHAR). `keyIndex' + 1 points to its ANSI value.
+ *
+ * Returns the status value. ERROR_SUCCESS if succeeded, a
+ * non-ERROR_SUCCESS value otherwise.
+ */
+static LONG
+getValueInRegistry(HKEY hKey,
+                   int keyIndex,
+                   LPDWORD typePtr,
+                   LPBYTE buf,
+                   LPDWORD bufLengthPtr)
+{
+    LONG ret;
+    DWORD bufLength = *bufLengthPtr;
+    char val[MAX_ZONE_CHAR];
+    DWORD valSize;
+    int len;
+
+    *typePtr = 0;
+    ret = RegQueryValueExW(hKey, (WCHAR *) keyNames[keyIndex], NULL,
+                           typePtr, buf, bufLengthPtr);
+    if (ret == ERROR_SUCCESS && *typePtr == REG_SZ) {
+        return ret;
+    }
+
+    valSize = sizeof(val);
+    ret = RegQueryValueExA(hKey, (char *) keyNames[keyIndex + 1], NULL,
+                           typePtr, val, &valSize);
+    if (ret != ERROR_SUCCESS) {
+        return ret;
+    }
+    if (*typePtr != REG_SZ) {
+        return ERROR_BADKEY;
+    }
+
+    len = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
+                              (LPCSTR) val, -1,
+                              (LPWSTR) buf, bufLength/sizeof(WCHAR));
+    if (len <= 0) {
+        return ERROR_BADKEY;
+    }
+    return ERROR_SUCCESS;
+}
+
+/*
+ * Produces custom name "GMT+hh:mm" from the given bias in buffer.
+ */
+static void customZoneName(LONG bias, char *buffer) {
+    LONG gmtOffset;
+    int sign;
+
+    if (bias > 0) {
+        gmtOffset = bias;
+        sign = -1;
+    } else {
+        gmtOffset = -bias;
+        sign = 1;
+    }
+    if (gmtOffset != 0) {
+        sprintf(buffer, "GMT%c%02d:%02d",
+                ((sign >= 0) ? '+' : '-'),
+                gmtOffset / 60,
+                gmtOffset % 60);
+    } else {
+        strcpy(buffer, "GMT");
+    }
+}
+
+/*
+ * Gets the current time zone entry in the "Time Zones" registry.
+ */
+static int getWinTimeZone(char *winZoneName)
+{
+    DYNAMIC_TIME_ZONE_INFORMATION dtzi;
+    DWORD timeType;
+    DWORD bufSize;
+    DWORD val;
+    HANDLE hKey = NULL;
+    LONG ret;
+    ULONG valueType;
+
+    /*
+     * Get the dynamic time zone information so that time zone redirection
+     * can be supported. (see JDK-7044727)
+     */
+    timeType = GetDynamicTimeZoneInformation(&dtzi);
+    if (timeType == TIME_ZONE_ID_INVALID) {
+        goto err;
+    }
+
+    /*
+     * Make sure TimeZoneKeyName is available from the API call. If
+     * DynamicDaylightTime is disabled, return a custom time zone name
+     * based on the GMT offset. Otherwise, return the TimeZoneKeyName
+     * value.
+     */
+    if (dtzi.TimeZoneKeyName[0] != 0) {
+        if (dtzi.DynamicDaylightTimeDisabled) {
+            customZoneName(dtzi.Bias, winZoneName);
+            return VALUE_GMTOFFSET;
+        }
+        wcstombs(winZoneName, dtzi.TimeZoneKeyName, MAX_ZONE_CHAR);
+        return VALUE_KEY;
+    }
+
+    /*
+     * If TimeZoneKeyName is not available, check whether StandardName
+     * is available to fall back to the older API GetTimeZoneInformation.
+     * If not, directly read the value from registry keys.
+     */
+    if (dtzi.StandardName[0] == 0) {
+        ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0,
+                           KEY_READ, (PHKEY)&hKey);
+        if (ret != ERROR_SUCCESS) {
+            goto err;
+        }
+
+        /*
+         * Determine if auto-daylight time adjustment is turned off.
+         */
+        bufSize = sizeof(val);
+        ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", NULL,
+                               &valueType, (LPBYTE) &val, &bufSize);
+        if (ret != ERROR_SUCCESS) {
+            goto err;
+        }
+        /*
+         * Return a custom time zone name if auto-daylight time adjustment
+         * is disabled.
+         */
+        if (val == 1) {
+            customZoneName(dtzi.Bias, winZoneName);
+            (void) RegCloseKey(hKey);
+            return VALUE_GMTOFFSET;
+        }
+
+        bufSize = MAX_ZONE_CHAR;
+        ret = RegQueryValueExA(hKey, "TimeZoneKeyName", NULL,
+                               &valueType, (LPBYTE) winZoneName, &bufSize);
+        if (ret != ERROR_SUCCESS) {
+            goto err;
+        }
+        (void) RegCloseKey(hKey);
+        return VALUE_KEY;
+    } else {
+        /*
+         * Fall back to GetTimeZoneInformation
+         */
+        TIME_ZONE_INFORMATION tzi;
+        HANDLE hSubKey = NULL;
+        DWORD nSubKeys, i;
+        ULONG valueType;
+        TCHAR subKeyName[MAX_ZONE_CHAR];
+        TCHAR szValue[MAX_ZONE_CHAR];
+        WCHAR stdNameInReg[MAX_ZONE_CHAR];
+        TziValue tempTzi;
+        WCHAR *stdNamePtr = tzi.StandardName;
+        int onlyMapID;
+
+        timeType = GetTimeZoneInformation(&tzi);
+        if (timeType == TIME_ZONE_ID_INVALID) {
+            goto err;
+        }
+
+        ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0,
+                           KEY_READ, (PHKEY)&hKey);
+        if (ret == ERROR_SUCCESS) {
+            /*
+             * Determine if auto-daylight time adjustment is turned off.
+             */
+            bufSize = sizeof(val);
+            ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", NULL,
+                                   &valueType, (LPBYTE) &val, &bufSize);
+            if (ret == ERROR_SUCCESS) {
+                if (val == 1 && tzi.DaylightDate.wMonth != 0) {
+                    (void) RegCloseKey(hKey);
+                    customZoneName(tzi.Bias, winZoneName);
+                    return VALUE_GMTOFFSET;
+                }
+            }
+
+            /*
+             * Win32 problem: If the length of the standard time name is equal
+             * to (or probably longer than) 32 in the registry,
+             * GetTimeZoneInformation() on NT returns a null string as its
+             * standard time name. We need to work around this problem by
+             * getting the same information from the TimeZoneInformation
+             * registry.
+             */
+            if (tzi.StandardName[0] == 0) {
+                bufSize = sizeof(stdNameInReg);
+                ret = getValueInRegistry(hKey, STANDARD_NAME, &valueType,
+                                         (LPBYTE) stdNameInReg, &bufSize);
+                if (ret != ERROR_SUCCESS) {
+                    goto err;
+                }
+                stdNamePtr = stdNameInReg;
+            }
+            (void) RegCloseKey(hKey);
+        }
+
+        /*
+         * Open the "Time Zones" registry.
+         */
+        ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NT_TZ_KEY, 0, KEY_READ, (PHKEY)&hKey);
+        if (ret != ERROR_SUCCESS) {
+            ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_TZ_KEY, 0, KEY_READ, (PHKEY)&hKey);
+            /*
+             * If both failed, then give up.
+             */
+            if (ret != ERROR_SUCCESS) {
+                return VALUE_UNKNOWN;
+            }
+        }
+
+        /*
+         * Get the number of subkeys of the "Time Zones" registry for
+         * enumeration.
+         */
+        ret = RegQueryInfoKey(hKey, NULL, NULL, NULL, &nSubKeys,
+                              NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+        if (ret != ERROR_SUCCESS) {
+            goto err;
+        }
+
+        /*
+         * Compare to the "Std" value of each subkey and find the entry that
+         * matches the current control panel setting.
+         */
+        onlyMapID = 0;
+        for (i = 0; i < nSubKeys; ++i) {
+            DWORD size = sizeof(subKeyName);
+            ret = RegEnumKeyEx(hKey, i, subKeyName, &size, NULL, NULL, NULL, NULL);
+            if (ret != ERROR_SUCCESS) {
+                goto err;
+            }
+            ret = RegOpenKeyEx(hKey, subKeyName, 0, KEY_READ, (PHKEY)&hSubKey);
+            if (ret != ERROR_SUCCESS) {
+                goto err;
+            }
+
+            size = sizeof(szValue);
+            ret = getValueInRegistry(hSubKey, STD_NAME, &valueType,
+                                     szValue, &size);
+            if (ret != ERROR_SUCCESS) {
+                /*
+                 * NT 4.0 SP3 fails here since it doesn't have the "Std"
+                 * entry in the Time Zones registry.
+                 */
+                RegCloseKey(hSubKey);
+                onlyMapID = 1;
+                ret = RegOpenKeyExW(hKey, stdNamePtr, 0, KEY_READ, (PHKEY)&hSubKey);
+                if (ret != ERROR_SUCCESS) {
+                    goto err;
+                }
+                break;
+            }
+
+            if (wcscmp((WCHAR *)szValue, stdNamePtr) == 0) {
+                /*
+                 * Some localized Win32 platforms use a same name to
+                 * different time zones. So, we can't rely only on the name
+                 * here. We need to check GMT offsets and transition dates
+                 * to make sure it's the registry of the current time
+                 * zone.
+                 */
+                DWORD tziValueSize = sizeof(tempTzi);
+                ret = RegQueryValueEx(hSubKey, "TZI", NULL, &valueType,
+                                      (unsigned char *) &tempTzi, &tziValueSize);
+                if (ret == ERROR_SUCCESS) {
+                    if ((tzi.Bias != tempTzi.bias) ||
+                        (memcmp((const void *) &tzi.StandardDate,
+                                (const void *) &tempTzi.stdDate,
+                                sizeof(SYSTEMTIME)) != 0)) {
+                        goto out;
+                    }
+
+                    if (tzi.DaylightBias != 0) {
+                        if ((tzi.DaylightBias != tempTzi.dstBias) ||
+                            (memcmp((const void *) &tzi.DaylightDate,
+                                    (const void *) &tempTzi.dstDate,
+                                    sizeof(SYSTEMTIME)) != 0)) {
+                            goto out;
+                        }
+                    }
+                }
+
+                /*
+                 * found matched record, terminate search
+                 */
+                strcpy(winZoneName, subKeyName);
+                break;
+            }
+        out:
+            (void) RegCloseKey(hSubKey);
+        }
+
+        (void) RegCloseKey(hKey);
+    }
+
+    return VALUE_KEY;
+
+ err:
+    if (hKey != NULL) {
+        (void) RegCloseKey(hKey);
+    }
+    return VALUE_UNKNOWN;
+}
+
+/*
+ * The mapping table file name.
+ */
+#define MAPPINGS_FILE "\\lib\\tzmappings"
+
+/*
+ * Index values for the mapping table.
+ */
+#define TZ_WIN_NAME     0
+#define TZ_REGION       1
+#define TZ_JAVA_NAME    2
+
+#define TZ_NITEMS       3       /* number of items (fields) */
+
+/*
+ * Looks up the mapping table (tzmappings) and returns a Java time
+ * zone ID (e.g., "America/Los_Angeles") if found. Otherwise, NULL is
+ * returned.
+ */
+static char *matchJavaTZ(char *tzName, const char *tzmappings)
+{
+    int line;
+    int IDmatched = 0;
+    FILE *fp;
+    char *javaTZName = NULL;
+    char *items[TZ_NITEMS];
+    char *mapFileName;
+    char lineBuffer[MAX_ZONE_CHAR * 4];
+    int offset = 0;
+    const char* errorMessage = "unknown error";
+    char region[MAX_REGION_LENGTH];
+
+    // Get the user's location
+    if (GetGeoInfo(GetUserGeoID(GEOCLASS_NATION),
+            GEO_ISO2, region, MAX_REGION_LENGTH, 0) == 0) {
+        // If GetGeoInfo fails, fallback to LCID's country
+        LCID lcid = GetUserDefaultLCID();
+        if (GetLocaleInfo(lcid,
+                          LOCALE_SISO3166CTRYNAME, region, MAX_REGION_LENGTH) == 0 &&
+            GetLocaleInfo(lcid,
+                          LOCALE_SISO3166CTRYNAME2, region, MAX_REGION_LENGTH) == 0) {
+            region[0] = '\0';
+        }
+    }
+
+    // Parsing below
+    line = 0;
+    int tzmappingsLen = strlen(tzmappings);
+    //while (fgets(lineBuffer, sizeof(lineBuffer), fp) != NULL) {
+    for(int i =0 ; i < tzmappingsLen; i+= sizeof(lineBuffer)) { 
+        char *start, *idx, *endp;
+        int itemIndex = 0;
+
+        line++;
+        strncpy(lineBuffer, tzmappings + i, sizeof(lineBuffer));
+        start = idx = lineBuffer;
+        endp = &lineBuffer[sizeof(lineBuffer)];
+
+        /*
+         * Ignore comment and blank lines.
+         */
+        if (*idx == '#' || *idx == '\n') {
+            continue;
+        }
+
+        for (itemIndex = 0; itemIndex < TZ_NITEMS; itemIndex++) {
+            items[itemIndex] = start;
+            while (*idx && *idx != ':') {
+                if (++idx >= endp) {
+                    errorMessage = "premature end of line";
+                    offset = (int)(idx - lineBuffer);
+                    goto illegal_format;
+                }
+            }
+            if (*idx == '\0') {
+                errorMessage = "illegal null character found";
+                offset = (int)(idx - lineBuffer);
+                goto illegal_format;
+            }
+            *idx++ = '\0';
+            start = idx;
+        }
+
+        if (*idx != '\n') {
+            errorMessage = "illegal non-newline character found";
+            offset = (int)(idx - lineBuffer);
+            goto illegal_format;
+        }
+
+        /*
+         * We need to scan items until the
+         * exact match is found or the end of data is detected.
+         */
+        if (strcmp(items[TZ_WIN_NAME], tzName) == 0) {
+            /*
+             * Found the time zone in the mapping table.
+             * Check the region code and select the appropriate entry
+             */
+            if (strcmp(items[TZ_REGION], region) == 0 ||
+                strcmp(items[TZ_REGION], "001") == 0) {
+                javaTZName = _strdup(items[TZ_JAVA_NAME]);
+                printf("Found item %s", javaTZName);
+                break;
+            }
+        }
+    }
+
+    return javaTZName;
+
+ illegal_format:
+    jio_fprintf(stderr, "Illegal format in tzmappings file: %s at line %d, offset %d.\n",
+                errorMessage, line, offset);
+    printf("illegal format");
+    return NULL;
+}
+
+/**
+ * Returns a GMT-offset-based time zone ID.
+ */
+char * customGetGMTOffsetID()
+{
+    LONG bias = 0;
+    LONG ret;
+    HANDLE hKey = NULL;
+    char zonename[32];
+
+    // Obtain the current GMT offset value of ActiveTimeBias.
+    ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0,
+                       KEY_READ, (PHKEY)&hKey);
+    if (ret == ERROR_SUCCESS) {
+        DWORD val;
+        DWORD bufSize = sizeof(val);
+        ULONG valueType = 0;
+        ret = RegQueryValueExA(hKey, "ActiveTimeBias",
+                               NULL, &valueType, (LPBYTE) &val, &bufSize);
+        if (ret == ERROR_SUCCESS) {
+            bias = (LONG) val;
+        }
+        (void) RegCloseKey(hKey);
+    }
+
+    // If we can't get the ActiveTimeBias value, use Bias of TimeZoneInformation.
+    // Note: Bias doesn't reflect current daylight saving.
+    if (ret != ERROR_SUCCESS) {
+        TIME_ZONE_INFORMATION tzi;
+        if (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_INVALID) {
+            bias = tzi.Bias;
+        }
+    }
+
+    customZoneName(bias, zonename);
+    return _strdup(zonename);
+}
+
+/*
+ * Detects the platform time zone which maps to a Java time zone ID.
+ */
+char *customFindJavaTZmd(const char *tzmappings)
+{
+    char winZoneName[MAX_ZONE_CHAR];
+    char *std_timezone = NULL;
+    int  result;
+
+    result = getWinTimeZone(winZoneName);
+
+    if (result != VALUE_UNKNOWN) {
+        if (result == VALUE_GMTOFFSET) {
+            std_timezone = _strdup(winZoneName);
+        } else {
+            std_timezone = matchJavaTZ(winZoneName, tzmappings);
+            if (std_timezone == NULL) {
+                std_timezone = customGetGMTOffsetID();
+            }
+        }
+    }
+    return std_timezone;
+}
+#else
+#include <stdio.h>
+char *customFindJavaTZmd(const char *tzmappings) {
+    printf("here2\n");
+    printf("%d\n", strlen(tzmappings));
+
+    return "EGZ";
+}
+#endif
+

From b653bbbcaf13446a09a258fb8784ff7990cb117c Mon Sep 17 00:00:00 2001
From: Esteban Ginez <esteban.ginez@oracle.com>
Date: Fri, 13 Mar 2020 17:40:47 -0700
Subject: [PATCH 05/13] [GR-21741] Adds implementation for time zone mappings
 for native method in windows

---
 .../src/com/oracle/svm/core/LibCHelper.java   |   2 +-
 .../com/oracle/svm/core/jdk/OSTargets.java    |  68 ++++++++
 .../svm/core/jdk/TimeZoneSubstitutions.java   | 151 +++++++++++-------
 .../oracle/svm/hosted/meta/HostedMethod.java  |   9 ++
 .../src/timeZone.c                            | 149 +++++++++++------
 5 files changed, 272 insertions(+), 107 deletions(-)
 create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/OSTargets.java

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java
index 02c87d197bf9..4b61d7ccfef7 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java
@@ -35,7 +35,7 @@ public class LibCHelper {
     @CFunction(transition = Transition.NO_TRANSITION)
     public static native CCharPointerPointer getEnviron();
 
-    @CFunction(transition = Transition.NO_TRANSITION)
+    @CFunction(transition = Transition.TO_NATIVE)
     public static native CCharPointer customFindJavaTZmd(CCharPointer tzmappings);
 
 }
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/OSTargets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/OSTargets.java
new file mode 100644
index 000000000000..c34238132e11
--- /dev/null
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/OSTargets.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.svm.core.jdk;
+
+import com.oracle.svm.core.OS;
+
+import java.util.function.BooleanSupplier;
+
+public final class OSTargets {
+
+    public static class Windows implements BooleanSupplier {
+        @Override
+        public boolean getAsBoolean() {
+            return OS.getCurrent() == OS.WINDOWS;
+        }
+    }
+
+    public static class Darwin implements BooleanSupplier {
+        @Override
+        public boolean getAsBoolean() {
+            return OS.getCurrent() == OS.DARWIN;
+        }
+    }
+
+    public static class Linux implements BooleanSupplier {
+        @Override
+        public boolean getAsBoolean() {
+            return OS.getCurrent() == OS.LINUX;
+        }
+    }
+
+    public static class UnixLike implements BooleanSupplier {
+        @Override
+        public boolean getAsBoolean() {
+            return OS.getCurrent() == OS.LINUX || OS.getCurrent() == OS.DARWIN;
+        }
+    }
+
+    public static class All implements BooleanSupplier {
+        @Override
+        public boolean getAsBoolean() {
+            return true;
+        }
+
+    }
+}
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
index 417f83853958..195aa2f6f511 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
@@ -26,11 +26,11 @@
 
 import com.oracle.svm.core.LibCHelper;
 import com.oracle.svm.core.OS;
-import com.oracle.svm.core.SubstrateUtil;
 import com.oracle.svm.core.annotate.Alias;
 import com.oracle.svm.core.annotate.AutomaticFeature;
 import com.oracle.svm.core.annotate.RecomputeFieldValue;
 import com.oracle.svm.core.annotate.Substitute;
+import com.oracle.svm.core.annotate.TargetElement;
 import com.oracle.svm.core.util.VMError;
 import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.options.Option;
@@ -38,18 +38,15 @@
 
 import com.oracle.svm.core.annotate.TargetClass;
 import com.oracle.svm.core.option.HostedOptionKey;
-//Checkstyle: stop
 import org.graalvm.nativeimage.ImageSingletons;
-import org.graalvm.nativeimage.Platform;
 import org.graalvm.nativeimage.c.type.CCharPointer;
 import org.graalvm.nativeimage.c.type.CTypeConversion;
 import org.graalvm.nativeimage.hosted.Feature;
+//Checkstyle: stop
 import sun.security.action.GetPropertyAction;
 //Checkstyle: resume
 
-import java.io.File;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -61,18 +58,6 @@
 @SuppressWarnings("unused")
 final class Target_java_util_TimeZone {
 
-    static final class TimeZoneSupport {
-        final byte[] tzMappingsContent;
-
-        TimeZoneSupport(final byte[] content) {
-            this.tzMappingsContent = content;
-        }
-
-        public byte[] getTzMappingsContent() {
-            return tzMappingsContent;
-        }
-    }
-
     @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) private static volatile TimeZone defaultTimeZone;
 
     @Alias
@@ -81,14 +66,20 @@ public byte[] getTzMappingsContent() {
     // Checkstyle: resume
 
     @Alias
-    static native TimeZone getDefaultRef();
+    private static native TimeZone getTimeZone(String id, boolean fallback);
+
+    @Alias
+    private static native String getSystemGMTOffsetID();
+
+    @Alias
+    @TargetElement(name = "getSystemTimeZoneID", onlyWith = OSTargets.UnixLike.class)
+    private static native String getSystemTimeZoneID(String javaHome);
 
     @Substitute
-    private static String getSystemTimeZoneID(String javaHome) {
-        // in windows call the custom function
-        // in unix call the normal function, can I call the jdk native function
+    @TargetElement(name = "getSystemTimeZoneID", onlyWith = {OSTargets.Windows.class})
+    private static String getSystemTimeZoneIDWindows(String javaHome) {
         TimeZoneSupport timeZoneSupport = ImageSingletons.lookup(TimeZoneSupport.class);
-        final byte[] content = timeZoneSupport.getTzMappingsContent();
+        byte[] content = timeZoneSupport.getTzMappingsContent();
         String tzmappings = new String(content);
         try (CTypeConversion.CCharPointerHolder tzMappingsHolder = CTypeConversion.toCString(tzmappings)) {
             CCharPointer tzMappings = tzMappingsHolder.get();
@@ -97,41 +88,70 @@ private static String getSystemTimeZoneID(String javaHome) {
         }
     }
 
-    /*
-     * @Alias private static native TimeZone getTimeZone(String id, boolean fallback);
-     * 
-     * @Alias private static native String getSystemGMTOffsetID();
-     * 
-     * @Substitute // Checkstyle: stop private static synchronized TimeZone setDefaultZone() { //
-     * Checkstyle: resume TimeZone tz; // get the time zone ID from the system properties Properties
-     * props = System.getProperties(); String zoneID = AccessController.doPrivileged( new
-     * GetPropertyAction("user.timezone"));
-     * 
-     * // if the time zone ID is not set (yet), perform the // platform to Java time zone ID
-     * mapping. if (zoneID == null || zoneID.isEmpty()) { try { // This is only different part from
-     * the JDK // because native-image java.home property is null zoneID = getSystemTimeZoneID("");
-     * if (zoneID == null) { zoneID = GMT_ID; } } catch (NullPointerException e) { zoneID = GMT_ID;
-     * } }
-     * 
-     * // Get the time zone for zoneID. But not fall back to // "GMT" here. tz = getTimeZone(zoneID,
-     * false);
-     * 
-     * if (tz == null) { // If the given zone ID is unknown in Java, try to // get the
-     * GMT-offset-based time zone ID, // a.k.a. custom time zone ID (e.g., "GMT-08:00"). String
-     * gmtOffsetID = getSystemGMTOffsetID(); if (gmtOffsetID != null) { zoneID = gmtOffsetID; } tz =
-     * getTimeZone(zoneID, true); } assert tz != null;
-     * 
-     * final String id = zoneID; props.setProperty("user.timezone", id);
-     * 
-     * defaultTimeZone = tz; return tz; }
-     */
+    @Substitute
+    // Checkstyle: stop
+    private static synchronized TimeZone setDefaultZone() {
+        // Checkstyle: resume
+        TimeZone tz;
+        // get the time zone ID from the system properties
+        Properties props = System.getProperties();
+        String zoneID = AccessController.doPrivileged(
+                        new GetPropertyAction("user.timezone"));
+
+        // if the time zone ID is not set (yet), perform the
+        // platform to Java time zone ID mapping.
+        if (zoneID == null || zoneID.isEmpty()) {
+            try {
+                // Send empty for as java home as opposed to null
+                if (OS.getCurrent() == OS.WINDOWS) {
+                    zoneID = getSystemTimeZoneIDWindows("");
+                } else {
+                    zoneID = getSystemTimeZoneID("");
+                }
+                if (zoneID == null) {
+                    zoneID = GMT_ID;
+                }
+            } catch (NullPointerException e) {
+                zoneID = GMT_ID;
+            }
+        }
+
+        // Get the time zone for zoneID. But not fall back to
+        // "GMT" here.
+        tz = getTimeZone(zoneID, false);
+
+        if (tz == null) {
+            // If the given zone ID is unknown in Java, try to
+            // get the GMT-offset-based time zone ID,
+            // a.k.a. custom time zone ID (e.g., "GMT-08:00").
+            String gmtOffsetID = getSystemGMTOffsetID();
+            if (gmtOffsetID != null) {
+                zoneID = gmtOffsetID;
+            }
+            tz = getTimeZone(zoneID, true);
+        }
+        assert tz != null;
+
+        final String id = zoneID;
+        props.setProperty("user.timezone", id);
+
+        defaultTimeZone = tz;
+        return tz;
+    }
 }
 
-// Add feature again
-// Replace Java_java_util_TimeZone_getSystemTimeZoneID with and call a CFunction
-// it seems like I am going to have to pull in also all function that calls
-// the jdk8 and jdk 11 implementations are different
-// it brings functions from libjvm
+final class TimeZoneSupport {
+    final byte[] tzMappingsContent;
+
+    TimeZoneSupport(final byte[] content) {
+        this.tzMappingsContent = content;
+    }
+
+    public byte[] getTzMappingsContent() {
+        return tzMappingsContent;
+    }
+
+}
 
 @AutomaticFeature
 final class TimeZoneFeature implements Feature {
@@ -161,18 +181,35 @@ private static void printWarning(String warning) {
         }
     }
 
+    private static byte[] cleanCR(byte[] buffer) {
+        byte[] scratch = new byte[buffer.length];
+        int copied = 0;
+        for (byte b : buffer) {
+            if (b == 13) {
+                continue;
+            }
+            scratch[copied++] = b;
+        }
+        byte[] content = new byte[copied];
+        System.arraycopy(scratch, 0, content, 0, copied);
+        return content;
+    }
+
     @Override
     public void afterRegistration(AfterRegistrationAccess access) {
 
         if (OS.getCurrent() != OS.WINDOWS) {
+            ImageSingletons.add(TimeZoneSupport.class, new TimeZoneSupport(null));
             return;
         }
 
         // read tzmappings on windows
         Path tzMappingsPath = Paths.get(System.getProperty("java.home"), "lib", "tzmappings");
         try {
-            byte[] content = Files.readAllBytes(tzMappingsPath);
-            ImageSingletons.add(Target_java_util_TimeZone.TimeZoneSupport.class, new Target_java_util_TimeZone.TimeZoneSupport(content));
+            byte[] buffer = Files.readAllBytes(tzMappingsPath);
+            // tzmappings has windows line endings on windows??
+            byte[] content = cleanCR(buffer);
+            ImageSingletons.add(TimeZoneSupport.class, new TimeZoneSupport(content));
         } catch (IOException e) {
             VMError.shouldNotReachHere("Failed to read time zone mappings. The time zone mappings should be part" +
                             "of your JDK usually found: " + tzMappingsPath.toAbsolutePath(), e);
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java
index 11beab0266ba..0da30f1e45e3 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java
@@ -31,6 +31,7 @@
 import java.lang.reflect.Executable;
 import java.lang.reflect.Type;
 
+import com.oracle.svm.hosted.substitute.SubstitutionMethod;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.JavaMethodContext;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -476,10 +477,18 @@ public int compareTo(HostedMethod other) {
         if (result == 0) {
             result = ((HostedType) this.getSignature().getReturnType(null)).compareTo((HostedType) other.getSignature().getReturnType(null));
         }
+
+        if (result == 0 && (isSubstitution() || other.isSubstitution())) {
+            result = isSubstitution() ? 1 : -1;
+        }
         assert result != 0;
         return result;
     }
 
+    protected boolean isSubstitution() {
+        return wrapped.getWrapped() instanceof SubstitutionMethod;
+    }
+
     @Override
     public Executable getJavaMethod() {
         return OriginalMethodProvider.getJavaMethod(getDeclaringClass().universe.getSnippetReflection(), wrapped);
diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c b/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
index f9a8f176602d..40f3d2d37686 100644
--- a/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
+++ b/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
@@ -21,13 +21,18 @@
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
  * questions.
+ */ 
+
+/*
+ * The following is an identical copy of the TimeZone_md.c file found at
+ * https://github.com/graalvm/labs-openjdk-11/blob/67ddc3bcadd985ea26997457aec6696f21caf154/src/java.base/unix/native/libjava/TimeZone_md.c
+ * With the exceptions of the commented functions this file has not been modified from its original.
  */
 
 #ifdef _WIN64
 #include <windows.h>
 #include <stdio.h>
 #include <stdlib.h>
-//#include "jvm.h"
 
 #define VALUE_UNKNOWN           0
 #define VALUE_KEY               1
@@ -36,7 +41,6 @@
 
 #define MAX_ZONE_CHAR           256
 #define MAX_MAPID_LENGTH        32
-#define MAX_REGION_LENGTH       4
 
 #define NT_TZ_KEY               "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"
 #define WIN_TZ_KEY              "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones"
@@ -146,7 +150,7 @@ static void customZoneName(LONG bias, char *buffer) {
 /*
  * Gets the current time zone entry in the "Time Zones" registry.
  */
-static int getWinTimeZone(char *winZoneName)
+static int getWinTimeZone(char *winZoneName, char *winMapID)
 {
     DYNAMIC_TIME_ZONE_INFORMATION dtzi;
     DWORD timeType;
@@ -232,6 +236,7 @@ static int getWinTimeZone(char *winZoneName)
         WCHAR stdNameInReg[MAX_ZONE_CHAR];
         TziValue tempTzi;
         WCHAR *stdNamePtr = tzi.StandardName;
+        DWORD valueSize;
         int onlyMapID;
 
         timeType = GetTimeZoneInformation(&tzi);
@@ -372,7 +377,24 @@ static int getWinTimeZone(char *winZoneName)
             (void) RegCloseKey(hSubKey);
         }
 
+        /*
+         * Get the "MapID" value of the registry to be able to eliminate
+         * duplicated key names later.
+         */
+        valueSize = MAX_MAPID_LENGTH;
+        ret = RegQueryValueExA(hSubKey, "MapID", NULL, &valueType, winMapID, &valueSize);
+        (void) RegCloseKey(hSubKey);
         (void) RegCloseKey(hKey);
+
+        if (ret != ERROR_SUCCESS) {
+            /*
+             * Vista doesn't have mapID. VALUE_UNKNOWN should be returned
+             * only for Windows NT.
+             */
+            if (onlyMapID == 1) {
+                return VALUE_UNKNOWN;
+            }
+        }
     }
 
     return VALUE_KEY;
@@ -385,25 +407,51 @@ static int getWinTimeZone(char *winZoneName)
 }
 
 /*
- * The mapping table file name.
+ * An implementation of fgets on a buffer as opposed to a file object.
+ *
  */
-#define MAPPINGS_FILE "\\lib\\tzmappings"
+static int readnewLine(char *dst, int num, int offset, char *source, int source_len) {
+    int read = 0;
+    while(read < num - 1) {
+        if (offset + read == source_len) {
+            break;
+        }
+        dst[read] = source[offset + read];
+        if (dst[read] == '\n') {
+            read++;
+            break;
+        }
+        read++;
+    }
+    dst[read+1] = '\0';
+    return read;
+}
 
 /*
  * Index values for the mapping table.
  */
 #define TZ_WIN_NAME     0
-#define TZ_REGION       1
-#define TZ_JAVA_NAME    2
+#define TZ_MAPID        1
+#define TZ_REGION       2
+#define TZ_JAVA_NAME    3
 
-#define TZ_NITEMS       3       /* number of items (fields) */
+#define TZ_NITEMS       4       /* number of items (fields) */
 
 /*
  * Looks up the mapping table (tzmappings) and returns a Java time
  * zone ID (e.g., "America/Los_Angeles") if found. Otherwise, NULL is
  * returned.
+ *
+ * value_type is one of the following values:
+ *      VALUE_KEY for exact key matching
+ *      VALUE_MAPID for MapID (this is
+ *      required for the old Windows, such as NT 4.0 SP3).
+ *
+ * The following function differs from the original by accepting a buffer and reading
+ * tzmappings data from it. The original function opens and reads  such data from a file.
  */
-static char *matchJavaTZ(char *tzName, const char *tzmappings)
+static char *matchJavaTZ_Java11(const char *tzmappings, int value_type, char *tzName,
+                         char *mapID)
 {
     int line;
     int IDmatched = 0;
@@ -412,33 +460,23 @@ static char *matchJavaTZ(char *tzName, const char *tzmappings)
     char *items[TZ_NITEMS];
     char *mapFileName;
     char lineBuffer[MAX_ZONE_CHAR * 4];
+    int noMapID = *mapID == '\0';       /* no mapID on Vista and later */
     int offset = 0;
     const char* errorMessage = "unknown error";
-    char region[MAX_REGION_LENGTH];
-
-    // Get the user's location
-    if (GetGeoInfo(GetUserGeoID(GEOCLASS_NATION),
-            GEO_ISO2, region, MAX_REGION_LENGTH, 0) == 0) {
-        // If GetGeoInfo fails, fallback to LCID's country
-        LCID lcid = GetUserDefaultLCID();
-        if (GetLocaleInfo(lcid,
-                          LOCALE_SISO3166CTRYNAME, region, MAX_REGION_LENGTH) == 0 &&
-            GetLocaleInfo(lcid,
-                          LOCALE_SISO3166CTRYNAME2, region, MAX_REGION_LENGTH) == 0) {
-            region[0] = '\0';
-        }
-    }
+    int tzmappingsLen;
+    int currLocation;
+    int readChars;
 
-    // Parsing below
     line = 0;
-    int tzmappingsLen = strlen(tzmappings);
-    //while (fgets(lineBuffer, sizeof(lineBuffer), fp) != NULL) {
-    for(int i =0 ; i < tzmappingsLen; i+= sizeof(lineBuffer)) { 
+    tzmappingsLen = strlen(tzmappings);
+    currLocation = 0;
+    readChars = 0;
+    while((readChars = readnewLine(lineBuffer, sizeof(lineBuffer), currLocation, tzmappings, tzmappingsLen)) != 0) {
         char *start, *idx, *endp;
         int itemIndex = 0;
 
+        currLocation += readChars;
         line++;
-        strncpy(lineBuffer, tzmappings + i, sizeof(lineBuffer));
         start = idx = lineBuffer;
         endp = &lineBuffer[sizeof(lineBuffer)];
 
@@ -473,19 +511,26 @@ static char *matchJavaTZ(char *tzName, const char *tzmappings)
             goto illegal_format;
         }
 
-        /*
-         * We need to scan items until the
-         * exact match is found or the end of data is detected.
-         */
-        if (strcmp(items[TZ_WIN_NAME], tzName) == 0) {
+        if (noMapID || strcmp(mapID, items[TZ_MAPID]) == 0) {
             /*
-             * Found the time zone in the mapping table.
-             * Check the region code and select the appropriate entry
+             * When there's no mapID, we need to scan items until the
+             * exact match is found or the end of data is detected.
              */
-            if (strcmp(items[TZ_REGION], region) == 0 ||
-                strcmp(items[TZ_REGION], "001") == 0) {
+            if (!noMapID) {
+                IDmatched = 1;
+            }
+            if (strcmp(items[TZ_WIN_NAME], tzName) == 0) {
+                /*
+                 * Found the time zone in the mapping table.
+                 */
                 javaTZName = _strdup(items[TZ_JAVA_NAME]);
-                printf("Found item %s", javaTZName);
+                break;
+            }
+        } else {
+            if (IDmatched == 1) {
+                /*
+                 * No need to look up the mapping table further.
+                 */
                 break;
             }
         }
@@ -496,14 +541,16 @@ static char *matchJavaTZ(char *tzName, const char *tzmappings)
  illegal_format:
     jio_fprintf(stderr, "Illegal format in tzmappings file: %s at line %d, offset %d.\n",
                 errorMessage, line, offset);
-    printf("illegal format");
     return NULL;
 }
 
 /**
  * Returns a GMT-offset-based time zone ID.
+ *
+ * No change from original just different function name
  */
-char * customGetGMTOffsetID()
+static char *
+customGetGMTOffsetID()
 {
     LONG bias = 0;
     LONG ret;
@@ -540,20 +587,29 @@ char * customGetGMTOffsetID()
 
 /*
  * Detects the platform time zone which maps to a Java time zone ID.
+ *
+ * The following function only differs from the original by calling a custom parsing
+ * function called "matchJavaTZ_Java11" that accepts a data buffer.
+ *
+ * This function expects its argument to contain the whole tzmappings data as an argument.
+ * The original function expected a buffer whose content was the path to JAVA_HOME
  */
 char *customFindJavaTZmd(const char *tzmappings)
 {
     char winZoneName[MAX_ZONE_CHAR];
+    char winMapID[MAX_MAPID_LENGTH];
     char *std_timezone = NULL;
     int  result;
 
-    result = getWinTimeZone(winZoneName);
+    winMapID[0] = 0;
+    result = getWinTimeZone(winZoneName, winMapID);
 
     if (result != VALUE_UNKNOWN) {
         if (result == VALUE_GMTOFFSET) {
             std_timezone = _strdup(winZoneName);
         } else {
-            std_timezone = matchJavaTZ(winZoneName, tzmappings);
+            std_timezone = matchJavaTZ_Java11(tzmappings, result,
+                                       winZoneName, winMapID);
             if (std_timezone == NULL) {
                 std_timezone = customGetGMTOffsetID();
             }
@@ -562,12 +618,7 @@ char *customFindJavaTZmd(const char *tzmappings)
     return std_timezone;
 }
 #else
-#include <stdio.h>
 char *customFindJavaTZmd(const char *tzmappings) {
-    printf("here2\n");
-    printf("%d\n", strlen(tzmappings));
-
-    return "EGZ";
+    return ((void*)0);
 }
-#endif
-
+#endif // _WIN64

From 5070568d79e9d3066724d037f4f94f4fb5726ac3 Mon Sep 17 00:00:00 2001
From: Esteban Ginez <esteban.ginez@oracle.com>
Date: Mon, 23 Mar 2020 11:22:01 -0700
Subject: [PATCH 06/13] [GR-21741] Removes substitution and adding C method
 implementation to call into the JDK

---
 .../svm/core/jdk/TimeZoneSubstitutions.java   | 84 ++-----------------
 .../src/timeZone.c                            |  3 +-
 2 files changed, 9 insertions(+), 78 deletions(-)

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
index 195aa2f6f511..8a2392e2d2f8 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
@@ -30,7 +30,6 @@
 import com.oracle.svm.core.annotate.AutomaticFeature;
 import com.oracle.svm.core.annotate.RecomputeFieldValue;
 import com.oracle.svm.core.annotate.Substitute;
-import com.oracle.svm.core.annotate.TargetElement;
 import com.oracle.svm.core.util.VMError;
 import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.options.Option;
@@ -42,16 +41,11 @@
 import org.graalvm.nativeimage.c.type.CCharPointer;
 import org.graalvm.nativeimage.c.type.CTypeConversion;
 import org.graalvm.nativeimage.hosted.Feature;
-//Checkstyle: stop
-import sun.security.action.GetPropertyAction;
-//Checkstyle: resume
 
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.security.AccessController;
-import java.util.Properties;
 import java.util.TimeZone;
 
 @TargetClass(java.util.TimeZone.class)
@@ -60,84 +54,20 @@ final class Target_java_util_TimeZone {
 
     @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) private static volatile TimeZone defaultTimeZone;
 
-    @Alias
-    // Checkstyle: stop
-    private static String GMT_ID;
-    // Checkstyle: resume
-
-    @Alias
-    private static native TimeZone getTimeZone(String id, boolean fallback);
-
-    @Alias
-    private static native String getSystemGMTOffsetID();
-
-    @Alias
-    @TargetElement(name = "getSystemTimeZoneID", onlyWith = OSTargets.UnixLike.class)
-    private static native String getSystemTimeZoneID(String javaHome);
-
     @Substitute
-    @TargetElement(name = "getSystemTimeZoneID", onlyWith = {OSTargets.Windows.class})
-    private static String getSystemTimeZoneIDWindows(String javaHome) {
-        TimeZoneSupport timeZoneSupport = ImageSingletons.lookup(TimeZoneSupport.class);
-        byte[] content = timeZoneSupport.getTzMappingsContent();
-        String tzmappings = new String(content);
+    private static String getSystemTimeZoneID(String javaHome) {
+        String tzmappings = "";
+        if (OS.getCurrent() == OS.WINDOWS) {
+            TimeZoneSupport timeZoneSupport = ImageSingletons.lookup(TimeZoneSupport.class);
+            byte[] content = timeZoneSupport.getTzMappingsContent();
+            tzmappings = new String(content);
+        }
         try (CTypeConversion.CCharPointerHolder tzMappingsHolder = CTypeConversion.toCString(tzmappings)) {
             CCharPointer tzMappings = tzMappingsHolder.get();
             CCharPointer tzId = LibCHelper.customFindJavaTZmd(tzMappings);
             return CTypeConversion.toJavaString(tzId);
         }
     }
-
-    @Substitute
-    // Checkstyle: stop
-    private static synchronized TimeZone setDefaultZone() {
-        // Checkstyle: resume
-        TimeZone tz;
-        // get the time zone ID from the system properties
-        Properties props = System.getProperties();
-        String zoneID = AccessController.doPrivileged(
-                        new GetPropertyAction("user.timezone"));
-
-        // if the time zone ID is not set (yet), perform the
-        // platform to Java time zone ID mapping.
-        if (zoneID == null || zoneID.isEmpty()) {
-            try {
-                // Send empty for as java home as opposed to null
-                if (OS.getCurrent() == OS.WINDOWS) {
-                    zoneID = getSystemTimeZoneIDWindows("");
-                } else {
-                    zoneID = getSystemTimeZoneID("");
-                }
-                if (zoneID == null) {
-                    zoneID = GMT_ID;
-                }
-            } catch (NullPointerException e) {
-                zoneID = GMT_ID;
-            }
-        }
-
-        // Get the time zone for zoneID. But not fall back to
-        // "GMT" here.
-        tz = getTimeZone(zoneID, false);
-
-        if (tz == null) {
-            // If the given zone ID is unknown in Java, try to
-            // get the GMT-offset-based time zone ID,
-            // a.k.a. custom time zone ID (e.g., "GMT-08:00").
-            String gmtOffsetID = getSystemGMTOffsetID();
-            if (gmtOffsetID != null) {
-                zoneID = gmtOffsetID;
-            }
-            tz = getTimeZone(zoneID, true);
-        }
-        assert tz != null;
-
-        final String id = zoneID;
-        props.setProperty("user.timezone", id);
-
-        defaultTimeZone = tz;
-        return tz;
-    }
 }
 
 final class TimeZoneSupport {
diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c b/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
index 40f3d2d37686..7ae1a63c1bef 100644
--- a/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
+++ b/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
@@ -618,7 +618,8 @@ char *customFindJavaTZmd(const char *tzmappings)
     return std_timezone;
 }
 #else
+extern char* findJavaTZ_md(const char *);
 char *customFindJavaTZmd(const char *tzmappings) {
-    return ((void*)0);
+    return findJavaTZ_md("");
 }
 #endif // _WIN64

From 3756affc7ba16533ee10636938fb6ca013718dec Mon Sep 17 00:00:00 2001
From: eginez <esteban.ginez@oracle.com>
Date: Mon, 23 Mar 2020 12:10:54 -0700
Subject: [PATCH 07/13] [GR-21741] Adding debug statement

---
 .../src/com/oracle/svm/hosted/meta/HostedMethod.java        | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java
index 0da30f1e45e3..7bd532a176a6 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java
@@ -479,7 +479,11 @@ public int compareTo(HostedMethod other) {
         }
 
         if (result == 0 && (isSubstitution() || other.isSubstitution())) {
-            result = isSubstitution() ? 1 : -1;
+            System.out.printf("EGZ!");
+            System.out.println(this.toString());
+            System.out.println(other.toString());
+            System.out.println("-----");
+            //result = isSubstitution() ? 1 : -1;
         }
         assert result != 0;
         return result;

From 464116e87204ad55c36e350771175acbd87c5baf Mon Sep 17 00:00:00 2001
From: Esteban Ginez <esteban.ginez@oracle.com>
Date: Mon, 23 Mar 2020 14:10:06 -0700
Subject: [PATCH 08/13] [GR-21741] removes debug messages

---
 .../com/oracle/svm/hosted/meta/HostedMethod.java    | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java
index 7bd532a176a6..11beab0266ba 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java
@@ -31,7 +31,6 @@
 import java.lang.reflect.Executable;
 import java.lang.reflect.Type;
 
-import com.oracle.svm.hosted.substitute.SubstitutionMethod;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.JavaMethodContext;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -477,22 +476,10 @@ public int compareTo(HostedMethod other) {
         if (result == 0) {
             result = ((HostedType) this.getSignature().getReturnType(null)).compareTo((HostedType) other.getSignature().getReturnType(null));
         }
-
-        if (result == 0 && (isSubstitution() || other.isSubstitution())) {
-            System.out.printf("EGZ!");
-            System.out.println(this.toString());
-            System.out.println(other.toString());
-            System.out.println("-----");
-            //result = isSubstitution() ? 1 : -1;
-        }
         assert result != 0;
         return result;
     }
 
-    protected boolean isSubstitution() {
-        return wrapped.getWrapped() instanceof SubstitutionMethod;
-    }
-
     @Override
     public Executable getJavaMethod() {
         return OriginalMethodProvider.getJavaMethod(getDeclaringClass().universe.getSnippetReflection(), wrapped);

From 280c5484c4d5c10498913cbf4600ba4b3eb59a1f Mon Sep 17 00:00:00 2001
From: Esteban Ginez <esteban.ginez@oracle.com>
Date: Tue, 24 Mar 2020 11:28:18 -0700
Subject: [PATCH 09/13] [GR-21741] Limiting substitution to JNI platforms

---
 .../src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java    | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
index 8a2392e2d2f8..2e927bf0c3cd 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
@@ -38,9 +38,11 @@
 import com.oracle.svm.core.annotate.TargetClass;
 import com.oracle.svm.core.option.HostedOptionKey;
 import org.graalvm.nativeimage.ImageSingletons;
+import org.graalvm.nativeimage.Platforms;
 import org.graalvm.nativeimage.c.type.CCharPointer;
 import org.graalvm.nativeimage.c.type.CTypeConversion;
 import org.graalvm.nativeimage.hosted.Feature;
+import org.graalvm.nativeimage.impl.InternalPlatform;
 
 import java.io.IOException;
 import java.nio.file.Files;
@@ -48,6 +50,7 @@
 import java.nio.file.Paths;
 import java.util.TimeZone;
 
+@Platforms(InternalPlatform.PLATFORM_JNI.class)
 @TargetClass(java.util.TimeZone.class)
 @SuppressWarnings("unused")
 final class Target_java_util_TimeZone {
@@ -84,6 +87,7 @@ public byte[] getTzMappingsContent() {
 }
 
 @AutomaticFeature
+@Platforms(InternalPlatform.PLATFORM_JNI.class)
 final class TimeZoneFeature implements Feature {
     static class Options {
         @Option(help = "When true, all time zones will be pre-initialized in the image.")//

From d36738bc2224fa17d9f6ed03361deb568539e315 Mon Sep 17 00:00:00 2001
From: Esteban Ginez <esteban.ginez@oracle.com>
Date: Tue, 24 Mar 2020 15:37:08 -0700
Subject: [PATCH 10/13]  [GR-21741] Fixing typos in header of c file, and other
 minor fixes

---
 .../src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java  | 3 +++
 .../src/com.oracle.svm.native.libchelper/src/timeZone.c     | 6 +++---
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
index 2e927bf0c3cd..8d162f8f6b91 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
@@ -150,3 +150,6 @@ public void afterRegistration(AfterRegistrationAccess access) {
         }
     }
 }
+
+class TimeZoneSubstitutions {
+}
diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c b/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
index 7ae1a63c1bef..a4be7e9b706a 100644
--- a/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
+++ b/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -10,7 +10,7 @@
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  * version 2 for more details (a copy is included in the LICENSE file that
  * accompanied this code).
  *
@@ -21,7 +21,7 @@
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
  * questions.
- */ 
+ */
 
 /*
  * The following is an identical copy of the TimeZone_md.c file found at

From 0a144d55b2a787c3b9a258bdd0fcaffe0834d717 Mon Sep 17 00:00:00 2001
From: Esteban Ginez <esteban.ginez@oracle.com>
Date: Wed, 25 Mar 2020 15:03:13 -0700
Subject: [PATCH 11/13] [GR-21741] Addressing comments from review

---
 .../src/com/oracle/svm/core/LibCHelper.java   |  4 +-
 .../com/oracle/svm/core/jdk/OSTargets.java    | 68 --------------
 .../svm/core/jdk/TimeZoneSubstitutions.java   | 69 ++++++++++----
 .../src/timeZone.c                            | 90 +++++++------------
 4 files changed, 85 insertions(+), 146 deletions(-)
 delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/OSTargets.java

diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java
index 4b61d7ccfef7..860eecae4d84 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java
@@ -36,6 +36,8 @@ public class LibCHelper {
     public static native CCharPointerPointer getEnviron();
 
     @CFunction(transition = Transition.TO_NATIVE)
-    public static native CCharPointer customFindJavaTZmd(CCharPointer tzmappings);
+    // Checkstyle: stop
+    public static native CCharPointer SVM_FindJavaTZmd(CCharPointer tzMappings, int length);
+    // Checkstyle: start
 
 }
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/OSTargets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/OSTargets.java
deleted file mode 100644
index c34238132e11..000000000000
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/OSTargets.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.svm.core.jdk;
-
-import com.oracle.svm.core.OS;
-
-import java.util.function.BooleanSupplier;
-
-public final class OSTargets {
-
-    public static class Windows implements BooleanSupplier {
-        @Override
-        public boolean getAsBoolean() {
-            return OS.getCurrent() == OS.WINDOWS;
-        }
-    }
-
-    public static class Darwin implements BooleanSupplier {
-        @Override
-        public boolean getAsBoolean() {
-            return OS.getCurrent() == OS.DARWIN;
-        }
-    }
-
-    public static class Linux implements BooleanSupplier {
-        @Override
-        public boolean getAsBoolean() {
-            return OS.getCurrent() == OS.LINUX;
-        }
-    }
-
-    public static class UnixLike implements BooleanSupplier {
-        @Override
-        public boolean getAsBoolean() {
-            return OS.getCurrent() == OS.LINUX || OS.getCurrent() == OS.DARWIN;
-        }
-    }
-
-    public static class All implements BooleanSupplier {
-        @Override
-        public boolean getAsBoolean() {
-            return true;
-        }
-
-    }
-}
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
index 8d162f8f6b91..7bd6641d2810 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
@@ -38,11 +38,11 @@
 import com.oracle.svm.core.annotate.TargetClass;
 import com.oracle.svm.core.option.HostedOptionKey;
 import org.graalvm.nativeimage.ImageSingletons;
-import org.graalvm.nativeimage.Platforms;
+import org.graalvm.nativeimage.PinnedObject;
 import org.graalvm.nativeimage.c.type.CCharPointer;
 import org.graalvm.nativeimage.c.type.CTypeConversion;
 import org.graalvm.nativeimage.hosted.Feature;
-import org.graalvm.nativeimage.impl.InternalPlatform;
+import org.graalvm.word.WordFactory;
 
 import java.io.IOException;
 import java.nio.file.Files;
@@ -50,29 +50,60 @@
 import java.nio.file.Paths;
 import java.util.TimeZone;
 
-@Platforms(InternalPlatform.PLATFORM_JNI.class)
+/**
+ * The following classes aim to provide full support for time zones for native-image. This is
+ * substitution is necessary due to the reliance in JAVA_HOME in the JDK.
+ *
+ * In summary in the JDK time zone data is extracted from the underlying platform via native
+ * methods, later the JDK code process that data to create time zone objects exposed via java apis.
+ *
+ * Luckily JAVA_HOME is only really necessary for the Windows operating system. Posix operating
+ * systems rely on system calls independent of JAVA_HOME (except for null checks done in the JNI
+ * function wrapping the native time zone JDK functions). Thus for Posix operating this
+ * implementation, simply, by-passes the null check(in native image JAVA_HOME is null) and calls
+ * into the original native functions by substituting the JNI method
+ * TimeZone.getSystemTimeZoneID(String).
+ *
+ * In windows, the JRE contains a special file called tzmappings, (see
+ * <a href="https://docs.oracle.com/javase/9/troubleshoot/time-zone-settings-jre.htm#JSTGD359">time
+ * zones in the jre</a>), representing the mapping between Windows and Java time zones. The
+ * tzmappings file is read and parsed in the native JDK code. Thus for windows,
+ * {@link TimeZoneFeature} reads such file and stores in the image heap at build-time. At run-time
+ * the contents of the file are passed to a special version of the time zone native functions that
+ * parse data from the buffer and not from a file.
+ */
 @TargetClass(java.util.TimeZone.class)
 @SuppressWarnings("unused")
 final class Target_java_util_TimeZone {
 
-    @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) private static volatile TimeZone defaultTimeZone;
+    @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) private static TimeZone defaultTimeZone;
 
     @Substitute
     private static String getSystemTimeZoneID(String javaHome) {
-        String tzmappings = "";
-        if (OS.getCurrent() == OS.WINDOWS) {
+        CCharPointer tzMappingsPtr = WordFactory.nullPointer();
+        int contentLen = 0;
+        PinnedObject pinnedContent = null;
+        try {
             TimeZoneSupport timeZoneSupport = ImageSingletons.lookup(TimeZoneSupport.class);
             byte[] content = timeZoneSupport.getTzMappingsContent();
-            tzmappings = new String(content);
-        }
-        try (CTypeConversion.CCharPointerHolder tzMappingsHolder = CTypeConversion.toCString(tzmappings)) {
-            CCharPointer tzMappings = tzMappingsHolder.get();
-            CCharPointer tzId = LibCHelper.customFindJavaTZmd(tzMappings);
+            if (content != null) {
+                contentLen = content.length;
+                pinnedContent = PinnedObject.create(content);
+                tzMappingsPtr = pinnedContent.addressOfArrayElement(0);
+            }
+            CCharPointer tzId = LibCHelper.SVM_FindJavaTZmd(tzMappingsPtr, contentLen);
             return CTypeConversion.toJavaString(tzId);
+        } finally {
+            if (pinnedContent != null) {
+                pinnedContent.close();
+            }
         }
     }
 }
 
+/**
+ * Holds time zone mapping data.
+ */
 final class TimeZoneSupport {
     final byte[] tzMappingsContent;
 
@@ -83,11 +114,12 @@ final class TimeZoneSupport {
     public byte[] getTzMappingsContent() {
         return tzMappingsContent;
     }
-
 }
 
+/**
+ * Reads time zone mappings data and stores in the image heap, if necessary.
+ */
 @AutomaticFeature
-@Platforms(InternalPlatform.PLATFORM_JNI.class)
 final class TimeZoneFeature implements Feature {
     static class Options {
         @Option(help = "When true, all time zones will be pre-initialized in the image.")//
@@ -95,7 +127,7 @@ static class Options {
             @Override
             protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean oldValue, Boolean newValue) {
                 super.onValueUpdate(values, oldValue, newValue);
-                printWarning("-H:IncludeAllTimeZones and -H:IncludeTimeZones are deprecated");
+                printWarning();
             }
         };
 
@@ -104,13 +136,14 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean o
             @Override
             protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, String oldValue, String newValue) {
                 super.onValueUpdate(values, oldValue, newValue);
-                printWarning("-H:IncludeAllTimeZones and -H:IncludeTimeZones are deprecated");
+                printWarning();
             }
         };
 
-        private static void printWarning(String warning) {
+        private static void printWarning() {
             // Checkstyle: stop
-            System.err.println(warning);
+            System.err.println("-H:IncludeAllTimeZones and -H:IncludeTimeZones are now deprecated. Native-image includes all timezones" +
+                            "by default.");
             // Checkstyle: resume
         }
     }
@@ -119,7 +152,7 @@ private static byte[] cleanCR(byte[] buffer) {
         byte[] scratch = new byte[buffer.length];
         int copied = 0;
         for (byte b : buffer) {
-            if (b == 13) {
+            if (b == '\r') {
                 continue;
             }
             scratch[copied++] = b;
diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c b/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
index a4be7e9b706a..77b0591dc884 100644
--- a/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
+++ b/substratevm/src/com.oracle.svm.native.libchelper/src/timeZone.c
@@ -23,13 +23,13 @@
  * questions.
  */
 
+
+#ifdef _WIN64
 /*
- * The following is an identical copy of the TimeZone_md.c file found at
- * https://github.com/graalvm/labs-openjdk-11/blob/67ddc3bcadd985ea26997457aec6696f21caf154/src/java.base/unix/native/libjava/TimeZone_md.c
+ * The following functions are an identical copy of the functions in file TimeZone_md.c found at
+ * https://github.com/graalvm/labs-openjdk-11/blob/67ddc3bcadd985ea26997457aec6696f21caf154/src/java.base/windows/native/libjava/TimeZone_md.c
  * With the exceptions of the commented functions this file has not been modified from its original.
  */
-
-#ifdef _WIN64
 #include <windows.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -410,7 +410,7 @@ static int getWinTimeZone(char *winZoneName, char *winMapID)
  * An implementation of fgets on a buffer as opposed to a file object.
  *
  */
-static int readnewLine(char *dst, int num, int offset, char *source, int source_len) {
+static int SVM_readBufferUntilNewLine(char *dst, int num, int offset, char *source, int source_len) {
     int read = 0;
     while(read < num - 1) {
         if (offset + read == source_len) {
@@ -450,8 +450,8 @@ static int readnewLine(char *dst, int num, int offset, char *source, int source_
  * The following function differs from the original by accepting a buffer and reading
  * tzmappings data from it. The original function opens and reads  such data from a file.
  */
-static char *matchJavaTZ_Java11(const char *tzmappings, int value_type, char *tzName,
-                         char *mapID)
+static char *SVM_matchJavaTZ(const char *tzmappings, int value_type, char *tzName,
+                         char *mapID, int tzmappingsLen)
 {
     int line;
     int IDmatched = 0;
@@ -463,15 +463,14 @@ static char *matchJavaTZ_Java11(const char *tzmappings, int value_type, char *tz
     int noMapID = *mapID == '\0';       /* no mapID on Vista and later */
     int offset = 0;
     const char* errorMessage = "unknown error";
-    int tzmappingsLen;
     int currLocation;
     int readChars;
 
     line = 0;
-    tzmappingsLen = strlen(tzmappings);
     currLocation = 0;
     readChars = 0;
-    while((readChars = readnewLine(lineBuffer, sizeof(lineBuffer), currLocation, tzmappings, tzmappingsLen)) != 0) {
+    // Reads from buffer and not from file
+    while((readChars = SVM_readBufferUntilNewLine(lineBuffer, sizeof(lineBuffer), currLocation, tzmappings, tzmappingsLen)) != 0) {
         char *start, *idx, *endp;
         int itemIndex = 0;
 
@@ -544,57 +543,18 @@ static char *matchJavaTZ_Java11(const char *tzmappings, int value_type, char *tz
     return NULL;
 }
 
-/**
- * Returns a GMT-offset-based time zone ID.
- *
- * No change from original just different function name
- */
-static char *
-customGetGMTOffsetID()
-{
-    LONG bias = 0;
-    LONG ret;
-    HANDLE hKey = NULL;
-    char zonename[32];
-
-    // Obtain the current GMT offset value of ActiveTimeBias.
-    ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0,
-                       KEY_READ, (PHKEY)&hKey);
-    if (ret == ERROR_SUCCESS) {
-        DWORD val;
-        DWORD bufSize = sizeof(val);
-        ULONG valueType = 0;
-        ret = RegQueryValueExA(hKey, "ActiveTimeBias",
-                               NULL, &valueType, (LPBYTE) &val, &bufSize);
-        if (ret == ERROR_SUCCESS) {
-            bias = (LONG) val;
-        }
-        (void) RegCloseKey(hKey);
-    }
-
-    // If we can't get the ActiveTimeBias value, use Bias of TimeZoneInformation.
-    // Note: Bias doesn't reflect current daylight saving.
-    if (ret != ERROR_SUCCESS) {
-        TIME_ZONE_INFORMATION tzi;
-        if (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_INVALID) {
-            bias = tzi.Bias;
-        }
-    }
-
-    customZoneName(bias, zonename);
-    return _strdup(zonename);
-}
+extern char* getGMTOffsetID();
 
 /*
  * Detects the platform time zone which maps to a Java time zone ID.
  *
  * The following function only differs from the original by calling a custom parsing
- * function called "matchJavaTZ_Java11" that accepts a data buffer.
+ * function called "SVM_matchJavaTZ" that accepts a data buffer.
  *
- * This function expects its argument to contain the whole tzmappings data as an argument.
- * The original function expected a buffer whose content was the path to JAVA_HOME
+ * This function expects its argument to contain the whole tzmappings data and length as an arguments.
+ * The original function expected a char array whose content was the path to JAVA_HOME
  */
-char *customFindJavaTZmd(const char *tzmappings)
+char *SVM_FindJavaTZmd(const char *tzmappings, int length)
 {
     char winZoneName[MAX_ZONE_CHAR];
     char winMapID[MAX_MAPID_LENGTH];
@@ -608,10 +568,10 @@ char *customFindJavaTZmd(const char *tzmappings)
         if (result == VALUE_GMTOFFSET) {
             std_timezone = _strdup(winZoneName);
         } else {
-            std_timezone = matchJavaTZ_Java11(tzmappings, result,
-                                       winZoneName, winMapID);
+            std_timezone = SVM_matchJavaTZ(tzmappings, result,
+                                       winZoneName, winMapID, length);
             if (std_timezone == NULL) {
-                std_timezone = customGetGMTOffsetID();
+                std_timezone = getGMTOffsetID();
             }
         }
     }
@@ -619,7 +579,19 @@ char *customFindJavaTZmd(const char *tzmappings)
 }
 #else
 extern char* findJavaTZ_md(const char *);
-char *customFindJavaTZmd(const char *tzmappings) {
-    return findJavaTZ_md("");
+
+char *SVM_FindJavaTZmd(const char *tzmappings, int length) {
+
+    /* 
+     * For POSIX operating systems the original function 
+     * does not need the JAVA_HOME nor tzmappings. Except
+     * for AIX (which is currently not supported in native image)
+     *
+     * We can safely call the original JDK function with java home set to
+     * NULL. Note the JNI wrapper of the below function, checks JAVA_HOME 
+     * is not NULL and returns NULL if it is, stoppings us from directly
+     * calling this function from java without some type of substitution.
+     */
+    return findJavaTZ_md((void *) 0);
 }
 #endif // _WIN64

From e03b903ec8646932eef4471766059fcd8288f399 Mon Sep 17 00:00:00 2001
From: Esteban Ginez <esteban.ginez@oracle.com>
Date: Fri, 27 Mar 2020 13:16:58 -0700
Subject: [PATCH 12/13] [GR-21741] Implements simple topological sorting native
 libraries and avoid linking failures

---
 .../org.graalvm.nativeimage/snapshot.sigtest  |   1 +
 .../nativeimage/c/function/CLibrary.java      |   7 +
 .../src/com/oracle/svm/core/LibCHelper.java   |   3 +-
 .../svm/core/jdk/TimeZoneSubstitutions.java   |  18 +--
 .../oracle/svm/hosted/c/NativeLibraries.java  | 121 +++++++++++++++++-
 5 files changed, 135 insertions(+), 15 deletions(-)

diff --git a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest
index 95f3e0a62e8e..919f385e3be8 100644
--- a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest
+++ b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest
@@ -483,6 +483,7 @@ CLSS public abstract interface !annotation org.graalvm.nativeimage.c.function.CL
  anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[TYPE, METHOD])
 intf java.lang.annotation.Annotation
 meth public abstract !hasdefault boolean requireStatic()
+meth public abstract !hasdefault java.lang.String[] dependsOn()
 meth public abstract java.lang.String value()
 
 CLSS public abstract interface !annotation org.graalvm.nativeimage.c.function.CMacroInfo
diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/c/function/CLibrary.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/c/function/CLibrary.java
index 18c9da039553..ecdb513abfce 100644
--- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/c/function/CLibrary.java
+++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/c/function/CLibrary.java
@@ -68,4 +68,11 @@
      * @since 19.1.0
      */
     boolean requireStatic() default false;
+
+    /**
+     * Specifies the name of the libraries this library depends on.
+     * 
+     * @since 20.0.1
+     */
+    String[] dependsOn() default {};
 }
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java
index 860eecae4d84..c91ae4d9ca5f 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java
@@ -30,7 +30,7 @@
 import org.graalvm.nativeimage.c.type.CCharPointer;
 import org.graalvm.nativeimage.c.type.CCharPointerPointer;
 
-@CLibrary(value = "libchelper", requireStatic = true)
+@CLibrary(value = "libchelper", requireStatic = true, dependsOn = "java")
 public class LibCHelper {
     @CFunction(transition = Transition.NO_TRANSITION)
     public static native CCharPointerPointer getEnviron();
@@ -39,5 +39,4 @@ public class LibCHelper {
     // Checkstyle: stop
     public static native CCharPointer SVM_FindJavaTZmd(CCharPointer tzMappings, int length);
     // Checkstyle: start
-
 }
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
index 7bd6641d2810..591cb4741f4d 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
@@ -51,26 +51,28 @@
 import java.util.TimeZone;
 
 /**
- * The following classes aim to provide full support for time zones for native-image. This is
- * substitution is necessary due to the reliance in JAVA_HOME in the JDK.
+ * The following classes aim to provide full support for time zones for native-image. This
+ * substitution is necessary due to the reliance on JAVA_HOME in the JDK.
  *
  * In summary in the JDK time zone data is extracted from the underlying platform via native
- * methods, later the JDK code process that data to create time zone objects exposed via java apis.
+ * methods, later the JDK code processes that data to create time zone objects exposed via JAVA
+ * APIs.
  *
  * Luckily JAVA_HOME is only really necessary for the Windows operating system. Posix operating
  * systems rely on system calls independent of JAVA_HOME (except for null checks done in the JNI
- * function wrapping the native time zone JDK functions). Thus for Posix operating this
+ * function wrapping the native time zone JDK functions). Thus for Posix operating systems this
  * implementation, simply, by-passes the null check(in native image JAVA_HOME is null) and calls
  * into the original native functions by substituting the JNI method
  * TimeZone.getSystemTimeZoneID(String).
  *
- * In windows, the JRE contains a special file called tzmappings, (see
+ * In Windows, the JRE contains a special file called tzmappings, (see
  * <a href="https://docs.oracle.com/javase/9/troubleshoot/time-zone-settings-jre.htm#JSTGD359">time
  * zones in the jre</a>), representing the mapping between Windows and Java time zones. The
  * tzmappings file is read and parsed in the native JDK code. Thus for windows,
- * {@link TimeZoneFeature} reads such file and stores in the image heap at build-time. At run-time
- * the contents of the file are passed to a special version of the time zone native functions that
- * parse data from the buffer and not from a file.
+ * {@link TimeZoneFeature} reads such file and stores it in the image heap at build-time. At
+ * run-time the contents of the file are passed to a custom implementation of the JDK time zones
+ * logic. The only difference in the custom implementation is reading and parsing time zone mappings
+ * from a buffer as opposed to a file.
  */
 @TargetClass(java.util.TimeZone.class)
 @SuppressWarnings("unused")
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java
index 1fe588f117dd..db86ca35a058 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java
@@ -34,10 +34,14 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
@@ -101,7 +105,7 @@ public final class NativeLibraries {
 
     private final LinkedHashSet<CLibrary> annotated;
     private final List<String> libraries;
-    private final List<String> staticLibraries;
+    private final DependencyGraph dependencyGraph;
     private final LinkedHashSet<String> libraryPaths;
 
     private final List<CInterfaceError> errors;
@@ -118,6 +122,103 @@ public final class NativeLibraries {
      */
     private static final Path CUSTOM_LIBC_STATIC_DIST_PATH = Paths.get("svm", "static-libs");
 
+    public static final class DependencyGraph {
+
+        private static final class Dependency {
+            private final String name;
+            private final Set<Dependency> dependencies;
+
+            Dependency(String name, Set<Dependency> dependencies) {
+                assert dependencies != null;
+                this.name = name;
+                this.dependencies = dependencies;
+            }
+
+            public String getName() {
+                return name;
+            }
+
+            public Set<Dependency> getDependencies() {
+                return dependencies;
+            }
+
+            @Override
+            public String toString() {
+                String depString = dependencies.stream().map(Dependency::getName).collect(Collectors.joining());
+                return "Dependency{" +
+                                "name='" + name + '\'' +
+                                ", dependencies=[" + depString +
+                                "]}";
+            }
+        }
+
+        private final Map<String, Dependency> allDependencies;
+
+        public DependencyGraph() {
+            allDependencies = new ConcurrentHashMap<>();
+        }
+
+        public void add(String library, String... dependencies) {
+            UserError.guarantee(library != null, "The library name must be not null and not empty");
+
+            Dependency libraryDependency = putWhenAbsent(library, new Dependency(library, new HashSet<>()));
+            Set<Dependency> collectedDependencies = libraryDependency.getDependencies();
+            if (dependencies == null) {
+                return;
+            }
+
+            for (String dependency : dependencies) {
+                collectedDependencies.add(putWhenAbsent(
+                                dependency, new Dependency(dependency, new HashSet<>())));
+            }
+        }
+
+        public List<String> sort() {
+            final Set<Dependency> discovered = new HashSet<>();
+            final Set<Dependency> processed = new LinkedHashSet<>();
+
+            for (Dependency dep : allDependencies.values()) {
+                visit(dep, discovered, processed);
+            }
+
+            LinkedList<String> names = new LinkedList<>();
+            processed.forEach(n -> names.push(n.getName()));
+            return names;
+        }
+
+        private Dependency putWhenAbsent(String libName, Dependency dep) {
+            if (!allDependencies.containsKey(libName)) {
+                allDependencies.put(libName, dep);
+            }
+            return allDependencies.get(libName);
+        }
+
+        private void visit(Dependency dep, Set<Dependency> discovered, Set<Dependency> processed) {
+            if (processed.contains(dep)) {
+                return;
+            }
+            if (discovered.contains(dep)) {
+                String message = String.format("While building list of static libraries dependencies a cycle was discovered for dependency: %s ", dep.getName());
+                UserError.abort(message);
+            }
+
+            discovered.add(dep);
+            dep.getDependencies().forEach(d -> visit(d, discovered, processed));
+            processed.add(dep);
+        }
+
+        @Override
+        public String toString() {
+            String depsStr = allDependencies.values()
+                            .stream()
+                            .map(Dependency::toString)
+                            .collect(Collectors.joining("\n"));
+            return "DependencyGraph{\n" +
+                            depsStr +
+                            '}';
+        }
+    }
+
     public NativeLibraries(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, TargetDescription target,
                     ClassInitializationSupport classInitializationSupport, Path tempDirectory, DebugContext debug) {
         this.metaAccess = metaAccess;
@@ -152,7 +253,7 @@ public NativeLibraries(ConstantReflectionProvider constantReflection, MetaAccess
          * libraries that have cyclic dependencies.
          */
         libraries = Collections.synchronizedList(new ArrayList<>());
-        staticLibraries = Collections.synchronizedList(new ArrayList<>());
+        dependencyGraph = new DependencyGraph();
 
         libraryPaths = initCLibraryPath();
 
@@ -270,7 +371,15 @@ public void addAnnotated(CLibrary library) {
     }
 
     public void addLibrary(String library, boolean requireStatic) {
-        (requireStatic ? staticLibraries : libraries).add(library);
+        addLibrary(library, requireStatic, null);
+    }
+
+    public void addLibrary(String library, boolean requireStatic, String[] dependencies) {
+        if (requireStatic) {
+            dependencyGraph.add(library, dependencies);
+        } else {
+            libraries.add(library);
+        }
     }
 
     public Collection<String> getLibraries() {
@@ -280,7 +389,9 @@ public Collection<String> getLibraries() {
     public Collection<Path> getStaticLibraries() {
         Map<Path, Path> allStaticLibs = getAllStaticLibs();
         List<Path> staticLibs = new ArrayList<>();
-        for (String staticLibraryName : staticLibraries) {
+        List<String> sortedList = dependencyGraph.sort();
+
+        for (String staticLibraryName : sortedList) {
             Path libraryPath = getStaticLibraryPath(allStaticLibs, staticLibraryName);
             if (libraryPath == null) {
                 continue;
@@ -444,7 +555,7 @@ public boolean processAnnotated() {
             return false;
         }
         for (CLibrary lib : annotated) {
-            addLibrary(lib.value(), lib.requireStatic());
+            addLibrary(lib.value(), lib.requireStatic(), lib.dependsOn());
         }
         annotated.clear();
         return true;

From d9992035ab8598263434be43ce44a555fc7287b3 Mon Sep 17 00:00:00 2001
From: Esteban Ginez <esteban.ginez@oracle.com>
Date: Mon, 6 Apr 2020 14:33:23 -0700
Subject: [PATCH 13/13] [GR-21741] Avoids data on posix oses

---
 .../src/org/graalvm/nativeimage/c/function/CLibrary.java    | 2 +-
 .../src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java  | 6 ++----
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/c/function/CLibrary.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/c/function/CLibrary.java
index ecdb513abfce..de00d235a5cf 100644
--- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/c/function/CLibrary.java
+++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/c/function/CLibrary.java
@@ -72,7 +72,7 @@
     /**
      * Specifies the name of the libraries this library depends on.
      * 
-     * @since 20.0.1
+     * @since 20.1.0
      */
     String[] dependsOn() default {};
 }
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
index 591cb4741f4d..1fadd645f47a 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java
@@ -86,9 +86,8 @@ private static String getSystemTimeZoneID(String javaHome) {
         int contentLen = 0;
         PinnedObject pinnedContent = null;
         try {
-            TimeZoneSupport timeZoneSupport = ImageSingletons.lookup(TimeZoneSupport.class);
-            byte[] content = timeZoneSupport.getTzMappingsContent();
-            if (content != null) {
+            if (ImageSingletons.contains(TimeZoneSupport.class)) {
+                byte[] content = ImageSingletons.lookup(TimeZoneSupport.class).getTzMappingsContent();
                 contentLen = content.length;
                 pinnedContent = PinnedObject.create(content);
                 tzMappingsPtr = pinnedContent.addressOfArrayElement(0);
@@ -168,7 +167,6 @@ private static byte[] cleanCR(byte[] buffer) {
     public void afterRegistration(AfterRegistrationAccess access) {
 
         if (OS.getCurrent() != OS.WINDOWS) {
-            ImageSingletons.add(TimeZoneSupport.class, new TimeZoneSupport(null));
             return;
         }