Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.classfile;
/**
* Helper class for internal representations of type information. In most
* cases, type information can be represented by a constant, but in some
* cases, a payload is included. Despite the payload coming after the type
* tag in the output, we store it in bits 8-23 for uniformity; the tag is
* always in bits 0-7.
*/
final class TypeInfo {
private TypeInfo() { }
static final int TOP = 0;
static final int INTEGER = 1;
static final int FLOAT = 2;
static final int DOUBLE = 3;
static final int LONG = 4;
static final int NULL = 5;
static final int UNINITIALIZED_THIS = 6;
static final int OBJECT_TAG = 7;
static final int UNINITIALIZED_VAR_TAG = 8;
static final int OBJECT(int constantPoolIndex) {
return ((constantPoolIndex & 0xFFFF) << 8) | OBJECT_TAG;
}
static final int OBJECT(String type, ConstantPool pool) {
return OBJECT(pool.addClass(type));
}
static final int UNINITIALIZED_VARIABLE(int bytecodeOffset) {
return ((bytecodeOffset & 0xFFFF) << 8) | UNINITIALIZED_VAR_TAG;
}
static final int getTag(int typeInfo) {
return typeInfo & 0xFF;
}
static final int getPayload(int typeInfo) {
return typeInfo >>> 8;
}
/**
* Treat the result of getPayload as a constant pool index and fetch the
* corresponding String mapped to it.
*
* Only works on OBJECT types.
*/
static final String getPayloadAsType(int typeInfo, ConstantPool pool) {
if (getTag(typeInfo) == OBJECT_TAG) {
return (String) pool.getConstantData(getPayload(typeInfo));
}
throw new IllegalArgumentException("expecting object type");
}
/**
* Create type information from an internal type.
*/
static final int fromType(String type, ConstantPool pool) {
if (type.length() == 1) {
switch (type.charAt(0)) {
case 'B': // sbyte
case 'C': // unicode char
case 'S': // short
case 'Z': // boolean
case 'I': // all of the above are verified as integers
return INTEGER;
case 'D':
return DOUBLE;
case 'F':
return FLOAT;
case 'J':
return LONG;
default:
throw new IllegalArgumentException("bad type");
}
}
return TypeInfo.OBJECT(type, pool);
}
static boolean isTwoWords(int type) {
return type == DOUBLE || type == LONG;
}
/**
* Merge two verification types.
*
* In most cases, the verification types must be the same. For example,
* INTEGER and DOUBLE cannot be merged and an exception will be thrown.
* The basic rules are:
*
* - If the types are equal, simply return one.
* - If either type is TOP, return TOP.
* - If either type is NULL, return the other type.
* - If both types are objects, find the lowest common ancestor in the
* class hierarchy.
*
* This method uses reflection to traverse the class hierarchy. Therefore,
* it is assumed that the current class being generated is never the target
* of a full object-object merge, which would need to load the current
* class reflectively.
*/
static int merge(int current, int incoming, ConstantPool pool) {
int currentTag = getTag(current);
int incomingTag = getTag(incoming);
boolean currentIsObject = currentTag == TypeInfo.OBJECT_TAG;
boolean incomingIsObject = incomingTag == TypeInfo.OBJECT_TAG;
if (current == incoming || (currentIsObject && incoming == NULL)) {
return current;
} else if (currentTag == TypeInfo.TOP ||
incomingTag == TypeInfo.TOP) {
return TypeInfo.TOP;
} else if (current == NULL && incomingIsObject) {
return incoming;
} else if (currentIsObject && incomingIsObject) {
String currentName = getPayloadAsType(current, pool);
String incomingName = getPayloadAsType(incoming, pool);
// The class file always has the class and super names in the same
// spot. The constant order is: class_data, class_name, super_data,
// super_name.
String currentlyGeneratedName = (String) pool.getConstantData(2);
String currentlyGeneratedSuperName =
(String) pool.getConstantData(4);
// If any of the merged types are the class that's currently being
// generated, automatically start at the super class instead. At
// this point, we already know the classes are different, so we
// don't need to handle that case.
if (currentName.equals(currentlyGeneratedName)) {
currentName = currentlyGeneratedSuperName;
}
if (incomingName.equals(currentlyGeneratedName)) {
incomingName = currentlyGeneratedSuperName;
}
Class currentClass = getClassFromInternalName(currentName);
Class incomingClass = getClassFromInternalName(incomingName);
if (currentClass.isAssignableFrom(incomingClass)) {
return current;
} else if (incomingClass.isAssignableFrom(currentClass)) {
return incoming;
} else if (incomingClass.isInterface() ||
currentClass.isInterface()) {
// For verification purposes, Sun specifies that interfaces are
// subtypes of Object. Therefore, we know that the merge result
// involving interfaces where one is not assignable to the
// other results in Object.
return OBJECT("java/lang/Object", pool);
} else {
Class commonClass = incomingClass.getSuperclass();
while (commonClass != null) {
if (commonClass.isAssignableFrom(currentClass)) {
String name = commonClass.getName();
name = ClassFileWriter.getSlashedForm(name);
return OBJECT(name, pool);
}
commonClass = commonClass.getSuperclass();
}
}
}
throw new IllegalArgumentException("bad merge attempt between " +
toString(current, pool) + " and " +
toString(incoming, pool));
}
static String toString(int type, ConstantPool pool) {
int tag = getTag(type);
switch (tag) {
case TypeInfo.TOP:
return "top";
case TypeInfo.INTEGER:
return "int";
case TypeInfo.FLOAT:
return "float";
case TypeInfo.DOUBLE:
return "double";
case TypeInfo.LONG:
return "long";
case TypeInfo.NULL:
return "null";
case TypeInfo.UNINITIALIZED_THIS:
return "uninitialized_this";
default:
if (tag == TypeInfo.OBJECT_TAG) {
return getPayloadAsType(type, pool);
} else if (tag == TypeInfo.UNINITIALIZED_VAR_TAG) {
return "uninitialized";
} else {
throw new IllegalArgumentException("bad type");
}
}
}
/**
* Take an internal name and return a java.lang.Class instance that
* represents it.
*
* For example, given "java/lang/Object", returns the equivalent of
* Class.forName("java.lang.Object"), but also handles exceptions.
*/
private static Class getClassFromInternalName(String internalName) {
try {
return Class.forName(internalName.replace('/', '.'));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
private static String toString(int[] types, int typesTop, ConstantPool pool) {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < typesTop; i++) {
if (i > 0) {
sb.append(", ");
}
sb.append(toString(types[i], pool));
}
sb.append("]");
return sb.toString();
}
static void print(int[] locals, int[] stack, ConstantPool pool) {
print(locals, locals.length, stack, stack.length, pool);
}
static void print(int[] locals, int localsTop, int[] stack, int stackTop,
ConstantPool pool) {
System.out.print("locals: ");
System.out.println(toString(locals, localsTop, pool));
System.out.print("stack: ");
System.out.println(toString(stack, stackTop, pool));
System.out.println();
}
}