private int getHighestIndex ( int highestIndex ) { for ( Node ref : currentArgumentsAccesses ) { Node getElem = ref . getParent ( ) ; // Bail on anything but argument[c] access where c is a constant. // TODO(user): We might not need to bail out all the time, there might // be more cases that we can cover. if ( ! getElem . isGetElem ( ) || ref != getElem . getFirstChild ( ) ) { return - 1 ; } Node index = ref . getNext ( ) ; // We have something like arguments[x] where x is not a constant. That // means at least one of the access is not known. if ( ! index . isNumber ( ) || index . getDouble ( ) < 0 ) { // TODO(user): Its possible not to give up just yet. The type // inference did a 'semi value propagation'. If we know that string // is never a subclass of the type of the index. We'd know that // it is never 'callee'. return - 1 ; // Give up. } //We want to bail out if someone tries to access arguments[0.5] for example if ( index . getDouble ( ) != Math . floor ( index . getDouble ( ) ) ) { return - 1 ; } Node getElemParent = getElem . getParent ( ) ; // When we have argument[0](), replacing it with a() is semantically // different if argument[0] is a function call that refers to 'this' if ( getElemParent . isCall ( ) && getElemParent . getFirstChild ( ) == getElem ) { // TODO(user): We can consider using .call() if aliasing that // argument allows shorter alias for other arguments. return - 1 ; } // Replace the highest index if we see an access that has a higher index // than all the one we saw before. int value = ( int ) index . getDouble ( ) ; if ( value > highestIndex ) { highestIndex = value ; } } return highestIndex ; }
Iterate through all the references to arguments array in the function to determine the real highestIndex . Returns - 1 when we should not be replacing any arguments for this scope - we should exit tryReplaceArguments