package com.oracle.truffle.js.nodes.access;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.FrameSlotKind;
import com.oracle.truffle.api.frame.FrameUtil;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.js.nodes.JavaScriptNode;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.objects.Dead;
public abstract class FrameSlotNode extends JavaScriptNode {
protected final FrameSlot frameSlot;
protected FrameSlotNode(FrameSlot frameSlot) {
assert frameSlot != null : "Frame slot must not be null";
this.frameSlot = frameSlot;
}
public final FrameSlot getFrameSlot() {
return frameSlot;
}
public final Object getIdentifier() {
return frameSlot.getIdentifier();
}
public abstract ScopeFrameNode getLevelFrameNode();
protected final boolean getBoolean(Frame frame) {
return FrameUtil.getBooleanSafe(frame, frameSlot);
}
protected final int getInt(Frame frame) {
return FrameUtil.getIntSafe(frame, frameSlot);
}
protected final double getDouble(Frame frame) {
return FrameUtil.getDoubleSafe(frame, frameSlot);
}
protected final Object getObject(Frame frame) {
return FrameUtil.getObjectSafe(frame, frameSlot);
}
protected final long getLong(Frame frame) {
return FrameUtil.getLongSafe(frame, frameSlot);
}
protected final boolean isBoolean(Frame frame) {
return frame.isBoolean(frameSlot);
}
protected final boolean isInt(Frame frame) {
return frame.isInt(frameSlot);
}
protected final boolean isDouble(Frame frame) {
return frame.isDouble(frameSlot);
}
protected final boolean isObject(Frame frame) {
return frame.isObject(frameSlot);
}
protected final boolean isLong(Frame frame) {
return frame.isLong(frameSlot);
}
public boolean hasTemporalDeadZone() {
return false;
}
protected final Object checkNotDead(Object value, BranchProfile deadBranch) {
if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, value == Dead.instance())) {
deadBranch.enter();
throw Errors.createReferenceErrorNotDefined(frameSlot.getIdentifier(), this);
}
return value;
}
public abstract static class WithDescriptor extends FrameSlotNode {
protected final FrameDescriptor frameDescriptor;
protected WithDescriptor(FrameSlot frameSlot, FrameDescriptor frameDescriptor) {
super(frameSlot);
this.frameDescriptor = frameDescriptor;
assert frameDescriptor != null;
}
protected final boolean isBooleanKind(Frame frame) {
return isOrSetKind(frame, FrameSlotKind.Boolean);
}
protected final boolean isIntegerKind(Frame frame) {
return isOrSetKind(frame, FrameSlotKind.Int);
}
protected final boolean isDoubleKind(Frame frame) {
return isOrSetKind(frame, FrameSlotKind.Double);
}
protected final boolean isLongKind(Frame frame) {
return isOrSetKind(frame, FrameSlotKind.Long);
}
protected final void ensureObjectKind(Frame frame) {
assert frameDescriptor == frame.getFrameDescriptor();
if (frameDescriptor.getFrameSlotKind(frameSlot) != FrameSlotKind.Object) {
CompilerDirectives.transferToInterpreterAndInvalidate();
frameDescriptor.setFrameSlotKind(frameSlot, FrameSlotKind.Object);
}
}
private boolean isOrSetKind(Frame frame, FrameSlotKind targetKind) {
assert frameDescriptor == frame.getFrameDescriptor();
FrameSlotKind currentKind = frameDescriptor.getFrameSlotKind(frameSlot);
if (currentKind == targetKind) {
return true;
} else if (currentKind == FrameSlotKind.Illegal) {
CompilerDirectives.transferToInterpreterAndInvalidate();
frameDescriptor.setFrameSlotKind(frameSlot, targetKind);
return true;
} else {
if (targetKind == FrameSlotKind.Double) {
if (currentKind == FrameSlotKind.Int || currentKind == FrameSlotKind.Long) {
CompilerDirectives.transferToInterpreterAndInvalidate();
frameDescriptor.setFrameSlotKind(frameSlot, FrameSlotKind.Double);
return true;
}
} else if (targetKind == FrameSlotKind.Long) {
if (currentKind == FrameSlotKind.Int) {
CompilerDirectives.transferToInterpreterAndInvalidate();
frameDescriptor.setFrameSlotKind(frameSlot, FrameSlotKind.Long);
return true;
}
}
return false;
}
}
}
}