package com.oracle.svm.truffle.nfi;
import java.util.ArrayList;
import org.graalvm.compiler.word.Word;
import org.graalvm.nativeimage.PinnedObject;
import org.graalvm.word.PointerBase;
import org.graalvm.word.WordFactory;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
public final class LocalNativeScope implements AutoCloseable {
private final LocalNativeScope parent;
private final short scopeId;
private int pinCount;
private final PinnedObject[] pinned;
private ArrayList<Object> localHandles;
LocalNativeScope(LocalNativeScope parent, int patchCount) {
this.parent = parent;
if (parent == null) {
scopeId = 1;
} else {
assert parent.scopeId < Short.MAX_VALUE;
scopeId = (short) (parent.scopeId + 1);
}
pinCount = 0;
pinned = patchCount > 0 ? new PinnedObject[patchCount] : null;
localHandles = null;
}
public TruffleObjectHandle createLocalHandle(Object obj) {
if (localHandles == null) {
localHandles = new ArrayList<>();
}
int idx = localHandles.size();
localHandles.add(obj);
assert localHandles.get(idx) == obj;
return (TruffleObjectHandle) WordFactory.unsigned(idx).shiftLeft(16).or(scopeId & 0xFFFF).not();
}
private LocalNativeScope findScope(short id) {
LocalNativeScope cur = this;
while (cur != null && cur.scopeId > id) {
cur = cur.parent;
}
if (cur != null && cur.scopeId == id) {
return cur;
} else {
return null;
}
}
public Object resolveLocalHandle(TruffleObjectHandle handle) {
Word word = ((Word) handle).not();
short handleScopeId = (short) word.and(0xFFFF).rawValue();
LocalNativeScope scope = findScope(handleScopeId);
if (scope != null) {
int idx = (int) word.unsignedShiftRight(16).rawValue();
return scope.localHandles.get(idx);
} else {
return null;
}
}
@TruffleBoundary
PointerBase pinArray(Object arr) {
PinnedObject ret = PinnedObject.create(arr);
pinned[pinCount++] = ret;
return ret.addressOfArrayElement(0);
}
@TruffleBoundary
PointerBase pinString(String str) {
byte[] array = TruffleNFISupport.javaStringToUtf8(str);
return pinArray(array);
}
@Override
public void close() {
for (int i = 0; i < pinCount; i++) {
pinned[i].close();
}
TruffleNFISupport.closeLocalScope(this, parent);
}
}