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

#ifndef V8_COMPILER_CODE_ASSEMBLER_H_
#define V8_COMPILER_CODE_ASSEMBLER_H_

#include <map>
9
#include <memory>
10 11 12 13

// Clients of this interface shouldn't depend on lots of compiler internals.
// Do not include anything from src/compiler here!
#include "src/allocation.h"
14
#include "src/base/template-utils.h"
15
#include "src/builtins/builtins.h"
16
#include "src/code-factory.h"
17
#include "src/globals.h"
18 19 20
#include "src/heap/heap.h"
#include "src/machine-type.h"
#include "src/runtime/runtime.h"
21
#include "src/zone/zone-containers.h"
22 23 24 25 26 27 28 29 30 31

namespace v8 {
namespace internal {

class Callable;
class CallInterfaceDescriptor;
class Isolate;
class Factory;
class Zone;

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
struct UntaggedT {};

struct IntegralT : UntaggedT {};

struct WordT : IntegralT {
  static const MachineRepresentation kMachineRepresentation =
      (kPointerSize == 4) ? MachineRepresentation::kWord32
                          : MachineRepresentation::kWord64;
};

struct IntPtrT : WordT {};
struct UintPtrT : WordT {};

struct RawPtrT : WordT {};

template <class To>
struct RawPtr : RawPtrT {};

struct Word64T : IntegralT {
  static const MachineRepresentation kMachineRepresentation =
      MachineRepresentation::kWord64;
};

struct Int64T : Word64T {};

struct Word32T : IntegralT {
  static const MachineRepresentation kMachineRepresentation =
      MachineRepresentation::kWord32;
};

struct Int32T : Word32T {};

struct Uint32T : Word32T {};

struct Float32T : UntaggedT {
  static const MachineRepresentation kMachineRepresentation =
      MachineRepresentation::kFloat32;
};

struct Float64T : UntaggedT {
  static const MachineRepresentation kMachineRepresentation =
      MachineRepresentation::kFloat64;
};

// Result of a comparison operation.
struct BoolT : Word32T {};

template <class Type, class Enable = void>
struct MachineRepresentationOf {
  static const MachineRepresentation value = Type::kMachineRepresentation;
};
template <>
struct MachineRepresentationOf<Object> {
  static const MachineRepresentation value = MachineRepresentation::kTagged;
};
template <>
struct MachineRepresentationOf<Smi> {
  static const MachineRepresentation value =
      MachineRepresentation::kTaggedSigned;
};
template <class HeapObjectSubtype>
struct MachineRepresentationOf<
    HeapObjectSubtype, typename std::enable_if<std::is_base_of<
                           HeapObject, HeapObjectSubtype>::value>::type> {
  static const MachineRepresentation value =
      MachineRepresentation::kTaggedPointer;
};

#define ENUM_ELEMENT(Name) k##Name,
#define ENUM_STRUCT_ELEMENT(NAME, Name, name) k##Name,
enum class ObjectType {
  kObject,
  OBJECT_TYPE_LIST(ENUM_ELEMENT) HEAP_OBJECT_TYPE_LIST(ENUM_ELEMENT)
      STRUCT_LIST(ENUM_STRUCT_ELEMENT)
};
#undef ENUM_ELEMENT
#undef ENUM_STRUCT_ELEMENT

class AccessCheckNeeded;
class CompilationCacheTable;
class Constructor;
class Filler;
class InternalizedString;
115
class JSArgumentsObject;
116 117
class JSContextExtensionObject;
class JSError;
118
class JSSloppyArgumentsObject;
119 120 121
class MapCache;
class MutableHeapNumber;
class NativeContext;
122
class SloppyArgumentsElements;
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
class StringWrapper;
class Undetectable;
class UniqueName;
class WasmMemoryObject;
class WasmModuleObject;
class WasmTableObject;

template <class T>
struct ObjectTypeOf {};

#define OBJECT_TYPE_CASE(Name)                           \
  template <>                                            \
  struct ObjectTypeOf<Name> {                            \
    static const ObjectType value = ObjectType::k##Name; \
  };
#define OBJECT_TYPE_STRUCT_CASE(NAME, Name, name)        \
  template <>                                            \
  struct ObjectTypeOf<Name> {                            \
    static const ObjectType value = ObjectType::k##Name; \
  };
#define OBJECT_TYPE_TEMPLATE_CASE(Name)                  \
  template <class... Args>                               \
  struct ObjectTypeOf<Name<Args...>> {                   \
    static const ObjectType value = ObjectType::k##Name; \
  };
OBJECT_TYPE_CASE(Object)
OBJECT_TYPE_LIST(OBJECT_TYPE_CASE)
HEAP_OBJECT_ORDINARY_TYPE_LIST(OBJECT_TYPE_CASE)
STRUCT_LIST(OBJECT_TYPE_STRUCT_CASE)
HEAP_OBJECT_TEMPLATE_TYPE_LIST(OBJECT_TYPE_TEMPLATE_CASE)
#undef OBJECT_TYPE_CASE
#undef OBJECT_TYPE_STRUCT_CASE
#undef OBJECT_TYPE_TEMPLATE_CASE

Smi* CheckObjectType(Object* value, Smi* type, String* location);

159 160 161
namespace compiler {

class CallDescriptor;
162 163
class CodeAssemblerLabel;
class CodeAssemblerVariable;
164 165
template <class T>
class TypedCodeAssemblerVariable;
166
class CodeAssemblerState;
167 168 169 170
class Node;
class RawMachineAssembler;
class RawMachineLabel;

171 172
typedef ZoneList<CodeAssemblerVariable*> CodeAssemblerVariableList;

173 174
typedef std::function<void()> CodeAssemblerCallback;

175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
// TNode<A> is an SSA value with the static type tag A, which is either a
// subclass of internal::Object or of internal::UntaggedT or it is
// ExternalReference.
template <class A>
class TNode {
 public:
  static_assert(std::is_base_of<Object, A>::value ||
                    std::is_base_of<UntaggedT, A>::value ||
                    std::is_same<ExternalReference, A>::value,
                "type tag must be ExternalReference or a subclass of Object or "
                "UntaggedT");

  template <class B, typename std::enable_if<std::is_base_of<A, B>::value,
                                             int>::type = 0>
  TNode(const TNode<B>& other) : node_(other) {}
  TNode() : node_(nullptr) {}

  TNode operator=(TNode other) {
193
    DCHECK_NULL(node_);
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 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 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
    node_ = other.node_;
    return *this;
  }

  operator compiler::Node*() const { return node_; }

  static TNode UncheckedCast(compiler::Node* node) { return TNode(node); }

 protected:
  explicit TNode(compiler::Node* node) : node_(node) {}

 private:
  compiler::Node* node_;
};

// SloppyTNode<A> is a variant of TNode<A> and allows implicit casts from
// Node*. It is intended for function arguments as long as some call sites
// still use untyped Node* arguments.
// TODO(tebbi): Delete this class once transition is finished.
template <class A>
class SloppyTNode : public TNode<A> {
 public:
  SloppyTNode(compiler::Node* node)  // NOLINT(runtime/explicit)
      : TNode<A>(node) {}
  template <class B, typename std::enable_if<std::is_base_of<A, B>::value,
                                             int>::type = 0>
  SloppyTNode(const TNode<B>& other)  // NOLINT(runtime/explicit)
      : TNode<A>(other) {}
};

#define CODE_ASSEMBLER_COMPARE_BINARY_OP_LIST(V)          \
  V(Float32Equal, BoolT, Float32T, Float32T)              \
  V(Float32LessThan, BoolT, Float32T, Float32T)           \
  V(Float32LessThanOrEqual, BoolT, Float32T, Float32T)    \
  V(Float32GreaterThan, BoolT, Float32T, Float32T)        \
  V(Float32GreaterThanOrEqual, BoolT, Float32T, Float32T) \
  V(Float64Equal, BoolT, Float64T, Float64T)              \
  V(Float64LessThan, BoolT, Float64T, Float64T)           \
  V(Float64LessThanOrEqual, BoolT, Float64T, Float64T)    \
  V(Float64GreaterThan, BoolT, Float64T, Float64T)        \
  V(Float64GreaterThanOrEqual, BoolT, Float64T, Float64T) \
  V(Int32GreaterThan, BoolT, Word32T, Word32T)            \
  V(Int32GreaterThanOrEqual, BoolT, Word32T, Word32T)     \
  V(Int32LessThan, BoolT, Word32T, Word32T)               \
  V(Int32LessThanOrEqual, BoolT, Word32T, Word32T)        \
  V(IntPtrLessThan, BoolT, WordT, WordT)                  \
  V(IntPtrLessThanOrEqual, BoolT, WordT, WordT)           \
  V(IntPtrGreaterThan, BoolT, WordT, WordT)               \
  V(IntPtrGreaterThanOrEqual, BoolT, WordT, WordT)        \
  V(IntPtrEqual, BoolT, WordT, WordT)                     \
  V(Uint32LessThan, BoolT, Word32T, Word32T)              \
  V(Uint32LessThanOrEqual, BoolT, Word32T, Word32T)       \
  V(Uint32GreaterThanOrEqual, BoolT, Word32T, Word32T)    \
  V(UintPtrLessThan, BoolT, WordT, WordT)                 \
  V(UintPtrLessThanOrEqual, BoolT, WordT, WordT)          \
  V(UintPtrGreaterThan, BoolT, WordT, WordT)              \
  V(UintPtrGreaterThanOrEqual, BoolT, WordT, WordT)       \
  V(WordEqual, BoolT, WordT, WordT)                       \
  V(WordNotEqual, BoolT, WordT, WordT)                    \
  V(Word32Equal, BoolT, Word32T, Word32T)                 \
  V(Word32NotEqual, BoolT, Word32T, Word32T)              \
  V(Word64Equal, BoolT, Word64T, Word64T)                 \
  V(Word64NotEqual, BoolT, Word64T, Word64T)

#define CODE_ASSEMBLER_BINARY_OP_LIST(V)                  \
  CODE_ASSEMBLER_COMPARE_BINARY_OP_LIST(V)                \
  V(Float64Add, Float64T, Float64T, Float64T)             \
  V(Float64Sub, Float64T, Float64T, Float64T)             \
  V(Float64Mul, Float64T, Float64T, Float64T)             \
  V(Float64Div, Float64T, Float64T, Float64T)             \
  V(Float64Mod, Float64T, Float64T, Float64T)             \
  V(Float64Atan2, Float64T, Float64T, Float64T)           \
  V(Float64Pow, Float64T, Float64T, Float64T)             \
  V(Float64Max, Float64T, Float64T, Float64T)             \
  V(Float64Min, Float64T, Float64T, Float64T)             \
  V(Float64InsertLowWord32, Float64T, Float64T, Word32T)  \
  V(Float64InsertHighWord32, Float64T, Float64T, Word32T) \
  V(IntPtrAddWithOverflow, IntPtrT, IntPtrT, IntPtrT)     \
  V(IntPtrSubWithOverflow, IntPtrT, IntPtrT, IntPtrT)     \
  V(Int32Add, Word32T, Word32T, Word32T)                  \
  V(Int32AddWithOverflow, Int32T, Int32T, Int32T)         \
  V(Int32Sub, Word32T, Word32T, Word32T)                  \
  V(Int32Mul, Word32T, Word32T, Word32T)                  \
  V(Int32MulWithOverflow, Int32T, Int32T, Int32T)         \
  V(Int32Div, Int32T, Int32T, Int32T)                     \
  V(Int32Mod, Int32T, Int32T, Int32T)                     \
  V(WordRor, WordT, WordT, IntegralT)                     \
  V(Word32Ror, Word32T, Word32T, Word32T)                 \
  V(Word64Ror, Word64T, Word64T, Word64T)

TNode<Float64T> Float64Add(TNode<Float64T> a, TNode<Float64T> b);

#define CODE_ASSEMBLER_UNARY_OP_LIST(V)           \
  V(Float64Abs, Float64T, Float64T)               \
  V(Float64Acos, Float64T, Float64T)              \
  V(Float64Acosh, Float64T, Float64T)             \
  V(Float64Asin, Float64T, Float64T)              \
  V(Float64Asinh, Float64T, Float64T)             \
  V(Float64Atan, Float64T, Float64T)              \
  V(Float64Atanh, Float64T, Float64T)             \
  V(Float64Cos, Float64T, Float64T)               \
  V(Float64Cosh, Float64T, Float64T)              \
  V(Float64Exp, Float64T, Float64T)               \
  V(Float64Expm1, Float64T, Float64T)             \
  V(Float64Log, Float64T, Float64T)               \
  V(Float64Log1p, Float64T, Float64T)             \
  V(Float64Log2, Float64T, Float64T)              \
  V(Float64Log10, Float64T, Float64T)             \
  V(Float64Cbrt, Float64T, Float64T)              \
  V(Float64Neg, Float64T, Float64T)               \
  V(Float64Sin, Float64T, Float64T)               \
  V(Float64Sinh, Float64T, Float64T)              \
  V(Float64Sqrt, Float64T, Float64T)              \
  V(Float64Tan, Float64T, Float64T)               \
  V(Float64Tanh, Float64T, Float64T)              \
  V(Float64ExtractLowWord32, Word32T, Float64T)   \
  V(Float64ExtractHighWord32, Word32T, Float64T)  \
  V(BitcastTaggedToWord, IntPtrT, Object)         \
  V(BitcastWordToTagged, Object, WordT)           \
  V(BitcastWordToTaggedSigned, Smi, WordT)        \
  V(TruncateFloat64ToFloat32, Float32T, Float64T) \
  V(TruncateFloat64ToWord32, Word32T, Float64T)   \
  V(TruncateInt64ToInt32, Int32T, Int64T)         \
  V(ChangeFloat32ToFloat64, Float64T, Float32T)   \
  V(ChangeFloat64ToUint32, Int32T, Float64T)      \
  V(ChangeFloat64ToUint64, Word64T, Float64T)     \
  V(ChangeInt32ToFloat64, Float64T, Int32T)       \
  V(ChangeInt32ToInt64, Int64T, Int32T)           \
  V(ChangeUint32ToFloat64, Float64T, Word32T)     \
  V(ChangeUint32ToUint64, Word64T, Word32T)       \
  V(RoundFloat64ToInt32, Int32T, Float64T)        \
  V(RoundInt32ToFloat32, Int32T, Float32T)        \
  V(Float64SilenceNaN, Float64T, Float64T)        \
  V(Float64RoundDown, Float64T, Float64T)         \
  V(Float64RoundUp, Float64T, Float64T)           \
  V(Float64RoundTiesEven, Float64T, Float64T)     \
  V(Float64RoundTruncate, Float64T, Float64T)     \
  V(Word32Clz, Int32T, Word32T)                   \
  V(Word32Not, Word32T, Word32T)                  \
  V(Int32AbsWithOverflow, Int32T, Int32T)         \
  V(Int64AbsWithOverflow, Int64T, Int64T)         \
  V(IntPtrAbsWithOverflow, IntPtrT, IntPtrT)      \
  V(Word32BinaryNot, Word32T, Word32T)
337 338

// A "public" interface used by components outside of compiler directory to
339 340 341 342
// create code objects with TurboFan's backend. This class is mostly a thin
// shim around the RawMachineAssembler, and its primary job is to ensure that
// the innards of the RawMachineAssembler and other compiler implementation
// details don't leak outside of the the compiler directory..
343 344
//
// V8 components that need to generate low-level code using this interface
345 346 347 348
// should include this header--and this header only--from the compiler
// directory (this is actually enforced). Since all interesting data
// structures are forward declared, it's not possible for clients to peek
// inside the compiler internals.
349 350 351 352 353
//
// In addition to providing isolation between TurboFan and code generation
// clients, CodeAssembler also provides an abstraction for creating variables
// and enhanced Label functionality to merge variable values along paths where
// they have differing values, including loops.
354 355 356 357
//
// The CodeAssembler itself is stateless (and instances are expected to be
// temporary-scoped and short-lived); all its state is encapsulated into
// a CodeAssemblerState instance.
358
class V8_EXPORT_PRIVATE CodeAssembler {
359
 public:
360
  explicit CodeAssembler(CodeAssemblerState* state) : state_(state) {}
361
  ~CodeAssembler();
362

363
  static Handle<Code> GenerateCode(CodeAssemblerState* state);
364 365 366 367

  bool Is64() const;
  bool IsFloat64RoundUpSupported() const;
  bool IsFloat64RoundDownSupported() const;
368
  bool IsFloat64RoundTiesEvenSupported() const;
369
  bool IsFloat64RoundTruncateSupported() const;
370 371 372
  bool IsInt32AbsWithOverflowSupported() const;
  bool IsInt64AbsWithOverflowSupported() const;
  bool IsIntPtrAbsWithOverflowSupported() const;
373

374
  // Shortened aliases for use in CodeAssembler subclasses.
375 376 377 378 379
  using Label = CodeAssemblerLabel;
  using Variable = CodeAssemblerVariable;
  template <class T>
  using TVariable = TypedCodeAssemblerVariable<T>;
  using VariableList = CodeAssemblerVariableList;
380

381 382 383 384
  // ===========================================================================
  // Base Assembler
  // ===========================================================================

385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
  class CheckedNode {
   public:
#ifdef DEBUG
    CheckedNode(Node* node, CodeAssembler* code_assembler, const char* location)
        : node_(node), code_assembler_(code_assembler), location_(location) {}
#else
    CheckedNode(compiler::Node* node, CodeAssembler*, const char*)
        : node_(node) {}
#endif

    template <class A>
    operator TNode<A>() {
      static_assert(std::is_base_of<Object, A>::value,
                    "Coercion to untagged values cannot be checked.");
#ifdef DEBUG
      if (FLAG_debug_code) {
        Node* function = code_assembler_->ExternalConstant(
            ExternalReference::check_object_type(code_assembler_->isolate()));
        code_assembler_->CallCFunction3(
            MachineType::AnyTagged(), MachineType::AnyTagged(),
            MachineType::TaggedSigned(), MachineType::AnyTagged(), function,
            node_,
            code_assembler_->SmiConstant(
                static_cast<int>(ObjectTypeOf<A>::value)),
            code_assembler_->StringConstant(location_));
      }
#endif
      return TNode<A>::UncheckedCast(node_);
    }

    template <class A>
    operator SloppyTNode<A>() {
      return base::implicit_cast<TNode<A>>(*this);
    }

    Node* node() const { return node_; }

   private:
    Node* node_;
#ifdef DEBUG
    CodeAssembler* code_assembler_;
    const char* location_;
#endif
  };

  CheckedNode Cast(Node* value, const char* location) {
    return CheckedNode(value, this, location);
  }
  template <class A>
  TNode<A> UncheckedCast(Node* value) {
    return TNode<A>::UncheckedCast(value);
  }

#ifdef DEBUG
#define STRINGIFY(x) #x
#define TO_STRING_LITERAL(x) STRINGIFY(x)
#define CAST(x) \
  Cast(x, "CAST(" #x ") at " __FILE__ ":" TO_STRING_LITERAL(__LINE__))
#else
#define CAST(x) Cast(x, "")
#endif

447
  // Constants.
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
  TNode<Int32T> Int32Constant(int32_t value);
  TNode<Int64T> Int64Constant(int64_t value);
  TNode<IntPtrT> IntPtrConstant(intptr_t value);
  TNode<Object> NumberConstant(double value);
  TNode<Smi> SmiConstant(Smi* value);
  TNode<Smi> SmiConstant(int value);
  TNode<HeapObject> UntypedHeapConstant(Handle<HeapObject> object);
  template <class Type>
  TNode<Type> HeapConstant(Handle<Type> object) {
    return UncheckedCast<Type>(UntypedHeapConstant(object));
  }
  TNode<String> StringConstant(const char* str);
  TNode<Oddball> BooleanConstant(bool value);
  TNode<ExternalReference> ExternalConstant(ExternalReference address);
  TNode<Float64T> Float64Constant(double value);
  TNode<HeapNumber> NaNConstant();
464

465 466
  bool ToInt32Constant(Node* node, int32_t& out_value);
  bool ToInt64Constant(Node* node, int64_t& out_value);
467
  bool ToSmiConstant(Node* node, Smi*& out_value);
468 469
  bool ToIntPtrConstant(Node* node, intptr_t& out_value);

470 471 472 473 474 475 476 477 478
  TNode<Int32T> Signed(TNode<Word32T> x) { return UncheckedCast<Int32T>(x); }
  TNode<IntPtrT> Signed(TNode<WordT> x) { return UncheckedCast<IntPtrT>(x); }
  TNode<Uint32T> Unsigned(TNode<Word32T> x) {
    return UncheckedCast<Uint32T>(x);
  }
  TNode<UintPtrT> Unsigned(TNode<WordT> x) {
    return UncheckedCast<UintPtrT>(x);
  }

479
  Node* Parameter(int value);
480 481 482 483 484 485

  TNode<Context> GetJSContextParameter();
  void Return(SloppyTNode<Object> value);
  void Return(SloppyTNode<Object> value1, SloppyTNode<Object> value2);
  void Return(SloppyTNode<Object> value1, SloppyTNode<Object> value2,
              SloppyTNode<Object> value3);
486
  void PopAndReturn(Node* pop, Node* value);
487

488 489
  void ReturnIf(Node* condition, Node* value);

490
  void DebugAbort(Node* message);
491
  void DebugBreak();
492
  void Unreachable();
493
  void Comment(const char* format, ...);
494

495
  void Bind(Label* label);
496 497 498
#if DEBUG
  void Bind(Label* label, AssemblerDebugInfo debug_info);
#endif  // DEBUG
499
  void Goto(Label* label);
500 501 502 503
  void GotoIf(SloppyTNode<IntegralT> condition, Label* true_label);
  void GotoIfNot(SloppyTNode<IntegralT> condition, Label* false_label);
  void Branch(SloppyTNode<IntegralT> condition, Label* true_label,
              Label* false_label);
504

505
  void Switch(Node* index, Label* default_label, const int32_t* case_values,
506 507 508 509 510 511 512 513 514 515 516
              Label** case_labels, size_t case_count);

  // Access to the frame pointer
  Node* LoadFramePointer();
  Node* LoadParentFramePointer();

  // Access to the stack pointer
  Node* LoadStackPointer();

  // Load raw memory location.
  Node* Load(MachineType rep, Node* base);
517 518 519 520 521 522
  template <class Type>
  TNode<Type> Load(MachineType rep, TNode<RawPtr<Type>> base) {
    DCHECK(
        IsSubtype(rep.representation(), MachineRepresentationOf<Type>::value));
    return UncheckedCast<Type>(Load(rep, static_cast<Node*>(base)));
  }
523 524
  Node* Load(MachineType rep, Node* base, Node* offset);
  Node* AtomicLoad(MachineType rep, Node* base, Node* offset);
525

526
  // Load a value from the root array.
527
  TNode<Object> LoadRoot(Heap::RootListIndex root_index);
528

529
  // Store value to raw memory location.
530 531
  Node* Store(Node* base, Node* value);
  Node* Store(Node* base, Node* offset, Node* value);
532
  Node* StoreWithMapWriteBarrier(Node* base, Node* offset, Node* value);
533
  Node* StoreNoWriteBarrier(MachineRepresentation rep, Node* base, Node* value);
534
  Node* StoreNoWriteBarrier(MachineRepresentation rep, Node* base, Node* offset,
535
                            Node* value);
536
  Node* AtomicStore(MachineRepresentation rep, Node* base, Node* offset,
537
                    Node* value);
538

539 540 541
  // Exchange value at raw memory location
  Node* AtomicExchange(MachineType type, Node* base, Node* offset, Node* value);

542 543 544 545
  // Compare and Exchange value at raw memory location
  Node* AtomicCompareExchange(MachineType type, Node* base, Node* offset,
                              Node* old_value, Node* new_value);

546 547 548 549 550 551 552 553 554 555
  Node* AtomicAdd(MachineType type, Node* base, Node* offset, Node* value);

  Node* AtomicSub(MachineType type, Node* base, Node* offset, Node* value);

  Node* AtomicAnd(MachineType type, Node* base, Node* offset, Node* value);

  Node* AtomicOr(MachineType type, Node* base, Node* offset, Node* value);

  Node* AtomicXor(MachineType type, Node* base, Node* offset, Node* value);

556 557 558
  // Store a value to the root array.
  Node* StoreRoot(Heap::RootListIndex root_index, Node* value);

559
// Basic arithmetic operations.
560 561
#define DECLARE_CODE_ASSEMBLER_BINARY_OP(name, ResType, Arg1Type, Arg2Type) \
  TNode<ResType> name(SloppyTNode<Arg1Type> a, SloppyTNode<Arg2Type> b);
562 563 564
  CODE_ASSEMBLER_BINARY_OP_LIST(DECLARE_CODE_ASSEMBLER_BINARY_OP)
#undef DECLARE_CODE_ASSEMBLER_BINARY_OP

565 566 567 568
  TNode<IntPtrT> WordShr(TNode<IntPtrT> left, TNode<IntegralT> right) {
    return UncheckedCast<IntPtrT>(
        WordShr(static_cast<Node*>(left), static_cast<Node*>(right)));
  }
569

570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
  TNode<IntPtrT> WordAnd(TNode<IntPtrT> left, TNode<IntPtrT> right) {
    return UncheckedCast<IntPtrT>(
        WordAnd(static_cast<Node*>(left), static_cast<Node*>(right)));
  }

  template <class Left, class Right,
            class = typename std::enable_if<
                std::is_base_of<Object, Left>::value &&
                std::is_base_of<Object, Right>::value>::type>
  TNode<BoolT> WordEqual(TNode<Left> left, TNode<Right> right) {
    return WordEqual(UncheckedCast<WordT>(left), UncheckedCast<WordT>(right));
  }
  TNode<BoolT> WordEqual(TNode<Object> left, Node* right) {
    return WordEqual(UncheckedCast<WordT>(left), UncheckedCast<WordT>(right));
  }
  TNode<BoolT> WordEqual(Node* left, TNode<Object> right) {
    return WordEqual(UncheckedCast<WordT>(left), UncheckedCast<WordT>(right));
  }
  template <class Left, class Right,
            class = typename std::enable_if<
                std::is_base_of<Object, Left>::value &&
                std::is_base_of<Object, Right>::value>::type>
  TNode<BoolT> WordNotEqual(TNode<Left> left, TNode<Right> right) {
    return WordNotEqual(UncheckedCast<WordT>(left),
                        UncheckedCast<WordT>(right));
  }
  TNode<BoolT> WordNotEqual(TNode<Object> left, Node* right) {
    return WordNotEqual(UncheckedCast<WordT>(left),
                        UncheckedCast<WordT>(right));
  }
  TNode<BoolT> WordNotEqual(Node* left, TNode<Object> right) {
    return WordNotEqual(UncheckedCast<WordT>(left),
                        UncheckedCast<WordT>(right));
  }

  TNode<Int32T> Int32Add(TNode<Int32T> left, TNode<Int32T> right) {
    return Signed(
        Int32Add(static_cast<Node*>(left), static_cast<Node*>(right)));
  }

  TNode<WordT> IntPtrAdd(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
  TNode<WordT> IntPtrSub(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
612
  TNode<WordT> IntPtrMul(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
613 614 615 616 617 618 619 620
  TNode<IntPtrT> IntPtrAdd(TNode<IntPtrT> left, TNode<IntPtrT> right) {
    return Signed(
        IntPtrAdd(static_cast<Node*>(left), static_cast<Node*>(right)));
  }
  TNode<IntPtrT> IntPtrSub(TNode<IntPtrT> left, TNode<IntPtrT> right) {
    return Signed(
        IntPtrSub(static_cast<Node*>(left), static_cast<Node*>(right)));
  }
621 622 623 624
  TNode<IntPtrT> IntPtrMul(TNode<IntPtrT> left, TNode<IntPtrT> right) {
    return Signed(
        IntPtrMul(static_cast<Node*>(left), static_cast<Node*>(right)));
  }
625 626 627 628 629 630 631

  TNode<WordT> WordShl(SloppyTNode<WordT> value, int shift);
  TNode<WordT> WordShr(SloppyTNode<WordT> value, int shift);
  TNode<IntPtrT> WordShr(TNode<IntPtrT> value, int shift) {
    return UncheckedCast<IntPtrT>(WordShr(static_cast<Node*>(value), shift));
  }
  TNode<Word32T> Word32Shr(SloppyTNode<Word32T> value, int shift);
632

633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
  TNode<WordT> WordOr(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
  TNode<WordT> WordAnd(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
  TNode<WordT> WordXor(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
  TNode<WordT> WordShl(SloppyTNode<WordT> left, SloppyTNode<IntegralT> right);
  TNode<WordT> WordShr(SloppyTNode<WordT> left, SloppyTNode<IntegralT> right);
  TNode<WordT> WordSar(SloppyTNode<WordT> left, SloppyTNode<IntegralT> right);
  TNode<Word32T> Word32Or(SloppyTNode<Word32T> left,
                          SloppyTNode<Word32T> right);
  TNode<Word32T> Word32And(SloppyTNode<Word32T> left,
                           SloppyTNode<Word32T> right);
  TNode<Word32T> Word32Xor(SloppyTNode<Word32T> left,
                           SloppyTNode<Word32T> right);
  TNode<Word32T> Word32Shl(SloppyTNode<Word32T> left,
                           SloppyTNode<Word32T> right);
  TNode<Word32T> Word32Shr(SloppyTNode<Word32T> left,
                           SloppyTNode<Word32T> right);
  TNode<Word32T> Word32Sar(SloppyTNode<Word32T> left,
                           SloppyTNode<Word32T> right);
  TNode<Word64T> Word64Or(SloppyTNode<Word64T> left,
                          SloppyTNode<Word64T> right);
  TNode<Word64T> Word64And(SloppyTNode<Word64T> left,
                           SloppyTNode<Word64T> right);
  TNode<Word64T> Word64Xor(SloppyTNode<Word64T> left,
                           SloppyTNode<Word64T> right);
  TNode<Word64T> Word64Shl(SloppyTNode<Word64T> left,
                           SloppyTNode<Word64T> right);
  TNode<Word64T> Word64Shr(SloppyTNode<Word64T> left,
                           SloppyTNode<Word64T> right);
  TNode<Word64T> Word64Sar(SloppyTNode<Word64T> left,
                           SloppyTNode<Word64T> right);

664
// Unary
665 666
#define DECLARE_CODE_ASSEMBLER_UNARY_OP(name, ResType, ArgType) \
  TNode<ResType> name(SloppyTNode<ArgType> a);
667 668 669
  CODE_ASSEMBLER_UNARY_OP_LIST(DECLARE_CODE_ASSEMBLER_UNARY_OP)
#undef DECLARE_CODE_ASSEMBLER_UNARY_OP

670 671 672 673
  // Changes a double to an inptr_t for pointer arithmetic outside of Smi range.
  // Assumes that the double can be exactly represented as an int.
  Node* ChangeFloat64ToUintPtr(Node* value);

674 675 676 677
  // Changes an intptr_t to a double, e.g. for storing an element index
  // outside Smi range in a HeapNumber. Lossless on 32-bit,
  // rounds on 64-bit (which doesn't affect valid element indices).
  Node* RoundIntPtrToFloat64(Node* value);
678
  // No-op on 32-bit, otherwise zero extend.
679
  TNode<UintPtrT> ChangeUint32ToWord(SloppyTNode<Word32T> value);
680
  // No-op on 32-bit, otherwise sign extend.
681
  TNode<IntPtrT> ChangeInt32ToIntPtr(SloppyTNode<Word32T> value);
682

683 684 685 686
  // No-op that guarantees that the value is kept alive till this point even
  // if GC happens.
  Node* Retain(Node* value);

687 688 689 690
  // Projections
  Node* Projection(int index, Node* value);

  // Calls
691
  template <class... TArgs>
692 693 694 695 696 697 698 699
  TNode<Object> CallRuntimeImpl(Runtime::FunctionId function,
                                SloppyTNode<Object> context, TArgs... args);
  template <class... TArgs>
  TNode<Object> CallRuntime(Runtime::FunctionId function,
                            SloppyTNode<Object> context, TArgs... args) {
    return CallRuntimeImpl(function, context,
                           base::implicit_cast<SloppyTNode<Object>>(args)...);
  }
700

701
  template <class... TArgs>
702 703 704 705 706 707 708 709
  TNode<Object> TailCallRuntimeImpl(Runtime::FunctionId function,
                                    SloppyTNode<Object> context, TArgs... args);
  template <class... TArgs>
  TNode<Object> TailCallRuntime(Runtime::FunctionId function,
                                SloppyTNode<Object> context, TArgs... args) {
    return TailCallRuntimeImpl(
        function, context, base::implicit_cast<SloppyTNode<Object>>(args)...);
  }
710

711 712 713
  template <class... TArgs>
  Node* CallStub(Callable const& callable, Node* context, TArgs... args) {
    Node* target = HeapConstant(callable.code());
714 715
    return CallStub(callable.descriptor(), target, context,
                    base::implicit_cast<Node*>(args)...);
716
  }
717

718
  template <class... TArgs>
719
  Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target,
720
                 Node* context, TArgs... args) {
721 722
    return CallStubR(descriptor, 1, target, context,
                     base::implicit_cast<Node*>(args)...);
723 724 725 726 727 728 729 730
  }

  template <class... TArgs>
  Node* CallStubR(const CallInterfaceDescriptor& descriptor, size_t result_size,
                  Node* target, Node* context, TArgs... args);

  Node* CallStubN(const CallInterfaceDescriptor& descriptor, size_t result_size,
                  int input_count, Node* const* inputs);
731

732 733 734 735 736
  template <class... TArgs>
  Node* TailCallStub(Callable const& callable, Node* context, TArgs... args) {
    Node* target = HeapConstant(callable.code());
    return TailCallStub(callable.descriptor(), target, context, args...);
  }
737

738
  template <class... TArgs>
739
  Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
740 741 742 743 744 745 746
                     Node* context, TArgs... args) {
    return TailCallStubImpl(descriptor, target, context,
                            base::implicit_cast<Node*>(args)...);
  }
  template <class... TArgs>
  Node* TailCallStubImpl(const CallInterfaceDescriptor& descriptor,
                         Node* target, Node* context, TArgs... args);
747

748
  template <class... TArgs>
749
  Node* TailCallBytecodeDispatch(const CallInterfaceDescriptor& descriptor,
750
                                 Node* target, TArgs... args);
751

752 753 754 755 756
  template <class... TArgs>
  Node* TailCallStubThenBytecodeDispatch(
      const CallInterfaceDescriptor& descriptor, Node* context, Node* target,
      TArgs... args);

757
  template <class... TArgs>
758
  Node* CallJS(Callable const& callable, Node* context, Node* function,
759 760 761 762 763
               Node* receiver, TArgs... args) {
    int argc = static_cast<int>(sizeof...(args));
    Node* arity = Int32Constant(argc);
    return CallStub(callable, context, function, arity, receiver, args...);
  }
764

765 766 767 768 769 770 771 772 773 774 775 776
  template <class... TArgs>
  Node* ConstructJS(Callable const& callable, Node* context, Node* new_target,
                    TArgs... args) {
    int argc = static_cast<int>(sizeof...(args));
    Node* arity = Int32Constant(argc);
    Node* receiver = LoadRoot(Heap::kUndefinedValueRootIndex);

    // Construct(target, new_target, arity, receiver, arguments...)
    return CallStub(callable, context, new_target, new_target, arity, receiver,
                    args...);
  }

777 778 779
  Node* CallCFunctionN(Signature<MachineType>* signature, int input_count,
                       Node* const* inputs);

780 781 782 783
  // Call to a C function with one argument.
  Node* CallCFunction1(MachineType return_type, MachineType arg0_type,
                       Node* function, Node* arg0);

784 785 786 787
  // Call to a C function with one argument, while saving/restoring caller
  // registers except the register used for return value.
  Node* CallCFunction1WithCallerSavedRegisters(MachineType return_type,
                                               MachineType arg0_type,
788 789
                                               Node* function, Node* arg0,
                                               SaveFPRegsMode mode);
790

791 792 793 794 795
  // Call to a C function with two arguments.
  Node* CallCFunction2(MachineType return_type, MachineType arg0_type,
                       MachineType arg1_type, Node* function, Node* arg0,
                       Node* arg1);

796 797 798 799 800
  // Call to a C function with three arguments.
  Node* CallCFunction3(MachineType return_type, MachineType arg0_type,
                       MachineType arg1_type, MachineType arg2_type,
                       Node* function, Node* arg0, Node* arg1, Node* arg2);

801 802
  // Call to a C function with three arguments, while saving/restoring caller
  // registers except the register used for return value.
803 804 805 806
  Node* CallCFunction3WithCallerSavedRegisters(
      MachineType return_type, MachineType arg0_type, MachineType arg1_type,
      MachineType arg2_type, Node* function, Node* arg0, Node* arg1, Node* arg2,
      SaveFPRegsMode mode);
807

808 809 810 811 812 813 814 815
  // Call to a C function with six arguments.
  Node* CallCFunction6(MachineType return_type, MachineType arg0_type,
                       MachineType arg1_type, MachineType arg2_type,
                       MachineType arg3_type, MachineType arg4_type,
                       MachineType arg5_type, Node* function, Node* arg0,
                       Node* arg1, Node* arg2, Node* arg3, Node* arg4,
                       Node* arg5);

816 817 818 819 820 821 822 823 824 825
  // Call to a C function with nine arguments.
  Node* CallCFunction9(MachineType return_type, MachineType arg0_type,
                       MachineType arg1_type, MachineType arg2_type,
                       MachineType arg3_type, MachineType arg4_type,
                       MachineType arg5_type, MachineType arg6_type,
                       MachineType arg7_type, MachineType arg8_type,
                       Node* function, Node* arg0, Node* arg1, Node* arg2,
                       Node* arg3, Node* arg4, Node* arg5, Node* arg6,
                       Node* arg7, Node* arg8);

826 827 828 829
  // Exception handling support.
  void GotoIfException(Node* node, Label* if_exception,
                       Variable* exception_var = nullptr);

830 831 832 833 834
  // Helpers which delegate to RawMachineAssembler.
  Factory* factory() const;
  Isolate* isolate() const;
  Zone* zone() const;

835 836
  CodeAssemblerState* state() { return state_; }

837 838
  void BreakOnNode(int node_id);

839 840
  bool UnalignedLoadSupported(MachineRepresentation rep) const;
  bool UnalignedStoreSupported(MachineRepresentation rep) const;
841

842
 protected:
843 844 845 846
  void RegisterCallGenerationCallbacks(
      const CodeAssemblerCallback& call_prologue,
      const CodeAssemblerCallback& call_epilogue);
  void UnregisterCallGenerationCallbacks();
847 848

 private:
849 850
  RawMachineAssembler* raw_assembler() const;

851 852 853 854
  // Calls respective callback registered in the state.
  void CallPrologue();
  void CallEpilogue();

855
  CodeAssemblerState* state_;
856 857 858 859

  DISALLOW_COPY_AND_ASSIGN(CodeAssembler);
};

860 861 862 863
class CodeAssemblerVariable {
 public:
  explicit CodeAssemblerVariable(CodeAssembler* assembler,
                                 MachineRepresentation rep);
864 865
  CodeAssemblerVariable(CodeAssembler* assembler, MachineRepresentation rep,
                        Node* initial_value);
866 867 868 869 870 871 872
#if DEBUG
  CodeAssemblerVariable(CodeAssembler* assembler, AssemblerDebugInfo debug_info,
                        MachineRepresentation rep);
  CodeAssemblerVariable(CodeAssembler* assembler, AssemblerDebugInfo debug_info,
                        MachineRepresentation rep, Node* initial_value);
#endif  // DEBUG

873 874 875 876 877 878 879
  ~CodeAssemblerVariable();
  void Bind(Node* value);
  Node* value() const;
  MachineRepresentation rep() const;
  bool IsBound() const;

 private:
880
  class Impl;
881 882
  friend class CodeAssemblerLabel;
  friend class CodeAssemblerState;
883 884
  friend std::ostream& operator<<(std::ostream&, const Impl&);
  friend std::ostream& operator<<(std::ostream&, const CodeAssemblerVariable&);
885 886
  Impl* impl_;
  CodeAssemblerState* state_;
887
  DISALLOW_COPY_AND_ASSIGN(CodeAssemblerVariable);
888 889
};

890 891 892
std::ostream& operator<<(std::ostream&, const CodeAssemblerVariable&);
std::ostream& operator<<(std::ostream&, const CodeAssemblerVariable::Impl&);

893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931
template <class T>
class TypedCodeAssemblerVariable : public CodeAssemblerVariable {
 public:
  TypedCodeAssemblerVariable(TNode<T> initial_value, CodeAssembler* assembler)
      : CodeAssemblerVariable(assembler, MachineRepresentationOf<T>::value,
                              initial_value) {}
  explicit TypedCodeAssemblerVariable(CodeAssembler* assembler)
      : CodeAssemblerVariable(assembler, MachineRepresentationOf<T>::value) {}
#if DEBUG
  TypedCodeAssemblerVariable(AssemblerDebugInfo debug_info,
                             CodeAssembler* assembler)
      : CodeAssemblerVariable(assembler, debug_info,
                              MachineRepresentationOf<T>::value) {}
  TypedCodeAssemblerVariable(AssemblerDebugInfo debug_info,
                             TNode<T> initial_value, CodeAssembler* assembler)
      : CodeAssemblerVariable(assembler, debug_info,
                              MachineRepresentationOf<T>::value,
                              initial_value) {}
#endif  // DEBUG

  template <class A,
            class = typename std::enable_if<std::is_base_of<A, T>::value>::type>
  operator TNode<A>() const {
    return TNode<T>::UncheckedCast(value());
  }
  template <class A,
            class = typename std::enable_if<std::is_base_of<A, T>::value>::type>
  operator SloppyTNode<A>() const {
    return value();
  }
  operator Node*() const { return value(); }

  void operator=(TNode<T> value) { Bind(value); }

 private:
  using CodeAssemblerVariable::Bind;
  using CodeAssemblerVariable::value;
};

932
class CodeAssemblerLabel {
933 934 935
 public:
  enum Type { kDeferred, kNonDeferred };

936 937 938 939 940
  explicit CodeAssemblerLabel(
      CodeAssembler* assembler,
      CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred)
      : CodeAssemblerLabel(assembler, 0, nullptr, type) {}
  CodeAssemblerLabel(
941
      CodeAssembler* assembler,
942 943 944 945 946
      const CodeAssemblerVariableList& merged_variables,
      CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred)
      : CodeAssemblerLabel(assembler, merged_variables.length(),
                           &(merged_variables[0]), type) {}
  CodeAssemblerLabel(
947 948
      CodeAssembler* assembler, size_t count,
      CodeAssemblerVariable* const* vars,
949
      CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred);
950 951 952 953 954
  CodeAssemblerLabel(
      CodeAssembler* assembler,
      std::initializer_list<CodeAssemblerVariable*> vars,
      CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred)
      : CodeAssemblerLabel(assembler, vars.size(), vars.begin(), type) {}
955 956 957 958
  CodeAssemblerLabel(
      CodeAssembler* assembler, CodeAssemblerVariable* merged_variable,
      CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred)
      : CodeAssemblerLabel(assembler, 1, &merged_variable, type) {}
959
  ~CodeAssemblerLabel();
960

961 962
  inline bool is_bound() const { return bound_; }

963 964 965 966
 private:
  friend class CodeAssembler;

  void Bind();
967 968 969 970
#if DEBUG
  void Bind(AssemblerDebugInfo debug_info);
#endif  // DEBUG
  void UpdateVariablesAfterBind();
971 972 973 974
  void MergeVariables();

  bool bound_;
  size_t merge_count_;
975
  CodeAssemblerState* state_;
976 977 978
  RawMachineLabel* label_;
  // Map of variables that need to be merged to their phi nodes (or placeholders
  // for those phis).
979
  std::map<CodeAssemblerVariable::Impl*, Node*> variable_phis_;
980 981
  // Map of variables to the list of value nodes that have been added from each
  // merge path in their order of merging.
982
  std::map<CodeAssemblerVariable::Impl*, std::vector<Node*>> variable_merges_;
983 984
};

985 986 987 988 989 990
class V8_EXPORT_PRIVATE CodeAssemblerState {
 public:
  // Create with CallStub linkage.
  // |result_size| specifies the number of results returned by the stub.
  // TODO(rmcilroy): move result_size to the CallInterfaceDescriptor.
  CodeAssemblerState(Isolate* isolate, Zone* zone,
991 992
                     const CallInterfaceDescriptor& descriptor, Code::Kind kind,
                     const char* name, size_t result_size = 1);
993 994 995

  // Create with JSCall linkage.
  CodeAssemblerState(Isolate* isolate, Zone* zone, int parameter_count,
996
                     Code::Kind kind, const char* name);
997 998 999

  ~CodeAssemblerState();

1000
  const char* name() const { return name_; }
1001
  int parameter_count() const;
1002

1003 1004 1005 1006 1007
#if DEBUG
  void PrintCurrentBlock(std::ostream& os);
#endif  // DEBUG
  void SetInitialDebugInformation(const char* msg, const char* file, int line);

1008 1009
 private:
  friend class CodeAssembler;
1010 1011
  friend class CodeAssemblerLabel;
  friend class CodeAssemblerVariable;
1012
  friend class CodeAssemblerTester;
1013 1014

  CodeAssemblerState(Isolate* isolate, Zone* zone,
1015
                     CallDescriptor* call_descriptor, Code::Kind kind,
1016 1017 1018
                     const char* name);

  std::unique_ptr<RawMachineAssembler> raw_assembler_;
1019
  Code::Kind kind_;
1020 1021
  const char* name_;
  bool code_generated_;
1022
  ZoneSet<CodeAssemblerVariable::Impl*> variables_;
1023 1024
  CodeAssemblerCallback call_prologue_;
  CodeAssemblerCallback call_epilogue_;
1025 1026 1027 1028

  DISALLOW_COPY_AND_ASSIGN(CodeAssemblerState);
};

1029 1030 1031 1032 1033
}  // namespace compiler
}  // namespace internal
}  // namespace v8

#endif  // V8_COMPILER_CODE_ASSEMBLER_H_