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