From 1330f79f95fd14b53c393402fbcbf7b7bbdcbc60 Mon Sep 17 00:00:00 2001 From: Deepanshu Gupta Date: Wed, 7 Jan 2015 16:25:59 -0800 Subject: Replace java.util.LinkedHashMap.eldest() Provide an alternate implementation for the above method and replace the calls to it, since the method is not available on host VM. Change-Id: I329d86b457d1859b137da8fb2790ddd7f8efa788 --- .../android/tools/layoutlib/create/CreateInfo.java | 2 ++ .../create/ReplaceMethodCallsAdapter.java | 32 +++++++++++++++++-- .../layoutlib/java/LinkedHashMap_Delegate.java | 36 ++++++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 tools/layoutlib/create/src/com/android/tools/layoutlib/java/LinkedHashMap_Delegate.java (limited to 'tools/layoutlib/create/src/com/android') diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 7faaed9..98acd2f 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -20,6 +20,7 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate; import com.android.tools.layoutlib.java.AutoCloseable; import com.android.tools.layoutlib.java.Charsets; import com.android.tools.layoutlib.java.IntegralToString; +import com.android.tools.layoutlib.java.LinkedHashMap_Delegate; import com.android.tools.layoutlib.java.Objects; import com.android.tools.layoutlib.java.System_Delegate; import com.android.tools.layoutlib.java.UnsafeByteSequence; @@ -133,6 +134,7 @@ public final class CreateInfo implements ICreateInfo { UnsafeByteSequence.class, Charsets.class, System_Delegate.class, + LinkedHashMap_Delegate.class, }; /** diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java index 1e2623f..384d8ca 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java @@ -16,6 +16,7 @@ package com.android.tools.layoutlib.create; +import com.android.tools.layoutlib.java.LinkedHashMap_Delegate; import com.android.tools.layoutlib.java.System_Delegate; import org.objectweb.asm.ClassVisitor; @@ -26,8 +27,10 @@ import org.objectweb.asm.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; /** @@ -44,7 +47,7 @@ public class ReplaceMethodCallsAdapter extends ClassVisitor { "([CI[CII)V", "([BI[BII)V", "([SI[SII)V", "([II[III)V", "([JI[JII)V", "([FI[FII)V", "([DI[DII)V", "([ZI[ZII)V")); - private static final List METHOD_REPLACERS = new ArrayList(2); + private static final List METHOD_REPLACERS = new ArrayList(5); private static final String ANDROID_LOCALE_CLASS = "com/android/layoutlib/bridge/android/AndroidLocale"; @@ -74,7 +77,8 @@ public class ReplaceMethodCallsAdapter extends ClassVisitor { // Case 2: java.util.Locale.toLanguageTag() and java.util.Locale.getScript() METHOD_REPLACERS.add(new MethodReplacer() { - String LOCALE_TO_STRING = Type.getMethodDescriptor(STRING, Type.getType(Locale.class)); + private final String LOCALE_TO_STRING = + Type.getMethodDescriptor(STRING, Type.getType(Locale.class)); @Override public boolean isNeeded(String owner, String name, String desc) { @@ -129,6 +133,30 @@ public class ReplaceMethodCallsAdapter extends ClassVisitor { mi.owner = Type.getInternalName(System_Delegate.class); } }); + + // Case 5: java.util.LinkedHashMap.eldest() + METHOD_REPLACERS.add(new MethodReplacer() { + + private final String VOID_TO_MAP_ENTRY = + Type.getMethodDescriptor(Type.getType(Map.Entry.class)); + private final String LINKED_HASH_MAP = Type.getInternalName(LinkedHashMap.class); + + @Override + public boolean isNeeded(String owner, String name, String desc) { + return LINKED_HASH_MAP.equals(owner) && + "eldest".equals(name) && + VOID_TO_MAP_ENTRY.equals(desc); + } + + @Override + public void replace(MethodInformation mi) { + assert isNeeded(mi.owner, mi.name, mi.desc); + mi.opcode = Opcodes.INVOKESTATIC; + mi.owner = Type.getInternalName(LinkedHashMap_Delegate.class); + mi.desc = Type.getMethodDescriptor( + Type.getType(Map.Entry.class), Type.getType(LinkedHashMap.class)); + } + }); } public static boolean isReplacementNeeded(String owner, String name, String desc) { diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/java/LinkedHashMap_Delegate.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/LinkedHashMap_Delegate.java new file mode 100644 index 0000000..59cc75f --- /dev/null +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/LinkedHashMap_Delegate.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * 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 com.android.tools.layoutlib.java; + +import com.android.tools.layoutlib.create.ReplaceMethodCallsAdapter; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Provides alternate implementation to java.util.LinkedHashMap#eldest(), which is present as a + * non-public method in the Android VM, but not present on the host VM. This is injected in the + * layoutlib using {@link ReplaceMethodCallsAdapter}. + */ +public class LinkedHashMap_Delegate { + public static Map.Entry eldest(LinkedHashMap map) { + Iterator> iterator = map.entrySet().iterator(); + return iterator.hasNext() ? iterator.next() : null; + } +} -- cgit v1.1