public void generateCompoundAssignment( BlockScope currentScope, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { this.receiver.generateCode(currentScope, true); if (this.receiver instanceof CastExpression // ((type[])null)[0] && ((CastExpression) this.receiver).innermostCastedExpression().resolvedType == TypeBinding.NULL) {} this.position.generateCode(currentScope, true); int operationTypeID; switch (operationTypeID = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) { case T_JavaLangString: case T_JavaLangObject: case T_undefined: break; default: // promote the array reference to the suitable operation type // generate the increment value (will by itself be promoted to the operation value) if (expression == IntLiteral.One) { // prefix operation } else { expression.generateCode(currentScope, true); } } }
/** * Die Methode generiert den Assembler-Code für diesen Ausdruck. Sie geht davon aus, dass die * Kontextanalyse vorher erfolgreich abgeschlossen wurde. * * @param code Der Strom, in den die Ausgabe erfolgt. */ void generateCode(CodeStream code) { leftOperand.generateCode(code); rightOperand.generateCode(code); }
/* * The APIs with an extra argument is used whenever there are two references to the same variable which * are optimized in one access: e.g "a = a + 1" optimized into "a++". */ public void generateCompoundAssignment( BlockScope currentScope, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.FIELD: // assigning to a field break; case Binding.LOCAL: // assigning to a local variable (cannot assign to outer local) LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; // using incr bytecode if possible Constant assignConstant; switch (localBinding.type.id) { case T_JavaLangString: return; case T_int: assignConstant = expression.constant; if (localBinding.resolvedPosition == -1) { if (valueRequired) { /* * restart code gen because we either: * - need the value * - the constant can have potential side-effect */ localBinding.useFlag = LocalVariableBinding.USED; throw new AbortMethod(null, null); } else if (assignConstant == Constant.NotAConstant) { // we only need to generate the value of the expression's constant if it is not a // constant expression expression.generateCode(currentScope, false); } return; } if ((assignConstant != Constant.NotAConstant) && (assignConstant.typeID() != TypeIds.T_float) // only for integral types && (assignConstant.typeID() != TypeIds.T_double)) { // TODO (philippe) is this test needed ? switch (operator) { case PLUS: int increment = assignConstant.intValue(); if (increment != (short) increment) break; // not representable as a 16-bits value return; case MINUS: increment = -assignConstant.intValue(); if (increment != (short) increment) break; // not representable as a 16-bits value return; } } // $FALL-THROUGH$ default: if (localBinding.resolvedPosition == -1) { assignConstant = expression.constant; if (valueRequired) { /* * restart code gen because we either: * - need the value * - the constant can have potential side-effect */ localBinding.useFlag = LocalVariableBinding.USED; throw new AbortMethod(null, null); } else if (assignConstant == Constant.NotAConstant) { // we only need to generate the value of the expression's constant if it is not a // constant expression expression.generateCode(currentScope, false); } return; } } } switch ((this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) { case T_JavaLangString: case T_JavaLangObject: case T_undefined: // we enter here if the single name reference is a field of type java.lang.String or if the // type of the // operation is java.lang.Object // For example: o = o + ""; // where the compiled type of o is java.lang.Object. // no need for generic cast on previous #getfield since using Object string buffer methods. break; default: // promote the array reference to the suitable operation type // generate the increment value (will by itself be promoted to the operation value) if (expression != IntLiteral.One) { // prefix operation expression.generateCode(currentScope, true); } } // store the result back into the variable switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.FIELD: // assigning to a field FieldBinding codegenField = ((FieldBinding) this.binding).original(); fieldStore( currentScope, codegenField, writeAccessor, this.actualReceiverType, true /* implicit this*/, valueRequired); // no need for generic cast as value got dupped return; case Binding.LOCAL: // assigning to a local variable LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; if (valueRequired) { switch (localBinding.type.id) { case TypeIds.T_long: case TypeIds.T_double: break; default: break; } } } }
/** * Die Methode generiert den Assembler-Code für diesen Ausdruck. Sie geht davon aus, dass die * Kontextanalyse vorher erfolgreich abgeschlossen wurde. * * @param code Der Strom, in den die Ausgabe erfolgt. */ void generateCode(CodeStream code) { if (identifier.declaration instanceof VarDeclaration) { VarDeclaration v = (VarDeclaration) identifier.declaration; if (v.isAttribute) { code.println("; Referenz auf Attribut " + identifier.name); code.println("MRM R5, (R2)"); code.println("MRI R6, " + v.offset); code.println("ADD R5, R6"); code.println("MMR (R2), R5"); } else { code.println("; Referenz auf Variable " + identifier.name); code.println("MRI R5, " + v.offset); code.println("ADD R5, R3"); code.println("ADD R2, R1"); code.println("MMR (R2), R5"); } } else if (identifier.declaration instanceof MethodDeclaration) { MethodDeclaration m = (MethodDeclaration) identifier.declaration; /** BEGIN Aufgabe (f): Methoden Parameter */ code.println("; CALL " + m.self.type.name + "." + m.identifier.name); /** BEGIN Aufgabe (j): Garbage Collector */ code.println("MRM R5, (R2) ; SELF von R2 nehmen"); code.println("SUB R2, R1"); code.println("ADD R4, R1"); code.println("MMR (R4), R5 ; SELF auf R4 legen"); /** END Aufgabe (j) */ if (!params.isEmpty()) { for (int i = 0; i < params.size(); i++) { Expression p = params.get(i); code.println("; Parameter " + i + ":"); p.generateCode(code); /** BEGIN Aufgabe (j): Garbage Collector */ code.println("MRM R5, (R2) ; Parameter " + i + " von R2 nehmen"); code.println("SUB R2, R1"); code.println("ADD R4, R1"); code.println("MMR (R4), R5 ; Parameter " + i + " auf R4 legen"); /** END Aufgabe (j) */ } } /** END Aufgabe (f) */ String returnLabel = code.nextLabel(); code.println("MRI R5, " + returnLabel); code.println("ADD R2, R1"); code.println("MMR (R2), R5 ; Rücksprungadresse auf den Stapel"); /** BEGIN Aufgabe (i): Vererbung */ if (dynamicBind) { // dynamisches Binden code.println("; Dynamischer Aufruf von " + identifier.name); code.println("MRI R5, " + (m.self.offset + 1)); /** BEGIN Aufgabe (j): Garbage Collector */ // code.println("ADD R5, R2 "); code.println("ADD R5, R4 "); /** END Aufgabe (j) */ code.println("MRM R5, (R5) ; Adresse von SELF auf dem Heap "); code.println("MRM R5, (R5) ; VMT Referenz "); code.println("MRI R6, " + m.index + " ; Methodenoffset"); code.println("ADD R5, R6 ; Methodenoffset anwenden"); code.println("MRM R5, (R5) ; Methodenadresse holen "); code.println("MRR R0, R5 ; Sprung zu " + m.identifier.name); } else { code.println("; Statischer Aufruf von " + identifier.name); code.println("MRI R0, " + m.self.type.name + "_" + m.identifier.name); } /** END Aufgabe (i) */ // code.println("; Statischer Aufruf von " + identifier.name); // code.println("MRI R0, " + m.self.type.name + "_" + m.identifier.name); code.println(returnLabel + ":"); } else { assert false; } }
public void generateCompoundAssignment( BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { boolean isStatic; // check if compound assignment is the only usage of a private field reportOnlyUselesslyReadPrivateField(currentScope, this.binding, valueRequired); FieldBinding codegenBinding = this.binding.original(); this.receiver.generateCode(currentScope, codeStream, !(isStatic = codegenBinding.isStatic())); if (isStatic) { if (this.syntheticAccessors == null || this.syntheticAccessors[FieldReference.READ] == null) { TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass( currentScope, codegenBinding, this.actualReceiverType, this.receiver.isImplicitThis()); codeStream.fieldAccess(Opcodes.OPC_getstatic, codegenBinding, constantPoolDeclaringClass); } else { codeStream.invoke( Opcodes.OPC_invokestatic, this.syntheticAccessors[FieldReference.READ], null /* default declaringClass */); } } else { codeStream.dup(); if (this.syntheticAccessors == null || this.syntheticAccessors[FieldReference.READ] == null) { TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass( currentScope, codegenBinding, this.actualReceiverType, this.receiver.isImplicitThis()); codeStream.fieldAccess(Opcodes.OPC_getfield, codegenBinding, constantPoolDeclaringClass); } else { codeStream.invoke( Opcodes.OPC_invokestatic, this.syntheticAccessors[FieldReference.READ], null /* default declaringClass */); } } int operationTypeID; switch (operationTypeID = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) { case T_JavaLangString: case T_JavaLangObject: case T_undefined: codeStream.generateStringConcatenationAppend(currentScope, null, expression); break; default: if (this.genericCast != null) codeStream.checkcast(this.genericCast); // promote the array reference to the suitable operation type codeStream.generateImplicitConversion(this.implicitConversion); // generate the increment value (will by itself be promoted to the operation value) if (expression == IntLiteral.One) { // prefix operation codeStream.generateConstant(expression.constant, this.implicitConversion); } else { expression.generateCode(currentScope, codeStream, true); } // perform the operation codeStream.sendOperator(operator, operationTypeID); // cast the value back to the array reference type codeStream.generateImplicitConversion(assignmentImplicitConversion); } fieldStore( currentScope, codeStream, codegenBinding, this.syntheticAccessors == null ? null : this.syntheticAccessors[FieldReference.WRITE], this.actualReceiverType, this.receiver.isImplicitThis(), valueRequired); // no need for generic cast as value got dupped }
/** Code generation for a array initializer */ public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { // Flatten the values and compute the dimensions, by iterating in depth into nested array // initializers int pc = codeStream.position; int expressionLength = (this.expressions == null) ? 0 : this.expressions.length; codeStream.generateInlinedValue(expressionLength); codeStream.newArray(this.binding); if (this.expressions != null) { // binding is an ArrayType, so I can just deal with the dimension int elementsTypeID = this.binding.dimensions > 1 ? -1 : this.binding.leafComponentType.id; for (int i = 0; i < expressionLength; i++) { Expression expr; if ((expr = this.expressions[i]).constant != Constant.NotAConstant) { switch (elementsTypeID) { // filter out initializations to default values case T_int: case T_short: case T_byte: case T_char: case T_long: if (expr.constant.longValue() != 0) { codeStream.dup(); codeStream.generateInlinedValue(i); expr.generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } break; case T_float: case T_double: double constantValue = expr.constant.doubleValue(); if (constantValue == -0.0 || constantValue != 0) { codeStream.dup(); codeStream.generateInlinedValue(i); expr.generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } break; case T_boolean: if (expr.constant.booleanValue() != false) { codeStream.dup(); codeStream.generateInlinedValue(i); expr.generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } break; default: if (!(expr instanceof NullLiteral)) { codeStream.dup(); codeStream.generateInlinedValue(i); expr.generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } } } else if (!(expr instanceof NullLiteral)) { codeStream.dup(); codeStream.generateInlinedValue(i); expr.generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } } } if (valueRequired) { codeStream.generateImplicitConversion(this.implicitConversion); } else { codeStream.pop(); } codeStream.recordPositionsFrom(pc, this.sourceStart); }