📄 macro-assembler-ia32.cc.svn-base
字号:
// Copyright 2006-2008 the V8 project authors. 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.// * Redistributions 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 Google Inc. nor the names of its// 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.#include "v8.h"#include "bootstrapper.h"#include "codegen-inl.h"#include "debug.h"#include "runtime.h"#include "serialize.h"namespace v8 { namespace internal {MacroAssembler::MacroAssembler(void* buffer, int size) : Assembler(buffer, size), unresolved_(0), generating_stub_(false), allow_stub_calls_(true) {}static void RecordWriteHelper(MacroAssembler* masm, Register object, Register addr, Register scratch) { Label fast; // Compute the page address from the heap object pointer, leave it // in 'object'. masm->and_(object, ~Page::kPageAlignmentMask); // Compute the bit addr in the remembered set, leave it in "addr". masm->sub(addr, Operand(object)); masm->shr(addr, kObjectAlignmentBits); // If the bit offset lies beyond the normal remembered set range, it is in // the extra remembered set area of a large object. masm->cmp(addr, Page::kPageSize / kPointerSize); masm->j(less, &fast); // Adjust 'addr' to be relative to the start of the extra remembered set // and the page address in 'object' to be the address of the extra // remembered set. masm->sub(Operand(addr), Immediate(Page::kPageSize / kPointerSize)); // Load the array length into 'scratch' and multiply by four to get the // size in bytes of the elements. masm->mov(scratch, Operand(object, Page::kObjectStartOffset + FixedArray::kLengthOffset)); masm->shl(scratch, kObjectAlignmentBits); // Add the page header, array header, and array body size to the page // address. masm->add(Operand(object), Immediate(Page::kObjectStartOffset + Array::kHeaderSize)); masm->add(object, Operand(scratch)); // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction // to limit code size. We should probably evaluate this decision by // measuring the performance of an equivalent implementation using // "simpler" instructions masm->bind(&fast); masm->bts(Operand(object, 0), addr);}class RecordWriteStub : public CodeStub { public: RecordWriteStub(Register object, Register addr, Register scratch) : object_(object), addr_(addr), scratch_(scratch) { } void Generate(MacroAssembler* masm); private: Register object_; Register addr_; Register scratch_; const char* GetName() { return "RecordWriteStub"; }#ifdef DEBUG void Print() { PrintF("RecordWriteStub (object reg %d), (addr reg %d), (scratch reg %d)\n", object_.code(), addr_.code(), scratch_.code()); }#endif // Minor key encoding in 12 bits of three registers (object, address and // scratch) OOOOAAAASSSS. class ScratchBits: public BitField<uint32_t, 0, 4> {}; class AddressBits: public BitField<uint32_t, 4, 4> {}; class ObjectBits: public BitField<uint32_t, 8, 4> {}; Major MajorKey() { return RecordWrite; } int MinorKey() { // Encode the registers. return ObjectBits::encode(object_.code()) | AddressBits::encode(addr_.code()) | ScratchBits::encode(scratch_.code()); }};void RecordWriteStub::Generate(MacroAssembler* masm) { RecordWriteHelper(masm, object_, addr_, scratch_); masm->ret(0);}// Set the remembered set bit for [object+offset].// object is the object being stored into, value is the object being stored.// If offset is zero, then the scratch register contains the array index into// the elements array represented as a Smi.// All registers are clobbered by the operation.void MacroAssembler::RecordWrite(Register object, int offset, Register value, Register scratch) { // First, check if a remembered set write is even needed. The tests below // catch stores of Smis and stores into young gen (which does not have space // for the remembered set bits. Label done; // This optimization cannot survive serialization and deserialization, // so we disable as long as serialization can take place. int32_t new_space_start = reinterpret_cast<int32_t>(ExternalReference::new_space_start().address()); if (Serializer::enabled() || new_space_start < 0) { // Cannot do smart bit-twiddling. Need to do two consecutive checks. // Check for Smi first. test(value, Immediate(kSmiTagMask)); j(zero, &done); // Test that the object address is not in the new space. We cannot // set remembered set bits in the new space. mov(value, Operand(object)); and_(value, Heap::NewSpaceMask()); cmp(Operand(value), Immediate(ExternalReference::new_space_start())); j(equal, &done); } else { // move the value SmiTag into the sign bit shl(value, 31); // combine the object with value SmiTag or_(value, Operand(object)); // remove the uninteresing bits inside the page and_(value, Heap::NewSpaceMask() | (1 << 31)); // xor has two effects: // - if the value was a smi, then the result will be negative // - if the object is pointing into new space area the page bits will // all be zero xor_(value, new_space_start | (1 << 31)); // Check for both conditions in one branch j(less_equal, &done); } if ((offset > 0) && (offset < Page::kMaxHeapObjectSize)) { // Compute the bit offset in the remembered set, leave it in 'value'. mov(value, Operand(object)); and_(value, Page::kPageAlignmentMask); add(Operand(value), Immediate(offset)); shr(value, kObjectAlignmentBits); // Compute the page address from the heap object pointer, leave it in // 'object'. and_(object, ~Page::kPageAlignmentMask); // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction // to limit code size. We should probably evaluate this decision by // measuring the performance of an equivalent implementation using // "simpler" instructions bts(Operand(object, 0), value); } else { Register dst = scratch; if (offset != 0) { lea(dst, Operand(object, offset)); } else { // array access: calculate the destination address in the same manner as // KeyedStoreIC::GenerateGeneric lea(dst, Operand(object, dst, times_2, Array::kHeaderSize - kHeapObjectTag)); } // If we are already generating a shared stub, not inlining the // record write code isn't going to save us any memory. if (generating_stub()) { RecordWriteHelper(this, object, dst, value); } else { RecordWriteStub stub(object, dst, value); CallStub(&stub); } } bind(&done);}void MacroAssembler::SaveRegistersToMemory(RegList regs) { ASSERT((regs & ~kJSCallerSaved) == 0); // Copy the content of registers to memory location. for (int i = 0; i < kNumJSCallerSaved; i++) { int r = JSCallerSavedCode(i); if ((regs & (1 << r)) != 0) { Register reg = { r }; ExternalReference reg_addr = ExternalReference(Debug_Address::Register(i)); mov(Operand::StaticVariable(reg_addr), reg); } }}void MacroAssembler::RestoreRegistersFromMemory(RegList regs) { ASSERT((regs & ~kJSCallerSaved) == 0); // Copy the content of memory location to registers. for (int i = kNumJSCallerSaved; --i >= 0;) { int r = JSCallerSavedCode(i); if ((regs & (1 << r)) != 0) { Register reg = { r }; ExternalReference reg_addr = ExternalReference(Debug_Address::Register(i)); mov(reg, Operand::StaticVariable(reg_addr)); } }}void MacroAssembler::PushRegistersFromMemory(RegList regs) { ASSERT((regs & ~kJSCallerSaved) == 0); // Push the content of the memory location to the stack. for (int i = 0; i < kNumJSCallerSaved; i++) { int r = JSCallerSavedCode(i); if ((regs & (1 << r)) != 0) { ExternalReference reg_addr = ExternalReference(Debug_Address::Register(i)); push(Operand::StaticVariable(reg_addr)); } }}void MacroAssembler::PopRegistersToMemory(RegList regs) { ASSERT((regs & ~kJSCallerSaved) == 0); // Pop the content from the stack to the memory location. for (int i = kNumJSCallerSaved; --i >= 0;) { int r = JSCallerSavedCode(i); if ((regs & (1 << r)) != 0) { ExternalReference reg_addr = ExternalReference(Debug_Address::Register(i)); pop(Operand::StaticVariable(reg_addr)); } }}void MacroAssembler::CopyRegistersFromStackToMemory(Register base, Register scratch, RegList regs) { ASSERT((regs & ~kJSCallerSaved) == 0); // Copy the content of the stack to the memory location and adjust base. for (int i = kNumJSCallerSaved; --i >= 0;) { int r = JSCallerSavedCode(i); if ((regs & (1 << r)) != 0) { mov(scratch, Operand(base, 0)); ExternalReference reg_addr = ExternalReference(Debug_Address::Register(i)); mov(Operand::StaticVariable(reg_addr), scratch); lea(base, Operand(base, kPointerSize)); } }}void MacroAssembler::Set(Register dst, const Immediate& x) { if (x.is_zero()) { xor_(dst, Operand(dst)); // shorter than mov } else { mov(Operand(dst), x); }}void MacroAssembler::Set(const Operand& dst, const Immediate& x) { mov(dst, x);}void MacroAssembler::FCmp() {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -