/** {@inheritDoc} */ public void convert(Klass klass) { lastClassNameStack.push(klass.getName()); int state = klass.getState(); if (state < Klass.STATE_CONVERTING) { if (klass.isArray()) { convert(Klass.OBJECT); klass.changeState(Klass.STATE_CONVERTED); } else { traceProgress(); ClassFile classFile = getClassFile(klass); classFile.convertPhase1(this, translationStrategy != BY_METHOD); if (klass.hasGlobalStatics()) { // record globals now. recordGlobalStatics(klass); } if (translationStrategy == BY_METHOD || translationStrategy == BY_CLASS) { // if NOT inlining, then generate squawk code now. classFile.convertPhase2(this, translationStrategy == BY_METHOD); classFiles.remove(klass.getName()); } } } lastClassNameStack.pop(); }
public void dumpReplayData(PrintStream out) { NMethod nm = getNativeMethod(); int code_size = 0; if (nm != null) { code_size = (int) nm.codeEnd().minus(nm.getVerifiedEntryPoint()); } Klass holder = getMethodHolder(); out.println( "ciMethod " + holder.getName().asString() + " " + OopUtilities.escapeString(getName().asString()) + " " + getSignature().asString() + " " + getInvocationCount() + " " + getBackedgeCount() + " " + interpreterInvocationCount() + " " + interpreterThrowoutCount() + " " + code_size); }
/** * Tests two given types to ensure that they are both {@link Klass#isSquawkPrimitive() Squawk * primitives} or both not Squawk primitives. If they are both Squawk primitives, then they must * be exactly the same type. This enforces the constraint that Squawk primitive values cannot be * assigned to or compared with any other type. * * @param type1 the first type to compare * @param type2 the second type to compare */ public void verifyUseOfSquawkPrimitive(Klass type1, Klass type2) { if (type1.isSquawkPrimitive() || type2.isSquawkPrimitive()) { if (type1 != type2) { // Offsets are implemented as Words // if (type1.getClassID() + type2.getClassID() != CID.UWORD + CID.OFFSET) { String type = type1.getName(); throw codeParser.verifyError( type + " values can only be written to or compared with other " + type + " values, not with " + type2.getName()); // } } } }
/** * Generate squawk code for methods of <code>klass</code> when doing whole-suite translation * (inlining, etc.) * * @param klass the klass to generate code for */ void convertPhase2(Klass klass) { Assert.that(translationStrategy != BY_METHOD); convert(klass); if (klass.getState() < Klass.STATE_CONVERTED) { if (!VM .isVerbose()) { // "squawk -verbose" will show the class names as it finishes loading // them, which is progress enough traceProgress(); } lastClassNameStack.push(klass.getName()); ClassFile classFile = getClassFile(klass); classFile.convertPhase2(this, false); classFiles.remove(klass.getName()); lastClassNameStack.pop(); } }
/** * Gets the class file corresponding to a given instance class. The <code>klass</code> must not * yet be converted and it must not be a {@link Klass#isSynthetic() synthetic} class. * * @param klass the instance class for which a class file is requested * @return the class file for <code>klass</code> */ ClassFile getClassFile(Klass klass) { Assert.that(!klass.isSynthetic(), "synthethic class has no classfile"); String name = klass.getName(); ClassFile classFile = (ClassFile) classFiles.get(name); if (classFile == null) { classFile = new ClassFile(klass); classFiles.put(name, classFile); } return classFile; }
boolean computeSubtypeOf(Klass k) { // An array is a subtype of Serializable, Clonable, and Object Symbol name = k.getName(); if (name != null && (name.equals(javaIoSerializableName()) || name.equals(javaLangCloneableName()) || name.equals(javaLangObjectName()))) { return true; } else { return false; } }
/** * Creates and returns the detailed error message when a local variable is used as a Squawk * primitive as well as some value not of exactly the same type. The message includes information * derived from the LocalVariableTable attribute so that the source code can be easily changed. * * @param index the local variable index that is (mis)used * @return the detailed error message */ private String getBadAddressLocalVariableMessage(int index, Klass type1, Klass type2) { Assert.that(type1.isSquawkPrimitive() || type2.isSquawkPrimitive()); if (type2.isSquawkPrimitive()) { Klass otherType = type1; type1 = type2; type2 = otherType; } StringBuffer buf = new StringBuffer( "Stack location " + index + " cannot be used for both a local variable of type " + type1.getName() + " and of type " + type2.getName() + ". Try moving the variable of type " + type1.getName() + " to the top-most scope of the method."); Enumeration e = codeParser.getLocalVariableTableEntries(); if (e != null) { buf.append(" (source code usage: "); while (e.hasMoreElements()) { LocalVariableTableEntry entry = (LocalVariableTableEntry) e.nextElement(); if (entry.getIndex() == index) { int start = codeParser.getSourceLineNumber(entry.getStart().getBytecodeOffset()); int end = codeParser.getSourceLineNumber(entry.getEnd().getBytecodeOffset()); buf.append(entry.getType().getName()) .append(' ') .append(entry.getName()) .append(" from line ") .append(start) .append(" to line ") .append(end) .append(';'); } } } return buf.toString(); }
/** * Gets the fully qualified name of this type. The returned name is formatted as it might appear * in a Java programming language declaration for objects of this type. * * <p>For primitive classes the returned name is the name of the corresponding primitive type; for * example, "int" is returned as the name of the class represented by {@link * java.lang.Integer#TYPE Integer.TYPE}. * * @return a string containing the type name. */ public String getName() { String name = klass.getName(); if (!klass.isArray()) { return name; } int dimensions = 0; while (name.charAt(dimensions) == '[') { ++dimensions; } name = name.substring(dimensions); char first = name.charAt(0); if (first == 'L') { name = name.substring(1, name.length() - 2).replace('/', '.'); } else { switch (first) { case 'I': name = "int"; break; case 'J': name = "long"; break; case 'F': name = "float"; break; case 'D': name = "double"; break; case 'Z': name = "boolean"; break; case 'C': name = "char"; break; case 'S': name = "short"; break; case 'B': name = "byte"; break; case 'V': name = "void"; break; } } while (dimensions-- != 0) { name += "[]"; } return name; }
/** {@inheritDoc} */ public void load(Klass klass) { Assert.that(VM.isHosted() || VM.getCurrentIsolate().getLeafSuite() == suite); int state = klass.getState(); if (state < Klass.STATE_LOADED) { if (klass.isArray()) { load(klass.getComponentType()); } else { lastClassNameStack.push(klass.getName()); ClassFile classFile = getClassFile(klass); load(classFile); lastClassNameStack.pop(); } } }
public void writeBytes(OutputStream os) throws IOException { // Map between any modified UTF-8 and it's constant pool index. Map utf8ToIndex = new HashMap(); DataOutputStream dos = new DataOutputStream(os); TypeArray tags = getTags(); int len = (int) getLength(); int ci = 0; // constant pool index // collect all modified UTF-8 Strings from Constant Pool for (ci = 1; ci < len; ci++) { byte cpConstType = tags.getByteAt(ci); if (cpConstType == JVM_CONSTANT_Utf8) { Symbol sym = getSymbolAt(ci); utf8ToIndex.put(sym.asString(), new Short((short) ci)); } else if (cpConstType == JVM_CONSTANT_Long || cpConstType == JVM_CONSTANT_Double) { ci++; } } for (ci = 1; ci < len; ci++) { int cpConstType = (int) tags.getByteAt(ci); // write cp_info // write constant type switch (cpConstType) { case JVM_CONSTANT_Utf8: { dos.writeByte(cpConstType); Symbol sym = getSymbolAt(ci); dos.writeShort((short) sym.getLength()); dos.write(sym.asByteArray()); if (DEBUG) debugMessage("CP[" + ci + "] = modified UTF-8 " + sym.asString()); break; } case JVM_CONSTANT_Unicode: throw new IllegalArgumentException("Unicode constant!"); case JVM_CONSTANT_Integer: dos.writeByte(cpConstType); dos.writeInt(getIntAt(ci)); if (DEBUG) debugMessage("CP[" + ci + "] = int " + getIntAt(ci)); break; case JVM_CONSTANT_Float: dos.writeByte(cpConstType); dos.writeFloat(getFloatAt(ci)); if (DEBUG) debugMessage("CP[" + ci + "] = float " + getFloatAt(ci)); break; case JVM_CONSTANT_Long: { dos.writeByte(cpConstType); long l = getLongAt(ci); // long entries occupy two pool entries ci++; dos.writeLong(l); break; } case JVM_CONSTANT_Double: dos.writeByte(cpConstType); dos.writeDouble(getDoubleAt(ci)); // double entries occupy two pool entries ci++; break; case JVM_CONSTANT_Class: { dos.writeByte(cpConstType); // Klass already resolved. ConstantPool constains klassOop. Klass refKls = (Klass) getObjAt(ci); String klassName = refKls.getName().asString(); Short s = (Short) utf8ToIndex.get(klassName); dos.writeShort(s.shortValue()); if (DEBUG) debugMessage("CP[" + ci + "] = class " + s); break; } // case JVM_CONSTANT_ClassIndex: case JVM_CONSTANT_UnresolvedClass: { dos.writeByte(JVM_CONSTANT_Class); String klassName = getSymbolAt(ci).asString(); Short s = (Short) utf8ToIndex.get(klassName); dos.writeShort(s.shortValue()); if (DEBUG) debugMessage("CP[" + ci + "] = class " + s); break; } case JVM_CONSTANT_String: { dos.writeByte(cpConstType); String str = OopUtilities.stringOopToString(getObjAt(ci)); Short s = (Short) utf8ToIndex.get(str); dos.writeShort(s.shortValue()); if (DEBUG) debugMessage("CP[" + ci + "] = string " + s); break; } // case JVM_CONSTANT_StringIndex: case JVM_CONSTANT_UnresolvedString: { dos.writeByte(JVM_CONSTANT_String); String val = getSymbolAt(ci).asString(); Short s = (Short) utf8ToIndex.get(val); dos.writeShort(s.shortValue()); if (DEBUG) debugMessage("CP[" + ci + "] = string " + s); break; } // all external, internal method/field references case JVM_CONSTANT_Fieldref: case JVM_CONSTANT_Methodref: case JVM_CONSTANT_InterfaceMethodref: { dos.writeByte(cpConstType); int value = getIntAt(ci); short klassIndex = (short) extractLowShortFromInt(value); short nameAndTypeIndex = (short) extractHighShortFromInt(value); dos.writeShort(klassIndex); dos.writeShort(nameAndTypeIndex); if (DEBUG) debugMessage( "CP[" + ci + "] = ref klass = " + klassIndex + ", N&T = " + nameAndTypeIndex); break; } case JVM_CONSTANT_NameAndType: { dos.writeByte(cpConstType); int value = getIntAt(ci); short nameIndex = (short) extractLowShortFromInt(value); short signatureIndex = (short) extractHighShortFromInt(value); dos.writeShort(nameIndex); dos.writeShort(signatureIndex); if (DEBUG) debugMessage( "CP[" + ci + "] = N&T name = " + nameIndex + ", type = " + signatureIndex); break; } } // switch } dos.flush(); return; }