Author: whe...@chromium.org Date: Thu Jun 11 06:51:46 2009 New Revision: 2146
Modified: branches/bleeding_edge/src/SConscript branches/bleeding_edge/src/x64/assembler-x64.cc branches/bleeding_edge/src/x64/assembler-x64.h branches/bleeding_edge/src/x64/codegen-x64.cc branches/bleeding_edge/src/x64/frames-x64.cc branches/bleeding_edge/src/x64/macro-assembler-x64.cc branches/bleeding_edge/src/x64/register-allocator-x64-inl.h branches/bleeding_edge/src/x64/register-allocator-x64.h branches/bleeding_edge/src/x64/virtual-frame-x64.cc branches/bleeding_edge/src/x64/virtual-frame-x64.h Log: X64 implementation starts using virtual frame and register allocators. Review URL: http://codereview.chromium.org/123018 Modified: branches/bleeding_edge/src/SConscript ============================================================================== --- branches/bleeding_edge/src/SConscript (original) +++ branches/bleeding_edge/src/SConscript Thu Jun 11 06:51:46 2009 @@ -77,7 +77,7 @@ 'x64/debug-x64.cc', 'x64/frames-x64.cc', 'x64/ic-x64.cc', 'x64/jump-target-x64.cc', 'x64/macro-assembler-x64.cc', # 'x64/regexp-macro-assembler-x64.cc', - 'x64/stub-cache-x64.cc' + 'x64/stub-cache-x64.cc', 'x64/virtual-frame-x64.cc' ], 'simulator:arm': ['arm/simulator-arm.cc'], 'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'], Modified: branches/bleeding_edge/src/x64/assembler-x64.cc ============================================================================== --- branches/bleeding_edge/src/x64/assembler-x64.cc (original) +++ branches/bleeding_edge/src/x64/assembler-x64.cc Thu Jun 11 06:51:46 2009 @@ -441,11 +441,11 @@ emit_rex_64(dst); if (is_int8(src.value_)) { emit(0x83); - emit_operand(Register::toRegister(subcode), dst); + emit_operand(subcode, dst); emit(src.value_); } else { emit(0x81); - emit_operand(Register::toRegister(subcode), dst); + emit_operand(subcode, dst); emitl(src.value_); } } @@ -459,16 +459,29 @@ emit_optional_rex_32(dst); if (is_int8(src.value_)) { emit(0x83); - emit_operand(Register::toRegister(subcode), dst); + emit_operand(subcode, dst); emit(src.value_); } else { emit(0x81); - emit_operand(Register::toRegister(subcode), dst); + emit_operand(subcode, dst); emitl(src.value_); } } +void Assembler::immediate_arithmetic_op_8(byte subcode, + const Operand& dst, + Immediate src) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit_optional_rex_32(dst); + ASSERT(is_int8(src.value_)); + emit(0x80); + emit_operand(subcode, dst); + emit(src.value_); +} + + void Assembler::shift(Register dst, Immediate shift_amount, int subcode) { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -1513,18 +1526,6 @@ return NULL; } - -StackFrame::Type ExitFrame::GetStateForFramePointer(unsigned char* a, - StackFrame::State* b) { - // TODO(X64): UNIMPLEMENTED - return NONE; -} - -int JavaScriptFrame::GetProvidedParametersCount() const { - UNIMPLEMENTED(); - return 0; -} - void JumpTarget::DoBind(int a) { UNIMPLEMENTED(); } @@ -1537,7 +1538,6 @@ UNIMPLEMENTED(); } - Object* LoadStubCompiler::CompileLoadCallback(JSObject* a, JSObject* b, AccessorInfo* c, @@ -1569,11 +1569,6 @@ return NULL; } -StackFrame::Type StackFrame::ComputeType(StackFrame::State* a) { - UNIMPLEMENTED(); - return NONE; -} - Object* StoreStubCompiler::CompileStoreCallback(JSObject* a, AccessorInfo* b, String* c) { @@ -1595,104 +1590,6 @@ } Object* StubCompiler::CompileLazyCompile(Code::Flags a) { - UNIMPLEMENTED(); - return NULL; -} - -void VirtualFrame::Drop(int a) { - UNIMPLEMENTED(); -} - -int VirtualFrame::InvalidateFrameSlotAt(int a) { - UNIMPLEMENTED(); - return -1; -} - -void VirtualFrame::MergeTo(VirtualFrame* a) { - UNIMPLEMENTED(); -} - -Result VirtualFrame::Pop() { - UNIMPLEMENTED(); - return Result(NULL); -} - -Result VirtualFrame::RawCallStub(CodeStub* a) { - UNIMPLEMENTED(); - return Result(NULL); -} - -void VirtualFrame::SyncElementBelowStackPointer(int a) { - UNIMPLEMENTED(); -} - -void VirtualFrame::SyncElementByPushing(int a) { - UNIMPLEMENTED(); -} - -void VirtualFrame::SyncRange(int a, int b) { - UNIMPLEMENTED(); -} - -VirtualFrame::VirtualFrame() : elements_(0) { - UNIMPLEMENTED(); -} - -byte* ArgumentsAdaptorFrame::GetCallerStackPointer() const { - UNIMPLEMENTED(); - return NULL; -} - -void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* a) { - UNIMPLEMENTED(); -} - -void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* a) { - UNIMPLEMENTED(); -} - -void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* a) { - UNIMPLEMENTED(); -} - -void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* a) { - UNIMPLEMENTED(); -} - -void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* a) { - UNIMPLEMENTED(); -} - -void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* a) { - UNIMPLEMENTED(); -} - -void CodeGenerator::GenerateLog(ZoneList<Expression*>* a) { - UNIMPLEMENTED(); -} - -void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* a) { - UNIMPLEMENTED(); -} - -void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* a) { - UNIMPLEMENTED(); -} - -void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* a) { - UNIMPLEMENTED(); -} - -void ExitFrame::Iterate(ObjectVisitor* a) const { - UNIMPLEMENTED(); -} - -byte* InternalFrame::GetCallerStackPointer() const { - UNIMPLEMENTED(); - return NULL; -} - -byte* JavaScriptFrame::GetCallerStackPointer() const { UNIMPLEMENTED(); return NULL; } Modified: branches/bleeding_edge/src/x64/assembler-x64.h ============================================================================== --- branches/bleeding_edge/src/x64/assembler-x64.h (original) +++ branches/bleeding_edge/src/x64/assembler-x64.h Thu Jun 11 06:51:46 2009 @@ -482,6 +482,10 @@ immediate_arithmetic_op_32(0x0, dst, src); } + void cmpb(const Operand& dst, Immediate src) { + immediate_arithmetic_op_8(0x7, dst, src); + } + void cmpq(Register dst, Register src) { arithmetic_op(0x3B, dst, src); } @@ -958,7 +962,12 @@ void arithmetic_op(byte opcode, Register reg, const Operand& op); void immediate_arithmetic_op(byte subcode, Register dst, Immediate src); void immediate_arithmetic_op(byte subcode, const Operand& dst, Immediate src); + // Operate on a 32-bit word in memory. void immediate_arithmetic_op_32(byte subcode, + const Operand& dst, + Immediate src); + // Operate on a byte in memory. + void immediate_arithmetic_op_8(byte subcode, const Operand& dst, Immediate src); // Emit machine code for a shift operation. Modified: branches/bleeding_edge/src/x64/codegen-x64.cc ============================================================================== --- branches/bleeding_edge/src/x64/codegen-x64.cc (original) +++ branches/bleeding_edge/src/x64/codegen-x64.cc Thu Jun 11 06:51:46 2009 @@ -41,6 +41,37 @@ void DeferredCode::RestoreRegisters() { UNIMPLEMENTED(); } +// ------------------------------------------------------------------------- +// CodeGenState implementation. + +CodeGenState::CodeGenState(CodeGenerator* owner) + : owner_(owner), + typeof_state_(NOT_INSIDE_TYPEOF), + destination_(NULL), + previous_(NULL) { + owner_->set_state(this); +} + + +CodeGenState::CodeGenState(CodeGenerator* owner, + TypeofState typeof_state, + ControlDestination* destination) + : owner_(owner), + typeof_state_(typeof_state), + destination_(destination), + previous_(owner->state()) { + owner_->set_state(this); +} + + +CodeGenState::~CodeGenState() { + ASSERT(owner_->state() == this); + owner_->set_state(previous_); +} + + +// ----------------------------------------------------------------------------- +// CodeGenerator implementation. CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script, @@ -71,6 +102,8 @@ const int initial_buffer_size = 4 * KB; CodeGenerator cgen(initial_buffer_size, NULL, false); CodeGeneratorScope scope(&cgen); + Scope dummy_scope; + cgen.scope_ = &dummy_scope; cgen.GenCode(NULL); CodeDesc desc; @@ -78,14 +111,67 @@ } -void CodeGenerator::GenCode(FunctionLiteral* a) { - if (a != NULL) { +void CodeGenerator::GenCode(FunctionLiteral* function) { + if (function != NULL) { + CodeForFunctionPosition(function); + // ASSERT(scope_ == NULL); + // scope_ = function->scope(); __ int3(); // UNIMPLEMENTED } else { // GenCode Implementation under construction. Run by TestCodeGenerator // with a == NULL. - __ movq(rax, Immediate(0x2a)); - __ Ret(); + // Everything guarded by if (function) should be run, unguarded, + // once testing is over. + // Record the position for debugging purposes. + if (function) { + CodeForFunctionPosition(function); + } + // ZoneList<Statement*>* body = fun->body(); + + // Initialize state. + // While testing, scope is set in cgen before calling GenCode(). + if (function) { + ASSERT(scope_ == NULL); + scope_ = function->scope(); + } + ASSERT(allocator_ == NULL); + RegisterAllocator register_allocator(this); + allocator_ = ®ister_allocator; + ASSERT(frame_ == NULL); + frame_ = new VirtualFrame(); + set_in_spilled_code(false); + + // Adjust for function-level loop nesting. + // loop_nesting_ += fun->loop_nesting(); + + JumpTarget::set_compiling_deferred_code(false); + +#ifdef DEBUG + if (strlen(FLAG_stop_at) > 0 && + // fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { + false) { + frame_->SpillAll(); + __ int3(); + } +#endif + + // New scope to get automatic timing calculation. + { // NOLINT + HistogramTimerScope codegen_timer(&Counters::code_generation); + CodeGenState state(this); + + // Entry: + // Stack: receiver, arguments, return address. + // ebp: caller's frame pointer + // esp: stack pointer + // edi: called JS function + // esi: callee's context + allocator_->Initialize(); + frame_->Enter(); + + __ movq(rax, Immediate(0x2a)); + __ Ret(); + } } } @@ -252,6 +338,46 @@ } void CodeGenerator::VisitThisFunction(ThisFunction* a) { + UNIMPLEMENTED(); +} + +void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* a) { + UNIMPLEMENTED(); +} + +void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* a) { + UNIMPLEMENTED(); +} + +void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* a) { + UNIMPLEMENTED(); +} + +void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* a) { + UNIMPLEMENTED(); +} + +void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* a) { + UNIMPLEMENTED(); +} + +void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* a) { + UNIMPLEMENTED(); +} + +void CodeGenerator::GenerateLog(ZoneList<Expression*>* a) { + UNIMPLEMENTED(); +} + +void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* a) { + UNIMPLEMENTED(); +} + +void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* a) { + UNIMPLEMENTED(); +} + +void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* a) { UNIMPLEMENTED(); } Modified: branches/bleeding_edge/src/x64/frames-x64.cc ============================================================================== --- branches/bleeding_edge/src/x64/frames-x64.cc (original) +++ branches/bleeding_edge/src/x64/frames-x64.cc Thu Jun 11 06:51:46 2009 @@ -25,3 +25,48 @@ // (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 "frames-inl.h" + +namespace v8 { +namespace internal { + +StackFrame::Type ExitFrame::GetStateForFramePointer(unsigned char* a, + StackFrame::State* b) { + // TODO(X64): UNIMPLEMENTED + return NONE; +} + +int JavaScriptFrame::GetProvidedParametersCount() const { + UNIMPLEMENTED(); + return 0; +} + +StackFrame::Type StackFrame::ComputeType(StackFrame::State* a) { + UNIMPLEMENTED(); + return NONE; +} + +byte* ArgumentsAdaptorFrame::GetCallerStackPointer() const { + UNIMPLEMENTED(); + return NULL; +} + + +void ExitFrame::Iterate(ObjectVisitor* a) const { + UNIMPLEMENTED(); +} + +byte* InternalFrame::GetCallerStackPointer() const { + UNIMPLEMENTED(); + return NULL; +} + +byte* JavaScriptFrame::GetCallerStackPointer() const { + UNIMPLEMENTED(); + return NULL; +} + + +} } // namespace v8::internal Modified: branches/bleeding_edge/src/x64/macro-assembler-x64.cc ============================================================================== --- branches/bleeding_edge/src/x64/macro-assembler-x64.cc (original) +++ branches/bleeding_edge/src/x64/macro-assembler-x64.cc Thu Jun 11 06:51:46 2009 @@ -278,6 +278,21 @@ } +void MacroAssembler::CmpObjectType(Register heap_object, + InstanceType type, + Register map) { + movq(map, FieldOperand(heap_object, HeapObject::kMapOffset)); + CmpInstanceType(map, type); +} + + +void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { + cmpb(FieldOperand(map, Map::kInstanceTypeOffset), + Immediate(static_cast<int8_t>(type))); +} + + + void MacroAssembler::SetCounter(StatsCounter* counter, int value) { if (FLAG_native_code_counters && counter->Enabled()) { movq(kScratchRegister, ExternalReference(counter)); Modified: branches/bleeding_edge/src/x64/register-allocator-x64-inl.h ============================================================================== --- branches/bleeding_edge/src/x64/register-allocator-x64-inl.h (original) +++ branches/bleeding_edge/src/x64/register-allocator-x64-inl.h Thu Jun 11 06:51:46 2009 @@ -37,8 +37,7 @@ // RegisterAllocator implementation. bool RegisterAllocator::IsReserved(Register reg) { - // All registers are reserved for now. - return true; + return reg.is(rsp) || reg.is(rbp) || reg.is(rsi) || reg.is(r10); } @@ -47,20 +46,19 @@ int RegisterAllocator::ToNumber(Register reg) { ASSERT(reg.is_valid() && !IsReserved(reg)); - UNIMPLEMENTED(); - return -1; + return reg.code(); } Register RegisterAllocator::ToRegister(int num) { ASSERT(num >= 0 && num < kNumRegisters); - UNIMPLEMENTED(); - return no_reg; + Register result = {num}; + return result; } void RegisterAllocator::Initialize() { - UNIMPLEMENTED(); + // TODO(X64): Implement. } Modified: branches/bleeding_edge/src/x64/register-allocator-x64.h ============================================================================== --- branches/bleeding_edge/src/x64/register-allocator-x64.h (original) +++ branches/bleeding_edge/src/x64/register-allocator-x64.h Thu Jun 11 06:51:46 2009 @@ -35,7 +35,7 @@ public: // Register allocation is not yet implemented on x64, but C++ // forbids 0-length arrays so we use 1 as the number of registers. - static const int kNumRegisters = 1; + static const int kNumRegisters = 16; static const int kInvalidRegister = -1; }; Modified: branches/bleeding_edge/src/x64/virtual-frame-x64.cc ============================================================================== --- branches/bleeding_edge/src/x64/virtual-frame-x64.cc (original) +++ branches/bleeding_edge/src/x64/virtual-frame-x64.cc Thu Jun 11 06:51:46 2009 @@ -25,3 +25,170 @@ // (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 "codegen-inl.h" +#include "register-allocator-inl.h" +#include "scopes.h" + +namespace v8 { +namespace internal { + +#define __ ACCESS_MASM(masm()) + +// ------------------------------------------------------------------------- +// VirtualFrame implementation. + +// On entry to a function, the virtual frame already contains the receiver, +// the parameters, and a return address. All frame elements are in memory. +VirtualFrame::VirtualFrame() + : elements_(parameter_count() + local_count() + kPreallocatedElements), + stack_pointer_(parameter_count() + 1) { // 0-based index of TOS. + for (int i = 0; i <= stack_pointer_; i++) { + elements_.Add(FrameElement::MemoryElement()); + } + for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { + register_locations_[i] = kIllegalIndex; + } +} + + +void VirtualFrame::Enter() { + // Registers live on entry to a JS frame: + // rsp: stack pointer, points to return address from this function. + // rbp: base pointer, points to previous JS, ArgumentsAdaptor, or + // Trampoline frame. + // rsi: context of this function call. + // rdi: pointer to this function object. + Comment cmnt(masm(), "[ Enter JS frame"); + +#ifdef DEBUG + // Verify that rdi contains a JS function. The following code + // relies on rax being available for use. + __ testq(rdi, Immediate(kSmiTagMask)); + __ Check(not_zero, + "VirtualFrame::Enter - rdi is not a function (smi check)."); + __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax); + __ Check(equal, + "VirtualFrame::Enter - rdi is not a function (map check)."); +#endif + + EmitPush(rbp); + + __ movq(rbp, rsp); + + // Store the context in the frame. The context is kept in rsi and a + // copy is stored in the frame. The external reference to rsi + // remains. + EmitPush(rsi); + + // Store the function in the frame. The frame owns the register + // reference now (ie, it can keep it in rdi or spill it later). + Push(rdi); + // SyncElementAt(element_count() - 1); + cgen()->allocator()->Unuse(rdi); +} + + +void VirtualFrame::Exit() { + Comment cmnt(masm(), "[ Exit JS frame"); + // Record the location of the JS exit code for patching when setting + // break point. + __ RecordJSReturn(); + + // Avoid using the leave instruction here, because it is too + // short. We need the return sequence to be a least the size of a + // call instruction to support patching the exit code in the + // debugger. See VisitReturnStatement for the full return sequence. + __ movq(rsp, rbp); + stack_pointer_ = frame_pointer(); + for (int i = element_count() - 1; i > stack_pointer_; i--) { + FrameElement last = elements_.RemoveLast(); + if (last.is_register()) { + Unuse(last.reg()); + } + } + + EmitPop(rbp); +} + + +void VirtualFrame::EmitPop(Register reg) { + ASSERT(stack_pointer_ == element_count() - 1); + stack_pointer_--; + elements_.RemoveLast(); + __ pop(reg); +} + + +void VirtualFrame::EmitPop(const Operand& operand) { + ASSERT(stack_pointer_ == element_count() - 1); + stack_pointer_--; + elements_.RemoveLast(); + __ pop(operand); +} + + +void VirtualFrame::EmitPush(Register reg) { + ASSERT(stack_pointer_ == element_count() - 1); + elements_.Add(FrameElement::MemoryElement()); + stack_pointer_++; + __ push(reg); +} + + +void VirtualFrame::EmitPush(const Operand& operand) { + ASSERT(stack_pointer_ == element_count() - 1); + elements_.Add(FrameElement::MemoryElement()); + stack_pointer_++; + __ push(operand); +} + + +void VirtualFrame::EmitPush(Immediate immediate) { + ASSERT(stack_pointer_ == element_count() - 1); + elements_.Add(FrameElement::MemoryElement()); + stack_pointer_++; + __ push(immediate); +} + + +void VirtualFrame::Drop(int a) { + UNIMPLEMENTED(); +} + +int VirtualFrame::InvalidateFrameSlotAt(int a) { + UNIMPLEMENTED(); + return -1; +} + +void VirtualFrame::MergeTo(VirtualFrame* a) { + UNIMPLEMENTED(); +} + +Result VirtualFrame::Pop() { + UNIMPLEMENTED(); + return Result(NULL); +} + +Result VirtualFrame::RawCallStub(CodeStub* a) { + UNIMPLEMENTED(); + return Result(NULL); +} + +void VirtualFrame::SyncElementBelowStackPointer(int a) { + UNIMPLEMENTED(); +} + +void VirtualFrame::SyncElementByPushing(int a) { + UNIMPLEMENTED(); +} + +void VirtualFrame::SyncRange(int a, int b) { + UNIMPLEMENTED(); +} + + +#undef __ + +} } // namespace v8::internal Modified: branches/bleeding_edge/src/x64/virtual-frame-x64.h ============================================================================== --- branches/bleeding_edge/src/x64/virtual-frame-x64.h (original) +++ branches/bleeding_edge/src/x64/virtual-frame-x64.h Thu Jun 11 06:51:46 2009 @@ -372,12 +372,12 @@ // Pop and save an element from the top of the expression stack and // emit a corresponding pop instruction. void EmitPop(Register reg); - void EmitPop(Operand operand); + void EmitPop(const Operand& operand); // Push an element on top of the expression stack and emit a // corresponding push instruction. void EmitPush(Register reg); - void EmitPush(Operand operand); + void EmitPush(const Operand& operand); void EmitPush(Immediate immediate); // Push an element on the virtual frame. --~--~---------~--~----~------------~-------~--~----~ v8-dev mailing list v8-dev@googlegroups.com http://groups.google.com/group/v8-dev -~----------~----~----~----~------~----~------~--~---