Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Locking to allow sumultaneous execution within same JS Engine #150

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions Jurassic/Compiler/Binders/Binder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ internal abstract class Binder
private BinderDelegate[] delegateCache;
private const int MaximumCachedParameterCount = 8;

[NonSerialized]
private Object lockObject = new Object();



Expand Down Expand Up @@ -82,23 +84,26 @@ public object Call(ScriptEngine engine, object thisObject, params object[] argum
/// the same parameter count will be markedly quicker. </remarks>
public BinderDelegate CreateDelegate(int argumentCount)
{
// If there are too many arguments, don't cache the delegate.
if (argumentCount > MaximumCachedParameterCount)
return CreateDelegateCore(argumentCount);

// Save the delegate that is created into a cache so it doesn't have to be created again.
if (this.delegateCache == null)
this.delegateCache = new BinderDelegate[MaximumCachedParameterCount + 1];
var binderDelegate = this.delegateCache[argumentCount];
if (binderDelegate == null)
lock (lockObject)
{
// Create a binding method.
binderDelegate = CreateDelegateCore(argumentCount);

// Store it in the cache.
this.delegateCache[argumentCount] = binderDelegate;
// If there are too many arguments, don't cache the delegate.
if (argumentCount > MaximumCachedParameterCount)
return CreateDelegateCore(argumentCount);

// Save the delegate that is created into a cache so it doesn't have to be created again.
if (this.delegateCache == null)
this.delegateCache = new BinderDelegate[MaximumCachedParameterCount + 1];
var binderDelegate = this.delegateCache[argumentCount];
if (binderDelegate == null)
{
// Create a binding method.
binderDelegate = CreateDelegateCore(argumentCount);

// Store it in the cache.
this.delegateCache[argumentCount] = binderDelegate;
}
return binderDelegate;
}
return binderDelegate;
}

/// <summary>
Expand Down
29 changes: 21 additions & 8 deletions Jurassic/Compiler/Binders/BinderMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal class BinderMethod
private int optionalParameterCount;
private Type paramArrayElementType;

private Object lockObject = new Object();


// INITIALIZATION
Expand Down Expand Up @@ -133,8 +134,11 @@ public int RequiredParameterCount
{
get
{
if (this.initialized == false)
Init();
lock (lockObject)
{
if (this.initialized == false)
Init();
}
return this.requiredParameterCount;
}
}
Expand All @@ -146,8 +150,11 @@ public int OptionalParameterCount
{
get
{
if (this.initialized == false)
Init();
lock (lockObject)
{
if (this.initialized == false)
Init();
}
return this.optionalParameterCount;
}
}
Expand All @@ -159,8 +166,11 @@ public bool HasParamArray
{
get
{
if (this.initialized == false)
Init();
lock (lockObject)
{
if (this.initialized == false)
Init();
}
return this.paramArrayElementType != null;
}
}
Expand All @@ -172,8 +182,11 @@ private Type ParamArrayElementType
{
get
{
if (this.initialized == false)
Init();
lock (lockObject)
{
if (this.initialized == false)
Init();
}
return this.paramArrayElementType;
}
}
Expand Down
14 changes: 9 additions & 5 deletions Jurassic/Library/ClrWrapper/ClrInstanceTypeWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace Jurassic.Library
[DebuggerTypeProxy(typeof(ClrInstanceTypeWrapperDebugView))]
internal class ClrInstanceTypeWrapper : ObjectInstance
{
private static Object lockObject = new Object();

// INITIALIZATION
//_________________________________________________________________________________________
Expand All @@ -28,11 +29,14 @@ public static ClrInstanceTypeWrapper FromCache(ScriptEngine engine, Type type)
throw new JavaScriptException(engine, ErrorType.TypeError, "Unsupported type: CLR types are not supported. Enable CLR types by setting the ScriptEngine's EnableExposedClrTypes property to true.");

ClrInstanceTypeWrapper cachedInstance;
if (engine.InstanceTypeWrapperCache.TryGetValue(type, out cachedInstance) == true)
return cachedInstance;
var newInstance = new ClrInstanceTypeWrapper(engine, type);
engine.InstanceTypeWrapperCache.Add(type, newInstance);
return newInstance;
lock (lockObject)
{
if (engine.InstanceTypeWrapperCache.TryGetValue(type, out cachedInstance) == true)
return cachedInstance;
var newInstance = new ClrInstanceTypeWrapper(engine, type);
engine.InstanceTypeWrapperCache.Add(type, newInstance);
return newInstance;
}
}

/// <summary>
Expand Down
64 changes: 34 additions & 30 deletions Jurassic/Library/Object/HiddenClassSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ private struct TransitionInfo
private HiddenClassSchema parent;
private TransitionInfo addPropertyTransitionInfo;

private object lockDuringAdd = new object();

/// <summary>
/// Creates a new HiddenClassSchema instance from a modify or delete operation.
/// </summary>
Expand Down Expand Up @@ -132,42 +134,44 @@ public SchemaProperty GetPropertyIndexAndAttributes(object key)
/// <returns> A new schema with the extra property. </returns>
public HiddenClassSchema AddProperty(object key, PropertyAttributes attributes = PropertyAttributes.FullAccess)
{
// Package the name and attributes into a struct.
var transitionInfo = new TransitionInfo() { Key = key, Attributes = attributes };
lock (this.lockDuringAdd)
{
// Package the name and attributes into a struct.
var transitionInfo = new TransitionInfo() { Key = key, Attributes = attributes };

// Check if there is a transition to the schema already.
HiddenClassSchema newSchema = null;
if (this.addTransitions != null)
this.addTransitions.TryGetValue(transitionInfo, out newSchema);
// Check if there is a transition to the schema already.
HiddenClassSchema newSchema = null;
if (this.addTransitions != null)
this.addTransitions.TryGetValue(transitionInfo, out newSchema);

if (newSchema == null)
{
if (this.parent == null)
if (newSchema == null)
{
// Create a new schema based on this one. A complete copy must be made of the properties hashtable.
var properties = new Dictionary<object, SchemaProperty>(this.properties);
properties.Add(key, new SchemaProperty(this.NextValueIndex, attributes));
newSchema = new HiddenClassSchema(properties, this.NextValueIndex + 1, this, transitionInfo);
if (this.parent == null)
{
// Create a new schema based on this one. A complete copy must be made of the properties hashtable.
var properties = new Dictionary<object, SchemaProperty>(this.properties);
properties.Add(key, new SchemaProperty(this.NextValueIndex, attributes));
newSchema = new HiddenClassSchema(properties, this.NextValueIndex + 1, this, transitionInfo);
}
else
{
// Create a new schema based on this one. The properties hashtable is "given
// away" so a copy does not have to be made.
if (this.properties == null)
this.properties = CreatePropertiesDictionary();
this.properties.Add(key, new SchemaProperty(this.NextValueIndex, attributes));
newSchema = new HiddenClassSchema(this.properties, this.NextValueIndex + 1, this, transitionInfo);
this.properties = null;
}

// Add a transition to the new schema.
if (this.addTransitions == null)
this.addTransitions = new Dictionary<TransitionInfo, HiddenClassSchema>(1);
this.addTransitions.Add(transitionInfo, newSchema);
}
else
{
// Create a new schema based on this one. The properties hashtable is "given
// away" so a copy does not have to be made.
if (this.properties == null)
this.properties = CreatePropertiesDictionary();
this.properties.Add(key, new SchemaProperty(this.NextValueIndex, attributes));
newSchema = new HiddenClassSchema(this.properties, this.NextValueIndex + 1, this, transitionInfo);
this.properties = null;
}


// Add a transition to the new schema.
if (this.addTransitions == null)
this.addTransitions = new Dictionary<TransitionInfo, HiddenClassSchema>(1);
this.addTransitions.Add(transitionInfo, newSchema);
return newSchema;
}

return newSchema;
}

/// <summary>
Expand Down
Loading