2010-02-04 20:36:58 +00:00
|
|
|
// 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.
|
2011-05-09 14:28:09 +00:00
|
|
|
// Copyright 2011 the V8 project authors. All rights reserved.
|
2010-02-04 20:36:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
#ifndef V8_MIPS_ASSEMBLER_MIPS_INL_H_
|
|
|
|
#define V8_MIPS_ASSEMBLER_MIPS_INL_H_
|
|
|
|
|
|
|
|
#include "mips/assembler-mips.h"
|
|
|
|
#include "cpu.h"
|
2011-03-28 13:05:36 +00:00
|
|
|
#include "debug.h"
|
2010-02-04 20:36:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2011-05-09 14:28:09 +00:00
|
|
|
// Operand and MemOperand.
|
2010-02-04 20:36:58 +00:00
|
|
|
|
|
|
|
Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) {
|
|
|
|
rm_ = no_reg;
|
|
|
|
imm32_ = immediate;
|
|
|
|
rmode_ = rmode;
|
|
|
|
}
|
|
|
|
|
2011-03-28 13:05:36 +00:00
|
|
|
|
2010-02-04 20:36:58 +00:00
|
|
|
Operand::Operand(const ExternalReference& f) {
|
|
|
|
rm_ = no_reg;
|
|
|
|
imm32_ = reinterpret_cast<int32_t>(f.address());
|
|
|
|
rmode_ = RelocInfo::EXTERNAL_REFERENCE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Operand::Operand(Smi* value) {
|
|
|
|
rm_ = no_reg;
|
|
|
|
imm32_ = reinterpret_cast<intptr_t>(value);
|
|
|
|
rmode_ = RelocInfo::NONE;
|
|
|
|
}
|
|
|
|
|
2011-03-28 13:05:36 +00:00
|
|
|
|
2010-02-04 20:36:58 +00:00
|
|
|
Operand::Operand(Register rm) {
|
|
|
|
rm_ = rm;
|
|
|
|
}
|
|
|
|
|
2011-03-28 13:05:36 +00:00
|
|
|
|
2010-02-04 20:36:58 +00:00
|
|
|
bool Operand::is_reg() const {
|
|
|
|
return rm_.is_valid();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2011-05-09 14:28:09 +00:00
|
|
|
// RelocInfo.
|
2010-02-04 20:36:58 +00:00
|
|
|
|
|
|
|
void RelocInfo::apply(intptr_t delta) {
|
|
|
|
// On MIPS we do not use pc relative addressing, so we don't need to patch the
|
|
|
|
// code here.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Address RelocInfo::target_address() {
|
|
|
|
ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
|
|
|
|
return Assembler::target_address_at(pc_);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Address RelocInfo::target_address_address() {
|
2011-03-28 13:05:36 +00:00
|
|
|
ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY
|
|
|
|
|| rmode_ == EMBEDDED_OBJECT
|
|
|
|
|| rmode_ == EXTERNAL_REFERENCE);
|
|
|
|
// Read the address of the word containing the target_address in an
|
|
|
|
// instruction stream.
|
|
|
|
// The only architecture-independent user of this function is the serializer.
|
|
|
|
// The serializer uses it to find out how many raw bytes of instruction to
|
|
|
|
// output before the next target.
|
|
|
|
// For an instructions like LUI/ORI where the target bits are mixed into the
|
|
|
|
// instruction bits, the size of the target will be zero, indicating that the
|
|
|
|
// serializer should not step forward in memory after a target is resolved
|
|
|
|
// and written. In this case the target_address_address function should
|
|
|
|
// return the end of the instructions to be patched, allowing the
|
|
|
|
// deserializer to deserialize the instructions as raw bytes and put them in
|
|
|
|
// place, ready to be patched with the target. In our case, that is the
|
|
|
|
// address of the instruction that follows LUI/ORI instruction pair.
|
|
|
|
return reinterpret_cast<Address>(
|
|
|
|
pc_ + Assembler::kInstructionsFor32BitConstant * Assembler::kInstrSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RelocInfo::target_address_size() {
|
|
|
|
return Assembler::kExternalTargetSize;
|
2010-02-04 20:36:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RelocInfo::set_target_address(Address target) {
|
|
|
|
ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
|
|
|
|
Assembler::set_target_address_at(pc_, target);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Object* RelocInfo::target_object() {
|
|
|
|
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
|
|
|
|
return reinterpret_cast<Object*>(Assembler::target_address_at(pc_));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> RelocInfo::target_object_handle(Assembler *origin) {
|
|
|
|
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
|
|
|
|
return Handle<Object>(reinterpret_cast<Object**>(
|
|
|
|
Assembler::target_address_at(pc_)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Object** RelocInfo::target_object_address() {
|
2011-03-28 13:05:36 +00:00
|
|
|
// Provide a "natural pointer" to the embedded object,
|
|
|
|
// which can be de-referenced during heap iteration.
|
2010-02-04 20:36:58 +00:00
|
|
|
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
|
2011-03-28 13:05:36 +00:00
|
|
|
// TODO(mips): Commenting out, to simplify arch-independent changes.
|
|
|
|
// GC won't work like this, but this commit is for asm/disasm/sim.
|
|
|
|
// reconstructed_obj_ptr_ =
|
|
|
|
// reinterpret_cast<Object*>(Assembler::target_address_at(pc_));
|
|
|
|
// return &reconstructed_obj_ptr_;
|
|
|
|
return NULL;
|
2010-02-04 20:36:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RelocInfo::set_target_object(Object* target) {
|
|
|
|
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
|
|
|
|
Assembler::set_target_address_at(pc_, reinterpret_cast<Address>(target));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Address* RelocInfo::target_reference_address() {
|
|
|
|
ASSERT(rmode_ == EXTERNAL_REFERENCE);
|
2011-03-28 13:05:36 +00:00
|
|
|
// TODO(mips): Commenting out, to simplify arch-independent changes.
|
|
|
|
// GC won't work like this, but this commit is for asm/disasm/sim.
|
|
|
|
// reconstructed_adr_ptr_ = Assembler::target_address_at(pc_);
|
|
|
|
// return &reconstructed_adr_ptr_;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<JSGlobalPropertyCell> RelocInfo::target_cell_handle() {
|
|
|
|
ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
|
|
|
|
Address address = Memory::Address_at(pc_);
|
|
|
|
return Handle<JSGlobalPropertyCell>(
|
|
|
|
reinterpret_cast<JSGlobalPropertyCell**>(address));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
JSGlobalPropertyCell* RelocInfo::target_cell() {
|
|
|
|
ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
|
|
|
|
Address address = Memory::Address_at(pc_);
|
|
|
|
Object* object = HeapObject::FromAddress(
|
|
|
|
address - JSGlobalPropertyCell::kValueOffset);
|
|
|
|
return reinterpret_cast<JSGlobalPropertyCell*>(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell) {
|
|
|
|
ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
|
|
|
|
Address address = cell->address() + JSGlobalPropertyCell::kValueOffset;
|
|
|
|
Memory::Address_at(pc_) = address;
|
2010-02-04 20:36:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Address RelocInfo::call_address() {
|
2011-03-28 13:05:36 +00:00
|
|
|
ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
|
|
|
|
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
|
|
|
|
// The pc_ offset of 0 assumes mips patched return sequence per
|
|
|
|
// debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or
|
|
|
|
// debug break slot per BreakLocationIterator::SetDebugBreakAtSlot().
|
|
|
|
return Assembler::target_address_at(pc_);
|
2010-02-04 20:36:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RelocInfo::set_call_address(Address target) {
|
2011-03-28 13:05:36 +00:00
|
|
|
ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
|
|
|
|
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
|
|
|
|
// The pc_ offset of 0 assumes mips patched return sequence per
|
|
|
|
// debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or
|
|
|
|
// debug break slot per BreakLocationIterator::SetDebugBreakAtSlot().
|
|
|
|
Assembler::set_target_address_at(pc_, target);
|
2010-02-04 20:36:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Object* RelocInfo::call_object() {
|
|
|
|
return *call_object_address();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Object** RelocInfo::call_object_address() {
|
2011-03-28 13:05:36 +00:00
|
|
|
ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
|
|
|
|
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
|
2010-02-04 20:36:58 +00:00
|
|
|
return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RelocInfo::set_call_object(Object* target) {
|
|
|
|
*call_object_address() = target;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool RelocInfo::IsPatchedReturnSequence() {
|
2011-03-28 13:05:36 +00:00
|
|
|
Instr instr0 = Assembler::instr_at(pc_);
|
|
|
|
Instr instr1 = Assembler::instr_at(pc_ + 1 * Assembler::kInstrSize);
|
|
|
|
Instr instr2 = Assembler::instr_at(pc_ + 2 * Assembler::kInstrSize);
|
|
|
|
bool patched_return = ((instr0 & kOpcodeMask) == LUI &&
|
|
|
|
(instr1 & kOpcodeMask) == ORI &&
|
|
|
|
(instr2 & kOpcodeMask) == SPECIAL &&
|
|
|
|
(instr2 & kFunctionFieldMask) == JALR);
|
|
|
|
return patched_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
|
|
|
|
Instr current_instr = Assembler::instr_at(pc_);
|
|
|
|
return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RelocInfo::Visit(ObjectVisitor* visitor) {
|
|
|
|
RelocInfo::Mode mode = rmode();
|
|
|
|
if (mode == RelocInfo::EMBEDDED_OBJECT) {
|
|
|
|
// RelocInfo is needed when pointer must be updated/serialized, such as
|
|
|
|
// UpdatingVisitor in mark-compact.cc or Serializer in serialize.cc.
|
|
|
|
// It is ignored by visitors that do not need it.
|
2011-05-09 14:28:09 +00:00
|
|
|
// TODO(mips): Commenting out, to simplify arch-independent changes.
|
2011-03-28 13:05:36 +00:00
|
|
|
// GC won't work like this, but this commit is for asm/disasm/sim.
|
|
|
|
// visitor->VisitPointer(target_object_address(), this);
|
|
|
|
} else if (RelocInfo::IsCodeTarget(mode)) {
|
|
|
|
visitor->VisitCodeTarget(this);
|
2011-05-09 14:28:09 +00:00
|
|
|
} else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
|
|
|
|
visitor->VisitGlobalPropertyCell(this);
|
2011-03-28 13:05:36 +00:00
|
|
|
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
|
|
|
|
// RelocInfo is needed when external-references must be serialized by
|
|
|
|
// Serializer Visitor in serialize.cc. It is ignored by visitors that
|
|
|
|
// do not need it.
|
2011-05-09 14:28:09 +00:00
|
|
|
// TODO(mips): Commenting out, to simplify arch-independent changes.
|
2011-03-28 13:05:36 +00:00
|
|
|
// Serializer won't work like this, but this commit is for asm/disasm/sim.
|
|
|
|
// visitor->VisitExternalReference(target_reference_address(), this);
|
|
|
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
|
|
|
// TODO(isolates): Get a cached isolate below.
|
|
|
|
} else if (((RelocInfo::IsJSReturn(mode) &&
|
|
|
|
IsPatchedReturnSequence()) ||
|
2011-05-09 14:28:09 +00:00
|
|
|
(RelocInfo::IsDebugBreakSlot(mode) &&
|
2011-03-28 13:05:36 +00:00
|
|
|
IsPatchedDebugBreakSlotSequence())) &&
|
|
|
|
Isolate::Current()->debug()->has_break_points()) {
|
|
|
|
visitor->VisitDebugTarget(this);
|
2010-02-04 20:36:58 +00:00
|
|
|
#endif
|
2011-03-28 13:05:36 +00:00
|
|
|
} else if (mode == RelocInfo::RUNTIME_ENTRY) {
|
|
|
|
visitor->VisitRuntimeEntry(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename StaticVisitor>
|
|
|
|
void RelocInfo::Visit(Heap* heap) {
|
|
|
|
RelocInfo::Mode mode = rmode();
|
|
|
|
if (mode == RelocInfo::EMBEDDED_OBJECT) {
|
|
|
|
StaticVisitor::VisitPointer(heap, target_object_address());
|
|
|
|
} else if (RelocInfo::IsCodeTarget(mode)) {
|
2011-05-09 14:28:09 +00:00
|
|
|
StaticVisitor::VisitCodeTarget(heap, this);
|
|
|
|
} else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
|
|
|
|
StaticVisitor::VisitGlobalPropertyCell(heap, this);
|
2011-03-28 13:05:36 +00:00
|
|
|
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
|
|
|
|
StaticVisitor::VisitExternalReference(target_reference_address());
|
|
|
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
|
|
|
} else if (heap->isolate()->debug()->has_break_points() &&
|
|
|
|
((RelocInfo::IsJSReturn(mode) &&
|
|
|
|
IsPatchedReturnSequence()) ||
|
|
|
|
(RelocInfo::IsDebugBreakSlot(mode) &&
|
|
|
|
IsPatchedDebugBreakSlotSequence()))) {
|
2011-05-09 14:28:09 +00:00
|
|
|
StaticVisitor::VisitDebugTarget(heap, this);
|
2011-03-28 13:05:36 +00:00
|
|
|
#endif
|
|
|
|
} else if (mode == RelocInfo::RUNTIME_ENTRY) {
|
|
|
|
StaticVisitor::VisitRuntimeEntry(this);
|
|
|
|
}
|
2010-02-04 20:36:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2011-05-09 14:28:09 +00:00
|
|
|
// Assembler.
|
2010-02-04 20:36:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
void Assembler::CheckBuffer() {
|
|
|
|
if (buffer_space() <= kGap) {
|
|
|
|
GrowBuffer();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-28 13:05:36 +00:00
|
|
|
void Assembler::CheckTrampolinePoolQuick() {
|
|
|
|
if (pc_offset() >= next_buffer_check_) {
|
|
|
|
CheckTrampolinePool();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-04 20:36:58 +00:00
|
|
|
void Assembler::emit(Instr x) {
|
|
|
|
CheckBuffer();
|
|
|
|
*reinterpret_cast<Instr*>(pc_) = x;
|
|
|
|
pc_ += kInstrSize;
|
2011-03-28 13:05:36 +00:00
|
|
|
CheckTrampolinePoolQuick();
|
2010-02-04 20:36:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} } // namespace v8::internal
|
|
|
|
|
|
|
|
#endif // V8_MIPS_ASSEMBLER_MIPS_INL_H_
|