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 } }