< prev index next > src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java
Print this page
/*
! * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
/*
! * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
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.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.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
* methods in a classfile. The class also provides some utility operations to
* generate bytecode instructions.
*
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.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.jvm.ByteCodes.*;
import static com.sun.tools.javac.jvm.UninitializedType.*;
! import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableEntry;
import java.util.Arrays;
+ import java.util.Map;
+ import java.util.HashMap;
+ import java.util.Set;
/** An internal structure that corresponds to the code attribute of
* methods in a classfile. The class also provides some utility operations to
* generate bytecode instructions.
*
final MethodSymbol meth;
private int letExprStackPos = 0;
+ private Map<Integer, Set<VarSymbol>> cpToUnsetFieldsMap = new HashMap<>();
+
+ public Set<VarSymbol> currentUnsetFields;
+
+ boolean generateAssertUnsetFieldsFrame;
+
/** 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 generateAssertUnsetFieldsFrame) {
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.generateAssertUnsetFieldsFrame = generateAssertUnsetFieldsFrame;
}
/* **************************************************************************
* Typecodes & related stuff
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;
}
/** A buffer of cldc stack map entries. */
StackMapFrame[] stackMapBuffer = null;
/** A buffer of compressed StackMapTable entries. */
! StackMapTableFrame[] stackMapTableBuffer = null;
int stackMapBufferSize = 0;
/** The last PC at which we generated a stack map. */
int lastStackMapPC = -1;
/** An entry in the stack map. */
static class StackMapFrame {
int pc;
Type[] locals;
Type[] stack;
+ Set<VarSymbol> unsetFields;
}
/** A buffer of cldc stack map entries. */
StackMapFrame[] stackMapBuffer = null;
/** A buffer of compressed StackMapTable entries. */
! StackMapTableEntry[] stackMapTableBuffer = null;
int stackMapBufferSize = 0;
/** The last PC at which we generated a stack map. */
int lastStackMapPC = -1;
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]);
}
}
+ Set<VarSymbol> unsetFieldsAtPC = cpToUnsetFieldsMap.get(pc);
+ boolean generateAssertUnsetFieldsEntry = unsetFieldsAtPC != null && generateAssertUnsetFieldsFrame;
+
if (stackMapTableBuffer == null) {
! stackMapTableBuffer = new StackMapTableEntry[20];
} else {
stackMapTableBuffer = ArrayUtils.ensureCapacity(
stackMapTableBuffer,
! stackMapBufferSize + (generateAssertUnsetFieldsEntry ? 1 : 0));
+ }
+
+ if (generateAssertUnsetFieldsEntry) {
+ if (lastFrame.unsetFields == null || !lastFrame.unsetFields.equals(unsetFieldsAtPC)) {
+ stackMapTableBuffer[stackMapBufferSize++] = new StackMapTableEntry.AssertUnsetFields(pc, unsetFieldsAtPC);
+ frame.unsetFields = unsetFieldsAtPC;
+ }
}
stackMapTableBuffer[stackMapBufferSize++] =
! StackMapTableEntry.getInstance(frame, lastFrame, types, pc);
frameBeforeLast = lastFrame;
lastFrame = frame;
}
+ public void addUnsetFieldsAtPC(int pc, Set<VarSymbol> unsetFields) {
+ cpToUnsetFieldsMap.put(pc, unsetFields);
+ }
+
StackMapFrame getInitialFrame() {
StackMapFrame frame = new StackMapFrame();
List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes;
int len = arg_types.length();
int count = 0;
}
if (opcode != dontgoto && isAlive()) {
result = new Chain(emitJump(opcode),
result,
state.dup());
+ if (currentUnsetFields != null) {
+ addUnsetFieldsAtPC(result.pc, currentUnsetFields);
+ }
fixedPc = fatcode;
if (opcode == goto_) alive = false;
}
return result;
}
/** 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);
+ if (cpToUnsetFieldsMap.get(chain.pc) != null) {
+ addUnsetFieldsAtPC(originalTarget, cpToUnsetFieldsMap.get(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);
+ if (cpToUnsetFieldsMap.get(chain.pc) != null) {
+ addUnsetFieldsAtPC(originalTarget, cpToUnsetFieldsMap.get(chain.pc));
+ }
+ }
Assert.check(!alive ||
chain.state.stacksize == newState.stacksize &&
chain.state.nlocks == newState.nlocks);
}
fixedPc = true;
< prev index next >