001/*
002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.truffle;
024
025import static com.oracle.graal.truffle.TruffleCompilerOptions.*;
026
027import java.lang.ref.*;
028import java.util.*;
029import java.util.stream.*;
030
031import jdk.internal.jvmci.code.*;
032
033import com.oracle.graal.debug.*;
034import com.oracle.truffle.api.*;
035import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
036import com.oracle.truffle.api.impl.*;
037import com.oracle.truffle.api.nodes.*;
038
039public final class OptimizedAssumption extends AbstractAssumption {
040
041    private static class Entry {
042        WeakReference<InstalledCode> installedCode;
043        long version;
044        Entry next;
045    }
046
047    private Entry first;
048
049    public OptimizedAssumption(String name) {
050        super(name);
051    }
052
053    @Override
054    public void check() throws InvalidAssumptionException {
055        if (!this.isValid()) {
056            CompilerDirectives.transferToInterpreterAndInvalidate();
057            throw new InvalidAssumptionException();
058        }
059    }
060
061    @Override
062    public synchronized void invalidate() {
063        if (isValid) {
064            invalidateImpl();
065        }
066    }
067
068    @TruffleBoundary
069    private void invalidateImpl() {
070        boolean invalidatedInstalledCode = false;
071        Entry e = first;
072        while (e != null) {
073            InstalledCode installedCode = e.installedCode.get();
074            if (installedCode != null && installedCode.getVersion() == e.version) {
075                invalidateWithReason(installedCode, "assumption invalidated");
076                invalidatedInstalledCode = true;
077                if (TraceTruffleAssumptions.getValue()) {
078                    logInvalidatedInstalledCode(installedCode);
079                }
080            }
081            e = e.next;
082        }
083        first = null;
084        isValid = false;
085
086        if (TraceTruffleAssumptions.getValue()) {
087            if (invalidatedInstalledCode) {
088                logStackTrace();
089            }
090        }
091    }
092
093    public synchronized void registerInstalledCode(InstalledCode installedCode) {
094        if (isValid) {
095            Entry e = new Entry();
096            e.installedCode = new WeakReference<>(installedCode);
097            e.version = installedCode.getVersion();
098            e.next = first;
099            first = e;
100        } else {
101            invalidateWithReason(installedCode, "assumption already invalidated when installing code");
102            if (TraceTruffleAssumptions.getValue()) {
103                logInvalidatedInstalledCode(installedCode);
104                logStackTrace();
105            }
106        }
107    }
108
109    private void invalidateWithReason(InstalledCode installedCode, String reason) {
110        if (installedCode instanceof OptimizedCallTarget) {
111            ((OptimizedCallTarget) installedCode).invalidate(this, reason);
112        } else {
113            installedCode.invalidate();
114        }
115    }
116
117    @Override
118    public boolean isValid() {
119        return isValid;
120    }
121
122    private void logInvalidatedInstalledCode(InstalledCode installedCode) {
123        TTY.out().out().printf("assumption '%s' invalidated installed code '%s'\n", name, installedCode);
124    }
125
126    private static void logStackTrace() {
127        final int skip = 1;
128        final int limit = TraceTruffleStackTraceLimit.getValue();
129        StackTraceElement[] stackTrace = new Throwable().getStackTrace();
130        String suffix = stackTrace.length > skip + limit ? "\n  ..." : "";
131        TTY.out().out().println(Arrays.stream(stackTrace).skip(skip).limit(limit).map(StackTraceElement::toString).collect(Collectors.joining("\n  ", "", suffix)));
132    }
133}