package com.oracle.truffle.js.nodes.access;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Executed;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.instrumentation.Tag;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.api.profiles.ValueProfile;
import com.oracle.truffle.js.nodes.JavaScriptNode;
import com.oracle.truffle.js.nodes.cast.JSToBigIntNode;
import com.oracle.truffle.js.nodes.cast.JSToBooleanNode;
import com.oracle.truffle.js.nodes.cast.JSToIndexNode;
import com.oracle.truffle.js.nodes.cast.JSToNumberNode;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.JSRuntime;
import com.oracle.truffle.js.runtime.array.TypedArray;
import com.oracle.truffle.js.runtime.array.TypedArrayFactory;
import com.oracle.truffle.js.runtime.builtins.JSArrayBuffer;
import com.oracle.truffle.js.runtime.builtins.JSDataView;
import com.oracle.truffle.js.runtime.objects.Undefined;
import java.util.Set;
public abstract class SetViewValueNode extends JavaScriptNode {
private final TypedArrayFactory factory;
private final JSContext context;
@Child @Executed protected JavaScriptNode viewNode;
@Child @Executed protected JavaScriptNode requestIndexNode;
@Child @Executed protected JavaScriptNode isLittleEndianNode;
@Child @Executed protected JavaScriptNode valueNode;
@Child private JSToBooleanNode toBooleanNode;
@Child private JSToNumberNode toNumberNode;
@Child private JSToBigIntNode toBigIntNode;
protected SetViewValueNode(JSContext context, String type, JavaScriptNode view, JavaScriptNode requestIndex, JavaScriptNode isLittleEndian, JavaScriptNode value) {
this(context, GetViewValueNode.typedArrayFactoryFromType(type, context), view, requestIndex, isLittleEndian, value);
}
protected SetViewValueNode(JSContext context, TypedArrayFactory factory, JavaScriptNode view, JavaScriptNode requestIndex, JavaScriptNode isLittleEndian, JavaScriptNode value) {
this.factory = factory;
this.context = context;
this.viewNode = view;
this.requestIndexNode = requestIndex;
this.isLittleEndianNode = isLittleEndian;
this.valueNode = value;
this.toBooleanNode = factory.getBytesPerElement() == 1 ? null : JSToBooleanNode.create();
if (JSRuntime.isTypedArrayBigIntFactory(factory)) {
this.toBigIntNode = JSToBigIntNode.create();
} else {
this.toNumberNode = JSToNumberNode.create();
}
}
public abstract Object execute(DynamicObject dataView, Object byteOffset, Object littleEndian, Object value);
@Specialization
protected final Object doSet(Object view, Object requestIndex, Object littleEndian, Object value,
@Cached("create()") JSToIndexNode toIndexNode,
@Cached("create()") BranchProfile errorBranch,
@Cached("createClassProfile()") ValueProfile typeProfile) {
if (!JSDataView.isJSDataView(view)) {
errorBranch.enter();
throw Errors.createTypeErrorNotADataView();
}
DynamicObject dataView = (DynamicObject) view;
DynamicObject buffer = JSDataView.getArrayBuffer(dataView);
long getIndex = toIndexNode.executeLong(requestIndex);
Object numberValue = JSRuntime.isTypedArrayBigIntFactory(factory) ? toBigIntNode.executeBigInteger(value) : toNumberNode.executeNumber(value);
boolean isLittleEndian = factory.getBytesPerElement() == 1 ? true : toBooleanNode.executeBoolean(littleEndian);
if (!context.getTypedArrayNotDetachedAssumption().isValid()) {
if (JSArrayBuffer.isDetachedBuffer(buffer)) {
errorBranch.enter();
throw Errors.createTypeErrorDetachedBuffer();
}
}
int viewLength = JSDataView.typedArrayGetLength(dataView);
int elementSize = factory.getBytesPerElement();
if (getIndex + elementSize > viewLength) {
errorBranch.enter();
throw Errors.createRangeError("index + elementSize > viewLength");
}
int viewOffset = JSDataView.typedArrayGetOffset(dataView);
assert getIndex + viewOffset <= Integer.MAX_VALUE;
int bufferIndex = (int) (getIndex + viewOffset);
TypedArray strategy = typeProfile.profile(factory.createArrayType(JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer), true));
strategy.setBufferElement(buffer, bufferIndex, isLittleEndian, numberValue);
return Undefined.instance;
}
public static SetViewValueNode create(JSContext context, String type, JavaScriptNode view, JavaScriptNode requestIndex, JavaScriptNode isLittleEndian, JavaScriptNode value) {
return SetViewValueNodeGen.create(context, type, view, requestIndex, isLittleEndian, value);
}
@Override
protected JavaScriptNode copyUninitialized(Set<Class<? extends Tag>> materializedTags) {
return SetViewValueNodeGen.create(context, factory, cloneUninitialized(viewNode, materializedTags), cloneUninitialized(requestIndexNode, materializedTags),
cloneUninitialized(isLittleEndianNode, materializedTags), cloneUninitialized(valueNode, materializedTags));
}
}