rt/vm8/src/test/java/org/apidesign/bck2brwsr/vm8/InvokeDynamicTest.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sun, 17 Aug 2014 08:27:45 +0200
branchjdk8
changeset 1672 1efb2645c7aa
parent 1668 ec0ee77173e9
permissions -rw-r--r--
Executing first lambda expression on bck2brwsr thanks to preprocessing of retrolamda
jaroslav@1648
     1
/**
jaroslav@1648
     2
 * Back 2 Browser Bytecode Translator
jaroslav@1648
     3
 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
jaroslav@1648
     4
 *
jaroslav@1648
     5
 * This program is free software: you can redistribute it and/or modify
jaroslav@1648
     6
 * it under the terms of the GNU General Public License as published by
jaroslav@1648
     7
 * the Free Software Foundation, version 2 of the License.
jaroslav@1648
     8
 *
jaroslav@1648
     9
 * This program is distributed in the hope that it will be useful,
jaroslav@1648
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
jaroslav@1648
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
jaroslav@1648
    12
 * GNU General Public License for more details.
jaroslav@1648
    13
 *
jaroslav@1648
    14
 * You should have received a copy of the GNU General Public License
jaroslav@1648
    15
 * along with this program. Look for COPYING file in the top folder.
jaroslav@1648
    16
 * If not, see http://opensource.org/licenses/GPL-2.0.
jaroslav@1648
    17
 */
jaroslav@1654
    18
package org.apidesign.bck2brwsr.vm8;
jaroslav@1648
    19
jaroslav@1648
    20
import java.io.ByteArrayInputStream;
jaroslav@1648
    21
import java.io.IOException;
jaroslav@1648
    22
import java.io.InputStream;
jaroslav@1648
    23
import java.lang.invoke.CallSite;
jaroslav@1648
    24
import java.lang.invoke.MethodHandles;
jaroslav@1648
    25
import java.lang.invoke.MethodType;
jaroslav@1648
    26
import java.lang.reflect.Method;
jaroslav@1648
    27
import java.net.URL;
jaroslav@1648
    28
import java.util.Enumeration;
jaroslav@1648
    29
import org.apidesign.vm4brwsr.Bck2Brwsr;
jaroslav@1648
    30
import org.objectweb.asm.ClassReader;
jaroslav@1648
    31
import org.objectweb.asm.ClassVisitor;
jaroslav@1648
    32
import org.objectweb.asm.ClassWriter;
jaroslav@1648
    33
import org.objectweb.asm.Handle;
jaroslav@1648
    34
import org.objectweb.asm.MethodVisitor;
jaroslav@1648
    35
import org.objectweb.asm.Opcodes;
jaroslav@1648
    36
import static org.objectweb.asm.Opcodes.ASM4;
jaroslav@1648
    37
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
jaroslav@1648
    38
import static org.testng.Assert.*;
jaroslav@1648
    39
import org.testng.annotations.AfterClass;
jaroslav@1648
    40
import org.testng.annotations.BeforeClass;
jaroslav@1648
    41
import org.testng.annotations.Test;
jaroslav@1648
    42
jaroslav@1648
    43
/**
jaroslav@1648
    44
 *
jaroslav@1648
    45
 * @author Jaroslav Tulach <jtulach@netbeans.org>
jaroslav@1648
    46
 */
jaroslav@1648
    47
public class InvokeDynamicTest {
jaroslav@1648
    48
    private static Class<?> invokeDynamicClass;
jaroslav@1648
    49
    private static byte[] invokeDynamicBytes;
jaroslav@1648
    50
    private static TestVM code;
jaroslav@1648
    51
    
jaroslav@1648
    52
    @Test public void simpleDynamicInJava() throws Exception {
jaroslav@1648
    53
        Method m = invokeDynamicClass.getMethod("dynamicSay");
jaroslav@1648
    54
        Object ret = m.invoke(m);
jaroslav@1648
    55
        assertEquals(ret, "Hello from Dynamic!");
jaroslav@1648
    56
    }
jaroslav@1672
    57
jaroslav@1672
    58
    /* Well, supporting general invokeDynamic is 
jaroslav@1672
    59
    huge hassle, so giving up. More at
jaroslav@1672
    60
    http://wiki.apidesign.org/wiki/InvokeDynamic
jaroslav@1648
    61
    
jaroslav@1648
    62
    @Test public void simpleDynamicInJS() throws Exception {
jaroslav@1668
    63
        code().assertExec(
jaroslav@1648
    64
            "Invoke dynamic can return a value", InvokeDynamic.class,
jaroslav@1656
    65
            "dynamicSay__Ljava_lang_String_2",
jaroslav@1648
    66
            "Hello from Dynamic!"
jaroslav@1648
    67
        );
jaroslav@1648
    68
    }
jaroslav@1672
    69
    */
jaroslav@1648
    70
    
jaroslav@1668
    71
    private TestVM code() throws Exception {
jaroslav@1668
    72
        if (code == null) {
jaroslav@1668
    73
            final EmulResWithInvDyn emul = new EmulResWithInvDyn();
jaroslav@1668
    74
            code = TestVM.compileClass(
jaroslav@1668
    75
                    null, null, emul,
jaroslav@1668
    76
                    InvokeDynamic.class.getName().replace('.', '/')
jaroslav@1668
    77
            );
jaroslav@1668
    78
jaroslav@1668
    79
            assertTrue(emul.loaded, "InvokeDynamic class should be processed!");
jaroslav@1668
    80
        }
jaroslav@1668
    81
        return code;
jaroslav@1668
    82
    }
jaroslav@1648
    83
jaroslav@1648
    84
    @AfterClass
jaroslav@1648
    85
    public static void releaseTheCode() {
jaroslav@1648
    86
        code = null;
jaroslav@1648
    87
    }
jaroslav@1648
    88
jaroslav@1648
    89
    //
jaroslav@1648
    90
    // the following code is inspired by 
jaroslav@1648
    91
    // https://code.google.com/p/indy-maven-plugin/
jaroslav@1648
    92
    // which I don't want to use, as it is not in a public repository
jaroslav@1648
    93
    //
jaroslav@1648
    94
    @BeforeClass 
jaroslav@1648
    95
    public static void prepareClass() throws Exception {
jaroslav@1648
    96
        InputStream is = InvokeDynamic.class.getResourceAsStream("InvokeDynamic.class");
jaroslav@1648
    97
        assertNotNull(is, "Class found");
jaroslav@1648
    98
        
jaroslav@1654
    99
        ClassReader reader = new ClassReader(is) {
jaroslav@1654
   100
            @Override
jaroslav@1654
   101
            public short readShort(int index) {
jaroslav@1654
   102
                if (index == 6) {
jaroslav@1654
   103
                    return Opcodes.V1_7;
jaroslav@1654
   104
                }
jaroslav@1654
   105
                return super.readShort(index);
jaroslav@1654
   106
            }
jaroslav@1654
   107
        };
jaroslav@1648
   108
        ClassWriter writer = new ClassWriter(reader, 0);
jaroslav@1648
   109
jaroslav@1648
   110
        reader.accept(
jaroslav@1648
   111
                new ClassVisitor(ASM4, writer) {
jaroslav@1648
   112
                    @Override
jaroslav@1648
   113
                    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions
jaroslav@1648
   114
                    ) {
jaroslav@1648
   115
                        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
jaroslav@1648
   116
                        return new InvokeDynamicProcessor(mv);
jaroslav@1648
   117
                    }
jaroslav@1648
   118
                },
jaroslav@1648
   119
                0);
jaroslav@1648
   120
        is.close();
jaroslav@1648
   121
        invokeDynamicBytes = writer.toByteArray();
jaroslav@1656
   122
        final boolean[] loaded = { false };
jaroslav@1648
   123
        ClassLoader l = new ClassLoader() {
jaroslav@1648
   124
            @Override
jaroslav@1648
   125
            public Class<?> loadClass(String name) throws ClassNotFoundException {
jaroslav@1648
   126
                if (name.equals(InvokeDynamic.class.getName())) {
jaroslav@1656
   127
                    loaded[0] = true;
jaroslav@1648
   128
                    return defineClass(name, invokeDynamicBytes, 0, invokeDynamicBytes.length);
jaroslav@1648
   129
                }
jaroslav@1648
   130
                return super.loadClass(name);
jaroslav@1648
   131
            }
jaroslav@1648
   132
        };
jaroslav@1648
   133
        invokeDynamicClass = l.loadClass(InvokeDynamic.class.getName());
jaroslav@1656
   134
        assertTrue(loaded[0], "InvokeDynamic class should be loaded!");
jaroslav@1648
   135
    }
jaroslav@1648
   136
    
jaroslav@1648
   137
    
jaroslav@1648
   138
    private static class InvokeDynamicProcessor extends MethodVisitor {
jaroslav@1648
   139
        InvokeDynamicProcessor(MethodVisitor mv) {
jaroslav@1648
   140
            super(ASM4, mv);
jaroslav@1648
   141
        }
jaroslav@1648
   142
jaroslav@1648
   143
        @Override
jaroslav@1648
   144
        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
jaroslav@1648
   145
            if (opcode == INVOKESTATIC) {
jaroslav@1648
   146
                if (name.startsWith("TEST_dynamic_")) {
jaroslav@1648
   147
                    final String shortName = name.substring(13);
jaroslav@1648
   148
                    Handle mh = new Handle(
jaroslav@1648
   149
                        Opcodes.H_INVOKESTATIC, owner, shortName,
jaroslav@1648
   150
                        MethodType.methodType(
jaroslav@1648
   151
                            CallSite.class,
jaroslav@1648
   152
                            MethodHandles.Lookup.class,
jaroslav@1648
   153
                            String.class, 
jaroslav@1648
   154
                            MethodType.class
jaroslav@1648
   155
                        ).toMethodDescriptorString()
jaroslav@1648
   156
                    );
jaroslav@1648
   157
                    super.visitInvokeDynamicInsn(shortName, desc, mh);
jaroslav@1648
   158
                    return;
jaroslav@1648
   159
                }
jaroslav@1648
   160
            }
jaroslav@1648
   161
            super.visitMethodInsn(opcode, owner, name, desc);
jaroslav@1648
   162
        }
jaroslav@1648
   163
    }
jaroslav@1648
   164
    
jaroslav@1656
   165
    private static class EmulResWithInvDyn implements Bck2Brwsr.Resources {
jaroslav@1656
   166
        boolean loaded;
jaroslav@1656
   167
        
jaroslav@1648
   168
        @Override
jaroslav@1648
   169
        public InputStream get(String name) throws IOException {
jaroslav@1656
   170
            if ("org/apidesign/bck2brwsr/vm8/InvokeDynamic.class".equals(name)) {
jaroslav@1656
   171
                loaded = true;
jaroslav@1648
   172
                return new ByteArrayInputStream(invokeDynamicBytes);
jaroslav@1648
   173
            }
jaroslav@1648
   174
            Enumeration<URL> en = InvokeDynamicTest.class.getClassLoader().getResources(name);
jaroslav@1648
   175
            URL u = null;
jaroslav@1648
   176
            while (en.hasMoreElements()) {
jaroslav@1648
   177
                u = en.nextElement();
jaroslav@1648
   178
            }
jaroslav@1648
   179
            if (u == null) {
jaroslav@1648
   180
                throw new IOException("Can't find " + name);
jaroslav@1648
   181
            }
jaroslav@1648
   182
            if (u.toExternalForm().contains("rt.jar!")) {
jaroslav@1648
   183
                throw new IOException("No emulation for " + u);
jaroslav@1648
   184
            }
jaroslav@1648
   185
            return u.openStream();
jaroslav@1648
   186
        }
jaroslav@1648
   187
    }
jaroslav@1648
   188
    
jaroslav@1648
   189
}