Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70f97ba5 authored by Diego Perez's avatar Diego Perez
Browse files

Fix StackMap renaming in Java 8

With the move to Java 8 of layoutlib, we now need to make sure that the
method stackmaps are kept up to date or the class verification step will
fail. Up until now, we were ignoring them but this caused TestDelegates
to start failing.
This updates the code to make sure that when we modify a class name, we
also update the stackmap in the calls.

Change-Id: Iddbde7454f065ddb8da5bb1ab499ec0616f9b4fe
parent f19e7822
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
@@ -16,9 +16,11 @@

package com.android.tools.layoutlib.create;

import java.util.Arrays;
import java.util.HashMap;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;

public class RefactorClassAdapter extends AbstractClassAdapter {

@@ -29,6 +31,14 @@ public class RefactorClassAdapter extends AbstractClassAdapter {
        mRefactorClasses = refactorClasses;
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature,
            String[] exceptions) {
        MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);

        return new RefactorStackMapAdapter(mw);
    }

    @Override
    protected String renameInternalType(String oldClassName) {
        if (oldClassName != null) {
@@ -46,4 +56,49 @@ public class RefactorClassAdapter extends AbstractClassAdapter {
        }
        return oldClassName;
    }

    /**
     * A method visitor that renames all references from an old class name to a new class name in
     * the stackmap of the method.
     */
    private class RefactorStackMapAdapter extends MethodVisitor {

        private RefactorStackMapAdapter(MethodVisitor mv) {
            super(Main.ASM_VERSION, mv);
        }


        private Object[] renameFrame(Object[] elements) {
            if (elements == null) {
                return null;
            }

            // The input array cannot be modified. We only copy the source array on write
            boolean copied = false;
            for (int i = 0; i < elements.length; i++) {
                if (!(elements[i] instanceof String)) {
                    continue;
                }

                if (!copied) {
                    elements = Arrays.copyOf(elements, elements.length);
                    copied = true;
                }

                String type = (String)elements[i];
                if (type.indexOf(';') > 0) {
                    elements[i] = renameTypeDesc(type);
                } else {
                    elements[i] = renameInternalType(type);
                }
            }

            return elements;
        }

        @Override
        public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
            super.visitFrame(type, nLocal, renameFrame(local), nStack, renameFrame(stack));
        }
    }
}