| /******************************************************************************* |
| * Copyright (c) 2000, 2021 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * This is an implementation of an early-draft specification developed under the Java |
| * Community Process (JCP) and is made available for testing and evaluation purposes |
| * only. The code is not compatible with any specification of the JCP. |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Stephan Herrmann - Contribution for |
| * bug 400710 - [1.8][compiler] synthetic access to default method generates wrong code |
| * bug 391376 - [1.8] check interaction of default methods with bridge methods and generics |
| * bug 421543 - [1.8][compiler] Compiler fails to recognize default method being turned into abstract by subtytpe |
| * Jesper S Moller - Contributions for |
| * Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335 |
| * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for |
| * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) |
| * Bug 409247 - [1.8][compiler] Verify error with code allocating multidimensional array |
| * Bug 409236 - [1.8][compiler] Type annotations on intersection cast types dropped by code generator |
| * Bug 409250 - [1.8][compiler] Various loose ends in 308 code generation |
| * Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas |
| * Bug 449467 - [1.8][compiler] Invalid lambda deserialization with anonymous class |
| * Olivier Tardieu (tardieu@us.ibm.com) - Contributions for |
| * Bug 442418 - $deserializeLambda$ off-by-one error when deserializing the captured arguments of a lambda that also capture this |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.compiler.codegen; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.Stack; |
| import java.util.function.Supplier; |
| |
| import org.eclipse.jdt.core.compiler.CharOperation; |
| import org.eclipse.jdt.internal.compiler.ClassFile; |
| import org.eclipse.jdt.internal.compiler.CompilationResult; |
| import org.eclipse.jdt.internal.compiler.ast.ASTNode; |
| import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; |
| import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression; |
| import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; |
| import org.eclipse.jdt.internal.compiler.ast.Expression; |
| import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.FunctionalExpression; |
| import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; |
| import org.eclipse.jdt.internal.compiler.ast.OperatorIds; |
| import org.eclipse.jdt.internal.compiler.ast.ReferenceExpression; |
| import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.TypeReference; |
| import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo; |
| import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
| import org.eclipse.jdt.internal.compiler.impl.Constant; |
| import org.eclipse.jdt.internal.compiler.lookup.*; |
| import org.eclipse.jdt.internal.compiler.problem.AbortMethod; |
| import org.eclipse.jdt.internal.compiler.util.Util; |
| |
| @SuppressWarnings({"rawtypes", "unchecked"}) |
| public class CodeStream { |
| |
| // It will be responsible for the following items. |
| // -> Tracking Max Stack. |
| |
| public static FieldBinding[] ImplicitThis = new FieldBinding[] {}; |
| public static final int LABELS_INCREMENT = 5; |
| // local variable attributes output |
| public static final int LOCALS_INCREMENT = 10; |
| public static final CompilationResult RESTART_IN_WIDE_MODE = new CompilationResult((char[])null, 0, 0, 0); |
| public static final CompilationResult RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE = new CompilationResult((char[])null, 0, 0, 0); |
| |
| public int allLocalsCounter; |
| public byte[] bCodeStream; |
| public ClassFile classFile; // The current classfile it is associated to. |
| public int classFileOffset; |
| public ConstantPool constantPool; // The constant pool used to generate bytecodes that need to store information into the constant pool |
| public int countLabels; |
| public ExceptionLabel[] exceptionLabels = new ExceptionLabel[LABELS_INCREMENT]; |
| public int exceptionLabelsCounter; |
| public int generateAttributes; |
| // store all the labels placed at the current position to be able to optimize |
| // a jump to the next bytecode. |
| static final int L_UNKNOWN = 0, L_OPTIMIZABLE = 2, L_CANNOT_OPTIMIZE = 4; |
| public BranchLabel[] labels = new BranchLabel[LABELS_INCREMENT]; |
| public int lastEntryPC; // last entry recorded |
| public int lastAbruptCompletion; // position of last instruction which abrupts completion: goto/return/athrow |
| |
| public int[] lineSeparatorPositions; |
| // line number of the body start and the body end |
| public int lineNumberStart; |
| |
| public int lineNumberEnd; |
| public LocalVariableBinding[] locals = new LocalVariableBinding[LOCALS_INCREMENT]; |
| public int maxFieldCount; |
| public int maxLocals; |
| public AbstractMethodDeclaration methodDeclaration; |
| public LambdaExpression lambdaExpression; |
| public int[] pcToSourceMap = new int[24]; |
| public int pcToSourceMapSize; |
| public int position; // So when first set can be incremented |
| public boolean preserveUnusedLocals; |
| |
| public int stackDepth; // Use Ints to keep from using extra bc when adding |
| |
| public int stackMax; // Use Ints to keep from using extra bc when adding |
| public int startingClassFileOffset; // I need to keep the starting point inside the byte array |
| // target level to manage different code generation between different target levels |
| protected long targetLevel; |
| |
| public LocalVariableBinding[] visibleLocals = new LocalVariableBinding[LOCALS_INCREMENT]; |
| |
| int visibleLocalsCount; |
| |
| // to handle goto_w |
| public boolean wideMode = false; |
| |
| public Stack<TypeBinding> switchSaveTypeBindings = new Stack<>(); |
| public int lastSwitchCumulativeSyntheticVars = 0; |
| |
| public CodeStream(ClassFile givenClassFile) { |
| this.targetLevel = givenClassFile.targetJDK; |
| this.generateAttributes = givenClassFile.produceAttributes; |
| if ((givenClassFile.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { |
| this.lineSeparatorPositions = givenClassFile.referenceBinding.scope.referenceCompilationUnit().compilationResult.getLineSeparatorPositions(); |
| } |
| } |
| /** |
| * This methods searches for an existing entry inside the pcToSourceMap table with a pc equals to @pc. |
| * If there is an existing entry it returns -1 (no insertion required). |
| * Otherwise it returns the index where the entry for the pc has to be inserted. |
| * This is based on the fact that the pcToSourceMap table is sorted according to the pc. |
| * |
| * @param pcToSourceMap the given pcToSourceMap array |
| * @param length the given length |
| * @param pc the given pc |
| * @return int |
| */ |
| public static int insertionIndex(int[] pcToSourceMap, int length, int pc) { |
| int g = 0; |
| int d = length - 2; |
| int m = 0; |
| while (g <= d) { |
| m = (g + d) / 2; |
| // we search only on even indexes |
| if ((m & 1) != 0) // faster than ((m % 2) != 0) |
| m--; |
| int currentPC = pcToSourceMap[m]; |
| if (pc < currentPC) { |
| d = m - 2; |
| } else |
| if (pc > currentPC) { |
| g = m + 2; |
| } else { |
| return -1; |
| } |
| } |
| if (pc < pcToSourceMap[m]) |
| return m; |
| return m + 2; |
| } |
| public static final void sort(int[] tab, int lo0, int hi0, int[] result) { |
| int lo = lo0; |
| int hi = hi0; |
| int mid; |
| if (hi0 > lo0) { |
| /* Arbitrarily establishing partition element as the midpoint of |
| * the array. |
| */ |
| mid = tab[lo0 + (hi0 - lo0) / 2]; |
| // loop through the array until indices cross |
| while (lo <= hi) { |
| /* find the first element that is greater than or equal to |
| * the partition element starting from the left Index. |
| */ |
| while ((lo < hi0) && (tab[lo] < mid)) |
| ++lo; |
| /* find an element that is smaller than or equal to |
| * the partition element starting from the right Index. |
| */ |
| while ((hi > lo0) && (tab[hi] > mid)) |
| --hi; |
| // if the indexes have not crossed, swap |
| if (lo <= hi) { |
| swap(tab, lo, hi, result); |
| ++lo; |
| --hi; |
| } |
| } |
| /* If the right index has not reached the left side of array |
| * must now sort the left partition. |
| */ |
| if (lo0 < hi) |
| sort(tab, lo0, hi, result); |
| /* If the left index has not reached the right side of array |
| * must now sort the right partition. |
| */ |
| if (lo < hi0) |
| sort(tab, lo, hi0, result); |
| } |
| } |
| |
| |
| private static final void swap(int a[], int i, int j, int result[]) { |
| int T; |
| T = a[i]; |
| a[i] = a[j]; |
| a[j] = T; |
| T = result[j]; |
| result[j] = result[i]; |
| result[i] = T; |
| } |
| |
| public void aaload() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_aaload; |
| pushTypeBindingArray(); |
| } |
| |
| public void aastore() { |
| this.countLabels = 0; |
| this.stackDepth -= 3; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_aastore; |
| popTypeBinding(3); |
| } |
| |
| public void aconst_null() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| if (this.stackDepth > this.stackMax) { |
| this.stackMax = this.stackDepth; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_aconst_null; |
| pushTypeBinding(TypeBinding.NULL); |
| } |
| |
| public void addDefinitelyAssignedVariables(Scope scope, int initStateIndex) { |
| // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect |
| if ((this.generateAttributes & (ClassFileConstants.ATTR_VARS |
| | ClassFileConstants.ATTR_STACK_MAP_TABLE |
| | ClassFileConstants.ATTR_STACK_MAP)) == 0) |
| return; |
| for (int i = 0; i < this.visibleLocalsCount; i++) { |
| LocalVariableBinding localBinding = this.visibleLocals[i]; |
| if (localBinding != null) { |
| // Check if the local is definitely assigned |
| if (isDefinitelyAssigned(scope, initStateIndex, localBinding)) { |
| if ((localBinding.initializationCount == 0) || (localBinding.initializationPCs[((localBinding.initializationCount - 1) << 1) + 1] != -1)) { |
| /* There are two cases: |
| * 1) there is no initialization interval opened ==> add an opened interval |
| * 2) there is already some initialization intervals but the last one is closed ==> add an opened interval |
| * An opened interval means that the value at localBinding.initializationPCs[localBinding.initializationCount - 1][1] |
| * is equals to -1. |
| * initializationPCs is a collection of pairs of int: |
| * first value is the startPC and second value is the endPC. -1 one for the last value means that the interval |
| * is not closed yet. |
| */ |
| localBinding.recordInitializationStartPC(this.position); |
| } |
| } |
| } |
| } |
| } |
| |
| public void addLabel(BranchLabel aLabel) { |
| if (this.countLabels == this.labels.length) |
| System.arraycopy(this.labels, 0, this.labels = new BranchLabel[this.countLabels + LABELS_INCREMENT], 0, this.countLabels); |
| this.labels[this.countLabels++] = aLabel; |
| } |
| |
| public void addVariable(LocalVariableBinding localBinding) { |
| /* do nothing */ |
| } |
| |
| public void addVisibleLocalVariable(LocalVariableBinding localBinding) { |
| if ((this.generateAttributes & (ClassFileConstants.ATTR_VARS |
| | ClassFileConstants.ATTR_STACK_MAP_TABLE |
| | ClassFileConstants.ATTR_STACK_MAP)) == 0) |
| return; |
| |
| if (this.visibleLocalsCount >= this.visibleLocals.length) |
| System.arraycopy(this.visibleLocals, 0, this.visibleLocals = new LocalVariableBinding[this.visibleLocalsCount * 2], 0, this.visibleLocalsCount); |
| this.visibleLocals[this.visibleLocalsCount++] = localBinding; |
| } |
| |
| public void aload(int iArg) { |
| this.countLabels = 0; |
| this.stackDepth++; |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.maxLocals <= iArg) { |
| this.maxLocals = iArg + 1; |
| } |
| pushTypeBinding(iArg); |
| if (iArg > 255) { // Widen |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_aload; |
| writeUnsignedShort(iArg); |
| } else { |
| // Don't need to use the wide bytecode |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_aload; |
| this.bCodeStream[this.classFileOffset++] = (byte) iArg; |
| } |
| } |
| |
| public void aload_0() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(0); |
| if (this.stackDepth > this.stackMax) { |
| this.stackMax = this.stackDepth; |
| } |
| if (this.maxLocals == 0) { |
| this.maxLocals = 1; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_aload_0; |
| } |
| |
| public void aload_1() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(1); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.maxLocals <= 1) { |
| this.maxLocals = 2; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_aload_1; |
| } |
| |
| public void aload_2() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(2); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.maxLocals <= 2) { |
| this.maxLocals = 3; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_aload_2; |
| } |
| |
| public void aload_3() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(3); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.maxLocals <= 3) { |
| this.maxLocals = 4; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_aload_3; |
| } |
| |
| public void anewarray(TypeBinding typeBinding) { |
| this.countLabels = 0; |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_anewarray; |
| writeUnsignedShort(this.constantPool.literalIndexForType(typeBinding)); |
| pushTypeBinding(1, typeBinding); |
| } |
| |
| public void areturn() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| // the stackDepth should be equal to 0 |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_areturn; |
| this.lastAbruptCompletion = this.position; |
| } |
| |
| public void arrayAt(int typeBindingID) { |
| switch (typeBindingID) { |
| case TypeIds.T_int : |
| iaload(); |
| break; |
| case TypeIds.T_byte : |
| case TypeIds.T_boolean : |
| baload(); |
| break; |
| case TypeIds.T_short : |
| saload(); |
| break; |
| case TypeIds.T_char : |
| caload(); |
| break; |
| case TypeIds.T_long : |
| laload(); |
| break; |
| case TypeIds.T_float : |
| faload(); |
| break; |
| case TypeIds.T_double : |
| daload(); |
| break; |
| default : |
| aaload(); |
| } |
| } |
| |
| public void arrayAtPut(int elementTypeID, boolean valueRequired) { |
| switch (elementTypeID) { |
| case TypeIds.T_int : |
| if (valueRequired) |
| dup_x2(); |
| iastore(); |
| break; |
| case TypeIds.T_byte : |
| case TypeIds.T_boolean : |
| if (valueRequired) |
| dup_x2(); |
| bastore(); |
| break; |
| case TypeIds.T_short : |
| if (valueRequired) |
| dup_x2(); |
| sastore(); |
| break; |
| case TypeIds.T_char : |
| if (valueRequired) |
| dup_x2(); |
| castore(); |
| break; |
| case TypeIds.T_long : |
| if (valueRequired) |
| dup2_x2(); |
| lastore(); |
| break; |
| case TypeIds.T_float : |
| if (valueRequired) |
| dup_x2(); |
| fastore(); |
| break; |
| case TypeIds.T_double : |
| if (valueRequired) |
| dup2_x2(); |
| dastore(); |
| break; |
| default : |
| if (valueRequired) |
| dup_x2(); |
| aastore(); |
| } |
| } |
| |
| public void arraylength() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_arraylength; |
| pushTypeBinding(1, TypeBinding.INT); |
| } |
| |
| public void astore(int iArg) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals <= iArg) { |
| this.maxLocals = iArg + 1; |
| } |
| if (iArg > 255) { // Widen |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position+=2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_astore; |
| writeUnsignedShort(iArg); |
| } else { |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position+=2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_astore; |
| this.bCodeStream[this.classFileOffset++] = (byte) iArg; |
| } |
| } |
| |
| public void astore_0() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals == 0) { |
| this.maxLocals = 1; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_astore_0; |
| } |
| |
| public void astore_1() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals <= 1) { |
| this.maxLocals = 2; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_astore_1; |
| } |
| |
| public void astore_2() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals <= 2) { |
| this.maxLocals = 3; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_astore_2; |
| } |
| |
| public void astore_3() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals <= 3) { |
| this.maxLocals = 4; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_astore_3; |
| } |
| |
| public void athrow() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_athrow; |
| this.lastAbruptCompletion = this.position; |
| } |
| |
| public void baload() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBindingArray(); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_baload; |
| } |
| |
| public void bastore() { |
| this.countLabels = 0; |
| this.stackDepth -= 3; |
| popTypeBinding(3); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_bastore; |
| } |
| |
| public void bipush(byte b) { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.BYTE); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_bipush; |
| this.bCodeStream[this.classFileOffset++] = b; |
| } |
| |
| public void caload() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBindingArray(); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_caload; |
| } |
| |
| public void castore() { |
| this.countLabels = 0; |
| this.stackDepth -= 3; |
| popTypeBinding(3); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_castore; |
| } |
| |
| public void checkcast(int baseId) { |
| this.countLabels = 0; |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_checkcast; |
| switch (baseId) { |
| case TypeIds.T_byte : |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangByteConstantPoolName)); |
| break; |
| case TypeIds.T_short : |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangShortConstantPoolName)); |
| break; |
| case TypeIds.T_char : |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangCharacterConstantPoolName)); |
| break; |
| case TypeIds.T_int : |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangIntegerConstantPoolName)); |
| break; |
| case TypeIds.T_long : |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangLongConstantPoolName)); |
| break; |
| case TypeIds.T_float : |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangFloatConstantPoolName)); |
| break; |
| case TypeIds.T_double : |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangDoubleConstantPoolName)); |
| break; |
| case TypeIds.T_boolean : |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangBooleanConstantPoolName)); |
| } |
| pushTypeBinding(1, TypeBinding.wellKnownBaseType(baseId)); |
| } |
| |
| public void checkcast(TypeBinding typeBinding) { |
| this.checkcast(null, typeBinding, -1); |
| } |
| |
| public void checkcast(TypeReference typeReference, TypeBinding typeBinding, int currentPosition) { |
| this.countLabels = 0; |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_checkcast; |
| writeUnsignedShort(this.constantPool.literalIndexForType(typeBinding)); |
| pushTypeBinding(1, typeBinding); |
| |
| } |
| |
| public void d2f() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(1, TypeBinding.FLOAT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_d2f; |
| } |
| |
| public void d2i() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(1, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_d2i; |
| } |
| |
| public void d2l() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_d2l; |
| pushTypeBinding(1, TypeBinding.LONG); |
| } |
| |
| public void dadd() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dadd; |
| pushTypeBinding(2, TypeBinding.DOUBLE); |
| } |
| |
| public void daload() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_daload; |
| pushTypeBindingArray(); |
| } |
| |
| public void dastore() { |
| this.countLabels = 0; |
| this.stackDepth -= 4; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dastore; |
| popTypeBinding(3); |
| } |
| |
| public void dcmpg() { |
| this.countLabels = 0; |
| this.stackDepth -= 3; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dcmpg; |
| pushTypeBinding(2, TypeBinding.INT); |
| } |
| |
| public void dcmpl() { |
| this.countLabels = 0; |
| this.stackDepth -= 3; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dcmpl; |
| pushTypeBinding(2, TypeBinding.INT); |
| } |
| |
| public void dconst_0() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.DOUBLE); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dconst_0; |
| } |
| |
| public void dconst_1() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.DOUBLE); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dconst_1; |
| } |
| |
| public void ddiv() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| pushTypeBinding(2, TypeBinding.DOUBLE); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ddiv; |
| } |
| |
| public void decrStackSize(int offset) { |
| this.stackDepth -= offset; |
| } |
| |
| public void dload(int iArg) { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.maxLocals < iArg + 2) { |
| this.maxLocals = iArg + 2; // + 2 because it is a double |
| } |
| pushTypeBinding(TypeBinding.DOUBLE); |
| if (iArg > 255) { // Widen |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dload; |
| writeUnsignedShort(iArg); |
| } else { |
| // Don't need to use the wide bytecode |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dload; |
| this.bCodeStream[this.classFileOffset++] = (byte) iArg; |
| } |
| } |
| |
| public void dload_0() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.DOUBLE); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.maxLocals < 2) { |
| this.maxLocals = 2; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dload_0; |
| } |
| |
| public void dload_1() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.DOUBLE); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.maxLocals < 3) { |
| this.maxLocals = 3; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dload_1; |
| } |
| |
| public void dload_2() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.DOUBLE); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.maxLocals < 4) { |
| this.maxLocals = 4; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dload_2; |
| } |
| |
| public void dload_3() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.DOUBLE); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.maxLocals < 5) { |
| this.maxLocals = 5; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dload_3; |
| } |
| |
| public void dmul() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| pushTypeBinding(2, TypeBinding.DOUBLE); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dmul; |
| } |
| |
| public void dneg() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dneg; |
| pushTypeBinding(1, TypeBinding.DOUBLE); |
| } |
| |
| public void drem() { |
| this.countLabels = 0; |
| pushTypeBinding(2, TypeBinding.DOUBLE); |
| this.stackDepth -= 2; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_drem; |
| } |
| |
| public void dreturn() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| // the stackDepth should be equal to 0 |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dreturn; |
| this.lastAbruptCompletion = this.position; |
| } |
| |
| public void dstore(int iArg) { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| if (this.maxLocals <= iArg + 1) { |
| this.maxLocals = iArg + 2; |
| } |
| if (iArg > 255) { // Widen |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dstore; |
| writeUnsignedShort(iArg); |
| } else { |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dstore; |
| this.bCodeStream[this.classFileOffset++] = (byte) iArg; |
| } |
| } |
| |
| public void dstore_0() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| if (this.maxLocals < 2) { |
| this.maxLocals = 2; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dstore_0; |
| } |
| |
| public void dstore_1() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| if (this.maxLocals < 3) { |
| this.maxLocals = 3; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dstore_1; |
| } |
| |
| public void dstore_2() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| if (this.maxLocals < 4) { |
| this.maxLocals = 4; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dstore_2; |
| } |
| |
| public void dstore_3() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| if (this.maxLocals < 5) { |
| this.maxLocals = 5; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dstore_3; |
| } |
| |
| public void dsub() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| pushTypeBinding(2, TypeBinding.DOUBLE); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dsub; |
| } |
| |
| public void dup() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| if (isSwitchStackTrackingActive()) { |
| pushTypeBinding(this.switchSaveTypeBindings.peek()); |
| } |
| if (this.stackDepth > this.stackMax) { |
| this.stackMax = this.stackDepth; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dup; |
| } |
| |
| private void adjustTypeBindingStackForDupX1() { |
| if (isSwitchStackTrackingActive()) { |
| TypeBinding[] topStack = { popTypeBinding(), popTypeBinding() }; |
| pushTypeBinding(topStack[0]); |
| pushTypeBinding(topStack[1]); |
| pushTypeBinding(topStack[0]); |
| } |
| } |
| |
| public void dup_x1() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| adjustTypeBindingStackForDupX1(); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dup_x1; |
| } |
| |
| private void adjustTypeBindingStackForDupX2() { |
| if (!isSwitchStackTrackingActive()) |
| return; |
| TypeBinding val1 = popTypeBinding(); |
| TypeBinding val2 = popTypeBinding(); |
| if (TypeIds.getCategory(val1.id) == 1) { |
| if (TypeIds.getCategory(val2.id) == 2) { |
| pushTypeBinding(val1); |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| } else { // 1 |
| TypeBinding val3 = popTypeBinding(); |
| if (TypeIds.getCategory(val3.id) == 1) { |
| pushTypeBinding(val1); |
| pushTypeBinding(val3); |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| } |
| } |
| } |
| } |
| public void dup_x2() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| adjustTypeBindingStackForDupX2(); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dup_x2; |
| } |
| |
| private void adjustTypeBindingStackForDup2() { |
| if (!isSwitchStackTrackingActive()) |
| return; |
| TypeBinding val1 = popTypeBinding(); |
| if (TypeIds.getCategory(val1.id) == 2) { |
| pushTypeBinding(val1); |
| pushTypeBinding(val1); |
| } else { // val1 category 1 |
| TypeBinding val2 = popTypeBinding(); |
| if (TypeIds.getCategory(val2.id) == 1) { |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| } |
| } |
| } |
| public void dup2() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| adjustTypeBindingStackForDup2(); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dup2; |
| } |
| |
| private void adjustTypeBindingStackForDup2X1() { |
| if (!isSwitchStackTrackingActive()) |
| return; |
| TypeBinding val1 = popTypeBinding(); |
| TypeBinding val2 = popTypeBinding(); |
| if (TypeIds.getCategory(val1.id) == 2) { |
| if (TypeIds.getCategory(val2.id) == 1) { |
| pushTypeBinding(val1); |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| } |
| } else { // val1 cat 1 |
| if (TypeIds.getCategory(val2.id) == 1) { |
| TypeBinding val3 = popTypeBinding(); |
| if (TypeIds.getCategory(val3.id) == 1) { |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| pushTypeBinding(val3); |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| } |
| } |
| } |
| } |
| public void dup2_x1() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| adjustTypeBindingStackForDup2X1(); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dup2_x1; |
| } |
| |
| private void adjustTypeBindingStackForDup2X2() { |
| if (!isSwitchStackTrackingActive()) |
| return; |
| TypeBinding val1 = popTypeBinding(); |
| if (TypeIds.getCategory(val1.id) == 2) { |
| TypeBinding val2 = popTypeBinding(); |
| if (TypeIds.getCategory(val2.id) == 2) { // Form 4 |
| pushTypeBinding(val1); |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| } else { |
| TypeBinding val3 = popTypeBinding(); |
| if (TypeIds.getCategory(val3.id) == 1) { // Form 2 |
| pushTypeBinding(val1); |
| pushTypeBinding(val3); |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| } |
| } |
| pushTypeBinding(val1); |
| pushTypeBinding(val1); |
| } else { // val1 category 1 |
| TypeBinding val2 = popTypeBinding(); |
| if (TypeIds.getCategory(val2.id) == 1) { |
| TypeBinding val3 = popTypeBinding(); |
| if (TypeIds.getCategory(val3.id) == 2) { // Form 3 |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| pushTypeBinding(val3); |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| } else { // val3 cat 1 |
| TypeBinding val4 = popTypeBinding(); |
| if (TypeIds.getCategory(val4.id) == 1) { // Form 1 |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| pushTypeBinding(val4); |
| pushTypeBinding(val3); |
| pushTypeBinding(val2); |
| pushTypeBinding(val1); |
| } |
| } |
| } |
| } |
| } |
| public void dup2_x2() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| adjustTypeBindingStackForDup2X2(); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dup2_x2; |
| } |
| |
| public void exitUserScope(BlockScope currentScope) { |
| // mark all the scope's locals as losing their definite assignment |
| if ((this.generateAttributes & (ClassFileConstants.ATTR_VARS |
| | ClassFileConstants.ATTR_STACK_MAP_TABLE |
| | ClassFileConstants.ATTR_STACK_MAP)) == 0) |
| return; |
| int index = this.visibleLocalsCount - 1; |
| while (index >= 0) { |
| LocalVariableBinding visibleLocal = this.visibleLocals[index]; |
| if (visibleLocal == null || visibleLocal.declaringScope != currentScope) { |
| // left currentScope |
| index--; |
| continue; |
| } |
| |
| // there may be some preserved locals never initialized |
| if (visibleLocal.initializationCount > 0) { |
| visibleLocal.recordInitializationEndPC(this.position); |
| } |
| this.visibleLocals[index--] = null; // this variable is no longer visible afterwards |
| } |
| } |
| |
| public void exitUserScope(BlockScope currentScope, LocalVariableBinding binding) { |
| // mark all the scope's locals as losing their definite assignment |
| if ((this.generateAttributes & (ClassFileConstants.ATTR_VARS |
| | ClassFileConstants.ATTR_STACK_MAP_TABLE |
| | ClassFileConstants.ATTR_STACK_MAP)) == 0) |
| return; |
| int index = this.visibleLocalsCount - 1; |
| while (index >= 0) { |
| LocalVariableBinding visibleLocal = this.visibleLocals[index]; |
| if (visibleLocal == null || visibleLocal.declaringScope != currentScope || visibleLocal == binding) { |
| // left currentScope |
| index--; |
| continue; |
| } |
| // there may be some preserved locals never initialized |
| if (visibleLocal.initializationCount > 0) { |
| visibleLocal.recordInitializationEndPC(this.position); |
| } |
| this.visibleLocals[index--] = null; // this variable is no longer visible afterwards |
| } |
| } |
| |
| public void f2d() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(1, TypeBinding.DOUBLE); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_f2d; |
| } |
| |
| public void f2i() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_f2i; |
| pushTypeBinding(1, TypeBinding.INT); |
| } |
| |
| public void f2l() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(1, TypeBinding.LONG); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_f2l; |
| } |
| |
| public void fadd() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.FLOAT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fadd; |
| } |
| |
| public void faload() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBindingArray(); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_faload; |
| } |
| |
| public void fastore() { |
| this.countLabels = 0; |
| this.stackDepth -= 3; |
| popTypeBinding(3); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fastore; |
| } |
| |
| public void fcmpg() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.FLOAT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fcmpg; |
| } |
| |
| public void fcmpl() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.FLOAT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fcmpl; |
| } |
| |
| public void fconst_0() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.FLOAT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fconst_0; |
| } |
| |
| public void fconst_1() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.FLOAT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fconst_1; |
| } |
| |
| public void fconst_2() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.FLOAT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fconst_2; |
| } |
| |
| public void fdiv() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.FLOAT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fdiv; |
| } |
| |
| public void fieldAccess(byte opcode, FieldBinding fieldBinding, TypeBinding declaringClass) { |
| if (declaringClass == null) declaringClass = fieldBinding.declaringClass; |
| if ((declaringClass.tagBits & TagBits.ContainsNestedTypeReferences) != 0) { |
| Util.recordNestedType(this.classFile, declaringClass); |
| } |
| TypeBinding returnType = fieldBinding.type; |
| int returnTypeSize; |
| switch (returnType.id) { |
| case TypeIds.T_long : |
| case TypeIds.T_double : |
| returnTypeSize = 2; |
| break; |
| default : |
| returnTypeSize = 1; |
| break; |
| } |
| this.fieldAccess(opcode, returnTypeSize, declaringClass.constantPoolName(), fieldBinding.name, returnType.signature(), returnType.id, returnType); |
| } |
| |
| private void fieldAccess(byte opcode, int returnTypeSize, char[] declaringClass, char[] fieldName, char[] signature, int typeId) { |
| fieldAccess(opcode, returnTypeSize, declaringClass, fieldName, signature, typeId, null); |
| } |
| private void fieldAccess(byte opcode, int returnTypeSize, char[] declaringClass, char[] fieldName, char[] signature, int typeId, TypeBinding typeBinding) { |
| this.countLabels = 0; |
| switch(opcode) { |
| case Opcodes.OPC_getfield : |
| if (returnTypeSize == 2) { |
| this.stackDepth++; |
| } |
| pushTypeBinding(1, typeBinding); |
| break; |
| case Opcodes.OPC_getstatic : |
| if (returnTypeSize == 2) { |
| this.stackDepth += 2; |
| pushTypeBinding(typeBinding); |
| } else { |
| this.stackDepth++; |
| pushTypeBinding(typeBinding); |
| } |
| break; |
| case Opcodes.OPC_putfield : |
| if (returnTypeSize == 2) { |
| this.stackDepth -= 3; |
| popTypeBinding(2); |
| } else { |
| this.stackDepth -= 2; |
| popTypeBinding(2); |
| } |
| break; |
| case Opcodes.OPC_putstatic : |
| if (returnTypeSize == 2) { |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| } else { |
| this.stackDepth--; |
| popTypeBinding(); |
| } |
| } |
| if (this.stackDepth > this.stackMax) { |
| this.stackMax = this.stackDepth; |
| } |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = opcode; |
| writeUnsignedShort(this.constantPool.literalIndexForField(declaringClass, fieldName, signature)); |
| } |
| |
| public void fload(int iArg) { |
| this.countLabels = 0; |
| this.stackDepth++; |
| if (this.maxLocals <= iArg) { |
| this.maxLocals = iArg + 1; |
| } |
| pushTypeBinding(TypeBinding.FLOAT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (iArg > 255) { // Widen |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fload; |
| writeUnsignedShort(iArg); |
| } else { |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fload; |
| this.bCodeStream[this.classFileOffset++] = (byte) iArg; |
| } |
| } |
| |
| public void fload_0() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.FLOAT); |
| if (this.maxLocals == 0) { |
| this.maxLocals = 1; |
| } |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fload_0; |
| } |
| |
| public void fload_1() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.FLOAT); |
| if (this.maxLocals <= 1) { |
| this.maxLocals = 2; |
| } |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fload_1; |
| } |
| |
| public void fload_2() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.FLOAT); |
| if (this.maxLocals <= 2) { |
| this.maxLocals = 3; |
| } |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fload_2; |
| } |
| |
| public void fload_3() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.FLOAT); |
| if (this.maxLocals <= 3) { |
| this.maxLocals = 4; |
| } |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fload_3; |
| } |
| |
| public void fmul() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.FLOAT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fmul; |
| } |
| |
| public void fneg() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fneg; |
| pushTypeBinding(1, TypeBinding.FLOAT); |
| } |
| |
| public void frem() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.FLOAT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_frem; |
| } |
| |
| public void freturn() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| // the stackDepth should be equal to 0 |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_freturn; |
| this.lastAbruptCompletion = this.position; |
| } |
| |
| public void fstore(int iArg) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals <= iArg) { |
| this.maxLocals = iArg + 1; |
| } |
| if (iArg > 255) { // Widen |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fstore; |
| writeUnsignedShort(iArg); |
| } else { |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fstore; |
| this.bCodeStream[this.classFileOffset++] = (byte) iArg; |
| } |
| } |
| |
| public void fstore_0() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals == 0) { |
| this.maxLocals = 1; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fstore_0; |
| } |
| |
| public void fstore_1() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals <= 1) { |
| this.maxLocals = 2; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fstore_1; |
| } |
| |
| public void fstore_2() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals <= 2) { |
| this.maxLocals = 3; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fstore_2; |
| } |
| |
| public void fstore_3() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals <= 3) { |
| this.maxLocals = 4; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fstore_3; |
| } |
| |
| public void fsub() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.FLOAT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fsub; |
| } |
| |
| public void generateBoxingConversion(int unboxedTypeID) { |
| switch (unboxedTypeID) { |
| case TypeIds.T_byte : |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| // invokestatic: Byte.valueOf(byte) |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangByteConstantPoolName, |
| ConstantPool.ValueOf, |
| ConstantPool.byteByteSignature, |
| unboxedTypeID, |
| TypeBinding.BYTE); |
| } else { |
| // new Byte( byte ) |
| newWrapperFor(unboxedTypeID); |
| dup_x1(); |
| swap(); |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 2, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangByteConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.ByteConstrSignature, |
| unboxedTypeID, |
| TypeBinding.BYTE); |
| } |
| break; |
| case TypeIds.T_short : |
| if ( this.targetLevel >= ClassFileConstants.JDK1_5 ) { |
| // invokestatic: Short.valueOf(short) |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangShortConstantPoolName, |
| ConstantPool.ValueOf, |
| ConstantPool.shortShortSignature, |
| unboxedTypeID, |
| TypeBinding.SHORT); |
| } else { |
| // new Short(short) |
| newWrapperFor(unboxedTypeID); |
| dup_x1(); |
| swap(); |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 2, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangShortConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.ShortConstrSignature, |
| unboxedTypeID, |
| TypeBinding.SHORT); |
| } |
| break; |
| case TypeIds.T_char : |
| if ( this.targetLevel >= ClassFileConstants.JDK1_5 ) { |
| // invokestatic: Character.valueOf(char) |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangCharacterConstantPoolName, |
| ConstantPool.ValueOf, |
| ConstantPool.charCharacterSignature, |
| unboxedTypeID, |
| TypeBinding.CHAR); |
| } else { |
| // new Char( char ) |
| newWrapperFor(unboxedTypeID); |
| dup_x1(); |
| swap(); |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 2, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangCharacterConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.CharConstrSignature, |
| unboxedTypeID, |
| TypeBinding.CHAR); |
| } |
| break; |
| case TypeIds.T_int : |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| // invokestatic: Integer.valueOf(int) |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangIntegerConstantPoolName, |
| ConstantPool.ValueOf, |
| ConstantPool.IntIntegerSignature, |
| unboxedTypeID, |
| TypeBinding.INT); |
| } else { |
| // new Integer(int) |
| newWrapperFor(unboxedTypeID); |
| dup_x1(); |
| swap(); |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 2, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangIntegerConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.IntConstrSignature, |
| unboxedTypeID, |
| TypeBinding.INT); |
| } |
| break; |
| case TypeIds.T_long : |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| // invokestatic: Long.valueOf(long) |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 2, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangLongConstantPoolName, |
| ConstantPool.ValueOf, |
| ConstantPool.longLongSignature, |
| unboxedTypeID, |
| TypeBinding.LONG); |
| } else { |
| // new Long( long ) |
| newWrapperFor(unboxedTypeID); |
| dup_x2(); |
| dup_x2(); |
| pop(); |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 3, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangLongConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.LongConstrSignature, |
| unboxedTypeID, |
| TypeBinding.LONG); |
| } |
| break; |
| case TypeIds.T_float : |
| if ( this.targetLevel >= ClassFileConstants.JDK1_5 ) { |
| // invokestatic: Float.valueOf(float) |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangFloatConstantPoolName, |
| ConstantPool.ValueOf, |
| ConstantPool.floatFloatSignature, |
| unboxedTypeID, |
| TypeBinding.FLOAT); |
| } else { |
| // new Float(float) |
| newWrapperFor(unboxedTypeID); |
| dup_x1(); |
| swap(); |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 2, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangFloatConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.FloatConstrSignature, |
| unboxedTypeID, |
| TypeBinding.FLOAT); |
| } |
| break; |
| case TypeIds.T_double : |
| if ( this.targetLevel >= ClassFileConstants.JDK1_5 ) { |
| // invokestatic: Double.valueOf(double) |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 2, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangDoubleConstantPoolName, |
| ConstantPool.ValueOf, |
| ConstantPool.doubleDoubleSignature, |
| unboxedTypeID, |
| TypeBinding.DOUBLE); |
| } else { |
| // new Double( double ) |
| newWrapperFor(unboxedTypeID); |
| dup_x2(); |
| dup_x2(); |
| pop(); |
| |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 3, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangDoubleConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.DoubleConstrSignature, |
| unboxedTypeID, |
| TypeBinding.DOUBLE); |
| } |
| |
| break; |
| case TypeIds.T_boolean : |
| if ( this.targetLevel >= ClassFileConstants.JDK1_5 ) { |
| // invokestatic: Boolean.valueOf(boolean) |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangBooleanConstantPoolName, |
| ConstantPool.ValueOf, |
| ConstantPool.booleanBooleanSignature, |
| unboxedTypeID, |
| TypeBinding.BOOLEAN); |
| } else { |
| // new Boolean(boolean) |
| newWrapperFor(unboxedTypeID); |
| dup_x1(); |
| swap(); |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 2, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangBooleanConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.BooleanConstrSignature, |
| unboxedTypeID, |
| TypeBinding.BOOLEAN); |
| } |
| } |
| } |
| |
| /** |
| * Macro for building a class descriptor object |
| */ |
| public void generateClassLiteralAccessForType(Scope scope, TypeBinding accessedType, FieldBinding syntheticFieldBinding) { |
| if (accessedType.isBaseType() && accessedType != TypeBinding.NULL) { |
| getTYPE(accessedType.id); |
| return; |
| } |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| // generation using the new ldc_w bytecode |
| this.ldc(accessedType); |
| } else { |
| BranchLabel endLabel = new BranchLabel(this); |
| if (syntheticFieldBinding != null) { // non interface case |
| fieldAccess(Opcodes.OPC_getstatic, syntheticFieldBinding, null /* default declaringClass */); |
| dup(); |
| ifnonnull(endLabel); |
| pop(); |
| } |
| |
| /* Macro for building a class descriptor object... using or not a field cache to store it into... |
| this sequence is responsible for building the actual class descriptor. |
| |
| If the fieldCache is set, then it is supposed to be the body of a synthetic access method |
| factoring the actual descriptor creation out of the invocation site (saving space). |
| If the fieldCache is nil, then we are dumping the bytecode on the invocation site, since |
| we have no way to get a hand on the field cache to do better. */ |
| |
| |
| // Wrap the code in an exception handler to convert a ClassNotFoundException into a NoClassDefError |
| |
| ExceptionLabel classNotFoundExceptionHandler = new ExceptionLabel(this, TypeBinding.NULL /*represents ClassNotFoundException*/); |
| classNotFoundExceptionHandler.placeStart(); |
| this.ldc(accessedType == TypeBinding.NULL ? "java.lang.Object" : String.valueOf(accessedType.constantPoolName()).replace('/', '.')); //$NON-NLS-1$ |
| invokeClassForName(); |
| |
| /* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=37565 |
| if (accessedType == BaseTypes.NullBinding) { |
| this.ldc("java.lang.Object"); //$NON-NLS-1$ |
| } else if (accessedType.isArrayType()) { |
| this.ldc(String.valueOf(accessedType.constantPoolName()).replace('/', '.')); |
| } else { |
| // we make it an array type (to avoid class initialization) |
| this.ldc("[L" + String.valueOf(accessedType.constantPoolName()).replace('/', '.') + ";"); //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| this.invokeClassForName(); |
| if (!accessedType.isArrayType()) { // extract the component type, which doesn't initialize the class |
| this.invokeJavaLangClassGetComponentType(); |
| } |
| */ |
| /* We need to protect the runtime code from binary inconsistencies |
| in case the accessedType is missing, the ClassNotFoundException has to be converted |
| into a NoClassDefError(old ex message), we thus need to build an exception handler for this one. */ |
| classNotFoundExceptionHandler.placeEnd(); |
| |
| if (syntheticFieldBinding != null) { // non interface case |
| dup(); |
| fieldAccess(Opcodes.OPC_putstatic, syntheticFieldBinding, null /* default declaringClass */); |
| } |
| goto_(endLabel); |
| |
| int savedStackDepth = this.stackDepth; |
| int switchSaveTypeBindingsStackSize = this.switchSaveTypeBindings.size(); |
| |
| // Generate the body of the exception handler |
| /* ClassNotFoundException on stack -- the class literal could be doing more things |
| on the stack, which means that the stack may not be empty at this point in the |
| above code gen. So we save its state and restart it from 1. */ |
| |
| pushExceptionOnStack(scope.getJavaLangClassNotFoundException()); |
| classNotFoundExceptionHandler.place(); |
| |
| // Transform the current exception, and repush and throw a |
| // NoClassDefFoundError(ClassNotFound.getMessage()) |
| |
| newNoClassDefFoundError(); |
| dup_x1(); |
| this.swap(); |
| |
| // Retrieve the message from the old exception |
| invokeThrowableGetMessage(); |
| |
| // Send the constructor taking a message string as an argument |
| invokeNoClassDefFoundErrorStringConstructor(); |
| athrow(); |
| endLabel.place(); |
| this.stackDepth = savedStackDepth; |
| popTypeBinding(this.switchSaveTypeBindings.size() - switchSaveTypeBindingsStackSize); |
| } |
| } |
| |
| /** |
| * This method generates the code attribute bytecode |
| */ |
| final public void generateCodeAttributeForProblemMethod(String problemMessage) { |
| newJavaLangError(); |
| dup(); |
| ldc(problemMessage); |
| invokeJavaLangErrorConstructor(); |
| athrow(); |
| } |
| |
| public void generateConstant(Constant constant, int implicitConversionCode) { |
| int targetTypeID = (implicitConversionCode & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; |
| if (targetTypeID == 0) targetTypeID = constant.typeID(); // use default constant type |
| switch (targetTypeID) { |
| case TypeIds.T_boolean : |
| generateInlinedValue(constant.booleanValue()); |
| break; |
| case TypeIds.T_char : |
| generateInlinedValue(constant.charValue()); |
| break; |
| case TypeIds.T_byte : |
| generateInlinedValue(constant.byteValue()); |
| break; |
| case TypeIds.T_short : |
| generateInlinedValue(constant.shortValue()); |
| break; |
| case TypeIds.T_int : |
| generateInlinedValue(constant.intValue()); |
| break; |
| case TypeIds.T_long : |
| generateInlinedValue(constant.longValue()); |
| break; |
| case TypeIds.T_float : |
| generateInlinedValue(constant.floatValue()); |
| break; |
| case TypeIds.T_double : |
| generateInlinedValue(constant.doubleValue()); |
| break; |
| case TypeIds.T_JavaLangString : |
| ldc(constant.stringValue()); |
| } |
| if ((implicitConversionCode & TypeIds.BOXING) != 0) { |
| // need boxing |
| generateBoxingConversion(targetTypeID); |
| } |
| } |
| |
| public void generateEmulatedReadAccessForField(FieldBinding fieldBinding) { |
| generateEmulationForField(fieldBinding); |
| // swap the field with the receiver |
| this.swap(); |
| invokeJavaLangReflectFieldGetter(fieldBinding.type); |
| if (!fieldBinding.type.isBaseType()) { |
| this.checkcast(fieldBinding.type); |
| } |
| } |
| |
| public void generateEmulatedWriteAccessForField(FieldBinding fieldBinding) { |
| invokeJavaLangReflectFieldSetter(fieldBinding.type); |
| } |
| |
| public void generateEmulationForConstructor(Scope scope, MethodBinding methodBinding) { |
| // leave a java.lang.reflect.Field object on the stack |
| this.ldc(String.valueOf(methodBinding.declaringClass.constantPoolName()).replace('/', '.')); |
| invokeClassForName(); |
| int paramLength = methodBinding.parameters.length; |
| this.generateInlinedValue(paramLength); |
| newArray(scope.createArrayType(scope.getType(TypeConstants.JAVA_LANG_CLASS, 3), 1)); |
| if (paramLength > 0) { |
| dup(); |
| for (int i = 0; i < paramLength; i++) { |
| this.generateInlinedValue(i); |
| TypeBinding parameter = methodBinding.parameters[i]; |
| if (parameter.isBaseType()) { |
| getTYPE(parameter.id); |
| } else if (parameter.isArrayType()) { |
| ArrayBinding array = (ArrayBinding)parameter; |
| if (array.leafComponentType.isBaseType()) { |
| getTYPE(array.leafComponentType.id); |
| } else { |
| this.ldc(String.valueOf(array.leafComponentType.constantPoolName()).replace('/', '.')); |
| invokeClassForName(); |
| } |
| int dimensions = array.dimensions; |
| this.generateInlinedValue(dimensions); |
| newarray(TypeIds.T_int); |
| invokeArrayNewInstance(); |
| invokeObjectGetClass(); |
| } else { |
| // parameter is a reference binding |
| this.ldc(String.valueOf(methodBinding.declaringClass.constantPoolName()).replace('/', '.')); |
| invokeClassForName(); |
| } |
| aastore(); |
| if (i < paramLength - 1) { |
| dup(); |
| } |
| } |
| } |
| invokeClassGetDeclaredConstructor(); |
| dup(); |
| iconst_1(); |
| invokeAccessibleObjectSetAccessible(); |
| } |
| |
| public void generateEmulationForField(FieldBinding fieldBinding) { |
| // leave a java.lang.reflect.Field object on the stack |
| this.ldc(String.valueOf(fieldBinding.declaringClass.constantPoolName()).replace('/', '.')); |
| invokeClassForName(); |
| this.ldc(String.valueOf(fieldBinding.name)); |
| invokeClassGetDeclaredField(); |
| dup(); |
| iconst_1(); |
| invokeAccessibleObjectSetAccessible(); |
| } |
| |
| public void generateEmulationForMethod(Scope scope, MethodBinding methodBinding) { |
| // leave a java.lang.reflect.Field object on the stack |
| this.ldc(String.valueOf(methodBinding.declaringClass.constantPoolName()).replace('/', '.')); |
| invokeClassForName(); |
| this.ldc(String.valueOf(methodBinding.selector)); |
| int paramLength = methodBinding.parameters.length; |
| this.generateInlinedValue(paramLength); |
| newArray(scope.createArrayType(scope.getType(TypeConstants.JAVA_LANG_CLASS, 3), 1)); |
| if (paramLength > 0) { |
| dup(); |
| for (int i = 0; i < paramLength; i++) { |
| this.generateInlinedValue(i); |
| TypeBinding parameter = methodBinding.parameters[i]; |
| if (parameter.isBaseType()) { |
| getTYPE(parameter.id); |
| } else if (parameter.isArrayType()) { |
| ArrayBinding array = (ArrayBinding)parameter; |
| if (array.leafComponentType.isBaseType()) { |
| getTYPE(array.leafComponentType.id); |
| } else { |
| this.ldc(String.valueOf(array.leafComponentType.constantPoolName()).replace('/', '.')); |
| invokeClassForName(); |
| } |
| int dimensions = array.dimensions; |
| this.generateInlinedValue(dimensions); |
| newarray(TypeIds.T_int); |
| invokeArrayNewInstance(); |
| invokeObjectGetClass(); |
| } else { |
| // parameter is a reference binding |
| this.ldc(String.valueOf(methodBinding.declaringClass.constantPoolName()).replace('/', '.')); |
| invokeClassForName(); |
| } |
| aastore(); |
| if (i < paramLength - 1) { |
| dup(); |
| } |
| } |
| } |
| invokeClassGetDeclaredMethod(); |
| dup(); |
| iconst_1(); |
| invokeAccessibleObjectSetAccessible(); |
| } |
| /** |
| * Generates the sequence of instructions which will perform the conversion of the expression |
| * on the stack into a different type (e.g. long l = someInt; --> i2l must be inserted). |
| * @param implicitConversionCode int |
| */ |
| public void generateImplicitConversion(int implicitConversionCode) { |
| if ((implicitConversionCode & TypeIds.UNBOXING) != 0) { |
| final int typeId = implicitConversionCode & TypeIds.COMPILE_TYPE_MASK; |
| generateUnboxingConversion(typeId); |
| // unboxing can further involve base type conversions |
| } |
| switch (implicitConversionCode & TypeIds.IMPLICIT_CONVERSION_MASK) { |
| case TypeIds.Float2Char : |
| f2i(); |
| i2c(); |
| break; |
| case TypeIds.Double2Char : |
| d2i(); |
| i2c(); |
| break; |
| case TypeIds.Int2Char : |
| case TypeIds.Short2Char : |
| case TypeIds.Byte2Char : |
| i2c(); |
| break; |
| case TypeIds.Long2Char : |
| l2i(); |
| i2c(); |
| break; |
| case TypeIds.Char2Float : |
| case TypeIds.Short2Float : |
| case TypeIds.Int2Float : |
| case TypeIds.Byte2Float : |
| i2f(); |
| break; |
| case TypeIds.Double2Float : |
| d2f(); |
| break; |
| case TypeIds.Long2Float : |
| l2f(); |
| break; |
| case TypeIds.Float2Byte : |
| f2i(); |
| i2b(); |
| break; |
| case TypeIds.Double2Byte : |
| d2i(); |
| i2b(); |
| break; |
| case TypeIds.Int2Byte : |
| case TypeIds.Short2Byte : |
| case TypeIds.Char2Byte : |
| i2b(); |
| break; |
| case TypeIds.Long2Byte : |
| l2i(); |
| i2b(); |
| break; |
| case TypeIds.Byte2Double : |
| case TypeIds.Char2Double : |
| case TypeIds.Short2Double : |
| case TypeIds.Int2Double : |
| i2d(); |
| break; |
| case TypeIds.Float2Double : |
| f2d(); |
| break; |
| case TypeIds.Long2Double : |
| l2d(); |
| break; |
| case TypeIds.Byte2Short : |
| case TypeIds.Char2Short : |
| case TypeIds.Int2Short : |
| i2s(); |
| break; |
| case TypeIds.Double2Short : |
| d2i(); |
| i2s(); |
| break; |
| case TypeIds.Long2Short : |
| l2i(); |
| i2s(); |
| break; |
| case TypeIds.Float2Short : |
| f2i(); |
| i2s(); |
| break; |
| case TypeIds.Double2Int : |
| d2i(); |
| break; |
| case TypeIds.Float2Int : |
| f2i(); |
| break; |
| case TypeIds.Long2Int : |
| l2i(); |
| break; |
| case TypeIds.Int2Long : |
| case TypeIds.Char2Long : |
| case TypeIds.Byte2Long : |
| case TypeIds.Short2Long : |
| i2l(); |
| break; |
| case TypeIds.Double2Long : |
| d2l(); |
| break; |
| case TypeIds.Float2Long : |
| f2l(); |
| break; |
| case TypeIds.Object2boolean: |
| case TypeIds.Object2byte: |
| case TypeIds.Object2short: |
| case TypeIds.Object2int: |
| case TypeIds.Object2long: |
| case TypeIds.Object2float: |
| case TypeIds.Object2char: |
| case TypeIds.Object2double: |
| // see table 5.1 in JLS S5.5 |
| // an Object to x conversion should have a check cast |
| // and an unboxing conversion. |
| int runtimeType = (implicitConversionCode & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; |
| checkcast(runtimeType); |
| generateUnboxingConversion(runtimeType); |
| break; |
| } |
| if ((implicitConversionCode & TypeIds.BOXING) != 0) { |
| // need to unbox/box the constant |
| final int typeId = (implicitConversionCode & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; |
| generateBoxingConversion(typeId); |
| } |
| } |
| |
| public void generateInlinedValue(boolean inlinedValue) { |
| if (inlinedValue) |
| iconst_1(); |
| else |
| iconst_0(); |
| } |
| |
| public void generateInlinedValue(byte inlinedValue) { |
| switch (inlinedValue) { |
| case -1 : |
| iconst_m1(); |
| break; |
| case 0 : |
| iconst_0(); |
| break; |
| case 1 : |
| iconst_1(); |
| break; |
| case 2 : |
| iconst_2(); |
| break; |
| case 3 : |
| iconst_3(); |
| break; |
| case 4 : |
| iconst_4(); |
| break; |
| case 5 : |
| iconst_5(); |
| break; |
| default : |
| if ((-128 <= inlinedValue) && (inlinedValue <= 127)) { |
| bipush(inlinedValue); |
| return; |
| } |
| } |
| } |
| |
| public void generateInlinedValue(char inlinedValue) { |
| switch (inlinedValue) { |
| case 0 : |
| iconst_0(); |
| break; |
| case 1 : |
| iconst_1(); |
| break; |
| case 2 : |
| iconst_2(); |
| break; |
| case 3 : |
| iconst_3(); |
| break; |
| case 4 : |
| iconst_4(); |
| break; |
| case 5 : |
| iconst_5(); |
| break; |
| default : |
| if ((6 <= inlinedValue) && (inlinedValue <= 127)) { |
| bipush((byte) inlinedValue); |
| return; |
| } |
| if ((128 <= inlinedValue) && (inlinedValue <= 32767)) { |
| sipush(inlinedValue); |
| return; |
| } |
| this.ldc(inlinedValue); |
| } |
| } |
| |
| public void generateInlinedValue(double inlinedValue) { |
| if (inlinedValue == 0.0) { |
| if (Double.doubleToLongBits(inlinedValue) != 0L) |
| this.ldc2_w(inlinedValue); |
| else |
| dconst_0(); |
| return; |
| } |
| if (inlinedValue == 1.0) { |
| dconst_1(); |
| return; |
| } |
| this.ldc2_w(inlinedValue); |
| } |
| |
| public void generateInlinedValue(float inlinedValue) { |
| if (inlinedValue == 0.0f) { |
| if (Float.floatToIntBits(inlinedValue) != 0) |
| this.ldc(inlinedValue); |
| else |
| fconst_0(); |
| return; |
| } |
| if (inlinedValue == 1.0f) { |
| fconst_1(); |
| return; |
| } |
| if (inlinedValue == 2.0f) { |
| fconst_2(); |
| return; |
| } |
| this.ldc(inlinedValue); |
| } |
| |
| public void generateInlinedValue(int inlinedValue) { |
| switch (inlinedValue) { |
| case -1 : |
| iconst_m1(); |
| break; |
| case 0 : |
| iconst_0(); |
| break; |
| case 1 : |
| iconst_1(); |
| break; |
| case 2 : |
| iconst_2(); |
| break; |
| case 3 : |
| iconst_3(); |
| break; |
| case 4 : |
| iconst_4(); |
| break; |
| case 5 : |
| iconst_5(); |
| break; |
| default : |
| if ((-128 <= inlinedValue) && (inlinedValue <= 127)) { |
| bipush((byte) inlinedValue); |
| return; |
| } |
| if ((-32768 <= inlinedValue) && (inlinedValue <= 32767)) { |
| sipush(inlinedValue); |
| return; |
| } |
| this.ldc(inlinedValue); |
| } |
| } |
| |
| public void generateInlinedValue(long inlinedValue) { |
| if (inlinedValue == 0) { |
| lconst_0(); |
| return; |
| } |
| if (inlinedValue == 1) { |
| lconst_1(); |
| return; |
| } |
| this.ldc2_w(inlinedValue); |
| } |
| |
| public void generateInlinedValue(short inlinedValue) { |
| switch (inlinedValue) { |
| case -1 : |
| iconst_m1(); |
| break; |
| case 0 : |
| iconst_0(); |
| break; |
| case 1 : |
| iconst_1(); |
| break; |
| case 2 : |
| iconst_2(); |
| break; |
| case 3 : |
| iconst_3(); |
| break; |
| case 4 : |
| iconst_4(); |
| break; |
| case 5 : |
| iconst_5(); |
| break; |
| default : |
| if ((-128 <= inlinedValue) && (inlinedValue <= 127)) { |
| bipush((byte) inlinedValue); |
| return; |
| } |
| sipush(inlinedValue); |
| } |
| } |
| |
| public void generateOuterAccess(Object[] mappingSequence, ASTNode invocationSite, Binding target, Scope scope) { |
| if (mappingSequence == null) { |
| if (target instanceof LocalVariableBinding) { |
| scope.problemReporter().needImplementation(invocationSite); //TODO (philippe) should improve local emulation failure reporting |
| } else { |
| scope.problemReporter().noSuchEnclosingInstance((ReferenceBinding)target, invocationSite, false); |
| } |
| return; |
| } |
| if (mappingSequence == BlockScope.NoEnclosingInstanceInConstructorCall) { |
| scope.problemReporter().noSuchEnclosingInstance((ReferenceBinding)target, invocationSite, true); |
| return; |
| } else if (mappingSequence == BlockScope.NoEnclosingInstanceInStaticContext) { |
| scope.problemReporter().noSuchEnclosingInstance((ReferenceBinding)target, invocationSite, false); |
| return; |
| } |
| |
| if (mappingSequence == BlockScope.EmulationPathToImplicitThis) { |
| aload_0(); |
| return; |
| } else if (mappingSequence[0] instanceof FieldBinding) { |
| FieldBinding fieldBinding = (FieldBinding) mappingSequence[0]; |
| aload_0(); |
| fieldAccess(Opcodes.OPC_getfield, fieldBinding, null /* default declaringClass */); |
| } else { |
| load((LocalVariableBinding) mappingSequence[0]); |
| } |
| for (int i = 1, length = mappingSequence.length; i < length; i++) { |
| if (mappingSequence[i] instanceof FieldBinding) { |
| FieldBinding fieldBinding = (FieldBinding) mappingSequence[i]; |
| fieldAccess(Opcodes.OPC_getfield, fieldBinding, null /* default declaringClass */); |
| } else { |
| invoke(Opcodes.OPC_invokestatic, (MethodBinding) mappingSequence[i], null /* default declaringClass */); |
| } |
| } |
| } |
| |
| public void generateReturnBytecode(Expression expression) { |
| if (expression == null) { |
| return_(); |
| } else { |
| final int implicitConversion = expression.implicitConversion; |
| if ((implicitConversion & TypeIds.BOXING) != 0) { |
| areturn(); |
| return; |
| } |
| int runtimeType = (implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; |
| switch (runtimeType) { |
| case TypeIds.T_boolean : |
| case TypeIds.T_int : |
| ireturn(); |
| break; |
| case TypeIds.T_float : |
| freturn(); |
| break; |
| case TypeIds.T_long : |
| lreturn(); |
| break; |
| case TypeIds.T_double : |
| dreturn(); |
| break; |
| default : |
| areturn(); |
| } |
| } |
| } |
| |
| /** |
| * The equivalent code performs a string conversion: |
| * |
| * @param blockScope the given blockScope |
| * @param oper1 the first expression |
| * @param oper2 the second expression |
| */ |
| public void generateStringConcatenationAppend(BlockScope blockScope, Expression oper1, Expression oper2) { |
| int pc; |
| if (oper1 == null) { |
| /* Operand is already on the stack, and maybe nil: |
| note type1 is always to java.lang.String here.*/ |
| newStringContatenation(); |
| dup_x1(); |
| this.swap(); |
| // If argument is reference type, need to transform it |
| // into a string (handles null case) |
| invokeStringValueOf(TypeIds.T_JavaLangObject); |
| invokeStringConcatenationStringConstructor(); |
| } else { |
| pc = this.position; |
| oper1.generateOptimizedStringConcatenationCreation(blockScope, this, oper1.implicitConversion & TypeIds.COMPILE_TYPE_MASK); |
| this.recordPositionsFrom(pc, oper1.sourceStart); |
| } |
| pc = this.position; |
| oper2.generateOptimizedStringConcatenation(blockScope, this, oper2.implicitConversion & TypeIds.COMPILE_TYPE_MASK); |
| this.recordPositionsFrom(pc, oper2.sourceStart); |
| invokeStringConcatenationToString(); |
| } |
| |
| /** |
| * @param accessBinding the access method binding to generate |
| */ |
| public void generateSyntheticBodyForConstructorAccess(SyntheticMethodBinding accessBinding) { |
| initializeMaxLocals(accessBinding); |
| MethodBinding constructorBinding = accessBinding.targetMethod; |
| TypeBinding[] parameters = constructorBinding.parameters; |
| int length = parameters.length; |
| int resolvedPosition = 1; |
| aload_0(); |
| // special name&ordinal argument generation for enum constructors |
| TypeBinding declaringClass = constructorBinding.declaringClass; |
| if (declaringClass.erasure().id == TypeIds.T_JavaLangEnum || declaringClass.isEnum()) { |
| aload_1(); // pass along name param as name arg |
| iload_2(); // pass along ordinal param as ordinal arg |
| resolvedPosition += 2; |
| } |
| if (declaringClass.isNestedType()) { |
| NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass; |
| SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticEnclosingInstances(); |
| for (int i = 0; i < (syntheticArguments == null ? 0 : syntheticArguments.length); i++) { |
| TypeBinding type; |
| load((type = syntheticArguments[i].type), resolvedPosition); |
| switch(type.id) { |
| case TypeIds.T_long : |
| case TypeIds.T_double : |
| resolvedPosition += 2; |
| break; |
| default : |
| resolvedPosition++; |
| break; |
| } |
| } |
| } |
| for (int i = 0; i < length; i++) { |
| TypeBinding parameter; |
| load(parameter = parameters[i], resolvedPosition); |
| switch(parameter.id) { |
| case TypeIds.T_long : |
| case TypeIds.T_double : |
| resolvedPosition += 2; |
| break; |
| default : |
| resolvedPosition++; |
| break; |
| } |
| } |
| |
| if (declaringClass.isNestedType()) { |
| NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass; |
| SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticOuterLocalVariables(); |
| for (int i = 0; i < (syntheticArguments == null ? 0 : syntheticArguments.length); i++) { |
| TypeBinding type; |
| load(type = syntheticArguments[i].type, resolvedPosition); |
| switch(type.id) { |
| case TypeIds.T_long : |
| case TypeIds.T_double : |
| resolvedPosition += 2; |
| break; |
| default : |
| resolvedPosition++; |
| break; |
| } |
| } |
| } |
| invoke(Opcodes.OPC_invokespecial, constructorBinding, null /* default declaringClass */); |
| return_(); |
| } |
| public void generateSyntheticBodyForArrayConstructor(SyntheticMethodBinding methodBinding) { |
| initializeMaxLocals(methodBinding); |
| iload_0(); |
| newArray(null, null, (ArrayBinding) methodBinding.returnType); |
| areturn(); |
| } |
| public void generateSyntheticBodyForArrayClone(SyntheticMethodBinding methodBinding) { |
| initializeMaxLocals(methodBinding); |
| TypeBinding arrayType = methodBinding.parameters[0]; |
| aload_0(); |
| invoke( // // invokevirtual: "[I".clone:()Ljava/lang/Object; |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| arrayType.signature(), // declaring class e.g "[I" |
| ConstantPool.Clone, |
| ConstantPool.CloneSignature, |
| getPopularBinding(ConstantPool.JavaLangObjectConstantPoolName)); |
| checkcast(arrayType); |
| areturn(); |
| } |
| public void generateSyntheticBodyForFactoryMethod(SyntheticMethodBinding methodBinding) { |
| initializeMaxLocals(methodBinding); |
| MethodBinding constructorBinding = methodBinding.targetMethod; |
| TypeBinding[] parameters = methodBinding.parameters; |
| int length = parameters.length; |
| |
| new_(constructorBinding.declaringClass); |
| dup(); |
| |
| int resolvedPosition = 0; |
| for (int i = 0; i < length; i++) { |
| TypeBinding parameter; |
| load(parameter = parameters[i], resolvedPosition); |
| switch(parameter.id) { |
| case TypeIds.T_long : |
| case TypeIds.T_double : |
| resolvedPosition += 2; |
| break; |
| default : |
| resolvedPosition++; |
| break; |
| } |
| } |
| for (int i = 0; i < methodBinding.fakePaddedParameters; i++) |
| aconst_null(); |
| |
| invoke(Opcodes.OPC_invokespecial, constructorBinding, null /* default declaringClass */); |
| areturn(); |
| } |
| //static X valueOf(String name) { |
| // return (X) Enum.valueOf(X.class, name); |
| //} |
| public void generateSyntheticBodyForEnumValueOf(SyntheticMethodBinding methodBinding) { |
| initializeMaxLocals(methodBinding); |
| final ReferenceBinding declaringClass = methodBinding.declaringClass; |
| generateClassLiteralAccessForType(((SourceTypeBinding) methodBinding.declaringClass).scope, declaringClass, null); |
| aload_0(); |
| invokeJavaLangEnumvalueOf(declaringClass); |
| this.checkcast(declaringClass); |
| areturn(); |
| } |
| |
| // TODO what about blowing the method limit? Ignore for now? |
| /** |
| * This is intended to match what javac generates. First there is a switch statement on the hashcode of the lambda method name - based on that |
| * an id is computed (0..N). An unrecognized hash gets the id -1. Then a second switch is on the id and each case here checks all the properties |
| * of the serialized lambda. If they all checkout OK an invokedynamic call to a bootstrap method targeting the altMetafactory. If any of the tests |
| * fail an IllegalArgumentException is thrown. This exception is not typically seen by the 'user', instead they seem to see a NPE when |
| * the lambda does not deserialize properly. |
| */ |
| public void generateSyntheticBodyForDeserializeLambda(SyntheticMethodBinding methodBinding,SyntheticMethodBinding[] syntheticMethodBindings) { |
| initializeMaxLocals(methodBinding); |
| |
| // Compute a map of hashcodes to a list of synthetic methods whose names share a hashcode |
| Map hashcodesTosynthetics = new LinkedHashMap(); |
| for (int i=0,max=syntheticMethodBindings.length;i<max;i++) { |
| SyntheticMethodBinding syntheticMethodBinding = syntheticMethodBindings[i]; |
| if (syntheticMethodBinding.lambda!=null && syntheticMethodBinding.lambda.isSerializable || |
| syntheticMethodBinding.serializableMethodRef != null) { |
| // TODO can I use > Java 1.4 features here? |
| Integer hashcode = Integer.valueOf(new String(syntheticMethodBinding.selector).hashCode()); |
| List syntheticssForThisHashcode = (List)hashcodesTosynthetics.get(hashcode); |
| if (syntheticssForThisHashcode==null) { |
| syntheticssForThisHashcode = new ArrayList(); |
| hashcodesTosynthetics.put(hashcode,syntheticssForThisHashcode); |
| } |
| syntheticssForThisHashcode.add(syntheticMethodBinding); |
| } |
| } |
| ClassScope scope = ((SourceTypeBinding)methodBinding.declaringClass).scope; |
| |
| // Generate the first switch, on method name hashcode |
| aload_0(); |
| invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName, ConstantPool.GetImplMethodName, ConstantPool.GetImplMethodNameSignature, |
| getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| astore_1(); |
| LocalVariableBinding lvb1 = new LocalVariableBinding("hashcode".toCharArray(),scope.getJavaLangString(),0,false); //$NON-NLS-1$ |
| lvb1.resolvedPosition = 1; |
| addVariable(lvb1); |
| iconst_m1(); |
| istore_2(); |
| LocalVariableBinding lvb2 = new LocalVariableBinding("id".toCharArray(),TypeBinding.INT,0,false); //$NON-NLS-1$ |
| lvb2.resolvedPosition = 2; |
| addVariable(lvb2); |
| aload_1(); |
| invokeStringHashCode(); |
| |
| BranchLabel label = new BranchLabel(this); |
| CaseLabel defaultLabel = new CaseLabel(this); |
| int numberOfHashcodes = hashcodesTosynthetics.size(); |
| CaseLabel[] switchLabels = new CaseLabel[numberOfHashcodes]; |
| int[] keys = new int[numberOfHashcodes]; |
| int[] sortedIndexes = new int[numberOfHashcodes]; |
| Set hashcodes = hashcodesTosynthetics.keySet(); |
| Iterator hashcodeIterator = hashcodes.iterator(); |
| int index=0; |
| while (hashcodeIterator.hasNext()) { |
| Integer hashcode = (Integer)hashcodeIterator.next(); |
| switchLabels[index] = new CaseLabel(this); |
| keys[index] = hashcode.intValue(); |
| sortedIndexes[index] = index; |
| index++; |
| } |
| int[] localKeysCopy; |
| System.arraycopy(keys,0,(localKeysCopy = new int[numberOfHashcodes]),0,numberOfHashcodes); |
| sort(localKeysCopy, 0, numberOfHashcodes-1, sortedIndexes); |
| // TODO need to use a tableswitch at some size threshold? |
| lookupswitch(defaultLabel, keys, sortedIndexes, switchLabels); |
| // TODO cope with multiple names that share the same hashcode |
| hashcodeIterator = hashcodes.iterator(); |
| index = 0; |
| while (hashcodeIterator.hasNext()) { |
| Integer hashcode = (Integer)hashcodeIterator.next(); |
| List synthetics = (List)hashcodesTosynthetics.get(hashcode); |
| switchLabels[index].place(); |
| BranchLabel nextOne = new BranchLabel(this); |
| // Loop through all lambdas that share the same hashcode |
| // TODO: isn't doing this for just one of these enough because they all share |
| // the same name? |
| for (int j=0,max=synthetics.size();j<max;j++) { |
| SyntheticMethodBinding syntheticMethodBinding = (SyntheticMethodBinding)synthetics.get(j); |
| aload_1(); |
| ldc(new String(syntheticMethodBinding.selector)); |
| invokeStringEquals(); |
| ifeq(nextOne); |
| loadInt(index); |
| istore_2(); |
| goto_(label); |
| nextOne.place(); |
| nextOne = new BranchLabel(this); |
| } |
| index++; |
| goto_(label); |
| } |
| defaultLabel.place(); |
| label.place(); |
| int syntheticsCount = hashcodes.size(); |
| // Second block is switching on the lambda id, -1 is the error (unrecognized) case |
| switchLabels = new CaseLabel[syntheticsCount]; |
| keys = new int[syntheticsCount]; |
| sortedIndexes = new int[syntheticsCount]; |
| BranchLabel errorLabel = new BranchLabel(this); |
| defaultLabel = new CaseLabel(this); |
| iload_2(); |
| for (int j=0;j<syntheticsCount;j++) { |
| switchLabels[j] = new CaseLabel(this); |
| keys[j] = j; |
| sortedIndexes[j] = j; |
| } |
| System.arraycopy(keys,0,(localKeysCopy = new int[syntheticsCount]),0,syntheticsCount); |
| // TODO no need to sort here? They should all be in order |
| sort(localKeysCopy, 0, syntheticsCount-1, sortedIndexes); |
| // TODO need to use a tableswitch at some size threshold? |
| lookupswitch(defaultLabel, keys, sortedIndexes, switchLabels); |
| hashcodeIterator = hashcodes.iterator(); |
| int hashcodeIndex = 0; |
| while (hashcodeIterator.hasNext()) { |
| Integer hashcode = (Integer)hashcodeIterator.next(); |
| List synthetics = (List)hashcodesTosynthetics.get(hashcode); |
| switchLabels[hashcodeIndex++].place(); |
| BranchLabel nextOne = synthetics.size() > 1 ? new BranchLabel(this) : errorLabel; |
| // Loop through all lambdas that share the same hashcode |
| for (int j = 0, count = synthetics.size(); j < count; j++) { |
| SyntheticMethodBinding syntheticMethodBinding = (SyntheticMethodBinding) synthetics.get(j); |
| // Compare ImplMethodKind |
| aload_0(); |
| FunctionalExpression funcEx = syntheticMethodBinding.lambda != null ? syntheticMethodBinding.lambda |
| : syntheticMethodBinding.serializableMethodRef; |
| MethodBinding mb = funcEx.binding; |
| invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName, |
| ConstantPool.GetImplMethodKind, ConstantPool.GetImplMethodKindSignature, TypeIds.T_int, |
| TypeBinding.INT); |
| byte methodKind = 0; |
| if (mb.isStatic()) { |
| methodKind = ClassFileConstants.MethodHandleRefKindInvokeStatic; |
| } else if (mb.isPrivate()) { |
| methodKind = ClassFileConstants.MethodHandleRefKindInvokeSpecial; |
| } else if (mb.isConstructor()) { |
| methodKind = ClassFileConstants.MethodHandleRefKindNewInvokeSpecial; |
| } else if (mb.declaringClass.isInterface()) { |
| methodKind = ClassFileConstants.MethodHandleRefKindInvokeInterface; |
| } else { |
| methodKind = ClassFileConstants.MethodHandleRefKindInvokeVirtual; |
| } |
| bipush(methodKind);// TODO see table below |
| if_icmpne(nextOne); |
| |
| // Compare FunctionalInterfaceClass |
| aload_0(); |
| invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName, |
| ConstantPool.GetFunctionalInterfaceClass, ConstantPool.GetFunctionalInterfaceClassSignature, |
| getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| String functionalInterface = null; |
| final TypeBinding expectedType = funcEx.expectedType(); |
| if (expectedType instanceof IntersectionTypeBinding18) { |
| functionalInterface = new String( |
| ((IntersectionTypeBinding18) expectedType).getSAMType(scope).constantPoolName()); |
| } else { |
| functionalInterface = new String(expectedType.constantPoolName()); |
| } |
| ldc(functionalInterface);// e.g. "com/foo/X$Foo" |
| invokeObjectEquals(); |
| ifeq(nextOne); |
| |
| // Compare FunctionalInterfaceMethodName |
| aload_0(); |
| invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName, |
| ConstantPool.GetFunctionalInterfaceMethodName, |
| ConstantPool.GetFunctionalInterfaceMethodNameSignature, |
| getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| ldc(new String(funcEx.descriptor.selector)); // e.g. "m" |
| invokeObjectEquals(); |
| ifeq(nextOne); |
| |
| // Compare FunctionalInterfaceMethodSignature |
| aload_0(); |
| invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName, |
| ConstantPool.GetFunctionalInterfaceMethodSignature, |
| ConstantPool.GetFunctionalInterfaceMethodSignatureSignature, |
| getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| ldc(new String(funcEx.descriptor.original().signature())); // e.g "()I" |
| invokeObjectEquals(); |
| ifeq(nextOne); |
| |
| // Compare ImplClass |
| aload_0(); |
| invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName, |
| ConstantPool.GetImplClass, ConstantPool.GetImplClassSignature, |
| getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| ldc(new String(mb.declaringClass.constantPoolName())); // e.g. "com/foo/X" |
| invokeObjectEquals(); |
| ifeq(nextOne); |
| |
| // Compare ImplMethodSignature |
| aload_0(); |
| invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName, |
| ConstantPool.GetImplMethodSignature, ConstantPool.GetImplMethodSignatureSignature, |
| getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| ldc(new String(mb.signature())); // e.g. "(I)I" |
| invokeObjectEquals(); |
| ifeq(nextOne); |
| |
| // Captured arguments |
| StringBuilder sig = new StringBuilder("("); //$NON-NLS-1$ |
| index = 0; |
| boolean isLambda = funcEx instanceof LambdaExpression; |
| TypeBinding receiverType = null; |
| SyntheticArgumentBinding[] outerLocalVariables = null; |
| if (isLambda) { |
| LambdaExpression lambdaEx = (LambdaExpression) funcEx; |
| if (lambdaEx.shouldCaptureInstance) |
| receiverType = mb.declaringClass; |
| outerLocalVariables = lambdaEx.outerLocalVariables; |
| } else { |
| ReferenceExpression refEx = (ReferenceExpression)funcEx; |
| if (refEx.haveReceiver) |
| receiverType = ((ReferenceExpression)funcEx).receiverType; |
| // Should never have outer locals |
| } |
| if (receiverType != null) { |
| aload_0(); |
| loadInt(index++); |
| invoke(Opcodes.OPC_invokevirtual, 1, 1, |
| ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName, |
| ConstantPool.GetCapturedArg, ConstantPool.GetCapturedArgSignature, |
| getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| checkcast(receiverType); |
| sig.append(receiverType.signature()); |
| } |
| for (int p = 0, max = outerLocalVariables == null ? 0 : outerLocalVariables.length; p < max; p++) { |
| TypeBinding varType = outerLocalVariables[p].type; |
| aload_0(); |
| loadInt(index); |
| invoke(Opcodes.OPC_invokevirtual, 1, 1, |
| ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName, |
| ConstantPool.GetCapturedArg, ConstantPool.GetCapturedArgSignature, |
| getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| if (varType.isBaseType()) { |
| checkcast(scope.boxing(varType)); |
| generateUnboxingConversion(varType.id); |
| if (varType.id == TypeIds.T_JavaLangLong || varType.id == TypeIds.T_JavaLangDouble) { |
| index++; |
| } |
| } else { |
| checkcast(varType); |
| } |
| index++; |
| sig.append(varType.signature()); |
| } |
| sig.append(")"); //$NON-NLS-1$ |
| if (funcEx.resolvedType instanceof IntersectionTypeBinding18) { |
| sig.append(((IntersectionTypeBinding18) funcEx.resolvedType).getSAMType(scope).signature()); |
| } else { |
| sig.append(funcEx.resolvedType.signature()); |
| } |
| // Example: invokeDynamic(0, 0, 1, "m".toCharArray(), "()Lcom/foo/X$Foo;".toCharArray()); |
| invokeDynamic(funcEx.bootstrapMethodNumber, index, 1, funcEx.descriptor.selector, |
| sig.toString().toCharArray(), funcEx.resolvedType.id, funcEx.resolvedType); |
| areturn(); |
| if (j < count - 1) { |
| nextOne.place(); |
| nextOne = j < count - 2 ? new BranchLabel(this) : errorLabel; |
| } |
| } |
| } |
| |
| removeVariable(lvb1); |
| removeVariable(lvb2); |
| defaultLabel.place(); |
| errorLabel.place(); |
| // Code: throw new IllegalArgumentException("Invalid lambda deserialization") |
| new_(scope.getJavaLangIllegalArgumentException()); |
| dup(); |
| ldc("Invalid lambda deserialization"); //$NON-NLS-1$ // TODO into a constant? |
| // invokespecial: java.lang.IllegalArgumentException.<init>(Ljava/lang/String;)V |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 2, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangIllegalArgumentExceptionConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.IllegalArgumentExceptionConstructorSignature, |
| null); |
| athrow(); |
| } |
| |
| /** |
| * Based on the supplied value add the most efficient load instruction to the code stream for that value. |
| * Note: Does not handle negative values. |
| */ |
| public void loadInt(int value) { |
| if (value<6) { |
| if (value==0) { |
| iconst_0(); |
| } else if (value==1) { |
| iconst_1(); |
| } else if (value==2) { |
| iconst_2(); |
| } else if (value==3) { |
| iconst_3(); |
| } else if (value==4) { |
| iconst_4(); |
| } else if (value==5) { |
| iconst_5(); |
| } |
| } else if (value < 128) { |
| // TODO [andy] testcases that hit this |
| bipush((byte)value); |
| } else { |
| // TODO [andy] testcases that hit this, yikes |
| ldc(value); |
| } |
| } |
| |
| //static X[] values() { |
| // X[] values; |
| // int length; |
| // X[] result; |
| // System.arraycopy(values = $VALUES, 0, result = new X[length= values.length], 0, length) |
| // return result; |
| //} |
| public void generateSyntheticBodyForEnumValues(SyntheticMethodBinding methodBinding) { |
| ClassScope scope = ((SourceTypeBinding)methodBinding.declaringClass).scope; |
| initializeMaxLocals(methodBinding); |
| TypeBinding enumArray = methodBinding.returnType; |
| fieldAccess(Opcodes.OPC_getstatic, scope.referenceContext.enumValuesSyntheticfield, null /* default declaringClass */); |
| dup(); |
| astore_0(); |
| iconst_0(); |
| aload_0(); |
| arraylength(); |
| dup(); |
| istore_1(); |
| newArray((ArrayBinding) enumArray); |
| dup(); |
| astore_2(); |
| iconst_0(); |
| iload_1(); |
| invokeSystemArraycopy(); |
| aload_2(); |
| areturn(); |
| } |
| public void generateSyntheticBodyForEnumInitializationMethod(SyntheticMethodBinding methodBinding) { |
| // no local used |
| this.maxLocals = 0; |
| // generate all enum constants |
| SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) methodBinding.declaringClass; |
| TypeDeclaration typeDeclaration = sourceTypeBinding.scope.referenceContext; |
| BlockScope staticInitializerScope = typeDeclaration.staticInitializerScope; |
| FieldDeclaration[] fieldDeclarations = typeDeclaration.fields; |
| for (int i = methodBinding.startIndex, max = methodBinding.endIndex; i < max; i++) { |
| FieldDeclaration fieldDecl = fieldDeclarations[i]; |
| if (fieldDecl.isStatic()) { |
| if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) { |
| fieldDecl.generateCode(staticInitializerScope, this); |
| } |
| } |
| } |
| return_(); |
| } |
| public void generateSyntheticBodyForFieldReadAccess(SyntheticMethodBinding accessMethod) { |
| initializeMaxLocals(accessMethod); |
| FieldBinding fieldBinding = accessMethod.targetReadField; |
| // target method declaring class may not be accessible (247953); |
| TypeBinding declaringClass = accessMethod.purpose == SyntheticMethodBinding.SuperFieldReadAccess |
| ? accessMethod.declaringClass.superclass() |
| : accessMethod.declaringClass; |
| if (fieldBinding.isStatic()) { |
| fieldAccess(Opcodes.OPC_getstatic, fieldBinding, declaringClass); |
| } else { |
| aload_0(); |
| fieldAccess(Opcodes.OPC_getfield, fieldBinding, declaringClass); |
| } |
| switch (fieldBinding.type.id) { |
| // case T_void : |
| // this.return_(); |
| // break; |
| case TypeIds.T_boolean : |
| case TypeIds.T_byte : |
| case TypeIds.T_char : |
| case TypeIds.T_short : |
| case TypeIds.T_int : |
| ireturn(); |
| break; |
| case TypeIds.T_long : |
| lreturn(); |
| break; |
| case TypeIds.T_float : |
| freturn(); |
| break; |
| case TypeIds.T_double : |
| dreturn(); |
| break; |
| default : |
| areturn(); |
| } |
| } |
| |
| public void generateSyntheticBodyForFieldWriteAccess(SyntheticMethodBinding accessMethod) { |
| initializeMaxLocals(accessMethod); |
| FieldBinding fieldBinding = accessMethod.targetWriteField; |
| // target method declaring class may not be accessible (247953); |
| TypeBinding declaringClass = accessMethod.purpose == SyntheticMethodBinding.SuperFieldWriteAccess |
| ? accessMethod.declaringClass.superclass() |
| : accessMethod.declaringClass; |
| if (fieldBinding.isStatic()) { |
| load(fieldBinding.type, 0); |
| fieldAccess(Opcodes.OPC_putstatic, fieldBinding, declaringClass); |
| } else { |
| aload_0(); |
| load(fieldBinding.type, 1); |
| fieldAccess(Opcodes.OPC_putfield, fieldBinding, declaringClass); |
| } |
| return_(); |
| } |
| |
| public void generateSyntheticBodyForMethodAccess(SyntheticMethodBinding accessMethod) { |
| initializeMaxLocals(accessMethod); |
| MethodBinding targetMethod = accessMethod.targetMethod; |
| TypeBinding[] parameters = targetMethod.parameters; |
| int length = parameters.length; |
| TypeBinding[] arguments = accessMethod.purpose == SyntheticMethodBinding.BridgeMethod |
| ? accessMethod.parameters |
| : null; |
| int resolvedPosition; |
| if (targetMethod.isStatic()) |
| resolvedPosition = 0; |
| else { |
| aload_0(); |
| resolvedPosition = 1; |
| } |
| for (int i = 0; i < length; i++) { |
| TypeBinding parameter = parameters[i]; |
| if (arguments != null) { // for bridge methods |
| TypeBinding argument = arguments[i]; |
| load(argument, resolvedPosition); |
| if (TypeBinding.notEquals(argument, parameter)) |
| checkcast(parameter); |
| } else { |
| load(parameter, resolvedPosition); |
| } |
| switch(parameter.id) { |
| case TypeIds.T_long : |
| case TypeIds.T_double : |
| resolvedPosition += 2; |
| break; |
| default : |
| resolvedPosition++; |
| break; |
| } |
| } |
| if (targetMethod.isStatic()) |
| invoke(Opcodes.OPC_invokestatic, targetMethod, accessMethod.declaringClass); // target method declaring class may not be accessible (128563) |
| else { |
| if (targetMethod.isConstructor() |
| || targetMethod.isPrivate() |
| // qualified super "X.super.foo()" targets methods from superclass |
| || accessMethod.purpose == SyntheticMethodBinding.SuperMethodAccess){ |
| // target method declaring class may not be accessible (247953); |
| TypeBinding declaringClass = accessMethod.purpose == SyntheticMethodBinding.SuperMethodAccess |
| ? findDirectSuperTypeTowards(accessMethod, targetMethod) |
| : accessMethod.declaringClass; |
| invoke(Opcodes.OPC_invokespecial, targetMethod, declaringClass); |
| } else { |
| if (targetMethod.declaringClass.isInterface()) { // interface or annotation type |
| invoke(Opcodes.OPC_invokeinterface, targetMethod, null /* default declaringClass */); |
| } else { |
| invoke(Opcodes.OPC_invokevirtual, targetMethod, accessMethod.declaringClass); // target method declaring class may not be accessible (128563) |
| } |
| } |
| } |
| switch (targetMethod.returnType.id) { |
| case TypeIds.T_void : |
| return_(); |
| break; |
| case TypeIds.T_boolean : |
| case TypeIds.T_byte : |
| case TypeIds.T_char : |
| case TypeIds.T_short : |
| case TypeIds.T_int : |
| ireturn(); |
| break; |
| case TypeIds.T_long : |
| lreturn(); |
| break; |
| case TypeIds.T_float : |
| freturn(); |
| break; |
| case TypeIds.T_double : |
| dreturn(); |
| break; |
| default : |
| TypeBinding accessErasure = accessMethod.returnType.erasure(); |
| TypeBinding match = targetMethod.returnType.findSuperTypeOriginatingFrom(accessErasure); |
| if (match == null) { |
| this.checkcast(accessErasure); // for bridge methods |
| } |
| areturn(); |
| } |
| } |
| /** When generating SuperMetodAccess towards targetMethod, |
| * find the suitable direct super type, that will eventually lead to targetMethod.declaringClass.*/ |
| ReferenceBinding findDirectSuperTypeTowards(SyntheticMethodBinding accessMethod, MethodBinding targetMethod) { |
| ReferenceBinding currentType = accessMethod.declaringClass; |
| ReferenceBinding superclass = currentType.superclass(); |
| if (targetMethod.isDefaultMethod()) { |
| // could be inherited via superclass *or* a super interface |
| ReferenceBinding targetType = targetMethod.declaringClass; |
| if (superclass.isCompatibleWith(targetType)) |
| return superclass; |
| ReferenceBinding[] superInterfaces = currentType.superInterfaces(); |
| if (superInterfaces != null) { |
| for (int i = 0; i < superInterfaces.length; i++) { |
| ReferenceBinding superIfc = superInterfaces[i]; |
| if (superIfc.isCompatibleWith(targetType)) |
| return superIfc; |
| } |
| } |
| throw new RuntimeException("Assumption violated: some super type must be conform to the declaring class of a super method"); //$NON-NLS-1$ |
| } else { |
| // only one path possible: |
| return superclass; |
| } |
| } |
| |
| public void generateSyntheticBodyForSwitchTable(SyntheticMethodBinding methodBinding) { |
| ClassScope scope = ((SourceTypeBinding)methodBinding.declaringClass).scope; |
| initializeMaxLocals(methodBinding); |
| final BranchLabel nullLabel = new BranchLabel(this); |
| FieldBinding syntheticFieldBinding = methodBinding.targetReadField; |
| fieldAccess(Opcodes.OPC_getstatic, syntheticFieldBinding, null /* default declaringClass */); |
| dup(); |
| ifnull(nullLabel); |
| areturn(); |
| pushOnStack(syntheticFieldBinding.type); |
| nullLabel.place(); |
| pop(); |
| ReferenceBinding enumBinding = (ReferenceBinding) methodBinding.targetEnumType; |
| ArrayBinding arrayBinding = scope.createArrayType(enumBinding, 1); |
| invokeJavaLangEnumValues(enumBinding, arrayBinding); |
| arraylength(); |
| newarray(ClassFileConstants.INT_ARRAY); |
| astore_0(); |
| LocalVariableBinding localVariableBinding = new LocalVariableBinding(" tab".toCharArray(), scope.createArrayType(TypeBinding.INT, 1), 0, false); //$NON-NLS-1$ |
| addVariable(localVariableBinding); |
| final FieldBinding[] fields = enumBinding.fields(); |
| if (fields != null) { |
| for (int i = 0, max = fields.length; i < max; i++) { |
| FieldBinding fieldBinding = fields[i]; |
| if ((fieldBinding.getAccessFlags() & ClassFileConstants.AccEnum) != 0) { |
| final BranchLabel endLabel = new BranchLabel(this); |
| final ExceptionLabel anyExceptionHandler = new ExceptionLabel(this, TypeBinding.LONG /* represents NoSuchFieldError*/); |
| anyExceptionHandler.placeStart(); |
| aload_0(); |
| fieldAccess(Opcodes.OPC_getstatic, fieldBinding, null /* default declaringClass */); |
| invokeEnumOrdinal(enumBinding.constantPoolName()); |
| this.generateInlinedValue(fieldBinding.id + 1); // zero should not be returned see bug 141810 |
| iastore(); |
| anyExceptionHandler.placeEnd(); |
| goto_(endLabel); |
| // Generate the body of the exception handler |
| pushExceptionOnStack(scope.getJavaLangNoSuchFieldError()); |
| anyExceptionHandler.place(); |
| pop(); // we don't use it so we can pop it |
| endLabel.place(); |
| } |
| } |
| } |
| aload_0(); |
| if (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK9 || !syntheticFieldBinding.isFinal()) { |
| // Modifying a final field outside of the <clinit> method is not allowed in 9 |
| dup(); |
| fieldAccess(Opcodes.OPC_putstatic, syntheticFieldBinding, null /* default declaringClass */); |
| } |
| areturn(); |
| removeVariable(localVariableBinding); |
| } |
| |
| /** |
| * Code responsible to generate the suitable code to supply values for the synthetic enclosing |
| * instance arguments of a constructor invocation of a nested type. |
| */ |
| public void generateSyntheticEnclosingInstanceValues(BlockScope currentScope, ReferenceBinding targetType, Expression enclosingInstance, ASTNode invocationSite) { |
| // supplying enclosing instance for the anonymous type's superclass |
| ReferenceBinding checkedTargetType = targetType.isAnonymousType() ? (ReferenceBinding)targetType.superclass().erasure() : targetType; |
| boolean hasExtraEnclosingInstance = enclosingInstance != null; |
| if (hasExtraEnclosingInstance |
| && (!checkedTargetType.isNestedType() || checkedTargetType.isStatic())) { |
| currentScope.problemReporter().unnecessaryEnclosingInstanceSpecification(enclosingInstance, checkedTargetType); |
| return; |
| } |
| |
| // perform some emulation work in case there is some and we are inside a local type only |
| ReferenceBinding[] syntheticArgumentTypes; |
| if ((syntheticArgumentTypes = targetType.syntheticEnclosingInstanceTypes()) != null) { |
| |
| ReferenceBinding targetEnclosingType = checkedTargetType.enclosingType(); |
| long compliance = currentScope.compilerOptions().complianceLevel; |
| |
| // deny access to enclosing instance argument for allocation and super constructor call (if 1.4) |
| // always consider it if complying to 1.5 |
| boolean denyEnclosingArgInConstructorCall; |
| if (compliance <= ClassFileConstants.JDK1_3) { |
| denyEnclosingArgInConstructorCall = invocationSite instanceof AllocationExpression; |
| } else if (compliance == ClassFileConstants.JDK1_4){ |
| denyEnclosingArgInConstructorCall = invocationSite instanceof AllocationExpression |
| || invocationSite instanceof ExplicitConstructorCall && ((ExplicitConstructorCall)invocationSite).isSuperAccess(); |
| } else if (compliance < ClassFileConstants.JDK1_7) { |
| //compliance >= JDK1_5 |
| denyEnclosingArgInConstructorCall = (invocationSite instanceof AllocationExpression |
| || invocationSite instanceof ExplicitConstructorCall && ((ExplicitConstructorCall)invocationSite).isSuperAccess()) |
| && !targetType.isLocalType(); |
| } else { |
| //compliance >= JDK1_7 |
| if (invocationSite instanceof AllocationExpression) { |
| denyEnclosingArgInConstructorCall = !targetType.isLocalType(); |
| } else if (invocationSite instanceof ExplicitConstructorCall && |
| ((ExplicitConstructorCall)invocationSite).isSuperAccess()) { |
| MethodScope enclosingMethodScope = currentScope.enclosingMethodScope(); |
| denyEnclosingArgInConstructorCall = !targetType.isLocalType() && enclosingMethodScope != null |
| && enclosingMethodScope.isConstructorCall; |
| } else { |
| denyEnclosingArgInConstructorCall = false; |
| } |
| } |
| |
| boolean complyTo14 = compliance >= ClassFileConstants.JDK1_4; |
| for (int i = 0, max = syntheticArgumentTypes.length; i < max; i++) { |
| ReferenceBinding syntheticArgType = syntheticArgumentTypes[i]; |
| if (hasExtraEnclosingInstance && TypeBinding.equalsEquals(syntheticArgType, targetEnclosingType)) { |
| hasExtraEnclosingInstance = false; |
| enclosingInstance.generateCode(currentScope, this, true); |
| if (complyTo14){ |
| dup(); |
| invokeObjectGetClass(); // will perform null check |
| pop(); |
| } |
| } else { |
| Object[] emulationPath = currentScope.getEmulationPath( |
| syntheticArgType, |
| false /*not only exact match (that is, allow compatible)*/, |
| denyEnclosingArgInConstructorCall); |
| generateOuterAccess(emulationPath, invocationSite, syntheticArgType, currentScope); |
| } |
| } |
| if (hasExtraEnclosingInstance){ |
| currentScope.problemReporter().unnecessaryEnclosingInstanceSpecification(enclosingInstance, checkedTargetType); |
| } |
| } |
| } |
| |
| /** |
| * Code responsible to generate the suitable code to supply values for the synthetic outer local |
| * variable arguments of a constructor invocation of a nested type. |
| * (bug 26122) - synthetic values for outer locals must be passed after user arguments, e.g. new X(i = 1){} |
| */ |
| public void generateSyntheticOuterArgumentValues(BlockScope currentScope, ReferenceBinding targetType, ASTNode invocationSite) { |
| // generate the synthetic outer arguments then |
| SyntheticArgumentBinding syntheticArguments[]; |
| if ((syntheticArguments = targetType.syntheticOuterLocalVariables()) != null) { |
| for (int i = 0, max = syntheticArguments.length; i < max; i++) { |
| LocalVariableBinding targetVariable = syntheticArguments[i].actualOuterLocalVariable; |
| VariableBinding[] emulationPath = currentScope.getEmulationPath(targetVariable); |
| generateOuterAccess(emulationPath, invocationSite, targetVariable, currentScope); |
| } |
| } |
| } |
| public void generateSyntheticBodyForRecordCanonicalConstructor(SyntheticMethodBinding canonConstructor) { |
| initializeMaxLocals(canonConstructor); |
| SourceTypeBinding declaringClass = (SourceTypeBinding) canonConstructor.declaringClass; |
| ReferenceBinding superClass = declaringClass.superclass(); |
| MethodBinding superCons = superClass.getExactConstructor(new TypeBinding[0]); |
| aload_0(); |
| invoke(Opcodes.OPC_invokespecial, superCons, superClass); |
| int resolvedPosition; |
| FieldBinding[] fields = declaringClass.getImplicitComponentFields(); |
| int len = fields != null ? fields.length : 0; |
| resolvedPosition = 1; |
| for (int i = 0; i < len; ++i) { |
| FieldBinding field = fields[i]; |
| aload_0(); |
| TypeBinding type = field.type; |
| load(type, resolvedPosition); |
| switch(type.id) { |
| case TypeIds.T_long : |
| case TypeIds.T_double : |
| resolvedPosition += 2; |
| break; |
| default : |
| resolvedPosition++; |
| break; |
| } |
| fieldAccess(Opcodes.OPC_putfield, field, declaringClass); |
| } |
| return_(); |
| } |
| public void generateSyntheticBodyForRecordEquals(SyntheticMethodBinding methodBinding, int index) { |
| initializeMaxLocals(methodBinding); |
| aload_0(); |
| aload_1(); |
| String sig = new String(methodBinding.signature()); |
| sig = sig.substring(0, 1)+ new String(methodBinding.declaringClass.signature()) + sig.substring(1); |
| invokeDynamic(index, methodBinding.parameters.length, 1, methodBinding.selector, sig.toCharArray(), |
| TypeIds.T_boolean, TypeBinding.BOOLEAN); |
| ireturn(); |
| } |
| public void generateSyntheticBodyForRecordHashCode(SyntheticMethodBinding methodBinding, int index) { |
| initializeMaxLocals(methodBinding); |
| aload_0(); |
| String sig = new String(methodBinding.signature()); |
| sig = sig.substring(0, 1)+ new String(methodBinding.declaringClass.signature()) + sig.substring(1); |
| invokeDynamic(index, methodBinding.parameters.length, 1, methodBinding.selector, sig.toCharArray(), |
| TypeIds.T_int, TypeBinding.INT); |
| ireturn(); |
| } |
| public void generateSyntheticBodyForRecordToString(SyntheticMethodBinding methodBinding, int index) { |
| initializeMaxLocals(methodBinding); |
| aload_0(); |
| String sig = new String(methodBinding.signature()); |
| sig = sig.substring(0, 1)+ new String(methodBinding.declaringClass.signature()) + sig.substring(1); |
| invokeDynamic(index, methodBinding.parameters.length, 1, methodBinding.selector, sig.toCharArray(), |
| TypeIds.T_JavaLangObject, getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| areturn(); |
| } |
| |
| public void generateUnboxingConversion(int unboxedTypeID) { |
| switch (unboxedTypeID) { |
| case TypeIds.T_byte : |
| // invokevirtual: byteValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangByteConstantPoolName, |
| ConstantPool.BYTEVALUE_BYTE_METHOD_NAME, |
| ConstantPool.BYTEVALUE_BYTE_METHOD_SIGNATURE, |
| unboxedTypeID, |
| TypeBinding.wellKnownBaseType(unboxedTypeID)); |
| break; |
| case TypeIds.T_short : |
| // invokevirtual: shortValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangShortConstantPoolName, |
| ConstantPool.SHORTVALUE_SHORT_METHOD_NAME, |
| ConstantPool.SHORTVALUE_SHORT_METHOD_SIGNATURE, |
| unboxedTypeID, |
| TypeBinding.wellKnownBaseType(unboxedTypeID)); |
| break; |
| case TypeIds.T_char : |
| // invokevirtual: charValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangCharacterConstantPoolName, |
| ConstantPool.CHARVALUE_CHARACTER_METHOD_NAME, |
| ConstantPool.CHARVALUE_CHARACTER_METHOD_SIGNATURE, |
| unboxedTypeID, |
| TypeBinding.wellKnownBaseType(unboxedTypeID)); |
| break; |
| case TypeIds.T_int : |
| // invokevirtual: intValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangIntegerConstantPoolName, |
| ConstantPool.INTVALUE_INTEGER_METHOD_NAME, |
| ConstantPool.INTVALUE_INTEGER_METHOD_SIGNATURE, |
| unboxedTypeID, |
| TypeBinding.wellKnownBaseType(unboxedTypeID)); |
| break; |
| case TypeIds.T_long : |
| // invokevirtual: longValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 2, // return type size |
| ConstantPool.JavaLangLongConstantPoolName, |
| ConstantPool.LONGVALUE_LONG_METHOD_NAME, |
| ConstantPool.LONGVALUE_LONG_METHOD_SIGNATURE, |
| unboxedTypeID, |
| TypeBinding.wellKnownBaseType(unboxedTypeID)); |
| break; |
| case TypeIds.T_float : |
| // invokevirtual: floatValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangFloatConstantPoolName, |
| ConstantPool.FLOATVALUE_FLOAT_METHOD_NAME, |
| ConstantPool.FLOATVALUE_FLOAT_METHOD_SIGNATURE, |
| unboxedTypeID, |
| TypeBinding.wellKnownBaseType(unboxedTypeID)); |
| break; |
| case TypeIds.T_double : |
| // invokevirtual: doubleValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 2, // return type size |
| ConstantPool.JavaLangDoubleConstantPoolName, |
| ConstantPool.DOUBLEVALUE_DOUBLE_METHOD_NAME, |
| ConstantPool.DOUBLEVALUE_DOUBLE_METHOD_SIGNATURE, |
| unboxedTypeID, |
| TypeBinding.wellKnownBaseType(unboxedTypeID)); |
| break; |
| case TypeIds.T_boolean : |
| // invokevirtual: booleanValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangBooleanConstantPoolName, |
| ConstantPool.BOOLEANVALUE_BOOLEAN_METHOD_NAME, |
| ConstantPool.BOOLEANVALUE_BOOLEAN_METHOD_SIGNATURE, |
| unboxedTypeID, |
| TypeBinding.wellKnownBaseType(unboxedTypeID)); |
| } |
| } |
| |
| |
| /* |
| * Wide conditional branch compare, improved by swapping comparison opcode |
| * ifeq WideTarget |
| * becomes |
| * ifne Intermediate |
| * gotow WideTarget |
| * Intermediate: |
| */ |
| public void generateWideRevertedConditionalBranch(byte revertedOpcode, BranchLabel wideTarget) { |
| BranchLabel intermediate = new BranchLabel(this); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = revertedOpcode; |
| intermediate.branch(); |
| goto_w(wideTarget); |
| intermediate.place(); |
| } |
| |
| public void getBaseTypeValue(int baseTypeID) { |
| switch (baseTypeID) { |
| case TypeIds.T_byte : |
| // invokevirtual: byteValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangByteConstantPoolName, |
| ConstantPool.BYTEVALUE_BYTE_METHOD_NAME, |
| ConstantPool.BYTEVALUE_BYTE_METHOD_SIGNATURE, |
| baseTypeID, |
| TypeBinding.wellKnownBaseType(baseTypeID)); |
| break; |
| case TypeIds.T_short : |
| // invokevirtual: shortValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangShortConstantPoolName, |
| ConstantPool.SHORTVALUE_SHORT_METHOD_NAME, |
| ConstantPool.SHORTVALUE_SHORT_METHOD_SIGNATURE, |
| baseTypeID, |
| TypeBinding.wellKnownBaseType(baseTypeID)); |
| break; |
| case TypeIds.T_char : |
| // invokevirtual: charValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangCharacterConstantPoolName, |
| ConstantPool.CHARVALUE_CHARACTER_METHOD_NAME, |
| ConstantPool.CHARVALUE_CHARACTER_METHOD_SIGNATURE, |
| baseTypeID, |
| TypeBinding.wellKnownBaseType(baseTypeID)); |
| break; |
| case TypeIds.T_int : |
| // invokevirtual: intValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangIntegerConstantPoolName, |
| ConstantPool.INTVALUE_INTEGER_METHOD_NAME, |
| ConstantPool.INTVALUE_INTEGER_METHOD_SIGNATURE, |
| baseTypeID, |
| TypeBinding.wellKnownBaseType(baseTypeID)); |
| break; |
| case TypeIds.T_long : |
| // invokevirtual: longValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 2, // return type size |
| ConstantPool.JavaLangLongConstantPoolName, |
| ConstantPool.LONGVALUE_LONG_METHOD_NAME, |
| ConstantPool.LONGVALUE_LONG_METHOD_SIGNATURE, |
| baseTypeID, |
| TypeBinding.wellKnownBaseType(baseTypeID)); |
| break; |
| case TypeIds.T_float : |
| // invokevirtual: floatValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangFloatConstantPoolName, |
| ConstantPool.FLOATVALUE_FLOAT_METHOD_NAME, |
| ConstantPool.FLOATVALUE_FLOAT_METHOD_SIGNATURE, |
| baseTypeID, |
| TypeBinding.wellKnownBaseType(baseTypeID)); |
| break; |
| case TypeIds.T_double : |
| // invokevirtual: doubleValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 2, // return type size |
| ConstantPool.JavaLangDoubleConstantPoolName, |
| ConstantPool.DOUBLEVALUE_DOUBLE_METHOD_NAME, |
| ConstantPool.DOUBLEVALUE_DOUBLE_METHOD_SIGNATURE, |
| baseTypeID, |
| TypeBinding.wellKnownBaseType(baseTypeID)); |
| break; |
| case TypeIds.T_boolean : |
| // invokevirtual: booleanValue() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangBooleanConstantPoolName, |
| ConstantPool.BOOLEANVALUE_BOOLEAN_METHOD_NAME, |
| ConstantPool.BOOLEANVALUE_BOOLEAN_METHOD_SIGNATURE, |
| baseTypeID, |
| TypeBinding.wellKnownBaseType(baseTypeID)); |
| } |
| } |
| |
| final public byte[] getContents() { |
| byte[] contents; |
| System.arraycopy(this.bCodeStream, 0, contents = new byte[this.position], 0, this.position); |
| return contents; |
| } |
| |
| /** |
| * Returns the type that should be substituted to original binding declaring class as the proper receiver type |
| * @param currentScope |
| * @param codegenBinding |
| * @param actualReceiverType |
| * @param isImplicitThisReceiver |
| * @return the receiver type to use in constant pool |
| */ |
| public static TypeBinding getConstantPoolDeclaringClass(Scope currentScope, FieldBinding codegenBinding, TypeBinding actualReceiverType, boolean isImplicitThisReceiver) { |
| ReferenceBinding constantPoolDeclaringClass = codegenBinding.declaringClass; |
| // if the binding declaring class is not visible, need special action |
| // for runtime compatibility on 1.2 VMs : change the declaring class of the binding |
| // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type |
| // and not from Object or implicit static field access. |
| if (TypeBinding.notEquals(constantPoolDeclaringClass, actualReceiverType.erasure()) |
| && !actualReceiverType.isArrayType() |
| && constantPoolDeclaringClass != null // array.length |
| && codegenBinding.constant() == Constant.NotAConstant) { |
| CompilerOptions options = currentScope.compilerOptions(); |
| if ((options.targetJDK >= ClassFileConstants.JDK1_2 |
| && (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(isImplicitThisReceiver && codegenBinding.isStatic())) |
| && constantPoolDeclaringClass.id != TypeIds.T_JavaLangObject) // no change for Object fields |
| || !constantPoolDeclaringClass.canBeSeenBy(currentScope)) { |
| |
| return actualReceiverType.erasure(); |
| } |
| } |
| return constantPoolDeclaringClass; |
| } |
| |
| /** |
| * Returns the type that should be substituted to original binding declaring class as the proper receiver type |
| * @param currentScope |
| * @param codegenBinding |
| * @param actualReceiverType |
| * @param isImplicitThisReceiver |
| * @return the receiver type to use in constant pool |
| */ |
| public static TypeBinding getConstantPoolDeclaringClass(Scope currentScope, MethodBinding codegenBinding, TypeBinding actualReceiverType, boolean isImplicitThisReceiver) { |
| TypeBinding constantPoolDeclaringClass = codegenBinding.declaringClass; |
| // Post 1.4.0 target, array clone() invocations are qualified with array type |
| // This is handled in array type #clone method binding resolution (see ArrayBinding.getCloneMethod()) |
| if (ArrayBinding.isArrayClone(actualReceiverType, codegenBinding)) { |
| CompilerOptions options = currentScope.compilerOptions(); |
| if (options.sourceLevel > ClassFileConstants.JDK1_4 ) { |
| constantPoolDeclaringClass = actualReceiverType.erasure(); |
| } |
| } else { |
| // if the binding declaring class is not visible, need special action |
| // for runtime compatibility on 1.2 VMs : change the declaring class of the binding |
| // NOTE: from target 1.2 on, method's declaring class is touched if any different from receiver type |
| // and not from Object or implicit static method call. |
| if (TypeBinding.notEquals(constantPoolDeclaringClass, actualReceiverType.erasure()) && !actualReceiverType.isArrayType()) { |
| CompilerOptions options = currentScope.compilerOptions(); |
| |
| if ((options.targetJDK >= ClassFileConstants.JDK1_2 |
| && (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(isImplicitThisReceiver && codegenBinding.isStatic())) |
| && codegenBinding.declaringClass.id != TypeIds.T_JavaLangObject) // no change for Object methods |
| || !codegenBinding.declaringClass.canBeSeenBy(currentScope)) { |
| TypeBinding erasedReceiverType = actualReceiverType.erasure(); |
| if (erasedReceiverType.isIntersectionType18()) { |
| actualReceiverType = erasedReceiverType; // need to peel the intersecting types below |
| } |
| if (actualReceiverType.isIntersectionType18()) { |
| TypeBinding[] intersectingTypes = ((IntersectionTypeBinding18)actualReceiverType).getIntersectingTypes(); |
| for(int i = 0; i < intersectingTypes.length; i++) { |
| if (intersectingTypes[i].findSuperTypeOriginatingFrom(constantPoolDeclaringClass) != null) { |
| constantPoolDeclaringClass = intersectingTypes[i].erasure(); |
| break; |
| } |
| } |
| } else { |
| constantPoolDeclaringClass = erasedReceiverType; |
| } |
| } |
| } |
| } |
| return constantPoolDeclaringClass; |
| } |
| protected int getPosition() { |
| return this.position; |
| } |
| |
| public void getTYPE(int baseTypeID) { |
| this.countLabels = 0; |
| switch (baseTypeID) { |
| case TypeIds.T_byte : |
| // getstatic: java.lang.Byte.TYPE |
| fieldAccess( |
| Opcodes.OPC_getstatic, |
| 1, // return type size |
| ConstantPool.JavaLangByteConstantPoolName, |
| ConstantPool.TYPE, |
| ConstantPool.JavaLangClassSignature, |
| baseTypeID); |
| break; |
| case TypeIds.T_short : |
| // getstatic: java.lang.Short.TYPE |
| fieldAccess( |
| Opcodes.OPC_getstatic, |
| 1, // return type size |
| ConstantPool.JavaLangShortConstantPoolName, |
| ConstantPool.TYPE, |
| ConstantPool.JavaLangClassSignature, |
| baseTypeID); |
| break; |
| case TypeIds.T_char : |
| // getstatic: java.lang.Character.TYPE |
| fieldAccess( |
| Opcodes.OPC_getstatic, |
| 1, // return type size |
| ConstantPool.JavaLangCharacterConstantPoolName, |
| ConstantPool.TYPE, |
| ConstantPool.JavaLangClassSignature, |
| baseTypeID); |
| break; |
| case TypeIds.T_int : |
| // getstatic: java.lang.Integer.TYPE |
| fieldAccess( |
| Opcodes.OPC_getstatic, |
| 1, // return type size |
| ConstantPool.JavaLangIntegerConstantPoolName, |
| ConstantPool.TYPE, |
| ConstantPool.JavaLangClassSignature, |
| baseTypeID); |
| break; |
| case TypeIds.T_long : |
| // getstatic: java.lang.Long.TYPE |
| fieldAccess( |
| Opcodes.OPC_getstatic, |
| 1, // return type size |
| ConstantPool.JavaLangLongConstantPoolName, |
| ConstantPool.TYPE, |
| ConstantPool.JavaLangClassSignature, |
| baseTypeID); |
| break; |
| case TypeIds.T_float : |
| // getstatic: java.lang.Float.TYPE |
| fieldAccess( |
| Opcodes.OPC_getstatic, |
| 1, // return type size |
| ConstantPool.JavaLangFloatConstantPoolName, |
| ConstantPool.TYPE, |
| ConstantPool.JavaLangClassSignature, |
| baseTypeID); |
| break; |
| case TypeIds.T_double : |
| // getstatic: java.lang.Double.TYPE |
| fieldAccess( |
| Opcodes.OPC_getstatic, |
| 1, // return type size |
| ConstantPool.JavaLangDoubleConstantPoolName, |
| ConstantPool.TYPE, |
| ConstantPool.JavaLangClassSignature, |
| baseTypeID); |
| break; |
| case TypeIds.T_boolean : |
| // getstatic: java.lang.Boolean.TYPE |
| fieldAccess( |
| Opcodes.OPC_getstatic, |
| 1, // return type size |
| ConstantPool.JavaLangBooleanConstantPoolName, |
| ConstantPool.TYPE, |
| ConstantPool.JavaLangClassSignature, |
| baseTypeID); |
| break; |
| case TypeIds.T_void : |
| // getstatic: java.lang.Void.TYPE |
| fieldAccess( |
| Opcodes.OPC_getstatic, |
| 1, // return type size |
| ConstantPool.JavaLangVoidConstantPoolName, |
| ConstantPool.TYPE, |
| ConstantPool.JavaLangClassSignature, |
| baseTypeID); |
| break; |
| } |
| } |
| |
| /** |
| * We didn't call it goto, because there is a conflit with the goto keyword |
| */ |
| public void goto_(BranchLabel label) { |
| if (this.wideMode) { |
| goto_w(label); |
| return; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| boolean chained = inlineForwardReferencesFromLabelsTargeting(label, this.position); |
| /* |
| Possible optimization for code such as: |
| public Object foo() { |
| boolean b = true; |
| if (b) { |
| if (b) |
| return null; |
| } else { |
| if (b) { |
| return null; |
| } |
| } |
| return null; |
| } |
| The goto around the else block for the first if will |
| be unreachable, because the thenClause of the second if |
| returns. Also see 114894 |
| }*/ |
| if (chained && this.lastAbruptCompletion == this.position) { |
| if (label.position != Label.POS_NOT_SET) { // ensure existing forward references are updated |
| int[] forwardRefs = label.forwardReferences(); |
| for (int i = 0, max = label.forwardReferenceCount(); i < max; i++) { |
| this.writePosition(label, forwardRefs[i]); |
| } |
| this.countLabels = 0; // backward jump, no further chaining allowed |
| } |
| return; |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_goto; |
| label.branch(); |
| this.lastAbruptCompletion = this.position; |
| } |
| |
| public void goto_w(BranchLabel label) { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_goto_w; |
| label.branchWide(); |
| this.lastAbruptCompletion = this.position; |
| } |
| |
| public void i2b() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_i2b; |
| pushTypeBinding(1, TypeBinding.INT); |
| } |
| |
| public void i2c() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_i2c; |
| pushTypeBinding(1, TypeBinding.INT); |
| } |
| |
| public void i2d() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(1, TypeBinding.INT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_i2d; |
| } |
| |
| public void i2f() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_i2f; |
| pushTypeBinding(1, TypeBinding.FLOAT); |
| } |
| |
| public void i2l() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(1, TypeBinding.LONG); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_i2l; |
| } |
| |
| public void i2s() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_i2s; |
| pushTypeBinding(1, TypeBinding.INT); |
| } |
| |
| public void iadd() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iadd; |
| } |
| |
| public void iaload() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBindingArray(); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iaload; |
| } |
| |
| public void iand() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iand; |
| } |
| |
| public void iastore() { |
| this.countLabels = 0; |
| this.stackDepth -= 3; |
| popTypeBinding(3); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iastore; |
| } |
| |
| public void iconst_0() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iconst_0; |
| } |
| |
| public void iconst_1() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iconst_1; |
| } |
| |
| public void iconst_2() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iconst_2; |
| } |
| public void iconst_3() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iconst_3; |
| } |
| |
| public void iconst_4() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iconst_4; |
| } |
| |
| public void iconst_5() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iconst_5; |
| } |
| |
| public void iconst_m1() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iconst_m1; |
| } |
| |
| public void idiv() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_idiv; |
| } |
| |
| public void if_acmpeq(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth-=2; |
| popTypeBinding(2); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_if_acmpne, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_if_acmpeq; |
| lbl.branch(); |
| } |
| } |
| |
| public void if_acmpne(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth-=2; |
| popTypeBinding(2); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_if_acmpeq, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_if_acmpne; |
| lbl.branch(); |
| } |
| } |
| |
| public void if_icmpeq(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(2); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_if_icmpne, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_if_icmpeq; |
| lbl.branch(); |
| } |
| } |
| |
| public void if_icmpge(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(2); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_if_icmplt, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_if_icmpge; |
| lbl.branch(); |
| } |
| } |
| |
| public void if_icmpgt(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(2); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_if_icmple, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_if_icmpgt; |
| lbl.branch(); |
| } |
| } |
| |
| public void if_icmple(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(2); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_if_icmpgt, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_if_icmple; |
| lbl.branch(); |
| } |
| } |
| |
| public void if_icmplt(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(2); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_if_icmpge, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_if_icmplt; |
| lbl.branch(); |
| } |
| } |
| |
| public void if_icmpne(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(2); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_if_icmpeq, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_if_icmpne; |
| lbl.branch(); |
| } |
| } |
| |
| public void ifeq(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_ifne, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ifeq; |
| lbl.branch(); |
| } |
| } |
| |
| public void ifge(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_iflt, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ifge; |
| lbl.branch(); |
| } |
| } |
| |
| public void ifgt(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_ifle, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ifgt; |
| lbl.branch(); |
| } |
| } |
| |
| public void ifle(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_ifgt, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ifle; |
| lbl.branch(); |
| } |
| } |
| |
| public void iflt(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_ifge, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iflt; |
| lbl.branch(); |
| } |
| } |
| |
| public void ifne(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_ifeq, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ifne; |
| lbl.branch(); |
| } |
| } |
| |
| public void ifnonnull(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_ifnull, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ifnonnull; |
| lbl.branch(); |
| } |
| } |
| |
| public void ifnull(BranchLabel lbl) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.wideMode) { |
| generateWideRevertedConditionalBranch(Opcodes.OPC_ifnonnull, lbl); |
| } else { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ifnull; |
| lbl.branch(); |
| } |
| } |
| |
| final public void iinc(int index, int value) { |
| this.countLabels = 0; |
| if ((index > 255) || (value < -128 || value > 127)) { // have to widen |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iinc; |
| writeUnsignedShort(index); |
| writeSignedShort(value); |
| } else { |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 3; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iinc; |
| this.bCodeStream[this.classFileOffset++] = (byte) index; |
| this.bCodeStream[this.classFileOffset++] = (byte) value; |
| } |
| } |
| |
| public void iload(int iArg) { |
| this.countLabels = 0; |
| this.stackDepth++; |
| if (this.maxLocals <= iArg) { |
| this.maxLocals = iArg + 1; |
| } |
| pushTypeBinding(TypeBinding.INT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (iArg > 255) { // Widen |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iload; |
| writeUnsignedShort(iArg); |
| } else { |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iload; |
| this.bCodeStream[this.classFileOffset++] = (byte) iArg; |
| } |
| } |
| |
| public void iload_0() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.maxLocals <= 0) { |
| this.maxLocals = 1; |
| } |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iload_0; |
| } |
| |
| public void iload_1() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.maxLocals <= 1) { |
| this.maxLocals = 2; |
| } |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iload_1; |
| } |
| |
| public void iload_2() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.maxLocals <= 2) { |
| this.maxLocals = 3; |
| } |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iload_2; |
| } |
| |
| public void iload_3() { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.maxLocals <= 3) { |
| this.maxLocals = 4; |
| } |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iload_3; |
| } |
| |
| public void imul() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_imul; |
| } |
| |
| public void ineg() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ineg; |
| pushTypeBinding(1, TypeBinding.INT); |
| } |
| |
| public void init(ClassFile targetClassFile) { |
| this.classFile = targetClassFile; |
| this.constantPool = targetClassFile.constantPool; |
| this.bCodeStream = targetClassFile.contents; |
| this.classFileOffset = targetClassFile.contentsOffset; |
| this.startingClassFileOffset = this.classFileOffset; |
| this.pcToSourceMapSize = 0; |
| this.lastEntryPC = 0; |
| this.visibleLocalsCount = 0; |
| |
| this.allLocalsCounter = 0; |
| |
| this.exceptionLabelsCounter = 0; |
| |
| this.countLabels = 0; |
| this.lastAbruptCompletion = -1; |
| |
| this.stackMax = 0; |
| this.stackDepth = 0; |
| this.maxLocals = 0; |
| this.position = 0; |
| |
| this.clearTypeBindingStack(); |
| this.lastSwitchCumulativeSyntheticVars = 0; |
| } |
| |
| /** |
| * @param methodBinding the given method binding to initialize the max locals |
| */ |
| public void initializeMaxLocals(MethodBinding methodBinding) { |
| if (methodBinding == null) { |
| this.maxLocals = 0; |
| return; |
| } |
| this.maxLocals = methodBinding.isStatic() ? 0 : 1; |
| ReferenceBinding declaringClass = methodBinding.declaringClass; |
| // take into account enum constructor synthetic name+ordinal |
| if (methodBinding.isConstructor() && declaringClass.isEnum()) { |
| this.maxLocals += 2; // String and int (enum constant name+ordinal) |
| } |
| |
| // take into account the synthetic parameters |
| if (methodBinding.isConstructor() && declaringClass.isNestedType()) { |
| this.maxLocals += declaringClass.getEnclosingInstancesSlotSize(); |
| this.maxLocals += declaringClass.getOuterLocalVariablesSlotSize(); |
| } |
| TypeBinding[] parameterTypes; |
| if ((parameterTypes = methodBinding.parameters) != null) { |
| for (int i = 0, max = parameterTypes.length; i < max; i++) { |
| switch (parameterTypes[i].id) { |
| case TypeIds.T_long : |
| case TypeIds.T_double : |
| this.maxLocals += 2; |
| break; |
| default: |
| this.maxLocals++; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Some placed labels might be branching to a goto bytecode which we can optimize better. |
| */ |
| public boolean inlineForwardReferencesFromLabelsTargeting(BranchLabel targetLabel, int gotoLocation) { |
| if (targetLabel.delegate != null) return false; // already inlined |
| int chaining = L_UNKNOWN; |
| for (int i = this.countLabels - 1; i >= 0; i--) { |
| BranchLabel currentLabel = this.labels[i]; |
| if (currentLabel.position != gotoLocation) break; |
| if (currentLabel == targetLabel) { |
| chaining |= L_CANNOT_OPTIMIZE; // recursive |
| continue; |
| } |
| if (currentLabel.isStandardLabel()) { |
| if (currentLabel.delegate != null) continue; // ignore since already inlined |
| targetLabel.becomeDelegateFor(currentLabel); |
| chaining |= L_OPTIMIZABLE; // optimizable, providing no vetoing |
| continue; |
| } |
| // case label |
| chaining |= L_CANNOT_OPTIMIZE; |
| } |
| return (chaining & (L_OPTIMIZABLE|L_CANNOT_OPTIMIZE)) == L_OPTIMIZABLE; // check was some standards, and no case/recursive |
| } |
| |
| /** |
| * We didn't call it instanceof because there is a conflict with the |
| * instanceof keyword |
| */ |
| public void instance_of(TypeBinding typeBinding) { |
| this.instance_of(null, typeBinding); |
| } |
| |
| /** |
| * We didn't call it instanceof because there is a conflict with the |
| * instanceof keyword |
| */ |
| public void instance_of(TypeReference typeReference, TypeBinding typeBinding) { |
| this.countLabels = 0; |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_instanceof; |
| writeUnsignedShort(this.constantPool.literalIndexForType(typeBinding)); |
| pushTypeBinding(1, TypeBinding.INT); |
| } |
| |
| protected void invoke(byte opcode, int receiverAndArgsSize, int returnTypeSize, char[] declaringClass, char[] selector, char[] signature, TypeBinding type) { |
| invoke(opcode, receiverAndArgsSize, returnTypeSize, declaringClass, selector, signature, TypeIds.T_JavaLangObject, type); |
| } |
| protected void _invoke(byte opcode, int receiverAndArgsSize, int returnTypeSize, char[] declaringClass, char[] selector, char[] signature, int typeId) { |
| // invoke18(opcode, receiverAndArgsSize, returnTypeSize, declaringClass, opcode == Opcodes.OPC_invokeinterface, selector, signature, typeId); |
| } |
| protected void invoke(byte opcode, int receiverAndArgsSize, int returnTypeSize, char[] declaringClass, char[] selector, char[] signature, int typeId, TypeBinding type) { |
| invoke18(opcode, receiverAndArgsSize, returnTypeSize, declaringClass, opcode == Opcodes.OPC_invokeinterface, selector, signature, typeId, type); |
| } |
| |
| private void popInvokeTypeBinding(int receiverAndArgsSize) { |
| if (!isSwitchStackTrackingActive()) |
| return; |
| for (int i = 0; i < receiverAndArgsSize;) { |
| TypeBinding typeBinding = popTypeBinding(); |
| // 571929: receiverAndArgsSize counts slots, so when we pop a long/double, we popped two slots |
| if (TypeIds.getCategory(typeBinding.id) == 2) { |
| i += 2; |
| } else { |
| i++; |
| } |
| } |
| } |
| |
| // Starting with 1.8 we can no longer deduce isInterface from opcode, invokespecial can be used for default methods, too. |
| // Hence adding explicit parameter 'isInterface', which is needed only for non-ctor invokespecial invocations |
| // (i.e., other clients may still call the shorter overload). |
| private void invoke18(byte opcode, int receiverAndArgsSize, int returnTypeSize, char[] declaringClass, |
| boolean isInterface, char[] selector, char[] signature, int typeId, TypeBinding type) { |
| this.countLabels = 0; |
| if (opcode == Opcodes.OPC_invokeinterface) { |
| // invokeinterface |
| if (this.classFileOffset + 4 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position +=3; |
| this.bCodeStream[this.classFileOffset++] = opcode; |
| writeUnsignedShort(this.constantPool.literalIndexForMethod(declaringClass, selector, signature, true)); |
| this.bCodeStream[this.classFileOffset++] = (byte) receiverAndArgsSize; |
| this.bCodeStream[this.classFileOffset++] = 0; |
| } else { |
| // invokespecial |
| // invokestatic |
| // invokevirtual |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = opcode; |
| writeUnsignedShort(this.constantPool.literalIndexForMethod(declaringClass, selector, signature, isInterface)); |
| } |
| this.stackDepth += returnTypeSize - receiverAndArgsSize; |
| popInvokeTypeBinding(receiverAndArgsSize); |
| if (returnTypeSize > 0) { |
| pushTypeBinding(type); |
| } |
| if (this.stackDepth > this.stackMax) { |
| this.stackMax = this.stackDepth; |
| } |
| } |
| |
| public void invokeDynamic(int bootStrapIndex, int argsSize, int returnTypeSize, char[] selector, char[] signature, |
| int typeId, TypeBinding type) { |
| this.invokeDynamic(bootStrapIndex, argsSize, returnTypeSize, selector, signature, false, null, null, typeId, type); |
| } |
| |
| public void invokeDynamic(int bootStrapIndex, int argsSize, int returnTypeSize, char[] selector, char[] signature, boolean isConstructorReference, TypeReference lhsTypeReference, TypeReference [] typeArguments, |
| int typeId, TypeBinding type) { |
| if (this.classFileOffset + 4 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| int invokeDynamicIndex = this.constantPool.literalIndexForInvokeDynamic(bootStrapIndex, selector, signature); |
| this.position +=3; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_invokedynamic; |
| writeUnsignedShort(invokeDynamicIndex); |
| this.bCodeStream[this.classFileOffset++] = 0; |
| this.bCodeStream[this.classFileOffset++] = 0; |
| this.stackDepth += returnTypeSize - argsSize; |
| popInvokeTypeBinding(argsSize); |
| if (returnTypeSize > 0) { |
| pushTypeBinding(type); |
| } |
| if (this.stackDepth > this.stackMax) { |
| this.stackMax = this.stackDepth; |
| } |
| } |
| |
| public void invoke(byte opcode, MethodBinding methodBinding, TypeBinding declaringClass) { |
| this.invoke(opcode, methodBinding, declaringClass, null); |
| } |
| |
| public void invoke(byte opcode, MethodBinding methodBinding, TypeBinding declaringClass, TypeReference[] typeArguments) { |
| if (declaringClass == null) declaringClass = methodBinding.declaringClass; |
| if ((declaringClass.tagBits & TagBits.ContainsNestedTypeReferences) != 0) { |
| Util.recordNestedType(this.classFile, declaringClass); |
| } |
| // compute receiverAndArgsSize |
| int receiverAndArgsSize; |
| switch(opcode) { |
| case Opcodes.OPC_invokestatic : |
| receiverAndArgsSize = 0; // no receiver |
| break; |
| case Opcodes.OPC_invokeinterface : |
| case Opcodes.OPC_invokevirtual : |
| receiverAndArgsSize = 1; // receiver |
| break; |
| case Opcodes.OPC_invokespecial : |
| receiverAndArgsSize = 1; // receiver |
| if (methodBinding.isConstructor()) { |
| if (declaringClass.isNestedType()) { |
| ReferenceBinding nestedType = (ReferenceBinding) declaringClass; |
| // enclosing instances |
| receiverAndArgsSize += nestedType.getEnclosingInstancesSlotSize(); |
| // outer local variables |
| SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticOuterLocalVariables(); |
| if (syntheticArguments != null) { |
| for (int i = 0, max = syntheticArguments.length; i < max; i++) { |
| switch (syntheticArguments[i].id) { |
| case TypeIds.T_double : |
| case TypeIds.T_long : |
| receiverAndArgsSize += 2; |
| break; |
| default: |
| receiverAndArgsSize++; |
| break; |
| } |
| } |
| } |
| } |
| if (declaringClass.isEnum()) { |
| // adding String (name) and int (ordinal) |
| receiverAndArgsSize += 2; |
| } |
| } |
| break; |
| default : |
| return; // should not occur |
| |
| } |
| for (int i = methodBinding.parameters.length - 1; i >= 0; i--) { |
| switch (methodBinding.parameters[i].id) { |
| case TypeIds.T_double : |
| case TypeIds.T_long : |
| receiverAndArgsSize += 2; |
| break; |
| default : |
| receiverAndArgsSize ++; |
| break; |
| } |
| } |
| // compute return type size |
| int returnTypeSize; |
| switch (methodBinding.returnType.id) { |
| case TypeIds.T_double : |
| case TypeIds.T_long : |
| returnTypeSize = 2; |
| break; |
| case TypeIds.T_void : |
| returnTypeSize = 0; |
| break; |
| default : |
| returnTypeSize = 1; |
| break; |
| } |
| invoke18( |
| opcode, |
| receiverAndArgsSize, |
| returnTypeSize, |
| declaringClass.constantPoolName(), |
| declaringClass.isInterface(), |
| methodBinding.selector, |
| methodBinding.signature(this.classFile), |
| methodBinding.returnType.id, |
| methodBinding.returnType); |
| } |
| |
| protected void invokeAccessibleObjectSetAccessible() { |
| // invokevirtual: java.lang.reflect.AccessibleObject.setAccessible(Z)V; |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 2, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JAVALANGREFLECTACCESSIBLEOBJECT_CONSTANTPOOLNAME, |
| ConstantPool.SETACCESSIBLE_NAME, |
| ConstantPool.SETACCESSIBLE_SIGNATURE, |
| null); |
| } |
| |
| protected void invokeArrayNewInstance() { |
| // invokestatic: java.lang.reflect.Array.newInstance(Ljava.lang.Class;int[])Ljava.lang.Object; |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 2, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JAVALANGREFLECTARRAY_CONSTANTPOOLNAME, |
| ConstantPool.NewInstance, |
| ConstantPool.NewInstanceSignature, |
| getPopularBinding(ConstantPool.JavaLangObjectConstantPoolName)); |
| } |
| public void invokeClassForName() { |
| // invokestatic: java.lang.Class.forName(Ljava.lang.String;)Ljava.lang.Class; |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangClassConstantPoolName, |
| ConstantPool.ForName, |
| ConstantPool.ForNameSignature, |
| getPopularBinding(ConstantPool.JavaLangClassConstantPoolName)); |
| } |
| |
| protected void invokeClassGetDeclaredConstructor() { |
| // invokevirtual: java.lang.Class getDeclaredConstructor([Ljava.lang.Class)Ljava.lang.reflect.Constructor; |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 2, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangClassConstantPoolName, |
| ConstantPool.GETDECLAREDCONSTRUCTOR_NAME, |
| ConstantPool.GETDECLAREDCONSTRUCTOR_SIGNATURE, |
| getPopularBinding(ConstantPool.JavaLangReflectConstructorConstantPoolName)); |
| } |
| |
| protected void invokeClassGetDeclaredField() { |
| // invokevirtual: java.lang.Class.getDeclaredField(Ljava.lang.String)Ljava.lang.reflect.Field; |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 2, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangClassConstantPoolName, |
| ConstantPool.GETDECLAREDFIELD_NAME, |
| ConstantPool.GETDECLAREDFIELD_SIGNATURE, |
| getPopularBinding(ConstantPool.JAVALANGREFLECTFIELD_CONSTANTPOOLNAME)); |
| } |
| |
| protected void invokeClassGetDeclaredMethod() { |
| // invokevirtual: java.lang.Class getDeclaredMethod(Ljava.lang.String, [Ljava.lang.Class)Ljava.lang.reflect.Method; |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 3, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangClassConstantPoolName, |
| ConstantPool.GETDECLAREDMETHOD_NAME, |
| ConstantPool.GETDECLAREDMETHOD_SIGNATURE, |
| getPopularBinding(ConstantPool.JAVALANGREFLECTMETHOD_CONSTANTPOOLNAME)); |
| } |
| |
| public void invokeEnumOrdinal(char[] enumTypeConstantPoolName) { |
| // invokevirtual: <enumConstantPoolName>.ordinal() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| enumTypeConstantPoolName, |
| ConstantPool.Ordinal, |
| ConstantPool.OrdinalSignature, |
| TypeIds.T_int, |
| TypeBinding.INT); |
| } |
| |
| public void invokeIterableIterator(TypeBinding iterableReceiverType) { |
| // invokevirtual/interface: <iterableReceiverType>.iterator() |
| if ((iterableReceiverType.tagBits & TagBits.ContainsNestedTypeReferences) != 0) { |
| Util.recordNestedType(this.classFile, iterableReceiverType); |
| } |
| invoke( |
| iterableReceiverType.isInterface() ? Opcodes.OPC_invokeinterface : Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // returnTypeSize |
| iterableReceiverType.constantPoolName(), |
| ConstantPool.ITERATOR_NAME, |
| ConstantPool.ITERATOR_SIGNATURE, |
| getPopularBinding(ConstantPool.JavaUtilIteratorConstantPoolName)); |
| } |
| |
| public void invokeAutoCloseableClose(TypeBinding resourceType) { |
| // invokevirtual/interface: <resourceType>.close() |
| invoke( |
| resourceType.erasure().isInterface() ? Opcodes.OPC_invokeinterface : Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 0, // returnTypeSize |
| resourceType.constantPoolName(), |
| ConstantPool.Close, |
| ConstantPool.CloseSignature, |
| null); |
| } |
| |
| public void invokeThrowableAddSuppressed() { |
| invoke(Opcodes.OPC_invokevirtual, |
| 2, // receiverAndArgsSize |
| 0, // returnTypeSize |
| ConstantPool.JavaLangThrowableConstantPoolName, |
| ConstantPool.AddSuppressed, |
| ConstantPool.AddSuppressedSignature, |
| null); |
| } |
| |
| public void invokeJavaLangAssertionErrorConstructor(int typeBindingID) { |
| // invokespecial: java.lang.AssertionError.<init>(typeBindingID)V |
| int receiverAndArgsSize; |
| char[] signature; |
| switch (typeBindingID) { |
| case TypeIds.T_int : |
| case TypeIds.T_byte : |
| case TypeIds.T_short : |
| signature = ConstantPool.IntConstrSignature; |
| receiverAndArgsSize = 2; |
| break; |
| case TypeIds.T_long : |
| signature = ConstantPool.LongConstrSignature; |
| receiverAndArgsSize = 3; |
| break; |
| case TypeIds.T_float : |
| signature = ConstantPool.FloatConstrSignature; |
| receiverAndArgsSize = 2; |
| break; |
| case TypeIds.T_double : |
| signature = ConstantPool.DoubleConstrSignature; |
| receiverAndArgsSize = 3; |
| break; |
| case TypeIds.T_char : |
| signature = ConstantPool.CharConstrSignature; |
| receiverAndArgsSize = 2; |
| break; |
| case TypeIds.T_boolean : |
| signature = ConstantPool.BooleanConstrSignature; |
| receiverAndArgsSize = 2; |
| break; |
| case TypeIds.T_JavaLangObject : |
| case TypeIds.T_JavaLangString : |
| case TypeIds.T_null : |
| signature = ConstantPool.ObjectConstrSignature; |
| receiverAndArgsSize = 2; |
| break; |
| default: |
| return; // should not occur |
| } |
| invoke( |
| Opcodes.OPC_invokespecial, |
| receiverAndArgsSize, |
| 0, // return type size |
| ConstantPool.JavaLangAssertionErrorConstantPoolName, |
| ConstantPool.Init, |
| signature, |
| null); |
| } |
| |
| public void invokeJavaLangAssertionErrorDefaultConstructor() { |
| // invokespecial: java.lang.AssertionError.<init>()V |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 1, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangAssertionErrorConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.DefaultConstructorSignature, |
| null); |
| } |
| public void invokeJavaLangIncompatibleClassChangeErrorDefaultConstructor() { |
| // invokespecial: java.lang.IncompatibleClassChangeError.<init>()V |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 1, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangIncompatibleClassChangeErrorConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.DefaultConstructorSignature, |
| null); |
| } |
| public void invokeJavaLangClassDesiredAssertionStatus() { |
| // invokevirtual: java.lang.Class.desiredAssertionStatus()Z; |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangClassConstantPoolName, |
| ConstantPool.DesiredAssertionStatus, |
| ConstantPool.DesiredAssertionStatusSignature, |
| TypeIds.T_boolean, |
| TypeBinding.BOOLEAN); |
| } |
| |
| public void invokeJavaLangEnumvalueOf(ReferenceBinding binding) { |
| // invokestatic: java.lang.Enum.valueOf(Class,String) |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 2, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangEnumConstantPoolName, |
| ConstantPool.ValueOf, |
| ConstantPool.ValueOfStringClassSignature, |
| getPopularBinding(ConstantPool.JavaLangEnumConstantPoolName)); |
| } |
| |
| public void invokeJavaLangEnumValues(TypeBinding enumBinding, ArrayBinding arrayBinding) { |
| char[] signature = "()".toCharArray(); //$NON-NLS-1$ |
| signature = CharOperation.concat(signature, arrayBinding.constantPoolName()); |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 0, // receiverAndArgsSize |
| 1, // return type size |
| enumBinding.constantPoolName(), |
| TypeConstants.VALUES, |
| signature, |
| arrayBinding); |
| } |
| |
| public void invokeJavaLangErrorConstructor() { |
| // invokespecial: java.lang.Error<init>(Ljava.lang.String;)V |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 2, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangErrorConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.StringConstructorSignature, |
| null); |
| } |
| |
| public void invokeJavaLangReflectConstructorNewInstance() { |
| // invokevirtual: java.lang.reflect.Constructor.newInstance([Ljava.lang.Object;)Ljava.lang.Object; |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 2, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangReflectConstructorConstantPoolName, |
| ConstantPool.NewInstance, |
| ConstantPool.JavaLangReflectConstructorNewInstanceSignature, |
| getPopularBinding(ConstantPool.JavaLangObjectSignature)); |
| } |
| |
| protected void invokeJavaLangReflectFieldGetter(TypeBinding type) { |
| char[] selector; |
| char[] signature; |
| int returnTypeSize; |
| int typeID = type.id; |
| switch (typeID) { |
| case TypeIds.T_int : |
| selector = ConstantPool.GET_INT_METHOD_NAME; |
| signature = ConstantPool.GET_INT_METHOD_SIGNATURE; |
| returnTypeSize = 1; |
| break; |
| case TypeIds.T_byte : |
| selector = ConstantPool.GET_BYTE_METHOD_NAME; |
| signature = ConstantPool.GET_BYTE_METHOD_SIGNATURE; |
| returnTypeSize = 1; |
| break; |
| case TypeIds.T_short : |
| selector = ConstantPool.GET_SHORT_METHOD_NAME; |
| signature = ConstantPool.GET_SHORT_METHOD_SIGNATURE; |
| returnTypeSize = 1; |
| break; |
| case TypeIds.T_long : |
| selector = ConstantPool.GET_LONG_METHOD_NAME; |
| signature = ConstantPool.GET_LONG_METHOD_SIGNATURE; |
| returnTypeSize = 2; |
| break; |
| case TypeIds.T_float : |
| selector = ConstantPool.GET_FLOAT_METHOD_NAME; |
| signature = ConstantPool.GET_FLOAT_METHOD_SIGNATURE; |
| returnTypeSize = 1; |
| break; |
| case TypeIds.T_double : |
| selector = ConstantPool.GET_DOUBLE_METHOD_NAME; |
| signature = ConstantPool.GET_DOUBLE_METHOD_SIGNATURE; |
| returnTypeSize = 2; |
| break; |
| case TypeIds.T_char : |
| selector = ConstantPool.GET_CHAR_METHOD_NAME; |
| signature = ConstantPool.GET_CHAR_METHOD_SIGNATURE; |
| returnTypeSize = 1; |
| break; |
| case TypeIds.T_boolean : |
| selector = ConstantPool.GET_BOOLEAN_METHOD_NAME; |
| signature = ConstantPool.GET_BOOLEAN_METHOD_SIGNATURE; |
| returnTypeSize = 1; |
| break; |
| default : |
| selector = ConstantPool.GET_OBJECT_METHOD_NAME; |
| signature = ConstantPool.GET_OBJECT_METHOD_SIGNATURE; |
| returnTypeSize = 1; |
| break; |
| } |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 2, // receiverAndArgsSize |
| returnTypeSize, // return type size |
| ConstantPool.JAVALANGREFLECTFIELD_CONSTANTPOOLNAME, |
| selector, |
| signature, |
| typeID, |
| type); |
| } |
| |
| protected void invokeJavaLangReflectFieldSetter(TypeBinding type) { |
| char[] selector; |
| char[] signature; |
| int receiverAndArgsSize; |
| int typeID = type.id; |
| switch (typeID) { |
| case TypeIds.T_int : |
| selector = ConstantPool.SET_INT_METHOD_NAME; |
| signature = ConstantPool.SET_INT_METHOD_SIGNATURE; |
| receiverAndArgsSize = 3; |
| break; |
| case TypeIds.T_byte : |
| selector = ConstantPool.SET_BYTE_METHOD_NAME; |
| signature = ConstantPool.SET_BYTE_METHOD_SIGNATURE; |
| receiverAndArgsSize = 3; |
| break; |
| case TypeIds.T_short : |
| selector = ConstantPool.SET_SHORT_METHOD_NAME; |
| signature = ConstantPool.SET_SHORT_METHOD_SIGNATURE; |
| receiverAndArgsSize = 3; |
| break; |
| case TypeIds.T_long : |
| selector = ConstantPool.SET_LONG_METHOD_NAME; |
| signature = ConstantPool.SET_LONG_METHOD_SIGNATURE; |
| receiverAndArgsSize = 4; |
| break; |
| case TypeIds.T_float : |
| selector = ConstantPool.SET_FLOAT_METHOD_NAME; |
| signature = ConstantPool.SET_FLOAT_METHOD_SIGNATURE; |
| receiverAndArgsSize = 3; |
| break; |
| case TypeIds.T_double : |
| selector = ConstantPool.SET_DOUBLE_METHOD_NAME; |
| signature = ConstantPool.SET_DOUBLE_METHOD_SIGNATURE; |
| receiverAndArgsSize = 4; |
| break; |
| case TypeIds.T_char : |
| selector = ConstantPool.SET_CHAR_METHOD_NAME; |
| signature = ConstantPool.SET_CHAR_METHOD_SIGNATURE; |
| receiverAndArgsSize = 3; |
| break; |
| case TypeIds.T_boolean : |
| selector = ConstantPool.SET_BOOLEAN_METHOD_NAME; |
| signature = ConstantPool.SET_BOOLEAN_METHOD_SIGNATURE; |
| receiverAndArgsSize = 3; |
| break; |
| default : |
| selector = ConstantPool.SET_OBJECT_METHOD_NAME; |
| signature = ConstantPool.SET_OBJECT_METHOD_SIGNATURE; |
| receiverAndArgsSize = 3; |
| break; |
| } |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| receiverAndArgsSize, |
| 0, // return type size |
| ConstantPool.JAVALANGREFLECTFIELD_CONSTANTPOOLNAME, |
| selector, |
| signature, |
| typeID, |
| type); |
| } |
| |
| public void invokeJavaLangReflectMethodInvoke() { |
| // invokevirtual: java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object; |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 3, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JAVALANGREFLECTMETHOD_CONSTANTPOOLNAME, |
| ConstantPool.INVOKE_METHOD_METHOD_NAME, |
| ConstantPool.INVOKE_METHOD_METHOD_SIGNATURE, |
| getPopularBinding(ConstantPool.JavaLangObjectSignature)); |
| } |
| |
| public void invokeJavaUtilIteratorHasNext() { |
| // invokeinterface java.util.Iterator.hasNext()Z |
| invoke( |
| Opcodes.OPC_invokeinterface, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaUtilIteratorConstantPoolName, |
| ConstantPool.HasNext, |
| ConstantPool.HasNextSignature, |
| TypeIds.T_boolean, |
| TypeBinding.BOOLEAN); |
| } |
| |
| public void invokeJavaUtilIteratorNext() { |
| // invokeinterface java.util.Iterator.next()java.lang.Object |
| invoke( |
| Opcodes.OPC_invokeinterface, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaUtilIteratorConstantPoolName, |
| ConstantPool.Next, |
| ConstantPool.NextSignature, |
| getPopularBinding(ConstantPool.JavaLangObjectSignature)); |
| } |
| |
| public void invokeJavaUtilObjectsrequireNonNull() { |
| // invokestatic: java.util.Objects.requireNonNull(Ljava.lang.Object;)Ljava.lang.Object; |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaUtilObjectsConstantPoolName, |
| ConstantPool.RequireNonNull, |
| ConstantPool.RequireNonNullSignature, |
| getPopularBinding(ConstantPool.JavaLangObjectSignature)); |
| } |
| |
| public void invokeNoClassDefFoundErrorStringConstructor() { |
| // invokespecial: java.lang.NoClassDefFoundError.<init>(Ljava.lang.String;)V |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 2, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangNoClassDefFoundErrorConstantPoolName, |
| ConstantPool.Init, |
| ConstantPool.StringConstructorSignature, |
| null); |
| } |
| |
| public void invokeObjectGetClass() { |
| // invokevirtual: java.lang.Object.getClass()Ljava.lang.Class; |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangObjectConstantPoolName, |
| ConstantPool.GetClass, |
| ConstantPool.GetClassSignature, |
| getPopularBinding(ConstantPool.JavaLangClassConstantPoolName)); |
| } |
| |
| /** |
| * The equivalent code performs a string conversion of the TOS |
| * @param typeID <CODE>int</CODE> |
| */ |
| public void invokeStringConcatenationAppendForType(int typeID) { |
| int receiverAndArgsSize; |
| char[] declaringClass = null; |
| char[] selector = ConstantPool.Append; |
| char[] signature = null; |
| switch (typeID) { |
| case TypeIds.T_int : |
| case TypeIds.T_byte : |
| case TypeIds.T_short : |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| declaringClass = ConstantPool.JavaLangStringBuilderConstantPoolName; |
| signature = ConstantPool.StringBuilderAppendIntSignature; |
| } else { |
| declaringClass = ConstantPool.JavaLangStringBufferConstantPoolName; |
| signature = ConstantPool.StringBufferAppendIntSignature; |
| } |
| receiverAndArgsSize = 2; |
| break; |
| case TypeIds.T_long : |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| declaringClass = ConstantPool.JavaLangStringBuilderConstantPoolName; |
| signature = ConstantPool.StringBuilderAppendLongSignature; |
| } else { |
| declaringClass = ConstantPool.JavaLangStringBufferConstantPoolName; |
| signature = ConstantPool.StringBufferAppendLongSignature; |
| } |
| receiverAndArgsSize = 3; |
| break; |
| case TypeIds.T_float : |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| declaringClass = ConstantPool.JavaLangStringBuilderConstantPoolName; |
| signature = ConstantPool.StringBuilderAppendFloatSignature; |
| } else { |
| declaringClass = ConstantPool.JavaLangStringBufferConstantPoolName; |
| signature = ConstantPool.StringBufferAppendFloatSignature; |
| } |
| receiverAndArgsSize = 2; |
| break; |
| case TypeIds.T_double : |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| declaringClass = ConstantPool.JavaLangStringBuilderConstantPoolName; |
| signature = ConstantPool.StringBuilderAppendDoubleSignature; |
| } else { |
| declaringClass = ConstantPool.JavaLangStringBufferConstantPoolName; |
| signature = ConstantPool.StringBufferAppendDoubleSignature; |
| } |
| receiverAndArgsSize = 3; |
| break; |
| case TypeIds.T_char : |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| declaringClass = ConstantPool.JavaLangStringBuilderConstantPoolName; |
| signature = ConstantPool.StringBuilderAppendCharSignature; |
| } else { |
| declaringClass = ConstantPool.JavaLangStringBufferConstantPoolName; |
| signature = ConstantPool.StringBufferAppendCharSignature; |
| } |
| receiverAndArgsSize = 2; |
| break; |
| case TypeIds.T_boolean : |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| declaringClass = ConstantPool.JavaLangStringBuilderConstantPoolName; |
| signature = ConstantPool.StringBuilderAppendBooleanSignature; |
| } else { |
| declaringClass = ConstantPool.JavaLangStringBufferConstantPoolName; |
| signature = ConstantPool.StringBufferAppendBooleanSignature; |
| } |
| receiverAndArgsSize = 2; |
| break; |
| case TypeIds.T_JavaLangString : |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| declaringClass = ConstantPool.JavaLangStringBuilderConstantPoolName; |
| signature = ConstantPool.StringBuilderAppendStringSignature; |
| } else { |
| declaringClass = ConstantPool.JavaLangStringBufferConstantPoolName; |
| signature = ConstantPool.StringBufferAppendStringSignature; |
| } |
| receiverAndArgsSize = 2; |
| break; |
| default : |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| declaringClass = ConstantPool.JavaLangStringBuilderConstantPoolName; |
| signature = ConstantPool.StringBuilderAppendObjectSignature; |
| } else { |
| declaringClass = ConstantPool.JavaLangStringBufferConstantPoolName; |
| signature = ConstantPool.StringBufferAppendObjectSignature; |
| } |
| receiverAndArgsSize = 2; |
| break; |
| } |
| // TODO: revisit after bug 561726 is fixed |
| TypeBinding type = this.targetLevel >= ClassFileConstants.JDK14 ? |
| getPopularBinding(ConstantPool.JavaLangStringBuilderConstantPoolName) : null; |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| receiverAndArgsSize, |
| 1, // return type size |
| declaringClass, |
| selector, |
| signature, |
| typeID, |
| type); |
| } |
| |
| public void invokeStringConcatenationDefaultConstructor() { |
| // invokespecial: java.lang.StringBuffer.<init>()V |
| // or invokespecial: java.lang.StringBuilder.<init>()V |
| char[] declaringClass; |
| if (this.targetLevel < ClassFileConstants.JDK1_5) { |
| declaringClass = ConstantPool.JavaLangStringBufferConstantPoolName; |
| } else { |
| declaringClass = ConstantPool.JavaLangStringBuilderConstantPoolName; |
| } |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 1, // receiverAndArgsSize |
| 0, // return type size |
| declaringClass, |
| ConstantPool.Init, |
| ConstantPool.DefaultConstructorSignature, |
| null); |
| } |
| |
| public void invokeStringConcatenationStringConstructor() { |
| // invokespecial: java.lang.StringBuffer.<init>(java.lang.String)V |
| // or invokespecial: java.lang.StringBuilder.<init>(java.lang.String)V |
| char[] declaringClass; |
| if (this.targetLevel < ClassFileConstants.JDK1_5) { |
| // invokespecial: java.lang.StringBuffer.<init>()V |
| declaringClass = ConstantPool.JavaLangStringBufferConstantPoolName; |
| } else { |
| // invokespecial: java.lang.StringStringBuilder.<init>(java.langString)V |
| declaringClass = ConstantPool.JavaLangStringBuilderConstantPoolName; |
| } |
| invoke( |
| Opcodes.OPC_invokespecial, |
| 2, // receiverAndArgsSize |
| 0, // return type size |
| declaringClass, |
| ConstantPool.Init, |
| ConstantPool.StringConstructorSignature, |
| null); |
| } |
| |
| public void invokeStringConcatenationToString() { |
| // invokespecial: java.lang.StringBuffer.toString()java.lang.String |
| // or invokespecial: java.lang.StringBuilder.toString()java.lang.String |
| char[] declaringClass; |
| if (this.targetLevel < ClassFileConstants.JDK1_5) { |
| // invokespecial: java.lang.StringBuffer.<init>()V |
| declaringClass = ConstantPool.JavaLangStringBufferConstantPoolName; |
| } else { |
| // invokespecial: java.lang.StringStringBuilder.<init>(java.langString)V |
| declaringClass = ConstantPool.JavaLangStringBuilderConstantPoolName; |
| } |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| declaringClass, |
| ConstantPool.ToString, |
| ConstantPool.ToStringSignature, |
| getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| } |
| public void invokeStringEquals() { |
| // invokevirtual: java.lang.String.equals() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 2, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangStringConstantPoolName, |
| ConstantPool.Equals, |
| ConstantPool.EqualsSignature, |
| TypeIds.T_boolean, |
| TypeBinding.BOOLEAN); |
| } |
| public void invokeObjectEquals() { |
| // invokevirtual: java.lang.Object.equals() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 2, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangObjectConstantPoolName, |
| ConstantPool.Equals, |
| ConstantPool.EqualsSignature, |
| TypeIds.T_boolean, |
| TypeBinding.BOOLEAN); |
| } |
| public void invokeStringHashCode() { |
| // invokevirtual: java.lang.String.hashCode() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangStringConstantPoolName, |
| ConstantPool.HashCode, |
| ConstantPool.HashCodeSignature, |
| TypeIds.T_int, |
| TypeBinding.INT); |
| } |
| public void invokeStringIntern() { |
| // invokevirtual: java.lang.String.intern() |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangStringConstantPoolName, |
| ConstantPool.Intern, |
| ConstantPool.InternSignature, |
| getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| } |
| public void invokeStringValueOf(int typeID) { |
| // invokestatic: java.lang.String.valueOf(argumentType) |
| char[] signature; |
| int receiverAndArgsSize; |
| switch (typeID) { |
| case TypeIds.T_int : |
| case TypeIds.T_byte : |
| case TypeIds.T_short : |
| signature = ConstantPool.ValueOfIntSignature; |
| receiverAndArgsSize = 1; |
| break; |
| case TypeIds.T_long : |
| signature = ConstantPool.ValueOfLongSignature; |
| receiverAndArgsSize = 2; |
| break; |
| case TypeIds.T_float : |
| signature = ConstantPool.ValueOfFloatSignature; |
| receiverAndArgsSize = 1; |
| break; |
| case TypeIds.T_double : |
| signature = ConstantPool.ValueOfDoubleSignature; |
| receiverAndArgsSize = 2; |
| break; |
| case TypeIds.T_char : |
| signature = ConstantPool.ValueOfCharSignature; |
| receiverAndArgsSize = 1; |
| break; |
| case TypeIds.T_boolean : |
| signature = ConstantPool.ValueOfBooleanSignature; |
| receiverAndArgsSize = 1; |
| break; |
| case TypeIds.T_JavaLangObject : |
| case TypeIds.T_JavaLangString : |
| case TypeIds.T_null : |
| case TypeIds.T_undefined : |
| signature = ConstantPool.ValueOfObjectSignature; |
| receiverAndArgsSize = 1; |
| break; |
| default : |
| return; // should not occur |
| } |
| invoke( |
| Opcodes.OPC_invokestatic, |
| receiverAndArgsSize, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangStringConstantPoolName, |
| ConstantPool.ValueOf, |
| signature, |
| typeID, |
| getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| } |
| |
| public void invokeSystemArraycopy() { |
| // invokestatic #21 <Method java/lang/System.arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V> |
| invoke( |
| Opcodes.OPC_invokestatic, |
| 5, // receiverAndArgsSize |
| 0, // return type size |
| ConstantPool.JavaLangSystemConstantPoolName, |
| ConstantPool.ArrayCopy, |
| ConstantPool.ArrayCopySignature, |
| null); |
| } |
| |
| public void invokeThrowableGetMessage() { |
| // invokevirtual: java.lang.Throwable.getMessage()Ljava.lang.String; |
| invoke( |
| Opcodes.OPC_invokevirtual, |
| 1, // receiverAndArgsSize |
| 1, // return type size |
| ConstantPool.JavaLangThrowableConstantPoolName, |
| ConstantPool.GetMessage, |
| ConstantPool.GetMessageSignature, |
| getPopularBinding(ConstantPool.JavaLangStringConstantPoolName)); |
| } |
| |
| public void ior() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ior; |
| } |
| |
| public void irem() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_irem; |
| } |
| |
| public void ireturn() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| // the stackDepth should be equal to 0 |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ireturn; |
| this.lastAbruptCompletion = this.position; |
| } |
| |
| public boolean isDefinitelyAssigned(Scope scope, int initStateIndex, LocalVariableBinding local) { |
| // Mirror of UnconditionalFlowInfo.isDefinitelyAssigned(..) |
| if ((local.tagBits & TagBits.IsArgument) != 0) { |
| return true; |
| } |
| if (initStateIndex == -1) |
| return false; |
| int localPosition = local.id + this.maxFieldCount; |
| MethodScope methodScope = scope.methodScope(); |
| // id is zero-based |
| if (localPosition < UnconditionalFlowInfo.BitCacheSize) { |
| return (methodScope.definiteInits[initStateIndex] & (1L << localPosition)) != 0; // use bits |
| } |
| // use extra vector |
| long[] extraInits = methodScope.extraDefiniteInits[initStateIndex]; |
| if (extraInits == null) |
| return false; // if vector not yet allocated, then not initialized |
| int vectorIndex; |
| if ((vectorIndex = (localPosition / UnconditionalFlowInfo.BitCacheSize) - 1) >= extraInits.length) |
| return false; // if not enough room in vector, then not initialized |
| return ((extraInits[vectorIndex]) & (1L << (localPosition % UnconditionalFlowInfo.BitCacheSize))) != 0; |
| } |
| |
| public void ishl() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ishl; |
| } |
| |
| public void ishr() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ishr; |
| } |
| |
| public void istore(int iArg) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals <= iArg) { |
| this.maxLocals = iArg + 1; |
| } |
| if (iArg > 255) { // Widen |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_istore; |
| writeUnsignedShort(iArg); |
| } else { |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_istore; |
| this.bCodeStream[this.classFileOffset++] = (byte) iArg; |
| } |
| } |
| |
| public void istore_0() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals == 0) { |
| this.maxLocals = 1; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_istore_0; |
| } |
| |
| public void istore_1() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals <= 1) { |
| this.maxLocals = 2; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_istore_1; |
| } |
| |
| public void istore_2() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals <= 2) { |
| this.maxLocals = 3; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_istore_2; |
| } |
| |
| public void istore_3() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.maxLocals <= 3) { |
| this.maxLocals = 4; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_istore_3; |
| } |
| |
| public void isub() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_isub; |
| } |
| |
| public void iushr() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_iushr; |
| } |
| |
| public void ixor() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ixor; |
| } |
| |
| final public void jsr(BranchLabel lbl) { |
| if (this.wideMode) { |
| jsr_w(lbl); |
| return; |
| } |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_jsr; |
| lbl.branch(); |
| } |
| |
| final public void jsr_w(BranchLabel lbl) { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_jsr_w; |
| lbl.branchWide(); |
| } |
| |
| public void l2d() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_l2d; |
| pushTypeBinding(1, TypeBinding.DOUBLE); |
| } |
| |
| public void l2f() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(1, TypeBinding.FLOAT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_l2f; |
| } |
| |
| public void l2i() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(1, TypeBinding.INT); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_l2i; |
| } |
| |
| public void ladd() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| pushTypeBinding(2, TypeBinding.LONG); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ladd; |
| } |
| |
| public void laload() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_laload; |
| pushTypeBindingArray(); |
| } |
| |
| public void land() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| pushTypeBinding(2, TypeBinding.LONG); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_land; |
| } |
| |
| public void lastore() { |
| this.countLabels = 0; |
| this.stackDepth -= 4; |
| popTypeBinding(3); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lastore; |
| } |
| |
| public void lcmp() { |
| this.countLabels = 0; |
| this.stackDepth -= 3; |
| pushTypeBinding(2, TypeBinding.LONG); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lcmp; |
| } |
| |
| public void lconst_0() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.LONG); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lconst_0; |
| } |
| |
| public void lconst_1() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.LONG); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lconst_1; |
| } |
| |
| public void ldc(float constant) { |
| this.countLabels = 0; |
| int index = this.constantPool.literalIndex(constant); |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.FLOAT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (index > 255) { |
| // Generate a ldc_w |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ldc_w; |
| writeUnsignedShort(index); |
| } else { |
| // Generate a ldc |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ldc; |
| this.bCodeStream[this.classFileOffset++] = (byte) index; |
| } |
| } |
| |
| public void ldc(int constant) { |
| this.countLabels = 0; |
| int index = this.constantPool.literalIndex(constant); |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (index > 255) { |
| // Generate a ldc_w |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ldc_w; |
| writeUnsignedShort(index); |
| } else { |
| // Generate a ldc |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ldc; |
| this.bCodeStream[this.classFileOffset++] = (byte) index; |
| } |
| } |
| |
| public void ldc(String constant) { |
| this.countLabels = 0; |
| int currentCodeStreamPosition = this.position; |
| char[] constantChars = constant.toCharArray(); |
| int index = this.constantPool.literalIndexForLdc(constantChars); |
| if (index > 0) { |
| // the string already exists inside the constant pool |
| // we reuse the same index |
| ldcForIndex(index); |
| } else { |
| // the string is too big to be utf8-encoded in one pass. |
| // we have to split it into different pieces. |
| // first we clean all side-effects due to the code above |
| // this case is very rare, so we can afford to lose time to handle it |
| this.position = currentCodeStreamPosition; |
| int i = 0; |
| int length = 0; |
| int constantLength = constant.length(); |
| byte[] utf8encoding = new byte[Math.min(constantLength + 100, 65535)]; |
| int utf8encodingLength = 0; |
| while ((length < 65532) && (i < constantLength)) { |
| char current = constantChars[i]; |
| // we resize the byte array immediately if necessary |
| if (length + 3 > (utf8encodingLength = utf8encoding.length)) { |
| System.arraycopy(utf8encoding, 0, utf8encoding = new byte[Math.min(utf8encodingLength + 100, 65535)], 0, length); |
| } |
| if ((current >= 0x0001) && (current <= 0x007F)) { |
| // we only need one byte: ASCII table |
| utf8encoding[length++] = (byte) current; |
| } else { |
| if (current > 0x07FF) { |
| // we need 3 bytes |
| utf8encoding[length++] = (byte) (0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110 0000 |
| utf8encoding[length++] = (byte) (0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000 0000 |
| utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000 |
| } else { |
| // we can be 0 or between 0x0080 and 0x07FF |
| // In that case we only need 2 bytes |
| utf8encoding[length++] = (byte) (0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100 0000 |
| utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000 |
| } |
| } |
| i++; |
| } |
| // check if all the string is encoded (PR 1PR2DWJ) |
| // the string is too big to be encoded in one pass |
| newStringContatenation(); |
| dup(); |
| // write the first part |
| char[] subChars = new char[i]; |
| System.arraycopy(constantChars, 0, subChars, 0, i); |
| System.arraycopy(utf8encoding, 0, utf8encoding = new byte[length], 0, length); |
| index = this.constantPool.literalIndex(subChars, utf8encoding); |
| ldcForIndex(index); |
| // write the remaining part |
| invokeStringConcatenationStringConstructor(); |
| while (i < constantLength) { |
| length = 0; |
| utf8encoding = new byte[Math.min(constantLength - i + 100, 65535)]; |
| int startIndex = i; |
| while ((length < 65532) && (i < constantLength)) { |
| char current = constantChars[i]; |
| // we resize the byte array immediately if necessary |
| if (length + 3 > (utf8encodingLength = utf8encoding.length)) { |
| System.arraycopy(utf8encoding, 0, utf8encoding = new byte[Math.min(utf8encodingLength + 100, 65535)], 0, length); |
| } |
| if ((current >= 0x0001) && (current <= 0x007F)) { |
| // we only need one byte: ASCII table |
| utf8encoding[length++] = (byte) current; |
| } else { |
| if (current > 0x07FF) { |
| // we need 3 bytes |
| utf8encoding[length++] = (byte) (0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110 0000 |
| utf8encoding[length++] = (byte) (0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000 0000 |
| utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000 |
| } else { |
| // we can be 0 or between 0x0080 and 0x07FF |
| // In that case we only need 2 bytes |
| utf8encoding[length++] = (byte) (0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100 0000 |
| utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000 |
| } |
| } |
| i++; |
| } |
| // the next part is done |
| int newCharLength = i - startIndex; |
| subChars = new char[newCharLength]; |
| System.arraycopy(constantChars, startIndex, subChars, 0, newCharLength); |
| System.arraycopy(utf8encoding, 0, utf8encoding = new byte[length], 0, length); |
| index = this.constantPool.literalIndex(subChars, utf8encoding); |
| ldcForIndex(index); |
| // now on the stack it should be a StringBuffer and a string. |
| invokeStringConcatenationAppendForType(TypeIds.T_JavaLangString); |
| } |
| invokeStringConcatenationToString(); |
| invokeStringIntern(); |
| } |
| } |
| |
| public void ldc(TypeBinding typeBinding) { |
| this.countLabels = 0; |
| int index = this.constantPool.literalIndexForType(typeBinding); |
| this.stackDepth++; |
| pushTypeBinding(typeBinding); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (index > 255) { |
| // Generate a ldc_w |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ldc_w; |
| writeUnsignedShort(index); |
| } else { |
| // Generate a ldc |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ldc; |
| this.bCodeStream[this.classFileOffset++] = (byte) index; |
| } |
| } |
| |
| public void ldc2_w(double constant) { |
| this.countLabels = 0; |
| int index = this.constantPool.literalIndex(constant); |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.DOUBLE); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| // Generate a ldc2_w |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ldc2_w; |
| writeUnsignedShort(index); |
| } |
| |
| public void ldc2_w(long constant) { |
| this.countLabels = 0; |
| int index = this.constantPool.literalIndex(constant); |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.LONG); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| // Generate a ldc2_w |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ldc2_w; |
| writeUnsignedShort(index); |
| } |
| |
| public void ldcForIndex(int index) { |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.INT); |
| if (this.stackDepth > this.stackMax) { |
| this.stackMax = this.stackDepth; |
| } |
| if (index > 255) { |
| // Generate a ldc_w |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ldc_w; |
| writeUnsignedShort(index); |
| } else { |
| // Generate a ldc |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ldc; |
| this.bCodeStream[this.classFileOffset++] = (byte) index; |
| } |
| } |
| |
| public void ldiv() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| pushTypeBinding(2, TypeBinding.LONG); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ldiv; |
| } |
| |
| public void lload(int iArg) { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| if (this.maxLocals <= iArg + 1) { |
| this.maxLocals = iArg + 2; |
| } |
| pushTypeBinding(TypeBinding.LONG); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (iArg > 255) { // Widen |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lload; |
| writeUnsignedShort(iArg); |
| } else { |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lload; |
| this.bCodeStream[this.classFileOffset++] = (byte) iArg; |
| } |
| } |
| |
| public void lload_0() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.LONG); |
| if (this.maxLocals < 2) { |
| this.maxLocals = 2; |
| } |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lload_0; |
| } |
| |
| public void lload_1() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.LONG); |
| if (this.maxLocals < 3) { |
| this.maxLocals = 3; |
| } |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lload_1; |
| } |
| |
| public void lload_2() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.LONG); |
| if (this.maxLocals < 4) { |
| this.maxLocals = 4; |
| } |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lload_2; |
| } |
| |
| public void lload_3() { |
| this.countLabels = 0; |
| this.stackDepth += 2; |
| pushTypeBinding(TypeBinding.LONG); |
| if (this.maxLocals < 5) { |
| this.maxLocals = 5; |
| } |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lload_3; |
| } |
| |
| public void lmul() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| pushTypeBinding(2, TypeBinding.LONG); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lmul; |
| } |
| |
| public void lneg() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lneg; |
| pushTypeBinding(1, TypeBinding.LONG); |
| } |
| |
| public final void load(LocalVariableBinding localBinding) { |
| load(localBinding.type, localBinding.resolvedPosition); |
| } |
| |
| protected final void load(TypeBinding typeBinding, int resolvedPosition) { |
| this.countLabels = 0; |
| // Using dedicated int bytecode |
| switch(typeBinding.id) { |
| case TypeIds.T_int : |
| case TypeIds.T_byte : |
| case TypeIds.T_char : |
| case TypeIds.T_boolean : |
| case TypeIds.T_short : |
| switch (resolvedPosition) { |
| case 0 : |
| iload_0(); |
| break; |
| case 1 : |
| iload_1(); |
| break; |
| case 2 : |
| iload_2(); |
| break; |
| case 3 : |
| iload_3(); |
| break; |
| //case -1 : |
| // internal failure: trying to load variable not supposed to be generated |
| // break; |
| default : |
| iload(resolvedPosition); |
| } |
| break; |
| case TypeIds.T_float : |
| switch (resolvedPosition) { |
| case 0 : |
| fload_0(); |
| break; |
| case 1 : |
| fload_1(); |
| break; |
| case 2 : |
| fload_2(); |
| break; |
| case 3 : |
| fload_3(); |
| break; |
| default : |
| fload(resolvedPosition); |
| } |
| break; |
| case TypeIds.T_long : |
| switch (resolvedPosition) { |
| case 0 : |
| lload_0(); |
| break; |
| case 1 : |
| lload_1(); |
| break; |
| case 2 : |
| lload_2(); |
| break; |
| case 3 : |
| lload_3(); |
| break; |
| default : |
| lload(resolvedPosition); |
| } |
| break; |
| case TypeIds.T_double : |
| switch (resolvedPosition) { |
| case 0 : |
| dload_0(); |
| break; |
| case 1 : |
| dload_1(); |
| break; |
| case 2 : |
| dload_2(); |
| break; |
| case 3 : |
| dload_3(); |
| break; |
| default : |
| dload(resolvedPosition); |
| } |
| break; |
| default : |
| switch (resolvedPosition) { |
| case 0 : |
| aload_0(); |
| break; |
| case 1 : |
| aload_1(); |
| break; |
| case 2 : |
| aload_2(); |
| break; |
| case 3 : |
| aload_3(); |
| break; |
| default : |
| aload(resolvedPosition); |
| } |
| } |
| } |
| |
| public void lookupswitch(CaseLabel defaultLabel, int[] keys, int[] sortedIndexes, CaseLabel[] casesLabel) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| int length = keys.length; |
| int pos = this.position; |
| defaultLabel.placeInstruction(); |
| for (int i = 0; i < length; i++) { |
| casesLabel[i].placeInstruction(); |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lookupswitch; |
| for (int i = (3 - (pos & 3)); i > 0; i--) { // faster than % 4 |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = 0; |
| } |
| defaultLabel.branch(); |
| writeSignedWord(length); |
| for (int i = 0; i < length; i++) { |
| writeSignedWord(keys[sortedIndexes[i]]); |
| casesLabel[sortedIndexes[i]].branch(); |
| } |
| } |
| |
| public void lor() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| pushTypeBinding(2, TypeBinding.LONG); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lor; |
| } |
| |
| public void lrem() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| pushTypeBinding(2, TypeBinding.LONG); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lrem; |
| } |
| |
| public void lreturn() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| // the stackDepth should be equal to 0 |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lreturn; |
| this.lastAbruptCompletion = this.position; |
| } |
| |
| public void lshl() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.LONG); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lshl; |
| } |
| |
| public void lshr() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.LONG); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lshr; |
| } |
| |
| public void lstore(int iArg) { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| if (this.maxLocals <= iArg + 1) { |
| this.maxLocals = iArg + 2; |
| } |
| if (iArg > 255) { // Widen |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lstore; |
| writeUnsignedShort(iArg); |
| } else { |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lstore; |
| this.bCodeStream[this.classFileOffset++] = (byte) iArg; |
| } |
| } |
| |
| public void lstore_0() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| if (this.maxLocals < 2) { |
| this.maxLocals = 2; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lstore_0; |
| } |
| |
| public void lstore_1() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| if (this.maxLocals < 3) { |
| this.maxLocals = 3; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lstore_1; |
| } |
| |
| public void lstore_2() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| if (this.maxLocals < 4) { |
| this.maxLocals = 4; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lstore_2; |
| } |
| |
| public void lstore_3() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| popTypeBinding(); |
| if (this.maxLocals < 5) { |
| this.maxLocals = 5; |
| } |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lstore_3; |
| } |
| |
| public void lsub() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| pushTypeBinding(2, TypeBinding.LONG); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lsub; |
| } |
| |
| public void lushr() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBinding(2, TypeBinding.LONG); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lushr; |
| } |
| |
| public void lxor() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| pushTypeBinding(2, TypeBinding.LONG); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lxor; |
| } |
| |
| public void monitorenter() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_monitorenter; |
| } |
| |
| public void monitorexit() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_monitorexit; |
| } |
| |
| public void multianewarray( |
| TypeReference typeReference, |
| TypeBinding typeBinding, |
| int dimensions, |
| ArrayAllocationExpression allocationExpression) { |
| this.countLabels = 0; |
| this.stackDepth += (1 - dimensions); |
| pushTypeBinding(dimensions, typeBinding); |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_multianewarray; |
| writeUnsignedShort(this.constantPool.literalIndexForType(typeBinding)); |
| this.bCodeStream[this.classFileOffset++] = (byte) dimensions; |
| } |
| |
| // We didn't call it new, because there is a conflict with the new keyword |
| public void new_(TypeBinding typeBinding) { |
| this.new_(null, typeBinding); |
| } |
| |
| // We didn't call it new, because there is a conflict with the new keyword |
| public void new_(TypeReference typeReference, TypeBinding typeBinding) { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(typeBinding); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_new; |
| writeUnsignedShort(this.constantPool.literalIndexForType(typeBinding)); |
| } |
| |
| public void newarray(int array_Type) { |
| this.countLabels = 0; |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_newarray; |
| this.bCodeStream[this.classFileOffset++] = (byte) array_Type; |
| pushTypeBinding(1, TypeBinding.wellKnownBaseType(array_Type)); |
| } |
| |
| public void newArray(ArrayBinding arrayBinding) { |
| this.newArray(null, null, arrayBinding); |
| } |
| |
| public void newArray(TypeReference typeReference, ArrayAllocationExpression allocationExpression, ArrayBinding arrayBinding) { |
| TypeBinding component = arrayBinding.elementsType(); |
| switch (component.id) { |
| case TypeIds.T_int : |
| newarray(ClassFileConstants.INT_ARRAY); |
| break; |
| case TypeIds.T_byte : |
| newarray(ClassFileConstants.BYTE_ARRAY); |
| break; |
| case TypeIds.T_boolean : |
| newarray(ClassFileConstants.BOOLEAN_ARRAY); |
| break; |
| case TypeIds.T_short : |
| newarray(ClassFileConstants.SHORT_ARRAY); |
| break; |
| case TypeIds.T_char : |
| newarray(ClassFileConstants.CHAR_ARRAY); |
| break; |
| case TypeIds.T_long : |
| newarray(ClassFileConstants.LONG_ARRAY); |
| break; |
| case TypeIds.T_float : |
| newarray(ClassFileConstants.FLOAT_ARRAY); |
| break; |
| case TypeIds.T_double : |
| newarray(ClassFileConstants.DOUBLE_ARRAY); |
| break; |
| default : |
| anewarray(component); |
| } |
| } |
| |
| public void newJavaLangAssertionError() { |
| // new: java.lang.AssertionError |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(ConstantPool.JavaLangAssertionErrorConstantPoolName); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_new; |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangAssertionErrorConstantPoolName)); |
| } |
| |
| public void newJavaLangError() { |
| // new: java.lang.Error |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(ConstantPool.JavaLangErrorConstantPoolName); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_new; |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangErrorConstantPoolName)); |
| } |
| public void newJavaLangIncompatibleClassChangeError() { |
| // new: java.lang.Error |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(ConstantPool.JavaLangIncompatibleClassChangeErrorConstantPoolName); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_new; |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangIncompatibleClassChangeErrorConstantPoolName)); |
| } |
| public void newNoClassDefFoundError() { |
| // new: java.lang.NoClassDefFoundError |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(ConstantPool.JavaLangNoClassDefFoundErrorConstantPoolName); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_new; |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangNoClassDefFoundErrorConstantPoolName)); |
| } |
| |
| public void newStringContatenation() { |
| // new: java.lang.StringBuffer |
| // new: java.lang.StringBuilder |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(ConstantPool.JavaLangStringBufferConstantPoolName); |
| if (this.stackDepth > this.stackMax) { |
| this.stackMax = this.stackDepth; |
| } |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_new; |
| if (this.targetLevel >= ClassFileConstants.JDK1_5) { |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangStringBuilderConstantPoolName)); |
| } else { |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangStringBufferConstantPoolName)); |
| } |
| } |
| |
| public void newWrapperFor(int typeID) { |
| this.countLabels = 0; |
| this.stackDepth++; |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset + 2 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_new; |
| switch (typeID) { |
| case TypeIds.T_int : // new: java.lang.Integer |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangIntegerConstantPoolName)); |
| pushTypeBinding(ConstantPool.JavaLangIntegerConstantPoolName); |
| break; |
| case TypeIds.T_boolean : // new: java.lang.Boolean |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangBooleanConstantPoolName)); |
| pushTypeBinding(ConstantPool.JavaLangBooleanConstantPoolName); |
| break; |
| case TypeIds.T_byte : // new: java.lang.Byte |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangByteConstantPoolName)); |
| pushTypeBinding(ConstantPool.JavaLangByteConstantPoolName); |
| break; |
| case TypeIds.T_char : // new: java.lang.Character |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangCharacterConstantPoolName)); |
| pushTypeBinding(ConstantPool.JavaLangCharacterConstantPoolName); |
| break; |
| case TypeIds.T_float : // new: java.lang.Float |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangFloatConstantPoolName)); |
| pushTypeBinding(ConstantPool.JavaLangFloatConstantPoolName); |
| break; |
| case TypeIds.T_double : // new: java.lang.Double |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangDoubleConstantPoolName)); |
| pushTypeBinding(ConstantPool.JavaLangDoubleConstantPoolName); |
| break; |
| case TypeIds.T_short : // new: java.lang.Short |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangShortConstantPoolName)); |
| pushTypeBinding(ConstantPool.JavaLangShortConstantPoolName); |
| break; |
| case TypeIds.T_long : // new: java.lang.Long |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangLongConstantPoolName)); |
| pushTypeBinding(ConstantPool.JavaLangLongConstantPoolName); |
| break; |
| case TypeIds.T_void : // new: java.lang.Void |
| writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangVoidConstantPoolName)); |
| pushTypeBinding(ConstantPool.JavaLangVoidConstantPoolName); |
| } |
| } |
| |
| public void nop() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_nop; |
| } |
| |
| public void optimizeBranch(int oldPosition, BranchLabel lbl) { |
| for (int i = 0; i < this.countLabels; i++) { |
| BranchLabel label = this.labels[i]; |
| if (oldPosition == label.position) { |
| label.position = this.position; |
| if (label instanceof CaseLabel) { |
| int offset = this.position - ((CaseLabel) label).instructionPosition; |
| int[] forwardRefs = label.forwardReferences(); |
| for (int j = 0, length = label.forwardReferenceCount(); j < length; j++) { |
| int forwardRef = forwardRefs[j]; |
| this.writeSignedWord(forwardRef, offset); |
| } |
| } else { |
| int[] forwardRefs = label.forwardReferences(); |
| for (int j = 0, length = label.forwardReferenceCount(); j < length; j++) { |
| final int forwardRef = forwardRefs[j]; |
| this.writePosition(lbl, forwardRef); |
| } |
| } |
| } |
| } |
| } |
| |
| public void pop() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_pop; |
| } |
| |
| private void adjustTypeBindingStackForPop2() { |
| if (!isSwitchStackTrackingActive()) |
| return; |
| TypeBinding v1 = this.switchSaveTypeBindings.peek(); |
| if (TypeIds.getCategory(v1.id) == 1) { |
| TypeBinding v2 = this.switchSaveTypeBindings.peek(); |
| if (TypeIds.getCategory(v2.id) == 1) { |
| popTypeBinding(2); |
| } |
| } else { |
| popTypeBinding(); |
| } |
| } |
| public void pop2() { |
| this.countLabels = 0; |
| this.stackDepth -= 2; |
| adjustTypeBindingStackForPop2(); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_pop2; |
| } |
| |
| public void pushExceptionOnStack(TypeBinding binding) { |
| this.stackDepth = 1; |
| // clearTypeBindingStack(); |
| pushTypeBinding(binding); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| } |
| |
| public void pushOnStack(TypeBinding binding) { |
| if (++this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| pushTypeBinding(binding); |
| } |
| |
| public void record(LocalVariableBinding local) { |
| if ((this.generateAttributes & (ClassFileConstants.ATTR_VARS |
| | ClassFileConstants.ATTR_STACK_MAP_TABLE |
| | ClassFileConstants.ATTR_STACK_MAP)) == 0) |
| return; |
| if (this.allLocalsCounter == this.locals.length) { |
| // resize the collection |
| System.arraycopy(this.locals, 0, this.locals = new LocalVariableBinding[this.allLocalsCounter + LOCALS_INCREMENT], 0, this.allLocalsCounter); |
| } |
| this.locals[this.allLocalsCounter++] = local; |
| local.initializationPCs = new int[4]; |
| local.initializationCount = 0; |
| } |
| |
| public void recordExpressionType(TypeBinding typeBinding) { |
| // nothing to do |
| } |
| public void recordExpressionType(TypeBinding typeBinding, int delta, boolean adjustStackDepth) { |
| // nothing to do |
| } |
| public void recordPositionsFrom(int startPC, int sourcePos) { |
| this.recordPositionsFrom(startPC, sourcePos, false); |
| } |
| |
| public void recordPositionsFrom(int startPC, int sourcePos, boolean widen) { |
| /* Record positions in the table, only if nothing has |
| * already been recorded. Since we output them on the way |
| * up (children first for more specific info) |
| * The pcToSourceMap table is always sorted. |
| */ |
| if ((this.generateAttributes & ClassFileConstants.ATTR_LINES) == 0 |
| || sourcePos == 0 |
| || (startPC == this.position && !widen) |
| || startPC > this.position) |
| return; |
| |
| // Widening an existing entry that already has the same source positions |
| if (this.pcToSourceMapSize + 4 > this.pcToSourceMap.length) { |
| // resize the array pcToSourceMap |
| System.arraycopy(this.pcToSourceMap, 0, this.pcToSourceMap = new int[this.pcToSourceMapSize << 1], 0, this.pcToSourceMapSize); |
| } |
| // lastEntryPC represents the endPC of the lastEntry. |
| if (this.pcToSourceMapSize > 0) { |
| int lineNumber = -1; |
| int previousLineNumber = this.pcToSourceMap[this.pcToSourceMapSize - 1]; |
| if (this.lineNumberStart == this.lineNumberEnd) { |
| // method on one line |
| lineNumber = this.lineNumberStart; |
| } else { |
| // Check next line number if this is the one we are looking for |
| int[] lineSeparatorPositions2 = this.lineSeparatorPositions; |
| int length = lineSeparatorPositions2.length; |
| if (previousLineNumber == 1) { |
| if (sourcePos < lineSeparatorPositions2[0]) { |
| lineNumber = 1; |
| } else if (length == 1 || sourcePos < lineSeparatorPositions2[1]) { |
| lineNumber = 2; |
| } |
| } else if (previousLineNumber < length) { |
| if (lineSeparatorPositions2[previousLineNumber - 2] < sourcePos) { |
| if (sourcePos < lineSeparatorPositions2[previousLineNumber - 1]) { |
| lineNumber = previousLineNumber; |
| } else if (sourcePos < lineSeparatorPositions2[previousLineNumber]) { |
| lineNumber = previousLineNumber + 1; |
| } |
| } |
| } else if (lineSeparatorPositions2[length - 1] < sourcePos) { |
| lineNumber = length + 1; |
| } |
| if(lineNumber == -1) { |
| // since lineSeparatorPositions is zero-based, we pass this.lineNumberStart - 1 and this.lineNumberEnd - 1 |
| lineNumber = Util.getLineNumber(sourcePos, lineSeparatorPositions2, this.lineNumberStart - 1, this.lineNumberEnd - 1); |
| } |
| } |
| // in this case there is already an entry in the table |
| if (previousLineNumber != lineNumber) { |
| if (startPC <= this.lastEntryPC) { |
| // we forgot to add an entry. |
| // search if an existing entry exists for startPC |
| int insertionIndex = insertionIndex(this.pcToSourceMap, this.pcToSourceMapSize, startPC); |
| if (insertionIndex != -1) { |
| // there is no existing entry starting with startPC. |
| if (!((insertionIndex > 1) && (this.pcToSourceMap[insertionIndex - 1] == lineNumber))) { |
| if(insertionIndex< this.pcToSourceMapSize && this.pcToSourceMap[insertionIndex + 1] == lineNumber) { |
| /* the entry at insertionIndex corresponds to an entry with the same line and a PC >= startPC. |
| in this case it is relevant to widen this entry instead of creating a new one. |
| line1: this(a, |
| b, |
| c); |
| with this code we generate each argument. We generate a aload0 to invoke the constructor. There is no entry for this |
| aload0 bytecode. The first entry is the one for the argument a. |
| But we want the constructor call to start at the aload0 pc and not just at the pc of the first argument. |
| So we widen the existing entry |
| */ |
| this.pcToSourceMap[insertionIndex] = startPC; |
| } else { |
| // we have to add an entry that won't be sorted. So we sort the pcToSourceMap. |
| System.arraycopy(this.pcToSourceMap, insertionIndex, this.pcToSourceMap, insertionIndex + 2, this.pcToSourceMapSize - insertionIndex); |
| this.pcToSourceMap[insertionIndex++] = startPC; |
| this.pcToSourceMap[insertionIndex] = lineNumber; |
| this.pcToSourceMapSize += 2; |
| } |
| } |
| } else if (this.position != this.lastEntryPC) { // no bytecode since last entry pc |
| if (this.lastEntryPC == startPC || this.lastEntryPC == this.pcToSourceMap[this.pcToSourceMapSize - 2]) { |
| this.pcToSourceMap[this.pcToSourceMapSize - 1] = lineNumber; |
| } else { |
| this.pcToSourceMap[this.pcToSourceMapSize++] = this.lastEntryPC; |
| this.pcToSourceMap[this.pcToSourceMapSize++] = lineNumber; |
| } |
| } else if (this.pcToSourceMap[this.pcToSourceMapSize - 1] < lineNumber && widen) { |
| // see if we can widen the existing entry |
| this.pcToSourceMap[this.pcToSourceMapSize - 1] = lineNumber; |
| } |
| } else { |
| // we can safely add the new entry. The endPC of the previous entry is not in conflit with the startPC of the new entry. |
| this.pcToSourceMap[this.pcToSourceMapSize++] = startPC; |
| this.pcToSourceMap[this.pcToSourceMapSize++] = lineNumber; |
| } |
| } else { |
| /* the last recorded entry is on the same line. But it could be relevant to widen this entry. |
| we want to extend this entry forward in case we generated some bytecode before the last entry that are not related to any statement |
| */ |
| if (startPC < this.pcToSourceMap[this.pcToSourceMapSize - 2]) { |
| int insertionIndex = insertionIndex(this.pcToSourceMap, this.pcToSourceMapSize, startPC); |
| if (insertionIndex != -1) { |
| // widen the existing entry |
| // we have to figure out if we need to move the last entry at another location to keep a sorted table |
| /* First we need to check if at the insertion position there is not an existing entry |
| * that includes the one we want to insert. This is the case if pcToSourceMap[insertionIndex - 1] == newLine. |
| * In this case we don't want to change the table. If not, we want to insert a new entry. Prior to insertion |
| * we want to check if it is worth doing an arraycopy. If not we simply update the recorded pc. |
| */ |
| if (!((insertionIndex > 1) && (this.pcToSourceMap[insertionIndex - 1] == lineNumber))) { |
| if (this.pcToSourceMap[insertionIndex + 1] != lineNumber) { |
| System.arraycopy(this.pcToSourceMap, insertionIndex, this.pcToSourceMap, insertionIndex + 2, this.pcToSourceMapSize - insertionIndex); |
| this.pcToSourceMap[insertionIndex++] = startPC; |
| this.pcToSourceMap[insertionIndex] = lineNumber; |
| this.pcToSourceMapSize += 2; |
| } else { |
| this.pcToSourceMap[insertionIndex] = startPC; |
| } |
| } |
| } |
| } |
| } |
| this.lastEntryPC = this.position; |
| } else { |
| int lineNumber = 0; |
| if (this.lineNumberStart == this.lineNumberEnd) { |
| // method on one line |
| lineNumber = this.lineNumberStart; |
| } else { |
| // since lineSeparatorPositions is zero-based, we pass this.lineNumberStart - 1 and this.lineNumberEnd - 1 |
| lineNumber = Util.getLineNumber(sourcePos, this.lineSeparatorPositions, this.lineNumberStart - 1, this.lineNumberEnd - 1); |
| } |
| // record the first entry |
| this.pcToSourceMap[this.pcToSourceMapSize++] = startPC; |
| this.pcToSourceMap[this.pcToSourceMapSize++] = lineNumber; |
| this.lastEntryPC = this.position; |
| } |
| } |
| /** |
| * @param anExceptionLabel org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel |
| */ |
| public void registerExceptionHandler(ExceptionLabel anExceptionLabel) { |
| int length; |
| if (this.exceptionLabelsCounter == (length = this.exceptionLabels.length)) { |
| // resize the exception handlers table |
| System.arraycopy(this.exceptionLabels, 0, this.exceptionLabels = new ExceptionLabel[length + LABELS_INCREMENT], 0, length); |
| } |
| // no need to resize. So just add the new exception label |
| this.exceptionLabels[this.exceptionLabelsCounter++] = anExceptionLabel; |
| } |
| |
| public void removeNotDefinitelyAssignedVariables(Scope scope, int initStateIndex) { |
| // given some flow info, make sure we did not loose some variables initialization |
| // if this happens, then we must update their pc entries to reflect it in debug attributes |
| if ((this.generateAttributes & (ClassFileConstants.ATTR_VARS |
| | ClassFileConstants.ATTR_STACK_MAP_TABLE |
| | ClassFileConstants.ATTR_STACK_MAP)) == 0) |
| return; |
| for (int i = 0; i < this.visibleLocalsCount; i++) { |
| LocalVariableBinding localBinding = this.visibleLocals[i]; |
| if (localBinding != null && !isDefinitelyAssigned(scope, initStateIndex, localBinding) && localBinding.initializationCount > 0) { |
| localBinding.recordInitializationEndPC(this.position); |
| } |
| } |
| } |
| |
| /** |
| * Remove all entries in pcToSourceMap table that are beyond this.position |
| */ |
| public void removeUnusedPcToSourceMapEntries() { |
| if (this.pcToSourceMapSize != 0) { |
| while (this.pcToSourceMapSize >= 2 && this.pcToSourceMap[this.pcToSourceMapSize - 2] > this.position) { |
| this.pcToSourceMapSize -= 2; |
| } |
| } |
| } |
| public void removeVariable(LocalVariableBinding localBinding) { |
| if (localBinding == null) return; |
| if (localBinding.initializationCount > 0) { |
| localBinding.recordInitializationEndPC(this.position); |
| } |
| for (int i = this.visibleLocalsCount - 1; i >= 0; i--) { |
| LocalVariableBinding visibleLocal = this.visibleLocals[i]; |
| if (visibleLocal == localBinding){ |
| this.visibleLocals[i] = null; // this variable is no longer visible afterwards |
| return; |
| } |
| } |
| } |
| |
| /** |
| * @param referenceMethod org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration |
| * @param targetClassFile org.eclipse.jdt.internal.compiler.codegen.ClassFile |
| */ |
| public void reset(AbstractMethodDeclaration referenceMethod, ClassFile targetClassFile) { |
| init(targetClassFile); |
| this.methodDeclaration = referenceMethod; |
| this.lambdaExpression = null; |
| int[] lineSeparatorPositions2 = this.lineSeparatorPositions; |
| if (lineSeparatorPositions2 != null) { |
| int length = lineSeparatorPositions2.length; |
| int lineSeparatorPositionsEnd = length - 1; |
| if (referenceMethod.isClinit() |
| || referenceMethod.isConstructor()) { |
| this.lineNumberStart = 1; |
| this.lineNumberEnd = length == 0 ? 1 : length; |
| } else { |
| int start = Util.getLineNumber(referenceMethod.bodyStart, lineSeparatorPositions2, 0, lineSeparatorPositionsEnd); |
| this.lineNumberStart = start; |
| if (start > lineSeparatorPositionsEnd) { |
| this.lineNumberEnd = start; |
| } else { |
| int end = Util.getLineNumber(referenceMethod.bodyEnd, lineSeparatorPositions2, start - 1, lineSeparatorPositionsEnd); |
| if (end >= lineSeparatorPositionsEnd) { |
| end = length; |
| } |
| this.lineNumberEnd = end == 0 ? 1 : end; |
| } |
| } |
| } |
| this.preserveUnusedLocals = referenceMethod.scope.compilerOptions().preserveAllLocalVariables; |
| initializeMaxLocals(referenceMethod.binding); |
| } |
| |
| public void reset(LambdaExpression lambda, ClassFile targetClassFile) { |
| init(targetClassFile); |
| this.lambdaExpression = lambda; |
| this.methodDeclaration = null; |
| int[] lineSeparatorPositions2 = this.lineSeparatorPositions; |
| if (lineSeparatorPositions2 != null) { |
| int length = lineSeparatorPositions2.length; |
| int lineSeparatorPositionsEnd = length - 1; |
| int start = Util.getLineNumber(lambda.body().sourceStart, lineSeparatorPositions2, 0, lineSeparatorPositionsEnd); |
| this.lineNumberStart = start; |
| if (start > lineSeparatorPositionsEnd) { |
| this.lineNumberEnd = start; |
| } else { |
| int end = Util.getLineNumber(lambda.body().sourceEnd, lineSeparatorPositions2, start - 1, lineSeparatorPositionsEnd); |
| if (end >= lineSeparatorPositionsEnd) { |
| end = length; |
| } |
| this.lineNumberEnd = end == 0 ? 1 : end; |
| } |
| |
| } |
| this.preserveUnusedLocals = lambda.scope.compilerOptions().preserveAllLocalVariables; |
| initializeMaxLocals(lambda.binding); |
| } |
| |
| public void reset(ClassFile givenClassFile) { |
| this.targetLevel = givenClassFile.targetJDK; |
| int produceAttributes = givenClassFile.produceAttributes; |
| this.generateAttributes = produceAttributes; |
| if ((produceAttributes & ClassFileConstants.ATTR_LINES) != 0 && givenClassFile.referenceBinding != null) { |
| this.lineSeparatorPositions = givenClassFile.referenceBinding.scope.referenceCompilationUnit().compilationResult.getLineSeparatorPositions(); |
| } else { |
| this.lineSeparatorPositions = null; |
| } |
| } |
| |
| /** |
| * @param targetClassFile The given classfile to reset the code stream |
| */ |
| public void resetForProblemClinit(ClassFile targetClassFile) { |
| init(targetClassFile); |
| initializeMaxLocals(null); |
| } |
| |
| public void resetInWideMode() { |
| this.wideMode = true; |
| } |
| public void resetForCodeGenUnusedLocals() { |
| // nothing to do in standard code stream |
| } |
| private final void resizeByteArray() { |
| int length = this.bCodeStream.length; |
| int requiredSize = length + length; |
| if (this.classFileOffset >= requiredSize) { |
| // must be sure to grow enough |
| requiredSize = this.classFileOffset + length; |
| } |
| System.arraycopy(this.bCodeStream, 0, this.bCodeStream = new byte[requiredSize], 0, length); |
| } |
| |
| final public void ret(int index) { |
| this.countLabels = 0; |
| if (index > 255) { // Widen |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ret; |
| writeUnsignedShort(index); |
| } else { // Don't Widen |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ret; |
| this.bCodeStream[this.classFileOffset++] = (byte) index; |
| } |
| } |
| |
| public void return_() { |
| this.countLabels = 0; |
| // the stackDepth should be equal to 0 |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_return; |
| this.lastAbruptCompletion = this.position; |
| } |
| |
| public void saload() { |
| this.countLabels = 0; |
| this.stackDepth--; |
| pushTypeBindingArray(); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_saload; |
| } |
| |
| public void sastore() { |
| this.countLabels = 0; |
| this.stackDepth -= 3; |
| popTypeBinding(3); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_sastore; |
| } |
| |
| /** |
| * @param operatorConstant int |
| * @param type_ID int |
| */ |
| public void sendOperator(int operatorConstant, int type_ID) { |
| switch (type_ID) { |
| case TypeIds.T_int : |
| case TypeIds.T_boolean : |
| case TypeIds.T_char : |
| case TypeIds.T_byte : |
| case TypeIds.T_short : |
| switch (operatorConstant) { |
| case OperatorIds.PLUS : |
| iadd(); |
| break; |
| case OperatorIds.MINUS : |
| isub(); |
| break; |
| case OperatorIds.MULTIPLY : |
| imul(); |
| break; |
| case OperatorIds.DIVIDE : |
| idiv(); |
| break; |
| case OperatorIds.REMAINDER : |
| irem(); |
| break; |
| case OperatorIds.LEFT_SHIFT : |
| ishl(); |
| break; |
| case OperatorIds.RIGHT_SHIFT : |
| ishr(); |
| break; |
| case OperatorIds.UNSIGNED_RIGHT_SHIFT : |
| iushr(); |
| break; |
| case OperatorIds.AND : |
| iand(); |
| break; |
| case OperatorIds.OR : |
| ior(); |
| break; |
| case OperatorIds.XOR : |
| ixor(); |
| break; |
| } |
| break; |
| case TypeIds.T_long : |
| switch (operatorConstant) { |
| case OperatorIds.PLUS : |
| ladd(); |
| break; |
| case OperatorIds.MINUS : |
| lsub(); |
| break; |
| case OperatorIds.MULTIPLY : |
| lmul(); |
| break; |
| case OperatorIds.DIVIDE : |
| ldiv(); |
| break; |
| case OperatorIds.REMAINDER : |
| lrem(); |
| break; |
| case OperatorIds.LEFT_SHIFT : |
| lshl(); |
| break; |
| case OperatorIds.RIGHT_SHIFT : |
| lshr(); |
| break; |
| case OperatorIds.UNSIGNED_RIGHT_SHIFT : |
| lushr(); |
| break; |
| case OperatorIds.AND : |
| land(); |
| break; |
| case OperatorIds.OR : |
| lor(); |
| break; |
| case OperatorIds.XOR : |
| lxor(); |
| break; |
| } |
| break; |
| case TypeIds.T_float : |
| switch (operatorConstant) { |
| case OperatorIds.PLUS : |
| fadd(); |
| break; |
| case OperatorIds.MINUS : |
| fsub(); |
| break; |
| case OperatorIds.MULTIPLY : |
| fmul(); |
| break; |
| case OperatorIds.DIVIDE : |
| fdiv(); |
| break; |
| case OperatorIds.REMAINDER : |
| frem(); |
| } |
| break; |
| case TypeIds.T_double : |
| switch (operatorConstant) { |
| case OperatorIds.PLUS : |
| dadd(); |
| break; |
| case OperatorIds.MINUS : |
| dsub(); |
| break; |
| case OperatorIds.MULTIPLY : |
| dmul(); |
| break; |
| case OperatorIds.DIVIDE : |
| ddiv(); |
| break; |
| case OperatorIds.REMAINDER : |
| drem(); |
| } |
| } |
| } |
| |
| public void sipush(int s) { |
| this.countLabels = 0; |
| this.stackDepth++; |
| pushTypeBinding(TypeBinding.SHORT); |
| if (this.stackDepth > this.stackMax) |
| this.stackMax = this.stackDepth; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_sipush; |
| writeSignedShort(s); |
| } |
| |
| public void store(LocalVariableBinding localBinding, boolean valueRequired) { |
| int localPosition = localBinding.resolvedPosition; |
| // Using dedicated int bytecode |
| switch(localBinding.type.id) { |
| case TypeIds.T_int : |
| case TypeIds.T_char : |
| case TypeIds.T_byte : |
| case TypeIds.T_short : |
| case TypeIds.T_boolean : |
| if (valueRequired) |
| dup(); |
| switch (localPosition) { |
| case 0 : |
| istore_0(); |
| break; |
| case 1 : |
| istore_1(); |
| break; |
| case 2 : |
| istore_2(); |
| break; |
| case 3 : |
| istore_3(); |
| break; |
| //case -1 : |
| // internal failure: trying to store into variable not supposed to be generated |
| // break; |
| default : |
| istore(localPosition); |
| } |
| break; |
| case TypeIds.T_float : |
| if (valueRequired) |
| dup(); |
| switch (localPosition) { |
| case 0 : |
| fstore_0(); |
| break; |
| case 1 : |
| fstore_1(); |
| break; |
| case 2 : |
| fstore_2(); |
| break; |
| case 3 : |
| fstore_3(); |
| break; |
| default : |
| fstore(localPosition); |
| } |
| break; |
| case TypeIds.T_double : |
| if (valueRequired) |
| dup2(); |
| switch (localPosition) { |
| case 0 : |
| dstore_0(); |
| break; |
| case 1 : |
| dstore_1(); |
| break; |
| case 2 : |
| dstore_2(); |
| break; |
| case 3 : |
| dstore_3(); |
| break; |
| default : |
| dstore(localPosition); |
| } |
| break; |
| case TypeIds.T_long : |
| if (valueRequired) |
| dup2(); |
| switch (localPosition) { |
| case 0 : |
| lstore_0(); |
| break; |
| case 1 : |
| lstore_1(); |
| break; |
| case 2 : |
| lstore_2(); |
| break; |
| case 3 : |
| lstore_3(); |
| break; |
| default : |
| lstore(localPosition); |
| } |
| break; |
| default: |
| // Reference object |
| if (valueRequired) |
| dup(); |
| switch (localPosition) { |
| case 0 : |
| astore_0(); |
| break; |
| case 1 : |
| astore_1(); |
| break; |
| case 2 : |
| astore_2(); |
| break; |
| case 3 : |
| astore_3(); |
| break; |
| default : |
| astore(localPosition); |
| } |
| } |
| } |
| |
| public void swap() { |
| this.countLabels = 0; |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_swap; |
| } |
| |
| public void tableswitch(CaseLabel defaultLabel, int low, int high, int[] keys, int[] sortedIndexes, int[] mapping, CaseLabel[] casesLabel) { |
| this.countLabels = 0; |
| this.stackDepth--; |
| popTypeBinding(); |
| int length = casesLabel.length; |
| int pos = this.position; |
| defaultLabel.placeInstruction(); |
| for (int i = 0; i < length; i++) |
| casesLabel[i].placeInstruction(); |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_tableswitch; |
| // padding |
| for (int i = (3 - (pos & 3)); i > 0; i--) { |
| if (this.classFileOffset >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position++; |
| this.bCodeStream[this.classFileOffset++] = 0; |
| } |
| defaultLabel.branch(); |
| writeSignedWord(low); |
| writeSignedWord(high); |
| int i = low, j = low; |
| // the index j is used to know if the index i is one of the missing entries in case of an |
| // optimized tableswitch |
| while (true) { |
| int index; |
| int key = keys[index = sortedIndexes[j - low]]; |
| if (key == i) { |
| casesLabel[mapping[index]].branch(); |
| j++; |
| if (i == high) break; // if high is maxint, then avoids wrapping to minint. |
| } else { |
| defaultLabel.branch(); |
| } |
| i++; |
| } |
| } |
| |
| public void throwAnyException(LocalVariableBinding anyExceptionVariable) { |
| this.load(anyExceptionVariable); |
| athrow(); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder buffer = new StringBuilder("( position:"); //$NON-NLS-1$ |
| buffer.append(this.position); |
| buffer.append(",\nstackDepth:"); //$NON-NLS-1$ |
| buffer.append(this.stackDepth); |
| buffer.append(",\nmaxStack:"); //$NON-NLS-1$ |
| buffer.append(this.stackMax); |
| buffer.append(",\nmaxLocals:"); //$NON-NLS-1$ |
| buffer.append(this.maxLocals); |
| buffer.append(")"); //$NON-NLS-1$ |
| return buffer.toString(); |
| } |
| protected void writePosition(BranchLabel label) { |
| int offset = label.position - this.position + 1; |
| if (Math.abs(offset) > 0x7FFF && !this.wideMode) { |
| throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE, null); |
| } |
| this.writeSignedShort(offset); |
| int[] forwardRefs = label.forwardReferences(); |
| for (int i = 0, max = label.forwardReferenceCount(); i < max; i++) { |
| this.writePosition(label, forwardRefs[i]); |
| } |
| } |
| |
| protected void writePosition(BranchLabel label, int forwardReference) { |
| final int offset = label.position - forwardReference + 1; |
| if (Math.abs(offset) > 0x7FFF && !this.wideMode) { |
| throw new AbortMethod(CodeStream.RESTART_IN_WIDE_MODE, null); |
| } |
| if (this.wideMode) { |
| if ((label.tagBits & BranchLabel.WIDE) != 0) { |
| this.writeSignedWord(forwardReference, offset); |
| } else { |
| this.writeSignedShort(forwardReference, offset); |
| } |
| } else { |
| this.writeSignedShort(forwardReference, offset); |
| } |
| } |
| |
| /** |
| * Write a signed 16 bits value into the byte array |
| * @param value the signed short |
| */ |
| private final void writeSignedShort(int value) { |
| // we keep the resize in here because it is used outside the code stream |
| if (this.classFileOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = (byte) (value >> 8); |
| this.bCodeStream[this.classFileOffset++] = (byte) value; |
| } |
| |
| private final void writeSignedShort(int pos, int value) { |
| int currentOffset = this.startingClassFileOffset + pos; |
| if (currentOffset + 1 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.bCodeStream[currentOffset] = (byte) (value >> 8); |
| this.bCodeStream[currentOffset + 1] = (byte) value; |
| } |
| |
| protected final void writeSignedWord(int value) { |
| // we keep the resize in here because it is used outside the code stream |
| if (this.classFileOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.position += 4; |
| this.bCodeStream[this.classFileOffset++] = (byte) ((value & 0xFF000000) >> 24); |
| this.bCodeStream[this.classFileOffset++] = (byte) ((value & 0xFF0000) >> 16); |
| this.bCodeStream[this.classFileOffset++] = (byte) ((value & 0xFF00) >> 8); |
| this.bCodeStream[this.classFileOffset++] = (byte) (value & 0xFF); |
| } |
| |
| protected void writeSignedWord(int pos, int value) { |
| int currentOffset = this.startingClassFileOffset + pos; |
| if (currentOffset + 3 >= this.bCodeStream.length) { |
| resizeByteArray(); |
| } |
| this.bCodeStream[currentOffset++] = (byte) ((value & 0xFF000000) >> 24); |
| this.bCodeStream[currentOffset++] = (byte) ((value & 0xFF0000) >> 16); |
| this.bCodeStream[currentOffset++] = (byte) ((value & 0xFF00) >> 8); |
| this.bCodeStream[currentOffset++] = (byte) (value & 0xFF); |
| } |
| |
| /** |
| * Write a unsigned 16 bits value into the byte array |
| * @param value the unsigned short |
| */ |
| private final void writeUnsignedShort(int value) { |
| // no bound check since used only from within codestream where already checked |
| this.position += 2; |
| this.bCodeStream[this.classFileOffset++] = (byte) (value >>> 8); |
| this.bCodeStream[this.classFileOffset++] = (byte) value; |
| } |
| |
| protected void writeWidePosition(BranchLabel label) { |
| int labelPos = label.position; |
| int offset = labelPos - this.position + 1; |
| this.writeSignedWord(offset); |
| int[] forwardRefs = label.forwardReferences(); |
| for (int i = 0, max = label.forwardReferenceCount(); i < max; i++) { |
| int forward = forwardRefs[i]; |
| offset = labelPos - forward + 1; |
| this.writeSignedWord(forward, offset); |
| } |
| } |
| private boolean isSwitchStackTrackingActive() { |
| return this.methodDeclaration != null && this.methodDeclaration.containsSwitchWithTry; |
| } |
| private TypeBinding retrieveLocalType(int currentPC, int resolvedPosition) { |
| for (int i = this.allLocalsCounter - 1 ; i >= 0; i--) { |
| LocalVariableBinding localVariable = this.locals[i]; |
| if (localVariable == null) continue; |
| if (resolvedPosition == localVariable.resolvedPosition) { |
| inits: for (int j = 0; j < localVariable.initializationCount; j++) { |
| int startPC = localVariable.initializationPCs[j << 1]; |
| int endPC = localVariable.initializationPCs[(j << 1) + 1]; |
| if (currentPC < startPC) { |
| continue inits; |
| } else if (endPC == -1) { // still live |
| // the current local is an active local |
| return localVariable.type; |
| } else if (currentPC < endPC) { |
| // the current local is an active local |
| return localVariable.type; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| private void pushTypeBinding(int resolvedPosition) { |
| if (!isSwitchStackTrackingActive()) |
| return; |
| assert resolvedPosition < this.maxLocals; |
| TypeBinding type = retrieveLocalType(this.position, resolvedPosition); |
| if (type == null && resolvedPosition == 0 && !this.methodDeclaration.isStatic()) { |
| type = this.methodDeclaration.binding.declaringClass; // thisReference.resolvedType |
| } |
| assert type != null; |
| pushTypeBinding(type); |
| } |
| private void pushTypeBindingArray() { |
| if (!isSwitchStackTrackingActive()) |
| return; |
| assert this.switchSaveTypeBindings.size() >= 2; // atleast arrayref and index in the typebinding stack |
| TypeBinding[] arrayref_t = {popTypeBinding()/* index */, popTypeBinding()/* arrayref */}; |
| TypeBinding type = arrayref_t[1]; // arrayref |
| assert type instanceof ArrayBinding; |
| pushTypeBinding(((ArrayBinding) type).leafComponentType); |
| } |
| private TypeBinding getPopularBinding(char[] typeName) { |
| Scope scope = this.classFile.referenceBinding.scope; |
| assert scope != null; |
| Supplier<ReferenceBinding> finder = scope.getCommonReferenceBinding(typeName); |
| return finder != null ? finder.get() : TypeBinding.NULL; |
| } |
| |
| private void pushTypeBinding(char[] typeName) { |
| if (!isSwitchStackTrackingActive()) |
| return; |
| pushTypeBinding(getPopularBinding(typeName)); |
| } |
| private void pushTypeBinding(TypeBinding typeBinding) { |
| if (isSwitchStackTrackingActive()) { |
| assert typeBinding != null; |
| this.switchSaveTypeBindings.push(typeBinding); |
| } |
| } |
| private void pushTypeBinding(int nPop, TypeBinding typeBinding) { |
| if (!isSwitchStackTrackingActive()) |
| return; |
| popTypeBinding(nPop); |
| pushTypeBinding(typeBinding); |
| } |
| private TypeBinding popTypeBinding() { |
| return isSwitchStackTrackingActive() ? this.switchSaveTypeBindings.pop() : null; |
| } |
| private void popTypeBinding(int nPop) { |
| if (!isSwitchStackTrackingActive()) |
| return; |
| for (int i = 0; i< nPop; ++i) |
| popTypeBinding(); |
| } |
| public void clearTypeBindingStack() { |
| if (!isSwitchStackTrackingActive()) |
| return; |
| this.switchSaveTypeBindings.clear(); |
| } |
| } |