// ex: se sts=4 sw=4 expandtab: /** * Yeti special library utility. * * Copyright (c) 2008,2009 Madis Janson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package yeti.lang; import java.io.*; import yeti.renamed.asmx.*; class LListAdapter extends ClassVisitor implements Opcodes { LListAdapter(ClassVisitor cv) { super(ASM5, cv); } public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { return "length".equals(name) || "forEach".equals(name) || "fold".equals(name) || "smap".equals(name) || "copy".equals(name) || "take".equals(name) ? null : cv.visitMethod(access, name, desc, signature, exceptions); } public void visitEnd() { MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "length", "()J", null, null); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 0); Label retry = new Label(), end = new Label(); mv.visitInsn(DUP); mv.visitJumpInsn(IFNULL, end); mv.visitLabel(retry); mv.visitIincInsn(0, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/AIter", "next", "()Lyeti/lang/AIter;", false); mv.visitInsn(DUP); mv.visitJumpInsn(IFNONNULL, retry); mv.visitLabel(end); mv.visitVarInsn(ILOAD, 0); mv.visitInsn(I2L); mv.visitInsn(LRETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cv.visitMethod(ACC_PUBLIC, "forEach", "(Ljava/lang/Object;)V", null, null); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, "yeti/lang/Fun"); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 0); mv.visitInsn(DUP); mv.visitJumpInsn(IFNULL, end = new Label()); mv.visitLabel(retry = new Label()); mv.visitInsn(DUP2); // fun iter fun iter mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/AIter", "first", "()Ljava/lang/Object;", false); mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/Fun", "apply", "(Ljava/lang/Object;)Ljava/lang/Object;", false); mv.visitInsn(POP); mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/AIter", "next", "()Lyeti/lang/AIter;", false); mv.visitInsn(DUP); mv.visitJumpInsn(IFNONNULL, retry); mv.visitLabel(end); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cv.visitMethod(ACC_PUBLIC, "fold", "(Lyeti/lang/Fun;Ljava/lang/Object;)Ljava/lang/Object;", null, null); mv.visitVarInsn(ALOAD, 2); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 2); mv.visitVarInsn(ALOAD, 0); mv.visitJumpInsn(IFNULL, end = new Label()); mv.visitLabel(retry = new Label()); mv.visitVarInsn(ALOAD, 1); mv.visitInsn(SWAP); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/AIter", "first", "()Ljava/lang/Object;", false); mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/Fun", "apply", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/AIter", "next", "()Lyeti/lang/AIter;", false); mv.visitInsn(DUP); mv.visitVarInsn(ASTORE, 0); mv.visitJumpInsn(IFNONNULL, retry); mv.visitLabel(end); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cv.visitMethod(ACC_PUBLIC, "smap", "(Lyeti/lang/Fun;)Lyeti/lang/AList;", null, null); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, "yeti/lang/Fun"); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(DUP); mv.visitJumpInsn(IFNULL, end = new Label()); mv.visitTypeInsn(NEW, "yeti/lang/MList"); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, "yeti/lang/MList", "<init>", "()V", false); mv.visitVarInsn(ASTORE, 0); mv.visitLabel(retry = new Label()); mv.visitInsn(DUP2); // fun iter fun iter mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/AIter", "first", "()Ljava/lang/Object;", false); // i -> v mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/Fun", "apply", // f v -> v' "(Ljava/lang/Object;)Ljava/lang/Object;", false); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(SWAP); mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/MList", "add", "(Ljava/lang/Object;)V", false); // l v' -> () mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/AIter", "next", "()Lyeti/lang/AIter;", false); // i -> i' mv.visitInsn(DUP); mv.visitJumpInsn(IFNONNULL, retry); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(ARETURN); mv.visitLabel(end); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cv.visitMethod(ACC_PUBLIC, "copy", "()Ljava/lang/Object;", null, null); mv.visitTypeInsn(NEW, "yeti/lang/MList"); mv.visitInsn(DUP); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 0); mv.visitMethodInsn(INVOKESPECIAL, "yeti/lang/MList", "<init>", "(Lyeti/lang/AIter;)V", false); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cv.visitMethod(ACC_PUBLIC, "take", "(II)Lyeti/lang/AList;", null, null); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 0); Label drop = new Label(); mv.visitLabel(retry = new Label()); mv.visitVarInsn(ILOAD, 1); mv.visitJumpInsn(IFLE, drop); mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/AList", "rest", "()Lyeti/lang/AList;", false); // i -> i' mv.visitIincInsn(1, -1); mv.visitInsn(DUP); mv.visitJumpInsn(IFNONNULL, retry); mv.visitInsn(ARETURN); mv.visitLabel(drop); mv.visitVarInsn(ILOAD, 2); mv.visitJumpInsn(IFLT, end = new Label()); mv.visitVarInsn(ILOAD, 2); mv.visitMethodInsn(INVOKESTATIC, "yeti/lang/TakeList", "take", "(Lyeti/lang/AIter;I)Lyeti/lang/AList;", false); mv.visitLabel(end); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); cv.visitEnd(); } } public class SpecialLib implements Opcodes { ClassWriter cw; String prefix; void transformLList() throws Exception { InputStream in = new FileInputStream(prefix + "yeti/lang/LList.class"); cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); LListAdapter la = new LListAdapter(cw); new ClassReader(in).accept(la, 0); in.close(); storeClass("yeti/lang/LList.class"); } void storeClass(String name) throws Exception { cw.visitEnd(); name = prefix + name; int p = name.lastIndexOf('/'); new java.io.File(name.substring(0, p)).mkdirs(); FileOutputStream os = new FileOutputStream(name); os.write(cw.toByteArray()); os.close(); } void fun2_() throws Exception { cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_4, ACC_SUPER, "yeti/lang/Fun2_", null, "yeti/lang/Fun", null); cw.visitField(ACC_PRIVATE | ACC_FINAL, "fun", "Lyeti/lang/Fun2;", null, null).visitEnd(); cw.visitField(ACC_PRIVATE | ACC_FINAL, "arg", "Ljava/lang/Object;", null, null).visitEnd(); MethodVisitor mv = cw.visitMethod(0, "<init>", "(Lyeti/lang/Fun2;Ljava/lang/Object;)V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "yeti/lang/Fun", "<init>", "()V", false); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(PUTFIELD, "yeti/lang/Fun2_", "fun", "Lyeti/lang/Fun2;"); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 2); mv.visitFieldInsn(PUTFIELD, "yeti/lang/Fun2_", "arg", "Ljava/lang/Object;"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "apply", "(Ljava/lang/Object;)Ljava/lang/Object;", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "yeti/lang/Fun2_", "fun", "Lyeti/lang/Fun2;"); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 0); mv.visitFieldInsn(GETFIELD, "yeti/lang/Fun2_", "arg", "Ljava/lang/Object;"); mv.visitVarInsn(ALOAD, 1); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/Fun2", "apply", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); storeClass("yeti/lang/Fun2_.class"); } void compose() throws Exception { cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_4, ACC_PUBLIC | ACC_FINAL | ACC_SUPER, "yeti/lang/Compose", null, "yeti/lang/Fun", null); cw.visitField(ACC_FINAL | ACC_PRIVATE, "f", "Lyeti/lang/Fun;", null, null).visitEnd(); cw.visitField(ACC_FINAL | ACC_PRIVATE, "g", "Lyeti/lang/Fun;", null, null).visitEnd(); MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "yeti/lang/Fun", "<init>", "()V", false); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, "yeti/lang/Fun"); mv.visitFieldInsn(PUTFIELD, "yeti/lang/Compose", "f", "Lyeti/lang/Fun;"); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 2); mv.visitTypeInsn(CHECKCAST, "yeti/lang/Fun"); mv.visitFieldInsn(PUTFIELD, "yeti/lang/Compose", "g", "Lyeti/lang/Fun;"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "apply", "(Ljava/lang/Object;)Ljava/lang/Object;", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "yeti/lang/Compose", "f", "Lyeti/lang/Fun;"); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "yeti/lang/Compose", "g", "Lyeti/lang/Fun;"); mv.visitVarInsn(ALOAD, 1); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/Fun", "apply", "(Ljava/lang/Object;)Ljava/lang/Object;", false); mv.visitMethodInsn(INVOKEVIRTUAL, "yeti/lang/Fun", "apply", "(Ljava/lang/Object;)Ljava/lang/Object;", false); mv.visitInsn(ARETURN); mv.visitMaxs(0, 0); mv.visitEnd(); storeClass("yeti/lang/Compose.class"); } void unsafe() throws Exception { cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_4, ACC_SUPER, "yeti/lang/Unsafe", null, "java/lang/Object", null); MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "unsafeThrow", "(Ljava/lang/Throwable;)V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitInsn(ATHROW); mv.visitMaxs(0, 0); mv.visitEnd(); storeClass("yeti/lang/Unsafe.class"); } public static void main(String[] args) throws Exception { SpecialLib l = new SpecialLib(); l.prefix = args[1] + '/'; if (args[0].equals("tr")) { l.transformLList(); } else if (args[0].equals("pre")) { l.fun2_(); l.compose(); l.unsafe(); } else { System.err.println(args[0] + ": WTF?"); } } }