/* * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.max.vm.bytecode.refmaps; /** * An interpreter that encodes the details for a frame in an {@code int}. The format of the encoding is: * <p> * <pre> * 0 26 27 30 31 * +---------------------+-----------------------+--------+---------+---+ * | locals ref map | operand stack ref map | unused | sp | I | * +---------------------+-----------------------+--------+---------+---+ * * |<---- maxLocals ---->|<----- maxStack ------> * * I: the frame is initialized if I == 1; * sp: stack depth (encoded on 4 bits, max depth being 15). */ public class CompactReferenceMapInterpreter extends ReferenceMapInterpreter { private static final int INITIALIZED_FRAME_BIT = 0x80000000; private static final int SP_SHIFT = 27; private static final int SP_MASK = 0xF; public static final int MAX_SLOTS = 27; public static final int MAX_STACK = 15; private int[] frames; private int currentFrame; /** * Decodes the part of a frame that encodes the reference map for the locals and operand stack. * * @param frame a frame * @param sp the number of reference map bits to include for the operand stack (i.e the current stack depth) * @return the reference maps for the locals and operand stack encoded in {@code frame} */ private int decodeReferenceMap(int frame, int sp) { final int mask = (1 << maxLocals() + sp) - 1; return frame & mask; } /** * Decodes the stack depth from a frame. * * @param frame a frame * @return the stack depth encoded in {@code frame} */ private static int decodeSp(int frame) { return (frame >> SP_SHIFT) & SP_MASK; } /** * Encodes a stack depth into a frame. * * @param frame a frame * @param sp a stack depth * @return the updated value of {@code frame} that now encodes {@code sp} */ private static int encodeSp(int frame, int sp) { assert sp <= MAX_STACK; return frame | (sp << SP_SHIFT); } @Override protected boolean mergeInto(int targetBlockIndex, int sp) { final boolean targetIsExceptionHandler = sp == -1; final int spForMerge = targetIsExceptionHandler ? 0 : sp; if ((frames[targetBlockIndex] & INITIALIZED_FRAME_BIT) == 0) { final int currentMap = decodeReferenceMap(currentFrame, spForMerge); final int targetFrame; if (targetIsExceptionHandler) { // Leave the exception object on the stack targetFrame = encodeSp(updateStack(currentMap, 0, true), 1); } else { assert sp <= MAX_STACK; targetFrame = encodeSp(currentMap, sp); } frames[targetBlockIndex] = targetFrame | INITIALIZED_FRAME_BIT; return true; } final int targetMap = decodeReferenceMap(frames[targetBlockIndex], spForMerge); final int currentMap = decodeReferenceMap(currentFrame, spForMerge); final int mergedMap = targetMap & currentMap; if (mergedMap != targetMap) { final int mergedFrame; if (targetIsExceptionHandler) { assert decodeSp(frames[targetBlockIndex]) == 1; // Leave the exception object on the stack mergedFrame = encodeSp(updateStack(mergedMap, 0, true), 1); assert decodeSp(mergedFrame) == 1; } else { mergedFrame = encodeSp(mergedMap, sp); } frames[targetBlockIndex] = mergedFrame | INITIALIZED_FRAME_BIT; return true; } return false; } @Override public boolean isFrameInitialized(int blockIndex) { return (frames[blockIndex] & INITIALIZED_FRAME_BIT) != 0; } @Override protected void resetInterpreter(ReferenceMapInterpreterContext context) { super.resetInterpreter(context); currentFrame = 0; if (context.blockFrames() == null) { assert maxStack() <= MAX_STACK && (maxStack() + maxLocals()) < MAX_SLOTS; frames = new int[context.numberOfBlocks()]; } else { frames = (int[]) context.blockFrames(); } } @Override protected Object frames() { return frames; } @Override public boolean performsAllocation() { return false; } @Override int resetAtBlock(int blockIndex) { currentFrame = frames[blockIndex]; return decodeSp(currentFrame); } @Override boolean isLocalRef(int index) { return testBit(currentFrame, index); } @Override boolean isStackRef(int index) { return testBit(currentFrame, index + maxLocals()); } @Override void updateLocal(int index, boolean isRef) { currentFrame = updateLocal(currentFrame, index, isRef); } private static int updateLocal(int frame, int index, boolean isRef) { return updateBit(frame, index, isRef); } @Override void updateStack(int index, boolean isRef) { currentFrame = updateStack(currentFrame, maxLocals(), index, isRef); } private int updateStack(int frame, int index, boolean isRef) { return updateStack(frame, maxLocals(), index, isRef); } private static int updateStack(int frame, int maxLocals, int index, boolean isRef) { return updateBit(frame, index + maxLocals, isRef); } private static boolean testBit(int map, int index) { return (map & (1 << index)) != 0; } private static int updateBit(int map, int index, boolean set) { if (set) { return map | (1 << index); } return map & ~(1 << index); } }