assembler-ia32-inl.h revision c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9
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 2012 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 "ia32/assembler-ia32.h"
41
42#include "cpu.h"
43#include "debug.h"
44
45namespace v8 {
46namespace internal {
47
48
49// The modes possibly affected by apply must be in kApplyMask.
50void RelocInfo::apply(intptr_t delta) {
51  if (rmode_ == RUNTIME_ENTRY || IsCodeTarget(rmode_)) {
52    int32_t* p = reinterpret_cast<int32_t*>(pc_);
53    *p -= delta;  // Relocate entry.
54    CPU::FlushICache(p, sizeof(uint32_t));
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    CPU::FlushICache(p, sizeof(uint32_t));
61  } else if (rmode_ == DEBUG_BREAK_SLOT && IsPatchedDebugBreakSlotSequence()) {
62    // Special handling of a debug break slot when a break point is set (call
63    // instruction has been inserted).
64    int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
65    *p -= delta;  // Relocate entry.
66    CPU::FlushICache(p, sizeof(uint32_t));
67  } else if (IsInternalReference(rmode_)) {
68    // absolute code pointer inside code object moves with the code object.
69    int32_t* p = reinterpret_cast<int32_t*>(pc_);
70    *p += delta;  // Relocate entry.
71    CPU::FlushICache(p, sizeof(uint32_t));
72  }
73}
74
75
76Address RelocInfo::target_address() {
77  ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
78  return Assembler::target_address_at(pc_);
79}
80
81
82Address RelocInfo::target_address_address() {
83  ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY
84                              || rmode_ == EMBEDDED_OBJECT
85                              || rmode_ == EXTERNAL_REFERENCE);
86  return reinterpret_cast<Address>(pc_);
87}
88
89
90int RelocInfo::target_address_size() {
91  return Assembler::kExternalTargetSize;
92}
93
94
95void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) {
96  Assembler::set_target_address_at(pc_, target);
97  ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
98  if (mode == UPDATE_WRITE_BARRIER && host() != NULL && IsCodeTarget(rmode_)) {
99    Object* target_code = Code::GetCodeFromTargetAddress(target);
100    host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
101        host(), this, HeapObject::cast(target_code));
102  }
103}
104
105
106Object* RelocInfo::target_object() {
107  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
108  return Memory::Object_at(pc_);
109}
110
111
112Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
113  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
114  return Memory::Object_Handle_at(pc_);
115}
116
117
118Object** RelocInfo::target_object_address() {
119  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
120  return &Memory::Object_at(pc_);
121}
122
123
124void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) {
125  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
126  Memory::Object_at(pc_) = target;
127  CPU::FlushICache(pc_, sizeof(Address));
128  if (mode == UPDATE_WRITE_BARRIER &&
129      host() != NULL &&
130      target->IsHeapObject()) {
131    host()->GetHeap()->incremental_marking()->RecordWrite(
132        host(), &Memory::Object_at(pc_), HeapObject::cast(target));
133  }
134}
135
136
137Address* RelocInfo::target_reference_address() {
138  ASSERT(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
139  return reinterpret_cast<Address*>(pc_);
140}
141
142
143Handle<JSGlobalPropertyCell> RelocInfo::target_cell_handle() {
144  ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
145  Address address = Memory::Address_at(pc_);
146  return Handle<JSGlobalPropertyCell>(
147      reinterpret_cast<JSGlobalPropertyCell**>(address));
148}
149
150
151JSGlobalPropertyCell* RelocInfo::target_cell() {
152  ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
153  Address address = Memory::Address_at(pc_);
154  Object* object = HeapObject::FromAddress(
155      address - JSGlobalPropertyCell::kValueOffset);
156  return reinterpret_cast<JSGlobalPropertyCell*>(object);
157}
158
159
160void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell,
161                                WriteBarrierMode mode) {
162  ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
163  Address address = cell->address() + JSGlobalPropertyCell::kValueOffset;
164  Memory::Address_at(pc_) = address;
165  CPU::FlushICache(pc_, sizeof(Address));
166  if (mode == UPDATE_WRITE_BARRIER && host() != NULL) {
167    // TODO(1550) We are passing NULL as a slot because cell can never be on
168    // evacuation candidate.
169    host()->GetHeap()->incremental_marking()->RecordWrite(
170        host(), NULL, cell);
171  }
172}
173
174
175Address RelocInfo::call_address() {
176  ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
177         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
178  return Assembler::target_address_at(pc_ + 1);
179}
180
181
182void RelocInfo::set_call_address(Address target) {
183  ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
184         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
185  Assembler::set_target_address_at(pc_ + 1, target);
186  if (host() != NULL) {
187    Object* target_code = Code::GetCodeFromTargetAddress(target);
188    host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
189        host(), this, HeapObject::cast(target_code));
190  }
191}
192
193
194Object* RelocInfo::call_object() {
195  return *call_object_address();
196}
197
198
199void RelocInfo::set_call_object(Object* target) {
200  *call_object_address() = target;
201}
202
203
204Object** RelocInfo::call_object_address() {
205  ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
206         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
207  return reinterpret_cast<Object**>(pc_ + 1);
208}
209
210
211bool RelocInfo::IsPatchedReturnSequence() {
212  return *pc_ == 0xE8;
213}
214
215
216bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
217  return !Assembler::IsNop(pc());
218}
219
220
221void RelocInfo::Visit(ObjectVisitor* visitor) {
222  RelocInfo::Mode mode = rmode();
223  if (mode == RelocInfo::EMBEDDED_OBJECT) {
224    visitor->VisitEmbeddedPointer(this);
225    CPU::FlushICache(pc_, sizeof(Address));
226  } else if (RelocInfo::IsCodeTarget(mode)) {
227    visitor->VisitCodeTarget(this);
228  } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
229    visitor->VisitGlobalPropertyCell(this);
230  } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
231    visitor->VisitExternalReference(this);
232    CPU::FlushICache(pc_, sizeof(Address));
233#ifdef ENABLE_DEBUGGER_SUPPORT
234  // TODO(isolates): Get a cached isolate below.
235  } else if (((RelocInfo::IsJSReturn(mode) &&
236              IsPatchedReturnSequence()) ||
237             (RelocInfo::IsDebugBreakSlot(mode) &&
238              IsPatchedDebugBreakSlotSequence())) &&
239             Isolate::Current()->debug()->has_break_points()) {
240    visitor->VisitDebugTarget(this);
241#endif
242  } else if (mode == RelocInfo::RUNTIME_ENTRY) {
243    visitor->VisitRuntimeEntry(this);
244  }
245}
246
247
248template<typename StaticVisitor>
249void RelocInfo::Visit(Heap* heap) {
250  RelocInfo::Mode mode = rmode();
251  if (mode == RelocInfo::EMBEDDED_OBJECT) {
252    StaticVisitor::VisitEmbeddedPointer(heap, this);
253    CPU::FlushICache(pc_, sizeof(Address));
254  } else if (RelocInfo::IsCodeTarget(mode)) {
255    StaticVisitor::VisitCodeTarget(heap, this);
256  } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
257    StaticVisitor::VisitGlobalPropertyCell(heap, this);
258  } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
259    StaticVisitor::VisitExternalReference(this);
260    CPU::FlushICache(pc_, sizeof(Address));
261#ifdef ENABLE_DEBUGGER_SUPPORT
262  } else if (heap->isolate()->debug()->has_break_points() &&
263             ((RelocInfo::IsJSReturn(mode) &&
264              IsPatchedReturnSequence()) ||
265             (RelocInfo::IsDebugBreakSlot(mode) &&
266              IsPatchedDebugBreakSlotSequence()))) {
267    StaticVisitor::VisitDebugTarget(heap, this);
268#endif
269  } else if (mode == RelocInfo::RUNTIME_ENTRY) {
270    StaticVisitor::VisitRuntimeEntry(this);
271  }
272}
273
274
275
276Immediate::Immediate(int x)  {
277  x_ = x;
278  rmode_ = RelocInfo::NONE;
279}
280
281
282Immediate::Immediate(const ExternalReference& ext) {
283  x_ = reinterpret_cast<int32_t>(ext.address());
284  rmode_ = RelocInfo::EXTERNAL_REFERENCE;
285}
286
287
288Immediate::Immediate(Label* internal_offset) {
289  x_ = reinterpret_cast<int32_t>(internal_offset);
290  rmode_ = RelocInfo::INTERNAL_REFERENCE;
291}
292
293
294Immediate::Immediate(Handle<Object> handle) {
295  // Verify all Objects referred by code are NOT in new space.
296  Object* obj = *handle;
297  ASSERT(!HEAP->InNewSpace(obj));
298  if (obj->IsHeapObject()) {
299    x_ = reinterpret_cast<intptr_t>(handle.location());
300    rmode_ = RelocInfo::EMBEDDED_OBJECT;
301  } else {
302    // no relocation needed
303    x_ =  reinterpret_cast<intptr_t>(obj);
304    rmode_ = RelocInfo::NONE;
305  }
306}
307
308
309Immediate::Immediate(Smi* value) {
310  x_ = reinterpret_cast<intptr_t>(value);
311  rmode_ = RelocInfo::NONE;
312}
313
314
315Immediate::Immediate(Address addr) {
316  x_ = reinterpret_cast<int32_t>(addr);
317  rmode_ = RelocInfo::NONE;
318}
319
320
321void Assembler::emit(uint32_t x) {
322  *reinterpret_cast<uint32_t*>(pc_) = x;
323  pc_ += sizeof(uint32_t);
324}
325
326
327void Assembler::emit(Handle<Object> handle) {
328  // Verify all Objects referred by code are NOT in new space.
329  Object* obj = *handle;
330  ASSERT(!isolate()->heap()->InNewSpace(obj));
331  if (obj->IsHeapObject()) {
332    emit(reinterpret_cast<intptr_t>(handle.location()),
333         RelocInfo::EMBEDDED_OBJECT);
334  } else {
335    // no relocation needed
336    emit(reinterpret_cast<intptr_t>(obj));
337  }
338}
339
340
341void Assembler::emit(uint32_t x, RelocInfo::Mode rmode, unsigned id) {
342  if (rmode == RelocInfo::CODE_TARGET && id != kNoASTId) {
343    RecordRelocInfo(RelocInfo::CODE_TARGET_WITH_ID, static_cast<intptr_t>(id));
344  } else if (rmode != RelocInfo::NONE) {
345    RecordRelocInfo(rmode);
346  }
347  emit(x);
348}
349
350
351void Assembler::emit(const Immediate& x) {
352  if (x.rmode_ == RelocInfo::INTERNAL_REFERENCE) {
353    Label* label = reinterpret_cast<Label*>(x.x_);
354    emit_code_relative_offset(label);
355    return;
356  }
357  if (x.rmode_ != RelocInfo::NONE) RecordRelocInfo(x.rmode_);
358  emit(x.x_);
359}
360
361
362void Assembler::emit_code_relative_offset(Label* label) {
363  if (label->is_bound()) {
364    int32_t pos;
365    pos = label->pos() + Code::kHeaderSize - kHeapObjectTag;
366    emit(pos);
367  } else {
368    emit_disp(label, Displacement::CODE_RELATIVE);
369  }
370}
371
372
373void Assembler::emit_w(const Immediate& x) {
374  ASSERT(x.rmode_ == RelocInfo::NONE);
375  uint16_t value = static_cast<uint16_t>(x.x_);
376  reinterpret_cast<uint16_t*>(pc_)[0] = value;
377  pc_ += sizeof(uint16_t);
378}
379
380
381Address Assembler::target_address_at(Address pc) {
382  return pc + sizeof(int32_t) + *reinterpret_cast<int32_t*>(pc);
383}
384
385
386void Assembler::set_target_address_at(Address pc, Address target) {
387  int32_t* p = reinterpret_cast<int32_t*>(pc);
388  *p = target - (pc + sizeof(int32_t));
389  CPU::FlushICache(p, sizeof(int32_t));
390}
391
392
393Displacement Assembler::disp_at(Label* L) {
394  return Displacement(long_at(L->pos()));
395}
396
397
398void Assembler::disp_at_put(Label* L, Displacement disp) {
399  long_at_put(L->pos(), disp.data());
400}
401
402
403void Assembler::emit_disp(Label* L, Displacement::Type type) {
404  Displacement disp(L, type);
405  L->link_to(pc_offset());
406  emit(static_cast<int>(disp.data()));
407}
408
409
410void Assembler::emit_near_disp(Label* L) {
411  byte disp = 0x00;
412  if (L->is_near_linked()) {
413    int offset = L->near_link_pos() - pc_offset();
414    ASSERT(is_int8(offset));
415    disp = static_cast<byte>(offset & 0xFF);
416  }
417  L->link_to(pc_offset(), Label::kNear);
418  *pc_++ = disp;
419}
420
421
422void Operand::set_modrm(int mod, Register rm) {
423  ASSERT((mod & -4) == 0);
424  buf_[0] = mod << 6 | rm.code();
425  len_ = 1;
426}
427
428
429void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
430  ASSERT(len_ == 1);
431  ASSERT((scale & -4) == 0);
432  // Use SIB with no index register only for base esp.
433  ASSERT(!index.is(esp) || base.is(esp));
434  buf_[1] = scale << 6 | index.code() << 3 | base.code();
435  len_ = 2;
436}
437
438
439void Operand::set_disp8(int8_t disp) {
440  ASSERT(len_ == 1 || len_ == 2);
441  *reinterpret_cast<int8_t*>(&buf_[len_++]) = disp;
442}
443
444
445void Operand::set_dispr(int32_t disp, RelocInfo::Mode rmode) {
446  ASSERT(len_ == 1 || len_ == 2);
447  int32_t* p = reinterpret_cast<int32_t*>(&buf_[len_]);
448  *p = disp;
449  len_ += sizeof(int32_t);
450  rmode_ = rmode;
451}
452
453Operand::Operand(Register reg) {
454  // reg
455  set_modrm(3, reg);
456}
457
458
459Operand::Operand(XMMRegister xmm_reg) {
460  Register reg = { xmm_reg.code() };
461  set_modrm(3, reg);
462}
463
464
465Operand::Operand(int32_t disp, RelocInfo::Mode rmode) {
466  // [disp/r]
467  set_modrm(0, ebp);
468  set_dispr(disp, rmode);
469}
470
471} }  // namespace v8::internal
472
473#endif  // V8_IA32_ASSEMBLER_IA32_INL_H_
474