< prev index next > src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java
Print this page
import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import java.util.function.ToIntBiFunction;
- import java.util.function.ToIntFunction;
import static com.sun.tools.javac.code.TypeTag.ARRAY;
import static com.sun.tools.javac.code.TypeTag.BOT;
import static com.sun.tools.javac.code.TypeTag.DOUBLE;
import static com.sun.tools.javac.code.TypeTag.INT;
import static com.sun.tools.javac.code.TypeTag.LONG;
! import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
import static com.sun.tools.javac.jvm.ByteCodes.*;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref;
- import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
import static com.sun.tools.javac.jvm.UninitializedType.*;
import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
import java.util.Arrays;
/** An internal structure that corresponds to the code attribute of
import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import java.util.function.ToIntBiFunction;
import static com.sun.tools.javac.code.TypeTag.ARRAY;
import static com.sun.tools.javac.code.TypeTag.BOT;
import static com.sun.tools.javac.code.TypeTag.DOUBLE;
import static com.sun.tools.javac.code.TypeTag.INT;
import static com.sun.tools.javac.code.TypeTag.LONG;
! import static com.sun.tools.javac.code.TypeTag.UNINITIALIZED_THIS;
import static com.sun.tools.javac.jvm.ByteCodes.*;
import static com.sun.tools.javac.jvm.UninitializedType.*;
import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
import java.util.Arrays;
/** An internal structure that corresponds to the code attribute of
final MethodSymbol meth;
private int letExprStackPos = 0;
+ /** The initial unset strict fields in this method frame
+ */
+ public List<VarSymbol> initialUnsetFields = List.nil();
+
+ boolean generateEarlyLarvalFrame;
+
/** Construct a code object, given the settings of the fatcode,
* debugging info switches and the CharacterRangeTable.
*/
public Code(MethodSymbol meth,
boolean fatcode,
StackMapFormat stackMap,
boolean debugCode,
CRTable crt,
Symtab syms,
Types types,
! PoolWriter poolWriter) {
this.meth = meth;
this.fatcode = fatcode;
this.lineMap = lineMap;
this.lineDebugInfo = lineMap != null;
this.varDebugInfo = varDebugInfo;
StackMapFormat stackMap,
boolean debugCode,
CRTable crt,
Symtab syms,
Types types,
! PoolWriter poolWriter,
+ boolean generateEarlyLarvalFrame) {
this.meth = meth;
this.fatcode = fatcode;
this.lineMap = lineMap;
this.lineDebugInfo = lineMap != null;
this.varDebugInfo = varDebugInfo;
default:
this.needStackMap = false;
}
state = new State();
lvar = new LocalVar[20];
+ this.generateEarlyLarvalFrame = generateEarlyLarvalFrame;
+ }
+
+ void initUnsetStrictFields(ClassSymbol csym) {
+ int strictFieldOffset = 0;
+ for (Symbol s : csym.members().getSymbols(Symbol::isStrictInstance)) {
+ VarSymbol strictField = (VarSymbol)s;
+ strictField.adr = strictFieldOffset++;
+ initialUnsetFields = initialUnsetFields.prepend(strictField); // lookup returns symbols in reversed order
+ state.unsetStrict.incl(strictField.adr);
+ }
}
/* **************************************************************************
* Typecodes & related stuff
break;
case goto_:
markDead();
break;
case putfield:
! state.pop(((Symbol)data).erasure(types));
state.pop(1); // object ref
break;
case getfield:
state.pop(1); // object ref
state.push(((Symbol)data).erasure(types));
break;
case goto_:
markDead();
break;
case putfield:
! VarSymbol field = (VarSymbol)data;
+ state.pop(field.erasure(types));
+ if (field.isStrictInstance() &&
+ field.owner == meth.owner &&
+ state.peek().hasTag(UNINITIALIZED_THIS)) {
+ state.unsetStrict.excl(field.adr);
+ }
state.pop(1); // object ref
break;
case getfield:
state.pop(1); // object ref
state.push(((Symbol)data).erasure(types));
default:
throw new AssertionError(mnem(op));
}
// postop();
}
-
/** Emit an opcode with a four-byte operand field.
*/
public void emitop4(int op, int od) {
emitop(op);
if (!alive) return;
/** An entry in the stack map. */
static class StackMapFrame {
int pc;
Type[] locals;
Type[] stack;
+ List<VarSymbol> unsetFields;
}
/** A buffer of cldc stack map entries. */
StackMapFrame[] stackMapBuffer = null;
}
StackMapFrame frame = new StackMapFrame();
frame.pc = pc;
int localCount = 0;
Type[] locals = new Type[localsSize];
for (int i=0; i<localsSize; i++, localCount++) {
if (state.defined.isMember(i) && lvar[i] != null) {
Type vtype = lvar[i].sym.type;
! if (!(vtype instanceof UninitializedType))
vtype = types.erasure(vtype);
locals[i] = vtype;
if (width(vtype) > 1) i++;
}
}
frame.locals = new Type[localCount];
}
StackMapFrame frame = new StackMapFrame();
frame.pc = pc;
+ boolean hasUninitializedThis = false;
int localCount = 0;
Type[] locals = new Type[localsSize];
for (int i=0; i<localsSize; i++, localCount++) {
if (state.defined.isMember(i) && lvar[i] != null) {
Type vtype = lvar[i].sym.type;
! if (!(vtype instanceof UninitializedType)) {
vtype = types.erasure(vtype);
+ } else if (vtype.hasTag(TypeTag.UNINITIALIZED_THIS)) {
+ hasUninitializedThis = true;
+ }
locals[i] = vtype;
if (width(vtype) > 1) i++;
}
}
frame.locals = new Type[localCount];
if (state.stack[i] != null) {
frame.stack[stackCount++] = types.erasure(state.stack[i]);
}
}
if (stackMapTableBuffer == null) {
stackMapTableBuffer = new StackMapTableFrame[20];
} else {
stackMapTableBuffer = ArrayUtils.ensureCapacity(
stackMapTableBuffer,
stackMapBufferSize);
}
! stackMapTableBuffer[stackMapBufferSize++] =
! StackMapTableFrame.getInstance(frame, lastFrame.pc, lastFrame.locals, types);
frameBeforeLast = lastFrame;
lastFrame = frame;
}
StackMapFrame getInitialFrame() {
StackMapFrame frame = new StackMapFrame();
List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes;
int len = arg_types.length();
int count = 0;
if (state.stack[i] != null) {
frame.stack[stackCount++] = types.erasure(state.stack[i]);
}
}
+ List<VarSymbol> unsetStrictFields = collectUnsetStrictFields();
+ boolean encloseWithEarlyLarvalFrame = generateEarlyLarvalFrame && hasUninitializedThis
+ && !lastFrame.unsetFields.equals(unsetStrictFields);
+
if (stackMapTableBuffer == null) {
stackMapTableBuffer = new StackMapTableFrame[20];
} else {
stackMapTableBuffer = ArrayUtils.ensureCapacity(
stackMapTableBuffer,
stackMapBufferSize);
}
!
! StackMapTableFrame tableFrame = StackMapTableFrame.getInstance(frame, lastFrame, types, pc);
+ if (encloseWithEarlyLarvalFrame) {
+ tableFrame = new StackMapTableFrame.EarlyLarvalFrame(tableFrame, unsetStrictFields);
+ frame.unsetFields = unsetStrictFields;
+ } else {
+ frame.unsetFields = lastFrame.unsetFields;
+ }
+ stackMapTableBuffer[stackMapBufferSize++] = tableFrame;
frameBeforeLast = lastFrame;
lastFrame = frame;
}
+ List<VarSymbol> collectUnsetStrictFields() {
+ return initialUnsetFields.stream()
+ .filter(s -> state.unsetStrict.isMember(s.adr))
+ .collect(List.collector());
+ }
+
StackMapFrame getInitialFrame() {
StackMapFrame frame = new StackMapFrame();
List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes;
int len = arg_types.length();
int count = 0;
for (Type arg_type : arg_types) {
frame.locals[count++] = types.erasure(arg_type);
}
frame.pc = -1;
frame.stack = null;
+ frame.unsetFields = initialUnsetFields;
return frame;
}
/* ************************************************************************
/** Resolve chain to point to given target.
*/
public void resolve(Chain chain, int target) {
boolean changed = false;
State newState = state;
+ int originalTarget = target;
for (; chain != null; chain = chain.next) {
Assert.check(state != chain.state
&& (target > chain.pc || isStatementStart()));
if (target >= cp) {
target = cp;
// from the instruction before goto_.
alive = true;
break;
}
} else {
! if (fatcode)
put4(chain.pc + 1, target - chain.pc);
else if (target - chain.pc < Short.MIN_VALUE ||
target - chain.pc > Short.MAX_VALUE)
fatcode = true;
! else
put2(chain.pc + 1, target - chain.pc);
Assert.check(!alive ||
chain.state.stacksize == newState.stacksize &&
chain.state.nlocks == newState.nlocks);
}
fixedPc = true;
// from the instruction before goto_.
alive = true;
break;
}
} else {
! if (fatcode) {
put4(chain.pc + 1, target - chain.pc);
+ }
else if (target - chain.pc < Short.MIN_VALUE ||
target - chain.pc > Short.MAX_VALUE)
fatcode = true;
! else {
put2(chain.pc + 1, target - chain.pc);
+ }
Assert.check(!alive ||
chain.state.stacksize == newState.stacksize &&
chain.state.nlocks == newState.nlocks);
}
fixedPc = true;
class State implements Cloneable {
/** The set of registers containing values. */
Bits defined;
+ /** The unset strict fields. */
+ Bits unsetStrict;
+
/** The (types of the) contents of the machine stack. */
Type[] stack;
/** The first stack position currently unused. */
int stacksize;
int[] locks;
int nlocks;
State() {
defined = new Bits();
+ unsetStrict = new Bits();
stack = new Type[16];
}
State dup() {
try {
State state = (State)super.clone();
state.defined = new Bits(defined);
+ state.unsetStrict = new Bits(unsetStrict);
state.stack = stack.clone();
if (locks != null) state.locks = locks.clone();
if (debugCode) {
System.err.println("duping state " + this);
dump();
}
}
State join(State other) {
defined.andSet(other.defined);
+ unsetStrict.orSet(other.unsetStrict);
Assert.check(stacksize == other.stacksize
&& nlocks == other.nlocks);
for (int i=0; i<stacksize; ) {
Type t = stack[i];
Type tother = other.stack[i];
< prev index next >