15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2009 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 1994-2006 Sun Microsystems Inc.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All Rights Reserved.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met:
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Redistributions of source code must retain the above copyright notice,
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this list of conditions and the following disclaimer.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Redistribution in binary form must reproduce the above copyright
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer in the
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// documentation and/or other materials provided with the distribution.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Neither the name of Sun Microsystems or the names of contributors may
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be used to endorse or promote products derived from this software without
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// specific prior written permission.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The original source code covered by the above license above has been
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modified significantly by Google Inc.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2006-2008 the V8 project authors. All rights reserved.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This implements a C++ assembler for dynamically generating machine code.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is heavily based on the v8 assembler, which has a long history of its
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// own.  Relocation information has been removed, and in general things were
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// made a bit simpler (and slower).  Everything is implemented inline.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef TRACELINE_ASSEMBLER_H_
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TRACELINE_ASSEMBLER_H_
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "logging.h"
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASSERT(x) CHECK(x)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum Register {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EAX = 0,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ECX = 1,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EDX = 2,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EBX = 3,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ESP = 4,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EBP = 5,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ESI = 6,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EDI = 7
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum Condition {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow      =  0,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  no_overflow   =  1,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  below         =  2,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  above_equal   =  3,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  equal         =  4,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  not_equal     =  5,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  below_equal   =  6,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  above         =  7,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sign          =  8,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  not_sign      =  9,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parity_even   = 10,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parity_odd    = 11,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  less          = 12,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  greater_equal = 13,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  less_equal    = 14,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  greater       = 15,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // aliases
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zero          = equal,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  not_zero      = not_equal,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  negative      = sign,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  positive      = not_sign
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Labels are used for branching, and marks an offset in the CodeBuffer.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A label can be in 3 states:
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  - Unused, the label has never be used in an instruction.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  - Linked, the label has been referenced (by a jump, for example), but the
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    target is not yet known, because the label is unbound.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  - Bound, the label has been bound so the offset is known.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Label {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Label() { Unuse(); }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~Label() { ASSERT(!is_linked()); }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Unuse() {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_ = 0;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_unused() const { return num_ == 0; }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_bound() const { return num_ == -1; }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_linked() const { return num_ > 0; }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int binding_pos() const {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(is_bound());
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return table_[0];
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_links() const {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(!is_bound());
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return num_;  // Will return 0 if unused.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int link_pos(int i) const {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(is_linked());
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(i < num_);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return table_[i];
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void bind_to(int pos)  {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(!is_bound());
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    table_[0] = pos;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_ = -1;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void link_to(int pos)  {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(!is_bound());
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(num_ < kTableSize);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    table_[num_] = pos;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++num_;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kTableSize = 3;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We store all links in a fixed size table.  When we're bound, we store the
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // binding position in the first entry of the table.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int table_[kTableSize];
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The number of entries in our table, if we're linked.  If 0, then we're
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // unusued.  If -1, then we are bound (and the pos is at table_[0]).
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class CodeBuffer;  // For binding, linking, etc
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum ScaleFactor {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SCALE_TIMES_1 = 0,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SCALE_TIMES_2 = 1,
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SCALE_TIMES_4 = 2,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SCALE_TIMES_8 = 3
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Operand {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit Operand(const Operand& x) : len_(x.len_) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(buf_, x.buf_, sizeof(buf_));
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reg
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit Operand(Register reg) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Init(reg);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // [disp/r]
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit Operand(int disp) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Init(disp);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // [base + disp/r]
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Operand(Register base, int disp) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Init(base, disp);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // [base + index*scale + disp/r]
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Operand(Register base, Register index, ScaleFactor scale, int disp) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Init(base, index, scale, disp);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // [index*scale + disp/r]
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Operand(Register index, ScaleFactor scale, int disp) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Init(index, scale, disp);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void set_reg(Register reg) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(len_ > 0);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buf_[0] = (buf_[0] & ~0x38) | static_cast<char>(reg << 3);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* data() { return buf_; }
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int length() { return len_; }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reg
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Init(Register reg) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    set_modrm(3, reg);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // [disp/r]
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Init(int disp) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    set_modrm(0, EBP);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    set_dispr(disp);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // [base + disp/r]
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Init(Register base, int disp) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (disp == 0) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // [base]
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_modrm(0, base);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (base == ESP) set_sib(SCALE_TIMES_1, ESP, base);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (is_int8(disp)) {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // [base + disp8]
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_modrm(1, base);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (base == ESP) set_sib(SCALE_TIMES_1, ESP, base);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_disp8(disp);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // [base + disp/r]
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_modrm(2, base);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (base == ESP) set_sib(SCALE_TIMES_1, ESP, base);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_dispr(disp);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // [base + index*scale + disp/r]
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Init(Register base,
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            Register index,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ScaleFactor scale,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            int disp) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(index != ESP);  // illegal addressing mode
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (disp == 0 && base != EBP) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // [base + index*scale]
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_modrm(0, ESP);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_sib(scale, index, base);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (is_int8(disp)) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // [base + index*scale + disp8]
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_modrm(1, ESP);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_sib(scale, index, base);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_disp8(disp);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // [base + index*scale + disp/r]
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_modrm(2, ESP);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_sib(scale, index, base);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_dispr(disp);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // [index*scale + disp/r]
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Init(Register index,
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ScaleFactor scale,
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            int disp) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(index != ESP);  // illegal addressing mode
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We can reduce instruction size by translating instructions of the form:
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //   8D044510000000    lea eax,[eax*2+0x10]
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // To the more concise scale=1 version:
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //   8D440010          lea eax,[eax+eax+0x10]
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (scale == SCALE_TIMES_2) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Init(index, index, SCALE_TIMES_1, disp);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_modrm(0, ESP);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_sib(scale, index, EBP);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      set_dispr(disp);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if this Operand is a wrapper for the specified register.
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_reg(Register reg) const {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ((buf_[0] & 0xF8) == 0xC0)  // addressing mode is register only.
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        && ((buf_[0] & 0x07) == reg);  // register codes match.
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void set_modrm(int mod, Register rm) {  // reg == 0
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT((mod & -4) == 0);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buf_[0] = mod << 6 | rm;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len_ = 1;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void set_sib(ScaleFactor scale, Register index, Register base) {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(len_ == 1);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT((scale & -4) == 0);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buf_[1] = scale << 6 | index << 3 | base;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len_ = 2;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void set_disp8(char disp) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(len_ == 1 || len_ == 2);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *reinterpret_cast<char*>(&buf_[len_++]) = disp;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void set_dispr(int disp) {
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(len_ == 1 || len_ == 2);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *reinterpret_cast<int*>(&buf_[len_]) = disp;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len_ += sizeof(int);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_int8(int x) { return x >= -128 && x <= 127; }
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mutable because reg in ModR/M byte is set by Assembler via set_reg().
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char buf_[6];
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The number of bytes in buf_.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int len_;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A convenient wrapper around a buffer for emitting code or data, etc.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CodeBuffer {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use an externally managed buffer
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit CodeBuffer(char* buf) : pos_(0), buf_(buf) { }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* data() { return buf_; }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int size() { return pos_; }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void emit(unsigned char b) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buf_[pos_++] = b;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void emit_word(unsigned short w) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *reinterpret_cast<unsigned short*>(&buf_[pos_]) = w;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pos_ += 2;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void emit_dword(unsigned int d) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *reinterpret_cast<unsigned int*>(&buf_[pos_]) = d;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pos_ += 4;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void emit_bytes(const char* bytes, size_t size) {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < size; ++i)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit(bytes[i]);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void emit_bytes(const std::string& bytes) {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit_bytes(bytes.data(), bytes.size());
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void put_dword_at(int pos, unsigned int d) {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *reinterpret_cast<unsigned int*>(&buf_[pos]) = d;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We pass by value so that we get a copy that we can modify.
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void emit_operand(Register reg, Operand operand) {
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    operand.set_reg(reg);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(&buf_[pos_], operand.data(), operand.length());
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pos_ += operand.length();
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void bind(Label* l) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(!l->is_bound());
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < l->num_links(); ++i) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      put_dword_at(l->link_pos(i), pos_ - (l->link_pos(i) + 4));
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    l->bind_to(pos_);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO deprecate blah_imm and use blah(Immediate)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void add(Register dst, Register src) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x01); emit(0xc0 | (src << 3) | dst);
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void add_imm(Register dst, int d) {
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (d >= -128 && d <= 127) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit(0x83); emit(0xc0 | dst); emit(d & 0xff);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit(0x81); emit(0xc0 | dst); emit_dword(d);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void and_(Register r, unsigned int mask) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x81); emit(0xe0 | r); emit_dword(mask);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void call(Register r) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    call(Operand(r));
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void call(const Operand& dst) {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xff); emit_operand(EDX, dst);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void cmp(Register r1, Register r2) {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x39); emit(0xc0 | (r2 << 3) | r1);
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void cmp_imm(Register r, int d) {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (d >= -128 && d <= 127) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit(0x83); emit(0xf8 | r); emit(d & 0xff);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit(0x81); emit(0xf8 | r); emit_dword(d);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void fs() {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x64);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Atomically increment the dword at |mem| with the increment amount in the
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // register |inc|.  Will replace |inc| with the old unincremented value.
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void inc_atomic(Register mem, Register inc) {
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // lock xadd [mem], inc
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xF0); emit(0x0F); emit(0xC1); emit((inc << 3) | mem);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void int3() {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xcc);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void jcc(Condition cc, Label* l) {
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x0f); emit(0x80 | cc);
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (l->is_bound()) {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit_dword(l->binding_pos() - (pos_ + 4));
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Will fix up when the label is bound.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l->link_to(pos_);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit_dword(0);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void jmp(Register r) {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xff); emit(0xe0 | r);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void jmp(Label* l) {
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (l->is_bound()) {
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jmp_rel(l->binding_pos() - (pos_ + 5));
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Will fix up when the label is bound.
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l->link_to(pos_ + 1);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jmp_rel(0);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void jmp_rel(int i) {
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xe9); emit_dword(i);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void jmp_rel_short(char c) {
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xeb); emit(c);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void lea(Register dst, const Operand& src) {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x8d); emit_operand(dst, src);
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void lodsb() {
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xac);
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void lodsd() {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xad);
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void loop(Label* l) {
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(l->is_bound());
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int pos = l->binding_pos() - (pos_ + 2);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(pos >= -128 && pos < 0);
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xe2); emit(pos & 0xff);
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void mov(Register dst, Register src) {
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x89); emit(0xc0 | (src << 3) | dst);
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void mov(Register dst, const Operand& src) {
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x8b); emit_operand(dst, src);
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void mov_imm(Register r, unsigned int d) {
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xb8 | r); emit_dword(d);
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void movsb() {
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xa4);
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void movsd() {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xa5);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void or_(Register r, unsigned int mask) {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x81); emit(0xc8 | r); emit_dword(mask);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void pop(Register r) {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x58 | r);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void pop(const Operand& dst) {
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x8f); emit_operand(EAX, dst);
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void push(Register r) {
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x50 | r);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void push(const Operand& src) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xff); emit_operand(ESI, src);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void push_imm(int i) {
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i >= -128 && i <= 127) {
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit(0x6a); emit(i & 0xff);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit(0x68); emit_dword(i);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Puts the cycle counter into edx:eax.
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void rdtsc() {
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x0F); emit(0x31);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void rep() {
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xf3);
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ret() {
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret(0);
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ret(short c) {
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (c == 0) {
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit(0xc3);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit(0xc2); emit_word(c);
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void spin() {
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jmp_rel_short(-2);
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void stosb() {
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xaa);
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void stosd() {
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0xab);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void sysenter() {
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x0f); emit(0x34);
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Puts a unique cpu identifier into eax, using sidt to fingerprint cores.
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void which_cpu() {
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make space
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    push(EAX);
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    push(EAX);
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // sidt [esp+2]
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x0f); emit(0x01); emit_operand(ECX, Operand(ESP, 2));
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pop(EAX);
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pop(EAX);  // sidt address
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Puts a unique identifier for the thread we're executing on into eax.
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void which_thread() {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // mov eax, [fs:0x24]
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x64); emit(0xa1); emit_dword(0x24);
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO: We could do this but it will use an encoding that is 1 byte bigger.
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // fs(); mov(EAX, Operand(0x24));
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void xchg(Register r1, Register r2) {
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (r1 == EAX) {
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit(0x90 | r2);
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (r2 == EAX) {
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      emit(0x90 | r1);
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      xchg(r1, Operand(r2));
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void xchg(Register r1, const Operand& oper) {
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    emit(0x87); emit_operand(r1, oper);
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pos_;
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* buf_;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // TRACELINE_ASSEMBLER_H_
577