Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Unified Diff: tools/traceline/traceline/assembler.h

Issue 20494: Import Traceline, a Windows performance trace event logger. (Closed)
Patch Set: Feedback. Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/traceline/traceline/README ('k') | tools/traceline/traceline/assembler_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/traceline/traceline/assembler.h
diff --git a/tools/traceline/traceline/assembler.h b/tools/traceline/traceline/assembler.h
new file mode 100755
index 0000000000000000000000000000000000000000..633d778e45f207255d20402a21df64fa7ebf132f
--- /dev/null
+++ b/tools/traceline/traceline/assembler.h
@@ -0,0 +1,581 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// - Redistribution in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// - Neither the name of Sun Microsystems or the names of contributors may
+// be used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+// This implements a C++ assembler for dynamically generating machine code.
+// It is heavily based on the v8 assembler, which has a long history of its
+// own. Relocation information has been removed, and in general things were
+// made a bit simpler (and slower). Everything is implemented inline.
+
+#ifndef TRACELINE_ASSEMBLER_H_
+#define TRACELINE_ASSEMBLER_H_
+
+#include <windows.h>
+#include <stdio.h>
+#include <string>
+
+#include "logging.h"
+
+#define ASSERT(x) CHECK(x)
+
+enum Register {
+ EAX = 0,
+ ECX = 1,
+ EDX = 2,
+ EBX = 3,
+ ESP = 4,
+ EBP = 5,
+ ESI = 6,
+ EDI = 7
+};
+
+enum Condition {
+ overflow = 0,
+ no_overflow = 1,
+ below = 2,
+ above_equal = 3,
+ equal = 4,
+ not_equal = 5,
+ below_equal = 6,
+ above = 7,
+ sign = 8,
+ not_sign = 9,
+ parity_even = 10,
+ parity_odd = 11,
+ less = 12,
+ greater_equal = 13,
+ less_equal = 14,
+ greater = 15,
+
+ // aliases
+ zero = equal,
+ not_zero = not_equal,
+ negative = sign,
+ positive = not_sign
+};
+
+// Labels are used for branching, and marks an offset in the CodeBuffer.
+// A label can be in 3 states:
+// - Unused, the label has never be used in an instruction.
+// - Linked, the label has been referenced (by a jump, for example), but the
+// target is not yet known, because the label is unbound.
+// - Bound, the label has been bound so the offset is known.
+class Label {
+ public:
+ Label() { Unuse(); }
+ ~Label() { ASSERT(!is_linked()); }
+
+ void Unuse() {
+ num_ = 0;
+ }
+
+ bool is_unused() const { return num_ == 0; }
+ bool is_bound() const { return num_ == -1; }
+ bool is_linked() const { return num_ > 0; }
+
+ int binding_pos() const {
+ ASSERT(is_bound());
+ return table_[0];
+ }
+
+ int num_links() const {
+ ASSERT(!is_bound());
+ return num_; // Will return 0 if unused.
+ }
+
+ int link_pos(int i) const {
+ ASSERT(is_linked());
+ ASSERT(i < num_);
+ return table_[i];
+ }
+
+ private:
+ void bind_to(int pos) {
+ ASSERT(!is_bound());
+ table_[0] = pos;
+ num_ = -1;
+ }
+ void link_to(int pos) {
+ ASSERT(!is_bound());
+ ASSERT(num_ < kTableSize);
+
+ table_[num_] = pos;
+ ++num_;
+ }
+
+ static const int kTableSize = 3;
+
+ // We store all links in a fixed size table. When we're bound, we store the
+ // binding position in the first entry of the table.
+ int table_[kTableSize];
+ // The number of entries in our table, if we're linked. If 0, then we're
+ // unusued. If -1, then we are bound (and the pos is at table_[0]).
+ int num_;
+
+ friend class CodeBuffer; // For binding, linking, etc
+};
+
+
+enum ScaleFactor {
+ SCALE_TIMES_1 = 0,
+ SCALE_TIMES_2 = 1,
+ SCALE_TIMES_4 = 2,
+ SCALE_TIMES_8 = 3
+};
+
+
+class Operand {
+ public:
+ explicit Operand(const Operand& x) : len_(x.len_) {
+ memcpy(buf_, x.buf_, sizeof(buf_));
+ }
+
+ // reg
+ explicit Operand(Register reg) {
+ Init(reg);
+ }
+
+ // [disp/r]
+ explicit Operand(int disp) {
+ Init(disp);
+ }
+
+ // [base + disp/r]
+ explicit Operand(Register base, int disp) {
+ Init(base, disp);
+ }
+
+ // [base + index*scale + disp/r]
+ explicit Operand(Register base,
+ Register index,
+ ScaleFactor scale,
+ int disp) {
+ Init(base, index, scale, disp);
+ }
+
+ // [index*scale + disp/r]
+ explicit Operand(Register index,
+ ScaleFactor scale,
+ int disp) {
+ Init(index, scale, disp);
+ }
+
+ void set_reg(Register reg) {
+ ASSERT(len_ > 0);
+ buf_[0] = (buf_[0] & ~0x38) | static_cast<char>(reg << 3);
+ }
+
+ char* data() { return buf_; }
+ int length() { return len_; }
+
+ private:
+ // reg
+ void Init(Register reg) {
+ set_modrm(3, reg);
+ }
+
+ // [disp/r]
+ void Init(int disp) {
+ set_modrm(0, EBP);
+ set_dispr(disp);
+ }
+
+ // [base + disp/r]
+ void Init(Register base, int disp) {
+ if (disp == 0) {
+ // [base]
+ set_modrm(0, base);
+ if (base == ESP) set_sib(SCALE_TIMES_1, ESP, base);
+ } else if (is_int8(disp)) {
+ // [base + disp8]
+ set_modrm(1, base);
+ if (base == ESP) set_sib(SCALE_TIMES_1, ESP, base);
+ set_disp8(disp);
+ } else {
+ // [base + disp/r]
+ set_modrm(2, base);
+ if (base == ESP) set_sib(SCALE_TIMES_1, ESP, base);
+ set_dispr(disp);
+ }
+ }
+
+ // [base + index*scale + disp/r]
+ void Init(Register base,
+ Register index,
+ ScaleFactor scale,
+ int disp) {
+ ASSERT(index != ESP); // illegal addressing mode
+ if (disp == 0 && base != EBP) {
+ // [base + index*scale]
+ set_modrm(0, ESP);
+ set_sib(scale, index, base);
+ } else if (is_int8(disp)) {
+ // [base + index*scale + disp8]
+ set_modrm(1, ESP);
+ set_sib(scale, index, base);
+ set_disp8(disp);
+ } else {
+ // [base + index*scale + disp/r]
+ set_modrm(2, ESP);
+ set_sib(scale, index, base);
+ set_dispr(disp);
+ }
+ }
+
+ // [index*scale + disp/r]
+ void Init(Register index,
+ ScaleFactor scale,
+ int disp) {
+ ASSERT(index != ESP); // illegal addressing mode
+ // We can reduce instruction size by translating instructions of the form:
+ // 8D044510000000 lea eax,[eax*2+0x10]
+ // To the more concise scale=1 version:
+ // 8D440010 lea eax,[eax+eax+0x10]
+ if (scale == SCALE_TIMES_2) {
+ Init(index, index, SCALE_TIMES_1, disp);
+ } else {
+ set_modrm(0, ESP);
+ set_sib(scale, index, EBP);
+ set_dispr(disp);
+ }
+ }
+
+ // Returns true if this Operand is a wrapper for the specified register.
+ bool is_reg(Register reg) const {
+ return ((buf_[0] & 0xF8) == 0xC0) // addressing mode is register only.
+ && ((buf_[0] & 0x07) == reg); // register codes match.
+ }
+
+ void set_modrm(int mod, Register rm) { // reg == 0
+ ASSERT((mod & -4) == 0);
+ buf_[0] = mod << 6 | rm;
+ len_ = 1;
+ }
+
+ void set_sib(ScaleFactor scale, Register index, Register base) {
+ ASSERT(len_ == 1);
+ ASSERT((scale & -4) == 0);
+ buf_[1] = scale << 6 | index << 3 | base;
+ len_ = 2;
+ }
+
+ void set_disp8(char disp) {
+ ASSERT(len_ == 1 || len_ == 2);
+ *reinterpret_cast<char*>(&buf_[len_++]) = disp;
+ }
+
+ void set_dispr(int disp) {
+ ASSERT(len_ == 1 || len_ == 2);
+ *reinterpret_cast<int*>(&buf_[len_]) = disp;
+ len_ += sizeof(int);
+ }
+
+ bool is_int8(int x) { return x >= -128 && x <= 127; }
+
+ // Mutable because reg in ModR/M byte is set by Assembler via set_reg().
+ char buf_[6];
+ // The number of bytes in buf_.
+ unsigned int len_;
+};
+
+// A convenient wrapper around a buffer for emitting code or data, etc.
+class CodeBuffer {
+ public:
+ // Use an externally managed buffer
+ explicit CodeBuffer(char* buf) : pos_(0), buf_(buf) { }
+
+ void* data() { return buf_; }
+ int size() { return pos_; }
+
+ void emit(unsigned char b) {
+ buf_[pos_++] = b;
+ }
+ void emit_word(unsigned short w) {
+ *reinterpret_cast<unsigned short*>(&buf_[pos_]) = w;
+ pos_ += 2;
+ }
+ void emit_dword(unsigned int d) {
+ *reinterpret_cast<unsigned int*>(&buf_[pos_]) = d;
+ pos_ += 4;
+ }
+
+ void emit_bytes(const char* bytes, size_t size) {
+ for (size_t i = 0; i < size; ++i)
+ emit(bytes[i]);
+ }
+
+ void emit_bytes(const std::string& bytes) {
+ emit_bytes(bytes.data(), bytes.size());
+ }
+
+ void put_dword_at(int pos, unsigned int d) {
+ *reinterpret_cast<unsigned int*>(&buf_[pos]) = d;
+ }
+
+ // We pass by value so that we get a copy that we can modify.
+ void emit_operand(Register reg, Operand operand) {
+ operand.set_reg(reg);
+ memcpy(&buf_[pos_], operand.data(), operand.length());
+ pos_ += operand.length();
+ }
+
+ void bind(Label* l) {
+ ASSERT(!l->is_bound());
+ for (int i = 0; i < l->num_links(); ++i) {
+ put_dword_at(l->link_pos(i), pos_ - (l->link_pos(i) + 4));
+ }
+ l->bind_to(pos_);
+ }
+
+ // TODO deprecate blah_imm and use blah(Immediate)
+
+ void add(Register dst, Register src) {
+ emit(0x01); emit(0xc0 | (src << 3) | dst);
+ }
+ void add_imm(Register dst, int d) {
+ if (d >= -128 && d <= 127) {
+ emit(0x83); emit(0xc0 | dst); emit(d & 0xff);
+ } else {
+ emit(0x81); emit(0xc0 | dst); emit_dword(d);
+ }
+ }
+
+ void and_(Register r, unsigned int mask) {
+ emit(0x81); emit(0xe0 | r); emit_dword(mask);
+ }
+
+ void call(Register r) {
+ call(Operand(r));
+ }
+ void call(const Operand& dst) {
+ emit(0xff); emit_operand(EDX, dst);
+ }
+
+ void cmp(Register r1, Register r2) {
+ emit(0x39); emit(0xc0 | (r2 << 3) | r1);
+ }
+
+ void cmp_imm(Register r, int d) {
+ if (d >= -128 && d <= 127) {
+ emit(0x83); emit(0xf8 | r); emit(d & 0xff);
+ } else {
+ emit(0x81); emit(0xf8 | r); emit_dword(d);
+ }
+ }
+
+ void fs() {
+ emit(0x64);
+ }
+
+ // Atomically increment the dword at |mem| with the increment amount in the
+ // register |inc|. Will replace |inc| with the old unincremented value.
+ void inc_atomic(Register mem, Register inc) {
+ // lock xadd [mem], inc
+ emit(0xF0); emit(0x0F); emit(0xC1); emit((inc << 3) | mem);
+ }
+
+ void int3() {
+ emit(0xcc);
+ }
+
+ void jcc(Condition cc, Label* l) {
+ emit(0x0f); emit(0x80 | cc);
+ if (l->is_bound()) {
+ emit_dword(l->binding_pos() - (pos_ + 4));
+ } else {
+ // Will fix up when the label is bound.
+ l->link_to(pos_);
+ emit_dword(0);
+ }
+ }
+
+ void jmp(Register r) {
+ emit(0xff); emit(0xe0 | r);
+ }
+
+ void jmp(Label* l) {
+ if (l->is_bound()) {
+ jmp_rel(l->binding_pos() - (pos_ + 5));
+ } else {
+ // Will fix up when the label is bound.
+ l->link_to(pos_ + 1);
+ jmp_rel(0);
+ }
+ }
+
+ void jmp_rel(int i) {
+ emit(0xe9); emit_dword(i);
+ }
+
+ void jmp_rel_short(char c) {
+ emit(0xeb); emit(c);
+ }
+
+ void lea(Register dst, const Operand& src) {
+ emit(0x8d); emit_operand(dst, src);
+ }
+
+ void lodsb() {
+ emit(0xac);
+ }
+ void lodsd() {
+ emit(0xad);
+ }
+
+ void loop(Label* l) {
+ ASSERT(l->is_bound());
+ int pos = l->binding_pos() - (pos_ + 2);
+ ASSERT(pos >= -128 && pos < 0);
+
+ emit(0xe2); emit(pos & 0xff);
+ }
+
+ void mov(Register dst, Register src) {
+ emit(0x89); emit(0xc0 | (src << 3) | dst);
+ }
+ void mov(Register dst, const Operand& src) {
+ emit(0x8b); emit_operand(dst, src);
+ }
+ void mov_imm(Register r, unsigned int d) {
+ emit(0xb8 | r); emit_dword(d);
+ }
+
+ void movsb() {
+ emit(0xa4);
+ }
+ void movsd() {
+ emit(0xa5);
+ }
+
+ void or_(Register r, unsigned int mask) {
+ emit(0x81); emit(0xc8 | r); emit_dword(mask);
+ }
+
+ void pop(Register r) {
+ emit(0x58 | r);
+ }
+ void pop(const Operand& dst) {
+ emit(0x8f); emit_operand(EAX, dst);
+ }
+
+ void push(Register r) {
+ emit(0x50 | r);
+ }
+ void push(const Operand& src) {
+ emit(0xff); emit_operand(ESI, src);
+ }
+ void push_imm(int i) {
+ if (i >= -128 && i <= 127) {
+ emit(0x6a); emit(i & 0xff);
+ } else {
+ emit(0x68); emit_dword(i);
+ }
+ }
+
+ // cycle counter into edx:eax.
+ void rdtsc() {
+ emit(0x0F); emit(0x31);
+ }
+
+ void rep() {
+ emit(0xf3);
+ }
+
+ void ret() {
+ ret(0);
+ }
+ void ret(short c) {
+ if (c == 0) {
+ emit(0xc3);
+ } else {
+ emit(0xc2); emit_word(c);
+ }
+ }
+
+ void spin() {
+ jmp_rel_short(-2);
+ }
+
+ void stosb() {
+ emit(0xaa);
+ }
+ void stosd() {
+ emit(0xab);
+ }
+
+ void sysenter() {
+ emit(0x0f); emit(0x34);
+ }
+
+ // Puts a unique cpu identifier into eax, using sidt to fingerprint cores.
+ void which_cpu() {
+ // Make space
+ push(EAX);
+ push(EAX);
+ // sidt [esp+2]
+ emit(0x0f); emit(0x01); emit_operand(ECX, Operand(ESP, 2));
+ pop(EAX);
+ pop(EAX); // sidt address
+ }
+
+ // Return a unique identifier for the thread we're executing on.
+ void which_thread() {
+ // mov eax, [fs:0x24]
+ emit(0x64); emit(0xa1); emit_dword(0x24);
+ // TODO we could do this but it will use an encoding that is 1 byte bigger.
+ // fs(); mov(EAX, Operand(0x24));
+ }
+
+ void xchg(Register r1, Register r2) {
+ if (r1 == EAX) {
+ emit(0x90 | r2);
+ } else if (r2 == EAX) {
+ emit(0x90 | r1);
+ } else {
+ xchg(r1, Operand(r2));
+ }
+ }
+ void xchg(Register r1, const Operand& oper) {
+ emit(0x87); emit_operand(r1, oper);
+ }
+
+ private:
+ int pos_;
+ char* buf_;
+};
+
+#endif // TRACELINE_ASSEMBLER_H_
« no previous file with comments | « tools/traceline/traceline/README ('k') | tools/traceline/traceline/assembler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698