001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.ia32;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.classloader.RVMArray;
017    import org.jikesrvm.classloader.TypeReference;
018    import org.jikesrvm.runtime.Magic;
019    import org.jikesrvm.runtime.RuntimeEntrypoints;
020    import org.vmmagic.unboxed.Address;
021    
022    /**
023     * Helper routine to pull the parameters to multianewarray off the
024     * Java expression stack maintained by the baseline compiler and
025     * pass them to RuntimeEntrypoints.buildMultiDimensionalArray.<p>
026     *
027     * TODO: There is only 1 line of platform dependent code here; refactor?
028     */
029    public abstract class MultianewarrayHelper {
030    
031      /**
032       * Allocate something like {@code new Foo[cnt0][cnt1]...[cntN-1]},
033       *                      or {@code new int[cnt0][cnt1]...[cntN-1]}.
034       * @param methodId method id of caller
035       * @param numDimensions number of array dimensions
036       * @param typeId type id of type reference for array
037       * @param argOffset position of word *above* `cnt0' argument within
038       * caller's frame This is used to access the number of elements to
039       * be allocated for each dimension.
040       *
041       * See also: bytecode 0xc5 ("multianewarray") in BaselineCompilerImpl
042       */
043      static Object newArrayArray(int methodId, int numDimensions, int typeId, int argOffset)
044          throws NoClassDefFoundError, NegativeArraySizeException, OutOfMemoryError {
045        if (numDimensions == 2) {
046          int dim0, dim1;
047          // fetch number of elements to be allocated for each array dimension
048          VM.disableGC();
049          Address argp = Magic.getFramePointer().plus(argOffset);
050          argp = argp.minus(4);
051          dim0 = argp.loadInt();
052          argp = argp.minus(4);
053          dim1 = argp.loadInt();
054          VM.enableGC();
055          // validate arguments
056          if ((dim0 < 0) || (dim1 < 0)) throw new NegativeArraySizeException();
057          // create array
058          TypeReference tRef = TypeReference.getTypeRef(typeId);
059          RVMArray array = tRef.resolve().asArray();
060          return RuntimeEntrypoints.buildTwoDimensionalArray(methodId, dim0, dim1, array);
061        } else {
062          // fetch number of elements to be allocated for each array dimension
063          int[] numElements = new int[numDimensions];
064          VM.disableGC();
065          Address argp = Magic.getFramePointer().plus(argOffset);
066          for (int i = 0; i < numDimensions; ++i) {
067            if (VM.BuildFor32Addr) {
068              argp = argp.minus(4);
069            } else {
070              argp = argp.minus(8);
071            }
072            numElements[i] = argp.loadInt();
073          }
074          VM.enableGC();
075          // validate arguments
076          for (int elements : numElements) {
077            if (elements < 0) throw new NegativeArraySizeException();
078          }
079          // create array
080          TypeReference tRef = TypeReference.getTypeRef(typeId);
081          RVMArray array = tRef.resolve().asArray();
082          return RuntimeEntrypoints.buildMultiDimensionalArray(methodId, numElements, array);
083        }
084      }
085    }