nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java
author lagergren
Fri, 26 Sep 2014 18:47:20 +0200
changeset 26886 18c744ab4df2
parent 26768 751b0f427090
child 27366 c0fdaac978ea
permissions -rw-r--r--
8059211: Changed ArrayData.length accessor to use the protected field and fixed javadoc warnings related to this Reviewed-by: attila, hannesw
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
     1
/*
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
     2
 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
     4
 *
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    10
 *
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    15
 * accompanied this code).
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    16
 *
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    20
 *
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    23
 * questions.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    24
 */
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    25
package jdk.nashorn.internal.codegen;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    26
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    27
import java.io.BufferedInputStream;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    28
import java.io.BufferedOutputStream;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    29
import java.io.DataInputStream;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    30
import java.io.DataOutputStream;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    31
import java.io.File;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    32
import java.io.FileInputStream;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    33
import java.io.FileOutputStream;
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    34
import java.io.IOException;
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    35
import java.io.InputStream;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    36
import java.net.URL;
26253
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
    37
import java.nio.file.Files;
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    38
import java.nio.file.Path;
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    39
import java.security.AccessController;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    40
import java.security.MessageDigest;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    41
import java.security.PrivilegedAction;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    42
import java.text.SimpleDateFormat;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    43
import java.util.Base64;
25586
cac6440168e2 8050964: OptimisticTypesPersistence.java should use java.util.Date instead of java.sql.Date
sundar
parents: 25255
diff changeset
    44
import java.util.Date;
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    45
import java.util.Map;
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    46
import java.util.Timer;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    47
import java.util.TimerTask;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    48
import java.util.concurrent.TimeUnit;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    49
import java.util.concurrent.atomic.AtomicBoolean;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    50
import java.util.function.Function;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    51
import java.util.function.IntFunction;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    52
import java.util.function.Predicate;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    53
import java.util.stream.Stream;
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    54
import jdk.nashorn.internal.codegen.types.Type;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    55
import jdk.nashorn.internal.runtime.Context;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    56
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    57
import jdk.nashorn.internal.runtime.Source;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    58
import jdk.nashorn.internal.runtime.logging.DebugLogger;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    59
import jdk.nashorn.internal.runtime.options.Options;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    60
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    61
/**
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    62
 * Static utility that encapsulates persistence of type information for functions compiled with optimistic
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    63
 * typing. With this feature enabled, when a JavaScript function is recompiled because it gets deoptimized,
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    64
 * the type information for deoptimization is stored in a cache file. If the same function is compiled in a
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    65
 * subsequent JVM invocation, the type information is used for initial compilation, thus allowing the system
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    66
 * to skip a lot of intermediate recompilations and immediately emit a version of the code that has its
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    67
 * optimistic types at (or near) the steady state.
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    68
 * </p><p>
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    69
 * Normally, the type info persistence feature is disabled. When the {@code nashorn.typeInfo.maxFiles} system
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    70
 * property is specified with a value greater than 0, it is enabled and operates in an operating-system
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    71
 * specific per-user cache directory. You can override the directory by specifying it in the
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    72
 * {@code nashorn.typeInfo.cacheDir} directory. The maximum number of files is softly enforced by a task that
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    73
 * cleans up the directory periodically on a separate thread. It is run after some delay after a new file is
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    74
 * added to the cache. The default delay is 20 seconds, and can be set using the
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    75
 * {@code nashorn.typeInfo.cleanupDelaySeconds} system property. You can also specify the word
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    76
 * {@code unlimited} as the value for {@code nashorn.typeInfo.maxFiles} in which case the type info cache is
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    77
 * allowed to grow without limits.
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    78
 */
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    79
public final class OptimisticTypesPersistence {
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    80
    // Default is 0, for disabling the feature when not specified. A reasonable default when enabled is
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    81
    // dependent on the application; setting it to e.g. 20000 is probably good enough for most uses and will
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    82
    // usually cap the cache directory to about 80MB presuming a 4kB filesystem allocation unit. There is one
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    83
    // file per JavaScript function.
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    84
    private static final int DEFAULT_MAX_FILES = 0;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    85
    // Constants for signifying that the cache should not be limited
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    86
    private static final int UNLIMITED_FILES = -1;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    87
    // Maximum number of files that should be cached on disk. The maximum will be softly enforced.
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    88
    private static final int MAX_FILES = getMaxFiles();
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    89
    // Number of seconds to wait between adding a new file to the cache and running a cleanup process
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    90
    private static final int DEFAULT_CLEANUP_DELAY = 20;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    91
    private static final int CLEANUP_DELAY = Math.max(0, Options.getIntProperty(
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    92
            "nashorn.typeInfo.cleanupDelaySeconds", DEFAULT_CLEANUP_DELAY));
26253
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
    93
    // The name of the default subdirectory within the system cache directory where we store type info.
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
    94
    private static final String DEFAULT_CACHE_SUBDIR_NAME = "com.oracle.java.NashornTypeInfo";
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
    95
    // The directory where we cache type info
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    96
    private static final File baseCacheDir = createBaseCacheDir();
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
    97
    private static final File cacheDir = createCacheDir(baseCacheDir);
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    98
    // In-process locks to make sure we don't have a cross-thread race condition manipulating any file.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
    99
    private static final Object[] locks = cacheDir == null ? null : createLockArray();
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   100
    // Only report one read/write error every minute
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   101
    private static final long ERROR_REPORT_THRESHOLD = 60000L;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   102
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   103
    private static volatile long lastReportedError;
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   104
    private static final AtomicBoolean scheduledCleanup;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   105
    private static final Timer cleanupTimer;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   106
    static {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   107
        if (baseCacheDir == null || MAX_FILES == UNLIMITED_FILES) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   108
            scheduledCleanup = null;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   109
            cleanupTimer = null;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   110
        } else {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   111
            scheduledCleanup = new AtomicBoolean();
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   112
            cleanupTimer = new Timer(true);
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   113
        }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   114
    }
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   115
    /**
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   116
     * Retrieves an opaque descriptor for the persistence location for a given function. It should be passed
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   117
     * to {@link #load(Object)} and {@link #store(Object, Map)} methods.
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   118
     * @param source the source where the function comes from
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   119
     * @param functionId the unique ID number of the function within the source
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   120
     * @param paramTypes the types of the function parameters (as persistence is per parameter type
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   121
     * specialization).
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   122
     * @return an opaque descriptor for the persistence location. Can be null if persistence is disabled.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   123
     */
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   124
    public static Object getLocationDescriptor(final Source source, final int functionId, final Type[] paramTypes) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   125
        if(cacheDir == null) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   126
            return null;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   127
        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   128
        final StringBuilder b = new StringBuilder(48);
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   129
        // Base64-encode the digest of the source, and append the function id.
25255
cf56cdc2c663 8049225: Source class exposes public mutable array
attila
parents: 25241
diff changeset
   130
        b.append(source.getDigest()).append('-').append(functionId);
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   131
        // Finally, if this is a parameter-type specialized version of the function, add the parameter types
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   132
        // to the file name.
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   133
        if(paramTypes != null && paramTypes.length > 0) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   134
            b.append('-');
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   135
            for(final Type t: paramTypes) {
26055
fe8be844ba50 8043956: Make code caching work with optimistic typing and lazy compilation
hannesw
parents: 25821
diff changeset
   136
                b.append(Type.getShortSignatureDescriptor(t));
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   137
            }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   138
        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   139
        return new LocationDescriptor(new File(cacheDir, b.toString()));
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   140
    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   141
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   142
    private static final class LocationDescriptor {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   143
        private final File file;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   144
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   145
        LocationDescriptor(final File file) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   146
            this.file = file;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   147
        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   148
    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   149
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   150
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   151
    /**
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   152
     * Stores the map of optimistic types for a given function.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   153
     * @param locationDescriptor the opaque persistence location descriptor, retrieved by calling
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   154
     * {@link #getLocationDescriptor(Source, int, Type[])}.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   155
     * @param optimisticTypes the map of optimistic types.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   156
     */
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   157
    @SuppressWarnings("resource")
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   158
    public static void store(final Object locationDescriptor, final Map<Integer, Type> optimisticTypes) {
26061
cf60b442cf78 8054898: Avoid creation of empty type info files
hannesw
parents: 26055
diff changeset
   159
        if(locationDescriptor == null || optimisticTypes.isEmpty()) {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   160
            return;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   161
        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   162
        final File file = ((LocationDescriptor)locationDescriptor).file;
25821
fbb51e67d2a7 8048869: Reduce compile time by about 5% by removing the Class.casts from the AST nodes
lagergren
parents: 25586
diff changeset
   163
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   164
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   165
            @Override
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   166
            public Void run() {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   167
                synchronized(getFileLock(file)) {
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   168
                    if (!file.exists()) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   169
                        // If the file already exists, we aren't increasing the number of cached files, so
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   170
                        // don't schedule cleanup.
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   171
                        scheduleCleanup();
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   172
                    }
26055
fe8be844ba50 8043956: Make code caching work with optimistic typing and lazy compilation
hannesw
parents: 25821
diff changeset
   173
                    try (final FileOutputStream out = new FileOutputStream(file)) {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   174
                        out.getChannel().lock(); // lock exclusive
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   175
                        final DataOutputStream dout = new DataOutputStream(new BufferedOutputStream(out));
26055
fe8be844ba50 8043956: Make code caching work with optimistic typing and lazy compilation
hannesw
parents: 25821
diff changeset
   176
                        Type.writeTypeMap(optimisticTypes, dout);
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   177
                        dout.flush();
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   178
                    } catch(final Exception e) {
25241
92eb440faf5c 8048009: Type info caching accidentally defeated
attila
parents: 25236
diff changeset
   179
                        reportError("write", file, e);
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   180
                    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   181
                }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   182
                return null;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   183
            }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   184
        });
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   185
    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   186
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   187
    /**
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   188
     * Loads the map of optimistic types for a given function.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   189
     * @param locationDescriptor the opaque persistence location descriptor, retrieved by calling
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   190
     * {@link #getLocationDescriptor(Source, int, Type[])}.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   191
     * @return the map of optimistic types, or null if persisted type information could not be retrieved.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   192
     */
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   193
    @SuppressWarnings("resource")
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   194
    public static Map<Integer, Type> load(final Object locationDescriptor) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   195
        if (locationDescriptor == null) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   196
            return null;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   197
        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   198
        final File file = ((LocationDescriptor)locationDescriptor).file;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   199
        return AccessController.doPrivileged(new PrivilegedAction<Map<Integer, Type>>() {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   200
            @Override
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   201
            public Map<Integer, Type> run() {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   202
                try {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   203
                    if(!file.isFile()) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   204
                        return null;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   205
                    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   206
                    synchronized(getFileLock(file)) {
26055
fe8be844ba50 8043956: Make code caching work with optimistic typing and lazy compilation
hannesw
parents: 25821
diff changeset
   207
                        try (final FileInputStream in = new FileInputStream(file)) {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   208
                            in.getChannel().lock(0, Long.MAX_VALUE, true); // lock shared
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   209
                            final DataInputStream din = new DataInputStream(new BufferedInputStream(in));
26055
fe8be844ba50 8043956: Make code caching work with optimistic typing and lazy compilation
hannesw
parents: 25821
diff changeset
   210
                            return Type.readTypeMap(din);
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   211
                        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   212
                    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   213
                } catch (final Exception e) {
25241
92eb440faf5c 8048009: Type info caching accidentally defeated
attila
parents: 25236
diff changeset
   214
                    reportError("read", file, e);
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   215
                    return null;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   216
                }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   217
            }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   218
        });
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   219
    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   220
25241
92eb440faf5c 8048009: Type info caching accidentally defeated
attila
parents: 25236
diff changeset
   221
    private static void reportError(final String msg, final File file, final Exception e) {
92eb440faf5c 8048009: Type info caching accidentally defeated
attila
parents: 25236
diff changeset
   222
        final long now = System.currentTimeMillis();
92eb440faf5c 8048009: Type info caching accidentally defeated
attila
parents: 25236
diff changeset
   223
        if(now - lastReportedError > ERROR_REPORT_THRESHOLD) {
92eb440faf5c 8048009: Type info caching accidentally defeated
attila
parents: 25236
diff changeset
   224
            getLogger().warning(String.format("Failed to %s %s", msg, file), e);
92eb440faf5c 8048009: Type info caching accidentally defeated
attila
parents: 25236
diff changeset
   225
            lastReportedError = now;
92eb440faf5c 8048009: Type info caching accidentally defeated
attila
parents: 25236
diff changeset
   226
        }
92eb440faf5c 8048009: Type info caching accidentally defeated
attila
parents: 25236
diff changeset
   227
    }
92eb440faf5c 8048009: Type info caching accidentally defeated
attila
parents: 25236
diff changeset
   228
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   229
    private static File createBaseCacheDir() {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   230
        if(MAX_FILES == 0 || Options.getBooleanProperty("nashorn.typeInfo.disabled")) {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   231
            return null;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   232
        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   233
        try {
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   234
            return createBaseCacheDirPrivileged();
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   235
        } catch(final Exception e) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   236
            getLogger().warning("Failed to create cache dir", e);
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   237
            return null;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   238
        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   239
    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   240
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   241
    private static File createBaseCacheDirPrivileged() {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   242
        return AccessController.doPrivileged(new PrivilegedAction<File>() {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   243
            @Override
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   244
            public File run() {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   245
                final String explicitDir = System.getProperty("nashorn.typeInfo.cacheDir");
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   246
                final File dir;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   247
                if(explicitDir != null) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   248
                    dir = new File(explicitDir);
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   249
                } else {
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   250
                    // When no directory is explicitly specified, get an operating system specific cache
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   251
                    // directory, and create "com.oracle.java.NashornTypeInfo" in it.
26253
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   252
                    final File systemCacheDir = getSystemCacheDir();
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   253
                    dir = new File(systemCacheDir, DEFAULT_CACHE_SUBDIR_NAME);
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   254
                    if (isSymbolicLink(dir)) {
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   255
                        return null;
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   256
                    }
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   257
                }
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   258
                return dir;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   259
            }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   260
        });
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   261
    }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   262
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   263
    private static File createCacheDir(final File baseDir) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   264
        if (baseDir == null) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   265
            return null;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   266
        }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   267
        try {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   268
            return createCacheDirPrivileged(baseDir);
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   269
        } catch(final Exception e) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   270
            getLogger().warning("Failed to create cache dir", e);
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   271
            return null;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   272
        }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   273
    }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   274
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   275
    private static File createCacheDirPrivileged(final File baseDir) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   276
        return AccessController.doPrivileged(new PrivilegedAction<File>() {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   277
            @Override
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   278
            public File run() {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   279
                final String versionDirName;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   280
                try {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   281
                    versionDirName = getVersionDirName();
25821
fbb51e67d2a7 8048869: Reduce compile time by about 5% by removing the Class.casts from the AST nodes
lagergren
parents: 25586
diff changeset
   282
                } catch(final Exception e) {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   283
                    getLogger().warning("Failed to calculate version dir name", e);
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   284
                    return null;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   285
                }
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   286
                final File versionDir = new File(baseDir, versionDirName);
26253
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   287
                if (isSymbolicLink(versionDir)) {
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   288
                    return null;
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   289
                }
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   290
                versionDir.mkdirs();
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   291
                if (versionDir.isDirectory()) {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   292
                    getLogger().info("Optimistic type persistence directory is " + versionDir);
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   293
                    return versionDir;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   294
                }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   295
                getLogger().warning("Could not create optimistic type persistence directory " + versionDir);
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   296
                return null;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   297
            }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   298
        });
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   299
    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   300
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   301
    /**
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   302
     * Returns an operating system specific root directory for cache files.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   303
     * @return an operating system specific root directory for cache files.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   304
     */
26253
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   305
    private static File getSystemCacheDir() {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   306
        final String os = System.getProperty("os.name", "generic");
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   307
        if("Mac OS X".equals(os)) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   308
            // Mac OS X stores caches in ~/Library/Caches
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   309
            return new File(new File(System.getProperty("user.home"), "Library"), "Caches");
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   310
        } else if(os.startsWith("Windows")) {
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   311
            // On Windows, temp directory is the best approximation of a cache directory, as its contents
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   312
            // persist across reboots and various cleanup utilities know about it. java.io.tmpdir normally
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   313
            // points to a user-specific temp directory, %HOME%\LocalSettings\Temp.
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   314
            return new File(System.getProperty("java.io.tmpdir"));
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   315
        } else {
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   316
            // In other cases we're presumably dealing with a UNIX flavor (Linux, Solaris, etc.); "~/.cache"
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   317
            return new File(System.getProperty("user.home"), ".cache");
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   318
        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   319
    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   320
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   321
    /**
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   322
     * In order to ensure that changes in Nashorn code don't cause corruption in the data, we'll create a
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   323
     * per-code-version directory. Normally, this will create the SHA-1 digest of the nashorn.jar. In case the classpath
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   324
     * for nashorn is local directory (e.g. during development), this will create the string "dev-" followed by the
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   325
     * timestamp of the most recent .class file.
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   326
     * @return
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   327
     */
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   328
    private static String getVersionDirName() throws Exception {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   329
        final URL url = OptimisticTypesPersistence.class.getResource("");
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   330
        final String protocol = url.getProtocol();
26055
fe8be844ba50 8043956: Make code caching work with optimistic typing and lazy compilation
hannesw
parents: 25821
diff changeset
   331
        if (protocol.equals("jar")) {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   332
            // Normal deployment: nashorn.jar
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   333
            final String jarUrlFile = url.getFile();
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   334
            final String filePath = jarUrlFile.substring(0, jarUrlFile.indexOf('!'));
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   335
            final URL file = new URL(filePath);
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   336
            try (final InputStream in = file.openStream()) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   337
                final byte[] buf = new byte[128*1024];
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   338
                final MessageDigest digest = MessageDigest.getInstance("SHA-1");
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   339
                for(;;) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   340
                    final int l = in.read(buf);
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   341
                    if(l == -1) {
25255
cf56cdc2c663 8049225: Source class exposes public mutable array
attila
parents: 25241
diff changeset
   342
                        return Base64.getUrlEncoder().withoutPadding().encodeToString(digest.digest());
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   343
                    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   344
                    digest.update(buf, 0, l);
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   345
                }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   346
            }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   347
        } else if(protocol.equals("file")) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   348
            // Development
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   349
            final String fileStr = url.getFile();
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   350
            final String className = OptimisticTypesPersistence.class.getName();
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   351
            final int packageNameLen = className.lastIndexOf('.');
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   352
            final String dirStr = fileStr.substring(0, fileStr.length() - packageNameLen - 1);
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   353
            final File dir = new File(dirStr);
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   354
            return "dev-" + new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(getLastModifiedClassFile(
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   355
                    dir, 0L)));
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   356
        } else {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   357
            throw new AssertionError();
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   358
        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   359
    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   360
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   361
    private static long getLastModifiedClassFile(final File dir, final long max) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   362
        long currentMax = max;
25821
fbb51e67d2a7 8048869: Reduce compile time by about 5% by removing the Class.casts from the AST nodes
lagergren
parents: 25586
diff changeset
   363
        for(final File f: dir.listFiles()) {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   364
            if(f.getName().endsWith(".class")) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   365
                final long lastModified = f.lastModified();
26055
fe8be844ba50 8043956: Make code caching work with optimistic typing and lazy compilation
hannesw
parents: 25821
diff changeset
   366
                if (lastModified > currentMax) {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   367
                    currentMax = lastModified;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   368
                }
26055
fe8be844ba50 8043956: Make code caching work with optimistic typing and lazy compilation
hannesw
parents: 25821
diff changeset
   369
            } else if (f.isDirectory()) {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   370
                final long lastModified = getLastModifiedClassFile(f, currentMax);
26055
fe8be844ba50 8043956: Make code caching work with optimistic typing and lazy compilation
hannesw
parents: 25821
diff changeset
   371
                if (lastModified > currentMax) {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   372
                    currentMax = lastModified;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   373
                }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   374
            }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   375
        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   376
        return currentMax;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   377
    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   378
26253
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   379
    /**
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   380
     * Returns true if the specified file is a symbolic link, and also logs a warning if it is.
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   381
     * @param file the file
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   382
     * @return true if file is a symbolic link, false otherwise.
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   383
     */
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   384
    private static boolean isSymbolicLink(final File file) {
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   385
        if (Files.isSymbolicLink(file.toPath())) {
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   386
            getLogger().warning("Directory " + file + " is a symlink");
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   387
            return true;
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   388
        }
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   389
        return false;
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   390
    }
059266c07564 8056243: OptimisticTypePersistence should refuse to work in symlinked directories
attila
parents: 26068
diff changeset
   391
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   392
    private static Object[] createLockArray() {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   393
        final Object[] lockArray = new Object[Runtime.getRuntime().availableProcessors() * 2];
26055
fe8be844ba50 8043956: Make code caching work with optimistic typing and lazy compilation
hannesw
parents: 25821
diff changeset
   394
        for (int i = 0; i < lockArray.length; ++i) {
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   395
            lockArray[i] = new Object();
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   396
        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   397
        return lockArray;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   398
    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   399
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   400
    private static Object getFileLock(final File file) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   401
        return locks[(file.hashCode() & Integer.MAX_VALUE) % locks.length];
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   402
    }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   403
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   404
    private static DebugLogger getLogger() {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   405
        try {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   406
            return Context.getContext().getLogger(RecompilableScriptFunctionData.class);
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   407
        } catch (final Exception e) {
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   408
            e.printStackTrace();
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   409
            return DebugLogger.DISABLED_LOGGER;
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   410
        }
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   411
    }
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   412
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   413
    private static void scheduleCleanup() {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   414
        if (MAX_FILES != UNLIMITED_FILES && scheduledCleanup.compareAndSet(false, true)) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   415
            cleanupTimer.schedule(new TimerTask() {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   416
                @Override
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   417
                public void run() {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   418
                    scheduledCleanup.set(false);
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   419
                    try {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   420
                        doCleanup();
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   421
                    } catch (final IOException e) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   422
                        // Ignore it. While this is unfortunate, we don't have good facility for reporting
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   423
                        // this, as we're running in a thread that has no access to Context, so we can't grab
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   424
                        // a DebugLogger.
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   425
                    }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   426
                }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   427
            }, TimeUnit.SECONDS.toMillis(CLEANUP_DELAY));
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   428
        }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   429
    }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   430
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   431
    private static void doCleanup() throws IOException {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   432
        final Path[] files = getAllRegularFilesInLastModifiedOrder();
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   433
        final int nFiles = files.length;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   434
        final int filesToDelete = Math.max(0, nFiles - MAX_FILES);
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   435
        int filesDeleted = 0;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   436
        for (int i = 0; i < nFiles && filesDeleted < filesToDelete; ++i) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   437
            try {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   438
                Files.deleteIfExists(files[i]);
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   439
                // Even if it didn't exist, we increment filesDeleted; it existed a moment earlier; something
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   440
                // else deleted it for us; that's okay with us.
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   441
                filesDeleted++;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   442
            } catch (final Exception e) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   443
                // does not increase filesDeleted
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   444
            }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   445
            files[i] = null; // gc eligible
26886
18c744ab4df2 8059211: Changed ArrayData.length accessor to use the protected field and fixed javadoc warnings related to this
lagergren
parents: 26768
diff changeset
   446
        }
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   447
    }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   448
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   449
    private static Path[] getAllRegularFilesInLastModifiedOrder() throws IOException {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   450
        try (final Stream<Path> filesStream = Files.walk(baseCacheDir.toPath())) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   451
            // TODO: rewrite below once we can use JDK8 syntactic constructs
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   452
            return filesStream
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   453
            .filter(new Predicate<Path>() {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   454
                @Override
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   455
                public boolean test(final Path path) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   456
                    return !Files.isDirectory(path);
26886
18c744ab4df2 8059211: Changed ArrayData.length accessor to use the protected field and fixed javadoc warnings related to this
lagergren
parents: 26768
diff changeset
   457
                }
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   458
            })
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   459
            .map(new Function<Path, PathAndTime>() {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   460
                @Override
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   461
                public PathAndTime apply(final Path path) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   462
                    return new PathAndTime(path);
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   463
                }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   464
            })
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   465
            .sorted()
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   466
            .map(new Function<PathAndTime, Path>() {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   467
                @Override
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   468
                public Path apply(final PathAndTime pathAndTime) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   469
                    return pathAndTime.path;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   470
                }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   471
            })
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   472
            .toArray(new IntFunction<Path[]>() { // Replace with Path::new
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   473
                @Override
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   474
                public Path[] apply(final int length) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   475
                    return new Path[length];
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   476
                }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   477
            });
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   478
        }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   479
    }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   480
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   481
    private static class PathAndTime implements Comparable<PathAndTime> {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   482
        private final Path path;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   483
        private final long time;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   484
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   485
        PathAndTime(final Path path) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   486
            this.path = path;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   487
            this.time = getTime(path);
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   488
        }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   489
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   490
        @Override
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   491
        public int compareTo(final PathAndTime other) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   492
            return Long.compare(time, other.time);
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   493
        }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   494
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   495
        private static long getTime(final Path path) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   496
            try {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   497
                return Files.getLastModifiedTime(path).toMillis();
26768
751b0f427090 8025435: Optimistic builtins support, implemented initial optimistic versions of push, pop, and charCodeAt
lagergren
parents: 26374
diff changeset
   498
            } catch (final IOException e) {
26374
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   499
                // All files for which we can't retrieve the last modified date will be considered oldest.
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   500
                return -1L;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   501
            }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   502
        }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   503
    }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   504
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   505
    private static int getMaxFiles() {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   506
        final String str = Options.getStringProperty("nashorn.typeInfo.maxFiles", null);
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   507
        if (str == null) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   508
            return DEFAULT_MAX_FILES;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   509
        } else if ("unlimited".equals(str)) {
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   510
            return UNLIMITED_FILES;
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   511
        }
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   512
        return Math.max(0, Integer.parseInt(str));
5bc67576b50e 8056913: Limit the size of type info cache on disk
attila
parents: 26253
diff changeset
   513
    }
25236
fac419f1e889 8046921: Deoptimization type information peristence
attila
parents:
diff changeset
   514
}