package com.oracle.truffle.js.nodes.access;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Executed;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.instrumentation.Tag;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObjectLibrary;
import com.oracle.truffle.api.object.HiddenKey;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.js.nodes.JavaScriptNode;
import com.oracle.truffle.js.nodes.function.JSFunctionCallNode;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.JSArguments;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.objects.Accessor;
import com.oracle.truffle.js.runtime.objects.Undefined;
import java.util.Set;
public abstract class PrivateFieldSetNode extends JSTargetableNode {
@Child @Executed protected JavaScriptNode targetNode;
@Child @Executed protected JavaScriptNode keyNode;
@Child @Executed protected JavaScriptNode valueNode;
protected final JSContext context;
public static PrivateFieldSetNode create(JavaScriptNode targetNode, JavaScriptNode keyNode, JavaScriptNode valueNode, JSContext context) {
return PrivateFieldSetNodeGen.create(targetNode, keyNode, valueNode, context);
}
protected PrivateFieldSetNode(JavaScriptNode targetNode, JavaScriptNode keyNode, JavaScriptNode valueNode, JSContext context) {
this.targetNode = targetNode;
this.keyNode = keyNode;
this.valueNode = valueNode;
this.context = context;
}
@Specialization(guards = {"isJSObject(target)"}, limit = "3")
Object doField(DynamicObject target, HiddenKey key, Object value,
@CachedLibrary("target") DynamicObjectLibrary access,
@Cached BranchProfile errorBranch) {
if (!access.putIfPresent(target, key, value)) {
errorBranch.enter();
missing(target, key, value);
}
return value;
}
@Specialization(guards = {"isJSObject(target)"})
Object doAccessor(DynamicObject target, Accessor accessor, Object value,
@Cached("createCall()") JSFunctionCallNode callNode,
@Cached BranchProfile errorBranch) {
DynamicObject setter = accessor.getSetter();
if (setter == Undefined.instance) {
errorBranch.enter();
throw Errors.createTypeErrorCannotSetAccessorProperty(keyAsString(), target);
}
return callNode.executeCall(JSArguments.createOneArg(target, setter, value));
}
@TruffleBoundary
@Fallback
Object missing(@SuppressWarnings("unused") Object target, @SuppressWarnings("unused") Object key, @SuppressWarnings("unused") Object value) {
throw Errors.createTypeErrorCannotSetPrivateMember(keyAsString(), this);
}
@TruffleBoundary
private String keyAsString() {
return keyNode.expressionToString();
}
@Override
public final JavaScriptNode getTarget() {
return targetNode;
}
@Override
protected JavaScriptNode copyUninitialized(Set<Class<? extends Tag>> materializedTags) {
return create(cloneUninitialized(targetNode, materializedTags), cloneUninitialized(keyNode, materializedTags), cloneUninitialized(valueNode, materializedTags), context);
}
}