From e07d8c6b1419753916f9030435b7e7c03d962b36 Mon Sep 17 00:00:00 2001 From: "norris%netscape.com" Date: Mon, 26 Apr 1999 20:41:57 +0000 Subject: [PATCH] Make JavaAdapter work on mozilla-only. --- js/rhino/org/mozilla/classfile/ByteCode.java | 1044 +++++++++++++ .../mozilla/classfile/ClassFileWriter.java | 1308 +++++++++++++++++ js/rhino/org/mozilla/javascript/Context.java | 6 +- .../org/mozilla/javascript/Interpreter.java | 14 +- .../org/mozilla/javascript/JavaAdapter.java | 492 +++++++ .../org/mozilla/javascript/LocalVariable.java | 22 + .../org/mozilla/javascript/VariableTable.java | 2 +- .../src/org/mozilla/classfile/ByteCode.java | 1044 +++++++++++++ .../mozilla/classfile/ClassFileWriter.java | 1308 +++++++++++++++++ .../src/org/mozilla/javascript/Context.java | 6 +- .../org/mozilla/javascript/Interpreter.java | 14 +- .../org/mozilla/javascript/JavaAdapter.java | 492 +++++++ .../org/mozilla/javascript/LocalVariable.java | 22 + .../org/mozilla/javascript/VariableTable.java | 2 +- 14 files changed, 5740 insertions(+), 36 deletions(-) create mode 100644 js/rhino/org/mozilla/classfile/ByteCode.java create mode 100644 js/rhino/org/mozilla/classfile/ClassFileWriter.java create mode 100644 js/rhino/org/mozilla/javascript/JavaAdapter.java create mode 100644 js/rhino/src/org/mozilla/classfile/ByteCode.java create mode 100644 js/rhino/src/org/mozilla/classfile/ClassFileWriter.java create mode 100644 js/rhino/src/org/mozilla/javascript/JavaAdapter.java diff --git a/js/rhino/org/mozilla/classfile/ByteCode.java b/js/rhino/org/mozilla/classfile/ByteCode.java new file mode 100644 index 000000000000..0c32e39ccb32 --- /dev/null +++ b/js/rhino/org/mozilla/classfile/ByteCode.java @@ -0,0 +1,1044 @@ +/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights + * Reserved. + */ + +package org.mozilla.classfile; + +public class ByteCode { + + public static final byte + NOP = 0x00, + ACONST_NULL = 0x01, + ICONST_M1 = 0x02, + ICONST_0 = 0x03, + ICONST_1 = 0x04, + ICONST_2 = 0x05, + ICONST_3 = 0x06, + ICONST_4 = 0x07, + ICONST_5 = 0x08, + LCONST_0 = 0x09, + LCONST_1 = 0x0A, + FCONST_0 = 0x0B, + FCONST_1 = 0x0C, + FCONST_2 = 0x0D, + DCONST_0 = 0x0E, + DCONST_1 = 0x0F, + BIPUSH = 0x10, + SIPUSH = 0x11, + LDC = 0x12, + LDC_W = 0x13, + LDC2_W = 0x14, + ILOAD = 0x15, + LLOAD = 0x16, + FLOAD = 0x17, + DLOAD = 0x18, + ALOAD = 0x19, + ILOAD_0 = 0x1A, + ILOAD_1 = 0x1B, + ILOAD_2 = 0x1C, + ILOAD_3 = 0x1D, + LLOAD_0 = 0x1E, + LLOAD_1 = 0x1F, + LLOAD_2 = 0x20, + LLOAD_3 = 0x21, + FLOAD_0 = 0x22, + FLOAD_1 = 0x23, + FLOAD_2 = 0x24, + FLOAD_3 = 0x25, + DLOAD_0 = 0x26, + DLOAD_1 = 0x27, + DLOAD_2 = 0x28, + DLOAD_3 = 0x29, + ALOAD_0 = 0x2A, + ALOAD_1 = 0x2B, + ALOAD_2 = 0x2C, + ALOAD_3 = 0x2D, + IALOAD = 0x2E, + LALOAD = 0x2F, + FALOAD = 0x30, + DALOAD = 0x31, + AALOAD = 0x32, + BALOAD = 0x33, + CALOAD = 0x34, + SALOAD = 0x35, + ISTORE = 0x36, + LSTORE = 0x37, + FSTORE = 0x38, + DSTORE = 0x39, + ASTORE = 0x3A, + ISTORE_0 = 0x3B, + ISTORE_1 = 0x3C, + ISTORE_2 = 0x3D, + ISTORE_3 = 0x3E, + LSTORE_0 = 0x3F, + LSTORE_1 = 0x40, + LSTORE_2 = 0x41, + LSTORE_3 = 0x42, + FSTORE_0 = 0x43, + FSTORE_1 = 0x44, + FSTORE_2 = 0x45, + FSTORE_3 = 0x46, + DSTORE_0 = 0x47, + DSTORE_1 = 0x48, + DSTORE_2 = 0x49, + DSTORE_3 = 0x4A, + ASTORE_0 = 0x4B, + ASTORE_1 = 0x4C, + ASTORE_2 = 0x4D, + ASTORE_3 = 0x4E, + IASTORE = 0x4F, + LASTORE = 0x50, + FASTORE = 0x51, + DASTORE = 0x52, + AASTORE = 0x53, + BASTORE = 0x54, + CASTORE = 0x55, + SASTORE = 0x56, + POP = 0x57, + POP2 = 0x58, + DUP = 0x59, + DUP_X1 = 0x5A, + DUP_X2 = 0x5B, + DUP2 = 0x5C, + DUP2_X1 = 0x5D, + DUP2_X2 = 0x5E, + SWAP = 0x5F, + IADD = 0x60, + LADD = 0x61, + FADD = 0x62, + DADD = 0x63, + ISUB = 0x64, + LSUB = 0x65, + FSUB = 0x66, + DSUB = 0x67, + IMUL = 0x68, + LMUL = 0x69, + FMUL = 0x6A, + DMUL = 0x6B, + IDIV = 0x6C, + LDIV = 0x6D, + FDIV = 0x6E, + DDIV = 0x6F, + IREM = 0x70, + LREM = 0x71, + FREM = 0x72, + DREM = 0x73, + INEG = 0x74, + LNEG = 0x75, + FNEG = 0x76, + DNEG = 0x77, + ISHL = 0x78, + LSHL = 0x79, + ISHR = 0x7A, + LSHR = 0x7B, + IUSHR = 0x7C, + LUSHR = 0x7D, + IAND = 0x7E, + LAND = 0x7F, + IOR = (byte)0x80, + LOR = (byte)0x81, + IXOR = (byte)0x82, + LXOR = (byte)0x83, + IINC = (byte)0x84, + I2L = (byte)0x85, + I2F = (byte)0x86, + I2D = (byte)0x87, + L2I = (byte)0x88, + L2F = (byte)0x89, + L2D = (byte)0x8A, + F2I = (byte)0x8B, + F2L = (byte)0x8C, + F2D = (byte)0x8D, + D2I = (byte)0x8E, + D2L = (byte)0x8F, + D2F = (byte)0x90, + I2B = (byte)0x91, + I2C = (byte)0x92, + I2S = (byte)0x93, + LCMP = (byte)0x94, + FCMPL = (byte)0x95, + FCMPG = (byte)0x96, + DCMPL = (byte)0x97, + DCMPG = (byte)0x98, + IFEQ = (byte)0x99, + IFNE = (byte)0x9A, + IFLT = (byte)0x9B, + IFGE = (byte)0x9C, + IFGT = (byte)0x9D, + IFLE = (byte)0x9E, + IF_ICMPEQ = (byte)0x9F, + IF_ICMPNE = (byte)0xA0, + IF_ICMPLT = (byte)0xA1, + IF_ICMPGE = (byte)0xA2, + IF_ICMPGT = (byte)0xA3, + IF_ICMPLE = (byte)0xA4, + IF_ACMPEQ = (byte)0xA5, + IF_ACMPNE = (byte)0xA6, + GOTO = (byte)0xA7, + JSR = (byte)0xA8, + RET = (byte)0xA9, + TABLESWITCH = (byte)0xAA, + LOOKUPSWITCH = (byte)0xAB, + IRETURN = (byte)0xAC, + LRETURN = (byte)0xAD, + FRETURN = (byte)0xAE, + DRETURN = (byte)0xAF, + ARETURN = (byte)0xB0, + RETURN = (byte)0xB1, + GETSTATIC = (byte)0xB2, + PUTSTATIC = (byte)0xB3, + GETFIELD = (byte)0xB4, + PUTFIELD = (byte)0xB5, + INVOKEVIRTUAL = (byte)0xB6, + INVOKESPECIAL = (byte)0xB7, + INVOKESTATIC = (byte)0xB8, + INVOKEINTERFACE = (byte)0xB9, + XXXUNUSEDXXX = (byte)0xBA, + NEW = (byte)0xBB, + NEWARRAY = (byte)0xBC, + ANEWARRAY = (byte)0xBD, + ARRAYLENGTH = (byte)0xBE, + ATHROW = (byte)0xBF, + CHECKCAST = (byte)0xC0, + INSTANCEOF = (byte)0xC1, + MONITORENTER = (byte)0xC2, + MONITOREXIT = (byte)0xC3, + WIDE = (byte)0xC4, + MULTIANEWARRAY = (byte)0xC5, + IFNULL = (byte)0xC6, + IFNONNULL = (byte)0xC7, + GOTO_W = (byte)0xC8, + JSR_W = (byte)0xC9, + BREAKPOINT = (byte)0xCA, + LDC_QUICK = (byte)0xCB, + LDC_W_QUICK = (byte)0xCC, + LDC2_W_QUICK = (byte)0xCD, + GETFIELD_QUICK = (byte)0xCE, + PUTFIELD_QUICK = (byte)0xCF, + GETFIELD2_QUICK = (byte)0xD0, + PUTFIELD2_QUICK = (byte)0xD1, + GETSTATIC_QUICK = (byte)0xD2, + PUTSTATIC_QUICK = (byte)0xD3, + GETSTATIC2_QUICK = (byte)0xD4, + PUTSTATIC2_QUICK = (byte)0xD5, + INVOKEVIRTUAL_QUICK = (byte)0xD6, + INVOKENONVIRTUAL_QUICK = (byte)0xD7, + INVOKESUPER_QUICK = (byte)0xD8, + INVOKESTATIC_QUICK = (byte)0xD9, + INVOKEINTERFACE_QUICK = (byte)0xDA, + INVOKEVIRTUALOBJECT_QUICK = (byte)0xDB, + + NEW_QUICK = (byte)0xDD, + ANEWARRAY_QUICK = (byte)0xDE, + MULTIANEWARRAY_QUICK = (byte)0xDF, + CHECKCAST_QUICK = (byte)0xE0, + INSTANCEOF_QUICK = (byte)0xE1, + INVOKEVIRTUAL_QUICK_W = (byte)0xE2, + GETFIELD_QUICK_W = (byte)0xE3, + PUTFIELD_QUICK_W = (byte)0xE4, + IMPDEP1 = (byte)0xFE, + IMPDEP2 = (byte)0xFF; + + + // Types for NEWARRAY + public static final byte + T_BOOLEAN = 4, + T_CHAR = 5, + T_FLOAT = 6, + T_DOUBLE = 7, + T_BYTE = 8, + T_SHORT = 9, + T_INT = 10, + T_LONG = 11; + + static final byte[] extra = { // # bytes of operands generated after the opcode + /* NOP */ 0, + /* ACONST_NULL */ 0, + /* ICONST_M1 */ 0, + /* ICONST_0 */ 0, + /* ICONST_1 */ 0, + /* ICONST_2 */ 0, + /* ICONST_3 */ 0, + /* ICONST_4 */ 0, + /* ICONST_5 */ 0, + /* LCONST_0 */ 0, + /* LCONST_1 */ 0, + /* FCONST_0 */ 0, + /* FCONST_1 */ 0, + /* FCONST_2 */ 0, + /* DCONST_0 */ 0, + /* DCONST_1 */ 0, + /* BIPUSH */ 1, + /* SIPUSH */ 2, + /* LDC */ 1, + /* LDC_W */ 2, + /* LDC2_W */ 2, + /* ILOAD */ 1, + /* LLOAD */ 1, + /* FLOAD */ 1, + /* DLOAD */ 1, + /* ALOAD */ 1, + /* ILOAD_0 */ 0, + /* ILOAD_1 */ 0, + /* ILOAD_2 */ 0, + /* ILOAD_3 */ 0, + /* LLOAD_0 */ 0, + /* LLOAD_1 */ 0, + /* LLOAD_2 */ 0, + /* LLOAD_3 */ 0, + /* FLOAD_0 */ 0, + /* FLOAD_1 */ 0, + /* FLOAD_2 */ 0, + /* FLOAD_3 */ 0, + /* DLOAD_0 */ 0, + /* DLOAD_1 */ 0, + /* DLOAD_2 */ 0, + /* DLOAD_3 */ 0, + /* ALOAD_0 */ 0, + /* ALOAD_1 */ 0, + /* ALOAD_2 */ 0, + /* ALOAD_3 */ 0, + /* IALOAD */ 0, + /* LALOAD */ 0, + /* FALOAD */ 0, + /* DALOAD */ 0, + /* AALOAD */ 0, + /* BALOAD */ 0, + /* CALOAD */ 0, + /* SALOAD */ 0, + /* ISTORE */ 1, + /* LSTORE */ 1, + /* FSTORE */ 1, + /* DSTORE */ 1, + /* ASTORE */ 1, + /* ISTORE_0 */ 0, + /* ISTORE_1 */ 0, + /* ISTORE_2 */ 0, + /* ISTORE_3 */ 0, + /* LSTORE_0 */ 0, + /* LSTORE_1 */ 0, + /* LSTORE_2 */ 0, + /* LSTORE_3 */ 0, + /* FSTORE_0 */ 0, + /* FSTORE_1 */ 0, + /* FSTORE_2 */ 0, + /* FSTORE_3 */ 0, + /* DSTORE_0 */ 0, + /* DSTORE_1 */ 0, + /* DSTORE_2 */ 0, + /* DSTORE_3 */ 0, + /* ASTORE_0 */ 0, + /* ASTORE_1 */ 0, + /* ASTORE_2 */ 0, + /* ASTORE_3 */ 0, + /* IASTORE */ 0, + /* LASTORE */ 0, + /* FASTORE */ 0, + /* DASTORE */ 0, + /* AASTORE */ 0, + /* BASTORE */ 0, + /* CASTORE */ 0, + /* SASTORE */ 0, + /* POP */ 0, + /* POP2 */ 0, + /* DUP */ 0, + /* DUP_X1 */ 0, + /* DUP_X2 */ 0, + /* DUP2 */ 0, + /* DUP2_X1 */ 0, + /* DUP2_X2 */ 0, + /* SWAP */ 0, + /* IADD */ 0, + /* LADD */ 0, + /* FADD */ 0, + /* DADD */ 0, + /* ISUB */ 0, + /* LSUB */ 0, + /* FSUB */ 0, + /* DSUB */ 0, + /* IMUL */ 0, + /* LMUL */ 0, + /* FMUL */ 0, + /* DMUL */ 0, + /* IDIV */ 0, + /* LDIV */ 0, + /* FDIV */ 0, + /* DDIV */ 0, + /* IREM */ 0, + /* LREM */ 0, + /* FREM */ 0, + /* DREM */ 0, + /* INEG */ 0, + /* LNEG */ 0, + /* FNEG */ 0, + /* DNEG */ 0, + /* ISHL */ 0, + /* LSHL */ 0, + /* ISHR */ 0, + /* LSHR */ 0, + /* IUSHR */ 0, + /* LUSHR */ 0, + /* IAND */ 0, + /* LAND */ 0, + /* IOR */ 0, + /* LOR */ 0, + /* IXOR */ 0, + /* LXOR */ 0, + /* IINC */ 2, + /* I2L */ 0, + /* I2F */ 0, + /* I2D */ 0, + /* L2I */ 0, + /* L2F */ 0, + /* L2D */ 0, + /* F2I */ 0, + /* F2L */ 0, + /* F2D */ 0, + /* D2I */ 0, + /* D2L */ 0, + /* D2F */ 0, + /* I2B */ 0, + /* I2C */ 0, + /* I2S */ 0, + /* LCMP */ 0, + /* FCMPL */ 0, + /* FCMPG */ 0, + /* DCMPL */ 0, + /* DCMPG */ 0, + /* IFEQ */ 2, + /* IFNE */ 2, + /* IFLT */ 2, + /* IFGE */ 2, + /* IFGT */ 2, + /* IFLE */ 2, + /* IF_ICMPEQ */ 2, + /* IF_ICMPNE */ 2, + /* IF_ICMPLT */ 2, + /* IF_ICMPGE */ 2, + /* IF_ICMPGT */ 2, + /* IF_ICMPLE */ 2, + /* IF_ACMPEQ */ 2, + /* IF_ACMPNE */ 2, + /* GOTO */ 2, + /* JSR */ 2, + /* RET */ 1, + /* TABLESWITCH */ -1, // depends on alignment + /* LOOKUPSWITCH */ -1, // depends on alignment + /* IRETURN */ 0, + /* LRETURN */ 0, + /* FRETURN */ 0, + /* DRETURN */ 0, + /* ARETURN */ 0, + /* RETURN */ 0, + /* GETSTATIC */ 2, + /* PUTSTATIC */ 2, + /* GETFIELD */ 2, + /* PUTFIELD */ 2, + /* INVOKEVIRTUAL */ 2, + /* INVOKESPECIAL */ 2, + /* INVOKESTATIC */ 2, + /* INVOKEINTERFACE */ 2, + /* XXXUNUSEDXXX */ 0, + /* NEW */ 2, + /* NEWARRAY */ 1, + /* ANEWARRAY */ 2, + /* ARRAYLENGTH */ 0, + /* ATHROW */ 0, + /* CHECKCAST */ 2, + /* INSTANCEOF */ 2, + /* MONITORENTER */ 0, + /* MONITOREXIT */ 0, + /* WIDE */ 0, + /* MULTIANEWARRAY */ 3, + /* IFNULL */ 2, + /* IFNONNULL */ 2, + /* GOTO_W */ 4, + /* JSR_W */ 4, + /* BREAKPOINT */ 0, + /* LDC_QUICK */ 1, + /* LDC_W_QUICK */ 2, + /* LDC2_W_QUICK */ 2, + /* GETFIELD_QUICK */ 2, + /* PUTFIELD_QUICK */ 2, + /* GETFIELD2_QUICK */ 2, + /* PUTFIELD2_QUICK */ 2, + /* GETSTATIC_QUICK */ 2, + /* PUTSTATIC_QUICK */ 2, + /* GETSTATIC2_QUICK */ 2, + /* PUTSTATIC2_QUICK */ 2, + /* INVOKEVIRTUAL_QUICK */ 2, + /* INVOKENONVIRTUAL_QUICK */ 2, + /* INVOKESUPER_QUICK */ 2, + /* INVOKESTATIC_QUICK */ 2, + /* INVOKEINTERFACE_QUICK */ 2, + /* INVOKEVIRTUALOBJECT_QUICK */ 2, + /* XXXUNUSEDXXX */ 0, + /* NEW_QUICK */ 2, + /* ANEWARRAY_QUICK */ 2, + /* MULTIANEWARRAY_QUICK */ 3, + /* CHECKCAST_QUICK */ 2, + /* INSTANCEOF_QUICK */ 2, + /* INVOKEVIRTUAL_QUICK_W */ 0, + /* GETFIELD_QUICK_W */ 2, + /* PUTFIELD_QUICK_W */ 2, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* IMPDEP1 */ 0, + /* IMPDEP2 */ 0 + }; + + static final byte[] opcodeCount = { // # of operands accompanying the opcode + /* NOP */ 0, + /* ACONST_NULL */ 0, + /* ICONST_M1 */ 0, + /* ICONST_0 */ 0, + /* ICONST_1 */ 0, + /* ICONST_2 */ 0, + /* ICONST_3 */ 0, + /* ICONST_4 */ 0, + /* ICONST_5 */ 0, + /* LCONST_0 */ 0, + /* LCONST_1 */ 0, + /* FCONST_0 */ 0, + /* FCONST_1 */ 0, + /* FCONST_2 */ 0, + /* DCONST_0 */ 0, + /* DCONST_1 */ 0, + /* BIPUSH */ 1, + /* SIPUSH */ 1, + /* LDC */ 1, + /* LDC_W */ 1, + /* LDC2_W */ 1, + /* ILOAD */ 1, + /* LLOAD */ 1, + /* FLOAD */ 1, + /* DLOAD */ 1, + /* ALOAD */ 1, + /* ILOAD_0 */ 0, + /* ILOAD_1 */ 0, + /* ILOAD_2 */ 0, + /* ILOAD_3 */ 0, + /* LLOAD_0 */ 0, + /* LLOAD_1 */ 0, + /* LLOAD_2 */ 0, + /* LLOAD_3 */ 0, + /* FLOAD_0 */ 0, + /* FLOAD_1 */ 0, + /* FLOAD_2 */ 0, + /* FLOAD_3 */ 0, + /* DLOAD_0 */ 0, + /* DLOAD_1 */ 0, + /* DLOAD_2 */ 0, + /* DLOAD_3 */ 0, + /* ALOAD_0 */ 0, + /* ALOAD_1 */ 0, + /* ALOAD_2 */ 0, + /* ALOAD_3 */ 0, + /* IALOAD */ 0, + /* LALOAD */ 0, + /* FALOAD */ 0, + /* DALOAD */ 0, + /* AALOAD */ 0, + /* BALOAD */ 0, + /* CALOAD */ 0, + /* SALOAD */ 0, + /* ISTORE */ 1, + /* LSTORE */ 1, + /* FSTORE */ 1, + /* DSTORE */ 1, + /* ASTORE */ 1, + /* ISTORE_0 */ 0, + /* ISTORE_1 */ 0, + /* ISTORE_2 */ 0, + /* ISTORE_3 */ 0, + /* LSTORE_0 */ 0, + /* LSTORE_1 */ 0, + /* LSTORE_2 */ 0, + /* LSTORE_3 */ 0, + /* FSTORE_0 */ 0, + /* FSTORE_1 */ 0, + /* FSTORE_2 */ 0, + /* FSTORE_3 */ 0, + /* DSTORE_0 */ 0, + /* DSTORE_1 */ 0, + /* DSTORE_2 */ 0, + /* DSTORE_3 */ 0, + /* ASTORE_0 */ 0, + /* ASTORE_1 */ 0, + /* ASTORE_2 */ 0, + /* ASTORE_3 */ 0, + /* IASTORE */ 0, + /* LASTORE */ 0, + /* FASTORE */ 0, + /* DASTORE */ 0, + /* AASTORE */ 0, + /* BASTORE */ 0, + /* CASTORE */ 0, + /* SASTORE */ 0, + /* POP */ 0, + /* POP2 */ 0, + /* DUP */ 0, + /* DUP_X1 */ 0, + /* DUP_X2 */ 0, + /* DUP2 */ 0, + /* DUP2_X1 */ 0, + /* DUP2_X2 */ 0, + /* SWAP */ 0, + /* IADD */ 0, + /* LADD */ 0, + /* FADD */ 0, + /* DADD */ 0, + /* ISUB */ 0, + /* LSUB */ 0, + /* FSUB */ 0, + /* DSUB */ 0, + /* IMUL */ 0, + /* LMUL */ 0, + /* FMUL */ 0, + /* DMUL */ 0, + /* IDIV */ 0, + /* LDIV */ 0, + /* FDIV */ 0, + /* DDIV */ 0, + /* IREM */ 0, + /* LREM */ 0, + /* FREM */ 0, + /* DREM */ 0, + /* INEG */ 0, + /* LNEG */ 0, + /* FNEG */ 0, + /* DNEG */ 0, + /* ISHL */ 0, + /* LSHL */ 0, + /* ISHR */ 0, + /* LSHR */ 0, + /* IUSHR */ 0, + /* LUSHR */ 0, + /* IAND */ 0, + /* LAND */ 0, + /* IOR */ 0, + /* LOR */ 0, + /* IXOR */ 0, + /* LXOR */ 0, + /* IINC */ 2, + /* I2L */ 0, + /* I2F */ 0, + /* I2D */ 0, + /* L2I */ 0, + /* L2F */ 0, + /* L2D */ 0, + /* F2I */ 0, + /* F2L */ 0, + /* F2D */ 0, + /* D2I */ 0, + /* D2L */ 0, + /* D2F */ 0, + /* I2B */ 0, + /* I2C */ 0, + /* I2S */ 0, + /* LCMP */ 0, + /* FCMPL */ 0, + /* FCMPG */ 0, + /* DCMPL */ 0, + /* DCMPG */ 0, + /* IFEQ */ 1, + /* IFNE */ 1, + /* IFLT */ 1, + /* IFGE */ 1, + /* IFGT */ 1, + /* IFLE */ 1, + /* IF_ICMPEQ */ 1, + /* IF_ICMPNE */ 1, + /* IF_ICMPLT */ 1, + /* IF_ICMPGE */ 1, + /* IF_ICMPGT */ 1, + /* IF_ICMPLE */ 1, + /* IF_ACMPEQ */ 1, + /* IF_ACMPNE */ 1, + /* GOTO */ 1, + /* JSR */ 1, + /* RET */ 1, + /* TABLESWITCH */ -1, + /* LOOKUPSWITCH */ -1, + /* IRETURN */ 0, + /* LRETURN */ 0, + /* FRETURN */ 0, + /* DRETURN */ 0, + /* ARETURN */ 0, + /* RETURN */ 0, + /* GETSTATIC */ 1, + /* PUTSTATIC */ 1, + /* GETFIELD */ 1, + /* PUTFIELD */ 1, + /* INVOKEVIRTUAL */ 1, + /* INVOKESPECIAL */ 1, + /* INVOKESTATIC */ 1, + /* INVOKEINTERFACE */ 1, + /* XXXUNUSEDXXX */ 0, + /* NEW */ 1, + /* NEWARRAY */ 1, + /* ANEWARRAY */ 1, + /* ARRAYLENGTH */ 0, + /* ATHROW */ 0, + /* CHECKCAST */ 1, + /* INSTANCEOF */ 1, + /* MONITORENTER */ 0, + /* MONITOREXIT */ 0, + /* WIDE */ 0, + /* MULTIANEWARRAY */ 2, + /* IFNULL */ 1, + /* IFNONNULL */ 1, + /* GOTO_W */ 1, + /* JSR_W */ 1, + /* BREAKPOINT */ 0, + /* LDC_QUICK */ -1, + /* LDC_W_QUICK */ -1, + /* LDC2_W_QUICK */ -1, + /* GETFIELD_QUICK */ -1, + /* PUTFIELD_QUICK */ -1, + /* GETFIELD2_QUICK */ -1, + /* PUTFIELD2_QUICK */ -1, + /* GETSTATIC_QUICK */ -1, + /* PUTSTATIC_QUICK */ -1, + /* GETSTATIC2_QUICK */ -1, + /* PUTSTATIC2_QUICK */ -1, + /* INVOKEVIRTUAL_QUICK */ -1, + /* INVOKENONVIRTUAL_QUICK */ -1, + /* INVOKESUPER_QUICK */ -1, + /* INVOKESTATIC_QUICK */ -1, + /* INVOKEINTERFACE_QUICK */ -1, + /* INVOKEVIRTUALOBJECT_QUICK */ -1, + /* XXXUNUSEDXXX */ -1, + /* NEW_QUICK */ -1, + /* ANEWARRAY_QUICK */ -1, + /* MULTIANEWARRAY_QUICK */ -1, + /* CHECKCAST_QUICK */ -1, + /* INSTANCEOF_QUICK */ -1, + /* INVOKEVIRTUAL_QUICK_W */ -1, + /* GETFIELD_QUICK_W */ -1, + /* PUTFIELD_QUICK_W */ -1, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* IMPDEP1 */ 0, + /* IMPDEP2 */ 0 + }; + + static final byte[] stackChange = { // the effect on the operand stack + /* NOP */ 0, + /* ACONST_NULL */ 1, + /* ICONST_M1 */ 1, + /* ICONST_0 */ 1, + /* ICONST_1 */ 1, + /* ICONST_2 */ 1, + /* ICONST_3 */ 1, + /* ICONST_4 */ 1, + /* ICONST_5 */ 1, + /* LCONST_0 */ 2, + /* LCONST_1 */ 2, + /* FCONST_0 */ 1, + /* FCONST_1 */ 1, + /* FCONST_2 */ 1, + /* DCONST_0 */ 2, + /* DCONST_1 */ 2, + /* BIPUSH */ 1, + /* SIPUSH */ 1, + /* LDC */ 1, + /* LDC_W */ 1, + /* LDC2_W */ 2, + /* ILOAD */ 1, + /* LLOAD */ 2, + /* FLOAD */ 1, + /* DLOAD */ 2, + /* ALOAD */ 1, + /* ILOAD_0 */ 1, + /* ILOAD_1 */ 1, + /* ILOAD_2 */ 1, + /* ILOAD_3 */ 1, + /* LLOAD_0 */ 2, + /* LLOAD_1 */ 2, + /* LLOAD_2 */ 2, + /* LLOAD_3 */ 2, + /* FLOAD_0 */ 1, + /* FLOAD_1 */ 1, + /* FLOAD_2 */ 1, + /* FLOAD_3 */ 1, + /* DLOAD_0 */ 2, + /* DLOAD_1 */ 2, + /* DLOAD_2 */ 2, + /* DLOAD_3 */ 2, + /* ALOAD_0 */ 1, + /* ALOAD_1 */ 1, + /* ALOAD_2 */ 1, + /* ALOAD_3 */ 1, + /* IALOAD */ -1, + /* LALOAD */ 0, + /* FALOAD */ -1, + /* DALOAD */ 0, + /* AALOAD */ -1, + /* BALOAD */ -1, + /* CALOAD */ -1, + /* SALOAD */ -1, + /* ISTORE */ -1, + /* LSTORE */ -2, + /* FSTORE */ -1, + /* DSTORE */ -2, + /* ASTORE */ -1, + /* ISTORE_0 */ -1, + /* ISTORE_1 */ -1, + /* ISTORE_2 */ -1, + /* ISTORE_3 */ -1, + /* LSTORE_0 */ -2, + /* LSTORE_1 */ -2, + /* LSTORE_2 */ -2, + /* LSTORE_3 */ -2, + /* FSTORE_0 */ -1, + /* FSTORE_1 */ -1, + /* FSTORE_2 */ -1, + /* FSTORE_3 */ -1, + /* DSTORE_0 */ -2, + /* DSTORE_1 */ -2, + /* DSTORE_2 */ -2, + /* DSTORE_3 */ -2, + /* ASTORE_0 */ -1, + /* ASTORE_1 */ -1, + /* ASTORE_2 */ -1, + /* ASTORE_3 */ -1, + /* IASTORE */ -3, + /* LASTORE */ -4, + /* FASTORE */ -3, + /* DASTORE */ -4, + /* AASTORE */ -3, + /* BASTORE */ -3, + /* CASTORE */ -3, + /* SASTORE */ -3, + /* POP */ -1, + /* POP2 */ -2, + /* DUP */ 1, + /* DUP_X1 */ 1, + /* DUP_X2 */ 1, + /* DUP2 */ 2, + /* DUP2_X1 */ 2, + /* DUP2_X2 */ 2, + /* SWAP */ 0, + /* IADD */ -1, + /* LADD */ -2, + /* FADD */ -1, + /* DADD */ -2, + /* ISUB */ -1, + /* LSUB */ -2, + /* FSUB */ -1, + /* DSUB */ -2, + /* IMUL */ -1, + /* LMUL */ -2, + /* FMUL */ -1, + /* DMUL */ -2, + /* IDIV */ -1, + /* LDIV */ -2, + /* FDIV */ -1, + /* DDIV */ -2, + /* IREM */ -1, + /* LREM */ -2, + /* FREM */ -1, + /* DREM */ -2, + /* INEG */ 0, + /* LNEG */ 0, + /* FNEG */ 0, + /* DNEG */ 0, + /* ISHL */ -1, + /* LSHL */ -1, + /* ISHR */ -1, + /* LSHR */ -1, + /* IUSHR */ -1, + /* LUSHR */ -1, + /* IAND */ -1, + /* LAND */ -2, + /* IOR */ -1, + /* LOR */ -2, + /* IXOR */ -1, + /* LXOR */ -2, + /* IINC */ 0, + /* I2L */ 1, + /* I2F */ 0, + /* I2D */ 1, + /* L2I */ -1, + /* L2F */ -1, + /* L2D */ 0, + /* F2I */ 0, + /* F2L */ 1, + /* F2D */ 1, + /* D2I */ -1, + /* D2L */ 0, + /* D2F */ -1, + /* I2B */ 0, + /* I2C */ 0, + /* I2S */ 0, + /* LCMP */ -3, + /* FCMPL */ -1, + /* FCMPG */ -1, + /* DCMPL */ -3, + /* DCMPG */ -3, + /* IFEQ */ -1, + /* IFNE */ -1, + /* IFLT */ -1, + /* IFGE */ -1, + /* IFGT */ -1, + /* IFLE */ -1, + /* IF_ICMPEQ */ -2, + /* IF_ICMPNE */ -2, + /* IF_ICMPLT */ -2, + /* IF_ICMPGE */ -2, + /* IF_ICMPGT */ -2, + /* IF_ICMPLE */ -2, + /* IF_ACMPEQ */ -2, + /* IF_ACMPNE */ -2, + /* GOTO */ 0, + /* JSR */ 1, + /* RET */ 0, + /* TABLESWITCH */ -1, + /* LOOKUPSWITCH */ -1, + /* IRETURN */ -1, + /* LRETURN */ -2, + /* FRETURN */ -1, + /* DRETURN */ -2, + /* ARETURN */ -1, + /* RETURN */ 0, + /* GETSTATIC */ 0, + /* PUTSTATIC */ 0, + /* GETFIELD */ -1, + /* PUTFIELD */ -1, + /* INVOKEVIRTUAL */ -1, // pops 'this' (unless static) + /* INVOKESPECIAL */ -1, // but needs to account for + /* INVOKESTATIC */ 0, // parameters and return type + /* INVOKEINTERFACE */ -1, // + /* XXXUNUSEDXXX */ 0, + /* NEW */ 1, + /* NEWARRAY */ 0, + /* ANEWARRAY */ 0, + /* ARRAYLENGTH */ 0, + /* ATHROW */ -1, + /* CHECKCAST */ 0, + /* INSTANCEOF */ 0, + /* MONITORENTER */ -1, + /* MONITOREXIT */ -1, + /* WIDE */ 0, + /* MULTIANEWARRAY */ 1, + /* IFNULL */ -1, + /* IFNONNULL */ -1, + /* GOTO_W */ 0, + /* JSR_W */ 1, + /* BREAKPOINT */ 0, + /* LDC_QUICK */ 1, + /* LDC_W_QUICK */ 1, + /* LDC2_W_QUICK */ 2, + /* GETFIELD_QUICK */ 0, + /* PUTFIELD_QUICK */ 0, + /* GETFIELD2_QUICK */ 0, + /* PUTFIELD2_QUICK */ 0, + /* GETSTATIC_QUICK */ 0, + /* PUTSTATIC_QUICK */ 0, + /* GETSTATIC2_QUICK */ 0, + /* PUTSTATIC2_QUICK */ 0, + /* INVOKEVIRTUAL_QUICK */ 0, + /* INVOKENONVIRTUAL_QUICK */ 0, + /* INVOKESUPER_QUICK */ 0, + /* INVOKESTATIC_QUICK */ 0, + /* INVOKEINTERFACE_QUICK */ 0, + /* INVOKEVIRTUALOBJECT_QUICK */ 0, + /* XXXUNUSEDXXX */ 0, + /* NEW_QUICK */ 1, + /* ANEWARRAY_QUICK */ 1, + /* MULTIANEWARRAY_QUICK */ 1, + /* CHECKCAST_QUICK */ -1, + /* INSTANCEOF_QUICK */ 0, + /* INVOKEVIRTUAL_QUICK_W */ 0, + /* GETFIELD_QUICK_W */ 0, + /* PUTFIELD_QUICK_W */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* IMPDEP1 */ 0, + /* IMPDEP2 */ 0 + }; +} diff --git a/js/rhino/org/mozilla/classfile/ClassFileWriter.java b/js/rhino/org/mozilla/classfile/ClassFileWriter.java new file mode 100644 index 000000000000..e88e4adc711d --- /dev/null +++ b/js/rhino/org/mozilla/classfile/ClassFileWriter.java @@ -0,0 +1,1308 @@ +/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights + * Reserved. + */ + +package org.mozilla.classfile; + +import org.mozilla.javascript.*; + +import java.io.*; +import java.util.*; + +public class ClassFileWriter extends LabelTable { + + public ClassFileWriter(String thisClass, String superClass, + String sourceFileName) + { + itsConstantPool = new ConstantPool(); + itsThisClassIndex = itsConstantPool.addClass(thisClass); + itsSuperClassIndex = itsConstantPool.addClass(superClass); + if (sourceFileName != null) + itsSourceFileNameIndex = itsConstantPool.addUtf8(sourceFileName); + itsFlags = ACC_PUBLIC; + } + + public void setFlags(short flags) + { + itsFlags = flags; + } + + public static String fullyQualifiedForm(String name) + { + return name.replace('.', '/'); + } + + public void addInterface(String interfaceName) + { + short interfaceIndex = itsConstantPool.addClass(interfaceName); + itsInterfaces.addElement(new Short(interfaceIndex)); + } + + + private final static long FileHeaderConstant = 0xCAFEBABE0003002DL; + private static final boolean DEBUG = true; + private static final boolean DEBUGSTACK = false; + private static final boolean DEBUGLABELS = false; + private static final boolean DEBUGCODE = false; + private static final int CodeBufferSize = 128; + + public static final short + ACC_PUBLIC = 0x0001, + ACC_PRIVATE = 0x0002, + ACC_PROTECTED = 0x0004, + ACC_STATIC = 0x0008, + ACC_FINAL = 0x0010, + ACC_SYNCHRONIZED = 0x0020, + ACC_VOLATILE = 0x0040, + ACC_TRANSIENT = 0x0080, + ACC_NATIVE = 0x0100, + ACC_ABSTRACT = 0x0400; + + public void add(byte theOpCode) + { + if (DEBUGCODE) + System.out.println("Add " + Integer.toHexString(theOpCode & 0xFF)); + if (DEBUG) { + if (ByteCode.opcodeCount[theOpCode & 0xFF] != 0) + throw new RuntimeException("Expected operands"); + } + addToCodeBuffer(theOpCode); + itsStackTop += ByteCode.stackChange[theOpCode & 0xFF]; + if (DEBUGSTACK) { + System.out.println("After " + Integer.toHexString(theOpCode & 0xFF) + " stack = " + itsStackTop); + } + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("Stack underflow"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + } + + public void add(byte theOpCode, int theOperand) + { + if (DEBUGCODE) + System.out.println("Add " + Integer.toHexString(theOpCode & 0xFF) + ", " + Integer.toHexString(theOperand) ); + itsStackTop += ByteCode.stackChange[theOpCode & 0xFF]; + if (DEBUGSTACK) { + System.out.println("After " + Integer.toHexString(theOpCode & 0xFF) + " stack = " + itsStackTop); + } + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("Stack underflow"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + + switch (theOpCode) { + case ByteCode.GOTO : + // fallthru... + case ByteCode.IFEQ : + case ByteCode.IFNE : + case ByteCode.IFLT : + case ByteCode.IFGE : + case ByteCode.IFGT : + case ByteCode.IFLE : + case ByteCode.IF_ICMPEQ : + case ByteCode.IF_ICMPNE : + case ByteCode.IF_ICMPLT : + case ByteCode.IF_ICMPGE : + case ByteCode.IF_ICMPGT : + case ByteCode.IF_ICMPLE : + case ByteCode.IF_ACMPEQ : + case ByteCode.IF_ACMPNE : + case ByteCode.JSR : + case ByteCode.IFNULL : + case ByteCode.IFNONNULL : { + if (DEBUG) { + if ((theOperand & 0x80000000) != 0x80000000) { + if ((theOperand < 0) || (theOperand > 65535)) + throw new RuntimeException("Bad label for branch"); + } + } + int branchPC = itsCodeBufferTop; + addToCodeBuffer(theOpCode); + if ((theOperand & 0x80000000) != 0x80000000) { + // hard displacement + int temp_Label = acquireLabel(); + int theLabel = temp_Label & 0x7FFFFFFF; + itsLabelTable[theLabel].setPC( + (short)(branchPC + theOperand)); + addToCodeBuffer((byte)(theOperand >> 8)); + addToCodeBuffer((byte)theOperand); + } + else { // a label + int theLabel = theOperand & 0x7FFFFFFF; + int targetPC = itsLabelTable[theLabel].getPC(); + if (DEBUGLABELS) { + System.out.println("Fixing branch to " + theLabel + " at " + targetPC + " from " + branchPC); + } + if (targetPC != -1) { + short offset = (short)(targetPC - branchPC); + addToCodeBuffer((byte)(offset >> 8)); + addToCodeBuffer((byte)offset); + } + else { + itsLabelTable[theLabel].addFixup(branchPC + 1); + addToCodeBuffer((byte)0); + addToCodeBuffer((byte)0); + } + } + } + break; + + case ByteCode.BIPUSH : + if (DEBUG) { + if ((theOperand < -128) || (theOperand > 127)) + throw new RuntimeException("out of range byte"); + } + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)theOperand); + break; + + case ByteCode.SIPUSH : + if (DEBUG) { + if ((theOperand < -32768) || (theOperand > 32767)) + throw new RuntimeException("out of range short"); + } + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)(theOperand >> 8)); + addToCodeBuffer((byte)theOperand); + break; + + case ByteCode.NEWARRAY : + if (DEBUG) { + if ((theOperand < 0) || (theOperand > 255)) + throw new RuntimeException("out of range index"); + } + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)theOperand); + break; + + case ByteCode.GETFIELD : + case ByteCode.PUTFIELD : + if (DEBUG) { + if ((theOperand < 0) || (theOperand > 65535)) + throw new RuntimeException("out of range field"); + } + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)(theOperand >> 8)); + addToCodeBuffer((byte)theOperand); + break; + + case ByteCode.LDC : + case ByteCode.LDC_W : + case ByteCode.LDC2_W : + if (DEBUG) { + if ((theOperand < 0) || (theOperand > 65535)) + throw new RuntimeException("out of range index"); + } + if ((theOperand >= 256) + || (theOpCode == ByteCode.LDC_W) + || (theOpCode == ByteCode.LDC2_W)) { + if (theOpCode == ByteCode.LDC) + addToCodeBuffer(ByteCode.LDC_W); + else + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)(theOperand >> 8)); + addToCodeBuffer((byte)theOperand); + } + else { + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)theOperand); + } + break; + + case ByteCode.RET : + case ByteCode.ILOAD : + case ByteCode.LLOAD : + case ByteCode.FLOAD : + case ByteCode.DLOAD : + case ByteCode.ALOAD : + case ByteCode.ISTORE : + case ByteCode.LSTORE : + case ByteCode.FSTORE : + case ByteCode.DSTORE : + case ByteCode.ASTORE : + if (DEBUG) { + if ((theOperand < 0) || (theOperand > 65535)) + throw new RuntimeException("out of range variable"); + } + if (theOperand >= 256) { + addToCodeBuffer(ByteCode.WIDE); + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)(theOperand >> 8)); + addToCodeBuffer((byte)theOperand); + } + else { + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)theOperand); + } + break; + + default : + throw new RuntimeException("Unexpected opcode for 1 operand"); + } + } + + public void addLoadConstant(int k) + { + add(ByteCode.LDC, itsConstantPool.addConstant(k)); + } + + public void addLoadConstant(long k) + { + add(ByteCode.LDC2_W, itsConstantPool.addConstant(k)); + } + + public void addLoadConstant(float k) + { + add(ByteCode.LDC, itsConstantPool.addConstant(k)); + } + + public void addLoadConstant(double k) + { + add(ByteCode.LDC2_W, itsConstantPool.addConstant(k)); + } + + public void addLoadConstant(String k) + { + add(ByteCode.LDC, itsConstantPool.addConstant(k)); + } + + public void add(byte theOpCode, int theOperand1, int theOperand2) + { + if (DEBUGCODE) + System.out.println("Add " + Integer.toHexString(theOpCode & 0xFF) + + ", " + Integer.toHexString(theOperand1) + + ", " + Integer.toHexString(theOperand2)); + itsStackTop += ByteCode.stackChange[theOpCode & 0xFF]; + if (DEBUGSTACK) { + System.out.println("After " + Integer.toHexString(theOpCode & 0xFF) + " stack = " + itsStackTop); + } + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("Stack underflow"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + + if (theOpCode == ByteCode.IINC) { + if (DEBUG) { + if ((theOperand1 < 0) || (theOperand1 > 65535)) + throw new RuntimeException("out of range variable"); + if ((theOperand2 < -32768) || (theOperand2 > 32767)) + throw new RuntimeException("out of range increment"); + } + if ((theOperand1 > 255) + || (theOperand2 < -128) || (theOperand2 > 127)) { + addToCodeBuffer(ByteCode.WIDE); + addToCodeBuffer(ByteCode.IINC); + addToCodeBuffer((byte)(theOperand1 >> 8)); + addToCodeBuffer((byte)theOperand1); + addToCodeBuffer((byte)(theOperand2 >> 8)); + addToCodeBuffer((byte)theOperand2); + } + else { + addToCodeBuffer(ByteCode.WIDE); + addToCodeBuffer(ByteCode.IINC); + addToCodeBuffer((byte)theOperand1); + addToCodeBuffer((byte)theOperand2); + } + } + else { + if (theOpCode == ByteCode.MULTIANEWARRAY) { + if (DEBUG) { + if ((theOperand1 < 0) || (theOperand1 > 65535)) + throw new RuntimeException("out of range index"); + if ((theOperand2 < 0) || (theOperand2 > 255)) + throw new RuntimeException("out of range dimensions"); + } + addToCodeBuffer(ByteCode.MULTIANEWARRAY); + addToCodeBuffer((byte)(theOperand1 >> 8)); + addToCodeBuffer((byte)theOperand1); + addToCodeBuffer((byte)theOperand2); + } + else { + throw new RuntimeException("Unexpected opcode for 2 operands"); + } + } + } + + public void add(byte theOpCode, String className) + { + if (DEBUGCODE) + System.out.println("Add " + Integer.toHexString(theOpCode & 0xFF) + + ", " + className); + itsStackTop += ByteCode.stackChange[theOpCode & 0xFF]; + if (DEBUGSTACK) { + System.out.println("After " + Integer.toHexString(theOpCode & 0xFF) + " stack = " + itsStackTop); + } + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("Stack underflow"); + } + switch (theOpCode) { + case ByteCode.NEW : + case ByteCode.ANEWARRAY : + case ByteCode.CHECKCAST : + case ByteCode.INSTANCEOF : { + short classIndex = itsConstantPool.addClass(className); + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)(classIndex >> 8)); + addToCodeBuffer((byte)classIndex); + } + break; + + default : + throw new RuntimeException("bad opcode for class reference"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + } + + + public void add(byte theOpCode, String className, + String fieldName, String fieldType) + { + if (DEBUGCODE) + System.out.println("Add " + Integer.toHexString(theOpCode & 0xFF) + + ", " + className + ", " + fieldName + ", " + fieldType); + itsStackTop += ByteCode.stackChange[theOpCode & 0xFF]; + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("After " + Integer.toHexString(theOpCode & 0xFF) + " Stack underflow"); + } + char fieldTypeChar = fieldType.charAt(0); + int fieldSize = ((fieldTypeChar == 'J') + || (fieldTypeChar == 'D')) ? 2 : 1; + switch (theOpCode) { + case ByteCode.GETFIELD : + case ByteCode.GETSTATIC : + itsStackTop += fieldSize; + break; + case ByteCode.PUTSTATIC : + case ByteCode.PUTFIELD : + itsStackTop -= fieldSize; + break; + default : + throw new RuntimeException("bad opcode for field reference"); + } + short fieldRefIndex = itsConstantPool.addFieldRef(className, + fieldName, fieldType); + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)(fieldRefIndex >> 8)); + addToCodeBuffer((byte)fieldRefIndex); + + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + if (DEBUGSTACK) { + System.out.println("After " + Integer.toHexString(theOpCode & 0xFF) + " stack = " + itsStackTop); + } + } + + /* + Really weird. Returns an int with # parameters in hi 16 bits, and + # slots occupied by parameters in the low 16 bits. If Java really + supported references we wouldn't have to be this perverted. + */ + public int sizeOfParameters(String pString) + { + if (DEBUG) { + if (pString.charAt(0) != '(') + throw new RuntimeException("Bad parameter signature"); + } + int index = 1; + int size = 0; + int count = 0; + while (pString.charAt(index) != ')') { + switch (pString.charAt(index)) { + case 'J' : + case 'D' : + size++; + // fall thru + case 'B' : + case 'S' : + case 'C' : + case 'I' : + case 'Z' : + case 'F' : + size++; + count++; + index++; + break; + case '[' : + while (pString.charAt(index) == '[') index++; + if (pString.charAt(index) != 'L') { + size++; + count++; + index++; + break; + } + // fall thru + case 'L' : + size++; + count++; + while (pString.charAt(index++) != ';') ; + break; + default : + throw new RuntimeException("Bad signature character"); + } + } + return ((count << 16) | size); + } + + public void add(byte theOpCode, String className, String methodName, + String parametersType, String returnType) + { + if (DEBUGCODE) + System.out.println("Add " + Integer.toHexString(theOpCode & 0xFF) + + ", " + className + ", " + methodName + ", " + parametersType + ", " + returnType); + int parameterInfo = sizeOfParameters(parametersType); + itsStackTop -= (parameterInfo & 0xFFFF); + itsStackTop += ByteCode.stackChange[theOpCode & 0xFF]; // adjusts for 'this' + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("After " + Integer.toHexString(theOpCode & 0xFF) + " Stack underflow"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + + switch (theOpCode) { + case ByteCode.INVOKEVIRTUAL : + case ByteCode.INVOKESPECIAL : + case ByteCode.INVOKESTATIC : + case ByteCode.INVOKEINTERFACE : { + char returnTypeChar = returnType.charAt(0); + if (returnTypeChar != 'V') + if ((returnTypeChar == 'J') || (returnTypeChar == 'D')) + itsStackTop += 2; + else + itsStackTop++; + addToCodeBuffer(theOpCode); + if (theOpCode == ByteCode.INVOKEINTERFACE) { + short ifMethodRefIndex + = itsConstantPool.addInterfaceMethodRef( + className, methodName, + parametersType + returnType); + addToCodeBuffer((byte)(ifMethodRefIndex >> 8)); + addToCodeBuffer((byte)ifMethodRefIndex); + addToCodeBuffer((byte)((parameterInfo >> 16) + 1)); + addToCodeBuffer((byte)0); + } + else { + short methodRefIndex = itsConstantPool.addMethodRef( + className, methodName, + parametersType + returnType); + addToCodeBuffer((byte)(methodRefIndex >> 8)); + addToCodeBuffer((byte)methodRefIndex); + } + } + break; + + default : + throw new RuntimeException("bad opcode for method reference"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + if (DEBUGSTACK) { + System.out.println("After " + Integer.toHexString(theOpCode & 0xFF) + " stack = " + itsStackTop); + } + } + + public int markLabel(int theLabel) { + return super.markLabel(theLabel, (short)itsCodeBufferTop); + } + + public int markLabel(int theLabel, short stackTop) { + itsStackTop = stackTop; + return super.markLabel(theLabel, (short)itsCodeBufferTop); + } + + public int markHandler(int theLabel) { + itsStackTop = 1; + return markLabel(theLabel); + } + + public short getStackTop() { + return itsStackTop; + } + + public void adjustStackTop(int delta) { + itsStackTop += delta; + if (DEBUGSTACK) { + System.out.println("After " + "adjustStackTop("+delta+")" + " stack = " + itsStackTop); + } + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("Stack underflow"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + } + + + public void addToCodeBuffer(byte b) + { + if (DEBUG) { + if (itsCurrentMethod == null) + throw new RuntimeException("No method to add to"); + } + if (itsCodeBuffer == null) { + itsCodeBuffer = new byte[CodeBufferSize]; + itsCodeBuffer[0] = b; + itsCodeBufferTop = 1; + } + else { + if (itsCodeBufferTop == itsCodeBuffer.length) { + byte currentBuffer[] = itsCodeBuffer; + itsCodeBuffer = new byte[itsCodeBufferTop * 2]; + System.arraycopy(currentBuffer, 0, itsCodeBuffer, + 0, itsCodeBufferTop); + } + itsCodeBuffer[itsCodeBufferTop++] = b; + } + } + + public void addField(String fieldName, String type, short flags) + { + short fieldNameIndex = itsConstantPool.addUtf8(fieldName); + short typeIndex = itsConstantPool.addUtf8(type); + itsFields.addElement( + new ClassFileField(fieldNameIndex, typeIndex, flags)); + } + + public void addField(String fieldName, String type, short flags, int value) + { + short fieldNameIndex = itsConstantPool.addUtf8(fieldName); + short typeIndex = itsConstantPool.addUtf8(type); + short cvAttr[] = new short[4]; + cvAttr[0] = itsConstantPool.addUtf8("ConstantValue"); + cvAttr[1] = 0; + cvAttr[2] = 2; + cvAttr[3] = itsConstantPool.addConstant(value); + itsFields.addElement( + new ClassFileField(fieldNameIndex, typeIndex, flags, cvAttr)); + } + + public void addField(String fieldName, String type, short flags, long value) + { + short fieldNameIndex = itsConstantPool.addUtf8(fieldName); + short typeIndex = itsConstantPool.addUtf8(type); + short cvAttr[] = new short[4]; + cvAttr[0] = itsConstantPool.addUtf8("ConstantValue"); + cvAttr[1] = 0; + cvAttr[2] = 2; + cvAttr[3] = itsConstantPool.addConstant(value); + itsFields.addElement( + new ClassFileField(fieldNameIndex, typeIndex, flags, cvAttr)); + } + + public void addField(String fieldName, String type, short flags, double value) + { + short fieldNameIndex = itsConstantPool.addUtf8(fieldName); + short typeIndex = itsConstantPool.addUtf8(type); + short cvAttr[] = new short[4]; + cvAttr[0] = itsConstantPool.addUtf8("ConstantValue"); + cvAttr[1] = 0; + cvAttr[2] = 2; + cvAttr[3] = itsConstantPool.addConstant(value); + itsFields.addElement( + new ClassFileField(fieldNameIndex, typeIndex, flags, cvAttr)); + } + + static final int ExceptionTableSize = 4; + + public void addExceptionHandler(int startLabel, int endLabel, + int handlerLabel, String catchClassName) + { + if ((startLabel & 0x80000000) != 0x80000000) + throw new RuntimeException("Bad startLabel"); + if ((endLabel & 0x80000000) != 0x80000000) + throw new RuntimeException("Bad endLabel"); + if ((handlerLabel & 0x80000000) != 0x80000000) + throw new RuntimeException("Bad handlerLabel"); + + /* + * if catchClassName is null, use 0 for the catch_type_index; which means + * catch everything. (Even when the verifier has let you throw something other + * than a Throwable.) + */ + ExceptionTableEntry newEntry + = new ExceptionTableEntry( + startLabel, + endLabel, + handlerLabel, + catchClassName == null + ? 0 + : itsConstantPool.addClass(catchClassName)); + + if (itsExceptionTable == null) { + itsExceptionTable = new ExceptionTableEntry[ExceptionTableSize]; + itsExceptionTable[0] = newEntry; + itsExceptionTableTop = 1; + } + else { + if (itsExceptionTableTop == itsExceptionTable.length) { + ExceptionTableEntry oldTable[] = itsExceptionTable; + itsExceptionTable = new ExceptionTableEntry + [itsExceptionTableTop * 2]; + System.arraycopy(oldTable, 0, itsExceptionTable, + 0, itsExceptionTableTop); + } + itsExceptionTable[itsExceptionTableTop++] = newEntry; + } + + } + + public void startMethod(String methodName, String type, short flags) + { + short methodNameIndex = itsConstantPool.addUtf8(methodName); + short typeIndex = itsConstantPool.addUtf8(type); + itsCurrentMethod = new ClassFileMethod(methodNameIndex, typeIndex, + flags); + itsMethods.addElement(itsCurrentMethod); + } + + public void stopMethod(short maxLocals, VariableTable vars) + { + if (DEBUG) { + if (itsCurrentMethod == null) + throw new RuntimeException("No method to stop"); + } + + for (int i = 0; i < itsLabelTableTop; i++) + itsLabelTable[i].fixGotos(itsCodeBuffer); + + itsMaxLocals = maxLocals; + + int lineNumberTableLength = 0; + if (itsLineNumberTable != null) { + // 6 bytes for the attribute header + // 2 bytes for the line number count + // 4 bytes for each entry + lineNumberTableLength = 6 + 2 + (itsLineNumberTableTop * 4); + } + + int variableTableLength = 0; + if (vars != null) { + // 6 bytes for the attribute header + // 2 bytes for the variable count + // 10 bytes for each entry + variableTableLength = 6 + 2 + (vars.size() * 10); + } + + int attrLength = 2 + // attribute_name_index + 4 + // attribute_length + 2 + // max_stack + 2 + // max_locals + 4 + // code_length + itsCodeBufferTop + + 2 + // exception_table_length + (itsExceptionTableTop * 8) + + 2 + // attributes_count + lineNumberTableLength + + variableTableLength; + + byte codeAttribute[] = new byte[attrLength]; + int index = 0; + int codeAttrIndex = itsConstantPool.addUtf8("Code"); + codeAttribute[index++] = (byte)(codeAttrIndex >> 8); + codeAttribute[index++] = (byte)codeAttrIndex; + attrLength -= 6; // discount the attribute header + codeAttribute[index++] = (byte)(attrLength >> 24); + codeAttribute[index++] = (byte)(attrLength >> 16); + codeAttribute[index++] = (byte)(attrLength >> 8); + codeAttribute[index++] = (byte)attrLength; + codeAttribute[index++] = (byte)(itsMaxStack >> 8); + codeAttribute[index++] = (byte)itsMaxStack; + codeAttribute[index++] = (byte)(itsMaxLocals >> 8); + codeAttribute[index++] = (byte)itsMaxLocals; + codeAttribute[index++] = (byte)(itsCodeBufferTop >> 24); + codeAttribute[index++] = (byte)(itsCodeBufferTop >> 16); + codeAttribute[index++] = (byte)(itsCodeBufferTop >> 8); + codeAttribute[index++] = (byte)itsCodeBufferTop; + System.arraycopy(itsCodeBuffer, 0, codeAttribute, index, + itsCodeBufferTop); + index += itsCodeBufferTop; + + + if (itsExceptionTableTop > 0) { + codeAttribute[index++] = (byte)(itsExceptionTableTop >> 8); + codeAttribute[index++] = (byte)(itsExceptionTableTop); + for (int i = 0; i < itsExceptionTableTop; i++) { + short startPC = itsExceptionTable[i].getStartPC(itsLabelTable); + codeAttribute[index++] = (byte)(startPC >> 8); + codeAttribute[index++] = (byte)(startPC); + short endPC = itsExceptionTable[i].getEndPC(itsLabelTable); + codeAttribute[index++] = (byte)(endPC >> 8); + codeAttribute[index++] = (byte)(endPC); + short handlerPC = itsExceptionTable[i].getHandlerPC(itsLabelTable); + codeAttribute[index++] = (byte)(handlerPC >> 8); + codeAttribute[index++] = (byte)(handlerPC); + short catchType = itsExceptionTable[i].getCatchType(); + codeAttribute[index++] = (byte)(catchType >> 8); + codeAttribute[index++] = (byte)(catchType); + } + } + else { + codeAttribute[index++] = (byte)(0); // exception table length + codeAttribute[index++] = (byte)(0); + } + + int attributeCount = 0; + if (itsLineNumberTable != null) + attributeCount++; + if (vars != null) + attributeCount++; + codeAttribute[index++] = (byte)(0); // (hibyte) attribute count... + codeAttribute[index++] = (byte)(attributeCount); // (lobyte) attribute count + + if (itsLineNumberTable != null) { + int lineNumberTableAttrIndex + = itsConstantPool.addUtf8("LineNumberTable"); + codeAttribute[index++] = (byte)(lineNumberTableAttrIndex >> 8); + codeAttribute[index++] = (byte)lineNumberTableAttrIndex; + int tableAttrLength = 2 + (itsLineNumberTableTop * 4); + codeAttribute[index++] = (byte)(tableAttrLength >> 24); + codeAttribute[index++] = (byte)(tableAttrLength >> 16); + codeAttribute[index++] = (byte)(tableAttrLength >> 8); + codeAttribute[index++] = (byte)tableAttrLength; + codeAttribute[index++] = (byte)(itsLineNumberTableTop >> 8); + codeAttribute[index++] = (byte)itsLineNumberTableTop; + for (int i = 0; i < itsLineNumberTableTop; i++) { + codeAttribute[index++] = (byte)(itsLineNumberTable[i] >> 24); + codeAttribute[index++] = (byte)(itsLineNumberTable[i] >> 16); + codeAttribute[index++] = (byte)(itsLineNumberTable[i] >> 8); + codeAttribute[index++] = (byte)itsLineNumberTable[i]; + } + } + + if (vars != null) { + int variableTableAttrIndex + = itsConstantPool.addUtf8("LocalVariableTable"); + codeAttribute[index++] = (byte)(variableTableAttrIndex >> 8); + codeAttribute[index++] = (byte)variableTableAttrIndex; + int varCount = vars.size(); + int tableAttrLength = 2 + (varCount * 10); + codeAttribute[index++] = (byte)(tableAttrLength >> 24); + codeAttribute[index++] = (byte)(tableAttrLength >> 16); + codeAttribute[index++] = (byte)(tableAttrLength >> 8); + codeAttribute[index++] = (byte)tableAttrLength; + codeAttribute[index++] = (byte)(varCount >> 8); + codeAttribute[index++] = (byte)varCount; + for (int i = 0; i < varCount; i++) { + LocalVariable lvar = vars.get(i); + // start pc + int startPc = lvar.getStartPC(); + codeAttribute[index++] = (byte)(startPc >> 8); + codeAttribute[index++] = (byte)startPc; + + // length + int length = itsCodeBufferTop - startPc; + codeAttribute[index++] = (byte)(length >> 8); + codeAttribute[index++] = (byte)length; + + // name index + int nameIndex + = itsConstantPool.addUtf8(lvar.getName()); + codeAttribute[index++] = (byte)(nameIndex >> 8); + codeAttribute[index++] = (byte)nameIndex; + + // descriptor index + int descriptorIndex = itsConstantPool.addUtf8( + lvar.isNumber() + ? "D" + : "Ljava/lang/Object;"); + codeAttribute[index++] = (byte)(descriptorIndex >> 8); + codeAttribute[index++] = (byte)descriptorIndex; + + // index + int jreg = lvar.getJRegister(); + codeAttribute[index++] = (byte)(jreg >> 8); + codeAttribute[index++] = (byte)jreg; + } + } + + itsCurrentMethod.setCodeAttribute(codeAttribute); + + itsExceptionTable = null; + itsExceptionTableTop = 0; + itsLabelTableTop = 0; + itsLineNumberTable = null; + itsCodeBufferTop = 0; + itsCurrentMethod = null; + itsMaxStack = 0; + itsStackTop = 0; + } + + private static final int LineNumberTableSize = 16; + + public void addLineNumberEntry(short lineNumber) + { + if (DEBUG) { + if (itsCurrentMethod == null) + throw new RuntimeException("No method to stop"); + } + + if (itsLineNumberTable == null) { + itsLineNumberTable = new int[LineNumberTableSize]; + itsLineNumberTable[0] = (itsCodeBufferTop << 16) + lineNumber; + itsLineNumberTableTop = 1; + } + else { + if (itsLineNumberTableTop == itsLineNumberTable.length) { + int[] oldTable = itsLineNumberTable; + itsLineNumberTable = new int[itsLineNumberTableTop * 2]; + System.arraycopy(oldTable, 0, itsLineNumberTable, + 0, itsLineNumberTableTop); + } + itsLineNumberTable[itsLineNumberTableTop++] + = (itsCodeBufferTop << 16) + lineNumber; + } + } + + public void write(OutputStream oStream) throws IOException + { + DataOutputStream out = new DataOutputStream(oStream); + + short sourceFileAttributeNameIndex = 0; + if (itsSourceFileNameIndex != 0) + sourceFileAttributeNameIndex + = itsConstantPool.addUtf8("SourceFile"); + + out.writeLong(FileHeaderConstant); + itsConstantPool.write(out); + out.writeShort(itsFlags); + out.writeShort(itsThisClassIndex); + out.writeShort(itsSuperClassIndex); + out.writeShort(itsInterfaces.size()); + for (int i = 0; i < itsInterfaces.size(); i++) { + out.writeShort(((Short)(itsInterfaces.elementAt(i))).shortValue()); + } + out.writeShort(itsFields.size()); + for (int i = 0; i < itsFields.size(); i++) { + ((ClassFileField)(itsFields.elementAt(i))).write(out); + } + out.writeShort(itsMethods.size()); + for (int i = 0; i < itsMethods.size(); i++) { + ((ClassFileMethod)(itsMethods.elementAt(i))).write(out); + } + if (itsSourceFileNameIndex != 0) { + out.writeShort(1); // attributes count + out.writeShort(sourceFileAttributeNameIndex); + out.writeInt(2); + out.writeShort(itsSourceFileNameIndex); + } + else + out.writeShort(0); // no attributes + } + + /* + TODO: fix reference + public void saveStartPC(OptLocalVariable var) { + var.setStartPC(itsCodeBufferTop); + } + */ + + private ExceptionTableEntry itsExceptionTable[]; + private int itsExceptionTableTop; + + private int itsLineNumberTable[]; // pack start_pc & line_number together + private int itsLineNumberTableTop; + + private byte itsCodeBuffer[]; + private int itsCodeBufferTop; + + private ConstantPool itsConstantPool; + + private short itsSourceFileAttributeIndex; + + private ClassFileMethod itsCurrentMethod; + private short itsStackTop; + + private short itsMaxStack; + private short itsMaxLocals; + + private Vector itsMethods = new Vector(); + private Vector itsFields = new Vector(); + private Vector itsInterfaces = new Vector(); + + private short itsFlags; + private short itsThisClassIndex; + private short itsSuperClassIndex; + private short itsSourceFileNameIndex; + +} + +class ExceptionTableEntry { + + ExceptionTableEntry(int startLabel, int endLabel, + int handlerLabel, short catchType) + { + itsStartLabel = startLabel; + itsEndLabel = endLabel; + itsHandlerLabel = handlerLabel; + itsCatchType = catchType; + } + + short getStartPC(Label labelTable[]) + { + short pc = labelTable[itsStartLabel & 0x7FFFFFFF].getPC(); + if (pc == -1) + throw new RuntimeException("start label not defined"); + return pc; + } + + short getEndPC(Label labelTable[]) + { + short pc = labelTable[itsEndLabel & 0x7FFFFFFF].getPC(); + if (pc == -1) + throw new RuntimeException("end label not defined"); + return pc; + } + + short getHandlerPC(Label labelTable[]) + { + short pc = labelTable[itsHandlerLabel & 0x7FFFFFFF].getPC(); + if (pc == -1) + throw new RuntimeException("handler label not defined"); + return pc; + } + + short getCatchType() + { + return itsCatchType; + } + + private int itsStartLabel; + private int itsEndLabel; + private int itsHandlerLabel; + private short itsCatchType; +} + +class ClassFileField { + + ClassFileField(short nameIndex, short typeIndex, short flags) + { + itsNameIndex = nameIndex; + itsTypeIndex = typeIndex; + itsFlags = flags; + } + + ClassFileField(short nameIndex, short typeIndex, short flags, short cvAttr[]) + { + itsNameIndex = nameIndex; + itsTypeIndex = typeIndex; + itsFlags = flags; + itsAttr = cvAttr; + } + + void write(DataOutputStream out) throws IOException + { + out.writeShort(itsFlags); + out.writeShort(itsNameIndex); + out.writeShort(itsTypeIndex); + if (itsAttr == null) + out.writeShort(0); // no attributes + else { + out.writeShort(1); + out.writeShort(itsAttr[0]); + out.writeShort(itsAttr[1]); + out.writeShort(itsAttr[2]); + out.writeShort(itsAttr[3]); + } + } + + private short itsNameIndex; + private short itsTypeIndex; + private short itsFlags; + private short itsAttr[]; +} + +class ClassFileMethod { + + ClassFileMethod(short nameIndex, short typeIndex, short flags) + { + itsNameIndex = nameIndex; + itsTypeIndex = typeIndex; + itsFlags = flags; + } + + void setCodeAttribute(byte codeAttribute[]) + { + itsCodeAttribute = codeAttribute; + } + + void write(DataOutputStream out) throws IOException + { + out.writeShort(itsFlags); + out.writeShort(itsNameIndex); + out.writeShort(itsTypeIndex); + out.writeShort(1); // Code attribute only + out.write(itsCodeAttribute, 0, itsCodeAttribute.length); + } + + private short itsNameIndex; + private short itsTypeIndex; + private short itsFlags; + private byte[] itsCodeAttribute; + +} + +class ConstantPool { + + ConstantPool() + { + itsTopIndex = 1; // the zero'th entry is reserved + itsPool = new byte[ConstantPoolSize]; + itsTop = 0; + } + + private static final int ConstantPoolSize = 256; + private static final byte + CONSTANT_Class = 7, + CONSTANT_Fieldref = 9, + CONSTANT_Methodref = 10, + CONSTANT_InterfaceMethodref = 11, + CONSTANT_String = 8, + CONSTANT_Integer = 3, + CONSTANT_Float = 4, + CONSTANT_Long = 5, + CONSTANT_Double = 6, + CONSTANT_NameAndType = 12, + CONSTANT_Utf8 = 1; + + void write(DataOutputStream out) throws IOException + { + out.writeShort((short)(itsTopIndex)); + out.write(itsPool, 0, itsTop); + } + + short addConstant(int k) + { + ensure(5); + itsPool[itsTop++] = CONSTANT_Integer; + itsPool[itsTop++] = (byte)(k >> 24); + itsPool[itsTop++] = (byte)(k >> 16); + itsPool[itsTop++] = (byte)(k >> 8); + itsPool[itsTop++] = (byte)k; + return (short)(itsTopIndex++); + } + + short addConstant(long k) + { + ensure(9); + itsPool[itsTop++] = CONSTANT_Long; + itsPool[itsTop++] = (byte)(k >> 56); + itsPool[itsTop++] = (byte)(k >> 48); + itsPool[itsTop++] = (byte)(k >> 40); + itsPool[itsTop++] = (byte)(k >> 32); + itsPool[itsTop++] = (byte)(k >> 24); + itsPool[itsTop++] = (byte)(k >> 16); + itsPool[itsTop++] = (byte)(k >> 8); + itsPool[itsTop++] = (byte)k; + short index = (short)(itsTopIndex); + itsTopIndex += 2; + return index; + } + + short addConstant(float k) + { + ensure(5); + itsPool[itsTop++] = CONSTANT_Float; + int bits = Float.floatToIntBits(k); + itsPool[itsTop++] = (byte)(bits >> 24); + itsPool[itsTop++] = (byte)(bits >> 16); + itsPool[itsTop++] = (byte)(bits >> 8); + itsPool[itsTop++] = (byte)bits; + return (short)(itsTopIndex++); + } + + short addConstant(double k) + { + ensure(9); + itsPool[itsTop++] = CONSTANT_Double; + long bits = Double.doubleToLongBits(k); + itsPool[itsTop++] = (byte)(bits >> 56); + itsPool[itsTop++] = (byte)(bits >> 48); + itsPool[itsTop++] = (byte)(bits >> 40); + itsPool[itsTop++] = (byte)(bits >> 32); + itsPool[itsTop++] = (byte)(bits >> 24); + itsPool[itsTop++] = (byte)(bits >> 16); + itsPool[itsTop++] = (byte)(bits >> 8); + itsPool[itsTop++] = (byte)bits; + short index = (short)(itsTopIndex); + itsTopIndex += 2; + return index; + } + + short addConstant(String k) + { + Utf8StringIndexPair theIndex = (Utf8StringIndexPair)(itsUtf8Hash.get(k)); + if (theIndex == null) { + addUtf8(k); + theIndex = (Utf8StringIndexPair)(itsUtf8Hash.get(k)); // OPT + } + if (theIndex.itsStringIndex == -1) { + theIndex.itsStringIndex = (short)(itsTopIndex++); + ensure(3); + itsPool[itsTop++] = CONSTANT_String; + itsPool[itsTop++] = (byte)(theIndex.itsUtf8Index >> 8); + itsPool[itsTop++] = (byte)theIndex.itsUtf8Index; + } + return theIndex.itsStringIndex; + } + + short addUtf8(String contents) + { + Utf8StringIndexPair theIndex = (Utf8StringIndexPair)(itsUtf8Hash.get(contents)); + if (theIndex == null) { + theIndex = new Utf8StringIndexPair((short)(itsTopIndex++), (short)(-1)); + itsUtf8Hash.put(contents, theIndex); + try { + // using DataOutputStream.writeUTF is a lot faster than String.getBytes("UTF8") + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + dos.writeUTF(contents); + byte theBytes[] = baos.toByteArray(); + ensure(1 + theBytes.length); + itsPool[itsTop++] = CONSTANT_Utf8; + System.arraycopy(theBytes, 0, itsPool, itsTop, theBytes.length); + itsTop += theBytes.length; + } + catch (IOException iox) { + throw WrappedException.wrapException(iox); + } + } + return theIndex.itsUtf8Index; + } + + short addNameAndType(short nameIndex, short typeIndex) + { + ensure(5); + itsPool[itsTop++] = CONSTANT_NameAndType; + itsPool[itsTop++] = (byte)(nameIndex >> 8); + itsPool[itsTop++] = (byte)(nameIndex); + itsPool[itsTop++] = (byte)(typeIndex >> 8); + itsPool[itsTop++] = (byte)(typeIndex); + return (short)(itsTopIndex++); + } + + short addClass(short classIndex) + { + Short classIndexKey = new Short(classIndex); + Short theIndex = (Short)(itsClassHash.get(classIndexKey)); + if (theIndex == null) { + ensure(3); + itsPool[itsTop++] = CONSTANT_Class; + itsPool[itsTop++] = (byte)(classIndex >> 8); + itsPool[itsTop++] = (byte)(classIndex); + theIndex = new Short((short)(itsTopIndex++)); + itsClassHash.put(classIndexKey, theIndex); + } + return theIndex.shortValue(); + } + + short addClass(String className) + { + short classIndex + = addUtf8(ClassFileWriter.fullyQualifiedForm(className)); + return addClass(classIndex); + } + + short addFieldRef(String className, String fieldName, String fieldType) + { + String fieldRefString = className + " " + fieldName + " " + fieldType; + Short theIndex = (Short)(itsFieldRefHash.get(fieldRefString)); + if (theIndex == null) { + short nameIndex = addUtf8(fieldName); + short typeIndex = addUtf8(fieldType); + short ntIndex = addNameAndType(nameIndex, typeIndex); + short classIndex = addClass(className); + ensure(5); + itsPool[itsTop++] = CONSTANT_Fieldref; + itsPool[itsTop++] = (byte)(classIndex >> 8); + itsPool[itsTop++] = (byte)(classIndex); + itsPool[itsTop++] = (byte)(ntIndex >> 8); + itsPool[itsTop++] = (byte)(ntIndex); + theIndex = new Short((short)(itsTopIndex++)); + itsFieldRefHash.put(fieldRefString, theIndex); + } + return theIndex.shortValue(); + } + + short addMethodRef(String className, String methodName, String fieldType) + { + String methodRefString = className + " " + methodName + " " + fieldType; + Short theIndex = (Short)(itsMethodRefHash.get(methodRefString)); + if (theIndex == null) { + short nameIndex = addUtf8(methodName); + short typeIndex = addUtf8(fieldType); + short ntIndex = addNameAndType(nameIndex, typeIndex); + short classIndex = addClass(className); + ensure(5); + itsPool[itsTop++] = CONSTANT_Methodref; + itsPool[itsTop++] = (byte)(classIndex >> 8); + itsPool[itsTop++] = (byte)(classIndex); + itsPool[itsTop++] = (byte)(ntIndex >> 8); + itsPool[itsTop++] = (byte)(ntIndex); + theIndex = new Short((short)(itsTopIndex++)); + itsMethodRefHash.put(methodRefString, theIndex); + } + return theIndex.shortValue(); + } + + short addInterfaceMethodRef(String className, + String methodName, String methodType) + { + short nameIndex = addUtf8(methodName); + short typeIndex = addUtf8(methodType); + short ntIndex = addNameAndType(nameIndex, typeIndex); + short classIndex = addClass(className); + ensure(5); + itsPool[itsTop++] = CONSTANT_InterfaceMethodref; + itsPool[itsTop++] = (byte)(classIndex >> 8); + itsPool[itsTop++] = (byte)(classIndex); + itsPool[itsTop++] = (byte)(ntIndex >> 8); + itsPool[itsTop++] = (byte)(ntIndex); + return (short)(itsTopIndex++); + } + + void ensure(int howMuch) + { + while ((itsTop + howMuch) >= itsPool.length) { + byte oldPool[] = itsPool; + itsPool = new byte[itsPool.length * 2]; + System.arraycopy(oldPool, 0, itsPool, 0, itsTop); + } + } + + private Hashtable itsUtf8Hash = new Hashtable(); + private Hashtable itsFieldRefHash = new Hashtable(); + private Hashtable itsMethodRefHash = new Hashtable(); + private Hashtable itsClassHash = new Hashtable(); + + private int itsTop; + private int itsTopIndex; + private byte itsPool[]; +} + +class Utf8StringIndexPair { + + Utf8StringIndexPair(short utf8Index, short stringIndex) + { + itsUtf8Index = utf8Index; + itsStringIndex = stringIndex; + } + + short itsUtf8Index; + short itsStringIndex; +} + diff --git a/js/rhino/org/mozilla/javascript/Context.java b/js/rhino/org/mozilla/javascript/Context.java index 99e76c69f336..878661d27768 100644 --- a/js/rhino/org/mozilla/javascript/Context.java +++ b/js/rhino/org/mozilla/javascript/Context.java @@ -474,7 +474,8 @@ public final class Context { "NativeNumber", "NativeDate", "NativeMath", "NativeCall", "NativeClosure", "NativeWith", - "regexp.NativeRegExp", "NativeScript" + "regexp.NativeRegExp", "NativeScript", + "JavaAdapter" }; for (int i=0; i < classes.length; i++) { try { @@ -488,9 +489,6 @@ public final class Context { // This creates the Packages and java package roots. NativeJavaPackage.init(scope); - - // Define JavaAdapter class if possible. - getCompiler().defineJavaAdapter(scope); } // All of these exceptions should not occur since we are initializing // from known classes diff --git a/js/rhino/org/mozilla/javascript/Interpreter.java b/js/rhino/org/mozilla/javascript/Interpreter.java index 6d99f5f15d23..7c5a8046ed06 100644 --- a/js/rhino/org/mozilla/javascript/Interpreter.java +++ b/js/rhino/org/mozilla/javascript/Interpreter.java @@ -53,19 +53,7 @@ public class Interpreter extends LabelTable { } return generateScriptICode(cx, scope, tree, securityDomain); } - - public void defineJavaAdapter(Scriptable scope) { - // do nothing; only the code generator can define the JavaAdapter - try { - String adapterName = System.getProperty("org.mozilla.javascript.JavaAdapter"); - if (adapterName != null) { - Class adapterClass = Class.forName(adapterName); - ScriptableObject.defineClass(scope, adapterClass); - } - } catch (Exception e) { - } - } - + private void generateICodeFromTree(Node tree, VariableTable varTable, boolean needsActivation, diff --git a/js/rhino/org/mozilla/javascript/JavaAdapter.java b/js/rhino/org/mozilla/javascript/JavaAdapter.java new file mode 100644 index 000000000000..273e14de5fc1 --- /dev/null +++ b/js/rhino/org/mozilla/javascript/JavaAdapter.java @@ -0,0 +1,492 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package org.mozilla.javascript; + +import org.mozilla.classfile.*; +import java.lang.reflect.*; +import java.io.*; +import java.util.*; + +public class JavaAdapter extends ScriptableObject { + + public String getClassName() { + return "JavaAdapter"; + } + + public static Object js_JavaAdapter(Context cx, Object[] args, + Function ctorObj, boolean inNewExpr) + throws InstantiationException, NoSuchMethodException, + IllegalAccessException, InvocationTargetException, + ClassNotFoundException + { + Class superClass = Object.class; + Class[] intfs = new Class[args.length-1]; + int interfaceCount = 0; + for (int i=0; i < args.length-1; i++) { + if (!(args[i] instanceof NativeJavaClass)) { + // TODO: report error + throw new RuntimeException("expected java class object"); + } + Class c = ((NativeJavaClass) args[i]).getClassObject(); + if (!c.isInterface()) { + superClass = c; + break; + } + intfs[interfaceCount++] = c; + } + + StringBuffer sb = new StringBuffer("adapter"); + sb.append(serial++); + String genName = sb.toString(); + ClassFileWriter cfw = new ClassFileWriter(genName, + superClass.getName(), + ""); + cfw.addField("o", "Lorg/mozilla/javascript/FlattenedObject;", + ClassFileWriter.ACC_PRIVATE); + cfw.addField("self", "Lorg/mozilla/javascript/Scriptable;", + (short) (ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_FINAL)); + for (int i = 0; i < interfaceCount; i++) { + if (intfs[i] != null) + cfw.addInterface(intfs[i].getName()); + } + + generateCtor(cfw, genName, superClass); + + Hashtable generatedOverrides = new Hashtable(); + + // if abstract class was specified, then generate appropriate overrides. + for (int i = 0; i < interfaceCount; i++) { + Method[] methods = intfs[i].getMethods(); + for (int j = 0; j < methods.length; j++) { + Method method = methods[j]; + int mods = method.getModifiers(); + if (Modifier.isStatic(mods) || Modifier.isFinal(mods)) + continue; + // make sure to generate only one instance of a particular + // method/signature. + String methodKey = getMethodSignature(method); + if (! generatedOverrides.containsKey(methodKey)) { + generateOverride(cfw, genName, method); + generatedOverrides.put(methodKey, methodKey); + } + } + } + + // Now, go through the superclasses methods, checking for abstract methods + // or additional methods to override. + FlattenedObject obj = new FlattenedObject( + (Scriptable) args[args.length - 1]); + + // generate any additional overrides that the object might contain. + Method[] methods = superClass.getMethods(); + for (int j = 0; j < methods.length; j++) { + Method method = methods[j]; + int mods = method.getModifiers(); + if (Modifier.isStatic(mods) || Modifier.isFinal(mods)) + continue; + // if a method is marked abstract, must implement it or the + // resulting class won't be instantiable. otherwise, if the object + // has a property of the same name, then an override is intended. + if (Modifier.isAbstract(mods) || obj.hasProperty(method.getName())) { + // make sure to generate only one instance of a particular + // method/signature. + String methodKey = getMethodSignature(method); + if (! generatedOverrides.containsKey(methodKey)) { + generateOverride(cfw, genName, method); + generatedOverrides.put(methodKey, method); + } + } + } + + // TODO: generate Java methods, fields for remaining properties that + // are not overrides? Probably not necessary to generate methods + // that aren't overrides. + + ByteArrayOutputStream out = new ByteArrayOutputStream(512); + try { + cfw.write(out); + } + catch (IOException ioe) { + throw new RuntimeException("unexpected IOException"); + } + byte[] bytes = out.toByteArray(); + classLoader.defineClass(genName, bytes); + Class c = classLoader.loadClass(genName, true); + Class[] ctorParms = { FlattenedObject.class }; + Object[] ctorArgs = { obj }; + Object v = c.getConstructor(ctorParms).newInstance(ctorArgs); + return cx.toObject(v, ScriptableObject.getTopLevelScope(ctorObj)); + } + + /** + * Utility method, which dynamically binds a Context to the current thread, + * if none already exists. + */ + public static Object callMethod(FlattenedObject object, Object methodId, + Object[] args) + { + try { + // old way, bind a Context dynamically, unbind if it wasn't there before. + Context cx = Context.getCurrentContext(); + if (cx == null) { + cx = new Context(); + cx.enter(); + try { + return (object.hasProperty(methodId) + ? object.callMethod(methodId, args) + : Context.getUndefinedValue()); + } finally { + cx.exit(); + } + } else { + return (object.hasProperty(methodId) + ? object.callMethod(methodId, args) + : Context.getUndefinedValue()); + } + } catch (Exception ex) { + ex.printStackTrace(System.err); + throw new Error(ex.getMessage()); + } + } + + private static void generateCtor(ClassFileWriter cfw, String genName, + Class superClass) + { + cfw.startMethod("", + "(Lorg/mozilla/javascript/FlattenedObject;)V", + ClassFileWriter.ACC_PUBLIC); + + // Invoke base class constructor + cfw.add(ByteCode.ALOAD_0); // this + cfw.add(ByteCode.INVOKESPECIAL, + superClass.getName().replace('.', '/'), + "", "()", "V"); + + // save parameter in instance variable + cfw.add(ByteCode.ALOAD_0); // this + cfw.add(ByteCode.ALOAD_1); // first arg + cfw.add(ByteCode.PUTFIELD, genName, "o", + "Lorg/mozilla/javascript/FlattenedObject;"); + + // store Scriptable object in "self" a public instance variable, so scripts can read it. + cfw.add(ByteCode.ALOAD_0); // this + cfw.add(ByteCode.ALOAD_1); // first arg + cfw.add(ByteCode.INVOKEVIRTUAL, + "org/mozilla/javascript/FlattenedObject", + "getObject", "()", + "Lorg/mozilla/javascript/Scriptable;"); + cfw.add(ByteCode.PUTFIELD, genName, "self", + "Lorg/mozilla/javascript/Scriptable;"); + + cfw.add(ByteCode.RETURN); + cfw.stopMethod((short)20, null); // TODO: magic number "20" + } + + /** + * Generates code to create a java.lang.Boolean, java.lang.Character or a + * java.lang.Double to wrap the specified primitive parameter. Leaves the + * wrapper object on the top of the stack. + */ + private static int generateWrapParam(ClassFileWriter cfw, int paramOffset, + Class paramType) + { + if (paramType.equals(Boolean.TYPE)) { + // wrap boolean values with java.lang.Boolean. + cfw.add(ByteCode.NEW, "java/lang/Boolean"); + cfw.add(ByteCode.DUP); + cfw.add(ByteCode.ILOAD, paramOffset++); + cfw.add(ByteCode.INVOKESPECIAL, "java/lang/Boolean", + "", "(Z)", "V"); + } else + if (paramType.equals(Character.TYPE)) { + // Create a string of length 1 using the character parameter. + cfw.add(ByteCode.NEW, "java/lang/String"); + cfw.add(ByteCode.DUP); + cfw.add(ByteCode.ICONST_1); + cfw.add(ByteCode.NEWARRAY, ByteCode.T_CHAR); + cfw.add(ByteCode.DUP); + cfw.add(ByteCode.ICONST_0); + cfw.add(ByteCode.ILOAD, paramOffset++); + cfw.add(ByteCode.CASTORE); + cfw.add(ByteCode.INVOKESPECIAL, "java/lang/String", + "", "([C)", "V"); + } else { + // convert all numeric values to java.lang.Double. + cfw.add(ByteCode.NEW, "java/lang/Double"); + cfw.add(ByteCode.DUP); + String typeName = paramType.getName(); + switch (typeName.charAt(0)) { + case 'b': + case 's': + case 'i': + // load an int value, convert to double. + cfw.add(ByteCode.ILOAD, paramOffset++); + cfw.add(ByteCode.I2D); + break; + case 'l': + // load a long, convert to double. + cfw.add(ByteCode.LLOAD, paramOffset); + cfw.add(ByteCode.L2D); + paramOffset += 2; + break; + case 'f': + // load a float, convert to double. + cfw.add(ByteCode.FLOAD, paramOffset++); + cfw.add(ByteCode.F2D); + break; + case 'd': + cfw.add(ByteCode.DLOAD, paramOffset); + paramOffset += 2; + break; + } + cfw.add(ByteCode.INVOKESPECIAL, "java/lang/Double", + "", "(D)", "V"); + } + return paramOffset; + } + + /** + * Generates code to convert a wrapped value type to a primitive type. + * Handles unwrapping java.lang.Boolean, and java.lang.Number types. + * May need to map between char and java.lang.String as well. + * Generates the appropriate RETURN bytecode. + */ + private static void generateReturnResult(ClassFileWriter cfw, + Class retType) + { + // wrap boolean values with java.lang.Boolean, convert all other + // primitive values to java.lang.Double. + if (retType.equals(Boolean.TYPE)) { + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/Context", + "toBoolean", "(Ljava/lang/Object;)", + "Z"); + cfw.add(ByteCode.IRETURN); + } else if (retType.equals(Character.TYPE)) { + // characters are represented as strings in JavaScript. + // return the first character. + // first convert the value to a string if possible. + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/Context", + "toString", "(Ljava/lang/Object;)", + "Ljava/lang/String;"); + cfw.add(ByteCode.ICONST_0); + cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/String", "charAt", + "(I)", "C"); + cfw.add(ByteCode.IRETURN); + } else if (retType.isPrimitive()) { + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/Context", + "toNumber", "(Ljava/lang/Object;)", + "D"); + String typeName = retType.getName(); + switch (typeName.charAt(0)) { + case 'b': + case 's': + case 'i': + cfw.add(ByteCode.D2I); + cfw.add(ByteCode.IRETURN); + break; + case 'l': + cfw.add(ByteCode.D2L); + cfw.add(ByteCode.LRETURN); + break; + case 'f': + cfw.add(ByteCode.D2F); + cfw.add(ByteCode.FRETURN); + break; + case 'd': + cfw.add(ByteCode.DRETURN); + break; + default: + throw new RuntimeException("Unexpected return type " + + retType.toString()); + } + } else if (retType.equals(String.class)) { + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/Context", + "toString", "(Ljava/lang/Object;)", + "Ljava/lang/String;"); + cfw.add(ByteCode.ARETURN); + } else if (retType.equals(Scriptable.class)) { + cfw.add(ByteCode.ALOAD_0); // load 'this' to find scope from + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/Context", + "toObject", + "(Ljava/lang/Object;" + + "Lorg/mozilla/javascript/Scriptable;)", + "Lorg/mozilla/javascript/Scriptable;"); + cfw.add(ByteCode.ARETURN); + } else { + // If it is a wrapped type, cast to Wrapper and call unwrap() + cfw.add(ByteCode.DUP); + cfw.add(ByteCode.INSTANCEOF, "org/mozilla/javascript/Wrapper"); + // skip 3 for IFEQ, 3 for CHECKCAST, and 3 for INVOKEVIRTUAL + cfw.add(ByteCode.IFEQ, 9); + cfw.add(ByteCode.CHECKCAST, "org/mozilla/javascript/Wrapper"); + cfw.add(ByteCode.INVOKEVIRTUAL, + "org/mozilla/javascript/Wrapper", + "unwrap", "()", "Ljava/lang/Object;"); + // Now cast to return type + String retTypeStr = retType.getName().replace('.', '/'); + cfw.add(ByteCode.CHECKCAST, retTypeStr); + cfw.add(ByteCode.ARETURN); + } + } + + private static void generateOverride(ClassFileWriter cfw, String genName, + Method m) + { + Class[] parms = m.getParameterTypes(); + StringBuffer sb = new StringBuffer(); + sb.append('('); + short arrayLocal = 1; // includes this. + for (int i = 0; i < parms.length; i++) { + Class type = parms[i]; + appendTypeString(sb, type); + if (type.equals(Long.TYPE) || type.equals(Double.TYPE)) + arrayLocal += 2; + else + arrayLocal += 1; + } + sb.append(')'); + appendTypeString(sb, m.getReturnType()); + String methodSignature = sb.toString(); + // System.out.println("generating " + m.getName() + methodSignature); + // System.out.flush(); + cfw.startMethod(m.getName(), methodSignature, + ClassFileWriter.ACC_PUBLIC); + cfw.add(ByteCode.BIPUSH, (byte) parms.length); // > 255 parms? + cfw.add(ByteCode.ANEWARRAY, "java/lang/Object"); + cfw.add(ByteCode.ASTORE, arrayLocal); + + // allocate a local variable to store the scope used to wrap native objects. + short scopeLocal = (short) (arrayLocal + 1); + boolean loadedScope = false; + + int paramOffset = 1; + for (int i = 0; i < parms.length; i++) { + cfw.add(ByteCode.ALOAD, arrayLocal); + cfw.add(ByteCode.BIPUSH, i); + if (parms[i].isPrimitive()) { + paramOffset = generateWrapParam(cfw, paramOffset, parms[i]); + } else { + // An arbitary Java object; call Context.toObject to wrap in + // a Scriptable object + cfw.add(ByteCode.ALOAD, paramOffset++); + if (! loadedScope) { + // load this.self into a local the first time it's needed. + // it will provide the scope needed by Context.toObject(). + cfw.add(ByteCode.ALOAD_0); + cfw.add(ByteCode.GETFIELD, genName, "self", + "Lorg/mozilla/javascript/Scriptable;"); + cfw.add(ByteCode.ASTORE, scopeLocal); + loadedScope = true; + } + cfw.add(ByteCode.ALOAD, scopeLocal); + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/Context", + "toObject", + "(Ljava/lang/Object;" + + "Lorg/mozilla/javascript/Scriptable;)", + "Lorg/mozilla/javascript/Scriptable;"); + } + cfw.add(ByteCode.AASTORE); + } + + cfw.add(ByteCode.ALOAD_0); // this + cfw.add(ByteCode.GETFIELD, genName, "o", + "Lorg/mozilla/javascript/FlattenedObject;"); + + cfw.addLoadConstant(m.getName()); + cfw.add(ByteCode.ALOAD, arrayLocal); + + // go through utility method, which creates a Context to run the + // method in. + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/JavaAdapter", + "callMethod", + "(Lorg/mozilla/javascript/FlattenedObject;" + + "Ljava/lang/Object;[Ljava/lang/Object;)", + "Ljava/lang/Object;"); + + Class retType = m.getReturnType(); + if (retType.equals(Void.TYPE)) { + cfw.add(ByteCode.POP); + cfw.add(ByteCode.RETURN); + } else { + generateReturnResult(cfw, retType); + } + cfw.stopMethod((short)(scopeLocal + 1), null); + } + + /** + * Returns a fully qualified method name concatenated with its signature. + */ + private static String getMethodSignature(Method method) { + Class[] parms = method.getParameterTypes(); + StringBuffer sb = new StringBuffer(); + sb.append(method.getName()); + sb.append('('); + for (int i = 0; i < parms.length; i++) { + Class type = parms[i]; + appendTypeString(sb, type); + } + sb.append(')'); + appendTypeString(sb, method.getReturnType()); + return sb.toString(); + } + + private static StringBuffer appendTypeString(StringBuffer sb, Class type) + { + while (type.isArray()) { + sb.append('['); + type = type.getComponentType(); + } + if (type.isPrimitive()) { + if (type.equals(Boolean.TYPE)) { + sb.append('Z'); + } else + if (type.equals(Long.TYPE)) { + sb.append('J'); + } else { + String typeName = type.getName(); + sb.append(Character.toUpperCase(typeName.charAt(0))); + } + } else { + sb.append('L'); + sb.append(type.getName().replace('.', '/')); + sb.append(';'); + } + return sb; + } + + static final class MyClassLoader extends ClassLoader { + public Class defineClass(String name, byte data[]) { + return super.defineClass(name, data, 0, data.length); + } + + protected Class loadClass(String name, boolean resolve) + throws ClassNotFoundException + { + Class clazz = findLoadedClass(name); + if (clazz == null) { + ClassLoader loader = getClass().getClassLoader(); + if (loader != null) + return loader.loadClass(name); + clazz = findSystemClass(name); + } + if (resolve) + resolveClass(clazz); + return clazz; + } + + private java.util.Hashtable loaded; + } + + private static int serial; + private static MyClassLoader classLoader = new MyClassLoader(); +} diff --git a/js/rhino/org/mozilla/javascript/LocalVariable.java b/js/rhino/org/mozilla/javascript/LocalVariable.java index d455a68db5f6..5098242eca34 100644 --- a/js/rhino/org/mozilla/javascript/LocalVariable.java +++ b/js/rhino/org/mozilla/javascript/LocalVariable.java @@ -33,6 +33,28 @@ public class LocalVariable { public String getName() { return itsName; } + /** + * Return the starting PC where this variable is live, or -1 + * if it is not a Java register. + */ + public int getStartPC() { + return -1; + } + + /** + * Return the Java register number or -1 if it is not a Java register. + */ + public short getJRegister() { + return -1; + } + + /** + * Return true if the local variable is a Java register with double type. + */ + public boolean isNumber() { + return false; + } + private String itsName; private int itsIndex = -1; diff --git a/js/rhino/org/mozilla/javascript/VariableTable.java b/js/rhino/org/mozilla/javascript/VariableTable.java index 1cfbd83927fd..bd8414886ef3 100644 --- a/js/rhino/org/mozilla/javascript/VariableTable.java +++ b/js/rhino/org/mozilla/javascript/VariableTable.java @@ -112,7 +112,7 @@ public class VariableTable { itsVariables.addElement(lVar); itsVariableNames.put(vName, new Integer(index)); } - + // a list of the formal parameters and local variables protected Vector itsVariables = new Vector(); diff --git a/js/rhino/src/org/mozilla/classfile/ByteCode.java b/js/rhino/src/org/mozilla/classfile/ByteCode.java new file mode 100644 index 000000000000..0c32e39ccb32 --- /dev/null +++ b/js/rhino/src/org/mozilla/classfile/ByteCode.java @@ -0,0 +1,1044 @@ +/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights + * Reserved. + */ + +package org.mozilla.classfile; + +public class ByteCode { + + public static final byte + NOP = 0x00, + ACONST_NULL = 0x01, + ICONST_M1 = 0x02, + ICONST_0 = 0x03, + ICONST_1 = 0x04, + ICONST_2 = 0x05, + ICONST_3 = 0x06, + ICONST_4 = 0x07, + ICONST_5 = 0x08, + LCONST_0 = 0x09, + LCONST_1 = 0x0A, + FCONST_0 = 0x0B, + FCONST_1 = 0x0C, + FCONST_2 = 0x0D, + DCONST_0 = 0x0E, + DCONST_1 = 0x0F, + BIPUSH = 0x10, + SIPUSH = 0x11, + LDC = 0x12, + LDC_W = 0x13, + LDC2_W = 0x14, + ILOAD = 0x15, + LLOAD = 0x16, + FLOAD = 0x17, + DLOAD = 0x18, + ALOAD = 0x19, + ILOAD_0 = 0x1A, + ILOAD_1 = 0x1B, + ILOAD_2 = 0x1C, + ILOAD_3 = 0x1D, + LLOAD_0 = 0x1E, + LLOAD_1 = 0x1F, + LLOAD_2 = 0x20, + LLOAD_3 = 0x21, + FLOAD_0 = 0x22, + FLOAD_1 = 0x23, + FLOAD_2 = 0x24, + FLOAD_3 = 0x25, + DLOAD_0 = 0x26, + DLOAD_1 = 0x27, + DLOAD_2 = 0x28, + DLOAD_3 = 0x29, + ALOAD_0 = 0x2A, + ALOAD_1 = 0x2B, + ALOAD_2 = 0x2C, + ALOAD_3 = 0x2D, + IALOAD = 0x2E, + LALOAD = 0x2F, + FALOAD = 0x30, + DALOAD = 0x31, + AALOAD = 0x32, + BALOAD = 0x33, + CALOAD = 0x34, + SALOAD = 0x35, + ISTORE = 0x36, + LSTORE = 0x37, + FSTORE = 0x38, + DSTORE = 0x39, + ASTORE = 0x3A, + ISTORE_0 = 0x3B, + ISTORE_1 = 0x3C, + ISTORE_2 = 0x3D, + ISTORE_3 = 0x3E, + LSTORE_0 = 0x3F, + LSTORE_1 = 0x40, + LSTORE_2 = 0x41, + LSTORE_3 = 0x42, + FSTORE_0 = 0x43, + FSTORE_1 = 0x44, + FSTORE_2 = 0x45, + FSTORE_3 = 0x46, + DSTORE_0 = 0x47, + DSTORE_1 = 0x48, + DSTORE_2 = 0x49, + DSTORE_3 = 0x4A, + ASTORE_0 = 0x4B, + ASTORE_1 = 0x4C, + ASTORE_2 = 0x4D, + ASTORE_3 = 0x4E, + IASTORE = 0x4F, + LASTORE = 0x50, + FASTORE = 0x51, + DASTORE = 0x52, + AASTORE = 0x53, + BASTORE = 0x54, + CASTORE = 0x55, + SASTORE = 0x56, + POP = 0x57, + POP2 = 0x58, + DUP = 0x59, + DUP_X1 = 0x5A, + DUP_X2 = 0x5B, + DUP2 = 0x5C, + DUP2_X1 = 0x5D, + DUP2_X2 = 0x5E, + SWAP = 0x5F, + IADD = 0x60, + LADD = 0x61, + FADD = 0x62, + DADD = 0x63, + ISUB = 0x64, + LSUB = 0x65, + FSUB = 0x66, + DSUB = 0x67, + IMUL = 0x68, + LMUL = 0x69, + FMUL = 0x6A, + DMUL = 0x6B, + IDIV = 0x6C, + LDIV = 0x6D, + FDIV = 0x6E, + DDIV = 0x6F, + IREM = 0x70, + LREM = 0x71, + FREM = 0x72, + DREM = 0x73, + INEG = 0x74, + LNEG = 0x75, + FNEG = 0x76, + DNEG = 0x77, + ISHL = 0x78, + LSHL = 0x79, + ISHR = 0x7A, + LSHR = 0x7B, + IUSHR = 0x7C, + LUSHR = 0x7D, + IAND = 0x7E, + LAND = 0x7F, + IOR = (byte)0x80, + LOR = (byte)0x81, + IXOR = (byte)0x82, + LXOR = (byte)0x83, + IINC = (byte)0x84, + I2L = (byte)0x85, + I2F = (byte)0x86, + I2D = (byte)0x87, + L2I = (byte)0x88, + L2F = (byte)0x89, + L2D = (byte)0x8A, + F2I = (byte)0x8B, + F2L = (byte)0x8C, + F2D = (byte)0x8D, + D2I = (byte)0x8E, + D2L = (byte)0x8F, + D2F = (byte)0x90, + I2B = (byte)0x91, + I2C = (byte)0x92, + I2S = (byte)0x93, + LCMP = (byte)0x94, + FCMPL = (byte)0x95, + FCMPG = (byte)0x96, + DCMPL = (byte)0x97, + DCMPG = (byte)0x98, + IFEQ = (byte)0x99, + IFNE = (byte)0x9A, + IFLT = (byte)0x9B, + IFGE = (byte)0x9C, + IFGT = (byte)0x9D, + IFLE = (byte)0x9E, + IF_ICMPEQ = (byte)0x9F, + IF_ICMPNE = (byte)0xA0, + IF_ICMPLT = (byte)0xA1, + IF_ICMPGE = (byte)0xA2, + IF_ICMPGT = (byte)0xA3, + IF_ICMPLE = (byte)0xA4, + IF_ACMPEQ = (byte)0xA5, + IF_ACMPNE = (byte)0xA6, + GOTO = (byte)0xA7, + JSR = (byte)0xA8, + RET = (byte)0xA9, + TABLESWITCH = (byte)0xAA, + LOOKUPSWITCH = (byte)0xAB, + IRETURN = (byte)0xAC, + LRETURN = (byte)0xAD, + FRETURN = (byte)0xAE, + DRETURN = (byte)0xAF, + ARETURN = (byte)0xB0, + RETURN = (byte)0xB1, + GETSTATIC = (byte)0xB2, + PUTSTATIC = (byte)0xB3, + GETFIELD = (byte)0xB4, + PUTFIELD = (byte)0xB5, + INVOKEVIRTUAL = (byte)0xB6, + INVOKESPECIAL = (byte)0xB7, + INVOKESTATIC = (byte)0xB8, + INVOKEINTERFACE = (byte)0xB9, + XXXUNUSEDXXX = (byte)0xBA, + NEW = (byte)0xBB, + NEWARRAY = (byte)0xBC, + ANEWARRAY = (byte)0xBD, + ARRAYLENGTH = (byte)0xBE, + ATHROW = (byte)0xBF, + CHECKCAST = (byte)0xC0, + INSTANCEOF = (byte)0xC1, + MONITORENTER = (byte)0xC2, + MONITOREXIT = (byte)0xC3, + WIDE = (byte)0xC4, + MULTIANEWARRAY = (byte)0xC5, + IFNULL = (byte)0xC6, + IFNONNULL = (byte)0xC7, + GOTO_W = (byte)0xC8, + JSR_W = (byte)0xC9, + BREAKPOINT = (byte)0xCA, + LDC_QUICK = (byte)0xCB, + LDC_W_QUICK = (byte)0xCC, + LDC2_W_QUICK = (byte)0xCD, + GETFIELD_QUICK = (byte)0xCE, + PUTFIELD_QUICK = (byte)0xCF, + GETFIELD2_QUICK = (byte)0xD0, + PUTFIELD2_QUICK = (byte)0xD1, + GETSTATIC_QUICK = (byte)0xD2, + PUTSTATIC_QUICK = (byte)0xD3, + GETSTATIC2_QUICK = (byte)0xD4, + PUTSTATIC2_QUICK = (byte)0xD5, + INVOKEVIRTUAL_QUICK = (byte)0xD6, + INVOKENONVIRTUAL_QUICK = (byte)0xD7, + INVOKESUPER_QUICK = (byte)0xD8, + INVOKESTATIC_QUICK = (byte)0xD9, + INVOKEINTERFACE_QUICK = (byte)0xDA, + INVOKEVIRTUALOBJECT_QUICK = (byte)0xDB, + + NEW_QUICK = (byte)0xDD, + ANEWARRAY_QUICK = (byte)0xDE, + MULTIANEWARRAY_QUICK = (byte)0xDF, + CHECKCAST_QUICK = (byte)0xE0, + INSTANCEOF_QUICK = (byte)0xE1, + INVOKEVIRTUAL_QUICK_W = (byte)0xE2, + GETFIELD_QUICK_W = (byte)0xE3, + PUTFIELD_QUICK_W = (byte)0xE4, + IMPDEP1 = (byte)0xFE, + IMPDEP2 = (byte)0xFF; + + + // Types for NEWARRAY + public static final byte + T_BOOLEAN = 4, + T_CHAR = 5, + T_FLOAT = 6, + T_DOUBLE = 7, + T_BYTE = 8, + T_SHORT = 9, + T_INT = 10, + T_LONG = 11; + + static final byte[] extra = { // # bytes of operands generated after the opcode + /* NOP */ 0, + /* ACONST_NULL */ 0, + /* ICONST_M1 */ 0, + /* ICONST_0 */ 0, + /* ICONST_1 */ 0, + /* ICONST_2 */ 0, + /* ICONST_3 */ 0, + /* ICONST_4 */ 0, + /* ICONST_5 */ 0, + /* LCONST_0 */ 0, + /* LCONST_1 */ 0, + /* FCONST_0 */ 0, + /* FCONST_1 */ 0, + /* FCONST_2 */ 0, + /* DCONST_0 */ 0, + /* DCONST_1 */ 0, + /* BIPUSH */ 1, + /* SIPUSH */ 2, + /* LDC */ 1, + /* LDC_W */ 2, + /* LDC2_W */ 2, + /* ILOAD */ 1, + /* LLOAD */ 1, + /* FLOAD */ 1, + /* DLOAD */ 1, + /* ALOAD */ 1, + /* ILOAD_0 */ 0, + /* ILOAD_1 */ 0, + /* ILOAD_2 */ 0, + /* ILOAD_3 */ 0, + /* LLOAD_0 */ 0, + /* LLOAD_1 */ 0, + /* LLOAD_2 */ 0, + /* LLOAD_3 */ 0, + /* FLOAD_0 */ 0, + /* FLOAD_1 */ 0, + /* FLOAD_2 */ 0, + /* FLOAD_3 */ 0, + /* DLOAD_0 */ 0, + /* DLOAD_1 */ 0, + /* DLOAD_2 */ 0, + /* DLOAD_3 */ 0, + /* ALOAD_0 */ 0, + /* ALOAD_1 */ 0, + /* ALOAD_2 */ 0, + /* ALOAD_3 */ 0, + /* IALOAD */ 0, + /* LALOAD */ 0, + /* FALOAD */ 0, + /* DALOAD */ 0, + /* AALOAD */ 0, + /* BALOAD */ 0, + /* CALOAD */ 0, + /* SALOAD */ 0, + /* ISTORE */ 1, + /* LSTORE */ 1, + /* FSTORE */ 1, + /* DSTORE */ 1, + /* ASTORE */ 1, + /* ISTORE_0 */ 0, + /* ISTORE_1 */ 0, + /* ISTORE_2 */ 0, + /* ISTORE_3 */ 0, + /* LSTORE_0 */ 0, + /* LSTORE_1 */ 0, + /* LSTORE_2 */ 0, + /* LSTORE_3 */ 0, + /* FSTORE_0 */ 0, + /* FSTORE_1 */ 0, + /* FSTORE_2 */ 0, + /* FSTORE_3 */ 0, + /* DSTORE_0 */ 0, + /* DSTORE_1 */ 0, + /* DSTORE_2 */ 0, + /* DSTORE_3 */ 0, + /* ASTORE_0 */ 0, + /* ASTORE_1 */ 0, + /* ASTORE_2 */ 0, + /* ASTORE_3 */ 0, + /* IASTORE */ 0, + /* LASTORE */ 0, + /* FASTORE */ 0, + /* DASTORE */ 0, + /* AASTORE */ 0, + /* BASTORE */ 0, + /* CASTORE */ 0, + /* SASTORE */ 0, + /* POP */ 0, + /* POP2 */ 0, + /* DUP */ 0, + /* DUP_X1 */ 0, + /* DUP_X2 */ 0, + /* DUP2 */ 0, + /* DUP2_X1 */ 0, + /* DUP2_X2 */ 0, + /* SWAP */ 0, + /* IADD */ 0, + /* LADD */ 0, + /* FADD */ 0, + /* DADD */ 0, + /* ISUB */ 0, + /* LSUB */ 0, + /* FSUB */ 0, + /* DSUB */ 0, + /* IMUL */ 0, + /* LMUL */ 0, + /* FMUL */ 0, + /* DMUL */ 0, + /* IDIV */ 0, + /* LDIV */ 0, + /* FDIV */ 0, + /* DDIV */ 0, + /* IREM */ 0, + /* LREM */ 0, + /* FREM */ 0, + /* DREM */ 0, + /* INEG */ 0, + /* LNEG */ 0, + /* FNEG */ 0, + /* DNEG */ 0, + /* ISHL */ 0, + /* LSHL */ 0, + /* ISHR */ 0, + /* LSHR */ 0, + /* IUSHR */ 0, + /* LUSHR */ 0, + /* IAND */ 0, + /* LAND */ 0, + /* IOR */ 0, + /* LOR */ 0, + /* IXOR */ 0, + /* LXOR */ 0, + /* IINC */ 2, + /* I2L */ 0, + /* I2F */ 0, + /* I2D */ 0, + /* L2I */ 0, + /* L2F */ 0, + /* L2D */ 0, + /* F2I */ 0, + /* F2L */ 0, + /* F2D */ 0, + /* D2I */ 0, + /* D2L */ 0, + /* D2F */ 0, + /* I2B */ 0, + /* I2C */ 0, + /* I2S */ 0, + /* LCMP */ 0, + /* FCMPL */ 0, + /* FCMPG */ 0, + /* DCMPL */ 0, + /* DCMPG */ 0, + /* IFEQ */ 2, + /* IFNE */ 2, + /* IFLT */ 2, + /* IFGE */ 2, + /* IFGT */ 2, + /* IFLE */ 2, + /* IF_ICMPEQ */ 2, + /* IF_ICMPNE */ 2, + /* IF_ICMPLT */ 2, + /* IF_ICMPGE */ 2, + /* IF_ICMPGT */ 2, + /* IF_ICMPLE */ 2, + /* IF_ACMPEQ */ 2, + /* IF_ACMPNE */ 2, + /* GOTO */ 2, + /* JSR */ 2, + /* RET */ 1, + /* TABLESWITCH */ -1, // depends on alignment + /* LOOKUPSWITCH */ -1, // depends on alignment + /* IRETURN */ 0, + /* LRETURN */ 0, + /* FRETURN */ 0, + /* DRETURN */ 0, + /* ARETURN */ 0, + /* RETURN */ 0, + /* GETSTATIC */ 2, + /* PUTSTATIC */ 2, + /* GETFIELD */ 2, + /* PUTFIELD */ 2, + /* INVOKEVIRTUAL */ 2, + /* INVOKESPECIAL */ 2, + /* INVOKESTATIC */ 2, + /* INVOKEINTERFACE */ 2, + /* XXXUNUSEDXXX */ 0, + /* NEW */ 2, + /* NEWARRAY */ 1, + /* ANEWARRAY */ 2, + /* ARRAYLENGTH */ 0, + /* ATHROW */ 0, + /* CHECKCAST */ 2, + /* INSTANCEOF */ 2, + /* MONITORENTER */ 0, + /* MONITOREXIT */ 0, + /* WIDE */ 0, + /* MULTIANEWARRAY */ 3, + /* IFNULL */ 2, + /* IFNONNULL */ 2, + /* GOTO_W */ 4, + /* JSR_W */ 4, + /* BREAKPOINT */ 0, + /* LDC_QUICK */ 1, + /* LDC_W_QUICK */ 2, + /* LDC2_W_QUICK */ 2, + /* GETFIELD_QUICK */ 2, + /* PUTFIELD_QUICK */ 2, + /* GETFIELD2_QUICK */ 2, + /* PUTFIELD2_QUICK */ 2, + /* GETSTATIC_QUICK */ 2, + /* PUTSTATIC_QUICK */ 2, + /* GETSTATIC2_QUICK */ 2, + /* PUTSTATIC2_QUICK */ 2, + /* INVOKEVIRTUAL_QUICK */ 2, + /* INVOKENONVIRTUAL_QUICK */ 2, + /* INVOKESUPER_QUICK */ 2, + /* INVOKESTATIC_QUICK */ 2, + /* INVOKEINTERFACE_QUICK */ 2, + /* INVOKEVIRTUALOBJECT_QUICK */ 2, + /* XXXUNUSEDXXX */ 0, + /* NEW_QUICK */ 2, + /* ANEWARRAY_QUICK */ 2, + /* MULTIANEWARRAY_QUICK */ 3, + /* CHECKCAST_QUICK */ 2, + /* INSTANCEOF_QUICK */ 2, + /* INVOKEVIRTUAL_QUICK_W */ 0, + /* GETFIELD_QUICK_W */ 2, + /* PUTFIELD_QUICK_W */ 2, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* IMPDEP1 */ 0, + /* IMPDEP2 */ 0 + }; + + static final byte[] opcodeCount = { // # of operands accompanying the opcode + /* NOP */ 0, + /* ACONST_NULL */ 0, + /* ICONST_M1 */ 0, + /* ICONST_0 */ 0, + /* ICONST_1 */ 0, + /* ICONST_2 */ 0, + /* ICONST_3 */ 0, + /* ICONST_4 */ 0, + /* ICONST_5 */ 0, + /* LCONST_0 */ 0, + /* LCONST_1 */ 0, + /* FCONST_0 */ 0, + /* FCONST_1 */ 0, + /* FCONST_2 */ 0, + /* DCONST_0 */ 0, + /* DCONST_1 */ 0, + /* BIPUSH */ 1, + /* SIPUSH */ 1, + /* LDC */ 1, + /* LDC_W */ 1, + /* LDC2_W */ 1, + /* ILOAD */ 1, + /* LLOAD */ 1, + /* FLOAD */ 1, + /* DLOAD */ 1, + /* ALOAD */ 1, + /* ILOAD_0 */ 0, + /* ILOAD_1 */ 0, + /* ILOAD_2 */ 0, + /* ILOAD_3 */ 0, + /* LLOAD_0 */ 0, + /* LLOAD_1 */ 0, + /* LLOAD_2 */ 0, + /* LLOAD_3 */ 0, + /* FLOAD_0 */ 0, + /* FLOAD_1 */ 0, + /* FLOAD_2 */ 0, + /* FLOAD_3 */ 0, + /* DLOAD_0 */ 0, + /* DLOAD_1 */ 0, + /* DLOAD_2 */ 0, + /* DLOAD_3 */ 0, + /* ALOAD_0 */ 0, + /* ALOAD_1 */ 0, + /* ALOAD_2 */ 0, + /* ALOAD_3 */ 0, + /* IALOAD */ 0, + /* LALOAD */ 0, + /* FALOAD */ 0, + /* DALOAD */ 0, + /* AALOAD */ 0, + /* BALOAD */ 0, + /* CALOAD */ 0, + /* SALOAD */ 0, + /* ISTORE */ 1, + /* LSTORE */ 1, + /* FSTORE */ 1, + /* DSTORE */ 1, + /* ASTORE */ 1, + /* ISTORE_0 */ 0, + /* ISTORE_1 */ 0, + /* ISTORE_2 */ 0, + /* ISTORE_3 */ 0, + /* LSTORE_0 */ 0, + /* LSTORE_1 */ 0, + /* LSTORE_2 */ 0, + /* LSTORE_3 */ 0, + /* FSTORE_0 */ 0, + /* FSTORE_1 */ 0, + /* FSTORE_2 */ 0, + /* FSTORE_3 */ 0, + /* DSTORE_0 */ 0, + /* DSTORE_1 */ 0, + /* DSTORE_2 */ 0, + /* DSTORE_3 */ 0, + /* ASTORE_0 */ 0, + /* ASTORE_1 */ 0, + /* ASTORE_2 */ 0, + /* ASTORE_3 */ 0, + /* IASTORE */ 0, + /* LASTORE */ 0, + /* FASTORE */ 0, + /* DASTORE */ 0, + /* AASTORE */ 0, + /* BASTORE */ 0, + /* CASTORE */ 0, + /* SASTORE */ 0, + /* POP */ 0, + /* POP2 */ 0, + /* DUP */ 0, + /* DUP_X1 */ 0, + /* DUP_X2 */ 0, + /* DUP2 */ 0, + /* DUP2_X1 */ 0, + /* DUP2_X2 */ 0, + /* SWAP */ 0, + /* IADD */ 0, + /* LADD */ 0, + /* FADD */ 0, + /* DADD */ 0, + /* ISUB */ 0, + /* LSUB */ 0, + /* FSUB */ 0, + /* DSUB */ 0, + /* IMUL */ 0, + /* LMUL */ 0, + /* FMUL */ 0, + /* DMUL */ 0, + /* IDIV */ 0, + /* LDIV */ 0, + /* FDIV */ 0, + /* DDIV */ 0, + /* IREM */ 0, + /* LREM */ 0, + /* FREM */ 0, + /* DREM */ 0, + /* INEG */ 0, + /* LNEG */ 0, + /* FNEG */ 0, + /* DNEG */ 0, + /* ISHL */ 0, + /* LSHL */ 0, + /* ISHR */ 0, + /* LSHR */ 0, + /* IUSHR */ 0, + /* LUSHR */ 0, + /* IAND */ 0, + /* LAND */ 0, + /* IOR */ 0, + /* LOR */ 0, + /* IXOR */ 0, + /* LXOR */ 0, + /* IINC */ 2, + /* I2L */ 0, + /* I2F */ 0, + /* I2D */ 0, + /* L2I */ 0, + /* L2F */ 0, + /* L2D */ 0, + /* F2I */ 0, + /* F2L */ 0, + /* F2D */ 0, + /* D2I */ 0, + /* D2L */ 0, + /* D2F */ 0, + /* I2B */ 0, + /* I2C */ 0, + /* I2S */ 0, + /* LCMP */ 0, + /* FCMPL */ 0, + /* FCMPG */ 0, + /* DCMPL */ 0, + /* DCMPG */ 0, + /* IFEQ */ 1, + /* IFNE */ 1, + /* IFLT */ 1, + /* IFGE */ 1, + /* IFGT */ 1, + /* IFLE */ 1, + /* IF_ICMPEQ */ 1, + /* IF_ICMPNE */ 1, + /* IF_ICMPLT */ 1, + /* IF_ICMPGE */ 1, + /* IF_ICMPGT */ 1, + /* IF_ICMPLE */ 1, + /* IF_ACMPEQ */ 1, + /* IF_ACMPNE */ 1, + /* GOTO */ 1, + /* JSR */ 1, + /* RET */ 1, + /* TABLESWITCH */ -1, + /* LOOKUPSWITCH */ -1, + /* IRETURN */ 0, + /* LRETURN */ 0, + /* FRETURN */ 0, + /* DRETURN */ 0, + /* ARETURN */ 0, + /* RETURN */ 0, + /* GETSTATIC */ 1, + /* PUTSTATIC */ 1, + /* GETFIELD */ 1, + /* PUTFIELD */ 1, + /* INVOKEVIRTUAL */ 1, + /* INVOKESPECIAL */ 1, + /* INVOKESTATIC */ 1, + /* INVOKEINTERFACE */ 1, + /* XXXUNUSEDXXX */ 0, + /* NEW */ 1, + /* NEWARRAY */ 1, + /* ANEWARRAY */ 1, + /* ARRAYLENGTH */ 0, + /* ATHROW */ 0, + /* CHECKCAST */ 1, + /* INSTANCEOF */ 1, + /* MONITORENTER */ 0, + /* MONITOREXIT */ 0, + /* WIDE */ 0, + /* MULTIANEWARRAY */ 2, + /* IFNULL */ 1, + /* IFNONNULL */ 1, + /* GOTO_W */ 1, + /* JSR_W */ 1, + /* BREAKPOINT */ 0, + /* LDC_QUICK */ -1, + /* LDC_W_QUICK */ -1, + /* LDC2_W_QUICK */ -1, + /* GETFIELD_QUICK */ -1, + /* PUTFIELD_QUICK */ -1, + /* GETFIELD2_QUICK */ -1, + /* PUTFIELD2_QUICK */ -1, + /* GETSTATIC_QUICK */ -1, + /* PUTSTATIC_QUICK */ -1, + /* GETSTATIC2_QUICK */ -1, + /* PUTSTATIC2_QUICK */ -1, + /* INVOKEVIRTUAL_QUICK */ -1, + /* INVOKENONVIRTUAL_QUICK */ -1, + /* INVOKESUPER_QUICK */ -1, + /* INVOKESTATIC_QUICK */ -1, + /* INVOKEINTERFACE_QUICK */ -1, + /* INVOKEVIRTUALOBJECT_QUICK */ -1, + /* XXXUNUSEDXXX */ -1, + /* NEW_QUICK */ -1, + /* ANEWARRAY_QUICK */ -1, + /* MULTIANEWARRAY_QUICK */ -1, + /* CHECKCAST_QUICK */ -1, + /* INSTANCEOF_QUICK */ -1, + /* INVOKEVIRTUAL_QUICK_W */ -1, + /* GETFIELD_QUICK_W */ -1, + /* PUTFIELD_QUICK_W */ -1, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* IMPDEP1 */ 0, + /* IMPDEP2 */ 0 + }; + + static final byte[] stackChange = { // the effect on the operand stack + /* NOP */ 0, + /* ACONST_NULL */ 1, + /* ICONST_M1 */ 1, + /* ICONST_0 */ 1, + /* ICONST_1 */ 1, + /* ICONST_2 */ 1, + /* ICONST_3 */ 1, + /* ICONST_4 */ 1, + /* ICONST_5 */ 1, + /* LCONST_0 */ 2, + /* LCONST_1 */ 2, + /* FCONST_0 */ 1, + /* FCONST_1 */ 1, + /* FCONST_2 */ 1, + /* DCONST_0 */ 2, + /* DCONST_1 */ 2, + /* BIPUSH */ 1, + /* SIPUSH */ 1, + /* LDC */ 1, + /* LDC_W */ 1, + /* LDC2_W */ 2, + /* ILOAD */ 1, + /* LLOAD */ 2, + /* FLOAD */ 1, + /* DLOAD */ 2, + /* ALOAD */ 1, + /* ILOAD_0 */ 1, + /* ILOAD_1 */ 1, + /* ILOAD_2 */ 1, + /* ILOAD_3 */ 1, + /* LLOAD_0 */ 2, + /* LLOAD_1 */ 2, + /* LLOAD_2 */ 2, + /* LLOAD_3 */ 2, + /* FLOAD_0 */ 1, + /* FLOAD_1 */ 1, + /* FLOAD_2 */ 1, + /* FLOAD_3 */ 1, + /* DLOAD_0 */ 2, + /* DLOAD_1 */ 2, + /* DLOAD_2 */ 2, + /* DLOAD_3 */ 2, + /* ALOAD_0 */ 1, + /* ALOAD_1 */ 1, + /* ALOAD_2 */ 1, + /* ALOAD_3 */ 1, + /* IALOAD */ -1, + /* LALOAD */ 0, + /* FALOAD */ -1, + /* DALOAD */ 0, + /* AALOAD */ -1, + /* BALOAD */ -1, + /* CALOAD */ -1, + /* SALOAD */ -1, + /* ISTORE */ -1, + /* LSTORE */ -2, + /* FSTORE */ -1, + /* DSTORE */ -2, + /* ASTORE */ -1, + /* ISTORE_0 */ -1, + /* ISTORE_1 */ -1, + /* ISTORE_2 */ -1, + /* ISTORE_3 */ -1, + /* LSTORE_0 */ -2, + /* LSTORE_1 */ -2, + /* LSTORE_2 */ -2, + /* LSTORE_3 */ -2, + /* FSTORE_0 */ -1, + /* FSTORE_1 */ -1, + /* FSTORE_2 */ -1, + /* FSTORE_3 */ -1, + /* DSTORE_0 */ -2, + /* DSTORE_1 */ -2, + /* DSTORE_2 */ -2, + /* DSTORE_3 */ -2, + /* ASTORE_0 */ -1, + /* ASTORE_1 */ -1, + /* ASTORE_2 */ -1, + /* ASTORE_3 */ -1, + /* IASTORE */ -3, + /* LASTORE */ -4, + /* FASTORE */ -3, + /* DASTORE */ -4, + /* AASTORE */ -3, + /* BASTORE */ -3, + /* CASTORE */ -3, + /* SASTORE */ -3, + /* POP */ -1, + /* POP2 */ -2, + /* DUP */ 1, + /* DUP_X1 */ 1, + /* DUP_X2 */ 1, + /* DUP2 */ 2, + /* DUP2_X1 */ 2, + /* DUP2_X2 */ 2, + /* SWAP */ 0, + /* IADD */ -1, + /* LADD */ -2, + /* FADD */ -1, + /* DADD */ -2, + /* ISUB */ -1, + /* LSUB */ -2, + /* FSUB */ -1, + /* DSUB */ -2, + /* IMUL */ -1, + /* LMUL */ -2, + /* FMUL */ -1, + /* DMUL */ -2, + /* IDIV */ -1, + /* LDIV */ -2, + /* FDIV */ -1, + /* DDIV */ -2, + /* IREM */ -1, + /* LREM */ -2, + /* FREM */ -1, + /* DREM */ -2, + /* INEG */ 0, + /* LNEG */ 0, + /* FNEG */ 0, + /* DNEG */ 0, + /* ISHL */ -1, + /* LSHL */ -1, + /* ISHR */ -1, + /* LSHR */ -1, + /* IUSHR */ -1, + /* LUSHR */ -1, + /* IAND */ -1, + /* LAND */ -2, + /* IOR */ -1, + /* LOR */ -2, + /* IXOR */ -1, + /* LXOR */ -2, + /* IINC */ 0, + /* I2L */ 1, + /* I2F */ 0, + /* I2D */ 1, + /* L2I */ -1, + /* L2F */ -1, + /* L2D */ 0, + /* F2I */ 0, + /* F2L */ 1, + /* F2D */ 1, + /* D2I */ -1, + /* D2L */ 0, + /* D2F */ -1, + /* I2B */ 0, + /* I2C */ 0, + /* I2S */ 0, + /* LCMP */ -3, + /* FCMPL */ -1, + /* FCMPG */ -1, + /* DCMPL */ -3, + /* DCMPG */ -3, + /* IFEQ */ -1, + /* IFNE */ -1, + /* IFLT */ -1, + /* IFGE */ -1, + /* IFGT */ -1, + /* IFLE */ -1, + /* IF_ICMPEQ */ -2, + /* IF_ICMPNE */ -2, + /* IF_ICMPLT */ -2, + /* IF_ICMPGE */ -2, + /* IF_ICMPGT */ -2, + /* IF_ICMPLE */ -2, + /* IF_ACMPEQ */ -2, + /* IF_ACMPNE */ -2, + /* GOTO */ 0, + /* JSR */ 1, + /* RET */ 0, + /* TABLESWITCH */ -1, + /* LOOKUPSWITCH */ -1, + /* IRETURN */ -1, + /* LRETURN */ -2, + /* FRETURN */ -1, + /* DRETURN */ -2, + /* ARETURN */ -1, + /* RETURN */ 0, + /* GETSTATIC */ 0, + /* PUTSTATIC */ 0, + /* GETFIELD */ -1, + /* PUTFIELD */ -1, + /* INVOKEVIRTUAL */ -1, // pops 'this' (unless static) + /* INVOKESPECIAL */ -1, // but needs to account for + /* INVOKESTATIC */ 0, // parameters and return type + /* INVOKEINTERFACE */ -1, // + /* XXXUNUSEDXXX */ 0, + /* NEW */ 1, + /* NEWARRAY */ 0, + /* ANEWARRAY */ 0, + /* ARRAYLENGTH */ 0, + /* ATHROW */ -1, + /* CHECKCAST */ 0, + /* INSTANCEOF */ 0, + /* MONITORENTER */ -1, + /* MONITOREXIT */ -1, + /* WIDE */ 0, + /* MULTIANEWARRAY */ 1, + /* IFNULL */ -1, + /* IFNONNULL */ -1, + /* GOTO_W */ 0, + /* JSR_W */ 1, + /* BREAKPOINT */ 0, + /* LDC_QUICK */ 1, + /* LDC_W_QUICK */ 1, + /* LDC2_W_QUICK */ 2, + /* GETFIELD_QUICK */ 0, + /* PUTFIELD_QUICK */ 0, + /* GETFIELD2_QUICK */ 0, + /* PUTFIELD2_QUICK */ 0, + /* GETSTATIC_QUICK */ 0, + /* PUTSTATIC_QUICK */ 0, + /* GETSTATIC2_QUICK */ 0, + /* PUTSTATIC2_QUICK */ 0, + /* INVOKEVIRTUAL_QUICK */ 0, + /* INVOKENONVIRTUAL_QUICK */ 0, + /* INVOKESUPER_QUICK */ 0, + /* INVOKESTATIC_QUICK */ 0, + /* INVOKEINTERFACE_QUICK */ 0, + /* INVOKEVIRTUALOBJECT_QUICK */ 0, + /* XXXUNUSEDXXX */ 0, + /* NEW_QUICK */ 1, + /* ANEWARRAY_QUICK */ 1, + /* MULTIANEWARRAY_QUICK */ 1, + /* CHECKCAST_QUICK */ -1, + /* INSTANCEOF_QUICK */ 0, + /* INVOKEVIRTUAL_QUICK_W */ 0, + /* GETFIELD_QUICK_W */ 0, + /* PUTFIELD_QUICK_W */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* XXXUNUSEDXXX */ 0, + /* IMPDEP1 */ 0, + /* IMPDEP2 */ 0 + }; +} diff --git a/js/rhino/src/org/mozilla/classfile/ClassFileWriter.java b/js/rhino/src/org/mozilla/classfile/ClassFileWriter.java new file mode 100644 index 000000000000..e88e4adc711d --- /dev/null +++ b/js/rhino/src/org/mozilla/classfile/ClassFileWriter.java @@ -0,0 +1,1308 @@ +/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights + * Reserved. + */ + +package org.mozilla.classfile; + +import org.mozilla.javascript.*; + +import java.io.*; +import java.util.*; + +public class ClassFileWriter extends LabelTable { + + public ClassFileWriter(String thisClass, String superClass, + String sourceFileName) + { + itsConstantPool = new ConstantPool(); + itsThisClassIndex = itsConstantPool.addClass(thisClass); + itsSuperClassIndex = itsConstantPool.addClass(superClass); + if (sourceFileName != null) + itsSourceFileNameIndex = itsConstantPool.addUtf8(sourceFileName); + itsFlags = ACC_PUBLIC; + } + + public void setFlags(short flags) + { + itsFlags = flags; + } + + public static String fullyQualifiedForm(String name) + { + return name.replace('.', '/'); + } + + public void addInterface(String interfaceName) + { + short interfaceIndex = itsConstantPool.addClass(interfaceName); + itsInterfaces.addElement(new Short(interfaceIndex)); + } + + + private final static long FileHeaderConstant = 0xCAFEBABE0003002DL; + private static final boolean DEBUG = true; + private static final boolean DEBUGSTACK = false; + private static final boolean DEBUGLABELS = false; + private static final boolean DEBUGCODE = false; + private static final int CodeBufferSize = 128; + + public static final short + ACC_PUBLIC = 0x0001, + ACC_PRIVATE = 0x0002, + ACC_PROTECTED = 0x0004, + ACC_STATIC = 0x0008, + ACC_FINAL = 0x0010, + ACC_SYNCHRONIZED = 0x0020, + ACC_VOLATILE = 0x0040, + ACC_TRANSIENT = 0x0080, + ACC_NATIVE = 0x0100, + ACC_ABSTRACT = 0x0400; + + public void add(byte theOpCode) + { + if (DEBUGCODE) + System.out.println("Add " + Integer.toHexString(theOpCode & 0xFF)); + if (DEBUG) { + if (ByteCode.opcodeCount[theOpCode & 0xFF] != 0) + throw new RuntimeException("Expected operands"); + } + addToCodeBuffer(theOpCode); + itsStackTop += ByteCode.stackChange[theOpCode & 0xFF]; + if (DEBUGSTACK) { + System.out.println("After " + Integer.toHexString(theOpCode & 0xFF) + " stack = " + itsStackTop); + } + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("Stack underflow"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + } + + public void add(byte theOpCode, int theOperand) + { + if (DEBUGCODE) + System.out.println("Add " + Integer.toHexString(theOpCode & 0xFF) + ", " + Integer.toHexString(theOperand) ); + itsStackTop += ByteCode.stackChange[theOpCode & 0xFF]; + if (DEBUGSTACK) { + System.out.println("After " + Integer.toHexString(theOpCode & 0xFF) + " stack = " + itsStackTop); + } + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("Stack underflow"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + + switch (theOpCode) { + case ByteCode.GOTO : + // fallthru... + case ByteCode.IFEQ : + case ByteCode.IFNE : + case ByteCode.IFLT : + case ByteCode.IFGE : + case ByteCode.IFGT : + case ByteCode.IFLE : + case ByteCode.IF_ICMPEQ : + case ByteCode.IF_ICMPNE : + case ByteCode.IF_ICMPLT : + case ByteCode.IF_ICMPGE : + case ByteCode.IF_ICMPGT : + case ByteCode.IF_ICMPLE : + case ByteCode.IF_ACMPEQ : + case ByteCode.IF_ACMPNE : + case ByteCode.JSR : + case ByteCode.IFNULL : + case ByteCode.IFNONNULL : { + if (DEBUG) { + if ((theOperand & 0x80000000) != 0x80000000) { + if ((theOperand < 0) || (theOperand > 65535)) + throw new RuntimeException("Bad label for branch"); + } + } + int branchPC = itsCodeBufferTop; + addToCodeBuffer(theOpCode); + if ((theOperand & 0x80000000) != 0x80000000) { + // hard displacement + int temp_Label = acquireLabel(); + int theLabel = temp_Label & 0x7FFFFFFF; + itsLabelTable[theLabel].setPC( + (short)(branchPC + theOperand)); + addToCodeBuffer((byte)(theOperand >> 8)); + addToCodeBuffer((byte)theOperand); + } + else { // a label + int theLabel = theOperand & 0x7FFFFFFF; + int targetPC = itsLabelTable[theLabel].getPC(); + if (DEBUGLABELS) { + System.out.println("Fixing branch to " + theLabel + " at " + targetPC + " from " + branchPC); + } + if (targetPC != -1) { + short offset = (short)(targetPC - branchPC); + addToCodeBuffer((byte)(offset >> 8)); + addToCodeBuffer((byte)offset); + } + else { + itsLabelTable[theLabel].addFixup(branchPC + 1); + addToCodeBuffer((byte)0); + addToCodeBuffer((byte)0); + } + } + } + break; + + case ByteCode.BIPUSH : + if (DEBUG) { + if ((theOperand < -128) || (theOperand > 127)) + throw new RuntimeException("out of range byte"); + } + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)theOperand); + break; + + case ByteCode.SIPUSH : + if (DEBUG) { + if ((theOperand < -32768) || (theOperand > 32767)) + throw new RuntimeException("out of range short"); + } + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)(theOperand >> 8)); + addToCodeBuffer((byte)theOperand); + break; + + case ByteCode.NEWARRAY : + if (DEBUG) { + if ((theOperand < 0) || (theOperand > 255)) + throw new RuntimeException("out of range index"); + } + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)theOperand); + break; + + case ByteCode.GETFIELD : + case ByteCode.PUTFIELD : + if (DEBUG) { + if ((theOperand < 0) || (theOperand > 65535)) + throw new RuntimeException("out of range field"); + } + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)(theOperand >> 8)); + addToCodeBuffer((byte)theOperand); + break; + + case ByteCode.LDC : + case ByteCode.LDC_W : + case ByteCode.LDC2_W : + if (DEBUG) { + if ((theOperand < 0) || (theOperand > 65535)) + throw new RuntimeException("out of range index"); + } + if ((theOperand >= 256) + || (theOpCode == ByteCode.LDC_W) + || (theOpCode == ByteCode.LDC2_W)) { + if (theOpCode == ByteCode.LDC) + addToCodeBuffer(ByteCode.LDC_W); + else + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)(theOperand >> 8)); + addToCodeBuffer((byte)theOperand); + } + else { + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)theOperand); + } + break; + + case ByteCode.RET : + case ByteCode.ILOAD : + case ByteCode.LLOAD : + case ByteCode.FLOAD : + case ByteCode.DLOAD : + case ByteCode.ALOAD : + case ByteCode.ISTORE : + case ByteCode.LSTORE : + case ByteCode.FSTORE : + case ByteCode.DSTORE : + case ByteCode.ASTORE : + if (DEBUG) { + if ((theOperand < 0) || (theOperand > 65535)) + throw new RuntimeException("out of range variable"); + } + if (theOperand >= 256) { + addToCodeBuffer(ByteCode.WIDE); + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)(theOperand >> 8)); + addToCodeBuffer((byte)theOperand); + } + else { + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)theOperand); + } + break; + + default : + throw new RuntimeException("Unexpected opcode for 1 operand"); + } + } + + public void addLoadConstant(int k) + { + add(ByteCode.LDC, itsConstantPool.addConstant(k)); + } + + public void addLoadConstant(long k) + { + add(ByteCode.LDC2_W, itsConstantPool.addConstant(k)); + } + + public void addLoadConstant(float k) + { + add(ByteCode.LDC, itsConstantPool.addConstant(k)); + } + + public void addLoadConstant(double k) + { + add(ByteCode.LDC2_W, itsConstantPool.addConstant(k)); + } + + public void addLoadConstant(String k) + { + add(ByteCode.LDC, itsConstantPool.addConstant(k)); + } + + public void add(byte theOpCode, int theOperand1, int theOperand2) + { + if (DEBUGCODE) + System.out.println("Add " + Integer.toHexString(theOpCode & 0xFF) + + ", " + Integer.toHexString(theOperand1) + + ", " + Integer.toHexString(theOperand2)); + itsStackTop += ByteCode.stackChange[theOpCode & 0xFF]; + if (DEBUGSTACK) { + System.out.println("After " + Integer.toHexString(theOpCode & 0xFF) + " stack = " + itsStackTop); + } + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("Stack underflow"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + + if (theOpCode == ByteCode.IINC) { + if (DEBUG) { + if ((theOperand1 < 0) || (theOperand1 > 65535)) + throw new RuntimeException("out of range variable"); + if ((theOperand2 < -32768) || (theOperand2 > 32767)) + throw new RuntimeException("out of range increment"); + } + if ((theOperand1 > 255) + || (theOperand2 < -128) || (theOperand2 > 127)) { + addToCodeBuffer(ByteCode.WIDE); + addToCodeBuffer(ByteCode.IINC); + addToCodeBuffer((byte)(theOperand1 >> 8)); + addToCodeBuffer((byte)theOperand1); + addToCodeBuffer((byte)(theOperand2 >> 8)); + addToCodeBuffer((byte)theOperand2); + } + else { + addToCodeBuffer(ByteCode.WIDE); + addToCodeBuffer(ByteCode.IINC); + addToCodeBuffer((byte)theOperand1); + addToCodeBuffer((byte)theOperand2); + } + } + else { + if (theOpCode == ByteCode.MULTIANEWARRAY) { + if (DEBUG) { + if ((theOperand1 < 0) || (theOperand1 > 65535)) + throw new RuntimeException("out of range index"); + if ((theOperand2 < 0) || (theOperand2 > 255)) + throw new RuntimeException("out of range dimensions"); + } + addToCodeBuffer(ByteCode.MULTIANEWARRAY); + addToCodeBuffer((byte)(theOperand1 >> 8)); + addToCodeBuffer((byte)theOperand1); + addToCodeBuffer((byte)theOperand2); + } + else { + throw new RuntimeException("Unexpected opcode for 2 operands"); + } + } + } + + public void add(byte theOpCode, String className) + { + if (DEBUGCODE) + System.out.println("Add " + Integer.toHexString(theOpCode & 0xFF) + + ", " + className); + itsStackTop += ByteCode.stackChange[theOpCode & 0xFF]; + if (DEBUGSTACK) { + System.out.println("After " + Integer.toHexString(theOpCode & 0xFF) + " stack = " + itsStackTop); + } + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("Stack underflow"); + } + switch (theOpCode) { + case ByteCode.NEW : + case ByteCode.ANEWARRAY : + case ByteCode.CHECKCAST : + case ByteCode.INSTANCEOF : { + short classIndex = itsConstantPool.addClass(className); + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)(classIndex >> 8)); + addToCodeBuffer((byte)classIndex); + } + break; + + default : + throw new RuntimeException("bad opcode for class reference"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + } + + + public void add(byte theOpCode, String className, + String fieldName, String fieldType) + { + if (DEBUGCODE) + System.out.println("Add " + Integer.toHexString(theOpCode & 0xFF) + + ", " + className + ", " + fieldName + ", " + fieldType); + itsStackTop += ByteCode.stackChange[theOpCode & 0xFF]; + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("After " + Integer.toHexString(theOpCode & 0xFF) + " Stack underflow"); + } + char fieldTypeChar = fieldType.charAt(0); + int fieldSize = ((fieldTypeChar == 'J') + || (fieldTypeChar == 'D')) ? 2 : 1; + switch (theOpCode) { + case ByteCode.GETFIELD : + case ByteCode.GETSTATIC : + itsStackTop += fieldSize; + break; + case ByteCode.PUTSTATIC : + case ByteCode.PUTFIELD : + itsStackTop -= fieldSize; + break; + default : + throw new RuntimeException("bad opcode for field reference"); + } + short fieldRefIndex = itsConstantPool.addFieldRef(className, + fieldName, fieldType); + addToCodeBuffer(theOpCode); + addToCodeBuffer((byte)(fieldRefIndex >> 8)); + addToCodeBuffer((byte)fieldRefIndex); + + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + if (DEBUGSTACK) { + System.out.println("After " + Integer.toHexString(theOpCode & 0xFF) + " stack = " + itsStackTop); + } + } + + /* + Really weird. Returns an int with # parameters in hi 16 bits, and + # slots occupied by parameters in the low 16 bits. If Java really + supported references we wouldn't have to be this perverted. + */ + public int sizeOfParameters(String pString) + { + if (DEBUG) { + if (pString.charAt(0) != '(') + throw new RuntimeException("Bad parameter signature"); + } + int index = 1; + int size = 0; + int count = 0; + while (pString.charAt(index) != ')') { + switch (pString.charAt(index)) { + case 'J' : + case 'D' : + size++; + // fall thru + case 'B' : + case 'S' : + case 'C' : + case 'I' : + case 'Z' : + case 'F' : + size++; + count++; + index++; + break; + case '[' : + while (pString.charAt(index) == '[') index++; + if (pString.charAt(index) != 'L') { + size++; + count++; + index++; + break; + } + // fall thru + case 'L' : + size++; + count++; + while (pString.charAt(index++) != ';') ; + break; + default : + throw new RuntimeException("Bad signature character"); + } + } + return ((count << 16) | size); + } + + public void add(byte theOpCode, String className, String methodName, + String parametersType, String returnType) + { + if (DEBUGCODE) + System.out.println("Add " + Integer.toHexString(theOpCode & 0xFF) + + ", " + className + ", " + methodName + ", " + parametersType + ", " + returnType); + int parameterInfo = sizeOfParameters(parametersType); + itsStackTop -= (parameterInfo & 0xFFFF); + itsStackTop += ByteCode.stackChange[theOpCode & 0xFF]; // adjusts for 'this' + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("After " + Integer.toHexString(theOpCode & 0xFF) + " Stack underflow"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + + switch (theOpCode) { + case ByteCode.INVOKEVIRTUAL : + case ByteCode.INVOKESPECIAL : + case ByteCode.INVOKESTATIC : + case ByteCode.INVOKEINTERFACE : { + char returnTypeChar = returnType.charAt(0); + if (returnTypeChar != 'V') + if ((returnTypeChar == 'J') || (returnTypeChar == 'D')) + itsStackTop += 2; + else + itsStackTop++; + addToCodeBuffer(theOpCode); + if (theOpCode == ByteCode.INVOKEINTERFACE) { + short ifMethodRefIndex + = itsConstantPool.addInterfaceMethodRef( + className, methodName, + parametersType + returnType); + addToCodeBuffer((byte)(ifMethodRefIndex >> 8)); + addToCodeBuffer((byte)ifMethodRefIndex); + addToCodeBuffer((byte)((parameterInfo >> 16) + 1)); + addToCodeBuffer((byte)0); + } + else { + short methodRefIndex = itsConstantPool.addMethodRef( + className, methodName, + parametersType + returnType); + addToCodeBuffer((byte)(methodRefIndex >> 8)); + addToCodeBuffer((byte)methodRefIndex); + } + } + break; + + default : + throw new RuntimeException("bad opcode for method reference"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + if (DEBUGSTACK) { + System.out.println("After " + Integer.toHexString(theOpCode & 0xFF) + " stack = " + itsStackTop); + } + } + + public int markLabel(int theLabel) { + return super.markLabel(theLabel, (short)itsCodeBufferTop); + } + + public int markLabel(int theLabel, short stackTop) { + itsStackTop = stackTop; + return super.markLabel(theLabel, (short)itsCodeBufferTop); + } + + public int markHandler(int theLabel) { + itsStackTop = 1; + return markLabel(theLabel); + } + + public short getStackTop() { + return itsStackTop; + } + + public void adjustStackTop(int delta) { + itsStackTop += delta; + if (DEBUGSTACK) { + System.out.println("After " + "adjustStackTop("+delta+")" + " stack = " + itsStackTop); + } + if (DEBUG) { + if (itsStackTop < 0) + throw new RuntimeException("Stack underflow"); + } + if (itsStackTop > itsMaxStack) itsMaxStack = itsStackTop; + } + + + public void addToCodeBuffer(byte b) + { + if (DEBUG) { + if (itsCurrentMethod == null) + throw new RuntimeException("No method to add to"); + } + if (itsCodeBuffer == null) { + itsCodeBuffer = new byte[CodeBufferSize]; + itsCodeBuffer[0] = b; + itsCodeBufferTop = 1; + } + else { + if (itsCodeBufferTop == itsCodeBuffer.length) { + byte currentBuffer[] = itsCodeBuffer; + itsCodeBuffer = new byte[itsCodeBufferTop * 2]; + System.arraycopy(currentBuffer, 0, itsCodeBuffer, + 0, itsCodeBufferTop); + } + itsCodeBuffer[itsCodeBufferTop++] = b; + } + } + + public void addField(String fieldName, String type, short flags) + { + short fieldNameIndex = itsConstantPool.addUtf8(fieldName); + short typeIndex = itsConstantPool.addUtf8(type); + itsFields.addElement( + new ClassFileField(fieldNameIndex, typeIndex, flags)); + } + + public void addField(String fieldName, String type, short flags, int value) + { + short fieldNameIndex = itsConstantPool.addUtf8(fieldName); + short typeIndex = itsConstantPool.addUtf8(type); + short cvAttr[] = new short[4]; + cvAttr[0] = itsConstantPool.addUtf8("ConstantValue"); + cvAttr[1] = 0; + cvAttr[2] = 2; + cvAttr[3] = itsConstantPool.addConstant(value); + itsFields.addElement( + new ClassFileField(fieldNameIndex, typeIndex, flags, cvAttr)); + } + + public void addField(String fieldName, String type, short flags, long value) + { + short fieldNameIndex = itsConstantPool.addUtf8(fieldName); + short typeIndex = itsConstantPool.addUtf8(type); + short cvAttr[] = new short[4]; + cvAttr[0] = itsConstantPool.addUtf8("ConstantValue"); + cvAttr[1] = 0; + cvAttr[2] = 2; + cvAttr[3] = itsConstantPool.addConstant(value); + itsFields.addElement( + new ClassFileField(fieldNameIndex, typeIndex, flags, cvAttr)); + } + + public void addField(String fieldName, String type, short flags, double value) + { + short fieldNameIndex = itsConstantPool.addUtf8(fieldName); + short typeIndex = itsConstantPool.addUtf8(type); + short cvAttr[] = new short[4]; + cvAttr[0] = itsConstantPool.addUtf8("ConstantValue"); + cvAttr[1] = 0; + cvAttr[2] = 2; + cvAttr[3] = itsConstantPool.addConstant(value); + itsFields.addElement( + new ClassFileField(fieldNameIndex, typeIndex, flags, cvAttr)); + } + + static final int ExceptionTableSize = 4; + + public void addExceptionHandler(int startLabel, int endLabel, + int handlerLabel, String catchClassName) + { + if ((startLabel & 0x80000000) != 0x80000000) + throw new RuntimeException("Bad startLabel"); + if ((endLabel & 0x80000000) != 0x80000000) + throw new RuntimeException("Bad endLabel"); + if ((handlerLabel & 0x80000000) != 0x80000000) + throw new RuntimeException("Bad handlerLabel"); + + /* + * if catchClassName is null, use 0 for the catch_type_index; which means + * catch everything. (Even when the verifier has let you throw something other + * than a Throwable.) + */ + ExceptionTableEntry newEntry + = new ExceptionTableEntry( + startLabel, + endLabel, + handlerLabel, + catchClassName == null + ? 0 + : itsConstantPool.addClass(catchClassName)); + + if (itsExceptionTable == null) { + itsExceptionTable = new ExceptionTableEntry[ExceptionTableSize]; + itsExceptionTable[0] = newEntry; + itsExceptionTableTop = 1; + } + else { + if (itsExceptionTableTop == itsExceptionTable.length) { + ExceptionTableEntry oldTable[] = itsExceptionTable; + itsExceptionTable = new ExceptionTableEntry + [itsExceptionTableTop * 2]; + System.arraycopy(oldTable, 0, itsExceptionTable, + 0, itsExceptionTableTop); + } + itsExceptionTable[itsExceptionTableTop++] = newEntry; + } + + } + + public void startMethod(String methodName, String type, short flags) + { + short methodNameIndex = itsConstantPool.addUtf8(methodName); + short typeIndex = itsConstantPool.addUtf8(type); + itsCurrentMethod = new ClassFileMethod(methodNameIndex, typeIndex, + flags); + itsMethods.addElement(itsCurrentMethod); + } + + public void stopMethod(short maxLocals, VariableTable vars) + { + if (DEBUG) { + if (itsCurrentMethod == null) + throw new RuntimeException("No method to stop"); + } + + for (int i = 0; i < itsLabelTableTop; i++) + itsLabelTable[i].fixGotos(itsCodeBuffer); + + itsMaxLocals = maxLocals; + + int lineNumberTableLength = 0; + if (itsLineNumberTable != null) { + // 6 bytes for the attribute header + // 2 bytes for the line number count + // 4 bytes for each entry + lineNumberTableLength = 6 + 2 + (itsLineNumberTableTop * 4); + } + + int variableTableLength = 0; + if (vars != null) { + // 6 bytes for the attribute header + // 2 bytes for the variable count + // 10 bytes for each entry + variableTableLength = 6 + 2 + (vars.size() * 10); + } + + int attrLength = 2 + // attribute_name_index + 4 + // attribute_length + 2 + // max_stack + 2 + // max_locals + 4 + // code_length + itsCodeBufferTop + + 2 + // exception_table_length + (itsExceptionTableTop * 8) + + 2 + // attributes_count + lineNumberTableLength + + variableTableLength; + + byte codeAttribute[] = new byte[attrLength]; + int index = 0; + int codeAttrIndex = itsConstantPool.addUtf8("Code"); + codeAttribute[index++] = (byte)(codeAttrIndex >> 8); + codeAttribute[index++] = (byte)codeAttrIndex; + attrLength -= 6; // discount the attribute header + codeAttribute[index++] = (byte)(attrLength >> 24); + codeAttribute[index++] = (byte)(attrLength >> 16); + codeAttribute[index++] = (byte)(attrLength >> 8); + codeAttribute[index++] = (byte)attrLength; + codeAttribute[index++] = (byte)(itsMaxStack >> 8); + codeAttribute[index++] = (byte)itsMaxStack; + codeAttribute[index++] = (byte)(itsMaxLocals >> 8); + codeAttribute[index++] = (byte)itsMaxLocals; + codeAttribute[index++] = (byte)(itsCodeBufferTop >> 24); + codeAttribute[index++] = (byte)(itsCodeBufferTop >> 16); + codeAttribute[index++] = (byte)(itsCodeBufferTop >> 8); + codeAttribute[index++] = (byte)itsCodeBufferTop; + System.arraycopy(itsCodeBuffer, 0, codeAttribute, index, + itsCodeBufferTop); + index += itsCodeBufferTop; + + + if (itsExceptionTableTop > 0) { + codeAttribute[index++] = (byte)(itsExceptionTableTop >> 8); + codeAttribute[index++] = (byte)(itsExceptionTableTop); + for (int i = 0; i < itsExceptionTableTop; i++) { + short startPC = itsExceptionTable[i].getStartPC(itsLabelTable); + codeAttribute[index++] = (byte)(startPC >> 8); + codeAttribute[index++] = (byte)(startPC); + short endPC = itsExceptionTable[i].getEndPC(itsLabelTable); + codeAttribute[index++] = (byte)(endPC >> 8); + codeAttribute[index++] = (byte)(endPC); + short handlerPC = itsExceptionTable[i].getHandlerPC(itsLabelTable); + codeAttribute[index++] = (byte)(handlerPC >> 8); + codeAttribute[index++] = (byte)(handlerPC); + short catchType = itsExceptionTable[i].getCatchType(); + codeAttribute[index++] = (byte)(catchType >> 8); + codeAttribute[index++] = (byte)(catchType); + } + } + else { + codeAttribute[index++] = (byte)(0); // exception table length + codeAttribute[index++] = (byte)(0); + } + + int attributeCount = 0; + if (itsLineNumberTable != null) + attributeCount++; + if (vars != null) + attributeCount++; + codeAttribute[index++] = (byte)(0); // (hibyte) attribute count... + codeAttribute[index++] = (byte)(attributeCount); // (lobyte) attribute count + + if (itsLineNumberTable != null) { + int lineNumberTableAttrIndex + = itsConstantPool.addUtf8("LineNumberTable"); + codeAttribute[index++] = (byte)(lineNumberTableAttrIndex >> 8); + codeAttribute[index++] = (byte)lineNumberTableAttrIndex; + int tableAttrLength = 2 + (itsLineNumberTableTop * 4); + codeAttribute[index++] = (byte)(tableAttrLength >> 24); + codeAttribute[index++] = (byte)(tableAttrLength >> 16); + codeAttribute[index++] = (byte)(tableAttrLength >> 8); + codeAttribute[index++] = (byte)tableAttrLength; + codeAttribute[index++] = (byte)(itsLineNumberTableTop >> 8); + codeAttribute[index++] = (byte)itsLineNumberTableTop; + for (int i = 0; i < itsLineNumberTableTop; i++) { + codeAttribute[index++] = (byte)(itsLineNumberTable[i] >> 24); + codeAttribute[index++] = (byte)(itsLineNumberTable[i] >> 16); + codeAttribute[index++] = (byte)(itsLineNumberTable[i] >> 8); + codeAttribute[index++] = (byte)itsLineNumberTable[i]; + } + } + + if (vars != null) { + int variableTableAttrIndex + = itsConstantPool.addUtf8("LocalVariableTable"); + codeAttribute[index++] = (byte)(variableTableAttrIndex >> 8); + codeAttribute[index++] = (byte)variableTableAttrIndex; + int varCount = vars.size(); + int tableAttrLength = 2 + (varCount * 10); + codeAttribute[index++] = (byte)(tableAttrLength >> 24); + codeAttribute[index++] = (byte)(tableAttrLength >> 16); + codeAttribute[index++] = (byte)(tableAttrLength >> 8); + codeAttribute[index++] = (byte)tableAttrLength; + codeAttribute[index++] = (byte)(varCount >> 8); + codeAttribute[index++] = (byte)varCount; + for (int i = 0; i < varCount; i++) { + LocalVariable lvar = vars.get(i); + // start pc + int startPc = lvar.getStartPC(); + codeAttribute[index++] = (byte)(startPc >> 8); + codeAttribute[index++] = (byte)startPc; + + // length + int length = itsCodeBufferTop - startPc; + codeAttribute[index++] = (byte)(length >> 8); + codeAttribute[index++] = (byte)length; + + // name index + int nameIndex + = itsConstantPool.addUtf8(lvar.getName()); + codeAttribute[index++] = (byte)(nameIndex >> 8); + codeAttribute[index++] = (byte)nameIndex; + + // descriptor index + int descriptorIndex = itsConstantPool.addUtf8( + lvar.isNumber() + ? "D" + : "Ljava/lang/Object;"); + codeAttribute[index++] = (byte)(descriptorIndex >> 8); + codeAttribute[index++] = (byte)descriptorIndex; + + // index + int jreg = lvar.getJRegister(); + codeAttribute[index++] = (byte)(jreg >> 8); + codeAttribute[index++] = (byte)jreg; + } + } + + itsCurrentMethod.setCodeAttribute(codeAttribute); + + itsExceptionTable = null; + itsExceptionTableTop = 0; + itsLabelTableTop = 0; + itsLineNumberTable = null; + itsCodeBufferTop = 0; + itsCurrentMethod = null; + itsMaxStack = 0; + itsStackTop = 0; + } + + private static final int LineNumberTableSize = 16; + + public void addLineNumberEntry(short lineNumber) + { + if (DEBUG) { + if (itsCurrentMethod == null) + throw new RuntimeException("No method to stop"); + } + + if (itsLineNumberTable == null) { + itsLineNumberTable = new int[LineNumberTableSize]; + itsLineNumberTable[0] = (itsCodeBufferTop << 16) + lineNumber; + itsLineNumberTableTop = 1; + } + else { + if (itsLineNumberTableTop == itsLineNumberTable.length) { + int[] oldTable = itsLineNumberTable; + itsLineNumberTable = new int[itsLineNumberTableTop * 2]; + System.arraycopy(oldTable, 0, itsLineNumberTable, + 0, itsLineNumberTableTop); + } + itsLineNumberTable[itsLineNumberTableTop++] + = (itsCodeBufferTop << 16) + lineNumber; + } + } + + public void write(OutputStream oStream) throws IOException + { + DataOutputStream out = new DataOutputStream(oStream); + + short sourceFileAttributeNameIndex = 0; + if (itsSourceFileNameIndex != 0) + sourceFileAttributeNameIndex + = itsConstantPool.addUtf8("SourceFile"); + + out.writeLong(FileHeaderConstant); + itsConstantPool.write(out); + out.writeShort(itsFlags); + out.writeShort(itsThisClassIndex); + out.writeShort(itsSuperClassIndex); + out.writeShort(itsInterfaces.size()); + for (int i = 0; i < itsInterfaces.size(); i++) { + out.writeShort(((Short)(itsInterfaces.elementAt(i))).shortValue()); + } + out.writeShort(itsFields.size()); + for (int i = 0; i < itsFields.size(); i++) { + ((ClassFileField)(itsFields.elementAt(i))).write(out); + } + out.writeShort(itsMethods.size()); + for (int i = 0; i < itsMethods.size(); i++) { + ((ClassFileMethod)(itsMethods.elementAt(i))).write(out); + } + if (itsSourceFileNameIndex != 0) { + out.writeShort(1); // attributes count + out.writeShort(sourceFileAttributeNameIndex); + out.writeInt(2); + out.writeShort(itsSourceFileNameIndex); + } + else + out.writeShort(0); // no attributes + } + + /* + TODO: fix reference + public void saveStartPC(OptLocalVariable var) { + var.setStartPC(itsCodeBufferTop); + } + */ + + private ExceptionTableEntry itsExceptionTable[]; + private int itsExceptionTableTop; + + private int itsLineNumberTable[]; // pack start_pc & line_number together + private int itsLineNumberTableTop; + + private byte itsCodeBuffer[]; + private int itsCodeBufferTop; + + private ConstantPool itsConstantPool; + + private short itsSourceFileAttributeIndex; + + private ClassFileMethod itsCurrentMethod; + private short itsStackTop; + + private short itsMaxStack; + private short itsMaxLocals; + + private Vector itsMethods = new Vector(); + private Vector itsFields = new Vector(); + private Vector itsInterfaces = new Vector(); + + private short itsFlags; + private short itsThisClassIndex; + private short itsSuperClassIndex; + private short itsSourceFileNameIndex; + +} + +class ExceptionTableEntry { + + ExceptionTableEntry(int startLabel, int endLabel, + int handlerLabel, short catchType) + { + itsStartLabel = startLabel; + itsEndLabel = endLabel; + itsHandlerLabel = handlerLabel; + itsCatchType = catchType; + } + + short getStartPC(Label labelTable[]) + { + short pc = labelTable[itsStartLabel & 0x7FFFFFFF].getPC(); + if (pc == -1) + throw new RuntimeException("start label not defined"); + return pc; + } + + short getEndPC(Label labelTable[]) + { + short pc = labelTable[itsEndLabel & 0x7FFFFFFF].getPC(); + if (pc == -1) + throw new RuntimeException("end label not defined"); + return pc; + } + + short getHandlerPC(Label labelTable[]) + { + short pc = labelTable[itsHandlerLabel & 0x7FFFFFFF].getPC(); + if (pc == -1) + throw new RuntimeException("handler label not defined"); + return pc; + } + + short getCatchType() + { + return itsCatchType; + } + + private int itsStartLabel; + private int itsEndLabel; + private int itsHandlerLabel; + private short itsCatchType; +} + +class ClassFileField { + + ClassFileField(short nameIndex, short typeIndex, short flags) + { + itsNameIndex = nameIndex; + itsTypeIndex = typeIndex; + itsFlags = flags; + } + + ClassFileField(short nameIndex, short typeIndex, short flags, short cvAttr[]) + { + itsNameIndex = nameIndex; + itsTypeIndex = typeIndex; + itsFlags = flags; + itsAttr = cvAttr; + } + + void write(DataOutputStream out) throws IOException + { + out.writeShort(itsFlags); + out.writeShort(itsNameIndex); + out.writeShort(itsTypeIndex); + if (itsAttr == null) + out.writeShort(0); // no attributes + else { + out.writeShort(1); + out.writeShort(itsAttr[0]); + out.writeShort(itsAttr[1]); + out.writeShort(itsAttr[2]); + out.writeShort(itsAttr[3]); + } + } + + private short itsNameIndex; + private short itsTypeIndex; + private short itsFlags; + private short itsAttr[]; +} + +class ClassFileMethod { + + ClassFileMethod(short nameIndex, short typeIndex, short flags) + { + itsNameIndex = nameIndex; + itsTypeIndex = typeIndex; + itsFlags = flags; + } + + void setCodeAttribute(byte codeAttribute[]) + { + itsCodeAttribute = codeAttribute; + } + + void write(DataOutputStream out) throws IOException + { + out.writeShort(itsFlags); + out.writeShort(itsNameIndex); + out.writeShort(itsTypeIndex); + out.writeShort(1); // Code attribute only + out.write(itsCodeAttribute, 0, itsCodeAttribute.length); + } + + private short itsNameIndex; + private short itsTypeIndex; + private short itsFlags; + private byte[] itsCodeAttribute; + +} + +class ConstantPool { + + ConstantPool() + { + itsTopIndex = 1; // the zero'th entry is reserved + itsPool = new byte[ConstantPoolSize]; + itsTop = 0; + } + + private static final int ConstantPoolSize = 256; + private static final byte + CONSTANT_Class = 7, + CONSTANT_Fieldref = 9, + CONSTANT_Methodref = 10, + CONSTANT_InterfaceMethodref = 11, + CONSTANT_String = 8, + CONSTANT_Integer = 3, + CONSTANT_Float = 4, + CONSTANT_Long = 5, + CONSTANT_Double = 6, + CONSTANT_NameAndType = 12, + CONSTANT_Utf8 = 1; + + void write(DataOutputStream out) throws IOException + { + out.writeShort((short)(itsTopIndex)); + out.write(itsPool, 0, itsTop); + } + + short addConstant(int k) + { + ensure(5); + itsPool[itsTop++] = CONSTANT_Integer; + itsPool[itsTop++] = (byte)(k >> 24); + itsPool[itsTop++] = (byte)(k >> 16); + itsPool[itsTop++] = (byte)(k >> 8); + itsPool[itsTop++] = (byte)k; + return (short)(itsTopIndex++); + } + + short addConstant(long k) + { + ensure(9); + itsPool[itsTop++] = CONSTANT_Long; + itsPool[itsTop++] = (byte)(k >> 56); + itsPool[itsTop++] = (byte)(k >> 48); + itsPool[itsTop++] = (byte)(k >> 40); + itsPool[itsTop++] = (byte)(k >> 32); + itsPool[itsTop++] = (byte)(k >> 24); + itsPool[itsTop++] = (byte)(k >> 16); + itsPool[itsTop++] = (byte)(k >> 8); + itsPool[itsTop++] = (byte)k; + short index = (short)(itsTopIndex); + itsTopIndex += 2; + return index; + } + + short addConstant(float k) + { + ensure(5); + itsPool[itsTop++] = CONSTANT_Float; + int bits = Float.floatToIntBits(k); + itsPool[itsTop++] = (byte)(bits >> 24); + itsPool[itsTop++] = (byte)(bits >> 16); + itsPool[itsTop++] = (byte)(bits >> 8); + itsPool[itsTop++] = (byte)bits; + return (short)(itsTopIndex++); + } + + short addConstant(double k) + { + ensure(9); + itsPool[itsTop++] = CONSTANT_Double; + long bits = Double.doubleToLongBits(k); + itsPool[itsTop++] = (byte)(bits >> 56); + itsPool[itsTop++] = (byte)(bits >> 48); + itsPool[itsTop++] = (byte)(bits >> 40); + itsPool[itsTop++] = (byte)(bits >> 32); + itsPool[itsTop++] = (byte)(bits >> 24); + itsPool[itsTop++] = (byte)(bits >> 16); + itsPool[itsTop++] = (byte)(bits >> 8); + itsPool[itsTop++] = (byte)bits; + short index = (short)(itsTopIndex); + itsTopIndex += 2; + return index; + } + + short addConstant(String k) + { + Utf8StringIndexPair theIndex = (Utf8StringIndexPair)(itsUtf8Hash.get(k)); + if (theIndex == null) { + addUtf8(k); + theIndex = (Utf8StringIndexPair)(itsUtf8Hash.get(k)); // OPT + } + if (theIndex.itsStringIndex == -1) { + theIndex.itsStringIndex = (short)(itsTopIndex++); + ensure(3); + itsPool[itsTop++] = CONSTANT_String; + itsPool[itsTop++] = (byte)(theIndex.itsUtf8Index >> 8); + itsPool[itsTop++] = (byte)theIndex.itsUtf8Index; + } + return theIndex.itsStringIndex; + } + + short addUtf8(String contents) + { + Utf8StringIndexPair theIndex = (Utf8StringIndexPair)(itsUtf8Hash.get(contents)); + if (theIndex == null) { + theIndex = new Utf8StringIndexPair((short)(itsTopIndex++), (short)(-1)); + itsUtf8Hash.put(contents, theIndex); + try { + // using DataOutputStream.writeUTF is a lot faster than String.getBytes("UTF8") + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + dos.writeUTF(contents); + byte theBytes[] = baos.toByteArray(); + ensure(1 + theBytes.length); + itsPool[itsTop++] = CONSTANT_Utf8; + System.arraycopy(theBytes, 0, itsPool, itsTop, theBytes.length); + itsTop += theBytes.length; + } + catch (IOException iox) { + throw WrappedException.wrapException(iox); + } + } + return theIndex.itsUtf8Index; + } + + short addNameAndType(short nameIndex, short typeIndex) + { + ensure(5); + itsPool[itsTop++] = CONSTANT_NameAndType; + itsPool[itsTop++] = (byte)(nameIndex >> 8); + itsPool[itsTop++] = (byte)(nameIndex); + itsPool[itsTop++] = (byte)(typeIndex >> 8); + itsPool[itsTop++] = (byte)(typeIndex); + return (short)(itsTopIndex++); + } + + short addClass(short classIndex) + { + Short classIndexKey = new Short(classIndex); + Short theIndex = (Short)(itsClassHash.get(classIndexKey)); + if (theIndex == null) { + ensure(3); + itsPool[itsTop++] = CONSTANT_Class; + itsPool[itsTop++] = (byte)(classIndex >> 8); + itsPool[itsTop++] = (byte)(classIndex); + theIndex = new Short((short)(itsTopIndex++)); + itsClassHash.put(classIndexKey, theIndex); + } + return theIndex.shortValue(); + } + + short addClass(String className) + { + short classIndex + = addUtf8(ClassFileWriter.fullyQualifiedForm(className)); + return addClass(classIndex); + } + + short addFieldRef(String className, String fieldName, String fieldType) + { + String fieldRefString = className + " " + fieldName + " " + fieldType; + Short theIndex = (Short)(itsFieldRefHash.get(fieldRefString)); + if (theIndex == null) { + short nameIndex = addUtf8(fieldName); + short typeIndex = addUtf8(fieldType); + short ntIndex = addNameAndType(nameIndex, typeIndex); + short classIndex = addClass(className); + ensure(5); + itsPool[itsTop++] = CONSTANT_Fieldref; + itsPool[itsTop++] = (byte)(classIndex >> 8); + itsPool[itsTop++] = (byte)(classIndex); + itsPool[itsTop++] = (byte)(ntIndex >> 8); + itsPool[itsTop++] = (byte)(ntIndex); + theIndex = new Short((short)(itsTopIndex++)); + itsFieldRefHash.put(fieldRefString, theIndex); + } + return theIndex.shortValue(); + } + + short addMethodRef(String className, String methodName, String fieldType) + { + String methodRefString = className + " " + methodName + " " + fieldType; + Short theIndex = (Short)(itsMethodRefHash.get(methodRefString)); + if (theIndex == null) { + short nameIndex = addUtf8(methodName); + short typeIndex = addUtf8(fieldType); + short ntIndex = addNameAndType(nameIndex, typeIndex); + short classIndex = addClass(className); + ensure(5); + itsPool[itsTop++] = CONSTANT_Methodref; + itsPool[itsTop++] = (byte)(classIndex >> 8); + itsPool[itsTop++] = (byte)(classIndex); + itsPool[itsTop++] = (byte)(ntIndex >> 8); + itsPool[itsTop++] = (byte)(ntIndex); + theIndex = new Short((short)(itsTopIndex++)); + itsMethodRefHash.put(methodRefString, theIndex); + } + return theIndex.shortValue(); + } + + short addInterfaceMethodRef(String className, + String methodName, String methodType) + { + short nameIndex = addUtf8(methodName); + short typeIndex = addUtf8(methodType); + short ntIndex = addNameAndType(nameIndex, typeIndex); + short classIndex = addClass(className); + ensure(5); + itsPool[itsTop++] = CONSTANT_InterfaceMethodref; + itsPool[itsTop++] = (byte)(classIndex >> 8); + itsPool[itsTop++] = (byte)(classIndex); + itsPool[itsTop++] = (byte)(ntIndex >> 8); + itsPool[itsTop++] = (byte)(ntIndex); + return (short)(itsTopIndex++); + } + + void ensure(int howMuch) + { + while ((itsTop + howMuch) >= itsPool.length) { + byte oldPool[] = itsPool; + itsPool = new byte[itsPool.length * 2]; + System.arraycopy(oldPool, 0, itsPool, 0, itsTop); + } + } + + private Hashtable itsUtf8Hash = new Hashtable(); + private Hashtable itsFieldRefHash = new Hashtable(); + private Hashtable itsMethodRefHash = new Hashtable(); + private Hashtable itsClassHash = new Hashtable(); + + private int itsTop; + private int itsTopIndex; + private byte itsPool[]; +} + +class Utf8StringIndexPair { + + Utf8StringIndexPair(short utf8Index, short stringIndex) + { + itsUtf8Index = utf8Index; + itsStringIndex = stringIndex; + } + + short itsUtf8Index; + short itsStringIndex; +} + diff --git a/js/rhino/src/org/mozilla/javascript/Context.java b/js/rhino/src/org/mozilla/javascript/Context.java index 99e76c69f336..878661d27768 100644 --- a/js/rhino/src/org/mozilla/javascript/Context.java +++ b/js/rhino/src/org/mozilla/javascript/Context.java @@ -474,7 +474,8 @@ public final class Context { "NativeNumber", "NativeDate", "NativeMath", "NativeCall", "NativeClosure", "NativeWith", - "regexp.NativeRegExp", "NativeScript" + "regexp.NativeRegExp", "NativeScript", + "JavaAdapter" }; for (int i=0; i < classes.length; i++) { try { @@ -488,9 +489,6 @@ public final class Context { // This creates the Packages and java package roots. NativeJavaPackage.init(scope); - - // Define JavaAdapter class if possible. - getCompiler().defineJavaAdapter(scope); } // All of these exceptions should not occur since we are initializing // from known classes diff --git a/js/rhino/src/org/mozilla/javascript/Interpreter.java b/js/rhino/src/org/mozilla/javascript/Interpreter.java index 6d99f5f15d23..7c5a8046ed06 100644 --- a/js/rhino/src/org/mozilla/javascript/Interpreter.java +++ b/js/rhino/src/org/mozilla/javascript/Interpreter.java @@ -53,19 +53,7 @@ public class Interpreter extends LabelTable { } return generateScriptICode(cx, scope, tree, securityDomain); } - - public void defineJavaAdapter(Scriptable scope) { - // do nothing; only the code generator can define the JavaAdapter - try { - String adapterName = System.getProperty("org.mozilla.javascript.JavaAdapter"); - if (adapterName != null) { - Class adapterClass = Class.forName(adapterName); - ScriptableObject.defineClass(scope, adapterClass); - } - } catch (Exception e) { - } - } - + private void generateICodeFromTree(Node tree, VariableTable varTable, boolean needsActivation, diff --git a/js/rhino/src/org/mozilla/javascript/JavaAdapter.java b/js/rhino/src/org/mozilla/javascript/JavaAdapter.java new file mode 100644 index 000000000000..273e14de5fc1 --- /dev/null +++ b/js/rhino/src/org/mozilla/javascript/JavaAdapter.java @@ -0,0 +1,492 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package org.mozilla.javascript; + +import org.mozilla.classfile.*; +import java.lang.reflect.*; +import java.io.*; +import java.util.*; + +public class JavaAdapter extends ScriptableObject { + + public String getClassName() { + return "JavaAdapter"; + } + + public static Object js_JavaAdapter(Context cx, Object[] args, + Function ctorObj, boolean inNewExpr) + throws InstantiationException, NoSuchMethodException, + IllegalAccessException, InvocationTargetException, + ClassNotFoundException + { + Class superClass = Object.class; + Class[] intfs = new Class[args.length-1]; + int interfaceCount = 0; + for (int i=0; i < args.length-1; i++) { + if (!(args[i] instanceof NativeJavaClass)) { + // TODO: report error + throw new RuntimeException("expected java class object"); + } + Class c = ((NativeJavaClass) args[i]).getClassObject(); + if (!c.isInterface()) { + superClass = c; + break; + } + intfs[interfaceCount++] = c; + } + + StringBuffer sb = new StringBuffer("adapter"); + sb.append(serial++); + String genName = sb.toString(); + ClassFileWriter cfw = new ClassFileWriter(genName, + superClass.getName(), + ""); + cfw.addField("o", "Lorg/mozilla/javascript/FlattenedObject;", + ClassFileWriter.ACC_PRIVATE); + cfw.addField("self", "Lorg/mozilla/javascript/Scriptable;", + (short) (ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_FINAL)); + for (int i = 0; i < interfaceCount; i++) { + if (intfs[i] != null) + cfw.addInterface(intfs[i].getName()); + } + + generateCtor(cfw, genName, superClass); + + Hashtable generatedOverrides = new Hashtable(); + + // if abstract class was specified, then generate appropriate overrides. + for (int i = 0; i < interfaceCount; i++) { + Method[] methods = intfs[i].getMethods(); + for (int j = 0; j < methods.length; j++) { + Method method = methods[j]; + int mods = method.getModifiers(); + if (Modifier.isStatic(mods) || Modifier.isFinal(mods)) + continue; + // make sure to generate only one instance of a particular + // method/signature. + String methodKey = getMethodSignature(method); + if (! generatedOverrides.containsKey(methodKey)) { + generateOverride(cfw, genName, method); + generatedOverrides.put(methodKey, methodKey); + } + } + } + + // Now, go through the superclasses methods, checking for abstract methods + // or additional methods to override. + FlattenedObject obj = new FlattenedObject( + (Scriptable) args[args.length - 1]); + + // generate any additional overrides that the object might contain. + Method[] methods = superClass.getMethods(); + for (int j = 0; j < methods.length; j++) { + Method method = methods[j]; + int mods = method.getModifiers(); + if (Modifier.isStatic(mods) || Modifier.isFinal(mods)) + continue; + // if a method is marked abstract, must implement it or the + // resulting class won't be instantiable. otherwise, if the object + // has a property of the same name, then an override is intended. + if (Modifier.isAbstract(mods) || obj.hasProperty(method.getName())) { + // make sure to generate only one instance of a particular + // method/signature. + String methodKey = getMethodSignature(method); + if (! generatedOverrides.containsKey(methodKey)) { + generateOverride(cfw, genName, method); + generatedOverrides.put(methodKey, method); + } + } + } + + // TODO: generate Java methods, fields for remaining properties that + // are not overrides? Probably not necessary to generate methods + // that aren't overrides. + + ByteArrayOutputStream out = new ByteArrayOutputStream(512); + try { + cfw.write(out); + } + catch (IOException ioe) { + throw new RuntimeException("unexpected IOException"); + } + byte[] bytes = out.toByteArray(); + classLoader.defineClass(genName, bytes); + Class c = classLoader.loadClass(genName, true); + Class[] ctorParms = { FlattenedObject.class }; + Object[] ctorArgs = { obj }; + Object v = c.getConstructor(ctorParms).newInstance(ctorArgs); + return cx.toObject(v, ScriptableObject.getTopLevelScope(ctorObj)); + } + + /** + * Utility method, which dynamically binds a Context to the current thread, + * if none already exists. + */ + public static Object callMethod(FlattenedObject object, Object methodId, + Object[] args) + { + try { + // old way, bind a Context dynamically, unbind if it wasn't there before. + Context cx = Context.getCurrentContext(); + if (cx == null) { + cx = new Context(); + cx.enter(); + try { + return (object.hasProperty(methodId) + ? object.callMethod(methodId, args) + : Context.getUndefinedValue()); + } finally { + cx.exit(); + } + } else { + return (object.hasProperty(methodId) + ? object.callMethod(methodId, args) + : Context.getUndefinedValue()); + } + } catch (Exception ex) { + ex.printStackTrace(System.err); + throw new Error(ex.getMessage()); + } + } + + private static void generateCtor(ClassFileWriter cfw, String genName, + Class superClass) + { + cfw.startMethod("", + "(Lorg/mozilla/javascript/FlattenedObject;)V", + ClassFileWriter.ACC_PUBLIC); + + // Invoke base class constructor + cfw.add(ByteCode.ALOAD_0); // this + cfw.add(ByteCode.INVOKESPECIAL, + superClass.getName().replace('.', '/'), + "", "()", "V"); + + // save parameter in instance variable + cfw.add(ByteCode.ALOAD_0); // this + cfw.add(ByteCode.ALOAD_1); // first arg + cfw.add(ByteCode.PUTFIELD, genName, "o", + "Lorg/mozilla/javascript/FlattenedObject;"); + + // store Scriptable object in "self" a public instance variable, so scripts can read it. + cfw.add(ByteCode.ALOAD_0); // this + cfw.add(ByteCode.ALOAD_1); // first arg + cfw.add(ByteCode.INVOKEVIRTUAL, + "org/mozilla/javascript/FlattenedObject", + "getObject", "()", + "Lorg/mozilla/javascript/Scriptable;"); + cfw.add(ByteCode.PUTFIELD, genName, "self", + "Lorg/mozilla/javascript/Scriptable;"); + + cfw.add(ByteCode.RETURN); + cfw.stopMethod((short)20, null); // TODO: magic number "20" + } + + /** + * Generates code to create a java.lang.Boolean, java.lang.Character or a + * java.lang.Double to wrap the specified primitive parameter. Leaves the + * wrapper object on the top of the stack. + */ + private static int generateWrapParam(ClassFileWriter cfw, int paramOffset, + Class paramType) + { + if (paramType.equals(Boolean.TYPE)) { + // wrap boolean values with java.lang.Boolean. + cfw.add(ByteCode.NEW, "java/lang/Boolean"); + cfw.add(ByteCode.DUP); + cfw.add(ByteCode.ILOAD, paramOffset++); + cfw.add(ByteCode.INVOKESPECIAL, "java/lang/Boolean", + "", "(Z)", "V"); + } else + if (paramType.equals(Character.TYPE)) { + // Create a string of length 1 using the character parameter. + cfw.add(ByteCode.NEW, "java/lang/String"); + cfw.add(ByteCode.DUP); + cfw.add(ByteCode.ICONST_1); + cfw.add(ByteCode.NEWARRAY, ByteCode.T_CHAR); + cfw.add(ByteCode.DUP); + cfw.add(ByteCode.ICONST_0); + cfw.add(ByteCode.ILOAD, paramOffset++); + cfw.add(ByteCode.CASTORE); + cfw.add(ByteCode.INVOKESPECIAL, "java/lang/String", + "", "([C)", "V"); + } else { + // convert all numeric values to java.lang.Double. + cfw.add(ByteCode.NEW, "java/lang/Double"); + cfw.add(ByteCode.DUP); + String typeName = paramType.getName(); + switch (typeName.charAt(0)) { + case 'b': + case 's': + case 'i': + // load an int value, convert to double. + cfw.add(ByteCode.ILOAD, paramOffset++); + cfw.add(ByteCode.I2D); + break; + case 'l': + // load a long, convert to double. + cfw.add(ByteCode.LLOAD, paramOffset); + cfw.add(ByteCode.L2D); + paramOffset += 2; + break; + case 'f': + // load a float, convert to double. + cfw.add(ByteCode.FLOAD, paramOffset++); + cfw.add(ByteCode.F2D); + break; + case 'd': + cfw.add(ByteCode.DLOAD, paramOffset); + paramOffset += 2; + break; + } + cfw.add(ByteCode.INVOKESPECIAL, "java/lang/Double", + "", "(D)", "V"); + } + return paramOffset; + } + + /** + * Generates code to convert a wrapped value type to a primitive type. + * Handles unwrapping java.lang.Boolean, and java.lang.Number types. + * May need to map between char and java.lang.String as well. + * Generates the appropriate RETURN bytecode. + */ + private static void generateReturnResult(ClassFileWriter cfw, + Class retType) + { + // wrap boolean values with java.lang.Boolean, convert all other + // primitive values to java.lang.Double. + if (retType.equals(Boolean.TYPE)) { + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/Context", + "toBoolean", "(Ljava/lang/Object;)", + "Z"); + cfw.add(ByteCode.IRETURN); + } else if (retType.equals(Character.TYPE)) { + // characters are represented as strings in JavaScript. + // return the first character. + // first convert the value to a string if possible. + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/Context", + "toString", "(Ljava/lang/Object;)", + "Ljava/lang/String;"); + cfw.add(ByteCode.ICONST_0); + cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/String", "charAt", + "(I)", "C"); + cfw.add(ByteCode.IRETURN); + } else if (retType.isPrimitive()) { + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/Context", + "toNumber", "(Ljava/lang/Object;)", + "D"); + String typeName = retType.getName(); + switch (typeName.charAt(0)) { + case 'b': + case 's': + case 'i': + cfw.add(ByteCode.D2I); + cfw.add(ByteCode.IRETURN); + break; + case 'l': + cfw.add(ByteCode.D2L); + cfw.add(ByteCode.LRETURN); + break; + case 'f': + cfw.add(ByteCode.D2F); + cfw.add(ByteCode.FRETURN); + break; + case 'd': + cfw.add(ByteCode.DRETURN); + break; + default: + throw new RuntimeException("Unexpected return type " + + retType.toString()); + } + } else if (retType.equals(String.class)) { + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/Context", + "toString", "(Ljava/lang/Object;)", + "Ljava/lang/String;"); + cfw.add(ByteCode.ARETURN); + } else if (retType.equals(Scriptable.class)) { + cfw.add(ByteCode.ALOAD_0); // load 'this' to find scope from + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/Context", + "toObject", + "(Ljava/lang/Object;" + + "Lorg/mozilla/javascript/Scriptable;)", + "Lorg/mozilla/javascript/Scriptable;"); + cfw.add(ByteCode.ARETURN); + } else { + // If it is a wrapped type, cast to Wrapper and call unwrap() + cfw.add(ByteCode.DUP); + cfw.add(ByteCode.INSTANCEOF, "org/mozilla/javascript/Wrapper"); + // skip 3 for IFEQ, 3 for CHECKCAST, and 3 for INVOKEVIRTUAL + cfw.add(ByteCode.IFEQ, 9); + cfw.add(ByteCode.CHECKCAST, "org/mozilla/javascript/Wrapper"); + cfw.add(ByteCode.INVOKEVIRTUAL, + "org/mozilla/javascript/Wrapper", + "unwrap", "()", "Ljava/lang/Object;"); + // Now cast to return type + String retTypeStr = retType.getName().replace('.', '/'); + cfw.add(ByteCode.CHECKCAST, retTypeStr); + cfw.add(ByteCode.ARETURN); + } + } + + private static void generateOverride(ClassFileWriter cfw, String genName, + Method m) + { + Class[] parms = m.getParameterTypes(); + StringBuffer sb = new StringBuffer(); + sb.append('('); + short arrayLocal = 1; // includes this. + for (int i = 0; i < parms.length; i++) { + Class type = parms[i]; + appendTypeString(sb, type); + if (type.equals(Long.TYPE) || type.equals(Double.TYPE)) + arrayLocal += 2; + else + arrayLocal += 1; + } + sb.append(')'); + appendTypeString(sb, m.getReturnType()); + String methodSignature = sb.toString(); + // System.out.println("generating " + m.getName() + methodSignature); + // System.out.flush(); + cfw.startMethod(m.getName(), methodSignature, + ClassFileWriter.ACC_PUBLIC); + cfw.add(ByteCode.BIPUSH, (byte) parms.length); // > 255 parms? + cfw.add(ByteCode.ANEWARRAY, "java/lang/Object"); + cfw.add(ByteCode.ASTORE, arrayLocal); + + // allocate a local variable to store the scope used to wrap native objects. + short scopeLocal = (short) (arrayLocal + 1); + boolean loadedScope = false; + + int paramOffset = 1; + for (int i = 0; i < parms.length; i++) { + cfw.add(ByteCode.ALOAD, arrayLocal); + cfw.add(ByteCode.BIPUSH, i); + if (parms[i].isPrimitive()) { + paramOffset = generateWrapParam(cfw, paramOffset, parms[i]); + } else { + // An arbitary Java object; call Context.toObject to wrap in + // a Scriptable object + cfw.add(ByteCode.ALOAD, paramOffset++); + if (! loadedScope) { + // load this.self into a local the first time it's needed. + // it will provide the scope needed by Context.toObject(). + cfw.add(ByteCode.ALOAD_0); + cfw.add(ByteCode.GETFIELD, genName, "self", + "Lorg/mozilla/javascript/Scriptable;"); + cfw.add(ByteCode.ASTORE, scopeLocal); + loadedScope = true; + } + cfw.add(ByteCode.ALOAD, scopeLocal); + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/Context", + "toObject", + "(Ljava/lang/Object;" + + "Lorg/mozilla/javascript/Scriptable;)", + "Lorg/mozilla/javascript/Scriptable;"); + } + cfw.add(ByteCode.AASTORE); + } + + cfw.add(ByteCode.ALOAD_0); // this + cfw.add(ByteCode.GETFIELD, genName, "o", + "Lorg/mozilla/javascript/FlattenedObject;"); + + cfw.addLoadConstant(m.getName()); + cfw.add(ByteCode.ALOAD, arrayLocal); + + // go through utility method, which creates a Context to run the + // method in. + cfw.add(ByteCode.INVOKESTATIC, + "org/mozilla/javascript/JavaAdapter", + "callMethod", + "(Lorg/mozilla/javascript/FlattenedObject;" + + "Ljava/lang/Object;[Ljava/lang/Object;)", + "Ljava/lang/Object;"); + + Class retType = m.getReturnType(); + if (retType.equals(Void.TYPE)) { + cfw.add(ByteCode.POP); + cfw.add(ByteCode.RETURN); + } else { + generateReturnResult(cfw, retType); + } + cfw.stopMethod((short)(scopeLocal + 1), null); + } + + /** + * Returns a fully qualified method name concatenated with its signature. + */ + private static String getMethodSignature(Method method) { + Class[] parms = method.getParameterTypes(); + StringBuffer sb = new StringBuffer(); + sb.append(method.getName()); + sb.append('('); + for (int i = 0; i < parms.length; i++) { + Class type = parms[i]; + appendTypeString(sb, type); + } + sb.append(')'); + appendTypeString(sb, method.getReturnType()); + return sb.toString(); + } + + private static StringBuffer appendTypeString(StringBuffer sb, Class type) + { + while (type.isArray()) { + sb.append('['); + type = type.getComponentType(); + } + if (type.isPrimitive()) { + if (type.equals(Boolean.TYPE)) { + sb.append('Z'); + } else + if (type.equals(Long.TYPE)) { + sb.append('J'); + } else { + String typeName = type.getName(); + sb.append(Character.toUpperCase(typeName.charAt(0))); + } + } else { + sb.append('L'); + sb.append(type.getName().replace('.', '/')); + sb.append(';'); + } + return sb; + } + + static final class MyClassLoader extends ClassLoader { + public Class defineClass(String name, byte data[]) { + return super.defineClass(name, data, 0, data.length); + } + + protected Class loadClass(String name, boolean resolve) + throws ClassNotFoundException + { + Class clazz = findLoadedClass(name); + if (clazz == null) { + ClassLoader loader = getClass().getClassLoader(); + if (loader != null) + return loader.loadClass(name); + clazz = findSystemClass(name); + } + if (resolve) + resolveClass(clazz); + return clazz; + } + + private java.util.Hashtable loaded; + } + + private static int serial; + private static MyClassLoader classLoader = new MyClassLoader(); +} diff --git a/js/rhino/src/org/mozilla/javascript/LocalVariable.java b/js/rhino/src/org/mozilla/javascript/LocalVariable.java index d455a68db5f6..5098242eca34 100644 --- a/js/rhino/src/org/mozilla/javascript/LocalVariable.java +++ b/js/rhino/src/org/mozilla/javascript/LocalVariable.java @@ -33,6 +33,28 @@ public class LocalVariable { public String getName() { return itsName; } + /** + * Return the starting PC where this variable is live, or -1 + * if it is not a Java register. + */ + public int getStartPC() { + return -1; + } + + /** + * Return the Java register number or -1 if it is not a Java register. + */ + public short getJRegister() { + return -1; + } + + /** + * Return true if the local variable is a Java register with double type. + */ + public boolean isNumber() { + return false; + } + private String itsName; private int itsIndex = -1; diff --git a/js/rhino/src/org/mozilla/javascript/VariableTable.java b/js/rhino/src/org/mozilla/javascript/VariableTable.java index 1cfbd83927fd..bd8414886ef3 100644 --- a/js/rhino/src/org/mozilla/javascript/VariableTable.java +++ b/js/rhino/src/org/mozilla/javascript/VariableTable.java @@ -112,7 +112,7 @@ public class VariableTable { itsVariables.addElement(lVar); itsVariableNames.put(vName, new Integer(index)); } - + // a list of the formal parameters and local variables protected Vector itsVariables = new Vector();