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
Original file line number Diff line number Diff line change
Expand Up @@ -2195,7 +2195,7 @@ private JavaScriptNode desugarForInOrOfBody(ForNode forNode, JavaScriptNode iter
wrappedBody = factory.createIteratorCloseWrapper(context, wrappedBody, iteratorVar.createReadNode(), false);
}

RepeatingNode repeatingNode = factory.createForOfRepeatingNode(iteratorNext, wrappedBody,
RepeatingNode repeatingNode = factory.createForOfRepeatingNode(iteratorVar.createReadNode(), iteratorNext, wrappedBody,
(JSWriteFrameSlotNode) nextResultVar.createWriteNode(null));
LoopNode loopNode = factory.createLoopNode(repeatingNode);
JavaScriptNode whileNode = forNode.isForOf()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,20 @@

import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Shared;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.GenerateCached;
import com.oracle.truffle.api.dsl.GenerateInline;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.InlinedBranchProfile;
import com.oracle.truffle.api.profiles.InlinedConditionProfile;
import com.oracle.truffle.api.profiles.InlinedIntValueProfile;
import com.oracle.truffle.js.builtins.ArrayIteratorPrototypeBuiltinsFactory.ArrayIteratorNextNodeGen;
import com.oracle.truffle.js.nodes.JavaScriptBaseNode;
import com.oracle.truffle.js.nodes.access.CreateIterResultObjectNode;
import com.oracle.truffle.js.nodes.access.ReadElementNode;
import com.oracle.truffle.js.nodes.array.JSGetLengthNode;
Expand All @@ -59,6 +64,7 @@
import com.oracle.truffle.js.nodes.function.JSBuiltin;
import com.oracle.truffle.js.nodes.function.JSBuiltinNode;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.JSConfig;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.JSRuntime;
import com.oracle.truffle.js.runtime.builtins.BuiltinEnum;
Expand Down Expand Up @@ -108,27 +114,39 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr

public abstract static class ArrayIteratorNextNode extends JSBuiltinNode {

@Child private CreateIterResultObjectNode createIterResultObjectNode;

protected ArrayIteratorNextNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
this.createIterResultObjectNode = CreateIterResultObjectNode.create(context);
}

protected JSObject createIteratorResultObject(Object value, boolean done) {
return createIterResultObjectNode.execute(value, done);
}

@Specialization(guards = {"!isUndefined(array)"})
JSObject doArrayIterator(JSArrayIteratorObject iterator,
@Bind("iterator.getIteratedObject()") Object array,
@Shared @Cached("create(getContext())") CreateIterResultObjectNode createIterResultObjectNode,
@Cached("create(getContext())") ReadElementNode readElementNode,
@Cached ArrayIteratorGetLengthNode getLengthNode,
@Cached(inline = true) LongToIntOrDoubleNode toJSIndex,
@Cached InlinedIntValueProfile iterationKindProfile) {
@Cached InlinedIntValueProfile iterationKindProfile,
@Cached InlinedConditionProfile skipLengthCheckBranch) {
long index = iterator.getNextIndex();
int itemKind = iterationKindProfile.profile(this, iterator.getIterationKind());
long length = getLengthNode.execute(this, array, getJSContext());

if (index >= length) {
iterator.setIteratedObject(Undefined.instance);
return createIterResultObjectNode.execute(Undefined.instance, true);
assert index >= 0;
if (skipLengthCheckBranch.profile(this, iterator.isSkipGetLength())) {
// Already checked in the caller, no need to get the length again.
iterator.setSkipGetLength(false);
} else {
long length = getLengthNode.execute(this, array, getContext());
if (index >= length) {
iterator.setIteratedObject(Undefined.instance);
return createIteratorResultObject(Undefined.instance, true);
}
}

int itemKind = iterationKindProfile.profile(this, iterator.getIterationKind());
iterator.setNextIndex(index + 1);
Object indexNumber = null;
if ((itemKind & JSRuntime.ITERATION_KIND_KEY) != 0) {
Expand All @@ -146,13 +164,12 @@ JSObject doArrayIterator(JSArrayIteratorObject iterator,
result = JSArray.createConstantObjectArray(getContext(), getRealm(), new Object[]{indexNumber, elementValue});
}
}
return createIterResultObjectNode.execute(result, false);
return createIteratorResultObject(result, false);
}

@Specialization(guards = {"isUndefined(iterator.getIteratedObject())"})
static JSObject doArrayIteratorDetached(@SuppressWarnings("unused") JSArrayIteratorObject iterator,
@Cached("create(getContext())") @Shared CreateIterResultObjectNode createIterResultObjectNode) {
return createIterResultObjectNode.execute(Undefined.instance, true);
final JSObject doArrayIteratorDetached(@SuppressWarnings("unused") JSArrayIteratorObject iterator) {
return createIteratorResultObject(Undefined.instance, true);
}

@SuppressWarnings("unused")
Expand All @@ -161,33 +178,87 @@ static JSObject doIncompatibleReceiver(Object iterator) {
throw Errors.createTypeError("not an Array Iterator");
}
}
}

@GenerateInline
@GenerateCached(false)
abstract class ArrayIteratorGetLengthNode extends Node {
@GenerateInline
@GenerateCached(false)
public abstract static class ArrayIteratorGetLengthNode extends JavaScriptBaseNode {

abstract long execute(Node node, Object array, JSContext context);
public abstract long execute(Node node, Object array, JSContext context);

@Specialization
static long doArray(JSArrayObject array, @SuppressWarnings("unused") JSContext context) {
return JSArray.arrayGetLength(array);
}
@Specialization
static long doArray(JSArrayObject array, @SuppressWarnings("unused") JSContext context) {
return JSArray.arrayGetLength(array);
}

@Specialization
static long doTypedArray(Node node, JSTypedArrayObject typedArray, JSContext context,
@Cached TypedArrayLengthNode typedArrayLengthNode,
@Cached InlinedBranchProfile errorBranch) {
if (JSArrayBufferView.isOutOfBounds(typedArray, context)) {
errorBranch.enter(node);
throw Errors.createTypeError("Cannot perform Array Iterator.prototype.next on a detached ArrayBuffer");
@Specialization
static long doTypedArray(Node node, JSTypedArrayObject typedArray, JSContext context,
@Cached TypedArrayLengthNode typedArrayLengthNode,
@Cached InlinedBranchProfile errorBranch) {
if (JSArrayBufferView.isOutOfBounds(typedArray, context)) {
errorBranch.enter(node);
throw Errors.createTypeError("Cannot perform Array Iterator.prototype.next on a detached ArrayBuffer");
}
return typedArrayLengthNode.execute(node, typedArray, context);
}

@Fallback
static long doArrayLike(Object array, @SuppressWarnings("unused") JSContext context,
@Cached(value = "create(context)", inline = false) JSGetLengthNode getLengthNode) {
return getLengthNode.executeLong(array);
}
return typedArrayLengthNode.execute(node, typedArray, context);
}

@Fallback
static long doArrayLike(Object array, @SuppressWarnings("unused") JSContext context,
@Cached(value = "create(context)", inline = false) JSGetLengthNode getLengthNode) {
return getLengthNode.executeLong(array);
/**
* Like {@link ArrayIteratorGetLengthNode}, but designed to avoid observable side effects. Only
* handles JS arrays, typed arrays, and foreign arrays (assumes getArraySize to well-behaved).
* Returns {@value JSRuntime#INVALID_INTEGER_INDEX} for other object types or if getting the
* length would throw an error.
*/
@ImportStatic(JSConfig.class)
@GenerateInline
@GenerateCached(false)
public abstract static class ArrayIteratorGetLengthSafeNode extends JavaScriptBaseNode {

public abstract long execute(Node node, Object array);

@Specialization
static long doArray(JSArrayObject array) {
return JSArray.arrayGetLength(array);
}

@Specialization
static long doTypedArray(Node node, JSTypedArrayObject typedArray,
@Cached TypedArrayLengthNode typedArrayLengthNode,
@Cached InlinedBranchProfile errorBranch) {
JSContext context = JSContext.get(node);
if (JSArrayBufferView.isOutOfBounds(typedArray, context)) {
errorBranch.enter(node);
// Must call into the next method to ensure correct stack trace for the error.
return JSRuntime.INVALID_INTEGER_INDEX;
}
return typedArrayLengthNode.execute(node, typedArray, context);
}

@Specialization(guards = "isUndefined(array)")
static long doUndefined(@SuppressWarnings("unused") Object array) {
// Iterator is already done and detached.
return 0L;
}

@Specialization(guards = {"interop.hasArrayElements(array)", "isForeignObject(array)"}, limit = "InteropLibraryLimit")
static long doForeignArray(Object array,
@CachedLibrary("array") InteropLibrary interop) {
try {
return interop.getArraySize(array);
} catch (UnsupportedMessageException e) {
return JSRuntime.INVALID_INTEGER_INDEX;
}
}

@Fallback
static long doArrayLike(@SuppressWarnings("unused") Object array) {
// Must call into the next method to ensure correct stack trace for length getters.
return JSRuntime.INVALID_INTEGER_INDEX;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -537,8 +537,8 @@ public JavaScriptNode createDesugaredForAwaitOf(LoopNode loopNode) {
return WhileNode.createDesugaredForAwaitOf(loopNode);
}

public RepeatingNode createForOfRepeatingNode(JavaScriptNode nextResultNode, JavaScriptNode body, JSWriteFrameSlotNode writeNextValueNode) {
return WhileNode.createForOfRepeatingNode(nextResultNode, body, writeNextValueNode);
public RepeatingNode createForOfRepeatingNode(JavaScriptNode iteratorNode, JavaScriptNode nextResultNode, JavaScriptNode body, JSWriteFrameSlotNode writeNextValueNode) {
return WhileNode.createForOfRepeatingNode(iteratorNode, nextResultNode, body, writeNextValueNode);
}

public RepeatingNode createForRepeatingNode(JavaScriptNode condition, JavaScriptNode body, JavaScriptNode modify, FrameDescriptor frameDescriptor, JavaScriptNode isFirstNode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,20 @@ private void checkThreadInterrupted() {
}

@Override
public Object execute(VirtualFrame frame) {
public final Object execute(VirtualFrame frame) {
return executeRepeating(frame);
}

@Override
public final boolean executeBoolean(VirtualFrame frame) {
return executeRepeating(frame);
}

@Override
public final Object executeRepeatingWithValue(VirtualFrame frame) {
return RepeatingNode.super.executeRepeatingWithValue(frame);
}

protected boolean materializationNeeded() {
// If we are using tagged nodes, this node is already materialized.
return !JSNodeUtil.isTaggedNode(bodyNode);
Expand Down
Loading