Skip to content

Commit

Permalink
#451 string comparison related performance improvements (#470)
Browse files Browse the repository at this point in the history
* change MruPropertyCache2 to have string key
* remove shared string property checks from ObjectInstance
* check length in array instance
* move prototype and constructor to ScriptFunctionInstance, specialize ObjectInstanceWithConstructor
  • Loading branch information
lahma authored and sebastienros committed Jan 24, 2018
1 parent ff0c6bb commit 34defd2
Show file tree
Hide file tree
Showing 11 changed files with 421 additions and 236 deletions.
12 changes: 6 additions & 6 deletions Jint/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -510,18 +510,18 @@ public object EvaluateExpression(INode expression)
/// <returns></returns>
public JsValue GetValue(object value)
{
var reference = value as Reference;
if (value is JsValue jsValue)
{
return jsValue;
}

var reference = value as Reference;
if (reference == null)
{
var completion = value as Completion;

if (completion != null)
if (value is Completion completion)
{
return GetValue(completion.Value);
}

return (JsValue)value;
}

if (reference.IsUnresolvableReference())
Expand Down
60 changes: 53 additions & 7 deletions Jint/Native/Array/ArrayInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public class ArrayInstance : ObjectInstance
{
private readonly Engine _engine;

private const string PropertyNameLength = "length";
private IPropertyDescriptor _length;

private const int MaxDenseArrayLength = 1024 * 10;

// we have dense and sparse, we usually can start with dense and fall back to sparse when necessary
Expand Down Expand Up @@ -75,7 +78,7 @@ public override void Put(string propertyName, JsValue value, bool throwOnError)

public override bool DefineOwnProperty(string propertyName, IPropertyDescriptor desc, bool throwOnError)
{
var oldLenDesc = GetOwnProperty("length");
var oldLenDesc = _length;
var oldLen = (uint) TypeConverter.ToNumber(oldLenDesc.Value);

if (propertyName == "length")
Expand Down Expand Up @@ -282,11 +285,36 @@ public override bool DefineOwnProperty(string propertyName, IPropertyDescriptor

public uint GetLength()
{
return GetLengthValue();
return TypeConverter.ToUint32(_length.Value);
}

protected override void AddProperty(string propertyName, IPropertyDescriptor descriptor)
{
if (propertyName == PropertyNameLength)
{
_length = descriptor;
return;
}
base.AddProperty(propertyName, descriptor);
}

protected override bool TryGetProperty(string propertyName, out IPropertyDescriptor descriptor)
{
if (propertyName == PropertyNameLength)
{
descriptor = _length;
return _length != null;
}
return base.TryGetProperty(propertyName, out descriptor);
}

public override IEnumerable<KeyValuePair<string, IPropertyDescriptor>> GetOwnProperties()
{
if (_length != null)
{
yield return new KeyValuePair<string, IPropertyDescriptor>(PropertyNameLength, _length);
}

if (_dense != null)
{
for (var i = 0; i < _dense.Length; i++)
Expand Down Expand Up @@ -323,6 +351,11 @@ public override IPropertyDescriptor GetOwnProperty(string propertyName)
return PropertyDescriptor.Undefined;
}

if (propertyName == PropertyNameLength)
{
return _length ?? PropertyDescriptor.Undefined;
}

return base.GetOwnProperty(propertyName);
}

Expand All @@ -332,6 +365,10 @@ protected internal override void SetOwnProperty(string propertyName, IPropertyDe
{
WriteArrayValue(index, desc);
}
else if (propertyName == PropertyNameLength)
{
_length = desc;
}
else
{
base.SetOwnProperty(propertyName, desc);
Expand All @@ -342,11 +379,16 @@ public override bool HasOwnProperty(string p)
{
if (IsArrayIndex(p, out var index))
{
return index < GetLengthValue()
return index < GetLength()
&& (_sparse == null || _sparse.ContainsKey(index))
&& (_dense == null || _dense[index] != null);
}

if (p == PropertyNameLength)
{
return _length != null;
}

return base.HasOwnProperty(p);
}

Expand All @@ -358,6 +400,11 @@ public override void RemoveOwnProperty(string p)
DeleteAt(index);
}

if (p == PropertyNameLength)
{
_length = null;
}

base.RemoveOwnProperty(p);
}

Expand Down Expand Up @@ -415,11 +462,10 @@ private static uint ParseArrayIndex(string p)

internal void SetIndexValue(uint index, JsValue value, bool throwOnError)
{
var length = GetLengthValue();
var length = GetLength();
if (index >= length)
{
var p = base.GetOwnProperty("length");
p.Value = index + 1;
_length.Value = index + 1;
}

WriteArrayValue(index, new ConfigurableEnumerableWritablePropertyDescriptor(value));
Expand Down Expand Up @@ -448,7 +494,7 @@ internal uint GetSmallestIndex()

public bool TryGetValue(uint index, out JsValue value)
{
value = JsValue.Undefined;
value = Undefined;

if (!TryGetDescriptor(index, out var desc)
|| desc == null
Expand Down
19 changes: 0 additions & 19 deletions Jint/Native/Function/FunctionConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using Esprima;
using Esprima.Ast;
using Jint.Native.Object;
using Jint.Native.String;
using Jint.Runtime;
using Jint.Runtime.Descriptors.Specialized;
using Jint.Runtime.Environments;
Expand Down Expand Up @@ -47,23 +46,6 @@ public override JsValue Call(JsValue thisObject, JsValue[] arguments)
return Construct(arguments);
}

private string[] ParseArgumentNames(string parameterDeclaration)
{
if (string.IsNullOrWhiteSpace(parameterDeclaration))
{
return System.Array.Empty<string>();
}

string[] values = parameterDeclaration.Split(ArgumentNameSeparator, StringSplitOptions.RemoveEmptyEntries);

var newValues = new string[values.Length];
for (var i = 0; i < values.Length; i++)
{
newValues[i] = StringPrototype.TrimEx(values[i]);
}
return newValues;
}

public ObjectInstance Construct(JsValue[] arguments)
{
var argCount = arguments.Length;
Expand All @@ -87,7 +69,6 @@ public ObjectInstance Construct(JsValue[] arguments)
body = TypeConverter.ToString(arguments[argCount-1]);
}

var parameters = this.ParseArgumentNames(p);
IFunction function;
try
{
Expand Down
109 changes: 93 additions & 16 deletions Jint/Native/Function/FunctionInstance.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
using Jint.Native.Object;
using System.Collections.Generic;
using Jint.Native.Object;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Environments;

namespace Jint.Native.Function
{
public abstract class FunctionInstance : ObjectInstance, ICallable
{
private const string PropertyNamePrototype = "prototype";
private IPropertyDescriptor _prototype;
private const string PropertyNameLength = "length";
private IPropertyDescriptor _length;

private readonly Engine _engine;

protected FunctionInstance(Engine engine, string[] parameters, LexicalEnvironment scope, bool strict) : base(engine)
Expand All @@ -24,10 +31,10 @@ protected FunctionInstance(Engine engine, string[] parameters, LexicalEnvironmen
/// <returns></returns>
public abstract JsValue Call(JsValue thisObject, JsValue[] arguments);

public LexicalEnvironment Scope { get; private set; }
public string[] FormalParameters { get; private set; }
public bool Strict { get; private set; }
public LexicalEnvironment Scope { get; }

public string[] FormalParameters { get; }
public bool Strict { get; }

public virtual bool HasInstance(JsValue v)
{
Expand All @@ -36,18 +43,18 @@ public virtual bool HasInstance(JsValue v)
{
return false;
}

var po = Get("prototype");
if (!po.IsObject())
{
throw new JavaScriptException(_engine.TypeError, string.Format("Function has non-object prototype '{0}' in instanceof check", TypeConverter.ToString(po)));
}

var o = po.AsObject();

if (o == null)
{
throw new JavaScriptException(_engine.TypeError);
throw new JavaScriptException(_engine.TypeError);
}

while (true)
Expand All @@ -58,20 +65,15 @@ public virtual bool HasInstance(JsValue v)
{
return false;
}

if (vObj == o)
{
return true;
}
}
}

public override string Class
{
get
{
return "Function";
}
}
public override string Class => "Function";

/// <summary>
/// http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5.4
Expand All @@ -90,5 +92,80 @@ public override JsValue Get(string propertyName)

return v;
}

public override IEnumerable<KeyValuePair<string, IPropertyDescriptor>> GetOwnProperties()
{
if (_prototype != null)
{
yield return new KeyValuePair<string, IPropertyDescriptor>(PropertyNamePrototype, _prototype);
}
if (_length != null)
{
yield return new KeyValuePair<string, IPropertyDescriptor>(PropertyNameLength, _length);
}

foreach (var entry in base.GetOwnProperties())
{
yield return entry;
}
}

public override IPropertyDescriptor GetOwnProperty(string propertyName)
{
if (propertyName == PropertyNamePrototype)
{
return _prototype ?? PropertyDescriptor.Undefined;
}
if (propertyName == PropertyNameLength)
{
return _length ?? PropertyDescriptor.Undefined;
}

return base.GetOwnProperty(propertyName);
}

protected internal override void SetOwnProperty(string propertyName, IPropertyDescriptor desc)
{
if (propertyName == PropertyNamePrototype)
{
_prototype = desc;
}
else if (propertyName == PropertyNameLength)
{
_length = desc;
}
else
{
base.SetOwnProperty(propertyName, desc);
}
}

public override bool HasOwnProperty(string propertyName)
{
if (propertyName == PropertyNamePrototype)
{
return _prototype != null;
}
if (propertyName == PropertyNameLength)
{
return _length != null;
}

return base.HasOwnProperty(propertyName);
}

public override void RemoveOwnProperty(string propertyName)
{
if (propertyName == PropertyNamePrototype)
{
_prototype = null;
}
if (propertyName == PropertyNameLength)
{
_prototype = null;
}

base.RemoveOwnProperty(propertyName);
}
}
}
}
Loading

0 comments on commit 34defd2

Please sign in to comment.