private static Scriptable js_sort ( final Context cx , final Scriptable scope , final Scriptable thisObj , final Object [ ] args ) { final Comparator < Object > comparator ; if ( args . length > 0 && Undefined . instance != args [ 0 ] ) { final Callable jsCompareFunction = ScriptRuntime . getValueFunctionAndThis ( args [ 0 ] , cx ) ; final Scriptable funThis = ScriptRuntime . lastStoredScriptable ( cx ) ; final Object [ ] cmpBuf = new Object [ 2 ] ; // Buffer for cmp arguments comparator = new ElementComparator ( new Comparator < Object > ( ) { @ Override public int compare ( final Object x , final Object y ) { // This comparator is invoked only for non-undefined objects cmpBuf [ 0 ] = x ; cmpBuf [ 1 ] = y ; Object ret = jsCompareFunction . call ( cx , scope , funThis , cmpBuf ) ; final double d = ScriptRuntime . toNumber ( ret ) ; if ( d < 0 ) { return - 1 ; } else if ( d > 0 ) { return + 1 ; } return 0 ; // ??? double and 0??? } } ) ; } else { comparator = DEFAULT_COMPARATOR ; } long llength = getLengthProperty ( cx , thisObj , false ) ; final int length = ( int ) llength ; if ( llength != length ) { throw Context . reportRuntimeError1 ( "msg.arraylength.too.big" , String . valueOf ( llength ) ) ; } // copy the JS array into a working array, so it can be // sorted cheaply. final Object [ ] working = new Object [ length ] ; for ( int i = 0 ; i != length ; ++ i ) { working [ i ] = getRawElem ( thisObj , i ) ; } Sorting . hybridSort ( working , comparator ) ; // copy the working array back into thisObj for ( int i = 0 ; i < length ; ++ i ) { setRawElem ( cx , thisObj , i , working [ i ] ) ; } return thisObj ; }
See ECMA 15 . 4 . 4 . 5