diff --git a/group24/448641125/src/com/donaldy/jvm/attr/CodeAttr.java b/group24/448641125/src/com/donaldy/jvm/attr/CodeAttr.java index 9122f3690a..854a0e2e75 100644 --- a/group24/448641125/src/com/donaldy/jvm/attr/CodeAttr.java +++ b/group24/448641125/src/com/donaldy/jvm/attr/CodeAttr.java @@ -104,7 +104,7 @@ public String toString(ConstantPool pool) { StringBuilder buffer = new StringBuilder(); //buffer.append("Code:").append(code).append("\n"); for(int i=0;i codeMap = new HashMap(); public static final String aconst_null = "01"; public static final String new_object = "BB"; @@ -52,11 +50,11 @@ public abstract class ByteCodeCommand { public static final String istore_2 = "3D"; public static final String iadd = "60"; public static final String iinc = "84"; - + private static Map codeMap = new HashMap(); static{ codeMap.put("01", "aconst_null"); - + codeMap.put("BB", "new"); codeMap.put("37", "lstore"); codeMap.put("B7", "invokespecial"); @@ -64,61 +62,61 @@ public abstract class ByteCodeCommand { codeMap.put("B4", "getfield"); codeMap.put("B5", "putfield"); codeMap.put("B2", "getstatic"); - + codeMap.put("2A", "aload_0"); codeMap.put("2B", "aload_1"); codeMap.put("2C", "aload_2"); - + codeMap.put("10", "bipush"); codeMap.put("15", "iload"); codeMap.put("1A", "iload_0"); codeMap.put("1B", "iload_1"); codeMap.put("1C", "iload_2"); codeMap.put("1D", "iload_3"); - + codeMap.put("25", "fload_3"); - + codeMap.put("1E", "lload_0"); - + codeMap.put("24", "fload_2"); codeMap.put("4C", "astore_1"); - + codeMap.put("A2", "if_icmp_ge"); codeMap.put("A4", "if_icmple"); - + codeMap.put("A7", "goto"); - + codeMap.put("B1", "return"); codeMap.put("AC", "ireturn"); codeMap.put("AE", "freturn"); - + codeMap.put("03", "iconst_0"); codeMap.put("04", "iconst_1"); - + codeMap.put("3C", "istore_1"); codeMap.put("3D", "istore_2"); - + codeMap.put("59", "dup"); - + codeMap.put("60", "iadd"); codeMap.put("84", "iinc"); - + codeMap.put("12", "ldc"); } - - - + + + protected ByteCodeCommand(ClassFile clzFile, String opCode){ this.clzFile = clzFile; this.opCode = opCode; } - + protected ClassFile getClassFile() { return clzFile; } - + public int getOffset() { return offset; } @@ -129,31 +127,19 @@ public void setOffset(int offset) { protected ConstantInfo getConstantInfo(int index){ return this.getClassFile().getConstantPool().getConstantInfo(index); } - + protected ConstantPool getConstantPool(){ return this.getClassFile().getConstantPool(); } - - - + + + public String getOpCode() { return opCode; } public abstract int getLength(); - - - - - public String toString(){ - - StringBuffer buffer = new StringBuffer(); - buffer.append(this.opCode); - - return buffer.toString(); - } - public abstract String toString(ConstantPool pool); - + public String getReadableCodeText(){ String txt = codeMap.get(opCode); if(txt == null){ @@ -163,4 +149,4 @@ public String getReadableCodeText(){ } public abstract void execute(StackFrame frame,ExecutionResult result); -} +} \ No newline at end of file diff --git a/group24/448641125/src/com/donaldy/jvm/cmd/CommandParser.java b/group24/448641125/src/com/donaldy/jvm/cmd/CommandParser.java index b43e0d3a06..ce793bb637 100644 --- a/group24/448641125/src/com/donaldy/jvm/cmd/CommandParser.java +++ b/group24/448641125/src/com/donaldy/jvm/cmd/CommandParser.java @@ -71,7 +71,7 @@ public static ByteCodeCommand[] parse(ClassFile clzFile, String codes) { cmds.add(cmd); } else if (invokevirtual.equals(opCode)) { - InvokeSpecialCmd cmd = new InvokeSpecialCmd(clzFile, opCode); + InvokeVirtualCmd cmd = new InvokeVirtualCmd(clzFile, opCode); cmd.setOprand1(iter.next2CharAsInt()); cmd.setOprand2(iter.next2CharAsInt()); diff --git a/group24/448641125/src/com/donaldy/jvm/cmd/GetFieldCmd.java b/group24/448641125/src/com/donaldy/jvm/cmd/GetFieldCmd.java index 9942038c25..cdfba64252 100644 --- a/group24/448641125/src/com/donaldy/jvm/cmd/GetFieldCmd.java +++ b/group24/448641125/src/com/donaldy/jvm/cmd/GetFieldCmd.java @@ -15,21 +15,23 @@ public GetFieldCmd(ClassFile clzFile,String opCode) { } @Override - public String toString(ConstantPool pool) { + public String toString() { - return super.getOperandAsField(pool); + return super.getOperandAsField(); } @Override - public void execute(StackFrame frame, ExecutionResult result) { - + public void execute(StackFrame frame,ExecutionResult result) { + FieldRefInfo fieldRef = (FieldRefInfo)this.getConstantInfo(this.getIndex()); String fieldName = fieldRef.getFieldName(); JavaObject jo = frame.getOprandStack().pop(); JavaObject fieldValue = jo.getFieldValue(fieldName); - + frame.getOprandStack().push(fieldValue); - + + + } diff --git a/group24/448641125/src/com/donaldy/jvm/cmd/GetStaticFieldCmd.java b/group24/448641125/src/com/donaldy/jvm/cmd/GetStaticFieldCmd.java index 33acd83c2e..18ff35be32 100644 --- a/group24/448641125/src/com/donaldy/jvm/cmd/GetStaticFieldCmd.java +++ b/group24/448641125/src/com/donaldy/jvm/cmd/GetStaticFieldCmd.java @@ -19,26 +19,24 @@ public GetStaticFieldCmd(ClassFile clzFile,String opCode) { } @Override - public String toString(ConstantPool pool) { + public String toString() { - return super.getOperandAsField(pool); + return super.getOperandAsField(); } - - @Override - public void execute(StackFrame frame, ExecutionResult result) { - + + @Override + public void execute(StackFrame frame,ExecutionResult result) { FieldRefInfo info = (FieldRefInfo)this.getConstantInfo(this.getIndex()); String className = info.getClassName(); String fieldName = info.getFieldName(); String fieldType = info.getFieldType(); - - if("java/lang/System".equals(className) - && "out".equals(fieldName) - && "Ljava/io/PrintStream;".equals(fieldType)){ + + if("java/lang/System".equals(className) + && "out".equals(fieldName) + && "Ljava/io/PrintStream;".equals(fieldType)){ JavaObject jo = Heap.getInstance().newObject(className); frame.getOprandStack().push(jo); } //TODO 处理非System.out的情况 } - } diff --git a/group24/448641125/src/com/donaldy/jvm/cmd/InvokeSpecialCmd.java b/group24/448641125/src/com/donaldy/jvm/cmd/InvokeSpecialCmd.java index 8390037f87..517906329f 100644 --- a/group24/448641125/src/com/donaldy/jvm/cmd/InvokeSpecialCmd.java +++ b/group24/448641125/src/com/donaldy/jvm/cmd/InvokeSpecialCmd.java @@ -17,28 +17,30 @@ public InvokeSpecialCmd(ClassFile clzFile,String opCode) { } @Override - public String toString(ConstantPool pool) { + public String toString() { - return super.getOperandAsMethod(pool); + return super.getOperandAsMethod(); } - @Override - public void execute(StackFrame frame, ExecutionResult result) { + public void execute(StackFrame frame,ExecutionResult result) { MethodRefInfo methodRefInfo = (MethodRefInfo)this.getConstantInfo(this.getIndex()); - + // 我们不用实现jang.lang.Object 的init方法 - if(methodRefInfo.getClassName().equals("java/lang/Object") - && methodRefInfo.getMethodName().equals("")){ + if(methodRefInfo.getClassName().equals("java/lang/Object") + && methodRefInfo.getMethodName().equals("")){ return ; - + } Method nextMethod = MethodArea.getInstance().getMethod(methodRefInfo); - - + + result.setNextAction(ExecutionResult.PAUSE_AND_RUN_NEW_FRAME); result.setNextMethod(nextMethod); - + + + } + } diff --git a/group24/448641125/src/com/donaldy/jvm/cmd/InvokeVirtualCmd.java b/group24/448641125/src/com/donaldy/jvm/cmd/InvokeVirtualCmd.java index 8e85fd8427..f0b59093a6 100644 --- a/group24/448641125/src/com/donaldy/jvm/cmd/InvokeVirtualCmd.java +++ b/group24/448641125/src/com/donaldy/jvm/cmd/InvokeVirtualCmd.java @@ -1,7 +1,6 @@ package com.donaldy.jvm.cmd; import com.donaldy.jvm.clz.ClassFile; -import com.donaldy.jvm.constant.ConstantPool; import com.donaldy.jvm.constant.MethodRefInfo; import com.donaldy.jvm.engine.ExecutionResult; import com.donaldy.jvm.engine.JavaObject; @@ -10,6 +9,7 @@ import com.donaldy.jvm.method.Method; + public class InvokeVirtualCmd extends TwoOperandCmd { public InvokeVirtualCmd(ClassFile clzFile,String opCode) { @@ -17,69 +17,70 @@ public InvokeVirtualCmd(ClassFile clzFile,String opCode) { } @Override - public String toString(ConstantPool pool) { + public String toString() { - return super.getOperandAsMethod(pool); + return super.getOperandAsMethod(); } + private boolean isSystemOutPrintlnMethod(String className, String methodName){ + return "java/io/PrintStream".equals(className) + && "println".equals(methodName); + } @Override - public void execute(StackFrame frame, ExecutionResult result) { + public void execute(StackFrame frame,ExecutionResult result) { + //先得到对该方法的描述 MethodRefInfo methodRefInfo = (MethodRefInfo)this.getConstantInfo(this.getIndex()); - + String className = methodRefInfo.getClassName(); String methodName = methodRefInfo.getMethodName(); - // 我们没有实现System.out.println方法, 所以也不用建立新的栈帧, 直接调用Java的方法, 打印出来即可。 + // 我们没有实现System.out.println方法, 所以也不用建立新的栈帧, 直接调用Java的方法, 打印出来即可。 if(isSystemOutPrintlnMethod(className,methodName)){ JavaObject jo = (JavaObject)frame.getOprandStack().pop(); String value = jo.toString(); System.err.println("-------------------"+value+"----------------"); - + // 这里就是那个out对象, 因为是个假的,直接pop出来 frame.getOprandStack().pop(); - + return; } - + //注意:多态, 这才是真正的对象, 先从该对象的class 中去找对应的方法,找不到的话再去找父类的方法 JavaObject jo = frame.getOprandStack().peek(); - + MethodArea ma = MethodArea.getInstance(); - + Method m = null; - + String currentClassName = jo.getClassName(); - + while(currentClassName != null){ - + ClassFile currentClassFile = ma.findClassFile(currentClassName); - - m = currentClassFile.getMethod(methodRefInfo.getMethodName(), - methodRefInfo.getParamAndReturnType()); + + m = currentClassFile.getMethod(methodRefInfo.getMethodName(), + methodRefInfo.getParamAndReturnType()); if(m != null){ - + break; - + } else{ //查找父类 currentClassName = currentClassFile.getSuperClassName(); } - } - + } + if(m == null){ throw new RuntimeException("Can't find method for :" + methodRefInfo.toString()); } - - + + result.setNextAction(ExecutionResult.PAUSE_AND_RUN_NEW_FRAME); - + result.setNextMethod(m); } - - private boolean isSystemOutPrintlnMethod(String className, String methodName){ - return "java/io/PrintStream".equals(className) - && "println".equals(methodName); - } + } diff --git a/group24/448641125/src/com/donaldy/jvm/cmd/LdcCmd.java b/group24/448641125/src/com/donaldy/jvm/cmd/LdcCmd.java index b6860b71c3..cf2d49ab1f 100644 --- a/group24/448641125/src/com/donaldy/jvm/cmd/LdcCmd.java +++ b/group24/448641125/src/com/donaldy/jvm/cmd/LdcCmd.java @@ -16,9 +16,9 @@ public LdcCmd(ClassFile clzFile,String opCode) { } @Override - public String toString(ConstantPool pool) { + public String toString() { - ConstantInfo info = (ConstantInfo)pool.getConstantInfo(this.getOperand()); + ConstantInfo info = getConstantInfo(this.getOperand()); String value = "TBD"; if(info instanceof StringInfo){ @@ -29,13 +29,11 @@ public String toString(ConstantPool pool) { return this.getOffset()+":"+this.getOpCode()+" " + this.getReadableCodeText() + " "+ value; } - - @Override - public void execute(StackFrame frame, ExecutionResult result) { - + public void execute(StackFrame frame,ExecutionResult result){ + ConstantPool pool = this.getConstantPool(); ConstantInfo info = (ConstantInfo)pool.getConstantInfo(this.getOperand()); - + if(info instanceof StringInfo){ StringInfo strInfo = (StringInfo)info; String value = strInfo.toString(); @@ -46,7 +44,7 @@ public void execute(StackFrame frame, ExecutionResult result) { //TBD 处理其他类型 throw new RuntimeException("Only support StringInfo constant"); } - + + } - } diff --git a/group24/448641125/src/com/donaldy/jvm/cmd/NewObjectCmd.java b/group24/448641125/src/com/donaldy/jvm/cmd/NewObjectCmd.java index 0da6ab9d83..237c5928dc 100644 --- a/group24/448641125/src/com/donaldy/jvm/cmd/NewObjectCmd.java +++ b/group24/448641125/src/com/donaldy/jvm/cmd/NewObjectCmd.java @@ -1,7 +1,6 @@ package com.donaldy.jvm.cmd; import com.donaldy.jvm.clz.ClassFile; -import com.donaldy.jvm.clz.ClassIndex; import com.donaldy.jvm.constant.ClassInfo; import com.donaldy.jvm.constant.ConstantPool; import com.donaldy.jvm.engine.ExecutionResult; @@ -16,24 +15,26 @@ public NewObjectCmd(ClassFile clzFile, String opCode){ } @Override - public String toString(ConstantPool pool) { + public String toString() { - return super.getOperandAsClassInfo(pool); + return super.getOperandAsClassInfo(); } - @Override - public void execute(StackFrame frame, ExecutionResult result) { - + public void execute(StackFrame frame,ExecutionResult result){ + int index = this.getIndex(); - - ClassInfo info = (ClassInfo) this.getConstantInfo(index); - + + ClassInfo info = (ClassInfo)this.getConstantInfo(index); + String clzName = info.getClassName(); - + //在Java堆上创建一个实例 JavaObject jo = Heap.getInstance().newObject(clzName); - + frame.getOprandStack().push(jo); + + + } } diff --git a/group24/448641125/src/com/donaldy/jvm/cmd/NoOperandCmd.java b/group24/448641125/src/com/donaldy/jvm/cmd/NoOperandCmd.java index f4a3f4f0cc..32ea5853ee 100644 --- a/group24/448641125/src/com/donaldy/jvm/cmd/NoOperandCmd.java +++ b/group24/448641125/src/com/donaldy/jvm/cmd/NoOperandCmd.java @@ -14,127 +14,133 @@ public NoOperandCmd(ClassFile clzFile, String opCode) { } @Override - public String toString(ConstantPool pool) { + public String toString() { return this.getOffset()+":" +this.getOpCode() + " "+ this.getReadableCodeText(); } - - - public int getLength(){ - return 1; - } - @Override - public void execute(StackFrame frame, ExecutionResult result) { - + public void execute(StackFrame frame,ExecutionResult result) { + String opCode = this.getOpCode(); - - if (ByteCodeCommand.aload_0.equals(opCode)) { - + + if(ByteCodeCommand.aload_0.equals(opCode)){ + JavaObject jo = frame.getLocalVariableValue(0); - + frame.getOprandStack().push(jo); - - } else if (ByteCodeCommand.aload_1.equals(opCode)) { - + + } else if(ByteCodeCommand.aload_1.equals(opCode)){ + JavaObject jo = frame.getLocalVariableValue(1); - + frame.getOprandStack().push(jo); - - } else if (ByteCodeCommand.aload_2.equals(opCode)) { - + + } else if(ByteCodeCommand.aload_2.equals(opCode)){ + JavaObject jo = frame.getLocalVariableValue(2); - + frame.getOprandStack().push(jo); - - } else if (ByteCodeCommand.iload_1.equals(opCode)) { - + + }else if(ByteCodeCommand.iload_1.equals(opCode)){ + JavaObject jo = frame.getLocalVariableValue(1); - + frame.getOprandStack().push(jo); - - } else if (ByteCodeCommand.iload_2.equals(opCode)) { - + + } else if (ByteCodeCommand.iload_2.equals(opCode)){ + JavaObject jo = frame.getLocalVariableValue(2); - + frame.getOprandStack().push(jo); - - } else if (ByteCodeCommand.iload_3.equals(opCode)) { - + + } else if (ByteCodeCommand.iload_3.equals(opCode)){ + JavaObject jo = frame.getLocalVariableValue(3); - + frame.getOprandStack().push(jo); - - } else if (ByteCodeCommand.fload_3.equals(opCode)) { - + + }else if (ByteCodeCommand.fload_3.equals(opCode)){ + JavaObject jo = frame.getLocalVariableValue(3); - + frame.getOprandStack().push(jo); - - } else if (ByteCodeCommand.voidreturn.equals(opCode)) { - + + } + else if (ByteCodeCommand.voidreturn.equals(opCode)){ + result.setNextAction(ExecutionResult.EXIT_CURRENT_FRAME); - - } else if (ByteCodeCommand.freturn.equals(opCode)) { - + + } else if(ByteCodeCommand.ireturn.equals(opCode)){ StackFrame callerFrame = frame.getCallerFrame(); JavaObject jo = frame.getOprandStack().pop(); callerFrame.getOprandStack().push(jo); - - } else if(ByteCodeCommand.astore_1.equals(opCode)){ - + + } else if(ByteCodeCommand.freturn.equals(opCode)){ + + StackFrame callerFrame = frame.getCallerFrame(); JavaObject jo = frame.getOprandStack().pop(); - - frame.setLocalVariableValue(1, jo); - + callerFrame.getOprandStack().push(jo); + } + + else if(ByteCodeCommand.astore_1.equals(opCode)){ + + JavaObject jo = frame.getOprandStack().pop(); + + frame.setLocalVariableValue(1, jo); + } else if(ByteCodeCommand.dup.equals(opCode)){ - + JavaObject jo = frame.getOprandStack().peek(); frame.getOprandStack().push(jo); - + } else if(ByteCodeCommand.iconst_0.equals(opCode)){ - + JavaObject jo = Heap.getInstance().newInt(0); - + frame.getOprandStack().push(jo); - + } else if(ByteCodeCommand.iconst_1.equals(opCode)){ - + JavaObject jo = Heap.getInstance().newInt(1); - + frame.getOprandStack().push(jo); - + } else if(ByteCodeCommand.istore_1.equals(opCode)){ - + JavaObject jo = frame.getOprandStack().pop(); - + frame.setLocalVariableValue(1, jo); - + } else if(ByteCodeCommand.istore_2.equals(opCode)){ - + JavaObject jo = frame.getOprandStack().pop(); - + frame.setLocalVariableValue(2, jo); - + } else if(ByteCodeCommand.iadd.equals(opCode)){ - + JavaObject jo1 = frame.getOprandStack().pop(); JavaObject jo2 = frame.getOprandStack().pop(); - + JavaObject sum = Heap.getInstance().newInt(jo1.getIntValue()+jo2.getIntValue()); - + frame.getOprandStack().push(sum); - + } else if (ByteCodeCommand.aconst_null.equals(opCode)){ - + frame.getOprandStack().push(null); - - } + + } else{ throw new RuntimeException("you must forget to implement the operation :" + opCode); } - + + + } + + + public int getLength(){ + return 1; } - } diff --git a/group24/448641125/src/com/donaldy/jvm/cmd/PutFieldCmd.java b/group24/448641125/src/com/donaldy/jvm/cmd/PutFieldCmd.java index 4a9f8aa8d3..cb9e60e27b 100644 --- a/group24/448641125/src/com/donaldy/jvm/cmd/PutFieldCmd.java +++ b/group24/448641125/src/com/donaldy/jvm/cmd/PutFieldCmd.java @@ -16,29 +16,29 @@ public PutFieldCmd(ClassFile clzFile,String opCode) { } @Override - public String toString(ConstantPool pool) { + public String toString() { - return super.getOperandAsField(pool); + return super.getOperandAsField(); } - - @Override - public void execute(StackFrame frame, ExecutionResult result) { - + public void execute(StackFrame frame,ExecutionResult result) { + FieldRefInfo fieldRef = (FieldRefInfo)this.getConstantInfo(this.getIndex()); - + ClassInfo clzInfo = (ClassInfo)this.getConstantInfo(fieldRef.getClassInfoIndex()); NameAndTypeInfo nameTypeInfo = (NameAndTypeInfo)this.getConstantInfo(fieldRef.getNameAndTypeIndex()); // for example : name String fieldName = nameTypeInfo.getName(); // for example : Ljava/lang/String : 注意:我们不再检查类型 String fieldType = nameTypeInfo.getTypeInfo(); - + JavaObject fieldValue = frame.getOprandStack().pop(); JavaObject objectRef = frame.getOprandStack().pop(); - + objectRef.setFieldValue(fieldName, fieldValue); - + } + + } diff --git a/group24/448641125/src/com/donaldy/jvm/cmd/TwoOperandCmd.java b/group24/448641125/src/com/donaldy/jvm/cmd/TwoOperandCmd.java index 1d38c8ed3f..3c62fd93e0 100644 --- a/group24/448641125/src/com/donaldy/jvm/cmd/TwoOperandCmd.java +++ b/group24/448641125/src/com/donaldy/jvm/cmd/TwoOperandCmd.java @@ -39,14 +39,14 @@ public int getIndex(){ return index; } - protected String getOperandAsClassInfo(ConstantPool pool){ + protected String getOperandAsClassInfo(){ int index = getIndex(); String codeTxt = getReadableCodeText(); - ClassInfo info = (ClassInfo)pool.getConstantInfo(index); + ClassInfo info = (ClassInfo)getConstantInfo(index); return this.getOffset()+":"+this.getOpCode()+" "+ codeTxt +" "+ info.getClassName(); } - protected String getOperandAsMethod(ConstantPool pool){ + protected String getOperandAsMethod(){ int index = getIndex(); String codeTxt = getReadableCodeText(); ConstantInfo constInfo = this.getConstantInfo(index); @@ -54,7 +54,7 @@ protected String getOperandAsMethod(ConstantPool pool){ return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); } - protected String getOperandAsField(ConstantPool pool){ + protected String getOperandAsField(){ int index = getIndex(); String codeTxt = getReadableCodeText(); diff --git a/group24/448641125/src/com/donaldy/jvm/engine/ExecutionResult.java b/group24/448641125/src/com/donaldy/jvm/engine/ExecutionResult.java index c90cc8fc65..ea6340e976 100644 --- a/group24/448641125/src/com/donaldy/jvm/engine/ExecutionResult.java +++ b/group24/448641125/src/com/donaldy/jvm/engine/ExecutionResult.java @@ -48,9 +48,6 @@ public int getNextCmdOffset() { public void setNextCmdOffset(int nextCmdOffset) { this.nextCmdOffset = nextCmdOffset; } - - - - + } diff --git a/group24/448641125/src/com/donaldy/jvm/engine/ExecutorEngine.java b/group24/448641125/src/com/donaldy/jvm/engine/ExecutorEngine.java index efa188d917..e18323a4d6 100644 --- a/group24/448641125/src/com/donaldy/jvm/engine/ExecutorEngine.java +++ b/group24/448641125/src/com/donaldy/jvm/engine/ExecutorEngine.java @@ -21,6 +21,7 @@ public ExecutorEngine() { public void execute(Method mainMethod){ StackFrame mainFrame = StackFrame.create(mainMethod); + stack.push(mainFrame); while (!stack.empty()) { @@ -33,8 +34,11 @@ public void execute(Method mainMethod){ if (result.isPauseAndRunNewFrame()) { Method nextMethod = result.getNextMethod(); + StackFrame nextFrame = StackFrame.create(nextMethod); + nextFrame.setCallerFrame(frame); + setupFunctionCallParams(frame, nextFrame); stack.push(nextFrame); @@ -48,34 +52,38 @@ public void execute(Method mainMethod){ } - - - + + + private void setupFunctionCallParams(StackFrame currentFrame,StackFrame nextFrame) { - + Method nextMethod = nextFrame.getMethod(); + List paramList = nextMethod.getParameterList(); //加上1 是因为要把this也传递过去 + int paramNum = paramList.size() + 1; - List values = new ArrayList<>(); - //从栈中取出栈顶的x个元素 - while (paramNum > 0) { + List values = new ArrayList(); + + //数据结构知识: 从栈中取出栈顶的x个元素 + while(paramNum>0){ values.add(currentFrame.getOprandStack().pop()); paramNum --; } - - //把一个列表倒序排列 + //数据结构知识: 把一个列表倒序排列 List params = new ArrayList(); - for (int i = values.size() - 1; i >= 0; i --) { + for(int i=values.size()-1; i>=0 ;i--){ params.add(values.get(i)); } + nextFrame.setLocalVariableTable(params); + } } diff --git a/group24/448641125/src/com/donaldy/jvm/engine/StackFrame.java b/group24/448641125/src/com/donaldy/jvm/engine/StackFrame.java index ca82395f14..56c4f9c3f7 100644 --- a/group24/448641125/src/com/donaldy/jvm/engine/StackFrame.java +++ b/group24/448641125/src/com/donaldy/jvm/engine/StackFrame.java @@ -5,6 +5,7 @@ import java.util.Stack; import com.donaldy.jvm.cmd.ByteCodeCommand; +import com.donaldy.jvm.cmd.InvokeVirtualCmd; import com.donaldy.jvm.method.Method; public class StackFrame { @@ -76,6 +77,8 @@ public ExecutionResult execute(){ System.out.println(cmds[this.index].toString()); + cmds[this.index].execute(this, result); + if (result.isRunNextCmd()) { this.index ++; } @@ -84,6 +87,7 @@ else if (result.isExitCurrentFrame()) { } else if (result.isPauseAndRunNewFrame()) { this.index ++; + return result; } else if (result.isJump()) { @@ -96,7 +100,9 @@ else if (result.isJump()) { //当前StackFrmae的指令全部执行完毕,可以退出了 ExecutionResult result = new ExecutionResult(); + result.setNextAction(ExecutionResult.EXIT_CURRENT_FRAME); + return result; } diff --git a/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java b/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java index b0229c7435..ea14b12360 100644 --- a/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java +++ b/group24/448641125/src/com/donaldy/jvm/loader/ClassFileParser.java @@ -125,10 +125,11 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { nameType.setIndex2(iter.nextU2ToInt()); pool.addConstantInfo(nameType); } else { - throw new RuntimeException("the constant pool tag" + tag); + throw new RuntimeException("the constant pool tag " + tag + " has not been implemented yet."); } } + System.out.println("Finished reading Constant pool "); return pool; } diff --git a/group24/448641125/src/com/donaldy/jvm/test/MinJVMTest.java b/group24/448641125/src/com/donaldy/jvm/test/MinJVMTest.java index 6ff89089b3..7936da4dfc 100644 --- a/group24/448641125/src/com/donaldy/jvm/test/MinJVMTest.java +++ b/group24/448641125/src/com/donaldy/jvm/test/MinJVMTest.java @@ -26,6 +26,6 @@ public void testMain() throws Exception { */ String [] classPaths = {PATH}; MiniJVM jvm = new MiniJVM(); - jvm.run(classPaths, "com.donaldy.jvm.test.EmployeeV1"); + jvm.run(classPaths, "com.coderising.jvm.test.EmployeeV1"); } } diff --git a/group24/448641125/src/java/io/PrintStream.java b/group24/448641125/src/java/io/PrintStream.java new file mode 100644 index 0000000000..659e3c4ea2 --- /dev/null +++ b/group24/448641125/src/java/io/PrintStream.java @@ -0,0 +1,1138 @@ +package java.io; + +/** + * Created by DonaldY on 2017/4/29. + */ +/* + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; +import java.util.Formatter; +import java.util.Locale; + +import java.util.Formatter; +import java.util.Locale; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; + +/** + * A PrintStream adds functionality to another output stream, + * namely the ability to print representations of various data values + * conveniently. Two other features are provided as well. Unlike other output + * streams, a PrintStream never throws an + * IOException; instead, exceptional situations merely set an + * internal flag that can be tested via the checkError method. + * Optionally, a PrintStream can be created so as to flush + * automatically; this means that the flush method is + * automatically invoked after a byte array is written, one of the + * println methods is invoked, or a newline character or byte + * ('\n') is written. + * + *

All characters printed by a PrintStream are converted into + * bytes using the platform's default character encoding. The {@link + * PrintWriter} class should be used in situations that require writing + * characters rather than bytes. + * + * @author Frank Yellin + * @author Mark Reinhold + * @since JDK1.0 + */ + +public class PrintStream extends FilterOutputStream + implements Appendable, Closeable +{ + + private final boolean autoFlush; + private boolean trouble = false; + private Formatter formatter; + + /** + * Track both the text- and character-output streams, so that their buffers + * can be flushed without flushing the entire stream. + */ + private BufferedWriter textOut; + private OutputStreamWriter charOut; + + /** + * requireNonNull is explicitly declared here so as not to create an extra + * dependency on java.util.Objects.requireNonNull. PrintStream is loaded + * early during system initialization. + */ + private static T requireNonNull(T obj, String message) { + if (obj == null) + throw new NullPointerException(message); + return obj; + } + + /** + * Returns a charset object for the given charset name. + * @throws NullPointerException is csn is null + * @throws UnsupportedEncodingException if the charset is not supported + */ + private static Charset toCharset(String csn) + throws UnsupportedEncodingException + { + requireNonNull(csn, "charsetName"); + try { + return Charset.forName(csn); + } catch (IllegalCharsetNameException |UnsupportedCharsetException unused) { + // UnsupportedEncodingException should be thrown + throw new UnsupportedEncodingException(csn); + } + } + + /* Private constructors */ + private PrintStream(boolean autoFlush, OutputStream out) { + super(out); + this.autoFlush = autoFlush; + this.charOut = new OutputStreamWriter(this); + this.textOut = new BufferedWriter(charOut); + } + + private PrintStream(boolean autoFlush, OutputStream out, Charset charset) { + super(out); + this.autoFlush = autoFlush; + this.charOut = new OutputStreamWriter(this, charset); + this.textOut = new BufferedWriter(charOut); + } + + /* Variant of the private constructor so that the given charset name + * can be verified before evaluating the OutputStream argument. Used + * by constructors creating a FileOutputStream that also take a + * charset name. + */ + private PrintStream(boolean autoFlush, Charset charset, OutputStream out) + throws UnsupportedEncodingException + { + this(autoFlush, out, charset); + } + + /** + * Creates a new print stream. This stream will not flush automatically. + * + * @param out The output stream to which values and objects will be + * printed + * + * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream) + */ + public PrintStream(OutputStream out) { + this(out, false); + } + + /** + * Creates a new print stream. + * + * @param out The output stream to which values and objects will be + * printed + * @param autoFlush A boolean; if true, the output buffer will be flushed + * whenever a byte array is written, one of the + * println methods is invoked, or a newline + * character or byte ('\n') is written + * + * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream, boolean) + */ + public PrintStream(OutputStream out, boolean autoFlush) { + this(autoFlush, requireNonNull(out, "Null output stream")); + } + + /** + * Creates a new print stream. + * + * @param out The output stream to which values and objects will be + * printed + * @param autoFlush A boolean; if true, the output buffer will be flushed + * whenever a byte array is written, one of the + * println methods is invoked, or a newline + * character or byte ('\n') is written + * @param encoding The name of a supported + * + * character encoding + * + * @throws UnsupportedEncodingException + * If the named encoding is not supported + * + * @since 1.4 + */ + public PrintStream(OutputStream out, boolean autoFlush, String encoding) + throws UnsupportedEncodingException + { + this(autoFlush, + requireNonNull(out, "Null output stream"), + toCharset(encoding)); + } + + /** + * Creates a new print stream, without automatic line flushing, with the + * specified file name. This convenience constructor creates + * the necessary intermediate {@link java.io.OutputStreamWriter + * OutputStreamWriter}, which will encode characters using the + * {@linkplain java.nio.charset.Charset#defaultCharset() default charset} + * for this instance of the Java virtual machine. + * + * @param fileName + * The name of the file to use as the destination of this print + * stream. If the file exists, then it will be truncated to + * zero size; otherwise, a new file will be created. The output + * will be written to the file and is buffered. + * + * @throws FileNotFoundException + * If the given file object does not denote an existing, writable + * regular file and a new regular file of that name cannot be + * created, or if some other error occurs while opening or + * creating the file + * + * @throws SecurityException + * If a security manager is present and {@link + * SecurityManager#checkWrite checkWrite(fileName)} denies write + * access to the file + * + * @since 1.5 + */ + public PrintStream(String fileName) throws FileNotFoundException { + this(false, new FileOutputStream(fileName)); + } + + /** + * Creates a new print stream, without automatic line flushing, with the + * specified file name and charset. This convenience constructor creates + * the necessary intermediate {@link java.io.OutputStreamWriter + * OutputStreamWriter}, which will encode characters using the provided + * charset. + * + * @param fileName + * The name of the file to use as the destination of this print + * stream. If the file exists, then it will be truncated to + * zero size; otherwise, a new file will be created. The output + * will be written to the file and is buffered. + * + * @param csn + * The name of a supported {@linkplain java.nio.charset.Charset + * charset} + * + * @throws FileNotFoundException + * If the given file object does not denote an existing, writable + * regular file and a new regular file of that name cannot be + * created, or if some other error occurs while opening or + * creating the file + * + * @throws SecurityException + * If a security manager is present and {@link + * SecurityManager#checkWrite checkWrite(fileName)} denies write + * access to the file + * + * @throws UnsupportedEncodingException + * If the named charset is not supported + * + * @since 1.5 + */ + public PrintStream(String fileName, String csn) + throws FileNotFoundException, UnsupportedEncodingException + { + // ensure charset is checked before the file is opened + this(false, toCharset(csn), new FileOutputStream(fileName)); + } + + /** + * Creates a new print stream, without automatic line flushing, with the + * specified file. This convenience constructor creates the necessary + * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter}, + * which will encode characters using the {@linkplain + * java.nio.charset.Charset#defaultCharset() default charset} for this + * instance of the Java virtual machine. + * + * @param file + * The file to use as the destination of this print stream. If the + * file exists, then it will be truncated to zero size; otherwise, + * a new file will be created. The output will be written to the + * file and is buffered. + * + * @throws FileNotFoundException + * If the given file object does not denote an existing, writable + * regular file and a new regular file of that name cannot be + * created, or if some other error occurs while opening or + * creating the file + * + * @throws SecurityException + * If a security manager is present and {@link + * SecurityManager#checkWrite checkWrite(file.getPath())} + * denies write access to the file + * + * @since 1.5 + */ + public PrintStream(File file) throws FileNotFoundException { + this(false, new FileOutputStream(file)); + } + + /** + * Creates a new print stream, without automatic line flushing, with the + * specified file and charset. This convenience constructor creates + * the necessary intermediate {@link java.io.OutputStreamWriter + * OutputStreamWriter}, which will encode characters using the provided + * charset. + * + * @param file + * The file to use as the destination of this print stream. If the + * file exists, then it will be truncated to zero size; otherwise, + * a new file will be created. The output will be written to the + * file and is buffered. + * + * @param csn + * The name of a supported {@linkplain java.nio.charset.Charset + * charset} + * + * @throws FileNotFoundException + * If the given file object does not denote an existing, writable + * regular file and a new regular file of that name cannot be + * created, or if some other error occurs while opening or + * creating the file + * + * @throws SecurityException + * If a security manager is present and {@link + * SecurityManager#checkWrite checkWrite(file.getPath())} + * denies write access to the file + * + * @throws UnsupportedEncodingException + * If the named charset is not supported + * + * @since 1.5 + */ + public PrintStream(File file, String csn) + throws FileNotFoundException, UnsupportedEncodingException + { + // ensure charset is checked before the file is opened + this(false, toCharset(csn), new FileOutputStream(file)); + } + + /** Check to make sure that the stream has not been closed */ + private void ensureOpen() throws IOException { + if (out == null) + throw new IOException("Stream closed"); + } + + /** + * Flushes the stream. This is done by writing any buffered output bytes to + * the underlying output stream and then flushing that stream. + * + * @see java.io.OutputStream#flush() + */ + public void flush() { + synchronized (this) { + try { + ensureOpen(); + out.flush(); + } + catch (IOException x) { + trouble = true; + } + } + } + + private boolean closing = false; /* To avoid recursive closing */ + + /** + * Closes the stream. This is done by flushing the stream and then closing + * the underlying output stream. + * + * @see java.io.OutputStream#close() + */ + public void close() { + synchronized (this) { + if (! closing) { + closing = true; + try { + textOut.close(); + out.close(); + } + catch (IOException x) { + trouble = true; + } + textOut = null; + charOut = null; + out = null; + } + } + } + + /** + * Flushes the stream and checks its error state. The internal error state + * is set to true when the underlying output stream throws an + * IOException other than InterruptedIOException, + * and when the setError method is invoked. If an operation + * on the underlying output stream throws an + * InterruptedIOException, then the PrintStream + * converts the exception back into an interrupt by doing: + *

+     *     Thread.currentThread().interrupt();
+     * 
+ * or the equivalent. + * + * @return true if and only if this stream has encountered an + * IOException other than + * InterruptedIOException, or the + * setError method has been invoked + */ + public boolean checkError() { + if (out != null) + flush(); + if (out instanceof java.io.PrintStream) { + PrintStream ps = (PrintStream) out; + return ps.checkError(); + } + return trouble; + } + + /** + * Sets the error state of the stream to true. + * + *

This method will cause subsequent invocations of {@link + * #checkError()} to return true until {@link + * #clearError()} is invoked. + * + * @since JDK1.1 + */ + protected void setError() { + trouble = true; + } + + /** + * Clears the internal error state of this stream. + * + *

This method will cause subsequent invocations of {@link + * #checkError()} to return false until another write + * operation fails and invokes {@link #setError()}. + * + * @since 1.6 + */ + protected void clearError() { + trouble = false; + } + + /* + * Exception-catching, synchronized output operations, + * which also implement the write() methods of OutputStream + */ + + /** + * Writes the specified byte to this stream. If the byte is a newline and + * automatic flushing is enabled then the flush method will be + * invoked. + * + *

Note that the byte is written as given; to write a character that + * will be translated according to the platform's default character + * encoding, use the print(char) or println(char) + * methods. + * + * @param b The byte to be written + * @see #print(char) + * @see #println(char) + */ + public void write(int b) { + try { + synchronized (this) { + ensureOpen(); + out.write(b); + if ((b == '\n') && autoFlush) + out.flush(); + } + } + catch (InterruptedIOException x) { + Thread.currentThread().interrupt(); + } + catch (IOException x) { + trouble = true; + } + } + + /** + * Writes len bytes from the specified byte array starting at + * offset off to this stream. If automatic flushing is + * enabled then the flush method will be invoked. + * + *

Note that the bytes will be written as given; to write characters + * that will be translated according to the platform's default character + * encoding, use the print(char) or println(char) + * methods. + * + * @param buf A byte array + * @param off Offset from which to start taking bytes + * @param len Number of bytes to write + */ + public void write(byte buf[], int off, int len) { + try { + synchronized (this) { + ensureOpen(); + out.write(buf, off, len); + if (autoFlush) + out.flush(); + } + } + catch (InterruptedIOException x) { + Thread.currentThread().interrupt(); + } + catch (IOException x) { + trouble = true; + } + } + + /* + * The following private methods on the text- and character-output streams + * always flush the stream buffers, so that writes to the underlying byte + * stream occur as promptly as with the original PrintStream. + */ + + private void write(char buf[]) { + try { + synchronized (this) { + ensureOpen(); + textOut.write(buf); + textOut.flushBuffer(); + charOut.flushBuffer(); + if (autoFlush) { + for (int i = 0; i < buf.length; i++) + if (buf[i] == '\n') + out.flush(); + } + } + } + catch (InterruptedIOException x) { + Thread.currentThread().interrupt(); + } + catch (IOException x) { + trouble = true; + } + } + + private void write(String s) { + try { + synchronized (this) { + ensureOpen(); + textOut.write(s); + textOut.flushBuffer(); + charOut.flushBuffer(); + if (autoFlush && (s.indexOf('\n') >= 0)) + out.flush(); + } + } + catch (InterruptedIOException x) { + Thread.currentThread().interrupt(); + } + catch (IOException x) { + trouble = true; + } + } + + private void newLine() { + try { + synchronized (this) { + ensureOpen(); + textOut.newLine(); + textOut.flushBuffer(); + charOut.flushBuffer(); + if (autoFlush) + out.flush(); + } + } + catch (InterruptedIOException x) { + Thread.currentThread().interrupt(); + } + catch (IOException x) { + trouble = true; + } + } + + /* Methods that do not terminate lines */ + + /** + * Prints a boolean value. The string produced by {@link + * java.lang.String#valueOf(boolean)} is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param b The boolean to be printed + */ + public void print(boolean b) { + write(b ? "true" : "false"); + } + + /** + * Prints a character. The character is translated into one or more bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param c The char to be printed + */ + public void print(char c) { + write(String.valueOf(c)); + } + + /** + * Prints an integer. The string produced by {@link + * java.lang.String#valueOf(int)} is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param i The int to be printed + * @see java.lang.Integer#toString(int) + */ + public void print(int i) { + write(String.valueOf(i)); + } + + /** + * Prints a long integer. The string produced by {@link + * java.lang.String#valueOf(long)} is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param l The long to be printed + * @see java.lang.Long#toString(long) + */ + public void print(long l) { + write(String.valueOf(l)); + } + + /** + * Prints a floating-point number. The string produced by {@link + * java.lang.String#valueOf(float)} is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param f The float to be printed + * @see java.lang.Float#toString(float) + */ + public void print(float f) { + write(String.valueOf(f)); + } + + /** + * Prints a double-precision floating-point number. The string produced by + * {@link java.lang.String#valueOf(double)} is translated into + * bytes according to the platform's default character encoding, and these + * bytes are written in exactly the manner of the {@link + * #write(int)} method. + * + * @param d The double to be printed + * @see java.lang.Double#toString(double) + */ + public void print(double d) { + write(String.valueOf(d)); + } + + /** + * Prints an array of characters. The characters are converted into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param s The array of chars to be printed + * + * @throws NullPointerException If s is null + */ + public void print(char s[]) { + write(s); + } + + /** + * Prints a string. If the argument is null then the string + * "null" is printed. Otherwise, the string's characters are + * converted into bytes according to the platform's default character + * encoding, and these bytes are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param s The String to be printed + */ + public void print(String s) { + if (s == null) { + s = "null"; + } + write(s); + } + + /** + * Prints an object. The string produced by the {@link + * java.lang.String#valueOf(Object)} method is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param obj The Object to be printed + * @see java.lang.Object#toString() + */ + public void print(Object obj) { + write(String.valueOf(obj)); + } + + + /* Methods that do terminate lines */ + + /** + * Terminates the current line by writing the line separator string. The + * line separator string is defined by the system property + * line.separator, and is not necessarily a single newline + * character ('\n'). + */ + public void println() { + newLine(); + } + + /** + * Prints a boolean and then terminate the line. This method behaves as + * though it invokes {@link #print(boolean)} and then + * {@link #println()}. + * + * @param x The boolean to be printed + */ + public void println(boolean x) { + synchronized (this) { + print(x); + newLine(); + } + } + + /** + * Prints a character and then terminate the line. This method behaves as + * though it invokes {@link #print(char)} and then + * {@link #println()}. + * + * @param x The char to be printed. + */ + public void println(char x) { + synchronized (this) { + print(x); + newLine(); + } + } + + /** + * Prints an integer and then terminate the line. This method behaves as + * though it invokes {@link #print(int)} and then + * {@link #println()}. + * + * @param x The int to be printed. + */ + public void println(int x) { + synchronized (this) { + print(x); + newLine(); + } + } + + /** + * Prints a long and then terminate the line. This method behaves as + * though it invokes {@link #print(long)} and then + * {@link #println()}. + * + * @param x a The long to be printed. + */ + public void println(long x) { + synchronized (this) { + print(x); + newLine(); + } + } + + /** + * Prints a float and then terminate the line. This method behaves as + * though it invokes {@link #print(float)} and then + * {@link #println()}. + * + * @param x The float to be printed. + */ + public void println(float x) { + synchronized (this) { + print(x); + newLine(); + } + } + + /** + * Prints a double and then terminate the line. This method behaves as + * though it invokes {@link #print(double)} and then + * {@link #println()}. + * + * @param x The double to be printed. + */ + public void println(double x) { + synchronized (this) { + print(x); + newLine(); + } + } + + /** + * Prints an array of characters and then terminate the line. This method + * behaves as though it invokes {@link #print(char[])} and + * then {@link #println()}. + * + * @param x an array of chars to print. + */ + public void println(char x[]) { + synchronized (this) { + print(x); + newLine(); + } + } + + /** + * Prints a String and then terminate the line. This method behaves as + * though it invokes {@link #print(String)} and then + * {@link #println()}. + * + * @param x The String to be printed. + */ + public void println(String x) { + synchronized (this) { + print(x); + newLine(); + } + } + + /** + * Prints an Object and then terminate the line. This method calls + * at first String.valueOf(x) to get the printed object's string value, + * then behaves as + * though it invokes {@link #print(String)} and then + * {@link #println()}. + * + * @param x The Object to be printed. + */ + public void println(Object x) { + String s = String.valueOf(x); + synchronized (this) { + print(s); + newLine(); + } + } + + + /** + * A convenience method to write a formatted string to this output stream + * using the specified format string and arguments. + * + *

An invocation of this method of the form out.printf(format, + * args) behaves in exactly the same way as the invocation + * + *

+     *     out.format(format, args) 
+ * + * @param format + * A format string as described in Format string syntax + * + * @param args + * Arguments referenced by the format specifiers in the format + * string. If there are more arguments than format specifiers, the + * extra arguments are ignored. The number of arguments is + * variable and may be zero. The maximum number of arguments is + * limited by the maximum dimension of a Java array as defined by + * The Java™ Virtual Machine Specification. + * The behaviour on a + * null argument depends on the conversion. + * + * @throws java.util.IllegalFormatException + * If a format string contains an illegal syntax, a format + * specifier that is incompatible with the given arguments, + * insufficient arguments given the format string, or other + * illegal conditions. For specification of all possible + * formatting errors, see the Details section of the + * formatter class specification. + * + * @throws NullPointerException + * If the format is null + * + * @return This output stream + * + * @since 1.5 + */ + public PrintStream printf(String format, Object ... args) { + return format(format, args); + } + + /** + * A convenience method to write a formatted string to this output stream + * using the specified format string and arguments. + * + *

An invocation of this method of the form out.printf(l, format, + * args) behaves in exactly the same way as the invocation + * + *

+     *     out.format(l, format, args) 
+ * + * @param l + * The {@linkplain java.util.Locale locale} to apply during + * formatting. If l is null then no localization + * is applied. + * + * @param format + * A format string as described in Format string syntax + * + * @param args + * Arguments referenced by the format specifiers in the format + * string. If there are more arguments than format specifiers, the + * extra arguments are ignored. The number of arguments is + * variable and may be zero. The maximum number of arguments is + * limited by the maximum dimension of a Java array as defined by + * The Java™ Virtual Machine Specification. + * The behaviour on a + * null argument depends on the conversion. + * + * @throws java.util.IllegalFormatException + * If a format string contains an illegal syntax, a format + * specifier that is incompatible with the given arguments, + * insufficient arguments given the format string, or other + * illegal conditions. For specification of all possible + * formatting errors, see the Details section of the + * formatter class specification. + * + * @throws NullPointerException + * If the format is null + * + * @return This output stream + * + * @since 1.5 + */ + public PrintStream printf(Locale l, String format, Object ... args) { + return format(l, format, args); + } + + /** + * Writes a formatted string to this output stream using the specified + * format string and arguments. + * + *

The locale always used is the one returned by {@link + * java.util.Locale#getDefault() Locale.getDefault()}, regardless of any + * previous invocations of other formatting methods on this object. + * + * @param format + * A format string as described in Format string syntax + * + * @param args + * Arguments referenced by the format specifiers in the format + * string. If there are more arguments than format specifiers, the + * extra arguments are ignored. The number of arguments is + * variable and may be zero. The maximum number of arguments is + * limited by the maximum dimension of a Java array as defined by + * The Java™ Virtual Machine Specification. + * The behaviour on a + * null argument depends on the conversion. + * + * @throws java.util.IllegalFormatException + * If a format string contains an illegal syntax, a format + * specifier that is incompatible with the given arguments, + * insufficient arguments given the format string, or other + * illegal conditions. For specification of all possible + * formatting errors, see the Details section of the + * formatter class specification. + * + * @throws NullPointerException + * If the format is null + * + * @return This output stream + * + * @since 1.5 + */ + public PrintStream format(String format, Object ... args) { + try { + synchronized (this) { + ensureOpen(); + if ((formatter == null) + || (formatter.locale() != Locale.getDefault())) + formatter = new Formatter((Appendable) this); + formatter.format(Locale.getDefault(), format, args); + } + } catch (InterruptedIOException x) { + Thread.currentThread().interrupt(); + } catch (IOException x) { + trouble = true; + } + return this; + } + + /** + * Writes a formatted string to this output stream using the specified + * format string and arguments. + * + * @param l + * The {@linkplain java.util.Locale locale} to apply during + * formatting. If l is null then no localization + * is applied. + * + * @param format + * A format string as described in Format string syntax + * + * @param args + * Arguments referenced by the format specifiers in the format + * string. If there are more arguments than format specifiers, the + * extra arguments are ignored. The number of arguments is + * variable and may be zero. The maximum number of arguments is + * limited by the maximum dimension of a Java array as defined by + * The Java™ Virtual Machine Specification. + * The behaviour on a + * null argument depends on the conversion. + * + * @throws java.util.IllegalFormatException + * If a format string contains an illegal syntax, a format + * specifier that is incompatible with the given arguments, + * insufficient arguments given the format string, or other + * illegal conditions. For specification of all possible + * formatting errors, see the Details section of the + * formatter class specification. + * + * @throws NullPointerException + * If the format is null + * + * @return This output stream + * + * @since 1.5 + */ + public PrintStream format(Locale l, String format, Object ... args) { + try { + synchronized (this) { + ensureOpen(); + if ((formatter == null) + || (formatter.locale() != l)) + formatter = new Formatter(this, l); + formatter.format(l, format, args); + } + } catch (InterruptedIOException x) { + Thread.currentThread().interrupt(); + } catch (IOException x) { + trouble = true; + } + return this; + } + + /** + * Appends the specified character sequence to this output stream. + * + *

An invocation of this method of the form out.append(csq) + * behaves in exactly the same way as the invocation + * + *

+     *     out.print(csq.toString()) 
+ * + *

Depending on the specification of toString for the + * character sequence csq, the entire sequence may not be + * appended. For instance, invoking then toString method of a + * character buffer will return a subsequence whose content depends upon + * the buffer's position and limit. + * + * @param csq + * The character sequence to append. If csq is + * null, then the four characters "null" are + * appended to this output stream. + * + * @return This output stream + * + * @since 1.5 + */ + public PrintStream append(CharSequence csq) { + if (csq == null) + print("null"); + else + print(csq.toString()); + return this; + } + + /** + * Appends a subsequence of the specified character sequence to this output + * stream. + * + *

An invocation of this method of the form out.append(csq, start, + * end) when csq is not null, behaves in + * exactly the same way as the invocation + * + *

+     *     out.print(csq.subSequence(start, end).toString()) 
+ * + * @param csq + * The character sequence from which a subsequence will be + * appended. If csq is null, then characters + * will be appended as if csq contained the four + * characters "null". + * + * @param start + * The index of the first character in the subsequence + * + * @param end + * The index of the character following the last character in the + * subsequence + * + * @return This output stream + * + * @throws IndexOutOfBoundsException + * If start or end are negative, start + * is greater than end, or end is greater than + * csq.length() + * + * @since 1.5 + */ + public PrintStream append(CharSequence csq, int start, int end) { + CharSequence cs = (csq == null ? "null" : csq); + write(cs.subSequence(start, end).toString()); + return this; + } + + /** + * Appends the specified character to this output stream. + * + *

An invocation of this method of the form out.append(c) + * behaves in exactly the same way as the invocation + * + *

+     *     out.print(c) 
+ * + * @param c + * The 16-bit character to append + * + * @return This output stream + * + * @since 1.5 + */ + public PrintStream append(char c) { + print(c); + return this; + } + +}