00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 #include "v8.h"
00029 
00030 #include "bootstrapper.h"
00031 #include "codegen-inl.h"
00032 #include "debug.h"
00033 #include "runtime.h"
00034 #include "serialize.h"
00035 
00036 namespace v8 { namespace internal {
00037 
00038 MacroAssembler::MacroAssembler(void* buffer, int size)
00039     : Assembler(buffer, size),
00040       unresolved_(0),
00041       generating_stub_(false),
00042       allow_stub_calls_(true) {
00043 }
00044 
00045 
00046 static void RecordWriteHelper(MacroAssembler* masm,
00047                               Register object,
00048                               Register addr,
00049                               Register scratch) {
00050   Label fast;
00051 
00052   
00053   
00054   masm->and_(object, ~Page::kPageAlignmentMask);
00055 
00056   
00057   masm->sub(addr, Operand(object));
00058   masm->shr(addr, kObjectAlignmentBits);
00059 
00060   
00061   
00062   masm->cmp(addr, Page::kPageSize / kPointerSize);
00063   masm->j(less, &fast);
00064 
00065   
00066   
00067   
00068   masm->sub(Operand(addr), Immediate(Page::kPageSize / kPointerSize));
00069   
00070   
00071   masm->mov(scratch, Operand(object, Page::kObjectStartOffset
00072                                      + FixedArray::kLengthOffset));
00073   masm->shl(scratch, kObjectAlignmentBits);
00074   
00075   
00076   masm->add(Operand(object), Immediate(Page::kObjectStartOffset
00077                                        + Array::kHeaderSize));
00078   masm->add(object, Operand(scratch));
00079 
00080 
00081   
00082   
00083   
00084   
00085   masm->bind(&fast);
00086   masm->bts(Operand(object, 0), addr);
00087 }
00088 
00089 
00090 class RecordWriteStub : public CodeStub {
00091  public:
00092   RecordWriteStub(Register object, Register addr, Register scratch)
00093       : object_(object), addr_(addr), scratch_(scratch) { }
00094 
00095   void Generate(MacroAssembler* masm);
00096 
00097  private:
00098   Register object_;
00099   Register addr_;
00100   Register scratch_;
00101 
00102 #ifdef DEBUG
00103   void Print() {
00104     PrintF("RecordWriteStub (object reg %d), (addr reg %d), (scratch reg %d)\n",
00105            object_.code(), addr_.code(), scratch_.code());
00106   }
00107 #endif
00108 
00109   
00110   
00111   class ScratchBits: public BitField<uint32_t, 0, 4> {};
00112   class AddressBits: public BitField<uint32_t, 4, 4> {};
00113   class ObjectBits: public BitField<uint32_t, 8, 4> {
00114 };
00115 
00116   Major MajorKey() { return RecordWrite; }
00117 
00118   int MinorKey() {
00119     
00120     return ObjectBits::encode(object_.code()) |
00121            AddressBits::encode(addr_.code()) |
00122            ScratchBits::encode(scratch_.code());
00123   }
00124 };
00125 
00126 
00127 void RecordWriteStub::Generate(MacroAssembler* masm) {
00128   RecordWriteHelper(masm, object_, addr_, scratch_);
00129   masm->ret(0);
00130 }
00131 
00132 
00133 
00134 
00135 
00136 
00137 
00138 void MacroAssembler::RecordWrite(Register object, int offset,
00139                                  Register value, Register scratch) {
00140   
00141   
00142   
00143   Label done;
00144 
00145   
00146   
00147   int32_t new_space_start =
00148       reinterpret_cast<int32_t>(ExternalReference::new_space_start().address());
00149   if (Serializer::enabled() || new_space_start < 0) {
00150     
00151     
00152     test(value, Immediate(kSmiTagMask));
00153     j(zero, &done);
00154     
00155     
00156     mov(value, Operand(object));
00157     and_(value, Heap::NewSpaceMask());
00158     cmp(Operand(value), Immediate(ExternalReference::new_space_start()));
00159     j(equal, &done);
00160   } else {
00161     
00162     shl(value, 31);
00163     
00164     or_(value, Operand(object));
00165     
00166     and_(value, Heap::NewSpaceMask() | (1 << 31));
00167     
00168     
00169     
00170     
00171     xor_(value, new_space_start | (1 << 31));
00172     
00173     j(less_equal, &done);
00174   }
00175 
00176   if ((offset > 0) && (offset < Page::kMaxHeapObjectSize)) {
00177     
00178     mov(value, Operand(object));
00179     and_(value, Page::kPageAlignmentMask);
00180     add(Operand(value), Immediate(offset));
00181     shr(value, kObjectAlignmentBits);
00182 
00183     
00184     
00185     and_(object, ~Page::kPageAlignmentMask);
00186 
00187     
00188     
00189     
00190     
00191     bts(Operand(object, 0), value);
00192   } else {
00193     Register dst = scratch;
00194     if (offset != 0) {
00195       lea(dst, Operand(object, offset));
00196     } else {
00197       
00198       
00199       lea(dst,
00200           Operand(object, dst, times_2, Array::kHeaderSize - kHeapObjectTag));
00201     }
00202     
00203     
00204     if (generating_stub()) {
00205       RecordWriteHelper(this, object, dst, value);
00206     } else {
00207       RecordWriteStub stub(object, dst, value);
00208       CallStub(&stub);
00209     }
00210   }
00211 
00212   bind(&done);
00213 }
00214 
00215 
00216 void MacroAssembler::SaveRegistersToMemory(RegList regs) {
00217   ASSERT((regs & ~kJSCallerSaved) == 0);
00218   
00219   for (int i = 0; i < kNumJSCallerSaved; i++) {
00220     int r = JSCallerSavedCode(i);
00221     if ((regs & (1 << r)) != 0) {
00222       Register reg = { r };
00223       ExternalReference reg_addr =
00224           ExternalReference(Debug_Address::Register(i));
00225       mov(Operand::StaticVariable(reg_addr), reg);
00226     }
00227   }
00228 }
00229 
00230 
00231 void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
00232   ASSERT((regs & ~kJSCallerSaved) == 0);
00233   
00234   for (int i = kNumJSCallerSaved; --i >= 0;) {
00235     int r = JSCallerSavedCode(i);
00236     if ((regs & (1 << r)) != 0) {
00237       Register reg = { r };
00238       ExternalReference reg_addr =
00239           ExternalReference(Debug_Address::Register(i));
00240       mov(reg, Operand::StaticVariable(reg_addr));
00241     }
00242   }
00243 }
00244 
00245 
00246 void MacroAssembler::PushRegistersFromMemory(RegList regs) {
00247   ASSERT((regs & ~kJSCallerSaved) == 0);
00248   
00249   for (int i = 0; i < kNumJSCallerSaved; i++) {
00250     int r = JSCallerSavedCode(i);
00251     if ((regs & (1 << r)) != 0) {
00252       ExternalReference reg_addr =
00253           ExternalReference(Debug_Address::Register(i));
00254       push(Operand::StaticVariable(reg_addr));
00255     }
00256   }
00257 }
00258 
00259 
00260 void MacroAssembler::PopRegistersToMemory(RegList regs) {
00261   ASSERT((regs & ~kJSCallerSaved) == 0);
00262   
00263   for (int i = kNumJSCallerSaved; --i >= 0;) {
00264     int r = JSCallerSavedCode(i);
00265     if ((regs & (1 << r)) != 0) {
00266       ExternalReference reg_addr =
00267           ExternalReference(Debug_Address::Register(i));
00268       pop(Operand::StaticVariable(reg_addr));
00269     }
00270   }
00271 }
00272 
00273 
00274 void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
00275                                                     Register scratch,
00276                                                     RegList regs) {
00277   ASSERT((regs & ~kJSCallerSaved) == 0);
00278   
00279   for (int i = kNumJSCallerSaved; --i >= 0;) {
00280     int r = JSCallerSavedCode(i);
00281     if ((regs & (1 << r)) != 0) {
00282       mov(scratch, Operand(base, 0));
00283       ExternalReference reg_addr =
00284           ExternalReference(Debug_Address::Register(i));
00285       mov(Operand::StaticVariable(reg_addr), scratch);
00286       lea(base, Operand(base, kPointerSize));
00287     }
00288   }
00289 }
00290 
00291 
00292 void MacroAssembler::Set(Register dst, const Immediate& x) {
00293   if (x.is_zero()) {
00294     xor_(dst, Operand(dst));  
00295   } else {
00296     mov(Operand(dst), x);
00297   }
00298 }
00299 
00300 
00301 void MacroAssembler::Set(const Operand& dst, const Immediate& x) {
00302   mov(dst, x);
00303 }
00304 
00305 
00306 void MacroAssembler::FCmp() {
00307   fcompp();
00308   push(eax);
00309   fnstsw_ax();
00310   sahf();
00311   pop(eax);
00312 }
00313 
00314 
00315 void MacroAssembler::EnterFrame(StackFrame::Type type) {
00316   push(ebp);
00317   mov(ebp, Operand(esp));
00318   push(esi);
00319   push(Immediate(Smi::FromInt(type)));
00320   push(Immediate(0));  
00321 }
00322 
00323 
00324 void MacroAssembler::LeaveFrame(StackFrame::Type type) {
00325   if (FLAG_debug_code) {
00326     cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
00327         Immediate(Smi::FromInt(type)));
00328     Check(equal, "stack frame types must match");
00329   }
00330   leave();
00331 }
00332 
00333 
00334 void MacroAssembler::EnterExitFrame(StackFrame::Type type) {
00335   ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG);
00336 
00337   
00338   ASSERT(ExitFrameConstants::kPPDisplacement == +2 * kPointerSize);
00339   ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
00340   ASSERT(ExitFrameConstants::kCallerFPOffset ==  0 * kPointerSize);
00341   push(ebp);
00342   mov(ebp, Operand(esp));
00343 
00344   
00345   ASSERT(ExitFrameConstants::kSPOffset  == -1 * kPointerSize);
00346   push(Immediate(0));  
00347   push(Immediate(type == StackFrame::EXIT_DEBUG ? 1 : 0));
00348 
00349   
00350   ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
00351   ExternalReference context_address(Top::k_context_address);
00352   mov(Operand::StaticVariable(c_entry_fp_address), ebp);
00353   mov(Operand::StaticVariable(context_address), esi);
00354 
00355   
00356   int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
00357   mov(edi, Operand(eax));
00358   lea(esi, Operand(ebp, eax, times_4, offset));
00359 
00360   
00361   
00362   if (type == StackFrame::EXIT_DEBUG) {
00363     
00364     
00365     
00366     
00367     
00368     
00369     PushRegistersFromMemory(kJSCallerSaved);
00370   }
00371 
00372   
00373   sub(Operand(esp), Immediate(2 * kPointerSize));
00374 
00375   
00376   static const int kFrameAlignment = OS::ActivationFrameAlignment();
00377   if (kFrameAlignment > 0) {
00378     ASSERT(IsPowerOf2(kFrameAlignment));
00379     and_(esp, -kFrameAlignment);
00380   }
00381 
00382   
00383   mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);
00384 }
00385 
00386 
00387 void MacroAssembler::LeaveExitFrame(StackFrame::Type type) {
00388   
00389   
00390   if (type == StackFrame::EXIT_DEBUG) {
00391     
00392     
00393     const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
00394     int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize;
00395     lea(ebx, Operand(ebp, kOffset));
00396     CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved);
00397   }
00398 
00399   
00400   mov(ecx, Operand(ebp, 1 * kPointerSize));
00401   mov(ebp, Operand(ebp, 0 * kPointerSize));
00402 
00403   
00404   lea(esp, Operand(esi, 1 * kPointerSize));
00405 
00406   
00407   ExternalReference context_address(Top::k_context_address);
00408   mov(esi, Operand::StaticVariable(context_address));
00409   if (kDebug) {
00410     mov(Operand::StaticVariable(context_address), Immediate(0));
00411   }
00412 
00413   
00414   push(ecx);
00415 
00416   
00417   ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
00418   mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
00419 }
00420 
00421 
00422 void MacroAssembler::PushTryHandler(CodeLocation try_location,
00423                                     HandlerType type) {
00424   ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize);  
00425   
00426   if (try_location == IN_JAVASCRIPT) {
00427     if (type == TRY_CATCH_HANDLER) {
00428       push(Immediate(StackHandler::TRY_CATCH));
00429     } else {
00430       push(Immediate(StackHandler::TRY_FINALLY));
00431     }
00432     push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent)));
00433     push(ebp);
00434     push(edi);
00435   } else {
00436     ASSERT(try_location == IN_JS_ENTRY);
00437     
00438     
00439     
00440     
00441     push(Immediate(StackHandler::ENTRY));
00442     push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent)));
00443     push(Immediate(0));  
00444     push(Immediate(0));  
00445   }
00446   
00447   mov(eax, Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
00448   
00449   mov(Operand::StaticVariable(ExternalReference(Top::k_handler_address)), esp);
00450 }
00451 
00452 
00453 Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
00454                                    JSObject* holder, Register holder_reg,
00455                                    Register scratch,
00456                                    Label* miss) {
00457   
00458   
00459   ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
00460 
00461   
00462   Register reg = object_reg;
00463   int depth = 1;
00464 
00465   
00466   
00467   while (object != holder) {
00468     depth++;
00469 
00470     
00471     
00472     ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
00473 
00474     JSObject* prototype = JSObject::cast(object->GetPrototype());
00475     if (Heap::InNewSpace(prototype)) {
00476       
00477       mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
00478       cmp(Operand(scratch), Immediate(Handle<Map>(object->map())));
00479       
00480       j(not_equal, miss, not_taken);
00481       
00482       
00483       
00484       if (object->IsJSGlobalProxy()) {
00485         CheckAccessGlobalProxy(reg, scratch, miss);
00486 
00487         
00488         
00489         mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
00490       }
00491       
00492       
00493       reg = holder_reg;  
00494       mov(reg, FieldOperand(scratch, Map::kPrototypeOffset));
00495 
00496     } else {
00497       
00498       cmp(FieldOperand(reg, HeapObject::kMapOffset),
00499           Immediate(Handle<Map>(object->map())));
00500       
00501       j(not_equal, miss, not_taken);
00502       
00503       
00504       
00505       if (object->IsJSGlobalProxy()) {
00506         CheckAccessGlobalProxy(reg, scratch, miss);
00507       }
00508       
00509       reg = holder_reg;  
00510       mov(reg, Handle<JSObject>(prototype));
00511     }
00512 
00513     
00514     object = prototype;
00515   }
00516 
00517   
00518   cmp(FieldOperand(reg, HeapObject::kMapOffset),
00519       Immediate(Handle<Map>(holder->map())));
00520   j(not_equal, miss, not_taken);
00521 
00522   
00523   LOG(IntEvent("check-maps-depth", depth));
00524 
00525   
00526   
00527   ASSERT(object == holder);
00528   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
00529   if (object->IsJSGlobalProxy()) {
00530     CheckAccessGlobalProxy(reg, scratch, miss);
00531   }
00532   return reg;
00533 }
00534 
00535 
00536 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
00537                                           Register scratch,
00538                                           Label* miss) {
00539   Label same_contexts;
00540 
00541   ASSERT(!holder_reg.is(scratch));
00542 
00543   
00544   mov(scratch, Operand(ebp, StandardFrameConstants::kContextOffset));
00545 
00546   
00547   if (FLAG_debug_code) {
00548     cmp(Operand(scratch), Immediate(0));
00549     Check(not_equal, "we should not have an empty lexical context");
00550   }
00551   
00552   int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
00553   mov(scratch, FieldOperand(scratch, offset));
00554   mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
00555 
00556   
00557   if (FLAG_debug_code) {
00558     push(scratch);
00559     
00560     mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
00561     cmp(scratch, Factory::global_context_map());
00562     Check(equal, "JSGlobalObject::global_context should be a global context.");
00563     pop(scratch);
00564   }
00565 
00566   
00567   cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
00568   j(equal, &same_contexts, taken);
00569 
00570   
00571   
00572   
00573   
00574   push(holder_reg);
00575   
00576   
00577   
00578   mov(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
00579 
00580   
00581   if (FLAG_debug_code) {
00582     cmp(holder_reg, Factory::null_value());
00583     Check(not_equal, "JSGlobalProxy::context() should not be null.");
00584 
00585     push(holder_reg);
00586     
00587     mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
00588     cmp(holder_reg, Factory::global_context_map());
00589     Check(equal, "JSGlobalObject::global_context should be a global context.");
00590     pop(holder_reg);
00591   }
00592 
00593   int token_offset = Context::kHeaderSize +
00594                      Context::SECURITY_TOKEN_INDEX * kPointerSize;
00595   mov(scratch, FieldOperand(scratch, token_offset));
00596   cmp(scratch, FieldOperand(holder_reg, token_offset));
00597   pop(holder_reg);
00598   j(not_equal, miss, not_taken);
00599 
00600   bind(&same_contexts);
00601 }
00602 
00603 
00604 void MacroAssembler::NegativeZeroTest(Register result,
00605                                       Register op,
00606                                       Label* then_label) {
00607   Label ok;
00608   test(result, Operand(result));
00609   j(not_zero, &ok, taken);
00610   test(op, Operand(op));
00611   j(sign, then_label, not_taken);
00612   bind(&ok);
00613 }
00614 
00615 
00616 void MacroAssembler::NegativeZeroTest(Register result,
00617                                       Register op1,
00618                                       Register op2,
00619                                       Register scratch,
00620                                       Label* then_label) {
00621   Label ok;
00622   test(result, Operand(result));
00623   j(not_zero, &ok, taken);
00624   mov(scratch, Operand(op1));
00625   or_(scratch, Operand(op2));
00626   j(sign, then_label, not_taken);
00627   bind(&ok);
00628 }
00629 
00630 
00631 void MacroAssembler::TryGetFunctionPrototype(Register function,
00632                                              Register result,
00633                                              Register scratch,
00634                                              Label* miss) {
00635   
00636   test(function, Immediate(kSmiTagMask));
00637   j(zero, miss, not_taken);
00638 
00639   
00640   mov(result, FieldOperand(function, HeapObject::kMapOffset));
00641   movzx_b(scratch, FieldOperand(result, Map::kInstanceTypeOffset));
00642   cmp(scratch, JS_FUNCTION_TYPE);
00643   j(not_equal, miss, not_taken);
00644 
00645   
00646   Label non_instance;
00647   movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset));
00648   test(scratch, Immediate(1 << Map::kHasNonInstancePrototype));
00649   j(not_zero, &non_instance, not_taken);
00650 
00651   
00652   mov(result,
00653       FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
00654 
00655   
00656   
00657   
00658   cmp(Operand(result), Immediate(Factory::the_hole_value()));
00659   j(equal, miss, not_taken);
00660 
00661   
00662   Label done;
00663   mov(scratch, FieldOperand(result, HeapObject::kMapOffset));
00664   movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
00665   cmp(scratch, MAP_TYPE);
00666   j(not_equal, &done);
00667 
00668   
00669   mov(result, FieldOperand(result, Map::kPrototypeOffset));
00670   jmp(&done);
00671 
00672   
00673   
00674   bind(&non_instance);
00675   mov(result, FieldOperand(result, Map::kConstructorOffset));
00676 
00677   
00678   bind(&done);
00679 }
00680 
00681 
00682 void MacroAssembler::CallStub(CodeStub* stub) {
00683   ASSERT(allow_stub_calls());  
00684   call(stub->GetCode(), RelocInfo::CODE_TARGET);
00685 }
00686 
00687 
00688 void MacroAssembler::StubReturn(int argc) {
00689   ASSERT(argc >= 1 && generating_stub());
00690   ret((argc - 1) * kPointerSize);
00691 }
00692 
00693 
00694 void MacroAssembler::IllegalOperation(int num_arguments) {
00695   if (num_arguments > 0) {
00696     add(Operand(esp), Immediate(num_arguments * kPointerSize));
00697   }
00698   mov(Operand(eax), Immediate(Factory::undefined_value()));
00699 }
00700 
00701 
00702 void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
00703   CallRuntime(Runtime::FunctionForId(id), num_arguments);
00704 }
00705 
00706 
00707 void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
00708   
00709   
00710   
00711   if (f->nargs >= 0 && f->nargs != num_arguments) {
00712     IllegalOperation(num_arguments);
00713     return;
00714   }
00715 
00716   Runtime::FunctionId function_id =
00717       static_cast<Runtime::FunctionId>(f->stub_id);
00718   RuntimeStub stub(function_id, num_arguments);
00719   CallStub(&stub);
00720 }
00721 
00722 
00723 void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
00724                                      int num_arguments) {
00725   
00726   
00727   
00728   
00729   mov(Operand(eax), Immediate(num_arguments));
00730   JumpToBuiltin(ext);
00731 }
00732 
00733 
00734 void MacroAssembler::JumpToBuiltin(const ExternalReference& ext) {
00735   
00736   mov(Operand(ebx), Immediate(ext));
00737   CEntryStub ces;
00738   jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
00739 }
00740 
00741 
00742 void MacroAssembler::InvokePrologue(const ParameterCount& expected,
00743                                     const ParameterCount& actual,
00744                                     Handle<Code> code_constant,
00745                                     const Operand& code_operand,
00746                                     Label* done,
00747                                     InvokeFlag flag) {
00748   bool definitely_matches = false;
00749   Label invoke;
00750   if (expected.is_immediate()) {
00751     ASSERT(actual.is_immediate());
00752     if (expected.immediate() == actual.immediate()) {
00753       definitely_matches = true;
00754     } else {
00755       mov(eax, actual.immediate());
00756       const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
00757       if (expected.immediate() == sentinel) {
00758         
00759         
00760         
00761         
00762         definitely_matches = true;
00763       } else {
00764         mov(ebx, expected.immediate());
00765       }
00766     }
00767   } else {
00768     if (actual.is_immediate()) {
00769       
00770       
00771       
00772       cmp(expected.reg(), actual.immediate());
00773       j(equal, &invoke);
00774       ASSERT(expected.reg().is(ebx));
00775       mov(eax, actual.immediate());
00776     } else if (!expected.reg().is(actual.reg())) {
00777       
00778       
00779       cmp(expected.reg(), Operand(actual.reg()));
00780       j(equal, &invoke);
00781       ASSERT(actual.reg().is(eax));
00782       ASSERT(expected.reg().is(ebx));
00783     }
00784   }
00785 
00786   if (!definitely_matches) {
00787     Handle<Code> adaptor =
00788         Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
00789     if (!code_constant.is_null()) {
00790       mov(Operand(edx), Immediate(code_constant));
00791       add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
00792     } else if (!code_operand.is_reg(edx)) {
00793       mov(edx, code_operand);
00794     }
00795 
00796     if (flag == CALL_FUNCTION) {
00797       call(adaptor, RelocInfo::CODE_TARGET);
00798       jmp(done);
00799     } else {
00800       jmp(adaptor, RelocInfo::CODE_TARGET);
00801     }
00802     bind(&invoke);
00803   }
00804 }
00805 
00806 
00807 void MacroAssembler::InvokeCode(const Operand& code,
00808                                 const ParameterCount& expected,
00809                                 const ParameterCount& actual,
00810                                 InvokeFlag flag) {
00811   Label done;
00812   InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
00813   if (flag == CALL_FUNCTION) {
00814     call(code);
00815   } else {
00816     ASSERT(flag == JUMP_FUNCTION);
00817     jmp(code);
00818   }
00819   bind(&done);
00820 }
00821 
00822 
00823 void MacroAssembler::InvokeCode(Handle<Code> code,
00824                                 const ParameterCount& expected,
00825                                 const ParameterCount& actual,
00826                                 RelocInfo::Mode rmode,
00827                                 InvokeFlag flag) {
00828   Label done;
00829   Operand dummy(eax);
00830   InvokePrologue(expected, actual, code, dummy, &done, flag);
00831   if (flag == CALL_FUNCTION) {
00832     call(code, rmode);
00833   } else {
00834     ASSERT(flag == JUMP_FUNCTION);
00835     jmp(code, rmode);
00836   }
00837   bind(&done);
00838 }
00839 
00840 
00841 void MacroAssembler::InvokeFunction(Register fun,
00842                                     const ParameterCount& actual,
00843                                     InvokeFlag flag) {
00844   ASSERT(fun.is(edi));
00845   mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
00846   mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
00847   mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
00848   mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
00849   lea(edx, FieldOperand(edx, Code::kHeaderSize));
00850 
00851   ParameterCount expected(ebx);
00852   InvokeCode(Operand(edx), expected, actual, flag);
00853 }
00854 
00855 
00856 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
00857   bool resolved;
00858   Handle<Code> code = ResolveBuiltin(id, &resolved);
00859 
00860     
00861   ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
00862 
00863   
00864   
00865   
00866   ParameterCount expected(0);
00867   InvokeCode(Handle<Code>(code), expected, expected,
00868              RelocInfo::CODE_TARGET, flag);
00869 
00870   const char* name = Builtins::GetName(id);
00871   int argc = Builtins::GetArgumentsCount(id);
00872 
00873   if (!resolved) {
00874     uint32_t flags =
00875         Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
00876         Bootstrapper::FixupFlagsIsPCRelative::encode(true);
00877     Unresolved entry = { pc_offset() - sizeof(int32_t), flags, name };
00878     unresolved_.Add(entry);
00879   }
00880 }
00881 
00882 
00883 void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
00884   bool resolved;
00885   Handle<Code> code = ResolveBuiltin(id, &resolved);
00886 
00887   const char* name = Builtins::GetName(id);
00888   int argc = Builtins::GetArgumentsCount(id);
00889 
00890   mov(Operand(target), Immediate(code));
00891   if (!resolved) {
00892     uint32_t flags =
00893         Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
00894         Bootstrapper::FixupFlagsIsPCRelative::encode(false);
00895     Unresolved entry = { pc_offset() - sizeof(int32_t), flags, name };
00896     unresolved_.Add(entry);
00897   }
00898   add(Operand(target), Immediate(Code::kHeaderSize - kHeapObjectTag));
00899 }
00900 
00901 
00902 Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
00903                                             bool* resolved) {
00904   
00905   
00906   
00907   
00908   
00909   mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
00910   mov(edx, FieldOperand(edx, GlobalObject::kBuiltinsOffset));
00911   int builtins_offset =
00912       JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
00913   mov(edi, FieldOperand(edx, builtins_offset));
00914 
00915 
00916   return Builtins::GetCode(id, resolved);
00917 }
00918 
00919 
00920 void MacroAssembler::Ret() {
00921   ret(0);
00922 }
00923 
00924 
00925 void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
00926   if (FLAG_native_code_counters && counter->Enabled()) {
00927     mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
00928   }
00929 }
00930 
00931 
00932 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
00933   ASSERT(value > 0);
00934   if (FLAG_native_code_counters && counter->Enabled()) {
00935     Operand operand = Operand::StaticVariable(ExternalReference(counter));
00936     if (value == 1) {
00937       inc(operand);
00938     } else {
00939       add(operand, Immediate(value));
00940     }
00941   }
00942 }
00943 
00944 
00945 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
00946   ASSERT(value > 0);
00947   if (FLAG_native_code_counters && counter->Enabled()) {
00948     Operand operand = Operand::StaticVariable(ExternalReference(counter));
00949     if (value == 1) {
00950       dec(operand);
00951     } else {
00952       sub(operand, Immediate(value));
00953     }
00954   }
00955 }
00956 
00957 
00958 void MacroAssembler::Assert(Condition cc, const char* msg) {
00959   if (FLAG_debug_code) Check(cc, msg);
00960 }
00961 
00962 
00963 void MacroAssembler::Check(Condition cc, const char* msg) {
00964   Label L;
00965   j(cc, &L, taken);
00966   Abort(msg);
00967   
00968   bind(&L);
00969 }
00970 
00971 
00972 void MacroAssembler::Abort(const char* msg) {
00973   
00974   
00975   
00976   
00977   
00978   intptr_t p1 = reinterpret_cast<intptr_t>(msg);
00979   intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
00980   ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
00981 #ifdef DEBUG
00982   if (msg != NULL) {
00983     RecordComment("Abort message: ");
00984     RecordComment(msg);
00985   }
00986 #endif
00987   push(eax);
00988   push(Immediate(p0));
00989   push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0))));
00990   CallRuntime(Runtime::kAbort, 2);
00991   
00992 }
00993 
00994 
00995 CodePatcher::CodePatcher(byte* address, int size)
00996   : address_(address), size_(size), masm_(address, size + Assembler::kGap) {
00997   
00998   
00999   
01000   ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
01001 }
01002 
01003 
01004 CodePatcher::~CodePatcher() {
01005   
01006   CPU::FlushICache(address_, size_);
01007 
01008   
01009   ASSERT(masm_.pc_ == address_ + size_);
01010   ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
01011 }
01012 
01013 
01014 } }