macro-assembler.h 8.13 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

#ifndef V8_MACRO_ASSEMBLER_H_
#define V8_MACRO_ASSEMBLER_H_

8 9
#include "src/assembler.h"

10 11 12 13 14 15 16 17

// Helper types to make boolean flag easier to read at call-site.
enum InvokeFlag {
  CALL_FUNCTION,
  JUMP_FUNCTION
};


18 19 20 21 22 23 24 25 26 27 28 29 30
// Flags used for the AllocateInNewSpace functions.
enum AllocationFlags {
  // No special flags.
  NO_ALLOCATION_FLAGS = 0,
  // Return the pointer to the allocated already tagged as a heap object.
  TAG_OBJECT = 1 << 0,
  // The content of the result register already contains the allocation top in
  // new space.
  RESULT_CONTAINS_TOP = 1 << 1,
  // Specify that the requested size of the space to allocate is specified in
  // words instead of bytes.
  SIZE_IN_WORDS = 1 << 2,
  // Align the allocation to a multiple of kDoubleSize
31
  DOUBLE_ALIGNMENT = 1 << 3,
32 33
  // Directly allocate in old space
  PRETENURE = 1 << 4,
34 35 36
};


37
#if V8_TARGET_ARCH_IA32
38 39 40
#include "src/ia32/assembler-ia32.h"
#include "src/ia32/assembler-ia32-inl.h"
#include "src/ia32/macro-assembler-ia32.h"
41
#elif V8_TARGET_ARCH_X64
42 43 44
#include "src/x64/assembler-x64.h"
#include "src/x64/assembler-x64-inl.h"
#include "src/x64/macro-assembler-x64.h"
45
#elif V8_TARGET_ARCH_ARM64
46
#include "src/arm64/assembler-arm64.h"
47
#include "src/arm64/assembler-arm64-inl.h"
48 49
#include "src/arm64/constants-arm64.h"
#include "src/arm64/macro-assembler-arm64.h"
50
#include "src/arm64/macro-assembler-arm64-inl.h"
51
#elif V8_TARGET_ARCH_ARM
52
#include "src/arm/assembler-arm.h"
53
#include "src/arm/assembler-arm-inl.h"
54 55
#include "src/arm/constants-arm.h"
#include "src/arm/macro-assembler-arm.h"
56
#elif V8_TARGET_ARCH_PPC
57
#include "src/ppc/assembler-ppc.h"
58
#include "src/ppc/assembler-ppc-inl.h"
59
#include "src/ppc/constants-ppc.h"
60
#include "src/ppc/macro-assembler-ppc.h"
61
#elif V8_TARGET_ARCH_MIPS
62
#include "src/mips/assembler-mips.h"
63
#include "src/mips/assembler-mips-inl.h"
64
#include "src/mips/constants-mips.h"
65
#include "src/mips/macro-assembler-mips.h"
66
#elif V8_TARGET_ARCH_MIPS64
67
#include "src/mips64/assembler-mips64.h"
68
#include "src/mips64/assembler-mips64-inl.h"
69
#include "src/mips64/constants-mips64.h"
70
#include "src/mips64/macro-assembler-mips64.h"
71 72 73 74 75
#elif V8_TARGET_ARCH_S390
#include "src/s390/assembler-s390.h"
#include "src/s390/assembler-s390-inl.h"
#include "src/s390/constants-s390.h"
#include "src/s390/macro-assembler-s390.h"
danno@chromium.org's avatar
danno@chromium.org committed
76
#elif V8_TARGET_ARCH_X87
77 78 79
#include "src/x87/assembler-x87.h"
#include "src/x87/assembler-x87-inl.h"
#include "src/x87/macro-assembler-x87.h"
80 81
#else
#error Unsupported target architecture.
82 83
#endif

84 85 86
namespace v8 {
namespace internal {

87 88 89
class FrameScope {
 public:
  explicit FrameScope(MacroAssembler* masm, StackFrame::Type type)
90
      : masm_(masm), type_(type), old_has_frame_(masm->has_frame()) {
91 92 93 94 95 96 97 98 99 100
    masm->set_has_frame(true);
    if (type != StackFrame::MANUAL && type_ != StackFrame::NONE) {
      masm->EnterFrame(type);
    }
  }

  ~FrameScope() {
    if (type_ != StackFrame::MANUAL && type_ != StackFrame::NONE) {
      masm_->LeaveFrame(type_);
    }
101
    masm_->set_has_frame(old_has_frame_);
102 103 104 105 106 107 108 109
  }

  // Normally we generate the leave-frame code when this object goes
  // out of scope.  Sometimes we may need to generate the code somewhere else
  // in addition.  Calling this will achieve that, but the object stays in
  // scope, the MacroAssembler is still marked as being in a frame scope, and
  // the code will be generated again when it goes out of scope.
  void GenerateLeaveFrame() {
110
    DCHECK(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE);
111 112 113 114 115 116
    masm_->LeaveFrame(type_);
  }

 private:
  MacroAssembler* masm_;
  StackFrame::Type type_;
117
  bool old_has_frame_;
118 119
};

120 121 122 123 124 125
class FrameAndConstantPoolScope {
 public:
  FrameAndConstantPoolScope(MacroAssembler* masm, StackFrame::Type type)
      : masm_(masm),
        type_(type),
        old_has_frame_(masm->has_frame()),
126 127
        old_constant_pool_available_(FLAG_enable_embedded_constant_pool &&
                                     masm->is_constant_pool_available()) {
128
    masm->set_has_frame(true);
129 130
    if (FLAG_enable_embedded_constant_pool) {
      masm->set_constant_pool_available(true);
131 132 133 134 135 136 137 138 139
    }
    if (type_ != StackFrame::MANUAL && type_ != StackFrame::NONE) {
      masm->EnterFrame(type, !old_constant_pool_available_);
    }
  }

  ~FrameAndConstantPoolScope() {
    masm_->LeaveFrame(type_);
    masm_->set_has_frame(old_has_frame_);
140 141
    if (FLAG_enable_embedded_constant_pool) {
      masm_->set_constant_pool_available(old_constant_pool_available_);
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    }
  }

  // Normally we generate the leave-frame code when this object goes
  // out of scope.  Sometimes we may need to generate the code somewhere else
  // in addition.  Calling this will achieve that, but the object stays in
  // scope, the MacroAssembler is still marked as being in a frame scope, and
  // the code will be generated again when it goes out of scope.
  void GenerateLeaveFrame() {
    DCHECK(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE);
    masm_->LeaveFrame(type_);
  }

 private:
  MacroAssembler* masm_;
  StackFrame::Type type_;
  bool old_has_frame_;
  bool old_constant_pool_available_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(FrameAndConstantPoolScope);
};

// Class for scoping the the unavailability of constant pool access.
class ConstantPoolUnavailableScope {
 public:
  explicit ConstantPoolUnavailableScope(MacroAssembler* masm)
      : masm_(masm),
169 170 171 172
        old_constant_pool_available_(FLAG_enable_embedded_constant_pool &&
                                     masm->is_constant_pool_available()) {
    if (FLAG_enable_embedded_constant_pool) {
      masm_->set_constant_pool_available(false);
173 174 175
    }
  }
  ~ConstantPoolUnavailableScope() {
176 177
    if (FLAG_enable_embedded_constant_pool) {
      masm_->set_constant_pool_available(old_constant_pool_available_);
178 179 180 181 182 183 184 185 186 187
    }
  }

 private:
  MacroAssembler* masm_;
  int old_constant_pool_available_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(ConstantPoolUnavailableScope);
};

188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212

class AllowExternalCallThatCantCauseGC: public FrameScope {
 public:
  explicit AllowExternalCallThatCantCauseGC(MacroAssembler* masm)
      : FrameScope(masm, StackFrame::NONE) { }
};


class NoCurrentFrameScope {
 public:
  explicit NoCurrentFrameScope(MacroAssembler* masm)
      : masm_(masm), saved_(masm->has_frame()) {
    masm->set_has_frame(false);
  }

  ~NoCurrentFrameScope() {
    masm_->set_has_frame(saved_);
  }

 private:
  MacroAssembler* masm_;
  bool saved_;
};


213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
// Support for "structured" code comments.
#ifdef DEBUG

class Comment {
 public:
  Comment(MacroAssembler* masm, const char* msg);
  ~Comment();

 private:
  MacroAssembler* masm_;
  const char* msg_;
};

#else

class Comment {
 public:
  Comment(MacroAssembler*, const char*)  {}
};

#endif  // DEBUG

235

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
// Wrapper class for passing expected and actual parameter counts as
// either registers or immediate values. Used to make sure that the
// caller provides exactly the expected number of parameters to the
// callee.
class ParameterCount BASE_EMBEDDED {
 public:
  explicit ParameterCount(Register reg) : reg_(reg), immediate_(0) {}
  explicit ParameterCount(int imm) : reg_(no_reg), immediate_(imm) {}

  bool is_reg() const { return !reg_.is(no_reg); }
  bool is_immediate() const { return !is_reg(); }

  Register reg() const {
    DCHECK(is_reg());
    return reg_;
  }
  int immediate() const {
    DCHECK(is_immediate());
    return immediate_;
  }

 private:
  const Register reg_;
  const int immediate_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(ParameterCount);
};


265 266 267 268
class AllocationUtils {
 public:
  static ExternalReference GetAllocationTopReference(
      Isolate* isolate, AllocationFlags flags) {
269 270
    if ((flags & PRETENURE) != 0) {
      return ExternalReference::old_space_allocation_top_address(isolate);
271 272
    }
    return ExternalReference::new_space_allocation_top_address(isolate);
273 274 275 276 277
  }


  static ExternalReference GetAllocationLimitReference(
      Isolate* isolate, AllocationFlags flags) {
278 279
    if ((flags & PRETENURE) != 0) {
      return ExternalReference::old_space_allocation_limit_address(isolate);
280 281
    }
    return ExternalReference::new_space_allocation_limit_address(isolate);
282 283 284 285
  }
};


286 287
}  // namespace internal
}  // namespace v8
288

289
#endif  // V8_MACRO_ASSEMBLER_H_