|
|
@@ -849,19 +849,14 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
|
|
|
|
|
|
|
|
public static class UnionTypeNode extends WriteFrameSlotTypeNode {
|
|
|
|
public static class UnionTypeNode extends WriteFrameSlotTypeNode {
|
|
|
|
@Children final TypeNode[] elementTypeNodes;
|
|
|
|
@Children final TypeNode[] elementTypeNodes;
|
|
|
|
private final boolean skipElementTypeChecks;
|
|
|
|
|
|
|
|
private final int defaultIndex;
|
|
|
|
private final int defaultIndex;
|
|
|
|
|
|
|
|
|
|
|
|
public UnionTypeNode(
|
|
|
|
public UnionTypeNode(
|
|
|
|
SourceSection sourceSection,
|
|
|
|
SourceSection sourceSection, int defaultIndex, TypeNode[] elementTypeNodes) {
|
|
|
|
int defaultIndex,
|
|
|
|
|
|
|
|
TypeNode[] elementTypeNodes,
|
|
|
|
|
|
|
|
boolean skipElementTypeChecks) {
|
|
|
|
|
|
|
|
super(sourceSection);
|
|
|
|
super(sourceSection);
|
|
|
|
assert elementTypeNodes.length > 0;
|
|
|
|
assert elementTypeNodes.length > 0;
|
|
|
|
this.elementTypeNodes = elementTypeNodes;
|
|
|
|
this.elementTypeNodes = elementTypeNodes;
|
|
|
|
this.defaultIndex = defaultIndex;
|
|
|
|
this.defaultIndex = defaultIndex;
|
|
|
|
this.skipElementTypeChecks = skipElementTypeChecks;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
@@ -879,7 +874,10 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public boolean isNoopTypeCheck() {
|
|
|
|
public boolean isNoopTypeCheck() {
|
|
|
|
return skipElementTypeChecks;
|
|
|
|
for (var element : elementTypeNodes) {
|
|
|
|
|
|
|
|
if (!element.isNoopTypeCheck()) return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
@@ -985,8 +983,6 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
@Fallback
|
|
|
|
@Fallback
|
|
|
|
@ExplodeLoop
|
|
|
|
@ExplodeLoop
|
|
|
|
protected Object executeLazily(VirtualFrame frame, Object value) {
|
|
|
|
protected Object executeLazily(VirtualFrame frame, Object value) {
|
|
|
|
if (skipElementTypeChecks) return value;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// escape analysis should remove this allocation in compiled code
|
|
|
|
// escape analysis should remove this allocation in compiled code
|
|
|
|
var typeMismatches = new VmTypeMismatchException[elementTypeNodes.length];
|
|
|
|
var typeMismatches = new VmTypeMismatchException[elementTypeNodes.length];
|
|
|
|
|
|
|
|
|
|
|
@@ -1037,8 +1033,6 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public Object executeEagerly(VirtualFrame frame, Object value) {
|
|
|
|
public Object executeEagerly(VirtualFrame frame, Object value) {
|
|
|
|
if (skipElementTypeChecks) return value;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// escape analysis should remove this allocation in compiled code
|
|
|
|
// escape analysis should remove this allocation in compiled code
|
|
|
|
var typeMismatches = new VmTypeMismatchException[elementTypeNodes.length];
|
|
|
|
var typeMismatches = new VmTypeMismatchException[elementTypeNodes.length];
|
|
|
|
|
|
|
|
|
|
|
@@ -1162,7 +1156,6 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
@Child private TypeNode elementTypeNode;
|
|
|
|
@Child private TypeNode elementTypeNode;
|
|
|
|
|
|
|
|
|
|
|
|
public CollectionTypeNode(SourceSection sourceSection, TypeNode elementTypeNode) {
|
|
|
|
public CollectionTypeNode(SourceSection sourceSection, TypeNode elementTypeNode) {
|
|
|
|
|
|
|
|
|
|
|
|
super(sourceSection);
|
|
|
|
super(sourceSection);
|
|
|
|
this.elementTypeNode = elementTypeNode;
|
|
|
|
this.elementTypeNode = elementTypeNode;
|
|
|
|
}
|
|
|
|
}
|
|
|
@@ -1272,12 +1265,10 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
|
|
|
|
|
|
|
|
public static final class ListTypeNode extends ObjectSlotTypeNode {
|
|
|
|
public static final class ListTypeNode extends ObjectSlotTypeNode {
|
|
|
|
@Child private TypeNode elementTypeNode;
|
|
|
|
@Child private TypeNode elementTypeNode;
|
|
|
|
private final boolean skipElementTypeChecks;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ListTypeNode(SourceSection sourceSection, TypeNode elementTypeNode) {
|
|
|
|
public ListTypeNode(SourceSection sourceSection, TypeNode elementTypeNode) {
|
|
|
|
super(sourceSection);
|
|
|
|
super(sourceSection);
|
|
|
|
this.elementTypeNode = elementTypeNode;
|
|
|
|
this.elementTypeNode = elementTypeNode;
|
|
|
|
skipElementTypeChecks = elementTypeNode.isNoopTypeCheck();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
@@ -1322,7 +1313,7 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
if (!(value instanceof VmList vmList)) {
|
|
|
|
if (!(value instanceof VmList vmList)) {
|
|
|
|
throw typeMismatch(value, BaseModule.getListClass());
|
|
|
|
throw typeMismatch(value, BaseModule.getListClass());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (skipElementTypeChecks) return vmList;
|
|
|
|
if (elementTypeNode.isNoopTypeCheck()) return vmList;
|
|
|
|
|
|
|
|
|
|
|
|
for (var elem : vmList) {
|
|
|
|
for (var elem : vmList) {
|
|
|
|
elementTypeNode.executeEagerly(frame, elem);
|
|
|
|
elementTypeNode.executeEagerly(frame, elem);
|
|
|
@@ -1339,7 +1330,7 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
if (!(value instanceof VmList vmList)) {
|
|
|
|
if (!(value instanceof VmList vmList)) {
|
|
|
|
throw typeMismatch(value, BaseModule.getListClass());
|
|
|
|
throw typeMismatch(value, BaseModule.getListClass());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (skipElementTypeChecks) return vmList;
|
|
|
|
if (elementTypeNode.isNoopTypeCheck()) return vmList;
|
|
|
|
var ret = vmList;
|
|
|
|
var ret = vmList;
|
|
|
|
var idx = 0;
|
|
|
|
var idx = 0;
|
|
|
|
|
|
|
|
|
|
|
@@ -1371,12 +1362,10 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
|
|
|
|
|
|
|
|
public abstract static class SetTypeNode extends ObjectSlotTypeNode {
|
|
|
|
public abstract static class SetTypeNode extends ObjectSlotTypeNode {
|
|
|
|
@Child private TypeNode elementTypeNode;
|
|
|
|
@Child private TypeNode elementTypeNode;
|
|
|
|
private final boolean skipElementTypeChecks;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected SetTypeNode(SourceSection sourceSection, TypeNode elementTypeNode) {
|
|
|
|
protected SetTypeNode(SourceSection sourceSection, TypeNode elementTypeNode) {
|
|
|
|
super(sourceSection);
|
|
|
|
super(sourceSection);
|
|
|
|
this.elementTypeNode = elementTypeNode;
|
|
|
|
this.elementTypeNode = elementTypeNode;
|
|
|
|
skipElementTypeChecks = elementTypeNode.isNoopTypeCheck();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
@@ -1426,7 +1415,7 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
|
|
|
|
|
|
|
|
@Specialization
|
|
|
|
@Specialization
|
|
|
|
protected Object eval(VirtualFrame frame, VmSet value) {
|
|
|
|
protected Object eval(VirtualFrame frame, VmSet value) {
|
|
|
|
if (skipElementTypeChecks) return value;
|
|
|
|
if (elementTypeNode.isNoopTypeCheck()) return value;
|
|
|
|
for (var elem : value) {
|
|
|
|
for (var elem : value) {
|
|
|
|
// no point doing a lazy check because set members have their hash code computed, which
|
|
|
|
// no point doing a lazy check because set members have their hash code computed, which
|
|
|
|
// necessarily deep-forces them.
|
|
|
|
// necessarily deep-forces them.
|
|
|
@@ -1451,14 +1440,11 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
public static final class MapTypeNode extends ObjectSlotTypeNode {
|
|
|
|
public static final class MapTypeNode extends ObjectSlotTypeNode {
|
|
|
|
@Child private TypeNode keyTypeNode;
|
|
|
|
@Child private TypeNode keyTypeNode;
|
|
|
|
@Child private TypeNode valueTypeNode;
|
|
|
|
@Child private TypeNode valueTypeNode;
|
|
|
|
private final boolean skipEntryTypeChecks;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public MapTypeNode(SourceSection sourceSection, TypeNode keyTypeNode, TypeNode valueTypeNode) {
|
|
|
|
public MapTypeNode(SourceSection sourceSection, TypeNode keyTypeNode, TypeNode valueTypeNode) {
|
|
|
|
|
|
|
|
|
|
|
|
super(sourceSection);
|
|
|
|
super(sourceSection);
|
|
|
|
this.keyTypeNode = keyTypeNode;
|
|
|
|
this.keyTypeNode = keyTypeNode;
|
|
|
|
this.valueTypeNode = valueTypeNode;
|
|
|
|
this.valueTypeNode = valueTypeNode;
|
|
|
|
skipEntryTypeChecks = keyTypeNode.isNoopTypeCheck() && valueTypeNode.isNoopTypeCheck();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
@@ -1531,7 +1517,7 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private Object eval(VirtualFrame frame, VmMap value) {
|
|
|
|
private Object eval(VirtualFrame frame, VmMap value) {
|
|
|
|
if (skipEntryTypeChecks) return value;
|
|
|
|
if (keyTypeNode.isNoopTypeCheck() && valueTypeNode.isNoopTypeCheck()) return value;
|
|
|
|
var ret = value;
|
|
|
|
var ret = value;
|
|
|
|
|
|
|
|
|
|
|
|
for (var entry : value) {
|
|
|
|
for (var entry : value) {
|
|
|
@@ -1548,7 +1534,7 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private Object evalEager(VirtualFrame frame, VmMap value) {
|
|
|
|
private Object evalEager(VirtualFrame frame, VmMap value) {
|
|
|
|
if (skipEntryTypeChecks) return value;
|
|
|
|
if (keyTypeNode.isNoopTypeCheck() && valueTypeNode.isNoopTypeCheck()) return value;
|
|
|
|
for (var entry : value) {
|
|
|
|
for (var entry : value) {
|
|
|
|
keyTypeNode.executeEagerly(frame, VmUtils.getKey(entry));
|
|
|
|
keyTypeNode.executeEagerly(frame, VmUtils.getKey(entry));
|
|
|
|
valueTypeNode.executeEagerly(frame, VmUtils.getValue(entry));
|
|
|
|
valueTypeNode.executeEagerly(frame, VmUtils.getValue(entry));
|
|
|
@@ -1712,9 +1698,6 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
@Child protected TypeNode valueTypeNode;
|
|
|
|
@Child protected TypeNode valueTypeNode;
|
|
|
|
@Child @Nullable protected ListingOrMappingTypeCastNode valueTypeCastNode;
|
|
|
|
@Child @Nullable protected ListingOrMappingTypeCastNode valueTypeCastNode;
|
|
|
|
|
|
|
|
|
|
|
|
private final boolean skipKeyTypeChecks;
|
|
|
|
|
|
|
|
private final boolean skipValueTypeChecks;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected ListingOrMappingTypeNode(
|
|
|
|
protected ListingOrMappingTypeNode(
|
|
|
|
SourceSection sourceSection,
|
|
|
|
SourceSection sourceSection,
|
|
|
|
VmLanguage language,
|
|
|
|
VmLanguage language,
|
|
|
@@ -1725,9 +1708,6 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
this.language = language;
|
|
|
|
this.language = language;
|
|
|
|
this.keyTypeNode = keyTypeNode;
|
|
|
|
this.keyTypeNode = keyTypeNode;
|
|
|
|
this.valueTypeNode = valueTypeNode;
|
|
|
|
this.valueTypeNode = valueTypeNode;
|
|
|
|
|
|
|
|
|
|
|
|
skipKeyTypeChecks = keyTypeNode == null || keyTypeNode.isNoopTypeCheck();
|
|
|
|
|
|
|
|
skipValueTypeChecks = valueTypeNode.isNoopTypeCheck();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private boolean isListing() {
|
|
|
|
private boolean isListing() {
|
|
|
@@ -1849,7 +1829,11 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected void doEagerCheck(VirtualFrame frame, VmObject object) {
|
|
|
|
protected void doEagerCheck(VirtualFrame frame, VmObject object) {
|
|
|
|
doEagerCheck(frame, object, skipKeyTypeChecks, skipValueTypeChecks);
|
|
|
|
doEagerCheck(
|
|
|
|
|
|
|
|
frame,
|
|
|
|
|
|
|
|
object,
|
|
|
|
|
|
|
|
keyTypeNode == null || keyTypeNode.isNoopTypeCheck(),
|
|
|
|
|
|
|
|
valueTypeNode.isNoopTypeCheck());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected void doEagerCheck(
|
|
|
|
protected void doEagerCheck(
|
|
|
@@ -2262,7 +2246,6 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
|
|
|
|
|
|
|
|
public PairTypeNode(
|
|
|
|
public PairTypeNode(
|
|
|
|
SourceSection sourceSection, TypeNode firstTypeNode, TypeNode secondTypeNode) {
|
|
|
|
SourceSection sourceSection, TypeNode firstTypeNode, TypeNode secondTypeNode) {
|
|
|
|
|
|
|
|
|
|
|
|
super(sourceSection);
|
|
|
|
super(sourceSection);
|
|
|
|
this.firstTypeNode = firstTypeNode;
|
|
|
|
this.firstTypeNode = firstTypeNode;
|
|
|
|
this.secondTypeNode = secondTypeNode;
|
|
|
|
this.secondTypeNode = secondTypeNode;
|
|
|
@@ -2773,6 +2756,21 @@ public abstract class TypeNode extends PklNode {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public Object executeEagerly(VirtualFrame frame, Object value) {
|
|
|
|
|
|
|
|
var prevOwner = VmUtils.getOwner(frame);
|
|
|
|
|
|
|
|
var prevReceiver = VmUtils.getReceiver(frame);
|
|
|
|
|
|
|
|
setOwner(frame, VmUtils.getOwner(typeAlias.getEnclosingFrame()));
|
|
|
|
|
|
|
|
setReceiver(frame, VmUtils.getReceiver(typeAlias.getEnclosingFrame()));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
return aliasedTypeNode.executeEagerly(frame, value);
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
|
|
setOwner(frame, prevOwner);
|
|
|
|
|
|
|
|
setReceiver(frame, prevReceiver);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** See docstring on {@link TypeAliasTypeNode#executeLazily}. */
|
|
|
|
/** See docstring on {@link TypeAliasTypeNode#executeLazily}. */
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public Object executeAndSet(VirtualFrame frame, Object value) {
|
|
|
|
public Object executeAndSet(VirtualFrame frame, Object value) {
|
|
|
|