How to handle "Invalid method Code length" in Coldfusion?

1.4k views Asked by At

I have a bunch of cfc files (running coldfusion8), which consist of a cfswitch bundling similar functions (user, search, ...).

Some of the cfc files are becoming too large, so I'm receiving a Invalid method Code length 72645 which I assume says, "your file is too big to be parsed"..

I'm usually reaching this at about 2000 lines and think this is ... not much.

Since I'm bumping this upper limit on a bunch of files, I'm considering adding another functional layer = remove all functions from the switch-statement and call cfinvoke with a separate cfc per function.

Question:
My application is not that big, so I'm wondering, is there a way to circumvent the "you-can't-have-more-than-2000-lines-in-a-cfc" upper-limit and if not, is it a viable approach to have separate CFCs/components for every main method to be called in an application?

Thanks!

EDIT: re: "planned" :-)
Currently my CFCs are structured like this:

<cfcomponent extends="controllers.main" output="false" hint="handle all user interactions">     
    <cfscript>
        VARIABLES.Instance.Validation = {   
            // all user-relate form fields including validation method to call (pass = no validation)
            id="spec_id"
          , corp="pass"
          ...
        };
    </cfscript> 

    <cffunction name="Init" access="public" returntype="any" output="false" hint="Initialize form data">
        <cfreturn true />
    </cffunction>   
    <cffunction name="Defaults" access="public" returntype="struct" output="false" hint="Assign defaults">
       <cfscript>
          // form default values assigned to instance
          var formDefaults = {
              id=""
            , comp=""
            ...
          };
       </cfscript>
       <cfreturn formDefaults />
    </cffunction>

    <cffunction name="Commit" access="remote" returntype="struct" output="false" hint="Main handler">
        <cfscript>
        // all var declarations
        var userID = "";
        var strRememberMe = "";
        var timestamp = now();
        ... 
        var defaultValues = THIS.Defaults();
        var LOCAL = {};

        structAppend(defaultValues, VARIABLES.Instance.FormData);
        LOCAL.User = defaultValues;
        LOCAL.User.timestamp = timestamp ;
        </cfscript> 

        <!--- the switch --->       
        <cfswitch expression = #LOCAL.User.submitted_form#>

            ... lot of stuff ...

        </cfswitch>

        <cfreturn LOCAL.Response />
    </cffunction>

    <!--- UTILITY FUNCTIONS --->
    <cffunction name="Validate" access="public" returntype="array" output="false" hint="validate form inputs">
        <cfscript>
        var LOCAL = {};
        var double = structNew();
        double.criteria = VARIABLES.Instance.Validation;
        double.form = VARIABLES.Instance.FormData;
        </cfscript>

        <!--- Get error name and type --->
        <cfinvoke component="form_validate" method="validate_fields" double="#double#" returnvariable="validation_errors"></cfinvoke>
        <cfset LOCAL.ErrorMessages = validation_errors />
        <cfreturn LOCAL.ErrorMessages />
    </cffunction>                                   
</cfcomponent>

Now I have been writing a lot of unstructured stuff, but splitting up in functional-cfcs and then handling them like this did not seem very "un-planned" to me.

If it is, what would be a better way to set this up, since I'm having to re-do it anyway? The switch will have about 15 cases, which is the average across all the main cfcs I'm using.

Thanks!

2

There are 2 answers

1
Alex On BEST ANSWER

I experienced this problem in CF8 some time ago as well. There is no general "2000 lines limit" but a maximum value in the JVM for the address offset in order to jump within a subroutine. The offset must not exceed 2 Bytes (WORD), otherwise you will face this exception. To avoid large address offsets within a subroutine (function), you need to minimize large blocks of conditional jumps (if/else/switch). You can do this by using multiple subroutines instead (these calls may take the full register up to 4/8 Bytes).

For example: Redesign...

function A (x, y) {
    if (...) {
        switch (...) {
            case ...:
                switch (...) {
                    ...
                }
            ...
        }
    } else {
        switch (...) {
            ...
        }
    }
}

To something like...

function A (x, y) {
    if (...) {
        call B(x, y);
    } else {
        call C(x, y);
    }
}

function B (x, y) {
    switch (...) {
        case ...:
            call B1(x, y);
        ...
    }
}

function B1 (x, y) {
    switch (...) {
        ....
    }
}

function C (x, y) {
    switch (...) {
        ....
    }
}

...you get the idea. This will usually also improve readability and maintainability.

0
Mr.Black On

Basically this error is happening because the function or method you wrote in ColdFusion is blowing a Java limit of 65535 bytes per method (around 2000 lines of CF code).

Simply shrink that function by calling smaller functions from that function.

Calling a 10,000 byte function is only costs 100 bytes.

Before (blows up):
    Function(){
      10,000 bytes of code
      15,000 bytes of code
      20,000 bytes of code
      30,000 bytes of code
    }

    After (success!):
    Function(){
      100 Byte call to 10,000 bytes of code
      100 Byte call to 15,000 bytes of code
      100 Byte call to 20,000 bytes of code
      100 Byte call to 30,000 bytes of code
    }