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 */
013package org.jikesrvm.ia32;
014
015import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_WORD;
016
017import org.jikesrvm.VM;
018import org.jikesrvm.classloader.RVMArray;
019import org.jikesrvm.classloader.TypeReference;
020import org.jikesrvm.runtime.Magic;
021import org.jikesrvm.runtime.RuntimeEntrypoints;
022import org.vmmagic.pragma.Entrypoint;
023import org.vmmagic.unboxed.Address;
024
025/**
026 * Helper routine to pull the parameters to multianewarray off the
027 * Java expression stack maintained by the baseline compiler and
028 * pass them to RuntimeEntrypoints.buildMultiDimensionalArray.<p>
029 *
030 * TODO: There is only 1 line of platform dependent code here; refactor?
031 */
032public abstract class MultianewarrayHelper {
033
034  /**
035   * Allocate something like {@code new Foo[cnt0][cnt1]...[cntN-1]},
036   *                      or {@code new int[cnt0][cnt1]...[cntN-1]}.
037   * @param methodId method id of caller
038   * @param numDimensions number of array dimensions
039   * @param typeId type id of type reference for array
040   * @param argOffset position of word *above* `cnt0' argument within
041   * caller's frame This is used to access the number of elements to
042   * be allocated for each dimension.
043   *
044   * See also: bytecode 0xc5 ("multianewarray") in BaselineCompilerImpl
045   *
046   * @return newly allocated multidimensional array
047   */
048  @Entrypoint
049  static Object newArrayArray(int methodId, int numDimensions, int typeId, int argOffset)
050      throws NoClassDefFoundError, NegativeArraySizeException, OutOfMemoryError {
051    if (numDimensions == 2) {
052      int dim0, dim1;
053      // fetch number of elements to be allocated for each array dimension
054      VM.disableGC();
055      Address argp = Magic.getFramePointer().plus(argOffset);
056      argp = argp.minus(BYTES_IN_WORD);
057      dim0 = argp.loadInt();
058      argp = argp.minus(BYTES_IN_WORD);
059      dim1 = argp.loadInt();
060      VM.enableGC();
061      // validate arguments
062      if ((dim0 < 0) || (dim1 < 0)) throw new NegativeArraySizeException();
063      // create array
064      TypeReference tRef = TypeReference.getTypeRef(typeId);
065      RVMArray array = tRef.resolve().asArray();
066      return RuntimeEntrypoints.buildTwoDimensionalArray(methodId, dim0, dim1, array);
067    } else {
068      // fetch number of elements to be allocated for each array dimension
069      int[] numElements = new int[numDimensions];
070      VM.disableGC();
071      Address argp = Magic.getFramePointer().plus(argOffset);
072      for (int i = 0; i < numDimensions; ++i) {
073        argp = argp.minus(BYTES_IN_WORD);
074        numElements[i] = argp.loadInt();
075      }
076      VM.enableGC();
077      // validate arguments
078      for (int elements : numElements) {
079        if (elements < 0) throw new NegativeArraySizeException();
080      }
081      // create array
082      TypeReference tRef = TypeReference.getTypeRef(typeId);
083      RVMArray array = tRef.resolve().asArray();
084      return RuntimeEntrypoints.buildMultiDimensionalArray(methodId, numElements, array);
085    }
086  }
087}