Jakub Míšek 2020-03-11 15:49:22 +01:00
Родитель ac5c82bfb0
Коммит f5b6e38e28
15 изменённых файлов: 136 добавлений и 111 удалений

Просмотреть файл

@ -2802,16 +2802,16 @@ namespace Pchp.CodeAnalysis.CodeGen
return t;
}
public void EmitIntStringKey(int key)
public void EmitIntStringKey(long key)
{
_il.EmitIntConstant(key);
EmitCall(ILOpCode.Newobj, CoreMethods.Ctors.IntStringKey_int);
_il.EmitLongConstant(key);
EmitCall(ILOpCode.Newobj, CoreMethods.Ctors.IntStringKey_long);
}
public void EmitIntStringKey(string key)
{
// try convert string to integer as it is in PHP:
if (TryConvertToIntKey(key, out int ikey))
if (TryConvertToIntKey(key, out var ikey))
{
EmitIntStringKey(ikey);
}
@ -2836,7 +2836,7 @@ namespace Pchp.CodeAnalysis.CodeGen
}
}
static bool TryConvertToIntKey(string key, out int ikey)
static bool TryConvertToIntKey(string key, out long ikey)
{
ikey = default;
@ -2858,7 +2858,7 @@ namespace Pchp.CodeAnalysis.CodeGen
}
return int.TryParse(key, out ikey);
return long.TryParse(key, out ikey);
}
public void EmitIntStringKey(BoundExpression expr)
@ -2878,7 +2878,7 @@ namespace Pchp.CodeAnalysis.CodeGen
}
else if (constant.Value is long l)
{
EmitIntStringKey((int)l);
EmitIntStringKey(l);
}
else if (constant.Value is int i)
{
@ -2886,7 +2886,7 @@ namespace Pchp.CodeAnalysis.CodeGen
}
else if (constant.Value is double d)
{
EmitIntStringKey((int)d);
EmitIntStringKey((long)d);
}
else if (constant.Value is bool b)
{

Просмотреть файл

@ -2507,7 +2507,7 @@ namespace Pchp.CodeAnalysis.Semantics
return cg.EmitCall(ILOpCode.Call, cg.CoreTypes.Operators.Method("GetListAccess", cg.CoreTypes.PhpValue));
}
static void EmitItemAssign(CodeGenerator cg, KeyValuePair<BoundExpression, BoundReferenceExpression> item, int index, IPlace arrplace)
static void EmitItemAssign(CodeGenerator cg, KeyValuePair<BoundExpression, BoundReferenceExpression> item, long index, IPlace arrplace)
{
var target = item;
if (target.Value == null)

Просмотреть файл

@ -862,7 +862,7 @@ namespace Pchp.CodeAnalysis.Symbols
Blob = ct.PhpString_Blob.Ctor();
PhpArray = ct.PhpArray.Ctor();
PhpArray_int = ct.PhpArray.Ctor(ct.Int32);
IntStringKey_int = ct.IntStringKey.Ctor(ct.Int32);
IntStringKey_long = ct.IntStringKey.Ctor(ct.Long);
IntStringKey_string = ct.IntStringKey.Ctor(ct.String);
ScriptAttribute_string = ct.ScriptAttribute.Ctor(ct.String);
PhpTraitAttribute = ct.PhpTraitAttribute.Ctor();
@ -885,7 +885,7 @@ namespace Pchp.CodeAnalysis.Symbols
PhpArray, PhpArray_int,
PhpString_Blob, PhpString_PhpString, PhpString_string_string, PhpString_PhpValue_Context,
Blob,
IntStringKey_int, IntStringKey_string,
IntStringKey_long, IntStringKey_string,
ScriptAttribute_string, PhpTraitAttribute, PharAttribute_string, PhpTypeAttribute_string_string, PhpFieldsOnlyCtorAttribute, PhpHiddenAttribute, NotNullAttribute,
DefaultValueAttribute_string,
ScriptDiedException, ScriptDiedException_Long, ScriptDiedException_PhpValue,

Просмотреть файл

@ -589,7 +589,7 @@ namespace Peachpie.Library.Network
return true;
}
internal static bool TrySetOption(this CURLResource ch, int option, PhpValue value, RuntimeTypeHandle callerCtx)
internal static bool TrySetOption(this CURLResource ch, long option, PhpValue value, RuntimeTypeHandle callerCtx)
{
switch (option)
{
@ -750,15 +750,18 @@ namespace Peachpie.Library.Network
/// <summary>
/// Lookups the constant name (CURLOPT_*) with given value.
/// </summary>
static string TryGetOptionName(int optionValue)
static string TryGetOptionName(long optionValue)
{
var field = typeof(CURLConstants).GetFields()
.Where(f => f.Name.StartsWith("CURLOPT_", StringComparison.Ordinal))
.First(f =>
{
var fval = f.GetRawConstantValue();
return (fval is int i && i == optionValue);
});
var field = typeof(CURLConstants)
.GetFields()
.FirstOrDefault(f =>
f.Name.StartsWith("CURLOPT_", StringComparison.Ordinal) &&
f.GetRawConstantValue() switch
{
int i => i == optionValue,
long l => l == optionValue,
_ => false,
});
return field != null ? field.Name : optionValue.ToString();
}

Просмотреть файл

@ -1443,7 +1443,7 @@ namespace Peachpie.Library.XmlDom
/// <summary>
/// Returns the <paramref name="index"/>th sibling with the same local name and namespace URI or <B>null</B>.
/// </summary>
private XmlElement GetSiblingForIndex(int index)
private XmlElement GetSiblingForIndex(long index)
{
if (index <= 0) return XmlElement;
@ -1464,7 +1464,7 @@ namespace Peachpie.Library.XmlDom
/// <summary>
/// Returns the <param name="index"/>th attribute with the current namespace URI or<B>null</B>.
/// </summary>
private XmlAttribute GetAttributeForIndex(int index)
private XmlAttribute GetAttributeForIndex(long index)
{
foreach (XmlAttribute attr in XmlElement.Attributes)
{

Просмотреть файл

@ -290,7 +290,7 @@ namespace Pchp.Library
return false;
}
int desc_no = e.CurrentKey.Integer;
var desc_no = e.CurrentKey.Integer;
switch (desc_no)
{
@ -310,7 +310,7 @@ namespace Pchp.Library
var descriptors_enum = descriptors.GetFastEnumerator();
while (descriptors_enum.MoveNext())
{
int desc_no = descriptors_enum.CurrentKey.Integer;
var desc_no = descriptors_enum.CurrentKey.Integer;
StreamAccessOptions access;
Stream stream;

Просмотреть файл

@ -473,9 +473,7 @@ namespace Pchp.Core
/// </summary>
public static PhpNumber ToNumber(string str)
{
long l;
double d;
var info = StringToNumber(str, out l, out d);
var info = StringToNumber(str, out var l, out var d);
return ((info & NumberInfo.Double) != 0) ? PhpNumber.Create(d) : PhpNumber.Create(l);
}
@ -546,17 +544,10 @@ namespace Pchp.Core
/// <summary>
/// Converts given value to an array key.
/// </summary>
public static IntStringKey ToIntStringKey(PhpValue value)
{
if (value.TryToIntStringKey(out IntStringKey key))
{
return key;
}
else
{
throw new ArgumentException();
}
}
/// <exception cref="ArgumentException">The value cannot be converted to <see cref="IntStringKey"/>.</exception>
public static IntStringKey ToIntStringKey(PhpValue value) => value.TryToIntStringKey(out var key)
? key
: throw new ArgumentException();
/// <summary>
/// Tries conversion to an array key.
@ -607,7 +598,7 @@ namespace Pchp.Core
Debug.Assert(index < str.Length, "str == {" + str + "}");
// simple <int> parser:
long result = (int)str[index] - '0';
long result = (str[index] - '0');
Debug.Assert(result != 0, "str == {" + str + "}");
if (result < 0 || result > 9) // not a number
@ -615,15 +606,19 @@ namespace Pchp.Core
while (++index < str.Length)
{
int c = (int)str[index] - '0';
int c = str[index] - '0';
if (c >= 0 && c <= 9)
{
// update <result>
var previous = result;
result = unchecked(c + result * 10);
// <int> range check
if (Utilities.NumberUtils.IsInt32(result))
continue; // still in <int> range
// overflow check
if (previous <= result)
{
// did not overflow
continue;
}
}
//
@ -632,13 +627,17 @@ namespace Pchp.Core
if (sign)
{
result = -result;
if (!Utilities.NumberUtils.IsInt32(result))
result = unchecked(-result);
if (result > 0)
{
// overflow
return new IntStringKey(str);
}
}
// <int> parsed properly:
return new IntStringKey(unchecked((int)result));
return new IntStringKey(result);
}
#endregion

Просмотреть файл

@ -77,7 +77,7 @@ namespace Pchp.Core.Dynamic
public static MethodInfo PhpArray_Remove = typeof(PhpHashtable).GetMethod("Remove", typeof(Core.IntStringKey)); // PhpHashtable.Remove(IntStringKey) returns bool
public static MethodInfo PhpArray_TryGetValue = typeof(PhpArray).GetMethod("TryGetValue", typeof(Core.IntStringKey), Types.PhpValue.MakeByRefType());
public static MethodInfo PhpArray_ContainsKey = typeof(PhpArray).GetMethod("ContainsKey", typeof(Core.IntStringKey));
public static MethodInfo ToBoolean_PhpArray = typeof(PhpArray).GetOpExplicit(typeof(bool));
public static MethodInfo ToBoolean_PhpValue = typeof(PhpValue).GetOpImplicit(typeof(bool));
public static MethodInfo ToBoolean_PhpNumber = typeof(PhpNumber).GetOpImplicit(typeof(bool));
@ -124,7 +124,7 @@ namespace Pchp.Core.Dynamic
public static class IntStringKey
{
public static ConstructorInfo ctor_String = typeof(Core.IntStringKey).GetCtor(Types.String);
public static ConstructorInfo ctor_Int = typeof(Core.IntStringKey).GetCtor(Types.Int);
public static ConstructorInfo ctor_Long = typeof(Core.IntStringKey).GetCtor(Types.Long);
}
public static class PhpAlias
@ -161,17 +161,18 @@ namespace Pchp.Core.Dynamic
public static MethodInfo GetMethod(this Type type, string name, params Type[] ptypes)
{
var result = type.GetRuntimeMethod(name, ptypes);
if (result == null)
if (result != null)
{
foreach (var m in type.GetTypeInfo().GetDeclaredMethods(name)) // non public methods
return result;
}
foreach (var m in type.GetTypeInfo().GetDeclaredMethods(name)) // non public methods
{
if (ParamsMatch(m.GetParameters(), ptypes))
return m;
}
}
Debug.Assert(result != null);
return result;
throw new InvalidOperationException($"{type.Name}.{name}({string.Join<Type>(", ", ptypes)}) was not resolved.");
}
static MethodInfo GetOpImplicit(this Type type, Type resultType) =>
@ -179,7 +180,7 @@ namespace Pchp.Core.Dynamic
static MethodInfo GetOpExplicit(this Type type, Type resultType) =>
GetOpMethod(type, "op_Explicit", resultType);
static MethodInfo GetOpMethod(Type type, string opname, Type resultType)
{
var methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
@ -191,7 +192,7 @@ namespace Pchp.Core.Dynamic
}
}
throw new InvalidOperationException();
throw new InvalidOperationException($"{resultType.Name} {type.Name}.{opname} was not resolved.");
}
static bool ParamsMatch(ParameterInfo[] ps, Type[] ptypes)
@ -219,7 +220,7 @@ namespace Pchp.Core.Dynamic
}
}
throw new ArgumentException();
throw new InvalidOperationException($"{type.Name}..ctor({string.Join<Type>(", ", ptypes)}) was not resolved.");
}
}
}

Просмотреть файл

@ -440,8 +440,8 @@ namespace Pchp.Core.Dynamic
{
var source = expr.Type;
if (source == typeof(int)) return Expression.New(Cache.IntStringKey.ctor_Int, expr);
if (source == typeof(long)) return Expression.New(Cache.IntStringKey.ctor_Int, Expression.Convert(expr, Cache.Types.Int[0]));
if (source == typeof(int)) return Expression.New(Cache.IntStringKey.ctor_Long, Expression.Convert(expr, Cache.Types.Long[0]));
if (source == typeof(long)) return Expression.New(Cache.IntStringKey.ctor_Long, expr);
if (source == typeof(string)) return Expression.New(Cache.IntStringKey.ctor_String, expr);
// following conversions may throw an exception

Просмотреть файл

@ -420,40 +420,56 @@ namespace Pchp.Core
public PhpValue GetItemValue(IntStringKey key)
{
if (key.IsInteger)
return PhpValue.FromClr(_array[key.Integer]);
if (key.IsInteger && Utilities.NumberUtils.IsInt32(key.Integer))
{
return PhpValue.FromClr(_array[unchecked((int)key.Integer)]);
}
else
{
throw new ArgumentException(nameof(key));
}
}
public PhpValue GetItemValue(PhpValue index) => GetItemValue(index.ToIntStringKey());
public void RemoveKey(IntStringKey key)
{
if (key.IsInteger)
_array.RemoveAt(key.Integer);
if (key.IsInteger && Utilities.NumberUtils.IsInt32(key.Integer))
{
_array.RemoveAt(unchecked((int)key.Integer));
}
else
{
throw new ArgumentException(nameof(key));
}
}
public void RemoveKey(PhpValue index) => RemoveKey(index.ToIntStringKey());
public void SetItemAlias(IntStringKey key, PhpAlias alias)
{
if (key.IsInteger)
_array[key.Integer] = ToObject(alias.Value);
if (key.IsInteger && Utilities.NumberUtils.IsInt32(key.Integer))
{
_array[unchecked((int)key.Integer)] = ToObject(alias.Value);
}
else
{
throw new ArgumentException(nameof(key));
}
}
public void SetItemAlias(PhpValue index, PhpAlias alias) => SetItemAlias(index.ToIntStringKey(), alias);
public void SetItemValue(IntStringKey key, PhpValue value)
{
if (key.IsInteger)
_array[key.Integer] = ToObject(value);
if (key.IsInteger && Utilities.NumberUtils.IsInt32(key.Integer))
{
_array[unchecked((int)key.Integer)] = ToObject(value);
}
else
{
throw new ArgumentException(nameof(key));
}
}
public void SetItemValue(PhpValue index, PhpValue value) => SetItemValue(index.ToIntStringKey(), value);
@ -610,11 +626,11 @@ namespace Pchp.Core
/// <param name="value">String to be accessed as array.</param>
/// <param name="index">Index.</param>
/// <returns>Character on index or empty string if index is our of range.</returns>
public static string GetItemValue(string value, int index)
public static string GetItemValue(string value, long index)
{
return (value != null && index >= 0 && index < value.Length)
? value[index].ToString()
: string.Empty;
? value[unchecked((int)index)].ToString()
: string.Empty; // TODO: quiet ?
}
/// <summary>
@ -622,9 +638,9 @@ namespace Pchp.Core
/// </summary>
public static string GetItemValue(string value, IntStringKey key)
{
int index = key.IsInteger
var index = key.IsInteger
? key.Integer
: (int)Convert.StringToLongInteger(key.String);
: Convert.StringToLongInteger(key.String);
return GetItemValue(value, index);
}
@ -634,12 +650,12 @@ namespace Pchp.Core
/// </summary>
public static string GetItemValueOrNull(string value, IntStringKey key)
{
int index = key.IsInteger
var index = key.IsInteger
? key.Integer
: (int)Convert.StringToLongInteger(key.String);
: Convert.StringToLongInteger(key.String);
return (value != null && index >= 0 && index < value.Length)
? value[index].ToString()
? value[unchecked((int)index)].ToString()
: null;
}
@ -648,9 +664,9 @@ namespace Pchp.Core
/// </summary>
public static string GetItemValue(string value, PhpValue index, bool quiet)
{
if (Convert.TryToIntStringKey(index, out var key))
if (value != null && Convert.TryToIntStringKey(index, out var key))
{
int i;
long i;
if (key.IsInteger)
{
@ -660,12 +676,12 @@ namespace Pchp.Core
{
if (quiet) return null;
i = (int)Convert.StringToLongInteger(key.String);
i = Convert.StringToLongInteger(key.String);
}
if (value != null && i >= 0 && i < value.Length)
if (i >= 0 && i < value.Length)
{
return value[i].ToString();
return value[(int)i].ToString();
}
}
@ -838,7 +854,7 @@ namespace Pchp.Core
{
if (key.Integer >= 0 && key.Integer < list.Count)
{
return PhpValue.FromClr(list[index.ToIntStringKey().Integer]);
return PhpValue.FromClr(list[(int)key.Integer]);
}
else if (!quiet)
{

Просмотреть файл

@ -44,19 +44,19 @@ namespace Pchp.Core
public bool Equals(IntStringKey x, IntStringKey y) => x._ikey == y._ikey && x._skey == y._skey;
public int GetHashCode(IntStringKey x) => x._ikey;
public int GetHashCode(IntStringKey x) => (int)x._ikey;
}
/// <summary>
/// Max value of <see cref="Integer"/>.
/// </summary>
internal const int MaxKeyValue = int.MaxValue; // TODO: change this and "Integer" to long64
internal const long MaxKeyValue = long.MaxValue;
/// <summary>
/// Integer value iff <see cref="IsString"/> return <B>false</B>.
/// </summary>
public int Integer => _ikey;
readonly int _ikey; // Holds string hashcode if skey != null
public long Integer => _ikey;
readonly long _ikey; // Holds string hashcode if skey != null
/// <summary>
/// String value iff <see cref="IsString"/> return <B>true</B>.
@ -75,7 +75,7 @@ namespace Pchp.Core
/// </summary>
public bool IsEmpty => Equals(EmptyStringKey);
public IntStringKey(int key)
public IntStringKey(long key)
{
_ikey = key;
_skey = null;
@ -103,7 +103,7 @@ namespace Pchp.Core
{
if (key is string str) return new IntStringKey(str);
if (key is int i) return new IntStringKey(i);
throw new ArgumentException();
}
@ -111,7 +111,7 @@ namespace Pchp.Core
public bool IsInteger => ReferenceEquals(_skey, null);
public override int GetHashCode() => _ikey;
public override int GetHashCode() => unchecked((int)_ikey);
public bool Equals(IntStringKey other) => _ikey == other._ikey && _skey == other._skey;
@ -124,7 +124,7 @@ namespace Pchp.Core
if (IsInteger)
{
if (other.IsInteger)
return _ikey - other._ikey;
return _ikey.CompareTo(other._ikey);
else
return string.CompareOrdinal(_ikey.ToString(), other._skey);
}
@ -195,7 +195,7 @@ namespace Pchp.Core
int _dataDeleted; // number of deleted elements within (0.._dataUsed] => Count = _dataUsed - _dataDeleted
uint _size; // physical size of the table (power of 2, minimum 8)
//int nInternalPointer; // intrinsic enumerator pointer
int _nextFreeKey; // the next integer key that will be used when inserting an element. It is one larger than the largest integer key that was ever used in this hashtable.
long _nextFreeKey; // the next integer key that will be used when inserting an element. It is one larger than the largest integer key that was ever used in this hashtable.
/// <summary>
/// Additional references sharing this object.
@ -228,9 +228,9 @@ namespace Pchp.Core
return mask;
}
int _get_max_int_key()
long _get_max_int_key()
{
int max = -1;
long max = -1;
var data = this._data;
for (int i = 0; i < this._dataUsed; i++)
{
@ -404,7 +404,7 @@ namespace Pchp.Core
_rehash();
}
private int _index(IntStringKey key) => (int)_mask & key.Integer;
private int _index(IntStringKey key) => unchecked((int)_mask & (int)key.Integer);
[Conditional("DEBUG")]
private void _debug_check()
@ -575,16 +575,16 @@ namespace Pchp.Core
if (IsPacked)
{
// packed array
index = key.Integer;
if (index < 0 || index >= _dataUsed || key.IsString)
// NOTE: packed array cannot be larger than Int32.MaxValue
if (key.IsInteger && key.Integer >= 0 && key.Integer < _dataUsed)
{
index = _invalidIndex;
Debug.Assert(!_data[key.Integer].IsDeleted);
index = (int)key.Integer;
}
else
{
Debug.Assert(!_data[index].IsDeleted);
index = _invalidIndex;
}
}
else
@ -717,7 +717,7 @@ namespace Pchp.Core
/// <summary>
/// Gets value for <see cref="_nextFreeKey"/>.
/// </summary>
static int _getNextFreeKey(int key) => key < IntStringKey.MaxKeyValue ? key + 1 : IntStringKey.MaxKeyValue;
static long _getNextFreeKey(long key) => key < IntStringKey.MaxKeyValue ? key + 1 : IntStringKey.MaxKeyValue;
/// <summary>
/// Adds value to the end of collection with newly assigned numeric key.
@ -770,7 +770,7 @@ namespace Pchp.Core
bucket.Key = key;
bucket.Value = value;
this._dataUsed = i + 1;
this._dataUsed = i + 1; // TODO: Overflow check
// hash table

Просмотреть файл

@ -1362,8 +1362,8 @@ namespace Pchp.Core
/// </summary>
PhpValue IPhpArray.GetItemValue(IntStringKey key)
{
int index = key.IsInteger ? key.Integer : (int)Convert.StringToLongInteger(key.String);
return (index >= 0 && index < this.Length) ? this[index].AsValue() : PhpValue.Create(string.Empty);
var index = key.IsInteger ? key.Integer : Convert.StringToLongInteger(key.String);
return (index >= 0 && index < this.Length) ? this[(int)index].AsValue() : PhpValue.Create(string.Empty);
}
PhpValue IPhpArray.GetItemValue(PhpValue index)
@ -1378,7 +1378,7 @@ namespace Pchp.Core
void IPhpArray.SetItemValue(PhpValue index, PhpValue value)
{
if (index.TryToIntStringKey(out IntStringKey key))
if (index.TryToIntStringKey(out var key))
{
((IPhpArray)this).SetItemValue(key, value);
}
@ -1393,8 +1393,15 @@ namespace Pchp.Core
/// </summary>
void IPhpArray.SetItemValue(IntStringKey key, PhpValue value)
{
int index = key.IsInteger ? key.Integer : (int)Convert.StringToLongInteger(key.String);
this[index] = value;
var index = key.IsInteger ? key.Integer : Convert.StringToLongInteger(key.String);
if (NumberUtils.IsInt32(index))
{
this[(int)index] = value;
}
else
{
throw new NotSupportedException();
}
}
/// <summary>

Просмотреть файл

@ -580,11 +580,11 @@ namespace Pchp.Core
return true;
case PhpTypeCode.Long:
key = new IntStringKey(checked((int)Long));
key = new IntStringKey(Long);
return true;
case PhpTypeCode.Double:
key = new IntStringKey((int)Double);
key = new IntStringKey((long)Double);
return true;
case PhpTypeCode.String:

Просмотреть файл

@ -16,8 +16,7 @@ namespace Pchp.Core.Utilities
/// </summary>
public static bool IsInt32(long l)
{
int i = unchecked((int)l);
return (i == l);
return l == unchecked((int)l);
}
/// <summary>Calculates the quotient of two 32-bit signed integers and also returns the remainder in an output parameter.</summary>

Просмотреть файл

@ -149,7 +149,7 @@ namespace Peachpie.Runtime.Tests
array.Shuffle(new Random());
var set = new HashSet<int>();
var set = new HashSet<long>();
foreach (var pair in array)
{
@ -207,7 +207,7 @@ namespace Peachpie.Runtime.Tests
{
public int Compare(KeyValuePair<IntStringKey, PhpValue> x, KeyValuePair<IntStringKey, PhpValue> y)
{
return x.Key.Integer - y.Key.Integer;
return x.Key.Integer.CompareTo(y.Key.Integer);
}
}