text: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
   * vim: set ts=4 sw=4 et tw=99:
   *
   * ***** BEGIN LICENSE BLOCK *****
   * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   *
   * The contents of this file are subject to the Mozilla Public License Version
   * 1.1 (the "License"); you may not use this file except in compliance with
   * the License. You may obtain a copy of the License at
   * http://www.mozilla.org/MPL/
   *
   * Software distributed under the License is distributed on an "AS IS" basis,
   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   * for the specific language governing rights and limitations under the
   * License.
   *
   * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
   * May 28, 2008.
   *
   * The Initial Developer of the Original Code is
   *   Brendan Eich <brendan@mozilla.org>
   *
   * Contributor(s):
   *   David Mandelin <dmandelin@mozilla.com>
   *   David Anderson <danderson@mozilla.com>
   *   Chris Leary <cdleary@mozilla.com>
   *   Jacob Bramley <Jacob.Bramely@arm.com>
   *
   * Alternatively, the contents of this file may be used under the terms of
   * either of the GNU General Public License Version 2 or later (the "GPL"),
   * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
   * in which case the provisions of the GPL or the LGPL are applicable instead
   * of those above. If you wish to allow use of your version of this file only
   * under the terms of either the GPL or the LGPL, and not to allow others to
   * use your version of this file under the terms of the MPL, indicate your
   * decision by deleting the provisions above and replace them with the notice
   * and other provisions required by the GPL or the LGPL. If you do not delete
   * the provisions above, a recipient may use your version of this file under
   * the terms of any one of the MPL, the GPL or the LGPL.
   *
   * ***** END LICENSE BLOCK ***** */
  
  #if !defined jsjaeger_ic_labels_h__ && defined JS_METHODJIT
  #define jsjaeger_ic_labels_h__
  
  #include "methodjit/BaseCompiler.h"
  
  class ICOffsetInitializer {
    public:
      ICOffsetInitializer();
  };
  
  namespace js {
  namespace mjit {
  namespace ic {
  
  /*
   * On x64 and ARM, we record offsets into the labels data structures at runtime
   * instead of using hardcoded offsets into the instruction stream, as we do on
   * x86.
   *
   * This is done on x64 because of variable-width instruction encoding when
   * using the extended register set. It is done on ARM for ease of
   * implementation.
   */
  
  #if defined JS_CPU_X64 || defined JS_CPU_ARM
  # define JS_HAS_IC_LABELS
  #endif
  
  /* GetPropCompiler */
  struct GetPropLabels : MacroAssemblerTypedefs {
      friend class ::ICOffsetInitializer;
  
      void setValueLoad(MacroAssembler &masm, Label fastPathRejoin, Label fastValueLoad) {
          int offset = masm.differenceBetween(fastPathRejoin, fastValueLoad);
  #ifdef JS_HAS_IC_LABELS
          inlineValueLoadOffset = offset;
  #endif
          /* 
           * Note: the offset between the type and data loads for x86 is asserted
           * in NunboxAssembler::loadValueWithAddressOffsetPatch.
           */
          JS_ASSERT(offset == inlineValueLoadOffset);
          (void) offset;
      }
  
      CodeLocationLabel getValueLoad(CodeLocationLabel fastPathRejoin) {
          return fastPathRejoin.labelAtOffset(inlineValueLoadOffset);
      }
  
      void setDslotsLoad(MacroAssembler &masm, Label fastPathRejoin, Label dslotsLoad) {
          int offset = masm.differenceBetween(fastPathRejoin, dslotsLoad);
          setDslotsLoadOffset(offset);
      }
  
      CodeLocationInstruction getDslotsLoad(CodeLocationLabel fastPathRejoin) {
          return fastPathRejoin.instructionAtOffset(getDslotsLoadOffset());
      }
  
      void setInlineShapeData(MacroAssembler &masm, Label shapeGuard, DataLabel32 inlineShape) {
          int offset = masm.differenceBetween(shapeGuard, inlineShape);
          setInlineShapeOffset(offset);
      }
  
      CodeLocationDataLabel32 getInlineShapeData(CodeLocationLabel fastShapeGuard) {
          return fastShapeGuard.dataLabel32AtOffset(getInlineShapeOffset());
      }
  
      /*
       * Note: on x64, the base is the inlineShapeLabel DataLabel32, whereas on other
       * platforms the base is the shapeGuard.
       */
      template <typename T>
      void setInlineShapeJump(MacroAssembler &masm, T base, Label afterJump) {
          setInlineShapeJumpOffset(masm.differenceBetween(base, afterJump));
      }
  
      CodeLocationJump getInlineShapeJump(CodeLocationLabel fastShapeGuard) {
          return fastShapeGuard.jumpAtOffset(getInlineShapeJumpOffset());
      }
  
      void setInlineTypeJump(MacroAssembler &masm, Label fastPathStart, Label afterTypeJump) {
          int offset = masm.differenceBetween(fastPathStart, afterTypeJump);
          setInlineTypeJumpOffset(offset);
      }
  
      CodeLocationJump getInlineTypeJump(CodeLocationLabel fastPathStart) {
          return fastPathStart.jumpAtOffset(getInlineTypeJumpOffset());
      }
  
      void setStubShapeJump(MacroAssembler &masm, Label stubStart, Label shapeJump) {
          int offset = masm.differenceBetween(stubStart, shapeJump);
          setStubShapeJumpOffset(offset);
      }
  
      /* Offset-based interface */
  
      void setDslotsLoadOffset(int offset) {
  #ifdef JS_HAS_IC_LABELS
          dslotsLoadOffset = offset;
  #endif
          JS_ASSERT(offset == dslotsLoadOffset);
      }
  
      void setInlineShapeOffset(int offset) {
  #ifdef JS_HAS_IC_LABELS
          inlineShapeOffset = offset;
  #endif
          JS_ASSERT(offset == inlineShapeOffset);
      }
      
      void setStubShapeJumpOffset(int offset) {
  #ifdef JS_HAS_IC_LABELS
          stubShapeJumpOffset = offset;
  #endif
          JS_ASSERT(offset == stubShapeJumpOffset);
      }
  
      int getInlineShapeJumpOffset() {
  #if defined JS_CPU_X64
          return getInlineShapeOffset() + INLINE_SHAPE_JUMP;
  #else
          return POST_INST_OFFSET(INLINE_SHAPE_JUMP);
  #endif
      }
  
      void setInlineShapeJumpOffset(int offset) {
          JS_ASSERT(INLINE_SHAPE_JUMP == offset);
      }
  
      int getInlineTypeJumpOffset() {
  #if defined JS_CPU_X86 || defined JS_CPU_X64
          return INLINE_TYPE_JUMP;
  #elif defined JS_CPU_ARM
          return POST_INST_OFFSET(inlineTypeJumpOffset);
  #endif
      }
  
      void setInlineTypeJumpOffset(int offset) {
  #if defined JS_CPU_X86 || defined JS_CPU_X64
          JS_ASSERT(INLINE_TYPE_JUMP == offset);
  #elif defined JS_CPU_ARM
          inlineTypeJumpOffset = offset;
          JS_ASSERT(offset == inlineTypeJumpOffset);
  #endif
       }
  
      int getInlineShapeOffset() {
          return inlineShapeOffset;
      }
      int getDslotsLoadOffset() {
          return dslotsLoadOffset;
      }
      int getStubShapeJumpOffset() {
          return POST_INST_OFFSET(stubShapeJumpOffset);
      }
  
    private:
      /* Offset from storeBack to beginning of 'mov dslots, addr' */
      int32 dslotsLoadOffset : 8;
  
      /* Offset from shapeGuard to end of shape comparison. */
      int32 inlineShapeOffset : 8;
  
      /* Offset from storeBack to end of value load. */
      int32 inlineValueLoadOffset : 8;
  
      /* 
       * Offset from lastStubStart to end of shape jump.
       * TODO: We can redefine the location of lastStubStart to be
       * after the jump -- at which point this is always 0.
       */
      int32 stubShapeJumpOffset : 8;
  
  #if defined JS_CPU_X86 
      static const int32 INLINE_SHAPE_JUMP = 12;
      static const int32 INLINE_TYPE_JUMP = 12;
  #elif defined JS_CPU_X64
      static const int32 INLINE_SHAPE_JUMP = 6;
      static const int32 INLINE_TYPE_JUMP = 19;
  #elif defined JS_CPU_ARM
      /* Offset from the shape guard start to the shape guard jump. */
      static const int32 INLINE_SHAPE_JUMP = 12;
  
      /* Offset from the fast path to the type guard jump. */
      int32 inlineTypeJumpOffset : 8;
  #endif
  };
  
  /* SetPropCompiler */
  struct SetPropLabels : MacroAssemblerTypedefs {
      friend class ::ICOffsetInitializer;
  
      void setInlineValueStore(MacroAssembler &masm, Label fastPathRejoin, DataLabel32 inlineValueStore,
                               const ValueRemat &vr) {
          int offset = masm.differenceBetween(fastPathRejoin, inlineValueStore);
          setInlineValueStoreOffset(offset, vr.isConstant(), vr.isTypeKnown());
      }
  
      CodeLocationLabel getInlineValueStore(CodeLocationLabel fastPathRejoin, const ValueRemat &vr) {
          return fastPathRejoin.labelAtOffset(getInlineValueStoreOffset(vr.isConstant(),
                                                                        vr.isTypeKnown()));
      }
  
      void setInlineShapeData(MacroAssembler &masm, Label shapeGuard, DataLabel32 inlineShapeData) {
          int offset = masm.differenceBetween(shapeGuard, inlineShapeData);
          setInlineShapeDataOffset(offset);
      }
  
      CodeLocationDataLabel32 getInlineShapeData(CodeLocationLabel fastPathStart, int shapeGuardOffset) {
          return fastPathStart.dataLabel32AtOffset(shapeGuardOffset + getInlineShapeDataOffset());
      }
  
      void setDslotsLoad(MacroAssembler &masm, Label fastPathRejoin, Label beforeLoad,
                         const ValueRemat &rhs) {
          int offset = masm.differenceBetween(fastPathRejoin, beforeLoad);
          setDslotsLoadOffset(offset, rhs.isConstant(), rhs.isTypeKnown());
      }
  
      CodeLocationInstruction getDslotsLoad(CodeLocationLabel fastPathRejoin, const ValueRemat &vr) {
          return fastPathRejoin.instructionAtOffset(getDslotsLoadOffset(vr));
      }
  
      void setInlineShapeJump(MacroAssembler &masm, Label shapeGuard, Label afterJump) {
          setInlineShapeJumpOffset(masm.differenceBetween(shapeGuard, afterJump));
      }
  
      CodeLocationJump getInlineShapeJump(CodeLocationLabel shapeGuard) {
          return shapeGuard.jumpAtOffset(getInlineShapeJumpOffset());
      }
  
      void setStubShapeJump(MacroAssembler &masm, Label stubStart, Label afterShapeJump) {
          int offset = masm.differenceBetween(stubStart, afterShapeJump);
          setStubShapeJumpOffset(offset);
      }
  
      CodeLocationJump getStubShapeJump(CodeLocationLabel stubStart) {
          return stubStart.jumpAtOffset(getStubShapeJumpOffset());
      }
  
    private:
  
      /* Offset-based interface. */
  
      void setDslotsLoadOffset(int offset, bool isConstant, bool isTypeKnown) {
  #if defined JS_HAS_IC_LABELS
          dslotsLoadOffset = offset;
          JS_ASSERT(offset == dslotsLoadOffset);
  #elif defined JS_CPU_X86
          JS_ASSERT_IF(isConstant, offset == INLINE_DSLOTS_BEFORE_CONSTANT);
          JS_ASSERT_IF(isTypeKnown && !isConstant, offset == INLINE_DSLOTS_BEFORE_KTYPE);
          JS_ASSERT_IF(!isTypeKnown, offset == INLINE_DSLOTS_BEFORE_DYNAMIC);
  #else
  # error
  #endif
      }
  
      int getDslotsLoadOffset(const ValueRemat &vr) {
  #if defined JS_CPU_X86
          if (vr.isConstant())
              return INLINE_DSLOTS_BEFORE_CONSTANT;
          if (vr.isTypeKnown())
              return INLINE_DSLOTS_BEFORE_KTYPE;
          return INLINE_DSLOTS_BEFORE_DYNAMIC;
  #else
          (void) vr;
          return dslotsLoadOffset;
  #endif
      }
  
      void setInlineShapeDataOffset(int offset) {
  #ifdef JS_HAS_IC_LABELS
          inlineShapeDataOffset = offset;
  #endif
          JS_ASSERT(offset == inlineShapeDataOffset);
      }
  
      void setStubShapeJumpOffset(int offset) {
  #ifdef JS_HAS_IC_LABELS
          stubShapeJumpOffset = offset;
  #endif
          JS_ASSERT(offset == stubShapeJumpOffset);
      }
  
      void setInlineValueStoreOffset(int offset, bool isConstant, bool isTypeKnown) {
  #ifdef JS_HAS_IC_LABELS
          inlineValueStoreOffset = offset;
          JS_ASSERT(offset == inlineValueStoreOffset);
  #elif defined JS_CPU_X86
          JS_ASSERT_IF(isConstant, offset == INLINE_VALUE_STORE_CONSTANT);
          JS_ASSERT_IF(isTypeKnown && !isConstant, offset == INLINE_VALUE_STORE_KTYPE);
          JS_ASSERT_IF(!isTypeKnown && !isConstant, offset == INLINE_VALUE_STORE_DYNAMIC);
  #endif
      }
  
      void setInlineShapeJumpOffset(int offset) {
  #ifdef JS_HAS_IC_LABELS
          inlineShapeJumpOffset = offset;
  #endif
          JS_ASSERT(offset == inlineShapeJumpOffset);
      }
  
      int getInlineShapeJumpOffset() {
          return POST_INST_OFFSET(inlineShapeJumpOffset);
      }
  
      int getInlineShapeDataOffset() {
          return inlineShapeDataOffset;
      }
  
      int getStubShapeJumpOffset() {
          return POST_INST_OFFSET(stubShapeJumpOffset);
      }
  
      int getInlineValueStoreOffset(bool isConstant, bool isTypeKnown) {
  #ifdef JS_HAS_IC_LABELS
          return inlineValueStoreOffset;
  #elif defined JS_CPU_X86
          if (isConstant)
              return INLINE_VALUE_STORE_CONSTANT;
          else if (isTypeKnown)
              return INLINE_VALUE_STORE_KTYPE;
          else
              return INLINE_VALUE_STORE_DYNAMIC;
  #endif
      }
  
      /* Offset from storeBack to beginning of 'mov dslots, addr'. */
  #if defined JS_CPU_X86
      static const int INLINE_DSLOTS_BEFORE_CONSTANT = -23;
      static const int INLINE_DSLOTS_BEFORE_KTYPE = -19;
      static const int INLINE_DSLOTS_BEFORE_DYNAMIC = -15;
  #else
      int32 dslotsLoadOffset : 8;
  #endif
  
      /* Offset from shapeGuard to end of shape comparison. */
      int32 inlineShapeDataOffset : 8;
  
      /* 
       * Offset from lastStubStart to end of shape jump.
       * TODO: We can redefine the location of lastStubStart to be
       * after the jump -- at which point this is always 0.
       */
      int32 stubShapeJumpOffset : 8;
  
  #if defined JS_CPU_X86
      static const int INLINE_VALUE_STORE_CONSTANT = -20;
      static const int INLINE_VALUE_STORE_KTYPE = -16;
      static const int INLINE_VALUE_STORE_DYNAMIC = -12;
  #else
      int32 inlineValueStoreOffset : 8;
  #endif
  
      /* Offset from shapeGuard to the end of the shape jump. */
      int32 inlineShapeJumpOffset : 8;
  };
  
  /* BindNameCompiler */
  struct BindNameLabels : MacroAssemblerTypedefs {
      friend class ::ICOffsetInitializer;
  
      void setInlineJumpOffset(int offset) {
  #ifdef JS_HAS_IC_LABELS
          inlineJumpOffset = offset;
  #endif
          JS_ASSERT(offset == inlineJumpOffset);
      }
  
      void setInlineJump(MacroAssembler &masm, Label shapeGuard, Jump inlineJump) {
          int offset = masm.differenceBetween(shapeGuard, inlineJump);
          setInlineJumpOffset(offset);
      }
  
      CodeLocationJump getInlineJump(CodeLocationLabel fastPathStart) {
          return fastPathStart.jumpAtOffset(getInlineJumpOffset());
      }
  
      int getInlineJumpOffset() {
          return inlineJumpOffset;
      }
  
      void setStubJumpOffset(int offset) {
  #ifdef JS_HAS_IC_LABELS
          stubJumpOffset = offset;
  #endif
          JS_ASSERT(offset == stubJumpOffset);
      }
  
      void setStubJump(MacroAssembler &masm, Label stubStart, Jump stubJump) {
          int offset = masm.differenceBetween(stubStart, stubJump);
          setStubJumpOffset(offset);
      }
  
      CodeLocationJump getStubJump(CodeLocationLabel lastStubStart) {
          return lastStubStart.jumpAtOffset(getStubJumpOffset());
      }
  
      int getStubJumpOffset() {
          return stubJumpOffset;
      }
  
    private:
      /* Offset from shapeGuard to end of shape jump. */
      int32 inlineJumpOffset : 8;
  
      /* Offset from lastStubStart to end of the shape jump. */
      int32 stubJumpOffset : 8;
  };
  
  /* ScopeNameCompiler */
  struct ScopeNameLabels : MacroAssemblerTypedefs {
      friend class ::ICOffsetInitializer;
  
      void setInlineJumpOffset(int offset) {
  #ifdef JS_HAS_IC_LABELS
          inlineJumpOffset = offset;
  #endif
          JS_ASSERT(offset == inlineJumpOffset);
      }
  
      void setInlineJump(MacroAssembler &masm, Label fastPathStart, Jump inlineJump) {
          int offset = masm.differenceBetween(fastPathStart, inlineJump);
          setInlineJumpOffset(offset);
      }
  
      CodeLocationJump getInlineJump(CodeLocationLabel fastPathStart) {
          return fastPathStart.jumpAtOffset(getInlineJumpOffset());
      }
  
      int getInlineJumpOffset() {
          return inlineJumpOffset;
      }
  
      void setStubJumpOffset(int offset) {
  #ifdef JS_HAS_IC_LABELS
          stubJumpOffset = offset;
  #endif
          JS_ASSERT(offset == stubJumpOffset);
      }
  
      void setStubJump(MacroAssembler &masm, Label stubStart, Jump stubJump) {
          int offset = masm.differenceBetween(stubStart, stubJump);
          setStubJumpOffset(offset);
      }
  
      CodeLocationJump getStubJump(CodeLocationLabel lastStubStart) {
          return lastStubStart.jumpAtOffset(getStubJumpOffset());
      }
  
      int getStubJumpOffset() {
          return stubJumpOffset;
      }
  
    private:
      /* Offset from fastPathStart to end of shape jump. */
      int32 inlineJumpOffset : 8;
  
      /* Offset from lastStubStart to end of the shape jump. */
      int32 stubJumpOffset : 8;
  };
  
  } /* namespace ic */
  } /* namespace mjit */
  } /* namespace js */
  
  #endif /* jsjaeger_ic_labels_h__ */
  