Skip to content
Draft
Show file tree
Hide file tree
Changes from 110 commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
9a765e2
Add verifier with phi resolution
danocmx Nov 25, 2025
09ac5b8
Handle constants and simple loops
danocmx Nov 25, 2025
d3dc97d
Fix StackSlot as label argument not working
danocmx Nov 25, 2025
51efb03
Make sure both previous and current values are present
danocmx Nov 25, 2025
8692753
Resolve phi variables from usage
danocmx Dec 2, 2025
ffe73e6
Optionally, resolve from jumps
danocmx Dec 2, 2025
3a7a664
Check for kind constraints
danocmx Dec 3, 2025
d80f0b8
Get target register by walking from first usage backwards
danocmx Dec 9, 2025
cefa342
Resolve variables from predecessor states
danocmx Dec 9, 2025
25128e7
Fix issues stemming from unit tests
danocmx Jan 5, 2026
69224db
Make sure speculative instruction is not missed
danocmx Jan 5, 2026
0775f2a
Resolve more variable locations
danocmx Jan 5, 2026
15eb8a4
Store all locations in one Map
danocmx Jan 6, 2026
872b321
Tag constants instead of moving them in FromJump resolver
danocmx Jan 6, 2026
b197244
Fix FromUsage resolver exploding in memory usage
danocmx Jan 6, 2026
b40a31d
Add readable error messages instead of asserts
danocmx Jan 7, 2026
f48e6d5
Check if register can be allocated
danocmx Jan 7, 2026
6e8dda9
Add missing exception
danocmx Jan 7, 2026
d84dd18
Use correct label instruction for label resolution error
danocmx Jan 19, 2026
c767c15
Fix logic bug in CircularDefinitionError
danocmx Jan 19, 2026
d260760
Fix trailing comma in LabelNotResolvedError
danocmx Jan 19, 2026
a3bd670
Add string representation for RAVInstruction
danocmx Jan 19, 2026
92c489a
Propagate variables with more accuracy
danocmx Jan 19, 2026
37b76d4
Add source to ValueAllocationState
danocmx Jan 19, 2026
3f7060e
Resolve materialized constants to variables
danocmx Jan 19, 2026
2ee75cf
Create a materialization conflict resolver
danocmx Jan 19, 2026
e3f33b2
Resolve from usage globally
danocmx Jan 19, 2026
569612d
Extract values from FrameState and verify its contents
danocmx Jan 21, 2026
00aa04a
Fix typo in ValueNotInRegisterException
danocmx Jan 30, 2026
2ae6469
Make sure variable can rematerialze as constant
danocmx Jan 30, 2026
4c7cc15
Add shared state for verifier phases
danocmx Jan 30, 2026
fd9d692
Remove unused memory map
danocmx Jan 30, 2026
499c44d
Split resolvers into their own classes
danocmx Jan 30, 2026
13fbbf6
Use more predecessors to resolve FromJump
danocmx Jan 30, 2026
a99f31d
Handle canRematerializeToStack for conflict resolution
danocmx Jan 30, 2026
cfa4627
Dump debug file on error
danocmx Jan 31, 2026
040c121
Add base Move class
danocmx Jan 31, 2026
5ed9c42
Move register check to AllocationStateMap
danocmx Jan 31, 2026
1bfa592
Add method selection logic to shared state
danocmx Jan 31, 2026
7cf409d
Flip logic for skipping files
danocmx Feb 14, 2026
1659f70
Store RAVInstruction as source
danocmx Feb 14, 2026
4bec15f
Change LinkedList usage to ArrayList where possible
danocmx Feb 14, 2026
76c0091
Change line endings to LF
danocmx Feb 14, 2026
ba197a5
Fix checkstyle issues
danocmx Feb 14, 2026
88e7d1e
Format code
danocmx Feb 14, 2026
ac00e5e
Wrap Value class for data structure indexing
danocmx Feb 15, 2026
786849a
Resolve todos
danocmx Feb 15, 2026
6f2564f
Make Unknown state create conflicts
danocmx Feb 17, 2026
05a32e6
Save register in exception
danocmx Feb 17, 2026
a598465
Add comments to verifer classes
danocmx Feb 18, 2026
89478c1
Do not use IllegalStateException
danocmx Feb 18, 2026
37dc5e3
Check if variable and its alias are equal
danocmx Feb 18, 2026
b061de7
Add license header
danocmx Feb 21, 2026
24afdde
Switch instaceof for ValueTool(s)
danocmx Feb 23, 2026
c7e2528
Remove old code and do refactoring
danocmx Mar 2, 2026
984a91f
Add tests for the verifier
danocmx Mar 2, 2026
13faefd
Remove phi resolution option
danocmx Mar 2, 2026
aec2780
Save values from ByteCodeFrame
danocmx Mar 3, 2026
0431f9c
Handle allocated stack slot
danocmx Mar 3, 2026
5fd14e0
Wrap around allocators
danocmx Mar 4, 2026
4b211b5
Make stack allocator verification optional
danocmx Mar 4, 2026
b07fce0
Handle callee saved registers
danocmx Mar 6, 2026
919995d
Change rav debug file format
danocmx Mar 6, 2026
d11b100
Check for java kinds from frames
danocmx Mar 7, 2026
e0a266e
Remove block argument in block state
danocmx Mar 12, 2026
9d641da
Add references list
danocmx Mar 12, 2026
225c9a0
Overwrite virtual stack slot in ValueMove
danocmx Mar 13, 2026
362858d
Update backup stack slot of a stack move
danocmx Mar 14, 2026
49baaa7
Fix issues when resolving variables
danocmx Mar 14, 2026
664f145
Move vstack to stack conversion for value moves
danocmx Mar 17, 2026
6b80ecf
Fix location warning in RegAllocVerifierTest
danocmx Mar 17, 2026
8b49f49
Check move kinds against state value being moved
danocmx Mar 17, 2026
c7b1080
Build references before final stage for verification
danocmx Mar 17, 2026
25779b4
Modify tests to pass verifier
danocmx Mar 17, 2026
12c14aa
Add @link to comments
danocmx Mar 17, 2026
8f88fa2
Fix warnings from ci
danocmx Mar 18, 2026
b9febcf
Run eclipse formatter
danocmx Mar 18, 2026
0b6de17
Run style check again
danocmx Mar 18, 2026
6cfce85
Run the formatter again
danocmx Mar 18, 2026
a47d947
Remove hotspot instructions
danocmx Mar 18, 2026
ac7a94e
Verify references list
danocmx Mar 21, 2026
6a91b75
Fix derived refs and native pointers
danocmx Mar 23, 2026
3dbe57f
Fix warnings from gate
danocmx Mar 23, 2026
2bfa987
Enable verifier by default for tests
danocmx Mar 23, 2026
1859d38
Add synonym map for weird virtual move cases
danocmx Mar 23, 2026
fbd27b1
Refactor label variable resolver
danocmx Mar 25, 2026
c28a22b
Skip register check for prealloc moves
danocmx Mar 25, 2026
47b29c3
Handle callee-saved values from virtual moves
danocmx Mar 26, 2026
1ff83e7
Check for kinds in value moves
danocmx Mar 26, 2026
67b2751
Fix resolver merge state base
danocmx Mar 26, 2026
6e159b8
Change synonym map to a conflict resolver
danocmx Mar 26, 2026
eb80d21
Run formatter
danocmx Mar 26, 2026
7d9daf5
Remove unused block parameter
danocmx Mar 26, 2026
1eb15c7
Handle variable synonyms in constant materialization
danocmx Mar 27, 2026
20a21e0
Add sources to synonym variable states
danocmx Mar 27, 2026
570de05
Refactor conflict resolver logic in checkOperand
danocmx Mar 27, 2026
3012298
Run formatter
danocmx Mar 27, 2026
68acbac
Improve debug file logging
danocmx Apr 1, 2026
ea465ec
Add test for infinite loop
danocmx Apr 1, 2026
25596b8
Add test for callee-saved registers
danocmx Apr 3, 2026
6180508
Add tests for other exceptions
danocmx Apr 4, 2026
689ffd0
Fix minor issues
danocmx Apr 4, 2026
f81cca6
Make references a set and remove worklist.remove(block)
danocmx Apr 8, 2026
615f0c9
Move ConflictResolver prepare stage
danocmx Apr 8, 2026
715d93b
Add test for deleted reference
danocmx Apr 8, 2026
f95f9cf
Fix access to overloaded instruction in exceptions
danocmx Apr 8, 2026
54e1cba
Add FailOnFirst option
danocmx Apr 8, 2026
5544c9d
Run spellcheck for comments
danocmx Apr 8, 2026
bbb3941
Adjust debuf file output
danocmx Apr 10, 2026
cc4dbe1
Add missing Override
danocmx Apr 10, 2026
219c6c1
Changes based on review
danocmx Apr 29, 2026
dd401b4
Fix amr related issues
danocmx Apr 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2026, 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
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.graal.compiler.lir.alloc.verifier;

import jdk.graal.compiler.core.common.cfg.BasicBlock;

/**
* Violation of the alive inputs occurred, the same location was marked as alive argument as well as
* temp or output.
*/
@SuppressWarnings("serial")
public class AliveConstraintViolationException extends RAVException {
public RAVInstruction.Op instruction;

/**
* Construct an AliveConstraintViolationException.
*
* @param instruction Instruction where violation occurred
* @param block Block where violation occurred
* @param location Location that is being shared
* @param asDest Alive location was used as an output
*/
public AliveConstraintViolationException(RAVInstruction.Op instruction, BasicBlock<?> block, RAValue location, boolean asDest) {
super(AliveConstraintViolationException.getErrorMessage(location, asDest), instruction, block);
this.instruction = instruction;
}

static String getErrorMessage(RAValue location, boolean asDest) {
if (asDest) {
return "Location " + location + " used as both alive and output";
}

return "Location " + location + " used as both alive and temp";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2026, 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
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.graal.compiler.lir.alloc.verifier;

import jdk.graal.compiler.core.common.cfg.BasicBlock;

/**
* Interface for state concrete location is in, stored in {@link AllocationStateMap}.
*/
public abstract class AllocationState {
/**
* Get the default allocation state for every location, instead of null, we have
* {@link UnknownAllocationState unknown} state.
*
* @return Default state for every location
*/
public static AllocationState getDefault() {
return UnknownAllocationState.INSTANCE;
}

/**
* Shortcut to check if state is {@link UnknownAllocationState unknown}.
*
* @return Is {@link UnknownAllocationState unknown state}
*/
public boolean isUnknown() {
return false;
}

/**
* Shortcut to check if state is {@link ConflictedAllocationState conflicted}.
*
* @return Is {@link ConflictedAllocationState conflicted}
*/
public boolean isConflicted() {
return false;
}

/**
* Create a copy of this state, necessary for state copies made over program graph edges.
*
* @return Newly copied state
*/
@Override
public abstract AllocationState clone();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that you should implement the Cloneable interface if you override Object.clone().


/**
* Meet a state from a different block coming from an edge in the program graph, decide what the
* result of said two states should be.
*
* @param other The other state coming from a predecessor edge
* @param otherBlock Which block is other state from
* @param block Which state is this state from?
* @return What is the new state the location is in.
*/
public abstract AllocationState meet(AllocationState other, BasicBlock<?> otherBlock, BasicBlock<?> block);

public abstract boolean equals(AllocationState other);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
* Copyright (c) 2026, 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
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.graal.compiler.lir.alloc.verifier;

import jdk.graal.compiler.core.common.LIRKind;
import jdk.graal.compiler.core.common.alloc.RegisterAllocationConfig;
import jdk.graal.compiler.core.common.cfg.BasicBlock;
import jdk.graal.compiler.util.EconomicHashMap;
import jdk.graal.compiler.util.EconomicHashSet;
import jdk.vm.ci.meta.ValueKind;

import java.util.Map;
import java.util.Set;

/**
* Mapping between a location and allocation state that stores one of these: -
* {@link UnknownAllocationState unknown} - our null state, nothing was stored yet -
* {@link ValueAllocationState value} - symbol that is stored at said location -
* {@link ConflictedAllocationState conflicted} - set of Values that are supposed to be at same
* location
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated formatting destroyed your list, please use proper HTML list syntax in Javadoc comments.

*
* <p>
* Conflicts are resolved by assigning new {@link ValueAllocationState value} to same location.
* Otherwise, they cannot be used. {@link ValueAllocationState Value} can store register, stack
* slot, constant, but most importantly variables used before allocation. These are what we are
* checking with the verification process.
* </p>
*/
public class AllocationStateMap {
protected BasicBlock<?> block;

/**
* Internal map maintaining the mapping.
*/
protected Map<RAValue, AllocationState> internalMap;

/**
* Map of casts for locations that was forced by allocator-inserted move, see
* {@link BlockVerifierState#isMoveKindChange}.
*/
protected Map<RAValue, ValueKind<LIRKind>> castMap;

/**
* Register allocation config describing which registers can be used.
*/
protected RegisterAllocationConfig registerAllocationConfig;

public AllocationStateMap(BasicBlock<?> block, RegisterAllocationConfig registerAllocationConfig) {
internalMap = new EconomicHashMap<>();
castMap = new EconomicHashMap<>();
this.block = block;
this.registerAllocationConfig = registerAllocationConfig;
}

public AllocationStateMap(BasicBlock<?> block, AllocationStateMap other) {
internalMap = new EconomicHashMap<>(other.internalMap);
castMap = new EconomicHashMap<>(other.castMap);
registerAllocationConfig = other.registerAllocationConfig;
this.block = block;
}

public boolean has(RAValue key) {
return internalMap.containsKey(key);
}

public AllocationState get(RAValue key) {
return this.get(key, AllocationState.getDefault());
}

public AllocationState get(RAValue key, AllocationState defaultValue) {
var state = internalMap.get(key);
if (state == null) {
return defaultValue;
}
return state;
}

/**
* Put a new state for location to the map, while checking if register can be allocated to.
*
* @param key Location used
* @param state State to store
*/
public void put(RAValue key, AllocationState state, RAVInstruction.Base instruction) {
this.checkRegisterDestinationValidity(key, instruction);
putWithoutRegCheck(key, state);
}

/**
* Put a new state for location to the map, without checking if the register can actually be
* used.
*
* <p>
* This is useful for registers that are used by the ABI in the first label but can actually
* never be changed, like rbp.
* </p>
*
* @param key Location used
* @param state State to store
*/
public void putWithoutRegCheck(RAValue key, AllocationState state) {
internalMap.put(key, state);
castMap.remove(key); // Always remove the cast when new value is inserted.
}

/**
* Put a copied state to a location, used when merging.
*
* @param key Location used
* @param state State to store
*/
public void putClone(RAValue key, AllocationState state, RAVInstruction.Base instruction) {
if (state.isUnknown()) {
this.put(key, state, instruction);
return;
}

this.put(key, state.clone(), instruction);
}

/**
* Get the set of locations holding this particular variable/constant.
*
* @param value Symbol we are looking for
* @return Set of locations holding the symbol
*/
public Set<RAValue> getValueLocations(RAValue value) {
Set<RAValue> locations = new EconomicHashSet<>();
for (var entry : this.internalMap.entrySet()) {
if (entry.getValue() instanceof ValueAllocationState valState) {
if (valState.getRAValue().equals(value)) {
locations.add(entry.getKey());
}
}
}
return locations;
}

/**
* Merge two maps, a source is generally the predecessor to the current block (this state map).
*
* @param source Predecessor merging to here
* @return Was this map changed?
*/
public boolean mergeWith(AllocationStateMap source) {
boolean changed = false;
for (var entry : source.internalMap.entrySet()) {
if (!this.internalMap.containsKey(entry.getKey())) {
changed = true;

this.putWithoutRegCheck(entry.getKey(), UnknownAllocationState.INSTANCE);
}

var currentValue = this.internalMap.get(entry.getKey());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method would be a bit cleaner if you did this get once and then used the result everywhere, including currentValue == null instead of the containsKey call.

var result = this.internalMap.get(entry.getKey()).meet(entry.getValue(), source.block, this.block);
if (!currentValue.equals(result)) {
changed = true;
}

this.putWithoutRegCheck(entry.getKey(), result);
}

castMap.putAll(source.castMap); // This should not affect the merge logic
return changed;
}

/**
* Check if register can be used by the register allocator. If not allowed, an exception is
* thrown.
*
* @param location Value that could be a register.
*/
protected void checkRegisterDestinationValidity(RAValue location, RAVInstruction.Base instruction) {
if (!location.isRegister()) {
return;
}

// Equality check so we know that this change was made by the register allocator.
var register = location.asRegister().getRegister();
if (!this.registerAllocationConfig.getAllocatableRegisters().contains(register)) {
throw new InvalidRegisterUsedException(register, instruction, block);
}
}
}
Loading
Loading