dart-sdk/runtime/vm/assembler_ia32.h
koda@google.com 600cd31660 Distinguish between initialization and updates to object fields. Currently only for DEBUG mode verification, but will be needed for deletion barrier.
Split up initialization flag in StoreInstanceFieldInstr for needed more precise semantics.

Zap swept old space with same value as uninitialized new in debug mode.

R=fschneider@google.com

Review URL: https://codereview.chromium.org//836593002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@42717 260f80e4-7a28-3924-810f-c04153c831b5
2015-01-08 20:45:39 +00:00

1028 lines
32 KiB
C++

// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef VM_ASSEMBLER_IA32_H_
#define VM_ASSEMBLER_IA32_H_
#ifndef VM_ASSEMBLER_H_
#error Do not include assembler_ia32.h directly; use assembler.h instead.
#endif
#include "platform/assert.h"
#include "platform/utils.h"
#include "vm/constants_ia32.h"
namespace dart {
// Forward declarations.
class RuntimeEntry;
class Immediate : public ValueObject {
public:
explicit Immediate(int32_t value) : value_(value) { }
Immediate(const Immediate& other) : ValueObject(), value_(other.value_) { }
int32_t value() const { return value_; }
bool is_int8() const { return Utils::IsInt(8, value_); }
bool is_uint8() const { return Utils::IsUint(8, value_); }
bool is_uint16() const { return Utils::IsUint(16, value_); }
private:
const int32_t value_;
// TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Immediate) once the mac
// build issue is resolved.
// And remove the unnecessary copy constructor.
};
class Operand : public ValueObject {
public:
uint8_t mod() const {
return (encoding_at(0) >> 6) & 3;
}
Register rm() const {
return static_cast<Register>(encoding_at(0) & 7);
}
ScaleFactor scale() const {
return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3);
}
Register index() const {
return static_cast<Register>((encoding_at(1) >> 3) & 7);
}
Register base() const {
return static_cast<Register>(encoding_at(1) & 7);
}
int8_t disp8() const {
ASSERT(length_ >= 2);
return static_cast<int8_t>(encoding_[length_ - 1]);
}
int32_t disp32() const {
ASSERT(length_ >= 5);
return bit_copy<int32_t>(encoding_[length_ - 4]);
}
Operand(const Operand& other) : ValueObject(), length_(other.length_) {
memmove(&encoding_[0], &other.encoding_[0], other.length_);
}
Operand& operator=(const Operand& other) {
length_ = other.length_;
memmove(&encoding_[0], &other.encoding_[0], other.length_);
return *this;
}
bool Equals(const Operand& other) const {
if (length_ != other.length_) return false;
for (uint8_t i = 0; i < length_; i++) {
if (encoding_[i] != other.encoding_[i]) return false;
}
return true;
}
protected:
Operand() : length_(0) { } // Needed by subclass Address.
void SetModRM(int mod, Register rm) {
ASSERT((mod & ~3) == 0);
encoding_[0] = (mod << 6) | rm;
length_ = 1;
}
void SetSIB(ScaleFactor scale, Register index, Register base) {
ASSERT(length_ == 1);
ASSERT((scale & ~3) == 0);
encoding_[1] = (scale << 6) | (index << 3) | base;
length_ = 2;
}
void SetDisp8(int8_t disp) {
ASSERT(length_ == 1 || length_ == 2);
encoding_[length_++] = static_cast<uint8_t>(disp);
}
void SetDisp32(int32_t disp) {
ASSERT(length_ == 1 || length_ == 2);
intptr_t disp_size = sizeof(disp);
memmove(&encoding_[length_], &disp, disp_size);
length_ += disp_size;
}
private:
uint8_t length_;
uint8_t encoding_[6];
uint8_t padding_;
explicit Operand(Register reg) { SetModRM(3, reg); }
// Get the operand encoding byte at the given index.
uint8_t encoding_at(intptr_t index) const {
ASSERT(index >= 0 && index < length_);
return encoding_[index];
}
// Returns whether or not this operand is really the given register in
// disguise. Used from the assembler to generate better encodings.
bool IsRegister(Register reg) const {
return ((encoding_[0] & 0xF8) == 0xC0) // Addressing mode is register only.
&& ((encoding_[0] & 0x07) == reg); // Register codes match.
}
friend class Assembler;
};
class Address : public Operand {
public:
Address(Register base, int32_t disp) {
if (disp == 0 && base != EBP) {
SetModRM(0, base);
if (base == ESP) SetSIB(TIMES_1, ESP, base);
} else if (Utils::IsInt(8, disp)) {
SetModRM(1, base);
if (base == ESP) SetSIB(TIMES_1, ESP, base);
SetDisp8(disp);
} else {
SetModRM(2, base);
if (base == ESP) SetSIB(TIMES_1, ESP, base);
SetDisp32(disp);
}
}
Address(Register index, ScaleFactor scale, int32_t disp) {
ASSERT(index != ESP); // Illegal addressing mode.
SetModRM(0, ESP);
SetSIB(scale, index, EBP);
SetDisp32(disp);
}
// This addressing mode does not exist.
Address(Register index, ScaleFactor scale, Register r);
Address(Register base, Register index, ScaleFactor scale, int32_t disp) {
ASSERT(index != ESP); // Illegal addressing mode.
if (disp == 0 && base != EBP) {
SetModRM(0, ESP);
SetSIB(scale, index, base);
} else if (Utils::IsInt(8, disp)) {
SetModRM(1, ESP);
SetSIB(scale, index, base);
SetDisp8(disp);
} else {
SetModRM(2, ESP);
SetSIB(scale, index, base);
SetDisp32(disp);
}
}
// This addressing mode does not exist.
Address(Register base, Register index, ScaleFactor scale, Register r);
Address(const Address& other) : Operand(other) { }
Address& operator=(const Address& other) {
Operand::operator=(other);
return *this;
}
static Address Absolute(const uword addr) {
Address result;
result.SetModRM(0, EBP);
result.SetDisp32(addr);
return result;
}
private:
Address() { } // Needed by Address::Absolute.
};
class FieldAddress : public Address {
public:
FieldAddress(Register base, int32_t disp)
: Address(base, disp - kHeapObjectTag) { }
// This addressing mode does not exist.
FieldAddress(Register base, Register r);
FieldAddress(Register base, Register index, ScaleFactor scale, int32_t disp)
: Address(base, index, scale, disp - kHeapObjectTag) { }
// This addressing mode does not exist.
FieldAddress(Register base, Register index, ScaleFactor scale, Register r);
FieldAddress(const FieldAddress& other) : Address(other) { }
FieldAddress& operator=(const FieldAddress& other) {
Address::operator=(other);
return *this;
}
};
class Label : public ValueObject {
public:
Label() : position_(0), unresolved_(0) {
#ifdef DEBUG
for (int i = 0; i < kMaxUnresolvedBranches; i++) {
unresolved_near_positions_[i] = -1;
}
#endif // DEBUG
}
~Label() {
// Assert if label is being destroyed with unresolved branches pending.
ASSERT(!IsLinked());
ASSERT(!HasNear());
}
// Returns the position for bound labels. Cannot be used for unused or linked
// labels.
intptr_t Position() const {
ASSERT(IsBound());
return -position_ - kWordSize;
}
intptr_t LinkPosition() const {
ASSERT(IsLinked());
return position_ - kWordSize;
}
intptr_t NearPosition() {
ASSERT(HasNear());
return unresolved_near_positions_[--unresolved_];
}
bool IsBound() const { return position_ < 0; }
bool IsUnused() const { return (position_ == 0) && (unresolved_ == 0); }
bool IsLinked() const { return position_ > 0; }
bool HasNear() const { return unresolved_ != 0; }
private:
void BindTo(intptr_t position) {
ASSERT(!IsBound());
ASSERT(!HasNear());
position_ = -position - kWordSize;
ASSERT(IsBound());
}
void LinkTo(intptr_t position) {
ASSERT(!IsBound());
position_ = position + kWordSize;
ASSERT(IsLinked());
}
void NearLinkTo(intptr_t position) {
ASSERT(!IsBound());
ASSERT(unresolved_ < kMaxUnresolvedBranches);
unresolved_near_positions_[unresolved_++] = position;
}
static const int kMaxUnresolvedBranches = 20;
intptr_t position_;
intptr_t unresolved_;
intptr_t unresolved_near_positions_[kMaxUnresolvedBranches];
friend class Assembler;
DISALLOW_COPY_AND_ASSIGN(Label);
};
class Assembler : public ValueObject {
public:
explicit Assembler(bool use_far_branches = false)
: buffer_(),
object_pool_(GrowableObjectArray::Handle()),
prologue_offset_(-1),
jit_cookie_(0),
comments_() {
// This mode is only needed and implemented for MIPS and ARM.
ASSERT(!use_far_branches);
}
~Assembler() { }
static const bool kNearJump = true;
static const bool kFarJump = false;
/*
* Emit Machine Instructions.
*/
void call(Register reg);
void call(const Address& address);
void call(Label* label);
void call(const ExternalLabel* label);
static const intptr_t kCallExternalLabelSize = 5;
void pushl(Register reg);
void pushl(const Address& address);
void pushl(const Immediate& imm);
void popl(Register reg);
void popl(const Address& address);
void pushal();
void popal();
void setcc(Condition condition, ByteRegister dst);
void movl(Register dst, const Immediate& src);
void movl(Register dst, Register src);
void movl(Register dst, const Address& src);
void movl(const Address& dst, Register src);
void movl(const Address& dst, const Immediate& imm);
void movzxb(Register dst, ByteRegister src);
void movzxb(Register dst, const Address& src);
void movsxb(Register dst, ByteRegister src);
void movsxb(Register dst, const Address& src);
void movb(Register dst, const Address& src);
void movb(const Address& dst, ByteRegister src);
void movb(const Address& dst, const Immediate& imm);
void movzxw(Register dst, Register src);
void movzxw(Register dst, const Address& src);
void movsxw(Register dst, Register src);
void movsxw(Register dst, const Address& src);
void movw(Register dst, const Address& src);
void movw(const Address& dst, Register src);
void leal(Register dst, const Address& src);
void cmovno(Register dst, Register src);
void cmove(Register dst, Register src);
void cmovne(Register dst, Register src);
void cmovs(Register dst, Register src);
void cmovns(Register dst, Register src);
void cmovgel(Register dst, Register src);
void cmovlessl(Register dst, Register src);
void rep_movsb();
void movss(XmmRegister dst, const Address& src);
void movss(const Address& dst, XmmRegister src);
void movss(XmmRegister dst, XmmRegister src);
void movd(XmmRegister dst, Register src);
void movd(Register dst, XmmRegister src);
void movq(const Address& dst, XmmRegister src);
void movq(XmmRegister dst, const Address& src);
void addss(XmmRegister dst, XmmRegister src);
void addss(XmmRegister dst, const Address& src);
void subss(XmmRegister dst, XmmRegister src);
void subss(XmmRegister dst, const Address& src);
void mulss(XmmRegister dst, XmmRegister src);
void mulss(XmmRegister dst, const Address& src);
void divss(XmmRegister dst, XmmRegister src);
void divss(XmmRegister dst, const Address& src);
void movsd(XmmRegister dst, const Address& src);
void movsd(const Address& dst, XmmRegister src);
void movsd(XmmRegister dst, XmmRegister src);
void movaps(XmmRegister dst, XmmRegister src);
void movups(XmmRegister dst, const Address& src);
void movups(const Address& dst, XmmRegister src);
void addsd(XmmRegister dst, XmmRegister src);
void addsd(XmmRegister dst, const Address& src);
void subsd(XmmRegister dst, XmmRegister src);
void subsd(XmmRegister dst, const Address& src);
void mulsd(XmmRegister dst, XmmRegister src);
void mulsd(XmmRegister dst, const Address& src);
void divsd(XmmRegister dst, XmmRegister src);
void divsd(XmmRegister dst, const Address& src);
void addpl(XmmRegister dst, XmmRegister src);
void subpl(XmmRegister dst, XmmRegister src);
void addps(XmmRegister dst, XmmRegister src);
void subps(XmmRegister dst, XmmRegister src);
void divps(XmmRegister dst, XmmRegister src);
void mulps(XmmRegister dst, XmmRegister src);
void minps(XmmRegister dst, XmmRegister src);
void maxps(XmmRegister dst, XmmRegister src);
void andps(XmmRegister dst, XmmRegister src);
void andps(XmmRegister dst, const Address& src);
void orps(XmmRegister dst, XmmRegister src);
void notps(XmmRegister dst);
void negateps(XmmRegister dst);
void absps(XmmRegister dst);
void zerowps(XmmRegister dst);
void cmppseq(XmmRegister dst, XmmRegister src);
void cmppsneq(XmmRegister dst, XmmRegister src);
void cmppslt(XmmRegister dst, XmmRegister src);
void cmppsle(XmmRegister dst, XmmRegister src);
void cmppsnlt(XmmRegister dst, XmmRegister src);
void cmppsnle(XmmRegister dst, XmmRegister src);
void sqrtps(XmmRegister dst);
void rsqrtps(XmmRegister dst);
void reciprocalps(XmmRegister dst);
void movhlps(XmmRegister dst, XmmRegister src);
void movlhps(XmmRegister dst, XmmRegister src);
void unpcklps(XmmRegister dst, XmmRegister src);
void unpckhps(XmmRegister dst, XmmRegister src);
void unpcklpd(XmmRegister dst, XmmRegister src);
void unpckhpd(XmmRegister dst, XmmRegister src);
void set1ps(XmmRegister dst, Register tmp, const Immediate& imm);
void shufps(XmmRegister dst, XmmRegister src, const Immediate& mask);
void addpd(XmmRegister dst, XmmRegister src);
void negatepd(XmmRegister dst);
void subpd(XmmRegister dst, XmmRegister src);
void mulpd(XmmRegister dst, XmmRegister src);
void divpd(XmmRegister dst, XmmRegister src);
void abspd(XmmRegister dst);
void minpd(XmmRegister dst, XmmRegister src);
void maxpd(XmmRegister dst, XmmRegister src);
void sqrtpd(XmmRegister dst);
void cvtps2pd(XmmRegister dst, XmmRegister src);
void cvtpd2ps(XmmRegister dst, XmmRegister src);
void shufpd(XmmRegister dst, XmmRegister src, const Immediate& mask);
void cvtsi2ss(XmmRegister dst, Register src);
void cvtsi2sd(XmmRegister dst, Register src);
void cvtss2si(Register dst, XmmRegister src);
void cvtss2sd(XmmRegister dst, XmmRegister src);
void cvtsd2si(Register dst, XmmRegister src);
void cvtsd2ss(XmmRegister dst, XmmRegister src);
void cvttss2si(Register dst, XmmRegister src);
void cvttsd2si(Register dst, XmmRegister src);
void cvtdq2pd(XmmRegister dst, XmmRegister src);
void comiss(XmmRegister a, XmmRegister b);
void comisd(XmmRegister a, XmmRegister b);
void movmskpd(Register dst, XmmRegister src);
void movmskps(Register dst, XmmRegister src);
void sqrtsd(XmmRegister dst, XmmRegister src);
void sqrtss(XmmRegister dst, XmmRegister src);
void xorpd(XmmRegister dst, const Address& src);
void xorpd(XmmRegister dst, XmmRegister src);
void xorps(XmmRegister dst, const Address& src);
void xorps(XmmRegister dst, XmmRegister src);
void andpd(XmmRegister dst, const Address& src);
void andpd(XmmRegister dst, XmmRegister src);
void orpd(XmmRegister dst, XmmRegister src);
void pextrd(Register dst, XmmRegister src, const Immediate& imm);
void pmovsxdq(XmmRegister dst, XmmRegister src);
void pcmpeqq(XmmRegister dst, XmmRegister src);
void pxor(XmmRegister dst, XmmRegister src);
enum RoundingMode {
kRoundToNearest = 0x0,
kRoundDown = 0x1,
kRoundUp = 0x2,
kRoundToZero = 0x3
};
void roundsd(XmmRegister dst, XmmRegister src, RoundingMode mode);
void flds(const Address& src);
void fstps(const Address& dst);
void fldl(const Address& src);
void fstpl(const Address& dst);
void fnstcw(const Address& dst);
void fldcw(const Address& src);
void fistpl(const Address& dst);
void fistps(const Address& dst);
void fildl(const Address& src);
void filds(const Address& src);
void fincstp();
void ffree(intptr_t value);
void fsin();
void fcos();
void fsincos();
void fptan();
void xchgl(Register dst, Register src);
void cmpl(Register reg, const Immediate& imm);
void cmpl(Register reg0, Register reg1);
void cmpl(Register reg, const Address& address);
void cmpl(const Address& address, Register reg);
void cmpl(const Address& address, const Immediate& imm);
void cmpb(const Address& address, const Immediate& imm);
void testl(Register reg1, Register reg2);
void testl(Register reg, const Immediate& imm);
void testb(const Address& address, const Immediate& imm);
void andl(Register dst, const Immediate& imm);
void andl(Register dst, Register src);
void andl(Register dst, const Address& address);
void orl(Register dst, const Immediate& imm);
void orl(Register dst, Register src);
void orl(Register dst, const Address& address);
void orl(const Address& address, Register dst);
void xorl(Register dst, const Immediate& imm);
void xorl(Register dst, Register src);
void xorl(Register dst, const Address& address);
void addl(Register dst, Register src);
void addl(Register reg, const Immediate& imm);
void addl(Register reg, const Address& address);
void addl(const Address& address, Register reg);
void addl(const Address& address, const Immediate& imm);
void adcl(Register dst, Register src);
void adcl(Register reg, const Immediate& imm);
void adcl(Register dst, const Address& address);
void adcl(const Address& dst, Register src);
void subl(Register dst, Register src);
void subl(Register reg, const Immediate& imm);
void subl(Register reg, const Address& address);
void subl(const Address& address, Register reg);
void cdq();
void idivl(Register reg);
void divl(Register reg);
void imull(Register dst, Register src);
void imull(Register reg, const Immediate& imm);
void imull(Register reg, const Address& address);
void imull(Register reg);
void imull(const Address& address);
void mull(Register reg);
void mull(const Address& address);
void sbbl(Register dst, Register src);
void sbbl(Register reg, const Immediate& imm);
void sbbl(Register reg, const Address& address);
void sbbl(const Address& address, Register reg);
void incl(Register reg);
void incl(const Address& address);
void decl(Register reg);
void decl(const Address& address);
void shll(Register reg, const Immediate& imm);
void shll(Register operand, Register shifter);
void shll(const Address& operand, Register shifter);
void shrl(Register reg, const Immediate& imm);
void shrl(Register operand, Register shifter);
void sarl(Register reg, const Immediate& imm);
void sarl(Register operand, Register shifter);
void sarl(const Address& address, Register shifter);
void shldl(Register dst, Register src);
void shldl(Register dst, Register src, const Immediate& imm);
void shldl(const Address& operand, Register src);
void shrdl(Register dst, Register src);
void shrdl(Register dst, Register src, const Immediate& imm);
void shrdl(const Address& dst, Register src);
void negl(Register reg);
void notl(Register reg);
void bsrl(Register dst, Register src);
void bt(Register base, Register offset);
void enter(const Immediate& imm);
void leave();
void ret();
void ret(const Immediate& imm);
// 'size' indicates size in bytes and must be in the range 1..8.
void nop(int size = 1);
void int3();
void hlt();
// Note: verified_mem mode forces far jumps.
void j(Condition condition, Label* label, bool near = kFarJump);
void j(Condition condition, const ExternalLabel* label);
void jmp(Register reg);
// Note: verified_mem mode forces far jumps.
void jmp(Label* label, bool near = kFarJump);
void jmp(const ExternalLabel* label);
void lock();
void cmpxchgl(const Address& address, Register reg);
void cpuid();
/*
* Macros for High-level operations and implemented on all architectures.
*/
void CompareRegisters(Register a, Register b);
// Issues a move instruction if 'to' is not the same as 'from'.
void MoveRegister(Register to, Register from);
void PopRegister(Register r);
void AddImmediate(Register reg, const Immediate& imm);
void SubImmediate(Register reg, const Immediate& imm);
void Drop(intptr_t stack_elements);
void LoadIsolate(Register dst);
void LoadObject(Register dst, const Object& object);
// If 'object' is a large Smi, xor it with a per-assembler cookie value to
// prevent user-controlled immediates from appearing in the code stream.
void LoadObjectSafely(Register dst, const Object& object);
void PushObject(const Object& object);
void CompareObject(Register reg, const Object& object);
void LoadDoubleConstant(XmmRegister dst, double value);
// When storing into a heap object field, knowledge of the previous content
// is expressed through these constants.
enum FieldContent {
kEmptyOrSmiOrNull, // Empty = garbage/zapped in release/debug mode.
kHeapObjectOrSmi,
kOnlySmi,
};
void StoreIntoObject(Register object, // Object we are storing into.
const Address& dest, // Where we are storing into.
Register value, // Value we are storing.
bool can_value_be_smi = true);
void StoreIntoObjectNoBarrier(Register object,
const Address& dest,
Register value,
FieldContent old_content = kHeapObjectOrSmi);
void InitializeFieldNoBarrier(Register object,
const Address& dest,
Register value) {
return StoreIntoObjectNoBarrier(object, dest, value, kEmptyOrSmiOrNull);
}
void StoreIntoObjectNoBarrier(Register object,
const Address& dest,
const Object& value,
FieldContent old_content = kHeapObjectOrSmi);
void InitializeFieldNoBarrier(Register object,
const Address& dest,
const Object& value) {
return StoreIntoObjectNoBarrier(object, dest, value, kEmptyOrSmiOrNull);
}
// Stores a Smi value into a heap object field that always contains a Smi.
void StoreIntoSmiField(const Address& dest, Register value);
void ZeroInitSmiField(const Address& dest);
// Increments a Smi field. Leaves flags in same state as an 'addl'.
void IncrementSmiField(const Address& dest, int32_t increment);
void DoubleNegate(XmmRegister d);
void FloatNegate(XmmRegister f);
void DoubleAbs(XmmRegister reg);
void LockCmpxchgl(const Address& address, Register reg) {
lock();
cmpxchgl(address, reg);
}
void EnterFrame(intptr_t frame_space);
void LeaveFrame();
void ReserveAlignedFrameSpace(intptr_t frame_space);
// Create a frame for calling into runtime that preserves all volatile
// registers. Frame's RSP is guaranteed to be correctly aligned and
// frame_space bytes are reserved under it.
void EnterCallRuntimeFrame(intptr_t frame_space);
void LeaveCallRuntimeFrame();
void CallRuntime(const RuntimeEntry& entry, intptr_t argument_count);
/*
* Loading and comparing classes of objects.
*/
void LoadClassId(Register result, Register object);
void LoadClassById(Register result, Register class_id);
void LoadClass(Register result, Register object, Register scratch);
void CompareClassId(Register object, intptr_t class_id, Register scratch);
void LoadTaggedClassIdMayBeSmi(Register result,
Register object);
void SmiUntagOrCheckClass(Register object,
intptr_t class_id,
Register scratch,
Label* is_smi);
void ComputeRange(Register result,
Register value,
Register lo_temp,
Register hi_temp,
Label* miss);
void UpdateRangeFeedback(Register value,
intptr_t index,
Register ic_data,
Register scratch1,
Register scratch2,
Register scratch3,
Label* miss);
static Address ElementAddressForIntIndex(bool is_external,
intptr_t cid,
intptr_t index_scale,
Register array,
intptr_t index);
static Address ElementAddressForRegIndex(bool is_external,
intptr_t cid,
intptr_t index_scale,
Register array,
Register index);
/*
* Misc. functionality
*/
void SmiTag(Register reg) {
addl(reg, reg);
}
void SmiUntag(Register reg) {
sarl(reg, Immediate(kSmiTagSize));
}
intptr_t PreferredLoopAlignment() { return 16; }
void Align(intptr_t alignment, intptr_t offset);
void Bind(Label* label);
void Jump(Label* label) { jmp(label); }
intptr_t CodeSize() const { return buffer_.Size(); }
intptr_t prologue_offset() const { return prologue_offset_; }
// Count the fixups that produce a pointer offset, without processing
// the fixups.
intptr_t CountPointerOffsets() const {
return buffer_.CountPointerOffsets();
}
const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const {
return buffer_.pointer_offsets();
}
const GrowableObjectArray& object_pool() const { return object_pool_; }
void FinalizeInstructions(const MemoryRegion& region) {
buffer_.FinalizeInstructions(region);
}
// Set up a Dart frame on entry with a frame pointer and PC information to
// enable easy access to the RawInstruction object of code corresponding
// to this frame.
// The dart frame layout is as follows:
// ....
// ret PC
// saved EBP <=== EBP
// pc (used to derive the RawInstruction Object of the dart code)
// locals space <=== ESP
// .....
// This code sets this up with the sequence:
// pushl ebp
// movl ebp, esp
// call L
// L: <code to adjust saved pc if there is any intrinsification code>
// .....
void EnterDartFrame(intptr_t frame_size);
// Set up a Dart frame for a function compiled for on-stack replacement.
// The frame layout is a normal Dart frame, but the frame is partially set
// up on entry (it is the frame of the unoptimized code).
void EnterOsrFrame(intptr_t extra_size);
// Set up a stub frame so that the stack traversal code can easily identify
// a stub frame.
// The stub frame layout is as follows:
// ....
// ret PC
// saved EBP
// 0 (used to indicate frame is a stub frame)
// .....
// This code sets this up with the sequence:
// pushl ebp
// movl ebp, esp
// pushl immediate(0)
// .....
void EnterStubFrame();
// Instruction pattern from entrypoint is used in dart frame prologs
// to set up the frame and save a PC which can be used to figure out the
// RawInstruction object corresponding to the code running in the frame.
// entrypoint:
// pushl ebp (size is 1 byte)
// movl ebp, esp (size is 2 bytes)
// call L (size is 5 bytes)
// L:
static const intptr_t kEntryPointToPcMarkerOffset = 8;
static intptr_t EntryPointToPcMarkerOffset() {
return kEntryPointToPcMarkerOffset;
}
void UpdateAllocationStats(intptr_t cid,
Register temp_reg,
Heap::Space space);
void UpdateAllocationStatsWithSize(intptr_t cid,
Register size_reg,
Register temp_reg,
Heap::Space space);
void UpdateAllocationStatsWithSize(intptr_t cid,
intptr_t instance_size,
Register temp_reg,
Heap::Space space);
// Inlined allocation of an instance of class 'cls', code has no runtime
// calls. Jump to 'failure' if the instance cannot be allocated here.
// Allocated instance is returned in 'instance_reg'.
// Only the tags field of the object is initialized.
void TryAllocate(const Class& cls,
Label* failure,
bool near_jump,
Register instance_reg,
Register temp_reg);
void TryAllocateArray(intptr_t cid,
intptr_t instance_size,
Label* failure,
bool near_jump,
Register instance,
Register end_address);
// Debugging and bringup support.
void Stop(const char* message);
void Unimplemented(const char* message);
void Untested(const char* message);
void Unreachable(const char* message);
static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
static bool EmittingComments();
const Code::Comments& GetCodeComments() const;
static const char* RegisterName(Register reg);
static const char* FpuRegisterName(FpuRegister reg);
// Smis that do not fit into 17 bits (16 bits of payload) are unsafe.
static bool IsSafeSmi(const Object& object) {
if (!object.IsSmi()) {
return false;
}
if (Utils::IsInt(17, reinterpret_cast<intptr_t>(object.raw()))) {
return true;
}
// Single bit smis (powers of two) and corresponding masks are safe.
const intptr_t value = Smi::Cast(object).Value();
if (Utils::IsPowerOfTwo(value) || Utils::IsPowerOfTwo(value + 1)) {
return true;
}
return false;
}
static bool IsSafe(const Object& object) {
return !object.IsSmi() || IsSafeSmi(object);
}
private:
class CodeComment : public ZoneAllocated {
public:
CodeComment(intptr_t pc_offset, const String& comment)
: pc_offset_(pc_offset), comment_(comment) { }
intptr_t pc_offset() const { return pc_offset_; }
const String& comment() const { return comment_; }
private:
intptr_t pc_offset_;
const String& comment_;
DISALLOW_COPY_AND_ASSIGN(CodeComment);
};
inline void EmitUint8(uint8_t value);
inline void EmitInt32(int32_t value);
inline void EmitRegisterOperand(int rm, int reg);
inline void EmitXmmRegisterOperand(int rm, XmmRegister reg);
inline void EmitFixup(AssemblerFixup* fixup);
inline void EmitOperandSizeOverride();
void EmitOperand(int rm, const Operand& operand);
void EmitImmediate(const Immediate& imm);
void EmitComplex(int rm, const Operand& operand, const Immediate& immediate);
void EmitLabel(Label* label, intptr_t instruction_size);
void EmitLabelLink(Label* label);
void EmitNearLabelLink(Label* label);
void EmitGenericShift(int rm, Register reg, const Immediate& imm);
void EmitGenericShift(int rm, const Operand& operand, Register shifter);
void StoreIntoObjectFilter(Register object, Register value, Label* no_update);
// Shorter filtering sequence that assumes that value is not a smi.
void StoreIntoObjectFilterNoSmi(Register object,
Register value,
Label* no_update);
#if defined(DEBUG)
void VerifyUninitialized(const Address& address);
void VerifyObjectOrSmi(const Address& address);
void VerifySmi(const Address& address, const char* stop_msg = "Expected Smi");
#endif // DEBUG
// Like VerifiedMemory::Verify(address, kWordSize) and ::Write, but also,
// in DEBUG mode, verifies that 'address' has content of type 'old_content'.
void VerifyHeapWord(const Address& address, FieldContent old_content);
void VerifiedWrite(const Address& dest,
Register value,
FieldContent old_content);
void UnverifiedStoreOldObject(const Address& dest, const Object& value);
int32_t jit_cookie();
AssemblerBuffer buffer_;
GrowableObjectArray& object_pool_; // Object pool is not used on ia32.
intptr_t prologue_offset_;
int32_t jit_cookie_;
GrowableArray<CodeComment*> comments_;
DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(Assembler);
};
inline void Assembler::EmitUint8(uint8_t value) {
buffer_.Emit<uint8_t>(value);
}
inline void Assembler::EmitInt32(int32_t value) {
buffer_.Emit<int32_t>(value);
}
inline void Assembler::EmitRegisterOperand(int rm, int reg) {
ASSERT(rm >= 0 && rm < 8);
buffer_.Emit<uint8_t>(0xC0 + (rm << 3) + reg);
}
inline void Assembler::EmitXmmRegisterOperand(int rm, XmmRegister reg) {
EmitRegisterOperand(rm, static_cast<Register>(reg));
}
inline void Assembler::EmitFixup(AssemblerFixup* fixup) {
buffer_.EmitFixup(fixup);
}
inline void Assembler::EmitOperandSizeOverride() {
EmitUint8(0x66);
}
} // namespace dart
#endif // VM_ASSEMBLER_IA32_H_