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

Executing any script using Jint 3 with Unity 2021.3 results in TypeLoadException #1564

Closed
lucidbard opened this issue Jun 15, 2023 · 19 comments

Comments

@lucidbard
Copy link

Version used

I'm using Unity version 2021.3.26f1, Jint version 3.0.0-beta-2049 (targeting netstandard-2.1) and Esprima 3.0.0-rc-02, SystemMemory version 4.5.5.

Describe the bug

I was successfully able to use Jira 2 from the tutorial . Any script using the Jira engine results in the error:

TypeLoadException: Failure has occurred while loading a type.
Jint.Runtime.Interpreter.Statements.JintExpressionStatement.Initialize (Jint.Runtime.Interpreter.EvaluationContext context) (at <0636d30103674fca8d470ee2d5418bc9>:0)
Jint.Runtime.Interpreter.Statements.JintStatement.Execute (Jint.Runtime.Interpreter.EvaluationContext context) (at <0636d30103674fca8d470ee2d5418bc9>:0)
Jint.Runtime.Interpreter.JintStatementList.Execute (Jint.Runtime.Interpreter.EvaluationContext context) (at <0636d30103674fca8d470ee2d5418bc9>:0)
Jint.Engine.ScriptEvaluation (Jint.Runtime.ScriptRecord scriptRecord) (at <0636d30103674fca8d470ee2d5418bc9>:0)
Jint.Engine+<>c__DisplayClass78_0.<Execute>b__0 () (at <0636d30103674fca8d470ee2d5418bc9>:0)
Jint.Engine.ExecuteWithConstraints[T] (System.Boolean strict, System.Func`1[TResult] callback) (at <0636d30103674fca8d470ee2d5418bc9>:0)
Jint.Engine.Execute (Esprima.Ast.Script script) (at <0636d30103674fca8d470ee2d5418bc9>:0)
Jint.Engine.Execute (System.String code, System.String source, Esprima.ParserOptions parserOptions) (at <0636d30103674fca8d470ee2d5418bc9>:0)
Jint.Engine.Execute (System.String code, System.String source) (at <0636d30103674fca8d470ee2d5418bc9>:0)
JavascriptRunner.Start () (at Assets/Scripts/JavascriptRunner.cs:23)

To Reproduce

Follow steps from tutorial Using real JavaScript with Unity, using the above versions of Jira.

using UnityEngine;
using Jint;
using System;
using Esprima;
using Jint.Runtime;
using Jint.Native;

public class JavascriptRunner : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
      try{

        var engine = new Engine();

        engine.SetValue("log", new Action<object>(msg => Debug.Log(msg)));

        JsValue v = engine.Evaluate(@"log('Hello World')", "test");
      } catch (TypeLoadException err)
      {
            Debug.Log(err.ToString());
      }
        // Debug.Log($"{worldModel.PlayerName} has {worldModel.NumberOfDonuts} donuts");
    }

}

Expected behavior

Should display "Hello World" to debug log.

@lucidbard lucidbard changed the title Executing any script using Jira 3 with Unity results in Executing any script using Jira 3 with Unity 2021.3 results in TypeLoadException Jun 15, 2023
@lucidbard lucidbard changed the title Executing any script using Jira 3 with Unity 2021.3 results in TypeLoadException Executing any script using Jint 3 with Unity 2021.3 results in TypeLoadException Jun 15, 2023
@lahma
Copy link
Collaborator

lahma commented Jun 25, 2023

You just might need a newer version of Unity. Unfortunately I don't have any Unity experience so cannot help with this one. Maybe you can try newer version of Unity and report back?

@lucidbard
Copy link
Author

No change when trying with Unity 2022.3.3f1 (with both .NET Framework (and corresponding 3.x libraries) or .NET Standard 2.1.

@lahma
Copy link
Collaborator

lahma commented Jun 27, 2023

@CreepGin can I pick your brain with this one. I know you have some experience with combining unity and jint 😉

@lucidbard
Copy link
Author

lucidbard commented Jun 27, 2023

Also just tested on Unity 2023.1.1f1 -- same results. Might be necessary to compile a debug version of Jint to see the type that's causing the exception.

Maybe unity's .NET profile support could be to blame: From their website:
https://docs.unity3d.com/Manual/dotnetProfileSupport.html

.NET Standard: .NET Standard 2.1, as published by the .NET Foundation.
.NET Framework 4.8, as published by Microsoft, plus additional APIs in .NET Standard 2.1.

@CreepGin
Copy link
Contributor

@lahma Sure ofc I'll take a stab at it =)

@lucidbard Has this been happening just for the recent Jint version (3.0.0-beta-2049)? The Jint version I'm using with Unity (without any problem) is a few months old.

I'm building the new Jint dll right now; will report back with any findings. (Apparently my current IDE needs updating; the Jint codebase now requires VS 2022 17.3+ to build)

@lucidbard
Copy link
Author

Thanks! I can do an incremental test on previous versions of Jint 3 -- it could be a recent change.

@CreepGin
Copy link
Contributor

CreepGin commented Jun 29, 2023

Okay I just finished my first round of testing. The latest changes in Jint did break a handful of stuff for me.

First the C#-side:

  • engine.Json and engine.Object are gone.
  • GetCompletionValue() is gone. It seems engine.Evaluate() is the preferred way now.

There are also now 2 hard JS errors that I need to spend more time on debugging. (Might be specific to my own setup).

But the following usage (from OP) of Jint in Unity worked fine for me:

engine.SetValue("log", new Action<object>(Debug.Log));
JsValue v = engine.Evaluate(@"log('Hello World')");

I'm on Windows, using Unity 2022.3. IL2CPP, compat level .NET Framework. (I tried a few other variants of these and all seemed to work fine as well).

I'll continue investigating

@lahma
Copy link
Collaborator

lahma commented Jun 30, 2023

  • engine.Json and engine.Object are gone.

Yes we've hidden everything that hasn't been requested to be visible. We try to open things via public API tests cases to ensure proper API is exposed and we don't accidentally hide it later. So if there's something needed missing - open a PR or an issue and we'll figure it out.

  • GetCompletionValue() is gone. It seems engine.Evaluate() is the preferred way now.

Yes. Execute just set the value inside the engine and you had to retrieve it manually. CompletionValue is more JS spec thing and Evaluate gives you the result you want. Execute is for running batch of commands which allows chaining.

@CreepGin
Copy link
Contributor

CreepGin commented Jun 30, 2023

Yup, thanks for the clarifications!

So a couple more breaking changes I found (though not Unity-specific).

new Length(n) in js no longer works for the following C# constructor (NullReferenceException somewhere in Jint.Runtime.TypeConverter.CalculateMethodParameterScore)

// Both LengthUnit and Length.Unit are enums
public Length(float value)
 : this(value, Length.Unit.Pixel)
{
}

public Length(float value, LengthUnit unit)
 : this(value, (Length.Unit) unit)
{
}

private Length(float value, Length.Unit unit)
 : this()
{
 this.value = value;
 this.m_Unit = unit;
}

I'm also experiencing some breakage from beta-2050 or beyond but don't know the culprit yet.

(I should probably start a separate thread 😊)

@lahma
Copy link
Collaborator

lahma commented Jul 1, 2023

The constructor matching should not be fixed with #1568 , The JsValue.Call problem would probably need some clarification, like example code.

@CreepGin
Copy link
Contributor

CreepGin commented Jul 1, 2023

The constructor matching should not be fixed with #1568 , The JsValue.Call problem would probably need some clarification, like example code.

Tyvm for the quick fix!

Yes so for the JsValue.Call, my old working code was the following: (pre-beta-2048)

// JS
globalThis.__setStyleProperty = function (style, key, value) {
    styleProcessors[key](style, value)
}
// C#
var globalThis = engine.GetValue("globalThis");
var func = globalThis.Get("__setStyleProperty");
func.Call(globalThis, JsValue.FromObject(engine, _dom.ve.style), key, val);

Before beta-2048, globalThis was needed as the 1st arg in the func.Call. But after beta-2048, globalThis seems to be no longer required and would actually be passed as the 1st arg to the target js function if left there.

Just appears to be a breaking change, not a bug or anything.

@lahma
Copy link
Collaborator

lahma commented Jul 1, 2023

Before beta-2048, globalThis was needed as the 1st arg in the func.Call. But after beta-2048, globalThis seems to be no longer required and would actually be passed as the 1st arg to the target js function if left there.

Just appears to be a breaking change, not a bug or anything.

Thanks for the clarification, IIRC, I changed the signatures you could earlier get different behavior based on parameter count so it was a bit ambiguous- beta label allows to do such surprising changes 😉

@lucidbard
Copy link
Author

I'm on Windows, using Unity 2022.3. IL2CPP, compat level .NET Framework. (I tried a few other variants of these and all seemed to work fine as well).

I'll continue investigating

Thanks for looking into it @CreepGin

Any idea why I might be getting that error? I have both jint.dll (-2049) and Esprima (3.0.0-rc-02). Did you use NuGet or put them into the Plugins folder? Any other factors that might contribute?

@CreepGin
Copy link
Contributor

CreepGin commented Jul 1, 2023

@lucidbard Yup, you got it. I just build from the repo using Visual Studio. Then I use the dlls from the Jint/bin/Release/net462 folder. I'm not sure if this make any difference, but if you select the dll asset in Unity, it should say "Assembly Info: Targets .NET 4.x".

@CreepGin
Copy link
Contributor

CreepGin commented Jul 1, 2023

Okay this one is Unity-specific. #1543 (beta-2050) has a ParameterInfo[].AsSpan usage which will throw ArrayTypeMismatchException in Mono (I think only when the target method is static).

It was reported to mono years ago (mono/mono#17993), but like many other mono bugs, I don't think they will get fixed anytime soon or ever.

This is breaking things like new Color(1, 1, 1, 1) with Unity, or anything similar to this:

// C#
public struct Foo {
    public Foo(float a, float b) {
    }

    public Foo(float a) {
    }
}
// JS
new Foo(1, 1) // throws ArrayTypeMismatchException: Attempted to access an element as a type incompatible with the array.

I submitted a PR for this: #1571

@CreepGin
Copy link
Contributor

CreepGin commented Jul 2, 2023

Oh another thing @lahma, the new test you provided in #1568 is throwing NullReferenceException for me.

Assert.Equal(12.3, engine.Evaluate("new Length(12.3).Value").AsNumber(), precision: 2);
  Message: 
    System.NullReferenceException : Object reference not set to an instance of an object.

  Stack Trace: 
    TypeConverter.CalculateMethodParameterScore(Engine engine, ParameterInfo parameter, JsValue parameterValue) line 1228
    TypeConverter.CalculateMethodScore(Engine engine, MethodDescriptor method, JsValue[] arguments) line 1145
    ....

UPDATE: Okay false alarm. It's been weird for me. After a rebase, the test passed. But after awhile (without changing anything), I ran the test, it failed again... And now it's passing again... I've no idea what's going on ¯\(ツ)

@lahma
Copy link
Collaborator

lahma commented Jul 2, 2023

OK cool, it seems that all open issues and problems have been addressed I guess - except for the original issue 😆

That seems still to be quite impossible to replicate - let's see if the build + installation instructions help.

@lucidbard
Copy link
Author

Good news and thank you @CreepGin ! I was able to run the code after compiling the latest version in the repository. It seems like the problem was with 2049. I did copy all dll files from the build folder, which may have also helped.

@lahma
Copy link
Collaborator

lahma commented Jul 2, 2023

Great to hear, so we can close this issue as resolved?

@lahma lahma closed this as completed Jul 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants