1// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// All Rights Reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// - Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10//
11// - Redistribution in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the distribution.
14//
15// - Neither the name of Sun Microsystems or the names of contributors may
16// be used to endorse or promote products derived from this software without
17// specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// The original source code covered by the above license above has been
32// modified significantly by Google Inc.
33// Copyright 2006-2008 the V8 project authors. All rights reserved.
34
35// A light-weight IA32 Assembler.
36
37#ifndef V8_IA32_ASSEMBLER_IA32_INL_H_
38#define V8_IA32_ASSEMBLER_IA32_INL_H_
39
40#include "cpu.h"
41
42namespace v8 {
43namespace internal {
44
45Condition NegateCondition(Condition cc) {
46  return static_cast<Condition>(cc ^ 1);
47}
48
49
50// The modes possibly affected by apply must be in kApplyMask.
51void RelocInfo::apply(intptr_t delta) {
52  if (rmode_ == RUNTIME_ENTRY || IsCodeTarget(rmode_)) {
53    int32_t* p = reinterpret_cast<int32_t*>(pc_);
54    *p -= delta;  // relocate entry
55  } else if (rmode_ == JS_RETURN && IsPatchedReturnSequence()) {
56    // Special handling of js_return when a break point is set (call
57    // instruction has been inserted).
58    int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
59    *p -= delta;  // relocate entry
60  } else if (IsInternalReference(rmode_)) {
61    // absolute code pointer inside code object moves with the code object.
62    int32_t* p = reinterpret_cast<int32_t*>(pc_);
63    *p += delta;  // relocate entry
64  }
65}
66
67
68Address RelocInfo::target_address() {
69  ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
70  return Assembler::target_address_at(pc_);
71}
72
73
74Address RelocInfo::target_address_address() {
75  ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
76  return reinterpret_cast<Address>(pc_);
77}
78
79
80void RelocInfo::set_target_address(Address target) {
81  ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
82  Assembler::set_target_address_at(pc_, target);
83}
84
85
86Object* RelocInfo::target_object() {
87  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
88  return Memory::Object_at(pc_);
89}
90
91
92Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
93  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
94  return Memory::Object_Handle_at(pc_);
95}
96
97
98Object** RelocInfo::target_object_address() {
99  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
100  return &Memory::Object_at(pc_);
101}
102
103
104void RelocInfo::set_target_object(Object* target) {
105  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
106  Memory::Object_at(pc_) = target;
107}
108
109
110Address* RelocInfo::target_reference_address() {
111  ASSERT(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
112  return reinterpret_cast<Address*>(pc_);
113}
114
115
116Address RelocInfo::call_address() {
117  ASSERT(IsPatchedReturnSequence());
118  return Assembler::target_address_at(pc_ + 1);
119}
120
121
122void RelocInfo::set_call_address(Address target) {
123  ASSERT(IsPatchedReturnSequence());
124  Assembler::set_target_address_at(pc_ + 1, target);
125}
126
127
128Object* RelocInfo::call_object() {
129  ASSERT(IsPatchedReturnSequence());
130  return *call_object_address();
131}
132
133
134Object** RelocInfo::call_object_address() {
135  ASSERT(IsPatchedReturnSequence());
136  return reinterpret_cast<Object**>(pc_ + 1);
137}
138
139
140void RelocInfo::set_call_object(Object* target) {
141  ASSERT(IsPatchedReturnSequence());
142  *call_object_address() = target;
143}
144
145
146bool RelocInfo::IsPatchedReturnSequence() {
147  return *pc_ == 0xE8;
148}
149
150
151Immediate::Immediate(int x)  {
152  x_ = x;
153  rmode_ = RelocInfo::NONE;
154}
155
156
157Immediate::Immediate(const ExternalReference& ext) {
158  x_ = reinterpret_cast<int32_t>(ext.address());
159  rmode_ = RelocInfo::EXTERNAL_REFERENCE;
160}
161
162Immediate::Immediate(const char* s) {
163  x_ = reinterpret_cast<int32_t>(s);
164  rmode_ = RelocInfo::EMBEDDED_STRING;
165}
166
167
168Immediate::Immediate(Label* internal_offset) {
169  x_ = reinterpret_cast<int32_t>(internal_offset);
170  rmode_ = RelocInfo::INTERNAL_REFERENCE;
171}
172
173
174Immediate::Immediate(Handle<Object> handle) {
175  // Verify all Objects referred by code are NOT in new space.
176  Object* obj = *handle;
177  ASSERT(!Heap::InNewSpace(obj));
178  if (obj->IsHeapObject()) {
179    x_ = reinterpret_cast<intptr_t>(handle.location());
180    rmode_ = RelocInfo::EMBEDDED_OBJECT;
181  } else {
182    // no relocation needed
183    x_ =  reinterpret_cast<intptr_t>(obj);
184    rmode_ = RelocInfo::NONE;
185  }
186}
187
188
189Immediate::Immediate(Smi* value) {
190  x_ = reinterpret_cast<intptr_t>(value);
191  rmode_ = RelocInfo::NONE;
192}
193
194
195void Assembler::emit(uint32_t x) {
196  *reinterpret_cast<uint32_t*>(pc_) = x;
197  pc_ += sizeof(uint32_t);
198}
199
200
201void Assembler::emit(Handle<Object> handle) {
202  // Verify all Objects referred by code are NOT in new space.
203  Object* obj = *handle;
204  ASSERT(!Heap::InNewSpace(obj));
205  if (obj->IsHeapObject()) {
206    emit(reinterpret_cast<intptr_t>(handle.location()),
207         RelocInfo::EMBEDDED_OBJECT);
208  } else {
209    // no relocation needed
210    emit(reinterpret_cast<intptr_t>(obj));
211  }
212}
213
214
215void Assembler::emit(uint32_t x, RelocInfo::Mode rmode) {
216  if (rmode != RelocInfo::NONE) RecordRelocInfo(rmode);
217  emit(x);
218}
219
220
221void Assembler::emit(const Immediate& x) {
222  if (x.rmode_ == RelocInfo::INTERNAL_REFERENCE) {
223    Label* label = reinterpret_cast<Label*>(x.x_);
224    emit_code_relative_offset(label);
225    return;
226  }
227  if (x.rmode_ != RelocInfo::NONE) RecordRelocInfo(x.rmode_);
228  emit(x.x_);
229}
230
231
232void Assembler::emit_code_relative_offset(Label* label) {
233  if (label->is_bound()) {
234    int32_t pos;
235    pos = label->pos() + Code::kHeaderSize - kHeapObjectTag;
236    emit(pos);
237  } else {
238    emit_disp(label, Displacement::CODE_RELATIVE);
239  }
240}
241
242
243void Assembler::emit_w(const Immediate& x) {
244  ASSERT(x.rmode_ == RelocInfo::NONE);
245  uint16_t value = static_cast<uint16_t>(x.x_);
246  reinterpret_cast<uint16_t*>(pc_)[0] = value;
247  pc_ += sizeof(uint16_t);
248}
249
250
251Address Assembler::target_address_at(Address pc) {
252  return pc + sizeof(int32_t) + *reinterpret_cast<int32_t*>(pc);
253}
254
255
256void Assembler::set_target_address_at(Address pc, Address target) {
257  int32_t* p = reinterpret_cast<int32_t*>(pc);
258  *p = target - (pc + sizeof(int32_t));
259  CPU::FlushICache(p, sizeof(int32_t));
260}
261
262
263Displacement Assembler::disp_at(Label* L) {
264  return Displacement(long_at(L->pos()));
265}
266
267
268void Assembler::disp_at_put(Label* L, Displacement disp) {
269  long_at_put(L->pos(), disp.data());
270}
271
272
273void Assembler::emit_disp(Label* L, Displacement::Type type) {
274  Displacement disp(L, type);
275  L->link_to(pc_offset());
276  emit(static_cast<int>(disp.data()));
277}
278
279
280void Operand::set_modrm(int mod, Register rm) {
281  ASSERT((mod & -4) == 0);
282  buf_[0] = mod << 6 | rm.code();
283  len_ = 1;
284}
285
286
287void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
288  ASSERT(len_ == 1);
289  ASSERT((scale & -4) == 0);
290  // Use SIB with no index register only for base esp.
291  ASSERT(!index.is(esp) || base.is(esp));
292  buf_[1] = scale << 6 | index.code() << 3 | base.code();
293  len_ = 2;
294}
295
296
297void Operand::set_disp8(int8_t disp) {
298  ASSERT(len_ == 1 || len_ == 2);
299  *reinterpret_cast<int8_t*>(&buf_[len_++]) = disp;
300}
301
302
303void Operand::set_dispr(int32_t disp, RelocInfo::Mode rmode) {
304  ASSERT(len_ == 1 || len_ == 2);
305  int32_t* p = reinterpret_cast<int32_t*>(&buf_[len_]);
306  *p = disp;
307  len_ += sizeof(int32_t);
308  rmode_ = rmode;
309}
310
311Operand::Operand(Register reg) {
312  // reg
313  set_modrm(3, reg);
314}
315
316
317Operand::Operand(int32_t disp, RelocInfo::Mode rmode) {
318  // [disp/r]
319  set_modrm(0, ebp);
320  set_dispr(disp, rmode);
321}
322
323} }  // namespace v8::internal
324
325#endif  // V8_IA32_ASSEMBLER_IA32_INL_H_
326