Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/main/java/cod/interpreter/InterpreterVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ public Object visit(Field n) {
throw new ProgramError("Cannot redeclare field: " + n.name);
}
}
ctx.objectInstance.fields.put(n.name, val);
ctx.setObjectField(n.name, val);
return val;
}

Expand Down
119 changes: 113 additions & 6 deletions src/main/java/cod/interpreter/context/ExecutionContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ protected Integer initialValue() {
private boolean inOptimizedLoop = false;
private List<Object> pendingOutputs = new ArrayList<Object>();
private boolean unsafeExecutionContext = false;
private IdentityHashMap<Object, Map<Long, Integer>> activeBorrowsByContainer;

// ========== TYPE HANDLER ==========
private final TypeHandler typeHandler;
Expand Down Expand Up @@ -155,6 +156,7 @@ public ExecutionContext(ObjectInstance obj, Map<String, Object> locals,
this.currentMethodName = null;
this.currentLambdaClosure = null;
this.typeHandler = typeHandler;
this.activeBorrowsByContainer = new IdentityHashMap<Object, Map<Long, Integer>>();

// Initialize locals
this.localsStack = new ArrayList<Map<String, Object>>();
Expand All @@ -176,6 +178,7 @@ public ExecutionContext(ObjectInstance obj, Map<String, Object> locals,

// Build optimized slot access structures
optimizeSlotAccess();
registerInitialBorrowState(initialLocals);
}

/**
Expand Down Expand Up @@ -236,7 +239,8 @@ public void setSlotValue(String slotName, Object value) {
}

// Update both representations
slotValues.put(slotName, value);
Object previous = slotValues.put(slotName, value);
replaceTrackedValue(previous, value);

if (slotsOptimized && slotIndexMap.containsKey(slotName)) {
int index = slotIndexMap.get(slotName);
Expand Down Expand Up @@ -326,7 +330,10 @@ public void pushScope() {

public void popScope() {
if (localsStack.size() > 1) {
localsStack.remove(localsStack.size() - 1);
Map<String, Object> removedScope = localsStack.remove(localsStack.size() - 1);
for (Object value : removedScope.values()) {
unregisterBorrowsFromValue(value);
}
localTypesStack.remove(localTypesStack.size() - 1);
}
}
Expand Down Expand Up @@ -373,14 +380,16 @@ public void setVariable(String name, Object value) {
for (int i = localsStack.size() - 1; i >= 0; i--) {
Map<String, Object> scope = localsStack.get(i);
if (scope.containsKey(name)) {
scope.put(name, value);
Object previous = scope.put(name, value);
replaceTrackedValue(previous, value);
return;
}
}

// Create in current scope
Map<String, Object> currentScope = localsStack.get(localsStack.size() - 1);
currentScope.put(name, value);
Object previous = currentScope.put(name, value);
replaceTrackedValue(previous, value);
}

public String getVariableType(String name) {
Expand Down Expand Up @@ -423,7 +432,9 @@ public Object removeVariable(String name) {
for (int i = localsStack.size() - 1; i >= 0; i--) {
Map<String, Object> scope = localsStack.get(i);
if (scope.containsKey(name)) {
return scope.remove(name);
Object removed = scope.remove(name);
unregisterBorrowsFromValue(removed);
return removed;
}
}
return null;
Expand All @@ -440,7 +451,8 @@ public boolean removeVariableFromAllScopes(String name) {
for (int i = localsStack.size() - 1; i >= 0; i--) {
Map<String, Object> scope = localsStack.get(i);
if (scope.containsKey(name)) {
scope.remove(name);
Object removed = scope.remove(name);
unregisterBorrowsFromValue(removed);
found = true;
}
}
Expand All @@ -461,6 +473,29 @@ public ExecutionContext copyWithVariable(String name, Object value, String type)

return new ExecutionContext(objectInstance, newLocals, slotValues, slotTypes, typeHandler);
}

public void setObjectField(String fieldName, Object value) {
if (fieldName == null) {
throw new InternalError("setObjectField called with null fieldName");
}
if (objectInstance == null || objectInstance.fields == null) {
throw new InternalError("setObjectField called outside object context");
}
Object previous = objectInstance.fields.put(fieldName, value);
replaceTrackedValue(previous, value);
}

public boolean hasActiveBorrow(Object container, long index) {
if (container == null) return false;
Map<Long, Integer> countsByIndex = activeBorrowsByContainer.get(container);
if (countsByIndex == null) return false;
Integer count = countsByIndex.get(index);
return count != null && count > 0;
}

public void trackValueReplacement(Object oldValue, Object newValue) {
replaceTrackedValue(oldValue, newValue);
}

// Clear slot optimization (if slots change)
public void rebuildSlotOptimization() {
Expand All @@ -471,4 +506,76 @@ public void rebuildSlotOptimization() {
this.slotTypesList = null;
optimizeSlotAccess();
}

private void registerInitialBorrowState(Map<String, Object> initialLocals) {
if (initialLocals != null) {
for (Object value : initialLocals.values()) {
registerBorrowsFromValue(value);
}
}
if (slotValues != null) {
for (Object value : slotValues.values()) {
registerBorrowsFromValue(value);
}
}
if (objectInstance != null && objectInstance.fields != null) {
for (Object value : objectInstance.fields.values()) {
registerBorrowsFromValue(value);
}
}
}

private void replaceTrackedValue(Object oldValue, Object newValue) {
unregisterBorrowsFromValue(oldValue);
registerBorrowsFromValue(newValue);
}

private void registerBorrowsFromValue(Object value) {
collectBorrowsRecursive(value, 1);
}

private void unregisterBorrowsFromValue(Object value) {
collectBorrowsRecursive(value, -1);
}

@SuppressWarnings("unchecked")
private void collectBorrowsRecursive(Object value, int delta) {
if (value == null) return;
Object unwrapped = typeHandler.unwrap(value);
if (unwrapped == null) return;

if (unwrapped instanceof TypeHandler.PointerValue) {
TypeHandler.PointerValue pointer = (TypeHandler.PointerValue) unwrapped;
updateBorrowCount(pointer.container, pointer.index, delta);
return;
}

if (unwrapped instanceof List) {
for (Object element : (List<Object>) unwrapped) {
collectBorrowsRecursive(element, delta);
}
}
}

private void updateBorrowCount(Object container, long index, int delta) {
if (container == null || delta == 0) return;

Map<Long, Integer> countsByIndex = activeBorrowsByContainer.get(container);
if (countsByIndex == null) {
if (delta < 0) return;
countsByIndex = new HashMap<Long, Integer>();
activeBorrowsByContainer.put(container, countsByIndex);
}

Integer current = countsByIndex.get(index);
int next = (current != null ? current : 0) + delta;
if (next > 0) {
countsByIndex.put(index, next);
} else {
countsByIndex.remove(index);
if (countsByIndex.isEmpty()) {
activeBorrowsByContainer.remove(container);
}
}
}
}
61 changes: 9 additions & 52 deletions src/main/java/cod/interpreter/handler/AssignmentHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -189,15 +189,18 @@ private Object handleIndexAssignment(IndexAccess indexAccess, Object newValue, E
NaturalArray natural = (NaturalArray) arrayObj;
long index = expressionHandler.toLongIndex(indexObj);
ensureNoActiveBorrow(arrayObj, index, ctx);
Object previous = natural.get(index);
natural.set(index, newValue);
ctx.trackValueReplacement(previous, newValue);
return newValue;
}

if (arrayObj instanceof List) {
int intIndex = expressionHandler.toIntIndex(indexObj);
ensureNoActiveBorrow(arrayObj, intIndex, ctx);
List<Object> list = (List<Object>) arrayObj;
list.set(intIndex, newValue);
Object previous = list.set(intIndex, newValue);
ctx.trackValueReplacement(previous, newValue);
return newValue;
}

Expand Down Expand Up @@ -338,15 +341,7 @@ private void ensureNoActiveBorrow(Object container, long index, ExecutionContext
if (!isBorrowCheckerActive(ctx)) {
return;
}
if (hasBorrowInLocals(container, index, ctx.getLocalsStack())) {
throwBorrowMutationViolation(index);
}
if (ctx.objectInstance != null
&& ctx.objectInstance.fields != null
&& hasBorrowInMap(container, index, ctx.objectInstance.fields)) {
throwBorrowMutationViolation(index);
}
if (ctx.getSlotValues() != null && hasBorrowInMap(container, index, ctx.getSlotValues())) {
if (ctx.hasActiveBorrow(container, index)) {
throwBorrowMutationViolation(index);
}
}
Expand All @@ -359,44 +354,6 @@ private boolean isBorrowCheckerActive(ExecutionContext ctx) {
return ctx != null && (ctx.isUnsafeExecutionContext() || (ctx.currentClass != null && ctx.currentClass.isUnsafe));
}

private boolean hasBorrowInLocals(Object container, long index, List<Map<String, Object>> scopes) {
if (scopes == null) return false;
for (Map<String, Object> scope : scopes) {
if (hasBorrowInMap(container, index, scope)) {
return true;
}
}
return false;
}

private boolean hasBorrowInMap(Object container, long index, Map<String, Object> values) {
if (values == null || values.isEmpty()) return false;
for (Object value : values.values()) {
if (containsBorrowForLocation(typeSystem.unwrap(value), container, index)) {
return true;
}
}
return false;
}

@SuppressWarnings("unchecked")
private boolean containsBorrowForLocation(Object value, Object container, long index) {
if (value == null) return false;
if (value instanceof TypeHandler.PointerValue) {
TypeHandler.PointerValue pointer = (TypeHandler.PointerValue) value;
return pointer.container == container && pointer.index == index;
}
if (value instanceof List) {
List<Object> list = (List<Object>) value;
for (Object element : list) {
if (containsBorrowForLocation(typeSystem.unwrap(element), container, index)) {
return true;
}
}
}
return false;
}

private Object handleVariableAssignment(Expr target, Object newValue, ExecutionContext ctx) {
try {
if (target instanceof PropertyAccess) {
Expand Down Expand Up @@ -459,7 +416,7 @@ public Object assignToVariableScoped(String varName, Object newValue, ExecutionC
if (NamingValidator.isAllCaps(varName)) {
throw new ProgramError("Cannot reassign constant field '" + varName + "'");
}
ctx.objectInstance.fields.put(varName, newValue);
ctx.setObjectField(varName, newValue);
return newValue;
}
}
Expand All @@ -484,7 +441,7 @@ private Object updateVariableInScope(String varName, Object newValue,
newValue = typeSystem.wrapUnionType(newValue, declaredType);
}

scope.put(varName, newValue);
ctx.setVariable(varName, newValue);
return newValue;
} catch (ProgramError e) {
throw e;
Expand All @@ -501,7 +458,7 @@ private Object assignToField(String fieldName, Object newValue, ExecutionContext
if (NamingValidator.isAllCaps(fieldName)) {
throw new ProgramError("Cannot reassign constant field '" + fieldName + "'");
}
ctx.objectInstance.fields.put(fieldName, newValue);
ctx.setObjectField(fieldName, newValue);
return newValue;
} else {
throw new ProgramError("Cannot assign to undefined field via this: " + fieldName);
Expand Down Expand Up @@ -535,7 +492,7 @@ private Object assignToSuperField(String fieldName, Object newValue, ExecutionCo
if (NamingValidator.isAllCaps(fieldName)) {
throw new ProgramError("Cannot reassign constant field '" + fieldName + "'");
}
ctx.objectInstance.fields.put(fieldName, newValue);
ctx.setObjectField(fieldName, newValue);
return newValue;
}
throw new ProgramError("Cannot assign to undefined field via super: " + fieldName);
Expand Down