rt/emul/compact/src/test/java/org/apidesign/vm4brwsr/dynamic/InvokeDynamicTest.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 09 Aug 2014 12:15:18 +0200
branchjdk8
changeset 1648 905b2a470def
permissions -rw-r--r--
Can these tests be placed in compact profile
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@1648
    18
package org.apidesign.vm4brwsr.dynamic;
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@1648
    57
    
jaroslav@1648
    58
    @Test public void simpleDynamicInJS() throws Exception {
jaroslav@1648
    59
        code.assertExec(
jaroslav@1648
    60
            "Invoke dynamic can return a value", InvokeDynamic.class,
jaroslav@1648
    61
            "dynamic__Ljava_lang_String_2",
jaroslav@1648
    62
            "Hello from Dynamic!"
jaroslav@1648
    63
        );
jaroslav@1648
    64
    }
jaroslav@1648
    65
    
jaroslav@1648
    66
jaroslav@1648
    67
    @AfterClass
jaroslav@1648
    68
    public static void releaseTheCode() {
jaroslav@1648
    69
        code = null;
jaroslav@1648
    70
    }
jaroslav@1648
    71
jaroslav@1648
    72
    //
jaroslav@1648
    73
    // the following code is inspired by 
jaroslav@1648
    74
    // https://code.google.com/p/indy-maven-plugin/
jaroslav@1648
    75
    // which I don't want to use, as it is not in a public repository
jaroslav@1648
    76
    //
jaroslav@1648
    77
    @BeforeClass 
jaroslav@1648
    78
    public static void prepareClass() throws Exception {
jaroslav@1648
    79
        InputStream is = InvokeDynamic.class.getResourceAsStream("InvokeDynamic.class");
jaroslav@1648
    80
        assertNotNull(is, "Class found");
jaroslav@1648
    81
        
jaroslav@1648
    82
        ClassReader reader = new ClassReader(is);
jaroslav@1648
    83
        ClassWriter writer = new ClassWriter(reader, 0);
jaroslav@1648
    84
jaroslav@1648
    85
        reader.accept(
jaroslav@1648
    86
                new ClassVisitor(ASM4, writer) {
jaroslav@1648
    87
                    @Override
jaroslav@1648
    88
                    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions
jaroslav@1648
    89
                    ) {
jaroslav@1648
    90
                        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
jaroslav@1648
    91
                        return new InvokeDynamicProcessor(mv);
jaroslav@1648
    92
                    }
jaroslav@1648
    93
                },
jaroslav@1648
    94
                0);
jaroslav@1648
    95
        is.close();
jaroslav@1648
    96
        invokeDynamicBytes = writer.toByteArray();
jaroslav@1648
    97
        ClassLoader l = new ClassLoader() {
jaroslav@1648
    98
            @Override
jaroslav@1648
    99
            public Class<?> loadClass(String name) throws ClassNotFoundException {
jaroslav@1648
   100
                if (name.equals(InvokeDynamic.class.getName())) {
jaroslav@1648
   101
                    return defineClass(name, invokeDynamicBytes, 0, invokeDynamicBytes.length);
jaroslav@1648
   102
                }
jaroslav@1648
   103
                return super.loadClass(name);
jaroslav@1648
   104
            }
jaroslav@1648
   105
        };
jaroslav@1648
   106
        invokeDynamicClass = l.loadClass(InvokeDynamic.class.getName());
jaroslav@1648
   107
        
jaroslav@1648
   108
        code = TestVM.compileClass(
jaroslav@1648
   109
            null, null, new EmulationResourcesWithException(),
jaroslav@1648
   110
            InvokeDynamic.class.getName().replace('.', '/')
jaroslav@1648
   111
        );
jaroslav@1648
   112
    }
jaroslav@1648
   113
    
jaroslav@1648
   114
    
jaroslav@1648
   115
    private static class InvokeDynamicProcessor extends MethodVisitor {
jaroslav@1648
   116
        InvokeDynamicProcessor(MethodVisitor mv) {
jaroslav@1648
   117
            super(ASM4, mv);
jaroslav@1648
   118
        }
jaroslav@1648
   119
jaroslav@1648
   120
        @Override
jaroslav@1648
   121
        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
jaroslav@1648
   122
            if (opcode == INVOKESTATIC) {
jaroslav@1648
   123
                if (name.startsWith("TEST_dynamic_")) {
jaroslav@1648
   124
                    final String shortName = name.substring(13);
jaroslav@1648
   125
                    Handle mh = new Handle(
jaroslav@1648
   126
                        Opcodes.H_INVOKESTATIC, owner, shortName,
jaroslav@1648
   127
                        MethodType.methodType(
jaroslav@1648
   128
                            CallSite.class,
jaroslav@1648
   129
                            MethodHandles.Lookup.class,
jaroslav@1648
   130
                            String.class, 
jaroslav@1648
   131
                            MethodType.class
jaroslav@1648
   132
                        ).toMethodDescriptorString()
jaroslav@1648
   133
                    );
jaroslav@1648
   134
                    super.visitInvokeDynamicInsn(shortName, desc, mh);
jaroslav@1648
   135
                    return;
jaroslav@1648
   136
                }
jaroslav@1648
   137
            }
jaroslav@1648
   138
            super.visitMethodInsn(opcode, owner, name, desc);
jaroslav@1648
   139
        }
jaroslav@1648
   140
    }
jaroslav@1648
   141
    
jaroslav@1648
   142
    private static class EmulationResourcesWithException implements Bck2Brwsr.Resources {
jaroslav@1648
   143
        @Override
jaroslav@1648
   144
        public InputStream get(String name) throws IOException {
jaroslav@1648
   145
            if ("org/apidesign/vm4brwsr/InvokeDynamic.class".equals(name)) {
jaroslav@1648
   146
                return new ByteArrayInputStream(invokeDynamicBytes);
jaroslav@1648
   147
            }
jaroslav@1648
   148
            if ("java/net/URI.class".equals(name)) {
jaroslav@1648
   149
                // skip
jaroslav@1648
   150
                return null;
jaroslav@1648
   151
            }
jaroslav@1648
   152
            if ("java/net/URLConnection.class".equals(name)) {
jaroslav@1648
   153
                // skip
jaroslav@1648
   154
                return null;
jaroslav@1648
   155
            }
jaroslav@1648
   156
            if ("java/lang/System.class".equals(name)) {
jaroslav@1648
   157
                // skip
jaroslav@1648
   158
                return null;
jaroslav@1648
   159
            }
jaroslav@1648
   160
            Enumeration<URL> en = InvokeDynamicTest.class.getClassLoader().getResources(name);
jaroslav@1648
   161
            URL u = null;
jaroslav@1648
   162
            while (en.hasMoreElements()) {
jaroslav@1648
   163
                u = en.nextElement();
jaroslav@1648
   164
            }
jaroslav@1648
   165
            if (u == null) {
jaroslav@1648
   166
                throw new IOException("Can't find " + name);
jaroslav@1648
   167
            }
jaroslav@1648
   168
            if (u.toExternalForm().contains("rt.jar!")) {
jaroslav@1648
   169
                throw new IOException("No emulation for " + u);
jaroslav@1648
   170
            }
jaroslav@1648
   171
            return u.openStream();
jaroslav@1648
   172
        }
jaroslav@1648
   173
    }
jaroslav@1648
   174
    
jaroslav@1648
   175
}