package com.oracle.truffle.js.runtime.builtins;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.Shape;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.JSRealm;
import com.oracle.truffle.js.runtime.JSRuntime;
import com.oracle.truffle.js.runtime.Symbol;
import com.oracle.truffle.js.runtime.objects.JSDynamicObject;
import com.oracle.truffle.js.runtime.objects.JSObject;
import com.oracle.truffle.js.runtime.objects.JSObjectUtil;
import com.oracle.truffle.js.runtime.objects.JSOrdinaryObject;
import com.oracle.truffle.js.runtime.objects.JSShape;
import com.oracle.truffle.js.runtime.objects.Null;
import com.oracle.truffle.js.runtime.util.CompilableBiFunction;
public final class JSOrdinary extends JSNonProxy implements PrototypeSupplier {
public static final String TYPE_NAME = "object";
public static final String CLASS_NAME = "Object";
public static final String PROTOTYPE_NAME = "Object.prototype";
public static final JSOrdinary INSTANCE = new JSOrdinary();
public static final CompilableBiFunction<JSContext, DynamicObject, Shape> SHAPE_SUPPLIER = (ctx, proto) -> JSObjectUtil.getProtoChildShape(proto, INSTANCE, ctx);
public static final JSOrdinary BARE_INSTANCE = new JSOrdinary();
private JSOrdinary() {
}
public static DynamicObject create(JSContext context) {
return create(context, context.getRealm());
}
public static DynamicObject create(JSContext context, JSObjectFactory factory) {
return createWithRealm(context, factory, context.getRealm());
}
public static DynamicObject createWithRealm(JSContext context, JSObjectFactory factory, JSRealm realm) {
DynamicObject obj = JSOrdinaryObject.create(factory.getShape(realm));
factory.initProto(obj, realm);
return context.trackAllocation(obj);
}
public static DynamicObject create(JSContext context, JSRealm realm) {
return createWithRealm(context, context.getOrdinaryObjectFactory(), realm);
}
@TruffleBoundary
public static DynamicObject createWithPrototype(DynamicObject prototype, JSContext context) {
assert JSObjectUtil.isValidPrototype(prototype);
if (prototype == Null.instance) {
return createWithNullPrototype(context);
} else {
return context.trackAllocation(JSOrdinaryObject.create(JSObjectUtil.getProtoChildShape(prototype, INSTANCE, context)));
}
}
public static DynamicObject createWithNullPrototype(JSContext context) {
return context.trackAllocation(JSOrdinaryObject.create(context.getEmptyShapeNullPrototype()));
}
public static DynamicObject createInitWithInstancePrototype(DynamicObject prototype, JSContext context) {
assert JSObjectUtil.isValidPrototype(prototype);
Shape shape = context.getEmptyShapePrototypeInObject();
JSOrdinaryObject obj = JSOrdinaryObject.create(shape);
setProtoSlow(obj, prototype);
return obj;
}
private static void setProtoSlow(DynamicObject obj, DynamicObject prototype) {
JSObjectUtil.putHiddenProperty(obj, JSObject.HIDDEN_PROTO, prototype);
}
public static DynamicObject createWithoutPrototype(JSContext context) {
Shape shape = context.getEmptyShapePrototypeInObject();
DynamicObject obj = create(context, shape);
return obj;
}
public static DynamicObject create(JSContext context, Shape shape) {
assert JSShape.getJSClass(shape) == JSOrdinary.INSTANCE;
return context.trackAllocation(JSOrdinaryObject.create(shape));
}
public static DynamicObject createInit(JSRealm realm) {
CompilerAsserts.neverPartOfCompilation();
return createInit(realm, realm.getObjectPrototype());
}
public static DynamicObject createInit(JSRealm realm, DynamicObject prototype) {
CompilerAsserts.neverPartOfCompilation();
assert JSObjectUtil.isValidPrototype(prototype);
JSContext context = realm.getContext();
if (context.isMultiContext()) {
return createInitWithInstancePrototype(prototype, context);
} else {
return JSOrdinaryObject.create(prototype == Null.instance ? context.getEmptyShapeNullPrototype() : JSObjectUtil.getProtoChildShape(prototype, INSTANCE, context));
}
}
public static DynamicObject createWithNullPrototypeInit(JSContext context) {
CompilerAsserts.neverPartOfCompilation();
return JSOrdinaryObject.create(context.getEmptyShapeNullPrototype());
}
public static boolean isJSOrdinaryObject(Object obj) {
return JSDynamicObject.isJSDynamicObject(obj) && isJSOrdinaryObject((DynamicObject) obj);
}
public static boolean isJSOrdinaryObject(DynamicObject obj) {
return isInstance(obj, INSTANCE);
}
@Override
@TruffleBoundary
public String getClassName(DynamicObject object) {
JSContext context = JSObject.getJSContext(object);
if (context.getEcmaScriptVersion() <= 5) {
Object toStringTag = get(object, Symbol.SYMBOL_TO_STRING_TAG);
if (JSRuntime.isString(toStringTag)) {
return JSRuntime.toStringIsString(toStringTag);
}
}
return CLASS_NAME;
}
@TruffleBoundary
@Override
public String toDisplayStringImpl(DynamicObject obj, int depth, boolean allowSideEffects, JSContext context) {
if (context.isOptionNashornCompatibilityMode()) {
return defaultToString(obj);
} else {
return JSRuntime.objectToConsoleString(obj, null, depth, allowSideEffects);
}
}
@TruffleBoundary
@Override
public Object get(DynamicObject thisObj, long index) {
return get(thisObj, String.valueOf(index));
}
@Override
public boolean hasOnlyShapeProperties(DynamicObject obj) {
return true;
}
@Override
public Shape makeInitialShape(JSContext context, DynamicObject prototype) {
return JSObjectUtil.getProtoChildShape(prototype, INSTANCE, context);
}
@Override
public DynamicObject getIntrinsicDefaultProto(JSRealm realm) {
return realm.getObjectPrototype();
}
}