📄 macro-assembler-ia32.cc.svn-base
字号:
fcompp(); push(eax); fnstsw_ax(); sahf(); pop(eax);}void MacroAssembler::EnterInternalFrame() { int type = StackFrame::INTERNAL; push(ebp); mov(ebp, Operand(esp)); push(esi); push(Immediate(Smi::FromInt(type))); push(Immediate(0)); // Push an empty code cache slot.}void MacroAssembler::LeaveInternalFrame() { if (FLAG_debug_code) { StackFrame::Type type = StackFrame::INTERNAL; cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset), Immediate(Smi::FromInt(type))); Check(equal, "stack frame types must match"); } leave();}void MacroAssembler::EnterExitFrame(StackFrame::Type type) { ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG); // Setup the frame structure on the stack. ASSERT(ExitFrameConstants::kPPDisplacement == +2 * kPointerSize); ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize); ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize); push(ebp); mov(ebp, Operand(esp)); // Reserve room for entry stack pointer and push the debug marker. ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize); push(Immediate(0)); // saved entry sp, patched before call push(Immediate(type == StackFrame::EXIT_DEBUG ? 1 : 0)); // Save the frame pointer and the context in top. ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); ExternalReference context_address(Top::k_context_address); mov(Operand::StaticVariable(c_entry_fp_address), ebp); mov(Operand::StaticVariable(context_address), esi); // Setup argc and argv in callee-saved registers. int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; mov(edi, Operand(eax)); lea(esi, Operand(ebp, eax, times_4, offset)); // Save the state of all registers to the stack from the memory // location. This is needed to allow nested break points. if (type == StackFrame::EXIT_DEBUG) { // TODO(1243899): This should be symmetric to // CopyRegistersFromStackToMemory() but it isn't! esp is assumed // correct here, but computed for the other call. Very error // prone! FIX THIS. Actually there are deeper problems with // register saving than this asymmetry (see the bug report // associated with this issue). PushRegistersFromMemory(kJSCallerSaved); } // Reserve space for two arguments: argc and argv. sub(Operand(esp), Immediate(2 * kPointerSize)); // Get the required frame alignment for the OS. static const int kFrameAlignment = OS::ActivationFrameAlignment(); if (kFrameAlignment > 0) { ASSERT(IsPowerOf2(kFrameAlignment)); and_(esp, -kFrameAlignment); } // Patch the saved entry sp. mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);}void MacroAssembler::LeaveExitFrame(StackFrame::Type type) { // Restore the memory copy of the registers by digging them out from // the stack. This is needed to allow nested break points. if (type == StackFrame::EXIT_DEBUG) { // It's okay to clobber register ebx below because we don't need // the function pointer after this. const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize; int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize; lea(ebx, Operand(ebp, kOffset)); CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved); } // Get the return address from the stack and restore the frame pointer. mov(ecx, Operand(ebp, 1 * kPointerSize)); mov(ebp, Operand(ebp, 0 * kPointerSize)); // Pop the arguments and the receiver from the caller stack. lea(esp, Operand(esi, 1 * kPointerSize)); // Restore current context from top and clear it in debug mode. ExternalReference context_address(Top::k_context_address); mov(esi, Operand::StaticVariable(context_address)); if (kDebug) { mov(Operand::StaticVariable(context_address), Immediate(0)); } // Push the return address to get ready to return. push(ecx); // Clear the top frame. ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));}void MacroAssembler::PushTryHandler(CodeLocation try_location, HandlerType type) { ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code // The pc (return address) is already on TOS. if (try_location == IN_JAVASCRIPT) { if (type == TRY_CATCH_HANDLER) { push(Immediate(StackHandler::TRY_CATCH)); } else { push(Immediate(StackHandler::TRY_FINALLY)); } push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent))); push(ebp); push(edi); } else { ASSERT(try_location == IN_JS_ENTRY); // The parameter pointer is meaningless here and ebp does not // point to a JS frame. So we save NULL for both pp and ebp. We // expect the code throwing an exception to check ebp before // dereferencing it to restore the context. push(Immediate(StackHandler::ENTRY)); push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent))); push(Immediate(0)); // NULL frame pointer push(Immediate(0)); // NULL parameter pointer } // Cached TOS. mov(eax, Operand::StaticVariable(ExternalReference(Top::k_handler_address))); // Link this handler. mov(Operand::StaticVariable(ExternalReference(Top::k_handler_address)), esp);}Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg, JSObject* holder, Register holder_reg, Register scratch, Label* miss) { // Make sure there's no overlap between scratch and the other // registers. ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg)); // Keep track of the current object in register reg. Register reg = object_reg; int depth = 1; // Check the maps in the prototype chain. // Traverse the prototype chain from the object and do map checks. while (object != holder) { depth++; // Only global objects and objects that do not require access // checks are allowed in stubs. ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded()); JSObject* prototype = JSObject::cast(object->GetPrototype()); if (Heap::InNewSpace(prototype)) { // Get the map of the current object. mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); cmp(Operand(scratch), Immediate(Handle<Map>(object->map()))); // Branch on the result of the map check. j(not_equal, miss, not_taken); // Check access rights to the global object. This has to happen // after the map check so that we know that the object is // actually a global object. if (object->IsJSGlobalObject()) { CheckAccessGlobal(reg, scratch, miss); // Restore scratch register to be the map of the object. We // load the prototype from the map in the scratch register. mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); } // The prototype is in new space; we cannot store a reference // to it in the code. Load it from the map. reg = holder_reg; // from now the object is in holder_reg mov(reg, FieldOperand(scratch, Map::kPrototypeOffset)); } else { // Check the map of the current object. cmp(FieldOperand(reg, HeapObject::kMapOffset), Immediate(Handle<Map>(object->map()))); // Branch on the result of the map check. j(not_equal, miss, not_taken); // Check access rights to the global object. This has to happen // after the map check so that we know that the object is // actually a global object. if (object->IsJSGlobalObject()) { CheckAccessGlobal(reg, scratch, miss); } // The prototype is in old space; load it directly. reg = holder_reg; // from now the object is in holder_reg mov(reg, Handle<JSObject>(prototype)); } // Go to the next object in the prototype chain. object = prototype; } // Check the holder map. cmp(FieldOperand(reg, HeapObject::kMapOffset), Immediate(Handle<Map>(holder->map()))); j(not_equal, miss, not_taken); // Log the check depth. LOG(IntEvent("check-maps-depth", depth)); // Perform security check for access to the global object and return // the holder register. ASSERT(object == holder); ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded()); if (object->IsJSGlobalObject()) { CheckAccessGlobal(reg, scratch, miss); } return reg;}void MacroAssembler::CheckAccessGlobal(Register holder_reg, Register scratch, Label* miss) { ASSERT(!holder_reg.is(scratch)); // Load the security context. ExternalReference security_context = ExternalReference(Top::k_security_context_address); mov(scratch, Operand::StaticVariable(security_context)); // When generating debug code, make sure the security context is set. if (FLAG_debug_code) { cmp(Operand(scratch), Immediate(0)); Check(not_equal, "we should not have an empty security context"); } // Load the global object of the security context. int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; mov(scratch, FieldOperand(scratch, offset)); // Check that the security token in the calling global object is // compatible with the security token in the receiving global // object. mov(scratch, FieldOperand(scratch, JSGlobalObject::kSecurityTokenOffset)); cmp(scratch, FieldOperand(holder_reg, JSGlobalObject::kSecurityTokenOffset)); j(not_equal, miss, not_taken);}void MacroAssembler::NegativeZeroTest(Register result, Register op, Label* then_label) { Label ok; test(result, Operand(result)); j(not_zero, &ok, taken); test(op, Operand(op)); j(sign, then_label, not_taken); bind(&ok);}void MacroAssembler::NegativeZeroTest(Register result, Register op1, Register op2, Register scratch, Label* then_label) { Label ok; test(result, Operand(result)); j(not_zero, &ok, taken); mov(scratch, Operand(op1)); or_(scratch, Operand(op2)); j(sign, then_label, not_taken); bind(&ok);}void MacroAssembler::CallStub(CodeStub* stub) { ASSERT(allow_stub_calls()); // calls are not allowed in some stubs call(stub->GetCode(), RelocInfo::CODE_TARGET);}void MacroAssembler::StubReturn(int argc) { ASSERT(argc >= 1 && generating_stub()); ret((argc - 1) * kPointerSize);}void MacroAssembler::IllegalOperation() { push(Immediate(Factory::undefined_value()));}void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { CallRuntime(Runtime::FunctionForId(id), num_arguments);}void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { // If the expected number of arguments of the runtime function is // constant, we check that the actual number of arguments match the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -