BowlerHatLLC / vscode-as3mxml

ActionScript & MXML language extension for Visual Studio Code. Develop apps for Adobe AIR, Adobe Flash Player, or Apache Royale.
https://as3mxml.com/
Apache License 2.0
256 stars 39 forks source link

ArrayIndexOutOfBoundsException and NegativeArraySizeException problems on functions #724

Open hachigoro opened 8 months ago

hachigoro commented 8 months ago

Hello,

I have been working on a large AS3 project on FlashDevelop for a long time, and I am trying to move it to VS Code using your plugin. Most of it works well, but I am getting some errors on the editor that shouldn't be marked as errors, as they build fine. One of them highlights in red an entire function in a class. The function definition looks like this:

public static function GetCategoryTooltipLocKey(category:int, bTargeted:Boolean = false, bEncouraged:Boolean = true):LocKey

The error I am getting is:

[{
    "resource": "/C:/xyz/ClubCriteriaCategory.as",
    "owner": "_generated_diagnostic_collection_name_#2",
    "code": "1317",
    "severity": 8,
    "message": "java.lang.ArrayIndexOutOfBoundsException: -2147483647\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGeneratingReducer.reduce_lookup_switchStmt(ABCGeneratingReducer.java:5746)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGeneratingReducer.reduce_switchStmt(ABCGeneratingReducer.java:5612)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.action_452(CmcEmitter.java:6362)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.dispatchAction(CmcEmitter.java:9142)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduceAntecedent(CmcEmitter.java:39127)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduce(CmcEmitter.java:39104)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduceSubgoals(CmcEmitter.java:39155)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduceAntecedent(CmcEmitter.java:39126)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduce(CmcEmitter.java:39104)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduceSubgoals(CmcEmitter.java:39146)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduceAntecedent(CmcEmitter.java:39126)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduce(CmcEmitter.java:39104)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.burm(CmcEmitter.java:39406)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGenerator.generateInstructions(ABCGenerator.java:235)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGenerator.generateMethodBodyForFunction(ABCGenerator.java:416)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGenerator.generateMethodBodyForFunction(ABCGenerator.java:370)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGenerator.generateFunction(ABCGenerator.java:272)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ClassDirectiveProcessor.declareFunction(ClassDirectiveProcessor.java:880)\r\n\tat org.apache.royale.compiler.internal.as.codegen.DirectiveProcessor.processNode(DirectiveProcessor.java:218)\r\n\tat org.apache.royale.compiler.internal.as.codegen.DirectiveProcessor.traverse(DirectiveProcessor.java:192)\r\n\tat org.apache.royale.compiler.internal.as.codegen.GlobalDirectiveProcessor.declareClass(GlobalDirectiveProcessor.java:462)\r\n\tat org.apache.royale.compiler.internal.as.codegen.DirectiveProcessor.processNode(DirectiveProcessor.java:210)\r\n\tat org.apache.royale.compiler.internal.as.codegen.DirectiveProcessor.traverse(DirectiveProcessor.java:192)\r\n\tat org.apache.royale.compiler.internal.as.codegen.GlobalDirectiveProcessor.declarePackage(GlobalDirectiveProcessor.java:488)\r\n\tat org.apache.royale.compiler.internal.as.codegen.DirectiveProcessor.processNode(DirectiveProcessor.java:227)\r\n\tat org.apache.royale.compiler.internal.as.codegen.DirectiveProcessor.traverse(DirectiveProcessor.java:192)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGenerator.generate(ABCGenerator.java:126)\r\n\tat org.apache.royale.compiler.internal.units.ASCompilationUnit.handleABCBytesRequest(ASCompilationUnit.java:395)\r\n\tat org.apache.royale.compiler.internal.units.CompilationUnitBase.processABCBytesRequest(CompilationUnitBase.java:876)\r\n\tat org.apache.royale.compiler.internal.units.CompilationUnitBase.access$300(CompilationUnitBase.java:109)\r\n\tat org.apache.royale.compiler.internal.units.CompilationUnitBase$4$1.call(CompilationUnitBase.java:313)\r\n\tat org.apache.royale.compiler.internal.units.CompilationUnitBase$4$1.call(CompilationUnitBase.java:309)\r\n\tat org.apache.royale.compiler.internal.units.requests.RequestMaker$1.call(RequestMaker.java:228)\r\n\tat org.apache.royale.compiler.internal.units.requests.RequestMaker$1.call(RequestMaker.java:222)\r\n\tat java.util.concurrent.FutureTask.run(FutureTask.java:266)\r\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\r\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\r\n\tat java.lang.Thread.run(Thread.java:750)\r\n",
    "startLineNumber": 127,
    "startColumn": 9,
    "endLineNumber": 152,
    "endColumn": 10
}]

I have a smiliar error in another function in a different class. In that case the function looks like: protected function GetFrameState(gameState:int):String

And the error is:

[{
    "resource": "/c:/Sims4/PackDevY/PackDevY/Assets/InGame/UI/Flash/as3/src/widgets/GameTray/controls/ControlPanel.as",
    "owner": "_generated_diagnostic_collection_name_#2",
    "code": "1317",
    "severity": 8,
    "message": "java.lang.NegativeArraySizeException\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGeneratingReducer.reduce_lookup_switchStmt(ABCGeneratingReducer.java:5726)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGeneratingReducer.reduce_switchStmt(ABCGeneratingReducer.java:5612)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.action_452(CmcEmitter.java:6362)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.dispatchAction(CmcEmitter.java:9142)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduceAntecedent(CmcEmitter.java:39127)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduce(CmcEmitter.java:39104)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduceSubgoals(CmcEmitter.java:39155)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduceAntecedent(CmcEmitter.java:39126)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduce(CmcEmitter.java:39104)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduceSubgoals(CmcEmitter.java:39146)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduceAntecedent(CmcEmitter.java:39126)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.reduce(CmcEmitter.java:39104)\r\n\tat org.apache.royale.compiler.internal.as.codegen.CmcEmitter.burm(CmcEmitter.java:39406)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGenerator.generateInstructions(ABCGenerator.java:235)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGenerator.generateMethodBodyForFunction(ABCGenerator.java:416)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGenerator.generateMethodBodyForFunction(ABCGenerator.java:370)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGenerator.generateFunction(ABCGenerator.java:272)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ClassDirectiveProcessor.declareFunction(ClassDirectiveProcessor.java:880)\r\n\tat org.apache.royale.compiler.internal.as.codegen.DirectiveProcessor.processNode(DirectiveProcessor.java:218)\r\n\tat org.apache.royale.compiler.internal.as.codegen.DirectiveProcessor.traverse(DirectiveProcessor.java:192)\r\n\tat org.apache.royale.compiler.internal.as.codegen.GlobalDirectiveProcessor.declareClass(GlobalDirectiveProcessor.java:462)\r\n\tat org.apache.royale.compiler.internal.as.codegen.DirectiveProcessor.processNode(DirectiveProcessor.java:210)\r\n\tat org.apache.royale.compiler.internal.as.codegen.DirectiveProcessor.traverse(DirectiveProcessor.java:192)\r\n\tat org.apache.royale.compiler.internal.as.codegen.GlobalDirectiveProcessor.declarePackage(GlobalDirectiveProcessor.java:488)\r\n\tat org.apache.royale.compiler.internal.as.codegen.DirectiveProcessor.processNode(DirectiveProcessor.java:227)\r\n\tat org.apache.royale.compiler.internal.as.codegen.DirectiveProcessor.traverse(DirectiveProcessor.java:192)\r\n\tat org.apache.royale.compiler.internal.as.codegen.ABCGenerator.generate(ABCGenerator.java:126)\r\n\tat org.apache.royale.compiler.internal.units.ASCompilationUnit.handleABCBytesRequest(ASCompilationUnit.java:395)\r\n\tat org.apache.royale.compiler.internal.units.CompilationUnitBase.processABCBytesRequest(CompilationUnitBase.java:876)\r\n\tat org.apache.royale.compiler.internal.units.CompilationUnitBase.access$300(CompilationUnitBase.java:109)\r\n\tat org.apache.royale.compiler.internal.units.CompilationUnitBase$4$1.call(CompilationUnitBase.java:313)\r\n\tat org.apache.royale.compiler.internal.units.CompilationUnitBase$4$1.call(CompilationUnitBase.java:309)\r\n\tat org.apache.royale.compiler.internal.units.requests.RequestMaker$1.call(RequestMaker.java:228)\r\n\tat org.apache.royale.compiler.internal.units.requests.RequestMaker$1.call(RequestMaker.java:222)\r\n\tat java.util.concurrent.FutureTask.run(FutureTask.java:266)\r\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\r\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\r\n\tat java.lang.Thread.run(Thread.java:750)\r\n",
    "startLineNumber": 2683,
    "startColumn": 9,
    "endLineNumber": 2795,
    "endColumn": 10
}]

If I remove the arguments in the functions, then the errors are gone. I have tried setting "as3mxml.languageServer.jvmargs": "-Xmx1g" in the project settings, without any effect. Any help would be very appreciated. Thanks!

joshtynjala commented 8 months ago

In both cases, it appears to be related to a switch() statement:

at org.apache.royale.compiler.internal.as.codegen.ABCGeneratingReducer.reduce_lookup_switchStmt(ABCGeneratingReducer.java:5746)

Do you think you could share either function's body so that I can see the code for the switch() statement? That should help me track down the issue and get it fixed in the AS3 parser. Thanks!

hachigoro commented 8 months ago

You're right, both functions have a switch inside. The weird thing about GetCategoryTooltipLocKey, is that even if I leave the function empty, it still shows as an error. The only way for the error to go away is to remove al the arguments from the function and leave it like public static function GetCategoryTooltipLocKey():LocKey

The full function looks like this (I have made some small changes):

public static function GetCategoryTooltipLocKey(category:int, bTargeted:Boolean = false, bEncouraged:Boolean = true):LocKey
{
    switch (category) 
    {
        case CATEGORY1:
            return KeysGP.CATEGORY_1;
        case CATEGORY2:
            return KeysGP.CATEGORY_2;
        case CATEGORY3:
            return KeysGP.CATEGORY_3;
        case CATEGORY4:
            return KeysGP.CATEGORY_4;
        case CATEGORY5:
            return KeysGP.CATEGORY_5;
        case CATEGORY6:
            return bTargeted ? KeysGP.CATEGORY_6A: KeysGP.CATEGORY_6B;
        case CATEGORY7:
            return KeysGP.CATEGORY_7;
        case CATEGORY8:
            return KeysGP.CATEGORY_8;
        case CATEGORY9:
            return bEncouraged ? KeysGP.CATEGORY_9A: KeysGP.CATEGORY_9B;
        default:
            return null;
    }
}

The items in the cases are declared in the same class, like this: public static const CATEGORY1:uint = 0;

For GetFrameState the problem is a little different. It has a switch with 8 cases inside. If I remove 2 cases (any of them) then the problem is gone. That does not solve the problem in GetCategoryTooltipLocKey, as that one still shows an error even if I remove everything in the function.

GetFrameState is like this:

protected function GetFrameState(gameState:int):String
{
    var result:String = null;

    switch (gameState)
    {
        case GameStates.STATE1:
            result = "state_1";
            break;

        case GameStates.STATE2:
            result = "state_2";
            break;

        case GameStates.STATE3:
            result = "state_3";
            break;

        case GameStates.STATE4:
            result = "state_4";
            break;

        case GameStates.STATE5:
            result = "state_5";
            break;

        case GameStates.STATE6:
            result = "state_6";
            break;

        case GameStates.STATE7:
            result = "state_7";                   
            break;

        default:
            result = null;
    }

    return result;
}

Thanks for your help.

joshtynjala commented 8 months ago

Thanks! That should hopefully help me reproduce the issue, and then I can try to figure out what's going on in the compiler.

joshtynjala commented 8 months ago

@hachigoro Can you share with me all of the integer values of the constants used for the case statements?

For GetCategoryTooltipLocKey, I need all the CATEGORY 1-9 integer values. For instance, above you mentioned that CATEGORY1 is 0. I'd like to see the rest too. Are they all defined as type uint?

For GetFrameState, I need all the STATE 1-7 integer values on the GameStates class. What type are they all? int?

It looks like the compiler has some special optimizations that depend on comparing/adding/subtracting case integer values, and it must not have accounted for certain value ranges. I can't reproduce yet, but I think it may help if I know which values you have in your code.

Thanks!

hachigoro commented 8 months ago

Sure, here they are:

public static const CATEGORY1:uint = 0; public static const CATEGORY2:uint = 1; public static const CATEGORY3:uint = 2; public static const CATEGORY4:uint = 3; public static const CATEGORY5:uint = 4; public static const CATEGORY6:uint = 5; public static const CATEGORY7:uint = 6; public static const CATEGORY8:uint = 7; public static const CATEGORY9:uint = uint.MAX_VALUE - 1;

And as I write this, I realized that the first error is gone if I change the type of category from int to uint. However, I imagine that it should probably show a warning instead of an error.

public static const STATE1:uint = 0x3a97a3bc; public static const STATE2:uint = 0x4bebcb10; public static const STATE3:uint = 0xfe056f8b; public static const STATE4:uint = 0x1020b807; public static const STATE5:uint = 0xd9016c91; public static const STATE6:uint = 0x0e31b441; public static const STATE7:uint = 0xae03c339;

Again, for GetFrameState, the error is gone if I change the type of gameState to uint.

Hopefully this helps, thanks!

joshtynjala commented 7 months ago

Fixed in apache/royale-compiler@70193ebf34bb17fbe988543e84db8f7da13a001f

This fix will be included in a version of vscode-as3mxml after the next Apache Royale version is released.