haxe/src/cs/internal/Runtime.cs
// Patched for s&box whitelist mode (no reflection slow-path)
// Compatible API surface for Haxe 4.3.x hxcs runtime.
namespace haxe.lang
{
public enum EmptyObject
{
EMPTY
}
}
#pragma warning disable 109, 114, 219, 429, 168, 162
namespace haxe.lang
{
public class Runtime
{
public Runtime()
{
}
// Keep: used by generated hxcs code
public static object getField(haxe.lang.HxObject obj, string field, int fieldHash, bool throwErrors)
{
if (obj == null && !throwErrors) return null;
return obj.__hx_getField(
field,
(fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash,
throwErrors,
false,
false
);
}
public static double getField_f(haxe.lang.HxObject obj, string field, int fieldHash, bool throwErrors)
{
if (obj == null && !throwErrors) return 0.0;
return obj.__hx_getField_f(
field,
(fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash,
throwErrors,
false
);
}
public static object setField(haxe.lang.HxObject obj, string field, int fieldHash, object value)
{
return obj.__hx_setField(
field,
(fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash,
value,
false
);
}
public static double setField_f(haxe.lang.HxObject obj, string field, int fieldHash, double value)
{
return obj.__hx_setField_f(
field,
(fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash,
value,
false
);
}
public static object callField(haxe.lang.HxObject obj, string field, int fieldHash, object[] args)
{
return obj.__hx_invokeField(
field,
(fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash,
args
);
}
public static readonly object undefined = (object)(new global::System.Object());
public static object closure(object obj, int hash, string field)
{
return new global::haxe.lang.Closure(obj, field, hash);
}
public static bool eq(object v1, object v2)
{
if (global::System.Object.ReferenceEquals(v1, v2)) return true;
if (global::System.Object.ReferenceEquals(v1, null) || global::System.Object.ReferenceEquals(v2, null)) return false;
// Keep original numeric/string comparisons (no reflection).
global::System.IConvertible v1c = v1 as global::System.IConvertible;
if (v1c != null)
{
global::System.IConvertible v2c = v2 as global::System.IConvertible;
if (v2c == null) return false;
global::System.TypeCode t1 = v1c.GetTypeCode();
global::System.TypeCode t2 = v2c.GetTypeCode();
if (t1 == t2)
return global::System.Object.Equals(v1c, v2c);
if (t1 == global::System.TypeCode.String || t2 == global::System.TypeCode.String)
return false;
switch (t1)
{
case global::System.TypeCode.Int64:
switch (t2)
{
case global::System.TypeCode.Int64:
case global::System.TypeCode.UInt64:
case global::System.TypeCode.Single:
case global::System.TypeCode.Double:
case global::System.TypeCode.DateTime:
return v1c.ToInt64(default(global::System.IFormatProvider)) == v2c.ToInt64(default(global::System.IFormatProvider));
case global::System.TypeCode.Decimal:
return v1c.ToDecimal(default(global::System.IFormatProvider)).Equals(v2c.ToDecimal(default(global::System.IFormatProvider)));
default:
return v1c.ToInt64(default(global::System.IFormatProvider)) == v2c.ToInt64(default(global::System.IFormatProvider));
}
case global::System.TypeCode.Single:
case global::System.TypeCode.Double:
switch (t2)
{
case global::System.TypeCode.Int64:
return v1c.ToInt64(default(global::System.IFormatProvider)) == v2c.ToInt64(default(global::System.IFormatProvider));
case global::System.TypeCode.Single:
case global::System.TypeCode.Double:
return v1c.ToDouble(default(global::System.IFormatProvider)) == v2c.ToDouble(default(global::System.IFormatProvider));
case global::System.TypeCode.Decimal:
return v1c.ToDecimal(default(global::System.IFormatProvider)).Equals(v2c.ToDecimal(default(global::System.IFormatProvider)));
case global::System.TypeCode.UInt64:
case global::System.TypeCode.DateTime:
return v1c.ToUInt64(default(global::System.IFormatProvider)) == v2c.ToUInt64(default(global::System.IFormatProvider));
default:
return v1c.ToDouble(default(global::System.IFormatProvider)) == v2c.ToDouble(default(global::System.IFormatProvider));
}
case global::System.TypeCode.Decimal:
return v1c.ToDecimal(default(global::System.IFormatProvider)).Equals(v2c.ToDecimal(default(global::System.IFormatProvider)));
case global::System.TypeCode.UInt64:
case global::System.TypeCode.DateTime:
switch (t2)
{
case global::System.TypeCode.Int64:
return v1c.ToInt64(default(global::System.IFormatProvider)) == v2c.ToInt64(default(global::System.IFormatProvider));
case global::System.TypeCode.UInt64:
case global::System.TypeCode.Single:
case global::System.TypeCode.Double:
case global::System.TypeCode.DateTime:
return v1c.ToUInt64(default(global::System.IFormatProvider)) == v2c.ToUInt64(default(global::System.IFormatProvider));
case global::System.TypeCode.Decimal:
return v1c.ToDecimal(default(global::System.IFormatProvider)).Equals(v2c.ToDecimal(default(global::System.IFormatProvider)));
default:
return v1c.ToUInt64(default(global::System.IFormatProvider)) == v2c.ToUInt64(default(global::System.IFormatProvider));
}
default:
switch (t2)
{
case global::System.TypeCode.Int64:
return v1c.ToInt64(default(global::System.IFormatProvider)) == v2c.ToInt64(default(global::System.IFormatProvider));
case global::System.TypeCode.Single:
case global::System.TypeCode.Double:
return v1c.ToDouble(default(global::System.IFormatProvider)) == v2c.ToDouble(default(global::System.IFormatProvider));
case global::System.TypeCode.Decimal:
return v1c.ToDecimal(default(global::System.IFormatProvider)).Equals(v2c.ToDecimal(default(global::System.IFormatProvider)));
case global::System.TypeCode.UInt64:
case global::System.TypeCode.DateTime:
return v1c.ToUInt64(default(global::System.IFormatProvider)) == v2c.ToUInt64(default(global::System.IFormatProvider));
default:
return v1c.ToInt32(default(global::System.IFormatProvider)) == v2c.ToInt32(default(global::System.IFormatProvider));
}
}
}
global::System.ValueType v1v = v1 as global::System.ValueType;
if (v1v != null) return v1.Equals(v2);
// Avoid any Type reflection. Only reference equality.
if (v1 is global::System.Type || v2 is global::System.Type)
return global::System.Object.ReferenceEquals(v1, v2);
return false;
}
public static bool refEq(object v1, object v2)
{
// Avoid typeEq (which used reflection); in whitelist we only allow reference equality.
return global::System.Object.ReferenceEquals(v1, v2);
}
public static double toDouble(object obj)
{
if (obj == null) return 0.0;
if (obj is double d) return d;
return (obj as global::System.IConvertible).ToDouble(default(global::System.IFormatProvider));
}
public static int toInt(object obj)
{
if (obj == null) return 0;
if (obj is int i) return i;
return (obj as global::System.IConvertible).ToInt32(default(global::System.IFormatProvider));
}
public static bool isInt(object obj)
{
global::System.IConvertible cv1 = obj as global::System.IConvertible;
if (cv1 == null) return false;
switch (cv1.GetTypeCode())
{
case global::System.TypeCode.Int32:
case global::System.TypeCode.UInt32:
return true;
case global::System.TypeCode.Double:
double d = (double)obj;
if (d >= global::System.Int32.MinValue && d <= global::System.Int32.MaxValue)
return d == (int)d;
return false;
default:
return false;
}
}
public static bool isUInt(object obj)
{
global::System.IConvertible cv1 = obj as global::System.IConvertible;
if (cv1 == null) return false;
switch (cv1.GetTypeCode())
{
case global::System.TypeCode.UInt32:
return true;
case global::System.TypeCode.Double:
double d = (double)obj;
if (d >= global::System.UInt32.MinValue && d <= global::System.UInt32.MaxValue)
return (uint)d == d;
return false;
default:
return false;
}
}
public static int compare(object v1, object v2)
{
if (global::System.Object.ReferenceEquals(v1, v2)) return 0;
if (global::System.Object.ReferenceEquals(v1, null)) return -1;
if (global::System.Object.ReferenceEquals(v2, null)) return 1;
global::System.IConvertible cv1 = v1 as global::System.IConvertible;
if (cv1 != null)
{
global::System.IConvertible cv2 = v2 as global::System.IConvertible;
if (cv2 == null)
throw new global::System.ArgumentException(concat(concat(concat("Cannot compare ", global::cs.Lib.getNativeType(v1).ToString()), " and "), global::cs.Lib.getNativeType(v2).ToString()));
switch (cv1.GetTypeCode())
{
case global::System.TypeCode.Double:
double d1 = (double)v1;
double d2 = cv2.ToDouble(default(global::System.IFormatProvider));
return d1 < d2 ? -1 : (d1 > d2 ? 1 : 0);
case global::System.TypeCode.String:
if (cv2.GetTypeCode() != global::System.TypeCode.String)
throw new global::System.ArgumentException(concat(concat(concat("Cannot compare ", global::cs.Lib.getNativeType(v1).ToString()), " and "), global::cs.Lib.getNativeType(v2).ToString()));
return string.Compare((string)v1, (string)v2, global::System.StringComparison.Ordinal);
default:
double n1 = cv1.ToDouble(default(global::System.IFormatProvider));
double n2 = cv2.ToDouble(default(global::System.IFormatProvider));
return n1 < n2 ? -1 : (n1 > n2 ? 1 : 0);
}
}
global::System.IComparable c1 = v1 as global::System.IComparable;
global::System.IComparable c2 = v2 as global::System.IComparable;
if (c1 == null || c2 == null)
throw new global::System.ArgumentException(concat(concat(concat("Cannot compare ", global::cs.Lib.getNativeType(v1).ToString()), " and "), global::cs.Lib.getNativeType(v2).ToString()));
return c1.CompareTo((object)c2);
}
public static object plus(object v1, object v2)
{
if (v1 is string || v2 is string)
return concat(global::Std.@string(v1), global::Std.@string(v2));
if (v1 == null)
{
if (v2 == null) return null;
v1 = 0;
}
else if (v2 == null)
{
v2 = 0;
}
global::System.IConvertible cv1 = v1 as global::System.IConvertible;
if (cv1 != null)
{
global::System.IConvertible cv2 = v2 as global::System.IConvertible;
if (cv2 == null)
throw new global::System.ArgumentException(concat(concat(concat("Cannot dynamically add ", global::cs.Lib.getNativeType(v1).ToString()), " and "), global::cs.Lib.getNativeType(v2).ToString()));
return cv1.ToDouble(default(global::System.IFormatProvider)) + cv2.ToDouble(default(global::System.IFormatProvider));
}
throw new global::System.ArgumentException(concat(concat(concat("Cannot dynamically add ", global::Std.@string(v1)), " and "), global::Std.@string(v2)));
}
// ---------------------------
// Whitelist-safe slow path
// ---------------------------
private static object SlowPathDenied(string kind, string field)
{
// No reflection here; just throw. Exceptions are whitelisted in your list.
throw new global::System.Exception(concat(concat(kind, ": "), field));
}
public static object slowGetField(object obj, string field, bool throwErrors)
{
if (obj == null)
{
if (throwErrors)
throw new global::System.NullReferenceException(concat(concat("Cannot access field '", field), "' of null."));
return null;
}
// Support string "pseudo-fields" only via the existing helper (no reflection).
string s = obj as string;
if (s != null)
return global::haxe.lang.StringRefl.handleGetField(s, field, throwErrors);
if (throwErrors)
return SlowPathDenied("GetField (reflection disabled)", field);
return null;
}
public static bool slowHasField(object obj, string field)
{
if (obj == null) return false;
string s = obj as string;
if (s != null)
return global::haxe.lang.StringRefl.handleGetField(s, field, false) != null;
return false;
}
public static object slowSetField(object obj, string field, object value)
{
if (obj == null)
throw new global::System.NullReferenceException(concat(concat("Cannot access field '", field), "' of null."));
// No reflection: cannot set on arbitrary CLR objects in whitelist mode.
return SlowPathDenied("SetField (reflection disabled)", field);
}
public static object mkNullable(object obj, global::System.Type nullableType)
{
// Reflection-based construction is blocked (GetMethod/Invoke).
// Keep behavior "best effort": return obj as-is.
return obj;
}
public static object callMethod(object obj, object[] methods, int methodLength, object[] args)
{
// Entire method selection/invocation is reflection-based.
return SlowPathDenied("CallMethod (reflection disabled)", "callMethod");
}
public static object slowCallField(object obj, string field, object[] args)
{
if (field == "toString" && (args == null || args.Length == 0))
return obj == null ? "null" : obj.ToString();
if (args == null) args = new object[0];
string s = obj as string;
if (s != null)
return global::haxe.lang.StringRefl.handleCallField(s, field, args);
return SlowPathDenied("CallField (reflection disabled)", field);
}
// These overloads are used heavily by generated code; keep the HxObject fast-path.
public static object callField(object obj, string field, int fieldHash, object[] args)
{
global::haxe.lang.HxObject hxObj = obj as global::haxe.lang.HxObject;
if (hxObj != null)
return hxObj.__hx_invokeField(field, (fieldHash == 0) ? global::haxe.lang.FieldLookup.hash(field) : fieldHash, args);
return global::haxe.lang.Runtime.slowCallField(obj, field, args);
}
public static object getField(object obj, string field, int fieldHash, bool throwErrors)
{
global::haxe.lang.HxObject hxObj = obj as global::haxe.lang.HxObject;
if (hxObj != null)
return hxObj.__hx_getField(field, (fieldHash == 0) ? global::haxe.lang.FieldLookup.hash(field) : fieldHash, throwErrors, false, false);
return global::haxe.lang.Runtime.slowGetField(obj, field, throwErrors);
}
public static double getField_f(object obj, string field, int fieldHash, bool throwErrors)
{
global::haxe.lang.HxObject hxObj = obj as global::haxe.lang.HxObject;
if (hxObj != null)
return hxObj.__hx_getField_f(field, (fieldHash == 0) ? global::haxe.lang.FieldLookup.hash(field) : fieldHash, throwErrors, false);
return global::haxe.lang.Runtime.toDouble(global::haxe.lang.Runtime.slowGetField(obj, field, throwErrors));
}
public static object setField(object obj, string field, int fieldHash, object value)
{
global::haxe.lang.HxObject hxObj = obj as global::haxe.lang.HxObject;
if (hxObj != null)
return hxObj.__hx_setField(field, (fieldHash == 0) ? global::haxe.lang.FieldLookup.hash(field) : fieldHash, value, false);
return global::haxe.lang.Runtime.slowSetField(obj, field, value);
}
public static double setField_f(object obj, string field, int fieldHash, double value)
{
global::haxe.lang.HxObject hxObj = obj as global::haxe.lang.HxObject;
if (hxObj != null)
return hxObj.__hx_setField_f(field, (fieldHash == 0) ? global::haxe.lang.FieldLookup.hash(field) : fieldHash, value, false);
return global::haxe.lang.Runtime.toDouble(global::haxe.lang.Runtime.slowSetField(obj, field, value));
}
public static string toString(object obj)
{
if (obj == null) return null;
if (obj is bool)
return toBool(obj) ? "true" : "false";
return obj.ToString();
}
public static bool typeEq(global::System.Type t1, global::System.Type t2)
{
// No reflection-based normalization in whitelist mode.
return global::System.Object.ReferenceEquals(t1, t2);
}
public static global::haxe.lang.GenericInterface getGenericAttr(global::System.Type t)
{
// Uses GetCustomAttributes in original; blocked in whitelist mode.
return null;
}
public static To genericCast<To>(object obj)
{
if (obj is To) return (To)obj;
if (obj == null) return default(To);
if (typeof(To) == typeof(double))
return (To)(object)toDouble(obj);
if (typeof(To) == typeof(int))
return (To)(object)toInt(obj);
if (typeof(To) == typeof(float))
return (To)(object)(float)toDouble(obj);
if (typeof(To) == typeof(long))
return (To)(object)(long)toDouble(obj);
return (To)obj;
}
public static string concat(string s1, string s2)
{
return (s1 == null ? "null" : s1) + (s2 == null ? "null" : s2);
}
public static bool toBool(object dyn)
{
if (dyn == null) return false;
return (bool)dyn;
}
public static object unbox(object dyn)
{
// This calls toDynamic via Runtime.callField, which will fast-path HxObject.
if (dyn != null && concat(global::Std.@string(global::cs.Lib.getNativeType(dyn)), "").StartsWith("haxe.lang.Null"))
return (object)global::haxe.lang.Runtime.callField(dyn, "toDynamic", 1705629508, null);
return dyn;
}
}
}