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.JSToBooleanNode;
import com.oracle.truffle.js.nodes.cast.JSToIndexNode;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.JSContext;
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 java.util.Set;
public abstract class GetViewValueNode 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 private JSToBooleanNode toBooleanNode;
protected GetViewValueNode(JSContext context, String type, JavaScriptNode view, JavaScriptNode requestIndex, JavaScriptNode isLittleEndian) {
this(context, typedArrayFactoryFromType(type, context), view, requestIndex, isLittleEndian);
}
protected GetViewValueNode(JSContext context, TypedArrayFactory factory, JavaScriptNode view, JavaScriptNode requestIndex, JavaScriptNode isLittleEndian) {
this.factory = factory;
this.context = context;
this.viewNode = view;
this.requestIndexNode = requestIndex;
this.isLittleEndianNode = isLittleEndian;
this.toBooleanNode = factory.getBytesPerElement() == 1 ? null : JSToBooleanNode.create();
}
static TypedArrayFactory typedArrayFactoryFromType(String type, JSContext context) {
for (TypedArrayFactory factory : TypedArray.factories(context)) {
if (factory.getName().startsWith(type)) {
return factory;
}
}
throw new IllegalArgumentException(type);
}
public abstract Object execute(Object dataView, Object requestIndex, Object littleEndian);
@Specialization
protected final Object doGet(Object view, Object requestIndex, Object littleEndian,
@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);
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));
return strategy.getBufferElement(buffer, bufferIndex, isLittleEndian);
}
public static GetViewValueNode create(JSContext context, String type, JavaScriptNode view, JavaScriptNode requestIndex, JavaScriptNode isLittleEndian) {
return GetViewValueNodeGen.create(context, type, view, requestIndex, isLittleEndian);
}
@Override
protected JavaScriptNode copyUninitialized(Set<Class<? extends Tag>> materializedTags) {
return GetViewValueNodeGen.create(context, factory, cloneUninitialized(viewNode, materializedTags), cloneUninitialized(requestIndexNode, materializedTags),
cloneUninitialized(isLittleEndianNode, materializedTags));
}
}