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.compilers.opt.bc2ir.ia32;
014
015import static org.jikesrvm.compilers.opt.ir.IRTools.offsetOperand;
016import static org.jikesrvm.compilers.opt.ir.Operators.GETFIELD;
017import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD;
018import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE;
019import static org.jikesrvm.compilers.opt.ir.Operators.REF_ADD;
020import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD;
021import static org.jikesrvm.compilers.opt.ir.Operators.REF_MOVE;
022import static org.jikesrvm.compilers.opt.ir.Operators.REF_STORE;
023import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.PAUSE;
024import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.PREFETCH;
025import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_FRAME_POINTER_OFFSET;
026import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_METHOD_ID_OFFSET;
027import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_RETURN_ADDRESS_OFFSET;
028
029import org.jikesrvm.classloader.Atom;
030import org.jikesrvm.classloader.MethodReference;
031import org.jikesrvm.classloader.RVMField;
032import org.jikesrvm.classloader.TypeReference;
033import org.jikesrvm.compilers.opt.MagicNotImplementedException;
034import org.jikesrvm.compilers.opt.bc2ir.BC2IR;
035import org.jikesrvm.compilers.opt.bc2ir.GenerationContext;
036import org.jikesrvm.compilers.opt.ir.CacheOp;
037import org.jikesrvm.compilers.opt.ir.Empty;
038import org.jikesrvm.compilers.opt.ir.GetField;
039import org.jikesrvm.compilers.opt.ir.Instruction;
040import org.jikesrvm.compilers.opt.ir.Load;
041import org.jikesrvm.compilers.opt.ir.Move;
042import org.jikesrvm.compilers.opt.ir.Store;
043import org.jikesrvm.compilers.opt.ir.ia32.PhysicalRegisterSet;
044import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand;
045import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
046import org.jikesrvm.compilers.opt.ir.operand.Operand;
047import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
048import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand;
049import org.jikesrvm.runtime.ArchEntrypoints;
050import org.jikesrvm.runtime.Magic;
051import org.jikesrvm.runtime.MagicNames;
052
053/**
054 * This class implements the machine-specific magics for the opt compiler.
055 *
056 * @see org.jikesrvm.compilers.opt.bc2ir.GenerateMagic for the machine-independent magics
057 */
058public abstract class GenerateMachineSpecificMagic {
059
060  /**
061   * "Semantic inlining" of methods of the Magic class.
062   * Based on the methodName, generate a sequence of opt instructions
063   * that implement the magic, updating the stack as necessary
064   *
065   * @param bc2ir the bc2ir object generating the ir containing this magic
066   * @param gc == bc2ir.gc
067   * @param meth the RVMMethod that is the magic method
068   * @return {@code true} if and only if magic was generated
069   */
070  public static boolean generateMagic(BC2IR bc2ir, GenerationContext gc, MethodReference meth)
071      throws MagicNotImplementedException {
072
073    Atom methodName = meth.getName();
074    PhysicalRegisterSet phys = gc.getTemps().getPhysicalRegisterSet().asIA32();
075
076    if (methodName == MagicNames.getESIAsThread) {
077      RegisterOperand rop = gc.getTemps().makeTROp();
078      bc2ir.markGuardlessNonNull(rop);
079      bc2ir.push(rop);
080    } else if (methodName == MagicNames.setESIAsThread) {
081      Operand val = bc2ir.popRef();
082      if (val instanceof RegisterOperand) {
083        bc2ir.appendInstruction(Move.create(REF_MOVE, gc.getTemps().makeTROp(), val));
084      } else {
085        String msg = " Unexpected operand Magic.setESIAsThread";
086        throw MagicNotImplementedException.UNEXPECTED(msg);
087      }
088    } else if (methodName == MagicNames.getFramePointer) {
089      gc.forceFrameAllocation();
090      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Address);
091      RVMField f = ArchEntrypoints.framePointerField;
092      RegisterOperand pr = new RegisterOperand(phys.getESI(), TypeReference.Address);
093      bc2ir.appendInstruction(GetField.create(GETFIELD,
094                                              val,
095                                              pr.copy(),
096                                              new AddressConstantOperand(f.getOffset()),
097                                              new LocationOperand(f),
098                                              new TrueGuardOperand()));
099      bc2ir.push(val.copyD2U());
100    } else if (methodName == MagicNames.getJTOC || methodName == MagicNames.getTocPointer) {
101      TypeReference t = (methodName == MagicNames.getJTOC ? TypeReference.IntArray : TypeReference.Address);
102      RegisterOperand val = gc.getTemps().makeTemp(t);
103      AddressConstantOperand addr = new AddressConstantOperand(Magic.getTocPointer());
104      bc2ir.appendInstruction(Move.create(REF_MOVE, val, addr));
105      bc2ir.push(val.copyD2U());
106    } else if (methodName == MagicNames.isync) {
107      // nothing required on Intel
108    } else if (methodName == MagicNames.sync) {
109      // nothing required on Intel
110    } else if (methodName == MagicNames.prefetch) {
111      bc2ir.appendInstruction(CacheOp.create(PREFETCH, bc2ir.popAddress()));
112    } else if (methodName == MagicNames.pause) {
113      bc2ir.appendInstruction(Empty.create(PAUSE));
114    } else if (methodName == MagicNames.getCallerFramePointer) {
115      Operand fp = bc2ir.popAddress();
116      RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Address);
117      bc2ir.appendInstruction(Load.create(REF_LOAD,
118                                          val,
119                                          fp,
120                                          offsetOperand(STACKFRAME_FRAME_POINTER_OFFSET),
121                                          null));
122      bc2ir.push(val.copyD2U());
123    } else if (methodName == MagicNames.setCallerFramePointer) {
124      Operand val = bc2ir.popAddress();
125      Operand fp = bc2ir.popAddress();
126      bc2ir.appendInstruction(Store.create(REF_STORE,
127                                           val,
128                                           fp,
129                                           offsetOperand(STACKFRAME_FRAME_POINTER_OFFSET),
130                                           null));
131    } else if (methodName == MagicNames.getCompiledMethodID) {
132      Operand fp = bc2ir.popAddress();
133      RegisterOperand val = gc.getTemps().makeTempInt();
134      bc2ir.appendInstruction(Load.create(INT_LOAD,
135                                          val,
136                                          fp,
137                                          offsetOperand(STACKFRAME_METHOD_ID_OFFSET),
138                                          null));
139      bc2ir.push(val.copyD2U());
140    } else if (methodName == MagicNames.setCompiledMethodID) {
141      Operand val = bc2ir.popInt();
142      Operand fp = bc2ir.popAddress();
143      bc2ir.appendInstruction(Store.create(INT_STORE,
144                                           val,
145                                           fp,
146                                           offsetOperand(STACKFRAME_METHOD_ID_OFFSET),
147                                           null));
148    } else if (methodName == MagicNames.getReturnAddressLocation) {
149      Operand fp = bc2ir.popAddress();
150      Instruction s = bc2ir._binaryHelper(REF_ADD, fp, offsetOperand(STACKFRAME_RETURN_ADDRESS_OFFSET), TypeReference.Address);
151      bc2ir.appendInstruction(s);
152    } else {
153      // Distinguish between magics that we know we don't implement
154      // (and never plan to implement) and those (usually new ones)
155      // that we want to be warned that we don't implement.
156      String msg = " Magic method not implemented: " + meth;
157      if (methodName == MagicNames.returnToNewStack) {
158        throw MagicNotImplementedException.EXPECTED(msg);
159      } else {
160        return false;
161        // throw MagicNotImplementedException.UNEXPECTED(msg);
162      }
163    }
164    return true;
165  }
166}