Skip to content

Commit

Permalink
perf: optimize Promise
Browse files Browse the repository at this point in the history
  • Loading branch information
LazuliKao committed Jul 30, 2023
1 parent 5707237 commit c6c9a3d
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 135 deletions.
128 changes: 2 additions & 126 deletions src/Loader/Modules/IO/FileModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,136 +4,12 @@
using Hosihikari.VanillaScript.QuickJS.Types;
using Hosihikari.VanillaScript.QuickJS.Wrapper;
using System.Runtime.InteropServices;
using Hosihikari.Minecraft.Extension;
using Hosihikari.VanillaScript.QuickJS.Extensions.Check;

namespace Hosihikari.VanillaScript.Loader.Modules.IO;

internal static class FileModule
{
private static void AwaitTask(
nint ctxPtr,
JsValue thisObj,
(SafeJsValue resolve, SafeJsValue reject) promise,
Task tasks
)
{
var safeThis = new SafeJsValue(thisObj);
Task.Run(async () =>
{
try
{
await tasks.ConfigureAwait(false);
LevelTick.PostTick(() =>
{
unsafe
{
if (JsContextWrapper.TryGet(ctxPtr, out var ctx))
{
Native.JS_Call(
ctx.Context,
promise.resolve.Instance,
safeThis.Instance,
0,
null
);
}
}
});
}
catch (Exception ex)
{
LevelTick.PostTick(() =>
{
var reason = ex.ToString();
unsafe
{
if (JsContextWrapper.TryGet(ctxPtr, out var ctx))
{
var reasonObj = JsValueCreateHelper
.NewString(ctx.Context, reason)
.Steal();
Native.JS_Call(
ctx.Context,
promise.reject.Instance,
safeThis.Instance,
1,
&reasonObj
);
}
}
});
}
});
}

/// <summary>
/// wrap Task to Promise
/// </summary>
/// <typeparam name="T"> result type </typeparam>
/// <param name="ctxPtr"></param>
/// <param name="thisObj"></param>
/// <param name="promise"></param>
/// <param name="tasks"></param>
/// <param name="fetchResult"></param>
private static void AwaitTask<T>(
nint ctxPtr,
JsValue thisObj,
(SafeJsValue resolve, SafeJsValue reject) promise,
Task<T> tasks,
Func<T, JsValue> fetchResult
)
{
var safeThis = new SafeJsValue(thisObj);
Task.Run(async () =>
{
try
{
var result = await tasks.ConfigureAwait(false);
LevelTick.PostTick(() =>
{
var resultObj = fetchResult(result);
unsafe
{
if (JsContextWrapper.TryGet(ctxPtr, out var ctx))
{
Native.JS_Call(
ctx.Context,
promise.resolve.Instance,
safeThis.Instance,
1,
&resultObj
);
}
}
});
}
catch (Exception ex)
{
LevelTick.PostTick(() =>
{
var reason = ex.ToString();
unsafe
{
if (JsContextWrapper.TryGet(ctxPtr, out var ctx))
{
var reasonObj = JsValueCreateHelper
.NewString(ctx.Context, reason)
.Steal();
Native.JS_Call(
ctx.Context,
promise.reject.Instance,
safeThis.Instance,
1,
&reasonObj
);
}
}
});
}
});
}

public static void Setup(JsContextWrapper ctx)
{
unsafe
Expand Down Expand Up @@ -186,7 +62,7 @@ static JsValue FileReadAllText(
#if JsPromise
var (promise, resolve, reject) = JsValueCreateHelper.NewPromise(ctx);
AwaitTask(
JsPromiseHelper.AwaitTask(
(nint)ctx,
thisObj,
(resolve, reject),
Expand Down Expand Up @@ -225,7 +101,7 @@ static JsValue FileWriteAllText(
argv[1].InsureTypeString(ctx, out var content);
#if JsPromise
var (promise, resolve, reject) = JsValueCreateHelper.NewPromise(ctx);
AwaitTask(
JsPromiseHelper.AwaitTask(
(nint)ctx,
thisObj,
(resolve, reject),
Expand Down
11 changes: 11 additions & 0 deletions src/QuickJS/Extensions/JsValueExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,17 @@ public static unsafe bool DefineProperty(
return Native.JS_DefinePropertyValueStr(ctx, @this, propertyName, value, flags);
}

public static unsafe bool DefineProperty(
this JsValue @this,
JsContext* ctx,
uint propertyAtom,
JsValue value,
JsPropertyFlags flags = JsPropertyFlags.CWE
)
{
return Native.JS_DefinePropertyValue(ctx, @this, propertyAtom, value, flags);
}

public static unsafe bool DefineFunction(
this JsValue @this,
JsContext* ctx,
Expand Down
154 changes: 154 additions & 0 deletions src/QuickJS/Helper/JsPromiseHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using Hosihikari.Minecraft.Extension;

Check failure on line 1 in src/QuickJS/Helper/JsPromiseHelper.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'Minecraft' does not exist in the namespace 'Hosihikari' (are you missing an assembly reference?)
using Hosihikari.VanillaScript.QuickJS.Extensions;
using Hosihikari.VanillaScript.QuickJS.Types;
using Hosihikari.VanillaScript.QuickJS.Wrapper;

namespace Hosihikari.VanillaScript.QuickJS.Helper;

public static class JsPromiseHelper
{
internal static JsValue BuildErrorJsValue(this JsContextWrapper ctx, Exception exception)
{
unsafe
{
var errorObj = JsValueCreateHelper.NewError(ctx.Context).Steal();
/*
JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
JS_NewString(ctx, buf),
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
*/
errorObj.DefineProperty(
ctx.Context,
JsAtomConst.Message,
JsValueCreateHelper.NewString(ctx.Context, exception.Message).Steal(),
JsPropertyFlags.Writable | JsPropertyFlags.Configurable
);
errorObj.DefineProperty(
ctx.Context,
JsAtomConst.Stack,
JsValueCreateHelper.NewString(ctx.Context, exception.StackTrace ?? "").Steal(),
JsPropertyFlags.Writable | JsPropertyFlags.Configurable
);
//todo JsAtomConst.ToStringFunc define .toString() function for errorObj
return errorObj;
}
}

public static void AwaitTask(
nint ctxPtr,
JsValue thisObj,
(SafeJsValue resolve, SafeJsValue reject) promise,
Task tasks
)
{
var safeThis = new SafeJsValue(thisObj);
Task.Run(async () =>
{
try
{
await tasks.ConfigureAwait(false);
LevelTick.PostTick(() =>
{
unsafe
{
if (JsContextWrapper.TryGet(ctxPtr, out var ctx))
{
Native.JS_Call(
ctx.Context,
promise.resolve.Instance,
safeThis.Instance,
0,
null
);
}
}
});
}
catch (Exception ex)
{
LevelTick.PostTick(() =>
{
var reason = ex.ToString();
unsafe
{
if (JsContextWrapper.TryGet(ctxPtr, out var ctx))
{
var reasonObj = ctx.BuildErrorJsValue(ex);
Native.JS_Call(
ctx.Context,
promise.reject.Instance,
safeThis.Instance,
1,
&reasonObj
);
}
}
});
}
});
}

/// <summary>
/// wrap Task to Promise
/// </summary>
/// <typeparam name="T"> result type </typeparam>
/// <param name="ctxPtr"></param>
/// <param name="thisObj"></param>
/// <param name="promise"></param>
/// <param name="tasks"></param>
/// <param name="fetchResult"></param>
public static void AwaitTask<T>(
nint ctxPtr,
JsValue thisObj,
(SafeJsValue resolve, SafeJsValue reject) promise,
Task<T> tasks,
Func<T, JsValue> fetchResult
)
{
var safeThis = new SafeJsValue(thisObj);
Task.Run(async () =>
{
try
{
var result = await tasks.ConfigureAwait(false);
LevelTick.PostTick(() =>
{
var resultObj = fetchResult(result);
unsafe
{
if (JsContextWrapper.TryGet(ctxPtr, out var ctx))
{
Native.JS_Call(
ctx.Context,
promise.resolve.Instance,
safeThis.Instance,
1,
&resultObj
);
}
}
});
}
catch (Exception ex)
{
LevelTick.PostTick(() =>
{
unsafe
{
if (JsContextWrapper.TryGet(ctxPtr, out var ctx))
{
var reasonObj = ctx.BuildErrorJsValue(ex);
Native.JS_Call(
ctx.Context,
promise.reject.Instance,
safeThis.Instance,
1,
&reasonObj
);
}
}
});
}
});
}
}
6 changes: 6 additions & 0 deletions src/QuickJS/Helper/JsValueCreateHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,12 @@ public static unsafe AutoDropJsValue NewObject(JsContext* ctx)
return Native.JS_NewObject(ctx);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe AutoDropJsValue NewError(JsContext* ctx)
{
return Native.JS_NewError(ctx);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe AutoDropJsValue NewPromise(
JsContext* ctx,
Expand Down
Loading

0 comments on commit c6c9a3d

Please sign in to comment.