From f9fd7bfba53d2f7d4fa5c810a21d1e9a052c1a10 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 19 Mar 2013 17:15:48 +0400 Subject: [PATCH] Tracking sliced map for debugging "Rewrite at slice..." --- .../jet/lang/resolve/BindingTraceContext.java | 12 +- .../jetbrains/jet/util/slicedmap/Slices.java | 1 + .../jet/util/slicedmap/TrackingSlicedMap.java | 186 ++++++++++++++++++ 3 files changed, 194 insertions(+), 5 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/util/slicedmap/TrackingSlicedMap.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java index a21e8a324de..bd006c54c10 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java @@ -21,10 +21,7 @@ import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; import org.jetbrains.jet.lang.diagnostics.Diagnostic; -import org.jetbrains.jet.util.slicedmap.MutableSlicedMap; -import org.jetbrains.jet.util.slicedmap.ReadOnlySlice; -import org.jetbrains.jet.util.slicedmap.SlicedMapImpl; -import org.jetbrains.jet.util.slicedmap.WritableSlice; +import org.jetbrains.jet.util.slicedmap.*; import java.util.Collection; import java.util.List; @@ -32,7 +29,12 @@ import java.util.List; public class BindingTraceContext implements BindingTrace { private final List diagnostics = Lists.newArrayList(); - private final MutableSlicedMap map = SlicedMapImpl.create(); + // This flag is used for debugging of "Rewrite at slice..." exceptions + // NOTE: sometimes TrackingSlicedMap throws a ClassCastException (after you have fixed the rewrite). + // I gave up debugging it, because it still serves its purpose. Any suggestions on how to fix it are welcome. (abreslav) + private final static boolean TRACK_REWRITES = false; + @SuppressWarnings("ConstantConditions") + private final MutableSlicedMap map = TRACK_REWRITES ? new TrackingSlicedMap(SlicedMapImpl.create()) : SlicedMapImpl.create(); private final BindingContext bindingContext = new BindingContext() { diff --git a/compiler/frontend/src/org/jetbrains/jet/util/slicedmap/Slices.java b/compiler/frontend/src/org/jetbrains/jet/util/slicedmap/Slices.java index bcaa464f209..3a9e0bff886 100644 --- a/compiler/frontend/src/org/jetbrains/jet/util/slicedmap/Slices.java +++ b/compiler/frontend/src/org/jetbrains/jet/util/slicedmap/Slices.java @@ -32,6 +32,7 @@ public class Slices { @Override public boolean processRewrite(WritableSlice slice, K key, V oldValue, V newValue) { if (!((oldValue == null && newValue == null) || (oldValue != null && oldValue.equals(newValue)))) { + // NOTE: Use BindingTraceContext.TRACK_REWRITES to debug this exception throw new IllegalStateException("Rewrite at slice " + slice + " key: " + key + " old value: " + oldValue + '@' + System.identityHashCode(oldValue) + diff --git a/compiler/frontend/src/org/jetbrains/jet/util/slicedmap/TrackingSlicedMap.java b/compiler/frontend/src/org/jetbrains/jet/util/slicedmap/TrackingSlicedMap.java new file mode 100644 index 00000000000..b8e0d5b3492 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/util/slicedmap/TrackingSlicedMap.java @@ -0,0 +1,186 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.util.slicedmap; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; +import org.jetbrains.jet.utils.Printer; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; + +public class TrackingSlicedMap implements MutableSlicedMap { + + private final MutableSlicedMap delegate; + private final Map, SliceWithStackTrace> sliceTranslationMap = Maps.newHashMap(); + + public TrackingSlicedMap(@NotNull MutableSlicedMap delegate) { + this.delegate = delegate; + } + + private SliceWithStackTrace wrapSlice(ReadOnlySlice slice) { + SliceWithStackTrace translated = sliceTranslationMap.get(slice); + if (translated == null) { + translated = new SliceWithStackTrace(slice); + sliceTranslationMap.put(slice, translated); + } + //noinspection unchecked + return (SliceWithStackTrace) translated; + } + + @Override + public V get(ReadOnlySlice slice, K key) { + return delegate.get(wrapSlice(slice), key).value; + } + + @Override + public Collection getKeys(WritableSlice slice) { + return delegate.getKeys(wrapSlice(slice)); + } + + @Override + public Iterator, ?>> iterator() { + Map, Object> map = Maps.newHashMap(); + for (Map.Entry, ?> entry : delegate) { + map.put(entry.getKey(), ((WithStackTrace) entry.getValue()).value); + } + //noinspection unchecked + return (Iterator) map.entrySet().iterator(); + } + + @Override + public void put(WritableSlice slice, K key, V value) { + delegate.put(wrapSlice(slice), key, new WithStackTrace(value)); + } + + @Override + public V remove(RemovableSlice slice, K key) { + return delegate.remove(wrapSlice(slice), key).value; + } + + @Override + public void clear() { + delegate.clear(); + } + + @Override + @NotNull + @TestOnly + public ImmutableMap getSliceContents(@NotNull ReadOnlySlice slice) { + return delegate.getSliceContents(slice); + } + + private static class WithStackTrace { + private final V value; + private final StackTraceElement[] stackTrace; + + private WithStackTrace(V value) { + this.value = value; + this.stackTrace = Thread.currentThread().getStackTrace(); + } + + private Appendable printStackTrace(Appendable appendable) { + Printer s = new Printer(appendable); + s.println(value); + s.println("Written at "); + StackTraceElement[] trace = stackTrace; + for (StackTraceElement aTrace : trace) { + s.println("\tat " + aTrace); + } + s.println("---------"); + return appendable; + } + + @Override + public String toString() { + return printStackTrace(new StringBuilder()).toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + WithStackTrace other = (WithStackTrace) o; + + if (value != null ? !value.equals(other.value) : other.value != null) return false; + + return true; + } + + @Override + public int hashCode() { + return value != null ? value.hashCode() : 0; + } + } + + public class SliceWithStackTrace implements RemovableSlice> { + + private final ReadOnlySlice delegate; + + private SliceWithStackTrace(@NotNull ReadOnlySlice delegate) { + this.delegate = delegate; + } + + // Methods of ReadOnlySlice + + @Override + public SlicedMapKey> makeKey(K key) { + //noinspection unchecked + return (SlicedMapKey) delegate.makeKey(key); + } + + @Override + public WithStackTrace computeValue(SlicedMap map, K key, WithStackTrace value, boolean valueNotFound) { + return new WithStackTrace(delegate.computeValue(map, key, value == null ? null : value.value, valueNotFound)); + } + + @Override + public ReadOnlySlice> makeRawValueVersion() { + return wrapSlice(delegate.makeRawValueVersion()); + } + + // Methods of WritableSlice + + private WritableSlice getWritableDelegate() { + return (WritableSlice) delegate; + } + + @Override + public boolean isCollective() { + return getWritableDelegate().isCollective(); + } + + @Override + public RewritePolicy getRewritePolicy() { + return getWritableDelegate().getRewritePolicy(); + } + + @Override + public void afterPut(MutableSlicedMap map, K key, WithStackTrace value) { + getWritableDelegate().afterPut(map, key, value.value); + } + + @Override + public boolean check(K key, WithStackTrace value) { + return getWritableDelegate().check(key, value.value); + } + } +}