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 "scopes.h"
00034 #include "runtime.h"
00035
00036 namespace v8 { namespace internal {
00037
00038 #define __ masm_->
00039
00040
00041
00042
00043 VirtualFrame::VirtualFrame(CodeGenerator* cgen) {
00044 ASSERT(cgen->scope() != NULL);
00045
00046 masm_ = cgen->masm();
00047 frame_local_count_ = cgen->scope()->num_stack_slots();
00048 parameter_count_ = cgen->scope()->num_parameters();
00049 }
00050
00051
00052 void VirtualFrame::Enter() {
00053 Comment cmnt(masm_, "[ Enter JS frame");
00054 __ push(ebp);
00055 __ mov(ebp, Operand(esp));
00056
00057
00058 __ push(esi);
00059 __ push(edi);
00060
00061
00062 if (FLAG_debug_code) {
00063 __ Set(edi, Immediate(reinterpret_cast<int>(kZapValue)));
00064 }
00065 }
00066
00067
00068 void VirtualFrame::Exit() {
00069 Comment cmnt(masm_, "[ Exit JS frame");
00070
00071
00072 __ RecordJSReturn();
00073
00074
00075
00076
00077
00078 __ mov(esp, Operand(ebp));
00079 __ pop(ebp);
00080 }
00081
00082
00083 void VirtualFrame::AllocateLocals() {
00084 if (frame_local_count_ > 0) {
00085 Comment cmnt(masm_, "[ Allocate space for locals");
00086 __ Set(eax, Immediate(Factory::undefined_value()));
00087 for (int i = 0; i < frame_local_count_; i++) {
00088 __ push(eax);
00089 }
00090 }
00091 }
00092
00093
00094 void VirtualFrame::Drop(int count) {
00095 ASSERT(count >= 0);
00096 if (count > 0) {
00097 __ add(Operand(esp), Immediate(count * kPointerSize));
00098 }
00099 }
00100
00101
00102 void VirtualFrame::Pop() {
00103 __ add(Operand(esp), Immediate(kPointerSize));
00104 }
00105
00106
00107 void VirtualFrame::Pop(Register reg) {
00108 __ pop(reg);
00109 }
00110
00111
00112 void VirtualFrame::Pop(Operand operand) {
00113 __ pop(operand);
00114 }
00115
00116
00117 void VirtualFrame::Push(Register reg) {
00118 __ push(reg);
00119 }
00120
00121
00122 void VirtualFrame::Push(Operand operand) {
00123 __ push(operand);
00124 }
00125
00126
00127 void VirtualFrame::Push(Immediate immediate) {
00128 __ push(immediate);
00129 }
00130
00131
00132
00133
00134
00135 CodeGenState::CodeGenState(CodeGenerator* owner)
00136 : owner_(owner),
00137 typeof_state_(NOT_INSIDE_TYPEOF),
00138 true_target_(NULL),
00139 false_target_(NULL),
00140 previous_(NULL) {
00141 owner_->set_state(this);
00142 }
00143
00144
00145 CodeGenState::CodeGenState(CodeGenerator* owner,
00146 TypeofState typeof_state,
00147 Label* true_target,
00148 Label* false_target)
00149 : owner_(owner),
00150 typeof_state_(typeof_state),
00151 true_target_(true_target),
00152 false_target_(false_target),
00153 previous_(owner->state()) {
00154 owner_->set_state(this);
00155 }
00156
00157
00158 CodeGenState::~CodeGenState() {
00159 ASSERT(owner_->state() == this);
00160 owner_->set_state(previous_);
00161 }
00162
00163
00164
00165
00166
00167 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
00168 bool is_eval)
00169 : is_eval_(is_eval),
00170 script_(script),
00171 deferred_(8),
00172 masm_(new MacroAssembler(NULL, buffer_size)),
00173 scope_(NULL),
00174 frame_(NULL),
00175 cc_reg_(no_condition),
00176 state_(NULL),
00177 is_inside_try_(false),
00178 break_stack_height_(0),
00179 loop_nesting_(0) {
00180 }
00181
00182
00183
00184
00185
00186
00187
00188
00189 void CodeGenerator::GenCode(FunctionLiteral* fun) {
00190
00191 __ RecordPosition(fun->start_position());
00192
00193 ZoneList<Statement*>* body = fun->body();
00194
00195
00196 ASSERT(scope_ == NULL);
00197 scope_ = fun->scope();
00198 ASSERT(frame_ == NULL);
00199 VirtualFrame virtual_frame(this);
00200 frame_ = &virtual_frame;
00201 cc_reg_ = no_condition;
00202 {
00203 CodeGenState state(this);
00204
00205
00206
00207
00208
00209
00210
00211
00212 frame_->Enter();
00213
00214 #ifdef DEBUG
00215 if (strlen(FLAG_stop_at) > 0 &&
00216 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
00217 __ int3();
00218 }
00219 #endif
00220
00221
00222
00223
00224
00225
00226
00227
00228 bool arguments_object_allocated = false;
00229 bool arguments_object_saved = false;
00230
00231
00232
00233
00234 if (scope_->arguments() != NULL) {
00235 ASSERT(scope_->arguments_shadow() != NULL);
00236 Comment cmnt(masm_, "[ allocate arguments object");
00237 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
00238 __ lea(eax, frame_->Receiver());
00239 frame_->Push(frame_->Function());
00240 frame_->Push(eax);
00241 frame_->Push(Immediate(Smi::FromInt(scope_->num_parameters())));
00242 __ CallStub(&stub);
00243 __ mov(ecx, Operand(eax));
00244 arguments_object_allocated = true;
00245 }
00246
00247
00248 frame_->AllocateLocals();
00249
00250 if (scope_->num_heap_slots() > 0) {
00251 Comment cmnt(masm_, "[ allocate local context");
00252
00253 if (arguments_object_allocated && !arguments_object_saved) {
00254 frame_->Push(ecx);
00255 arguments_object_saved = true;
00256 }
00257
00258
00259 frame_->Push(frame_->Function());
00260 __ CallRuntime(Runtime::kNewContext, 1);
00261
00262 if (kDebug) {
00263 Label verified_true;
00264
00265 __ cmp(eax, Operand(esi));
00266 __ j(equal, &verified_true);
00267 __ int3();
00268 __ bind(&verified_true);
00269 }
00270
00271
00272 __ mov(frame_->Context(), esi);
00273
00274 }
00275
00276
00277
00278
00279
00280 {
00281 Comment cmnt2(masm_, "[ copy context parameters into .context");
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291 for (int i = 0; i < scope_->num_parameters(); i++) {
00292 Variable* par = scope_->parameter(i);
00293 Slot* slot = par->slot();
00294 if (slot != NULL && slot->type() == Slot::CONTEXT) {
00295
00296 if (arguments_object_allocated && !arguments_object_saved) {
00297 frame_->Push(ecx);
00298 arguments_object_saved = true;
00299 }
00300 ASSERT(!scope_->is_global_scope());
00301 __ mov(eax, frame_->Parameter(i));
00302
00303 __ mov(SlotOperand(slot, ecx), eax);
00304 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
00305 __ RecordWrite(ecx, offset, eax, ebx);
00306 }
00307 }
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317 if (arguments_object_allocated) {
00318 ASSERT(scope_->arguments() != NULL);
00319 ASSERT(scope_->arguments_shadow() != NULL);
00320 Comment cmnt(masm_, "[ store arguments object");
00321 { Reference shadow_ref(this, scope_->arguments_shadow());
00322 ASSERT(shadow_ref.is_slot());
00323 { Reference arguments_ref(this, scope_->arguments());
00324 ASSERT(arguments_ref.is_slot());
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334 if (!arguments_object_saved) {
00335 frame_->Push(ecx);
00336 }
00337 arguments_ref.SetValue(NOT_CONST_INIT);
00338 }
00339 shadow_ref.SetValue(NOT_CONST_INIT);
00340 }
00341 frame_->Pop();
00342 }
00343
00344
00345
00346
00347
00348 if (scope_->HasIllegalRedeclaration()) {
00349 Comment cmnt(masm_, "[ illegal redeclarations");
00350 scope_->VisitIllegalRedeclaration(this);
00351 } else {
00352 Comment cmnt(masm_, "[ declarations");
00353 ProcessDeclarations(scope_->declarations());
00354
00355
00356 if (HasStackOverflow()) return;
00357 }
00358
00359 if (FLAG_trace) {
00360 __ CallRuntime(Runtime::kTraceEnter, 0);
00361
00362 }
00363 CheckStack();
00364
00365
00366
00367
00368 if (!scope_->HasIllegalRedeclaration()) {
00369 Comment cmnt(masm_, "[ function body");
00370 #ifdef DEBUG
00371 bool is_builtin = Bootstrapper::IsActive();
00372 bool should_trace =
00373 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
00374 if (should_trace) {
00375 __ CallRuntime(Runtime::kDebugTrace, 0);
00376
00377 }
00378 #endif
00379 VisitStatements(body);
00380
00381
00382 if (body->is_empty() || body->last()->AsReturnStatement() == NULL) {
00383 Literal undefined(Factory::undefined_value());
00384 ReturnStatement statement(&undefined);
00385 statement.set_statement_pos(fun->end_position());
00386 VisitReturnStatement(&statement);
00387 }
00388 }
00389 }
00390
00391
00392 scope_ = NULL;
00393 frame_ = NULL;
00394 ASSERT(!has_cc());
00395 ASSERT(state_ == NULL);
00396 }
00397
00398
00399 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
00400
00401
00402
00403
00404
00405
00406
00407
00408 ASSERT(slot != NULL);
00409 int index = slot->index();
00410 switch (slot->type()) {
00411 case Slot::PARAMETER:
00412 return frame_->Parameter(index);
00413
00414 case Slot::LOCAL:
00415 return frame_->Local(index);
00416
00417 case Slot::CONTEXT: {
00418
00419 ASSERT(!tmp.is(esi));
00420 Register context = esi;
00421 int chain_length = scope()->ContextChainLength(slot->var()->scope());
00422 for (int i = chain_length; i-- > 0;) {
00423
00424
00425
00426
00427 __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
00428
00429 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
00430 context = tmp;
00431 }
00432
00433
00434
00435
00436
00437
00438
00439 __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
00440 return ContextOperand(tmp, index);
00441 }
00442
00443 default:
00444 UNREACHABLE();
00445 return Operand(eax);
00446 }
00447 }
00448
00449
00450
00451
00452
00453
00454
00455 void CodeGenerator::LoadCondition(Expression* x,
00456 TypeofState typeof_state,
00457 Label* true_target,
00458 Label* false_target,
00459 bool force_cc) {
00460 ASSERT(!has_cc());
00461
00462 { CodeGenState new_state(this, typeof_state, true_target, false_target);
00463 Visit(x);
00464 }
00465 if (force_cc && !has_cc()) {
00466 ToBoolean(true_target, false_target);
00467 }
00468 ASSERT(has_cc() || !force_cc);
00469 }
00470
00471
00472 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
00473 Label true_target;
00474 Label false_target;
00475 LoadCondition(x, typeof_state, &true_target, &false_target, false);
00476
00477 if (has_cc()) {
00478
00479
00480 Label loaded, materialize_true;
00481 __ j(cc_reg_, &materialize_true);
00482 frame_->Push(Immediate(Factory::false_value()));
00483 __ jmp(&loaded);
00484 __ bind(&materialize_true);
00485 frame_->Push(Immediate(Factory::true_value()));
00486 __ bind(&loaded);
00487 cc_reg_ = no_condition;
00488 }
00489
00490 if (true_target.is_linked() || false_target.is_linked()) {
00491
00492
00493
00494 Label loaded;
00495 __ jmp(&loaded);
00496 bool both = true_target.is_linked() && false_target.is_linked();
00497
00498 if (true_target.is_linked()) {
00499 __ bind(&true_target);
00500 frame_->Push(Immediate(Factory::true_value()));
00501 }
00502
00503
00504 if (both)
00505 __ jmp(&loaded);
00506
00507 if (false_target.is_linked()) {
00508 __ bind(&false_target);
00509 frame_->Push(Immediate(Factory::false_value()));
00510 }
00511
00512 __ bind(&loaded);
00513 }
00514 ASSERT(!has_cc());
00515 }
00516
00517
00518 void CodeGenerator::LoadGlobal() {
00519 frame_->Push(GlobalObject());
00520 }
00521
00522
00523 void CodeGenerator::LoadGlobalReceiver(Register scratch) {
00524 __ mov(scratch, GlobalObject());
00525 frame_->Push(FieldOperand(scratch, GlobalObject::kGlobalReceiverOffset));
00526 }
00527
00528
00529
00530
00531
00532 void CodeGenerator::LoadTypeofExpression(Expression* x) {
00533 Variable* variable = x->AsVariableProxy()->AsVariable();
00534 if (variable != NULL && !variable->is_this() && variable->is_global()) {
00535
00536
00537
00538 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX);
00539 Literal key(variable->name());
00540
00541
00542 Property property(&global, &key, RelocInfo::kNoPosition);
00543 Load(&property);
00544 } else {
00545 Load(x, INSIDE_TYPEOF);
00546 }
00547 }
00548
00549
00550 Reference::Reference(CodeGenerator* cgen, Expression* expression)
00551 : cgen_(cgen), expression_(expression), type_(ILLEGAL) {
00552 cgen->LoadReference(this);
00553 }
00554
00555
00556 Reference::~Reference() {
00557 cgen_->UnloadReference(this);
00558 }
00559
00560
00561 void CodeGenerator::LoadReference(Reference* ref) {
00562 Comment cmnt(masm_, "[ LoadReference");
00563 Expression* e = ref->expression();
00564 Property* property = e->AsProperty();
00565 Variable* var = e->AsVariableProxy()->AsVariable();
00566
00567 if (property != NULL) {
00568
00569
00570 Load(property->obj());
00571
00572
00573
00574
00575 Literal* literal = property->key()->AsLiteral();
00576 uint32_t dummy;
00577 if (literal != NULL &&
00578 literal->handle()->IsSymbol() &&
00579 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
00580 ref->set_type(Reference::NAMED);
00581 } else {
00582 Load(property->key());
00583 ref->set_type(Reference::KEYED);
00584 }
00585 } else if (var != NULL) {
00586
00587
00588 if (var->is_global()) {
00589 LoadGlobal();
00590 ref->set_type(Reference::NAMED);
00591 } else {
00592 ASSERT(var->slot() != NULL);
00593 ref->set_type(Reference::SLOT);
00594 }
00595 } else {
00596
00597 Load(e);
00598 __ CallRuntime(Runtime::kThrowReferenceError, 1);
00599 }
00600 }
00601
00602
00603 void CodeGenerator::UnloadReference(Reference* ref) {
00604
00605 Comment cmnt(masm_, "[ UnloadReference");
00606 int size = ref->size();
00607 if (size <= 0) {
00608
00609 } else if (size == 1) {
00610 frame_->Pop(eax);
00611 __ mov(frame_->Top(), eax);
00612 } else {
00613 frame_->Pop(eax);
00614 frame_->Drop(size);
00615 frame_->Push(eax);
00616 }
00617 }
00618
00619
00620 class ToBooleanStub: public CodeStub {
00621 public:
00622 ToBooleanStub() { }
00623
00624 void Generate(MacroAssembler* masm);
00625
00626 private:
00627 Major MajorKey() { return ToBoolean; }
00628 int MinorKey() { return 0; }
00629 };
00630
00631
00632
00633
00634
00635 void CodeGenerator::ToBoolean(Label* true_target, Label* false_target) {
00636 Comment cmnt(masm_, "[ ToBoolean");
00637
00638
00639 frame_->Pop(eax);
00640
00641
00642
00643
00644 __ cmp(eax, Factory::false_value());
00645 __ j(equal, false_target);
00646
00647
00648 __ cmp(eax, Factory::true_value());
00649 __ j(equal, true_target);
00650
00651
00652 __ cmp(eax, Factory::undefined_value());
00653 __ j(equal, false_target);
00654
00655
00656 ASSERT(kSmiTag == 0);
00657 __ test(eax, Operand(eax));
00658 __ j(zero, false_target);
00659 __ test(eax, Immediate(kSmiTagMask));
00660 __ j(zero, true_target);
00661
00662
00663 frame_->Push(eax);
00664 ToBooleanStub stub;
00665 __ CallStub(&stub);
00666
00667 __ test(eax, Operand(eax));
00668
00669 ASSERT(not_equal == not_zero);
00670 cc_reg_ = not_equal;
00671 }
00672
00673
00674 class FloatingPointHelper : public AllStatic {
00675 public:
00676
00677
00678
00679
00680 static void LoadFloatOperands(MacroAssembler* masm, Register scratch);
00681
00682
00683
00684 static void CheckFloatOperands(MacroAssembler* masm,
00685 Label* non_float,
00686 Register scratch);
00687
00688
00689 static void AllocateHeapNumber(MacroAssembler* masm,
00690 Label* need_gc,
00691 Register scratch1,
00692 Register scratch2);
00693 };
00694
00695
00696
00697
00698 enum GenericBinaryFlags {
00699 SMI_CODE_IN_STUB,
00700 SMI_CODE_INLINED
00701 };
00702
00703
00704 class GenericBinaryOpStub: public CodeStub {
00705 public:
00706 GenericBinaryOpStub(Token::Value op,
00707 OverwriteMode mode,
00708 GenericBinaryFlags flags)
00709 : op_(op), mode_(mode), flags_(flags) { }
00710
00711 void GenerateSmiCode(MacroAssembler* masm, Label* slow);
00712
00713 private:
00714 Token::Value op_;
00715 OverwriteMode mode_;
00716 GenericBinaryFlags flags_;
00717
00718 const char* GetName();
00719
00720 #ifdef DEBUG
00721 void Print() {
00722 PrintF("GenericBinaryOpStub (op %s), (mode %d, flags %d)\n",
00723 Token::String(op_),
00724 static_cast<int>(mode_),
00725 static_cast<int>(flags_));
00726 }
00727 #endif
00728
00729
00730 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
00731 class OpBits: public BitField<Token::Value, 2, 13> {};
00732 class FlagBits: public BitField<GenericBinaryFlags, 15, 1> {};
00733
00734 Major MajorKey() { return GenericBinaryOp; }
00735 int MinorKey() {
00736
00737 return OpBits::encode(op_) |
00738 ModeBits::encode(mode_) |
00739 FlagBits::encode(flags_);
00740 }
00741 void Generate(MacroAssembler* masm);
00742 };
00743
00744
00745 const char* GenericBinaryOpStub::GetName() {
00746 switch (op_) {
00747 case Token::ADD: return "GenericBinaryOpStub_ADD";
00748 case Token::SUB: return "GenericBinaryOpStub_SUB";
00749 case Token::MUL: return "GenericBinaryOpStub_MUL";
00750 case Token::DIV: return "GenericBinaryOpStub_DIV";
00751 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
00752 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
00753 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
00754 case Token::SAR: return "GenericBinaryOpStub_SAR";
00755 case Token::SHL: return "GenericBinaryOpStub_SHL";
00756 case Token::SHR: return "GenericBinaryOpStub_SHR";
00757 default: return "GenericBinaryOpStub";
00758 }
00759 }
00760
00761
00762 class DeferredInlineBinaryOperation: public DeferredCode {
00763 public:
00764 DeferredInlineBinaryOperation(CodeGenerator* generator,
00765 Token::Value op,
00766 OverwriteMode mode,
00767 GenericBinaryFlags flags)
00768 : DeferredCode(generator), stub_(op, mode, flags) { }
00769
00770 void GenerateInlineCode() {
00771 stub_.GenerateSmiCode(masm(), enter());
00772 }
00773
00774 virtual void Generate() {
00775 __ push(ebx);
00776 __ CallStub(&stub_);
00777
00778
00779
00780
00781 __ push(eax);
00782 }
00783
00784 private:
00785 GenericBinaryOpStub stub_;
00786 };
00787
00788
00789 void CodeGenerator::GenericBinaryOperation(Token::Value op,
00790 StaticType* type,
00791 OverwriteMode overwrite_mode) {
00792 Comment cmnt(masm_, "[ BinaryOperation");
00793 Comment cmnt_token(masm_, Token::String(op));
00794
00795 if (op == Token::COMMA) {
00796
00797 frame_->Pop(eax);
00798 frame_->Pop();
00799 frame_->Push(eax);
00800 return;
00801 }
00802
00803
00804 GenericBinaryFlags flags;
00805 switch (op) {
00806 case Token::BIT_OR:
00807 case Token::BIT_AND:
00808 case Token::BIT_XOR:
00809 case Token::SHL:
00810 case Token::SHR:
00811 case Token::SAR:
00812
00813
00814 flags = (loop_nesting() > 0)
00815 ? SMI_CODE_INLINED
00816 : SMI_CODE_IN_STUB;
00817 break;
00818
00819 default:
00820
00821
00822 flags = ((loop_nesting() > 0) && type->IsLikelySmi())
00823 ? SMI_CODE_INLINED
00824 : SMI_CODE_IN_STUB;
00825 break;
00826 }
00827
00828 if (flags == SMI_CODE_INLINED) {
00829
00830 DeferredInlineBinaryOperation* deferred =
00831 new DeferredInlineBinaryOperation(this, op, overwrite_mode, flags);
00832
00833 frame_->Pop(ebx);
00834 __ mov(eax, frame_->Top());
00835
00836 deferred->GenerateInlineCode();
00837
00838
00839
00840
00841 __ bind(deferred->exit());
00842 __ mov(frame_->Top(), eax);
00843 } else {
00844
00845 GenericBinaryOpStub stub(op, overwrite_mode, flags);
00846 __ CallStub(&stub);
00847 frame_->Push(eax);
00848 }
00849 }
00850
00851
00852 class DeferredInlinedSmiOperation: public DeferredCode {
00853 public:
00854 DeferredInlinedSmiOperation(CodeGenerator* generator,
00855 Token::Value op, int value,
00856 OverwriteMode overwrite_mode) :
00857 DeferredCode(generator), op_(op), value_(value),
00858 overwrite_mode_(overwrite_mode) {
00859 set_comment("[ DeferredInlinedSmiOperation");
00860 }
00861 virtual void Generate() {
00862 __ push(eax);
00863 __ push(Immediate(Smi::FromInt(value_)));
00864 GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED);
00865 __ CallStub(&igostub);
00866 }
00867
00868 private:
00869 Token::Value op_;
00870 int value_;
00871 OverwriteMode overwrite_mode_;
00872 };
00873
00874
00875 class DeferredInlinedSmiOperationReversed: public DeferredCode {
00876 public:
00877 DeferredInlinedSmiOperationReversed(CodeGenerator* generator,
00878 Token::Value op, int value,
00879 OverwriteMode overwrite_mode) :
00880 DeferredCode(generator), op_(op), value_(value),
00881 overwrite_mode_(overwrite_mode) {
00882 set_comment("[ DeferredInlinedSmiOperationReversed");
00883 }
00884 virtual void Generate() {
00885 __ push(Immediate(Smi::FromInt(value_)));
00886 __ push(eax);
00887 GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED);
00888 __ CallStub(&igostub);
00889 }
00890
00891 private:
00892 Token::Value op_;
00893 int value_;
00894 OverwriteMode overwrite_mode_;
00895 };
00896
00897
00898 class DeferredInlinedSmiAdd: public DeferredCode {
00899 public:
00900 DeferredInlinedSmiAdd(CodeGenerator* generator, int value,
00901 OverwriteMode overwrite_mode) :
00902 DeferredCode(generator), value_(value), overwrite_mode_(overwrite_mode) {
00903 set_comment("[ DeferredInlinedSmiAdd");
00904 }
00905
00906 virtual void Generate() {
00907
00908 Immediate immediate(Smi::FromInt(value_));
00909 __ sub(Operand(eax), immediate);
00910 __ push(eax);
00911 __ push(immediate);
00912 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED);
00913 __ CallStub(&igostub);
00914 }
00915
00916 private:
00917 int value_;
00918 OverwriteMode overwrite_mode_;
00919 };
00920
00921
00922 class DeferredInlinedSmiAddReversed: public DeferredCode {
00923 public:
00924 DeferredInlinedSmiAddReversed(CodeGenerator* generator, int value,
00925 OverwriteMode overwrite_mode) :
00926 DeferredCode(generator), value_(value), overwrite_mode_(overwrite_mode) {
00927 set_comment("[ DeferredInlinedSmiAddReversed");
00928 }
00929
00930 virtual void Generate() {
00931
00932 Immediate immediate(Smi::FromInt(value_));
00933 __ sub(Operand(eax), immediate);
00934 __ push(immediate);
00935 __ push(eax);
00936 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED);
00937 __ CallStub(&igostub);
00938 }
00939
00940 private:
00941 int value_;
00942 OverwriteMode overwrite_mode_;
00943 };
00944
00945
00946 class DeferredInlinedSmiSub: public DeferredCode {
00947 public:
00948 DeferredInlinedSmiSub(CodeGenerator* generator, int value,
00949 OverwriteMode overwrite_mode) :
00950 DeferredCode(generator), value_(value), overwrite_mode_(overwrite_mode) {
00951 set_comment("[ DeferredInlinedSmiSub");
00952 }
00953
00954 virtual void Generate() {
00955
00956 Immediate immediate(Smi::FromInt(value_));
00957 __ add(Operand(eax), immediate);
00958 __ push(eax);
00959 __ push(immediate);
00960 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED);
00961 __ CallStub(&igostub);
00962 }
00963
00964 private:
00965 int value_;
00966 OverwriteMode overwrite_mode_;
00967 };
00968
00969
00970 class DeferredInlinedSmiSubReversed: public DeferredCode {
00971 public:
00972
00973
00974 DeferredInlinedSmiSubReversed(CodeGenerator* generator, Register tos_reg,
00975 OverwriteMode overwrite_mode) :
00976 DeferredCode(generator), tos_reg_(tos_reg),
00977 overwrite_mode_(overwrite_mode) {
00978 set_comment("[ DeferredInlinedSmiSubReversed");
00979 }
00980
00981 virtual void Generate() {
00982
00983 __ add(eax, Operand(tos_reg_));
00984 __ push(eax);
00985 __ push(tos_reg_);
00986 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED);
00987 __ CallStub(&igostub);
00988 }
00989
00990 private:
00991 Register tos_reg_;
00992 OverwriteMode overwrite_mode_;
00993 };
00994
00995
00996 void CodeGenerator::SmiOperation(Token::Value op,
00997 StaticType* type,
00998 Handle<Object> value,
00999 bool reversed,
01000 OverwriteMode overwrite_mode) {
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012 int int_value = Smi::cast(*value)->value();
01013 ASSERT(is_intn(int_value, kMaxSmiInlinedBits));
01014
01015 switch (op) {
01016 case Token::ADD: {
01017 DeferredCode* deferred = NULL;
01018 if (!reversed) {
01019 deferred = new DeferredInlinedSmiAdd(this, int_value, overwrite_mode);
01020 } else {
01021 deferred = new DeferredInlinedSmiAddReversed(this, int_value,
01022 overwrite_mode);
01023 }
01024 frame_->Pop(eax);
01025 __ add(Operand(eax), Immediate(value));
01026 __ j(overflow, deferred->enter(), not_taken);
01027 __ test(eax, Immediate(kSmiTagMask));
01028 __ j(not_zero, deferred->enter(), not_taken);
01029 __ bind(deferred->exit());
01030 frame_->Push(eax);
01031 break;
01032 }
01033
01034 case Token::SUB: {
01035 DeferredCode* deferred = NULL;
01036 frame_->Pop(eax);
01037 if (!reversed) {
01038 deferred = new DeferredInlinedSmiSub(this, int_value, overwrite_mode);
01039 __ sub(Operand(eax), Immediate(value));
01040 } else {
01041 deferred = new DeferredInlinedSmiSubReversed(this, edx, overwrite_mode);
01042 __ mov(edx, Operand(eax));
01043 __ mov(Operand(eax), Immediate(value));
01044 __ sub(eax, Operand(edx));
01045 }
01046 __ j(overflow, deferred->enter(), not_taken);
01047 __ test(eax, Immediate(kSmiTagMask));
01048 __ j(not_zero, deferred->enter(), not_taken);
01049 __ bind(deferred->exit());
01050 frame_->Push(eax);
01051 break;
01052 }
01053
01054 case Token::SAR: {
01055 if (reversed) {
01056 frame_->Pop(eax);
01057 frame_->Push(Immediate(value));
01058 frame_->Push(eax);
01059 GenericBinaryOperation(op, type, overwrite_mode);
01060 } else {
01061 int shift_value = int_value & 0x1f;
01062 DeferredCode* deferred =
01063 new DeferredInlinedSmiOperation(this, Token::SAR, shift_value,
01064 overwrite_mode);
01065 frame_->Pop(eax);
01066 __ test(eax, Immediate(kSmiTagMask));
01067 __ j(not_zero, deferred->enter(), not_taken);
01068 __ sar(eax, shift_value);
01069 __ and_(eax, ~kSmiTagMask);
01070 __ bind(deferred->exit());
01071 frame_->Push(eax);
01072 }
01073 break;
01074 }
01075
01076 case Token::SHR: {
01077 if (reversed) {
01078 frame_->Pop(eax);
01079 frame_->Push(Immediate(value));
01080 frame_->Push(eax);
01081 GenericBinaryOperation(op, type, overwrite_mode);
01082 } else {
01083 int shift_value = int_value & 0x1f;
01084 DeferredCode* deferred =
01085 new DeferredInlinedSmiOperation(this, Token::SHR, shift_value,
01086 overwrite_mode);
01087 frame_->Pop(eax);
01088 __ test(eax, Immediate(kSmiTagMask));
01089 __ mov(ebx, Operand(eax));
01090 __ j(not_zero, deferred->enter(), not_taken);
01091 __ sar(ebx, kSmiTagSize);
01092 __ shr(ebx, shift_value);
01093 __ test(ebx, Immediate(0xc0000000));
01094 __ j(not_zero, deferred->enter(), not_taken);
01095
01096 ASSERT(kSmiTagSize == times_2);
01097 __ lea(eax, Operand(ebx, times_2, kSmiTag));
01098 __ bind(deferred->exit());
01099 frame_->Push(eax);
01100 }
01101 break;
01102 }
01103
01104 case Token::SHL: {
01105 if (reversed) {
01106 frame_->Pop(eax);
01107 frame_->Push(Immediate(value));
01108 frame_->Push(eax);
01109 GenericBinaryOperation(op, type, overwrite_mode);
01110 } else {
01111 int shift_value = int_value & 0x1f;
01112 DeferredCode* deferred =
01113 new DeferredInlinedSmiOperation(this, Token::SHL, shift_value,
01114 overwrite_mode);
01115 frame_->Pop(eax);
01116 __ test(eax, Immediate(kSmiTagMask));
01117 __ mov(ebx, Operand(eax));
01118 __ j(not_zero, deferred->enter(), not_taken);
01119 __ sar(ebx, kSmiTagSize);
01120 __ shl(ebx, shift_value);
01121 __ lea(ecx, Operand(ebx, 0x40000000));
01122 __ test(ecx, Immediate(0x80000000));
01123 __ j(not_zero, deferred->enter(), not_taken);
01124
01125 ASSERT(kSmiTagSize == times_2);
01126 __ lea(eax, Operand(ebx, times_2, kSmiTag));
01127 __ bind(deferred->exit());
01128 frame_->Push(eax);
01129 }
01130 break;
01131 }
01132
01133 case Token::BIT_OR:
01134 case Token::BIT_XOR:
01135 case Token::BIT_AND: {
01136 DeferredCode* deferred = NULL;
01137 if (!reversed) {
01138 deferred = new DeferredInlinedSmiOperation(this, op, int_value,
01139 overwrite_mode);
01140 } else {
01141 deferred = new DeferredInlinedSmiOperationReversed(this, op, int_value,
01142 overwrite_mode);
01143 }
01144 frame_->Pop(eax);
01145 __ test(eax, Immediate(kSmiTagMask));
01146 __ j(not_zero, deferred->enter(), not_taken);
01147 if (op == Token::BIT_AND) {
01148 __ and_(Operand(eax), Immediate(value));
01149 } else if (op == Token::BIT_XOR) {
01150 __ xor_(Operand(eax), Immediate(value));
01151 } else {
01152 ASSERT(op == Token::BIT_OR);
01153 __ or_(Operand(eax), Immediate(value));
01154 }
01155 __ bind(deferred->exit());
01156 frame_->Push(eax);
01157 break;
01158 }
01159
01160 default: {
01161 if (!reversed) {
01162 frame_->Push(Immediate(value));
01163 } else {
01164 frame_->Pop(eax);
01165 frame_->Push(Immediate(value));
01166 frame_->Push(eax);
01167 }
01168 GenericBinaryOperation(op, type, overwrite_mode);
01169 break;
01170 }
01171 }
01172 }
01173
01174
01175 class CompareStub: public CodeStub {
01176 public:
01177 CompareStub(Condition cc, bool strict) : cc_(cc), strict_(strict) { }
01178
01179 void Generate(MacroAssembler* masm);
01180
01181 private:
01182 Condition cc_;
01183 bool strict_;
01184
01185 Major MajorKey() { return Compare; }
01186
01187 int MinorKey() {
01188
01189 ASSERT(static_cast<int>(cc_) < (1 << 15));
01190 return (static_cast<int>(cc_) << 1) | (strict_ ? 1 : 0);
01191 }
01192
01193 #ifdef DEBUG
01194 void Print() {
01195 PrintF("CompareStub (cc %d), (strict %s)\n",
01196 static_cast<int>(cc_),
01197 strict_ ? "true" : "false");
01198 }
01199 #endif
01200 };
01201
01202
01203 void CodeGenerator::Comparison(Condition cc, bool strict) {
01204
01205 ASSERT(!strict || cc == equal);
01206
01207
01208 if (cc == greater || cc == less_equal) {
01209 cc = ReverseCondition(cc);
01210 frame_->Pop(edx);
01211 frame_->Pop(eax);
01212 } else {
01213 frame_->Pop(eax);
01214 frame_->Pop(edx);
01215 }
01216
01217
01218 Label is_smi, done;
01219 __ mov(ecx, Operand(eax));
01220 __ or_(ecx, Operand(edx));
01221 __ test(ecx, Immediate(kSmiTagMask));
01222 __ j(zero, &is_smi, taken);
01223
01224
01225
01226 CompareStub stub(cc, strict);
01227 __ CallStub(&stub);
01228 if (cc == equal) {
01229 __ test(eax, Operand(eax));
01230 } else {
01231 __ cmp(eax, 0);
01232 }
01233 __ jmp(&done);
01234
01235
01236 __ bind(&is_smi);
01237 __ cmp(edx, Operand(eax));
01238
01239
01240 __ bind(&done);
01241 cc_reg_ = cc;
01242 }
01243
01244
01245 class SmiComparisonDeferred: public DeferredCode {
01246 public:
01247 SmiComparisonDeferred(CodeGenerator* generator,
01248 Condition cc,
01249 bool strict,
01250 int value)
01251 : DeferredCode(generator), cc_(cc), strict_(strict), value_(value) {
01252 set_comment("[ ComparisonDeferred");
01253 }
01254 virtual void Generate();
01255
01256 private:
01257 Condition cc_;
01258 bool strict_;
01259 int value_;
01260 };
01261
01262
01263 void SmiComparisonDeferred::Generate() {
01264 CompareStub stub(cc_, strict_);
01265
01266 __ mov(edx, Operand(eax));
01267 __ mov(Operand(eax), Immediate(Smi::FromInt(value_)));
01268 __ CallStub(&stub);
01269 __ cmp(eax, 0);
01270
01271 }
01272
01273
01274 void CodeGenerator::SmiComparison(Condition cc,
01275 Handle<Object> value,
01276 bool strict) {
01277
01278 ASSERT(!strict || cc == equal);
01279
01280 int int_value = Smi::cast(*value)->value();
01281 ASSERT(is_intn(int_value, kMaxSmiInlinedBits));
01282
01283 SmiComparisonDeferred* deferred =
01284 new SmiComparisonDeferred(this, cc, strict, int_value);
01285 frame_->Pop(eax);
01286 __ test(eax, Immediate(kSmiTagMask));
01287 __ j(not_zero, deferred->enter(), not_taken);
01288
01289 __ cmp(Operand(eax), Immediate(value));
01290 __ bind(deferred->exit());
01291 cc_reg_ = cc;
01292 }
01293
01294
01295 class CallFunctionStub: public CodeStub {
01296 public:
01297 explicit CallFunctionStub(int argc) : argc_(argc) { }
01298
01299 void Generate(MacroAssembler* masm);
01300
01301 private:
01302 int argc_;
01303
01304 #ifdef DEBUG
01305 void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); }
01306 #endif
01307
01308 Major MajorKey() { return CallFunction; }
01309 int MinorKey() { return argc_; }
01310 };
01311
01312
01313
01314
01315 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
01316 int position) {
01317
01318 for (int i = 0; i < args->length(); i++) {
01319 Load(args->at(i));
01320 }
01321
01322
01323 __ RecordPosition(position);
01324
01325
01326 CallFunctionStub call_function(args->length());
01327 __ CallStub(&call_function);
01328
01329
01330 __ mov(esi, frame_->Context());
01331 __ mov(frame_->Top(), eax);
01332 }
01333
01334
01335 void CodeGenerator::Branch(bool if_true, Label* L) {
01336 ASSERT(has_cc());
01337 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
01338 __ j(cc, L);
01339 cc_reg_ = no_condition;
01340 }
01341
01342
01343 void CodeGenerator::CheckStack() {
01344 if (FLAG_check_stack) {
01345 Label stack_is_ok;
01346 StackCheckStub stub;
01347 ExternalReference stack_guard_limit =
01348 ExternalReference::address_of_stack_guard_limit();
01349 __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
01350 __ j(above_equal, &stack_is_ok, taken);
01351 __ CallStub(&stub);
01352 __ bind(&stack_is_ok);
01353 }
01354 }
01355
01356
01357 void CodeGenerator::VisitBlock(Block* node) {
01358 Comment cmnt(masm_, "[ Block");
01359 RecordStatementPosition(node);
01360 node->set_break_stack_height(break_stack_height_);
01361 VisitStatements(node->statements());
01362 __ bind(node->break_target());
01363 }
01364
01365
01366 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
01367 frame_->Push(Immediate(pairs));
01368 frame_->Push(esi);
01369 frame_->Push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
01370 __ CallRuntime(Runtime::kDeclareGlobals, 3);
01371
01372 }
01373
01374
01375 void CodeGenerator::VisitDeclaration(Declaration* node) {
01376 Comment cmnt(masm_, "[ Declaration");
01377 Variable* var = node->proxy()->var();
01378 ASSERT(var != NULL);
01379 Slot* slot = var->slot();
01380
01381
01382
01383
01384 if (slot != NULL && slot->type() == Slot::LOOKUP) {
01385
01386
01387 ASSERT(var->mode() == Variable::DYNAMIC);
01388
01389 frame_->Push(esi);
01390 frame_->Push(Immediate(var->name()));
01391
01392 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
01393 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
01394 frame_->Push(Immediate(Smi::FromInt(attr)));
01395
01396
01397
01398
01399 if (node->mode() == Variable::CONST) {
01400 frame_->Push(Immediate(Factory::the_hole_value()));
01401 } else if (node->fun() != NULL) {
01402 Load(node->fun());
01403 } else {
01404 frame_->Push(Immediate(0));
01405 }
01406 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
01407
01408 return;
01409 }
01410
01411 ASSERT(!var->is_global());
01412
01413
01414 Expression* val = NULL;
01415 if (node->mode() == Variable::CONST) {
01416 val = new Literal(Factory::the_hole_value());
01417 } else {
01418 val = node->fun();
01419 }
01420
01421 if (val != NULL) {
01422
01423 Reference target(this, node->proxy());
01424 ASSERT(target.is_slot());
01425 Load(val);
01426 target.SetValue(NOT_CONST_INIT);
01427
01428
01429
01430
01431 frame_->Pop();
01432 }
01433 }
01434
01435
01436 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
01437 Comment cmnt(masm_, "[ ExpressionStatement");
01438 RecordStatementPosition(node);
01439 Expression* expression = node->expression();
01440 expression->MarkAsStatement();
01441 Load(expression);
01442
01443 frame_->Pop();
01444 }
01445
01446
01447 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
01448 Comment cmnt(masm_, "// EmptyStatement");
01449
01450 }
01451
01452
01453 void CodeGenerator::VisitIfStatement(IfStatement* node) {
01454 Comment cmnt(masm_, "[ IfStatement");
01455
01456
01457 bool has_then_stm = node->HasThenStatement();
01458 bool has_else_stm = node->HasElseStatement();
01459
01460 RecordStatementPosition(node);
01461 Label exit;
01462 if (has_then_stm && has_else_stm) {
01463 Label then;
01464 Label else_;
01465
01466 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
01467 Branch(false, &else_);
01468
01469 __ bind(&then);
01470 Visit(node->then_statement());
01471 __ jmp(&exit);
01472
01473 __ bind(&else_);
01474 Visit(node->else_statement());
01475
01476 } else if (has_then_stm) {
01477 ASSERT(!has_else_stm);
01478 Label then;
01479
01480 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true);
01481 Branch(false, &exit);
01482
01483 __ bind(&then);
01484 Visit(node->then_statement());
01485
01486 } else if (has_else_stm) {
01487 ASSERT(!has_then_stm);
01488 Label else_;
01489
01490 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true);
01491 Branch(true, &exit);
01492
01493 __ bind(&else_);
01494 Visit(node->else_statement());
01495
01496 } else {
01497 ASSERT(!has_then_stm && !has_else_stm);
01498
01499 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false);
01500 if (has_cc()) {
01501 cc_reg_ = no_condition;
01502 } else {
01503
01504
01505 frame_->Pop();
01506 }
01507 }
01508
01509
01510 __ bind(&exit);
01511 }
01512
01513
01514 void CodeGenerator::CleanStack(int num_bytes) {
01515 ASSERT(num_bytes % kPointerSize == 0);
01516 frame_->Drop(num_bytes / kPointerSize);
01517 }
01518
01519
01520 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
01521 Comment cmnt(masm_, "[ ContinueStatement");
01522 RecordStatementPosition(node);
01523 CleanStack(break_stack_height_ - node->target()->break_stack_height());
01524 __ jmp(node->target()->continue_target());
01525 }
01526
01527
01528 void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
01529 Comment cmnt(masm_, "[ BreakStatement");
01530 RecordStatementPosition(node);
01531 CleanStack(break_stack_height_ - node->target()->break_stack_height());
01532 __ jmp(node->target()->break_target());
01533 }
01534
01535
01536 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
01537 Comment cmnt(masm_, "[ ReturnStatement");
01538 RecordStatementPosition(node);
01539 Load(node->expression());
01540
01541
01542 frame_->Pop(eax);
01543
01544
01545
01546
01547
01548 if (is_inside_try_ || function_return_.is_bound()) {
01549 __ jmp(&function_return_);
01550 } else {
01551 __ bind(&function_return_);
01552 if (FLAG_trace) {
01553 frame_->Push(eax);
01554 __ CallRuntime(Runtime::kTraceExit, 1);
01555 }
01556
01557
01558 Label check_exit_codesize;
01559 __ bind(&check_exit_codesize);
01560
01561
01562
01563 frame_->Exit();
01564 __ ret((scope_->num_parameters() + 1) * kPointerSize);
01565
01566
01567
01568 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
01569 __ SizeOfCodeGeneratedSince(&check_exit_codesize));
01570 }
01571 }
01572
01573
01574 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
01575 Comment cmnt(masm_, "[ WithEnterStatement");
01576 RecordStatementPosition(node);
01577 Load(node->expression());
01578 __ CallRuntime(Runtime::kPushContext, 1);
01579
01580 if (kDebug) {
01581 Label verified_true;
01582
01583 __ cmp(eax, Operand(esi));
01584 __ j(equal, &verified_true);
01585 __ int3();
01586 __ bind(&verified_true);
01587 }
01588
01589
01590 __ mov(frame_->Context(), esi);
01591 }
01592
01593
01594 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
01595 Comment cmnt(masm_, "[ WithExitStatement");
01596
01597 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX));
01598
01599 __ mov(frame_->Context(), esi);
01600 }
01601
01602 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
01603 return kFastSwitchMaxOverheadFactor;
01604 }
01605
01606 int CodeGenerator::FastCaseSwitchMinCaseCount() {
01607 return kFastSwitchMinCaseCount;
01608 }
01609
01610
01611 void CodeGenerator::GenerateFastCaseSwitchJumpTable(
01612 SwitchStatement* node,
01613 int min_index,
01614 int range,
01615 Label* fail_label,
01616 Vector<Label*> case_targets,
01617 Vector<Label> case_labels) {
01618
01619
01620
01621
01622
01623
01624
01625
01626 frame_->Pop(eax);
01627
01628 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
01629 if (min_index != 0) {
01630 __ sub(Operand(eax), Immediate(min_index << kSmiTagSize));
01631 }
01632 __ test(eax, Immediate(0x80000000 | kSmiTagMask));
01633 __ j(not_equal, fail_label, not_taken);
01634 __ cmp(eax, range << kSmiTagSize);
01635 __ j(greater_equal, fail_label, not_taken);
01636
01637
01638 __ jmp(Operand(eax, times_2, 0x0, RelocInfo::INTERNAL_REFERENCE));
01639
01640 int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t);
01641
01642 __ Align(4);
01643 Label table_start;
01644 __ bind(&table_start);
01645 __ WriteInternalReference(jump_table_ref, table_start);
01646
01647 for (int i = 0; i < range; i++) {
01648
01649 __ dd(0x0, RelocInfo::INTERNAL_REFERENCE);
01650 }
01651
01652 GenerateFastCaseSwitchCases(node, case_labels);
01653
01654 for (int i = 0, entry_pos = table_start.pos();
01655 i < range; i++, entry_pos += sizeof(uint32_t)) {
01656 __ WriteInternalReference(entry_pos, *case_targets[i]);
01657 }
01658 }
01659
01660
01661 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
01662 Comment cmnt(masm_, "[ SwitchStatement");
01663 RecordStatementPosition(node);
01664 node->set_break_stack_height(break_stack_height_);
01665
01666 Load(node->tag());
01667
01668 if (TryGenerateFastCaseSwitchStatement(node)) {
01669 return;
01670 }
01671
01672 Label next, fall_through, default_case;
01673 ZoneList<CaseClause*>* cases = node->cases();
01674 int length = cases->length();
01675
01676 for (int i = 0; i < length; i++) {
01677 CaseClause* clause = cases->at(i);
01678 Comment cmnt(masm_, "[ case clause");
01679
01680 if (clause->is_default()) {
01681
01682
01683 __ jmp(&next);
01684
01685
01686
01687 ASSERT(default_case.is_unused());
01688 __ bind(&default_case);
01689 } else {
01690 __ bind(&next);
01691 next.Unuse();
01692 __ mov(eax, frame_->Top());
01693 frame_->Push(eax);
01694 Load(clause->label());
01695 Comparison(equal, true);
01696 Branch(false, &next);
01697 }
01698
01699
01700
01701 frame_->Pop(eax);
01702
01703
01704
01705
01706
01707 __ bind(&fall_through);
01708 fall_through.Unuse();
01709 VisitStatements(clause->statements());
01710 __ jmp(&fall_through);
01711 }
01712
01713 __ bind(&next);
01714
01715 if (default_case.is_bound()) {
01716
01717 __ jmp(&default_case);
01718 } else {
01719
01720 frame_->Pop();
01721 }
01722
01723 __ bind(&fall_through);
01724 __ bind(node->break_target());
01725 }
01726
01727
01728 void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
01729 Comment cmnt(masm_, "[ LoopStatement");
01730 RecordStatementPosition(node);
01731 node->set_break_stack_height(break_stack_height_);
01732
01733
01734 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
01735 if (node->cond() == NULL) {
01736 ASSERT(node->type() == LoopStatement::FOR_LOOP);
01737 info = ALWAYS_TRUE;
01738 } else {
01739 Literal* lit = node->cond()->AsLiteral();
01740 if (lit != NULL) {
01741 if (lit->IsTrue()) {
01742 info = ALWAYS_TRUE;
01743 } else if (lit->IsFalse()) {
01744 info = ALWAYS_FALSE;
01745 }
01746 }
01747 }
01748
01749 Label loop, entry;
01750
01751
01752 if (node->init() != NULL) {
01753 ASSERT(node->type() == LoopStatement::FOR_LOOP);
01754 Visit(node->init());
01755 }
01756 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) {
01757 __ jmp(&entry);
01758 }
01759
01760 IncrementLoopNesting();
01761
01762
01763 __ bind(&loop);
01764 CheckStack();
01765 Visit(node->body());
01766
01767
01768 __ bind(node->continue_target());
01769 if (node->next() != NULL) {
01770
01771
01772
01773 RecordStatementPosition(node);
01774 __ RecordPosition(node->statement_pos());
01775 ASSERT(node->type() == LoopStatement::FOR_LOOP);
01776 Visit(node->next());
01777 }
01778
01779
01780 __ bind(&entry);
01781 switch (info) {
01782 case ALWAYS_TRUE:
01783 __ jmp(&loop);
01784 break;
01785 case ALWAYS_FALSE:
01786 break;
01787 case DONT_KNOW:
01788 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &loop,
01789 node->break_target(), true);
01790 Branch(true, &loop);
01791 break;
01792 }
01793
01794 DecrementLoopNesting();
01795
01796
01797 __ bind(node->break_target());
01798 }
01799
01800
01801 void CodeGenerator::VisitForInStatement(ForInStatement* node) {
01802 Comment cmnt(masm_, "[ ForInStatement");
01803 RecordStatementPosition(node);
01804
01805
01806
01807
01808 const int kForInStackSize = 5 * kPointerSize;
01809 break_stack_height_ += kForInStackSize;
01810 node->set_break_stack_height(break_stack_height_);
01811
01812 Label loop, next, entry, cleanup, exit, primitive, jsobject;
01813 Label end_del_check, fixed_array;
01814
01815
01816 Load(node->enumerable());
01817
01818
01819
01820 frame_->Pop(eax);
01821
01822
01823 __ cmp(eax, Factory::undefined_value());
01824 __ j(equal, &exit);
01825 __ cmp(eax, Factory::null_value());
01826 __ j(equal, &exit);
01827
01828
01829
01830
01831
01832
01833
01834
01835
01836
01837 __ test(eax, Immediate(kSmiTagMask));
01838 __ j(zero, &primitive);
01839 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
01840 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
01841 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
01842 __ j(above_equal, &jsobject);
01843
01844 __ bind(&primitive);
01845 frame_->Push(eax);
01846 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
01847
01848
01849
01850 __ bind(&jsobject);
01851
01852
01853
01854 frame_->Push(eax);
01855
01856 frame_->Push(eax);
01857 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
01858
01859
01860
01861
01862
01863 __ mov(edx, Operand(eax));
01864 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
01865 __ cmp(ecx, Factory::meta_map());
01866 __ j(not_equal, &fixed_array);
01867
01868
01869
01870 __ mov(ecx, Operand(eax));
01871 __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset));
01872
01873 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
01874
01875 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
01876
01877 frame_->Push(eax);
01878 frame_->Push(edx);
01879 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
01880 __ shl(eax, kSmiTagSize);
01881 frame_->Push(eax);
01882 frame_->Push(Immediate(Smi::FromInt(0)));
01883 __ jmp(&entry);
01884
01885
01886 __ bind(&fixed_array);
01887
01888
01889 frame_->Push(Immediate(Smi::FromInt(0)));
01890 frame_->Push(eax);
01891
01892
01893 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
01894 __ shl(eax, kSmiTagSize);
01895 frame_->Push(eax);
01896 frame_->Push(Immediate(Smi::FromInt(0)));
01897 __ jmp(&entry);
01898
01899
01900 __ bind(&loop);
01901 Visit(node->body());
01902
01903
01904 __ bind(node->continue_target());
01905 __ bind(&next);
01906 frame_->Pop(eax);
01907 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
01908 frame_->Push(eax);
01909
01910
01911 __ bind(&entry);
01912
01913 __ mov(eax, frame_->Element(0));
01914 __ cmp(eax, frame_->Element(1));
01915 __ j(above_equal, &cleanup);
01916
01917
01918 __ mov(edx, frame_->Element(2));
01919 __ mov(ebx, Operand(edx, eax, times_2,
01920 FixedArray::kHeaderSize - kHeapObjectTag));
01921
01922
01923
01924
01925 __ mov(edx, frame_->Element(3));
01926
01927
01928
01929
01930
01931 __ mov(ecx, frame_->Element(4));
01932 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
01933 __ cmp(ecx, Operand(edx));
01934 __ j(equal, &end_del_check);
01935
01936
01937 frame_->Push(frame_->Element(4));
01938 frame_->Push(ebx);
01939 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
01940 __ mov(ebx, Operand(eax));
01941
01942
01943 __ cmp(ebx, Factory::null_value());
01944 __ j(equal, &next);
01945
01946
01947 __ bind(&end_del_check);
01948
01949
01950
01951 frame_->Push(ebx);
01952 { Reference each(this, node->each());
01953 if (!each.is_illegal()) {
01954 if (each.size() > 0) {
01955 frame_->Push(frame_->Element(each.size()));
01956 }
01957
01958
01959
01960 each.SetValue(NOT_CONST_INIT);
01961 if (each.size() > 0) {
01962
01963
01964
01965
01966
01967 frame_->Pop();
01968 }
01969 }
01970 }
01971
01972
01973 frame_->Pop();
01974 CheckStack();
01975 __ jmp(&loop);
01976
01977
01978 __ bind(&cleanup);
01979 __ bind(node->break_target());
01980 frame_->Drop(5);
01981
01982
01983 __ bind(&exit);
01984
01985 break_stack_height_ -= kForInStackSize;
01986 }
01987
01988
01989 void CodeGenerator::VisitTryCatch(TryCatch* node) {
01990 Comment cmnt(masm_, "[ TryCatch");
01991
01992 Label try_block, exit;
01993
01994 __ call(&try_block);
01995
01996 frame_->Push(eax);
01997
01998
01999 { Reference ref(this, node->catch_var());
02000 ASSERT(ref.is_slot());
02001
02002
02003
02004 ref.SetValue(NOT_CONST_INIT);
02005 }
02006
02007
02008 frame_->Pop();
02009
02010 VisitStatements(node->catch_block()->statements());
02011 __ jmp(&exit);
02012
02013
02014
02015 __ bind(&try_block);
02016
02017 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
02018
02019 frame_->Push(eax);
02020
02021
02022
02023
02024
02025
02026
02027
02028 int nof_escapes = node->escaping_labels()->length();
02029 List<LabelShadow*> shadows(1 + nof_escapes);
02030 shadows.Add(new LabelShadow(&function_return_));
02031 for (int i = 0; i < nof_escapes; i++) {
02032 shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
02033 }
02034
02035
02036 bool was_inside_try = is_inside_try_;
02037 is_inside_try_ = true;
02038 VisitStatements(node->try_block()->statements());
02039 is_inside_try_ = was_inside_try;
02040
02041
02042
02043
02044 int nof_unlinks = 0;
02045 for (int i = 0; i <= nof_escapes; i++) {
02046 shadows[i]->StopShadowing();
02047 if (shadows[i]->is_linked()) nof_unlinks++;
02048 }
02049
02050
02051 ExternalReference handler_address(Top::k_handler_address);
02052
02053
02054
02055 if (FLAG_debug_code) {
02056 __ mov(eax, Operand::StaticVariable(handler_address));
02057 __ lea(eax, Operand(eax, StackHandlerConstants::kAddressDisplacement));
02058 __ cmp(esp, Operand(eax));
02059 __ Assert(equal, "stack pointer should point to top handler");
02060 }
02061
02062
02063 frame_->Pop(eax);
02064 __ mov(Operand::StaticVariable(handler_address), eax);
02065 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
02066
02067 if (nof_unlinks > 0) __ jmp(&exit);
02068
02069
02070
02071 for (int i = 0; i <= nof_escapes; i++) {
02072 if (shadows[i]->is_linked()) {
02073
02074 __ bind(shadows[i]);
02075
02076
02077
02078 __ mov(edx, Operand::StaticVariable(handler_address));
02079 const int kNextOffset = StackHandlerConstants::kNextOffset +
02080 StackHandlerConstants::kAddressDisplacement;
02081 __ lea(esp, Operand(edx, kNextOffset));
02082
02083 frame_->Pop(Operand::StaticVariable(handler_address));
02084 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
02085
02086 __ jmp(shadows[i]->original_label());
02087 }
02088 }
02089
02090 __ bind(&exit);
02091 }
02092
02093
02094 void CodeGenerator::VisitTryFinally(TryFinally* node) {
02095 Comment cmnt(masm_, "[ TryFinally");
02096
02097
02098
02099
02100 enum { FALLING, THROWING, JUMPING };
02101
02102 Label exit, unlink, try_block, finally_block;
02103
02104 __ call(&try_block);
02105
02106 frame_->Push(eax);
02107
02108 __ Set(ecx, Immediate(Smi::FromInt(THROWING)));
02109 __ jmp(&finally_block);
02110
02111
02112
02113 __ bind(&try_block);
02114
02115 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
02116
02117 frame_->Push(eax);
02118
02119
02120
02121
02122
02123
02124
02125
02126 int nof_escapes = node->escaping_labels()->length();
02127 List<LabelShadow*> shadows(1 + nof_escapes);
02128 shadows.Add(new LabelShadow(&function_return_));
02129 for (int i = 0; i < nof_escapes; i++) {
02130 shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
02131 }
02132
02133
02134 bool was_inside_try = is_inside_try_;
02135 is_inside_try_ = true;
02136 VisitStatements(node->try_block()->statements());
02137 is_inside_try_ = was_inside_try;
02138
02139
02140
02141
02142 int nof_unlinks = 0;
02143 for (int i = 0; i <= nof_escapes; i++) {
02144 shadows[i]->StopShadowing();
02145 if (shadows[i]->is_linked()) nof_unlinks++;
02146 }
02147
02148
02149 frame_->Push(Immediate(Factory::undefined_value()));
02150 __ Set(ecx, Immediate(Smi::FromInt(FALLING)));
02151 if (nof_unlinks > 0) __ jmp(&unlink);
02152
02153
02154
02155 for (int i = 0; i <= nof_escapes; i++) {
02156 if (shadows[i]->is_linked()) {
02157 __ bind(shadows[i]);
02158 if (shadows[i]->original_label() == &function_return_) {
02159
02160
02161 frame_->Push(eax);
02162 } else {
02163
02164 frame_->Push(Immediate(Factory::undefined_value()));
02165 }
02166 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i)));
02167 __ jmp(&unlink);
02168 }
02169 }
02170
02171
02172 __ bind(&unlink);
02173
02174
02175
02176 frame_->Pop(eax);
02177 ExternalReference handler_address(Top::k_handler_address);
02178 __ mov(edx, Operand::StaticVariable(handler_address));
02179 const int kNextOffset = StackHandlerConstants::kNextOffset +
02180 StackHandlerConstants::kAddressDisplacement;
02181 __ lea(esp, Operand(edx, kNextOffset));
02182
02183 frame_->Pop(Operand::StaticVariable(handler_address));
02184 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
02185
02186
02187 frame_->Push(eax);
02188
02189
02190 __ bind(&finally_block);
02191
02192
02193 frame_->Push(ecx);
02194
02195
02196
02197
02198
02199 const int kFinallyStackSize = 2 * kPointerSize;
02200 break_stack_height_ += kFinallyStackSize;
02201
02202
02203 VisitStatements(node->finally_block()->statements());
02204
02205
02206 frame_->Pop(ecx);
02207 frame_->Pop(eax);
02208 break_stack_height_ -= kFinallyStackSize;
02209
02210
02211
02212 for (int i = 0; i <= nof_escapes; i++) {
02213 if (shadows[i]->is_bound()) {
02214 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i)));
02215 __ j(equal, shadows[i]->original_label());
02216 }
02217 }
02218
02219
02220 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING)));
02221 __ j(not_equal, &exit);
02222
02223
02224 frame_->Push(eax);
02225 __ CallRuntime(Runtime::kReThrow, 1);
02226
02227
02228 __ bind(&exit);
02229 }
02230
02231
02232 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
02233 Comment cmnt(masm_, "[ DebuggerStatement");
02234 RecordStatementPosition(node);
02235 __ CallRuntime(Runtime::kDebugBreak, 0);
02236
02237 }
02238
02239
02240 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
02241 ASSERT(boilerplate->IsBoilerplate());
02242
02243
02244 frame_->Push(Immediate(boilerplate));
02245
02246
02247 frame_->Push(esi);
02248 __ CallRuntime(Runtime::kNewClosure, 2);
02249 frame_->Push(eax);
02250 }
02251
02252
02253 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
02254 Comment cmnt(masm_, "[ FunctionLiteral");
02255
02256
02257 Handle<JSFunction> boilerplate = BuildBoilerplate(node);
02258
02259 if (HasStackOverflow()) return;
02260 InstantiateBoilerplate(boilerplate);
02261 }
02262
02263
02264 void CodeGenerator::VisitFunctionBoilerplateLiteral(
02265 FunctionBoilerplateLiteral* node) {
02266 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
02267 InstantiateBoilerplate(node->boilerplate());
02268 }
02269
02270
02271 void CodeGenerator::VisitConditional(Conditional* node) {
02272 Comment cmnt(masm_, "[ Conditional");
02273 Label then, else_, exit;
02274 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
02275 Branch(false, &else_);
02276 __ bind(&then);
02277 Load(node->then_expression(), typeof_state());
02278 __ jmp(&exit);
02279 __ bind(&else_);
02280 Load(node->else_expression(), typeof_state());
02281 __ bind(&exit);
02282 }
02283
02284
02285 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
02286 if (slot->type() == Slot::LOOKUP) {
02287 ASSERT(slot->var()->mode() == Variable::DYNAMIC);
02288
02289
02290 frame_->Push(esi);
02291 frame_->Push(Immediate(slot->var()->name()));
02292
02293 if (typeof_state == INSIDE_TYPEOF) {
02294 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
02295 } else {
02296 __ CallRuntime(Runtime::kLoadContextSlot, 2);
02297 }
02298 frame_->Push(eax);
02299
02300 } else {
02301
02302
02303
02304 if (slot->var()->mode() == Variable::CONST) {
02305
02306
02307
02308 Comment cmnt(masm_, "[ Load const");
02309 Label exit;
02310 __ mov(eax, SlotOperand(slot, ecx));
02311 __ cmp(eax, Factory::the_hole_value());
02312 __ j(not_equal, &exit);
02313 __ mov(eax, Factory::undefined_value());
02314 __ bind(&exit);
02315 frame_->Push(eax);
02316 } else {
02317 frame_->Push(SlotOperand(slot, ecx));
02318 }
02319 }
02320 }
02321
02322
02323 void CodeGenerator::VisitSlot(Slot* node) {
02324 Comment cmnt(masm_, "[ Slot");
02325 LoadFromSlot(node, typeof_state());
02326 }
02327
02328
02329 void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
02330 Comment cmnt(masm_, "[ VariableProxy");
02331 Variable* var = node->var();
02332 Expression* expr = var->rewrite();
02333 if (expr != NULL) {
02334 Visit(expr);
02335 } else {
02336 ASSERT(var->is_global());
02337 Reference ref(this, node);
02338 ref.GetValue(typeof_state());
02339 }
02340 }
02341
02342
02343 void CodeGenerator::VisitLiteral(Literal* node) {
02344 Comment cmnt(masm_, "[ Literal");
02345 if (node->handle()->IsSmi() && !IsInlineSmi(node)) {
02346
02347
02348 int bits = reinterpret_cast<int>(*node->handle());
02349 __ mov(eax, bits & 0x0000FFFF);
02350 __ xor_(eax, bits & 0xFFFF0000);
02351 frame_->Push(eax);
02352 } else {
02353 frame_->Push(Immediate(node->handle()));
02354 }
02355 }
02356
02357
02358 class RegExpDeferred: public DeferredCode {
02359 public:
02360 RegExpDeferred(CodeGenerator* generator, RegExpLiteral* node)
02361 : DeferredCode(generator), node_(node) {
02362 set_comment("[ RegExpDeferred");
02363 }
02364 virtual void Generate();
02365 private:
02366 RegExpLiteral* node_;
02367 };
02368
02369
02370 void RegExpDeferred::Generate() {
02371
02372
02373
02374
02375 __ push(ecx);
02376
02377 __ push(Immediate(Smi::FromInt(node_->literal_index())));
02378
02379 __ push(Immediate(node_->pattern()));
02380
02381 __ push(Immediate(node_->flags()));
02382 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
02383 __ mov(ebx, Operand(eax));
02384 }
02385
02386
02387 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
02388 Comment cmnt(masm_, "[ RegExp Literal");
02389 RegExpDeferred* deferred = new RegExpDeferred(this, node);
02390
02391
02392
02393
02394 __ mov(ecx, frame_->Function());
02395
02396
02397 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset));
02398
02399
02400 int literal_offset =
02401 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
02402 __ mov(ebx, FieldOperand(ecx, literal_offset));
02403
02404
02405
02406 __ cmp(ebx, Factory::undefined_value());
02407 __ j(equal, deferred->enter(), not_taken);
02408 __ bind(deferred->exit());
02409
02410
02411 frame_->Push(ebx);
02412 }
02413
02414
02415
02416
02417
02418
02419 class ObjectLiteralDeferred: public DeferredCode {
02420 public:
02421 ObjectLiteralDeferred(CodeGenerator* generator,
02422 ObjectLiteral* node)
02423 : DeferredCode(generator), node_(node) {
02424 set_comment("[ ObjectLiteralDeferred");
02425 }
02426 virtual void Generate();
02427 private:
02428 ObjectLiteral* node_;
02429 };
02430
02431
02432 void ObjectLiteralDeferred::Generate() {
02433
02434
02435
02436
02437 __ push(ecx);
02438
02439 __ push(Immediate(Smi::FromInt(node_->literal_index())));
02440
02441 __ push(Immediate(node_->constant_properties()));
02442 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
02443 __ mov(ebx, Operand(eax));
02444 }
02445
02446
02447 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
02448 Comment cmnt(masm_, "[ ObjectLiteral");
02449 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node);
02450
02451
02452
02453
02454 __ mov(ecx, frame_->Function());
02455
02456
02457 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset));
02458
02459
02460 int literal_offset =
02461 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
02462 __ mov(ebx, FieldOperand(ecx, literal_offset));
02463
02464
02465
02466 __ cmp(ebx, Factory::undefined_value());
02467 __ j(equal, deferred->enter(), not_taken);
02468 __ bind(deferred->exit());
02469
02470
02471 frame_->Push(ebx);
02472
02473 __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
02474
02475 frame_->Push(eax);
02476
02477
02478 for (int i = 0; i < node->properties()->length(); i++) {
02479 ObjectLiteral::Property* property = node->properties()->at(i);
02480 switch (property->kind()) {
02481 case ObjectLiteral::Property::CONSTANT: break;
02482 case ObjectLiteral::Property::COMPUTED: {
02483 Handle<Object> key(property->key()->handle());
02484 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
02485 if (key->IsSymbol()) {
02486 __ mov(eax, frame_->Top());
02487 frame_->Push(eax);
02488 Load(property->value());
02489 frame_->Pop(eax);
02490 __ Set(ecx, Immediate(key));
02491 __ call(ic, RelocInfo::CODE_TARGET);
02492 frame_->Pop();
02493
02494 break;
02495 }
02496
02497 }
02498 case ObjectLiteral::Property::PROTOTYPE: {
02499 __ mov(eax, frame_->Top());
02500 frame_->Push(eax);
02501 Load(property->key());
02502 Load(property->value());
02503 __ CallRuntime(Runtime::kSetProperty, 3);
02504
02505 break;
02506 }
02507 case ObjectLiteral::Property::SETTER: {
02508
02509
02510 __ mov(eax, frame_->Top());
02511 frame_->Push(eax);
02512 Load(property->key());
02513 frame_->Push(Immediate(Smi::FromInt(1)));
02514 Load(property->value());
02515 __ CallRuntime(Runtime::kDefineAccessor, 4);
02516
02517 break;
02518 }
02519 case ObjectLiteral::Property::GETTER: {
02520
02521
02522 __ mov(eax, frame_->Top());
02523 frame_->Push(eax);
02524 Load(property->key());
02525 frame_->Push(Immediate(Smi::FromInt(0)));
02526 Load(property->value());
02527 __ CallRuntime(Runtime::kDefineAccessor, 4);
02528
02529 break;
02530 }
02531 default: UNREACHABLE();
02532 }
02533 }
02534 }
02535
02536
02537 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
02538 Comment cmnt(masm_, "[ ArrayLiteral");
02539
02540
02541 frame_->Push(Immediate(node->literals()));
02542
02543 __ mov(ecx, frame_->Function());
02544
02545 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset));
02546 frame_->Push(ecx);
02547 __ CallRuntime(Runtime::kCreateArrayLiteral, 2);
02548
02549
02550 frame_->Push(eax);
02551
02552
02553
02554 for (int i = 0; i < node->values()->length(); i++) {
02555 Expression* value = node->values()->at(i);
02556
02557
02558
02559 if (value->AsLiteral() == NULL) {
02560
02561 Load(value);
02562
02563
02564 frame_->Pop(eax);
02565
02566 __ mov(ecx, frame_->Top());
02567
02568 __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
02569
02570
02571 int offset = i * kPointerSize + Array::kHeaderSize;
02572 __ mov(FieldOperand(ecx, offset), eax);
02573
02574
02575 __ RecordWrite(ecx, offset, eax, ebx);
02576 }
02577 }
02578 }
02579
02580
02581 bool CodeGenerator::IsInlineSmi(Literal* literal) {
02582 if (literal == NULL || !literal->handle()->IsSmi()) return false;
02583 int int_value = Smi::cast(*literal->handle())->value();
02584 return is_intn(int_value, kMaxSmiInlinedBits);
02585 }
02586
02587
02588 void CodeGenerator::VisitAssignment(Assignment* node) {
02589 Comment cmnt(masm_, "[ Assignment");
02590
02591 RecordStatementPosition(node);
02592 Reference target(this, node->target());
02593 if (target.is_illegal()) return;
02594
02595 if (node->op() == Token::ASSIGN ||
02596 node->op() == Token::INIT_VAR ||
02597 node->op() == Token::INIT_CONST) {
02598 Load(node->value());
02599
02600 } else {
02601 target.GetValue(NOT_INSIDE_TYPEOF);
02602 Literal* literal = node->value()->AsLiteral();
02603 if (IsInlineSmi(literal)) {
02604 SmiOperation(node->binary_op(), node->type(), literal->handle(), false,
02605 NO_OVERWRITE);
02606 } else {
02607 Load(node->value());
02608 GenericBinaryOperation(node->binary_op(), node->type());
02609 }
02610 }
02611
02612 Variable* var = node->target()->AsVariableProxy()->AsVariable();
02613 if (var != NULL &&
02614 var->mode() == Variable::CONST &&
02615 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
02616
02617 } else {
02618 __ RecordPosition(node->position());
02619 if (node->op() == Token::INIT_CONST) {
02620
02621
02622
02623 target.SetValue(CONST_INIT);
02624 } else {
02625 target.SetValue(NOT_CONST_INIT);
02626 }
02627 }
02628 }
02629
02630
02631 void CodeGenerator::VisitThrow(Throw* node) {
02632 Comment cmnt(masm_, "[ Throw");
02633
02634 Load(node->exception());
02635 __ RecordPosition(node->position());
02636 __ CallRuntime(Runtime::kThrow, 1);
02637 frame_->Push(eax);
02638 }
02639
02640
02641 void CodeGenerator::VisitProperty(Property* node) {
02642 Comment cmnt(masm_, "[ Property");
02643
02644 Reference property(this, node);
02645 property.GetValue(typeof_state());
02646 }
02647
02648
02649 void CodeGenerator::VisitCall(Call* node) {
02650 Comment cmnt(masm_, "[ Call");
02651
02652 ZoneList<Expression*>* args = node->arguments();
02653
02654 RecordStatementPosition(node);
02655
02656
02657 Expression* function = node->expression();
02658 Variable* var = function->AsVariableProxy()->AsVariable();
02659 Property* property = function->AsProperty();
02660
02661
02662
02663
02664
02665
02666
02667
02668
02669
02670 if (var != NULL && !var->is_this() && var->is_global()) {
02671
02672
02673
02674
02675
02676 frame_->Push(Immediate(var->name()));
02677
02678
02679
02680
02681 LoadGlobal();
02682
02683
02684 for (int i = 0; i < args->length(); i++) {
02685 Load(args->at(i));
02686 }
02687
02688
02689 Handle<Code> stub = ComputeCallInitialize(args->length());
02690 __ RecordPosition(node->position());
02691 __ call(stub, RelocInfo::CODE_TARGET_CONTEXT);
02692 __ mov(esi, frame_->Context());
02693
02694
02695 __ mov(frame_->Top(), eax);
02696
02697 } else if (var != NULL && var->slot() != NULL &&
02698 var->slot()->type() == Slot::LOOKUP) {
02699
02700
02701
02702
02703
02704 frame_->Push(esi);
02705 frame_->Push(Immediate(var->name()));
02706 __ CallRuntime(Runtime::kLoadContextSlot, 2);
02707
02708
02709
02710 frame_->Push(eax);
02711 frame_->Push(edx);
02712
02713
02714 CallWithArguments(args, node->position());
02715
02716 } else if (property != NULL) {
02717
02718 Literal* literal = property->key()->AsLiteral();
02719
02720 if (literal != NULL && literal->handle()->IsSymbol()) {
02721
02722
02723
02724
02725
02726 frame_->Push(Immediate(literal->handle()));
02727 Load(property->obj());
02728
02729
02730 for (int i = 0; i < args->length(); i++) Load(args->at(i));
02731
02732
02733 Handle<Code> stub = ComputeCallInitialize(args->length());
02734 __ RecordPosition(node->position());
02735 __ call(stub, RelocInfo::CODE_TARGET);
02736 __ mov(esi, frame_->Context());
02737
02738
02739 __ mov(frame_->Top(), eax);
02740
02741 } else {
02742
02743
02744
02745
02746
02747 Reference ref(this, property);
02748 ref.GetValue(NOT_INSIDE_TYPEOF);
02749
02750
02751
02752 frame_->Push(frame_->Element(ref.size()));
02753
02754
02755 CallWithArguments(args, node->position());
02756 }
02757
02758 } else {
02759
02760
02761
02762
02763
02764 Load(function);
02765
02766
02767 LoadGlobalReceiver(eax);
02768
02769
02770 CallWithArguments(args, node->position());
02771 }
02772 }
02773
02774
02775 void CodeGenerator::VisitCallNew(CallNew* node) {
02776 Comment cmnt(masm_, "[ CallNew");
02777
02778
02779
02780
02781
02782
02783
02784
02785
02786
02787 Load(node->expression());
02788 LoadGlobal();
02789
02790
02791 ZoneList<Expression*>* args = node->arguments();
02792 for (int i = 0; i < args->length(); i++) Load(args->at(i));
02793
02794
02795
02796
02797 __ Set(eax, Immediate(args->length()));
02798
02799
02800
02801 __ mov(edi, frame_->Element(args->length() + 1));
02802
02803
02804
02805 __ RecordPosition(node->position());
02806 __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
02807 RelocInfo::CONSTRUCT_CALL);
02808
02809 __ mov(frame_->Top(), eax);
02810 }
02811
02812
02813 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
02814 ASSERT(args->length() == 1);
02815 Load(args->at(0));
02816 frame_->Pop(eax);
02817 __ test(eax, Immediate(kSmiTagMask));
02818 cc_reg_ = zero;
02819 }
02820
02821
02822 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
02823 ASSERT(args->length() == 1);
02824 Load(args->at(0));
02825 frame_->Pop(eax);
02826 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
02827 cc_reg_ = zero;
02828 }
02829
02830
02831
02832
02833
02834
02835
02836
02837 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
02838 ASSERT(args->length() == 2);
02839
02840 Label slow_case;
02841 Label end;
02842 Label not_a_flat_string;
02843 Label not_a_cons_string_either;
02844 Label try_again_with_new_string;
02845 Label ascii_string;
02846 Label got_char_code;
02847
02848
02849 Load(args->at(0));
02850 frame_->Pop(eax);
02851
02852 ASSERT(kSmiTag == 0);
02853 __ test(eax, Immediate(kSmiTagMask));
02854 __ j(zero, &slow_case, not_taken);
02855
02856
02857 Load(args->at(1));
02858 frame_->Pop(ebx);
02859
02860
02861 ASSERT(kSmiTag == 0);
02862 __ test(ebx, Immediate(kSmiTagMask | 0x80000000));
02863 __ j(not_zero, &slow_case, not_taken);
02864
02865 __ sar(ebx, kSmiTagSize);
02866
02867 __ bind(&try_again_with_new_string);
02868
02869 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
02870 __ movzx_b(edi, FieldOperand(edx, Map::kInstanceTypeOffset));
02871
02872 __ test(edi, Immediate(kIsNotStringMask));
02873 __ j(not_zero, &slow_case, not_taken);
02874
02875
02876
02877 ASSERT(kLongStringTag == 0);
02878 ASSERT(kMediumStringTag + String::kLongLengthShift ==
02879 String::kMediumLengthShift);
02880 ASSERT(kShortStringTag + String::kLongLengthShift ==
02881 String::kShortLengthShift);
02882 __ mov(ecx, Operand(edi));
02883 __ and_(ecx, kStringSizeMask);
02884 __ add(Operand(ecx), Immediate(String::kLongLengthShift));
02885
02886 __ mov(edx, FieldOperand(eax, String::kLengthOffset));
02887 __ shr(edx);
02888
02889
02890
02891 __ cmp(ebx, Operand(edx));
02892 __ j(greater_equal, &slow_case, not_taken);
02893
02894
02895 ASSERT(kSeqStringTag == 0);
02896 __ test(edi, Immediate(kStringRepresentationMask));
02897 __ j(not_zero, ¬_a_flat_string, not_taken);
02898
02899
02900 __ test(edi, Immediate(kStringEncodingMask));
02901 __ j(not_zero, &ascii_string, taken);
02902
02903
02904
02905 __ movzx_w(eax,
02906 FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
02907 __ jmp(&got_char_code);
02908
02909
02910 __ bind(&ascii_string);
02911
02912 __ movzx_b(eax, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize));
02913
02914 __ bind(&got_char_code);
02915 ASSERT(kSmiTag == 0);
02916 __ shl(eax, kSmiTagSize);
02917 frame_->Push(eax);
02918 __ jmp(&end);
02919
02920
02921 __ bind(¬_a_flat_string);
02922 __ and_(edi, kStringRepresentationMask);
02923 __ cmp(edi, kConsStringTag);
02924 __ j(not_equal, ¬_a_cons_string_either, not_taken);
02925
02926
02927
02928 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset));
02929 __ jmp(&try_again_with_new_string);
02930
02931 __ bind(¬_a_cons_string_either);
02932 __ cmp(edi, kSlicedStringTag);
02933 __ j(not_equal, &slow_case, not_taken);
02934
02935
02936
02937 __ add(ebx, FieldOperand(eax, SlicedString::kStartOffset));
02938 __ j(overflow, &slow_case);
02939
02940 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset));
02941 __ jmp(&try_again_with_new_string);
02942
02943 __ bind(&slow_case);
02944 frame_->Push(Immediate(Factory::undefined_value()));
02945
02946 __ bind(&end);
02947 }
02948
02949
02950 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
02951 ASSERT(args->length() == 1);
02952 Load(args->at(0));
02953 Label answer;
02954
02955
02956
02957
02958 frame_->Pop(eax);
02959 __ mov(ecx, Operand(eax));
02960 __ and_(ecx, kSmiTagMask);
02961 __ xor_(ecx, kSmiTagMask);
02962 __ j(not_equal, &answer, not_taken);
02963
02964 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
02965 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
02966
02967 __ cmp(eax, JS_ARRAY_TYPE);
02968 __ bind(&answer);
02969 cc_reg_ = equal;
02970 }
02971
02972
02973 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
02974 ASSERT(args->length() == 0);
02975
02976
02977
02978
02979 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters())));
02980
02981
02982 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
02983 __ CallStub(&stub);
02984 frame_->Push(eax);
02985 }
02986
02987
02988 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
02989 ASSERT(args->length() == 1);
02990 Label leave;
02991 Load(args->at(0));
02992 __ mov(eax, frame_->Top());
02993
02994 __ test(eax, Immediate(kSmiTagMask));
02995 __ j(zero, &leave, taken);
02996
02997 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
02998 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
02999
03000 __ cmp(ecx, JS_VALUE_TYPE);
03001 __ j(not_equal, &leave, not_taken);
03002 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
03003 __ mov(frame_->Top(), eax);
03004 __ bind(&leave);
03005 }
03006
03007
03008 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
03009 ASSERT(args->length() == 2);
03010 Label leave;
03011 Load(args->at(0));
03012 Load(args->at(1));
03013 __ mov(eax, frame_->Element(1));
03014 __ mov(ecx, frame_->Top());
03015
03016 __ test(eax, Immediate(kSmiTagMask));
03017 __ j(zero, &leave, taken);
03018
03019 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
03020 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
03021
03022 __ cmp(ebx, JS_VALUE_TYPE);
03023 __ j(not_equal, &leave, not_taken);
03024
03025 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx);
03026
03027 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx);
03028
03029 __ bind(&leave);
03030 __ mov(ecx, frame_->Top());
03031 frame_->Pop();
03032 __ mov(frame_->Top(), ecx);
03033 }
03034
03035
03036 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
03037 ASSERT(args->length() == 1);
03038
03039
03040
03041 Load(args->at(0));
03042 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters())));
03043
03044
03045 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
03046 __ CallStub(&stub);
03047 __ mov(frame_->Top(), eax);
03048 }
03049
03050
03051 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
03052 ASSERT(args->length() == 2);
03053
03054
03055 Load(args->at(0));
03056 Load(args->at(1));
03057 frame_->Pop(eax);
03058 frame_->Pop(ecx);
03059 __ cmp(eax, Operand(ecx));
03060 cc_reg_ = equal;
03061 }
03062
03063
03064 void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
03065 if (CheckForInlineRuntimeCall(node)) return;
03066
03067 ZoneList<Expression*>* args = node->arguments();
03068 Comment cmnt(masm_, "[ CallRuntime");
03069 Runtime::Function* function = node->function();
03070
03071 if (function == NULL) {
03072
03073 frame_->Push(Immediate(node->name()));
03074
03075 __ mov(edx, GlobalObject());
03076 frame_->Push(FieldOperand(edx, GlobalObject::kBuiltinsOffset));
03077 }
03078
03079
03080 for (int i = 0; i < args->length(); i++)
03081 Load(args->at(i));
03082
03083 if (function != NULL) {
03084
03085 __ CallRuntime(function, args->length());
03086 frame_->Push(eax);
03087 } else {
03088
03089 Handle<Code> stub = ComputeCallInitialize(args->length());
03090 __ Set(eax, Immediate(args->length()));
03091 __ call(stub, RelocInfo::CODE_TARGET);
03092 __ mov(esi, frame_->Context());
03093 __ mov(frame_->Top(), eax);
03094 }
03095 }
03096
03097
03098 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
03099 Comment cmnt(masm_, "[ UnaryOperation");
03100
03101 Token::Value op = node->op();
03102
03103 if (op == Token::NOT) {
03104 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF,
03105 false_target(), true_target(), true);
03106 cc_reg_ = NegateCondition(cc_reg_);
03107
03108 } else if (op == Token::DELETE) {
03109 Property* property = node->expression()->AsProperty();
03110 if (property != NULL) {
03111 Load(property->obj());
03112 Load(property->key());
03113 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
03114 frame_->Push(eax);
03115 return;
03116 }
03117
03118 Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
03119 if (variable != NULL) {
03120 Slot* slot = variable->slot();
03121 if (variable->is_global()) {
03122 LoadGlobal();
03123 frame_->Push(Immediate(variable->name()));
03124 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
03125 frame_->Push(eax);
03126 return;
03127
03128 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
03129
03130 frame_->Push(esi);
03131 frame_->Push(Immediate(variable->name()));
03132 __ CallRuntime(Runtime::kLookupContext, 2);
03133
03134 frame_->Push(eax);
03135 frame_->Push(Immediate(variable->name()));
03136 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
03137 frame_->Push(eax);
03138 return;
03139 }
03140
03141
03142
03143 frame_->Push(Immediate(Factory::false_value()));
03144
03145 } else {
03146
03147 Load(node->expression());
03148 __ Set(frame_->Top(), Immediate(Factory::true_value()));
03149 }
03150
03151 } else if (op == Token::TYPEOF) {
03152
03153
03154 LoadTypeofExpression(node->expression());
03155 __ CallRuntime(Runtime::kTypeof, 1);
03156 frame_->Push(eax);
03157
03158 } else {
03159 Load(node->expression());
03160 switch (op) {
03161 case Token::NOT:
03162 case Token::DELETE:
03163 case Token::TYPEOF:
03164 UNREACHABLE();
03165 break;
03166
03167 case Token::SUB: {
03168 UnarySubStub stub;
03169
03170 frame_->Pop(eax);
03171 __ CallStub(&stub);
03172 frame_->Push(eax);
03173 break;
03174 }
03175
03176 case Token::BIT_NOT: {
03177
03178 Label smi_label;
03179 Label continue_label;
03180 frame_->Pop(eax);
03181 __ test(eax, Immediate(kSmiTagMask));
03182 __ j(zero, &smi_label, taken);
03183
03184 frame_->Push(eax);
03185 __ InvokeBuiltin(Builtins::BIT_NOT, CALL_FUNCTION);
03186
03187 __ jmp(&continue_label);
03188 __ bind(&smi_label);
03189 __ not_(eax);
03190 __ and_(eax, ~kSmiTagMask);
03191 __ bind(&continue_label);
03192 frame_->Push(eax);
03193 break;
03194 }
03195
03196 case Token::VOID:
03197 __ mov(frame_->Top(), Factory::undefined_value());
03198 break;
03199
03200 case Token::ADD: {
03201
03202 Label continue_label;
03203 frame_->Pop(eax);
03204 __ test(eax, Immediate(kSmiTagMask));
03205 __ j(zero, &continue_label);
03206
03207 frame_->Push(eax);
03208 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
03209
03210 __ bind(&continue_label);
03211 frame_->Push(eax);
03212 break;
03213 }
03214
03215 default:
03216 UNREACHABLE();
03217 }
03218 }
03219 }
03220
03221
03222 class CountOperationDeferred: public DeferredCode {
03223 public:
03224 CountOperationDeferred(CodeGenerator* generator,
03225 bool is_postfix,
03226 bool is_increment,
03227 int result_offset)
03228 : DeferredCode(generator),
03229 is_postfix_(is_postfix),
03230 is_increment_(is_increment),
03231 result_offset_(result_offset) {
03232 set_comment("[ CountOperationDeferred");
03233 }
03234
03235 virtual void Generate();
03236
03237 private:
03238 bool is_postfix_;
03239 bool is_increment_;
03240 int result_offset_;
03241 };
03242
03243
03244 class RevertToNumberStub: public CodeStub {
03245 public:
03246 explicit RevertToNumberStub(bool is_increment)
03247 : is_increment_(is_increment) { }
03248
03249 private:
03250 bool is_increment_;
03251
03252 Major MajorKey() { return RevertToNumber; }
03253 int MinorKey() { return is_increment_ ? 1 : 0; }
03254 void Generate(MacroAssembler* masm);
03255
03256 #ifdef DEBUG
03257 void Print() {
03258 PrintF("RevertToNumberStub (is_increment %s)\n",
03259 is_increment_ ? "true" : "false");
03260 }
03261 #endif
03262 };
03263
03264
03265 class CounterOpStub: public CodeStub {
03266 public:
03267 CounterOpStub(int result_offset, bool is_postfix, bool is_increment)
03268 : result_offset_(result_offset),
03269 is_postfix_(is_postfix),
03270 is_increment_(is_increment) { }
03271
03272 private:
03273 int result_offset_;
03274 bool is_postfix_;
03275 bool is_increment_;
03276
03277 Major MajorKey() { return CounterOp; }
03278 int MinorKey() {
03279 return ((result_offset_ << 2) |
03280 (is_postfix_ ? 2 : 0) |
03281 (is_increment_ ? 1 : 0));
03282 }
03283 void Generate(MacroAssembler* masm);
03284
03285 #ifdef DEBUG
03286 void Print() {
03287 PrintF("CounterOpStub (result_offset %d), (is_postfix %s),"
03288 " (is_increment %s)\n",
03289 result_offset_,
03290 is_postfix_ ? "true" : "false",
03291 is_increment_ ? "true" : "false");
03292 }
03293 #endif
03294 };
03295
03296
03297 void CountOperationDeferred::Generate() {
03298 if (is_postfix_) {
03299 RevertToNumberStub to_number_stub(is_increment_);
03300 __ CallStub(&to_number_stub);
03301 }
03302 CounterOpStub stub(result_offset_, is_postfix_, is_increment_);
03303 __ CallStub(&stub);
03304 }
03305
03306
03307 void CodeGenerator::VisitCountOperation(CountOperation* node) {
03308 Comment cmnt(masm_, "[ CountOperation");
03309
03310 bool is_postfix = node->is_postfix();
03311 bool is_increment = node->op() == Token::INC;
03312
03313 Variable* var = node->expression()->AsVariableProxy()->AsVariable();
03314 bool is_const = (var != NULL && var->mode() == Variable::CONST);
03315
03316
03317 if (is_postfix) {
03318 frame_->Push(Immediate(0));
03319 }
03320
03321 { Reference target(this, node->expression());
03322 if (target.is_illegal()) return;
03323 target.GetValue(NOT_INSIDE_TYPEOF);
03324
03325 CountOperationDeferred* deferred =
03326 new CountOperationDeferred(this, is_postfix, is_increment,
03327 target.size() * kPointerSize);
03328
03329 frame_->Pop(eax);
03330
03331
03332 if (is_postfix) {
03333 __ mov(frame_->Element(target.size()), eax);
03334 }
03335
03336
03337 if (is_increment) {
03338 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
03339 } else {
03340 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
03341 }
03342
03343
03344
03345
03346 __ j(overflow, deferred->enter(), not_taken);
03347 __ test(eax, Immediate(kSmiTagMask));
03348 __ j(not_zero, deferred->enter(), not_taken);
03349
03350
03351 __ bind(deferred->exit());
03352 frame_->Push(eax);
03353 if (!is_const) target.SetValue(NOT_CONST_INIT);
03354 }
03355
03356
03357 if (is_postfix) {
03358 frame_->Pop();
03359 }
03360 }
03361
03362
03363 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
03364 Comment cmnt(masm_, "[ BinaryOperation");
03365 Token::Value op = node->op();
03366
03367
03368
03369
03370
03371
03372
03373
03374
03375
03376
03377
03378
03379 if (op == Token::AND) {
03380 Label is_true;
03381 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &is_true,
03382 false_target(), false);
03383 if (has_cc()) {
03384 Branch(false, false_target());
03385
03386
03387 __ bind(&is_true);
03388 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(),
03389 false_target(), false);
03390
03391 } else {
03392 Label pop_and_continue, exit;
03393
03394
03395
03396
03397
03398 __ mov(eax, frame_->Top());
03399 frame_->Push(eax);
03400 ToBoolean(&pop_and_continue, &exit);
03401 Branch(false, &exit);
03402
03403
03404 __ bind(&pop_and_continue);
03405 frame_->Pop();
03406
03407
03408 __ bind(&is_true);
03409 Load(node->right());
03410
03411
03412 __ bind(&exit);
03413 }
03414
03415 } else if (op == Token::OR) {
03416 Label is_false;
03417 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(),
03418 &is_false, false);
03419 if (has_cc()) {
03420 Branch(true, true_target());
03421
03422
03423 __ bind(&is_false);
03424 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(),
03425 false_target(), false);
03426
03427 } else {
03428 Label pop_and_continue, exit;
03429
03430
03431
03432
03433
03434 __ mov(eax, frame_->Top());
03435 frame_->Push(eax);
03436 ToBoolean(&exit, &pop_and_continue);
03437 Branch(true, &exit);
03438
03439
03440 __ bind(&pop_and_continue);
03441 frame_->Pop();
03442
03443
03444 __ bind(&is_false);
03445 Load(node->right());
03446
03447
03448 __ bind(&exit);
03449 }
03450
03451 } else {
03452
03453
03454 OverwriteMode overwrite_mode = NO_OVERWRITE;
03455 if (node->left()->AsBinaryOperation() != NULL &&
03456 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) {
03457 overwrite_mode = OVERWRITE_LEFT;
03458 } else if (node->right()->AsBinaryOperation() != NULL &&
03459 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) {
03460 overwrite_mode = OVERWRITE_RIGHT;
03461 }
03462
03463
03464
03465 Literal* lliteral = node->left()->AsLiteral();
03466 Literal* rliteral = node->right()->AsLiteral();
03467
03468 if (IsInlineSmi(rliteral)) {
03469 Load(node->left());
03470 SmiOperation(node->op(), node->type(), rliteral->handle(), false,
03471 overwrite_mode);
03472 } else if (IsInlineSmi(lliteral)) {
03473 Load(node->right());
03474 SmiOperation(node->op(), node->type(), lliteral->handle(), true,
03475 overwrite_mode);
03476 } else {
03477 Load(node->left());
03478 Load(node->right());
03479 GenericBinaryOperation(node->op(), node->type(), overwrite_mode);
03480 }
03481 }
03482 }
03483
03484
03485 void CodeGenerator::VisitThisFunction(ThisFunction* node) {
03486 frame_->Push(frame_->Function());
03487 }
03488
03489
03490 class InstanceofStub: public CodeStub {
03491 public:
03492 InstanceofStub() { }
03493
03494 void Generate(MacroAssembler* masm);
03495
03496 private:
03497 Major MajorKey() { return Instanceof; }
03498 int MinorKey() { return 0; }
03499 };
03500
03501
03502 void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
03503 Comment cmnt(masm_, "[ CompareOperation");
03504
03505
03506 Expression* left = node->left();
03507 Expression* right = node->right();
03508 Token::Value op = node->op();
03509
03510
03511
03512
03513
03514
03515 if (op == Token::EQ || op == Token::EQ_STRICT) {
03516 bool left_is_null =
03517 left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
03518 bool right_is_null =
03519 right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
03520
03521 if (left_is_null || right_is_null) {
03522 Load(left_is_null ? right : left);
03523 Label exit, undetectable;
03524 frame_->Pop(eax);
03525 __ cmp(eax, Factory::null_value());
03526
03527
03528
03529 if (op != Token::EQ_STRICT) {
03530 __ j(equal, &exit);
03531 __ cmp(eax, Factory::undefined_value());
03532
03533
03534 __ j(equal, &exit);
03535 __ test(eax, Immediate(kSmiTagMask));
03536
03537 __ j(not_equal, &undetectable);
03538 __ jmp(false_target());
03539
03540 __ bind(&undetectable);
03541 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
03542 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
03543 __ and_(ecx, 1 << Map::kIsUndetectable);
03544 __ cmp(ecx, 1 << Map::kIsUndetectable);
03545 }
03546
03547 __ bind(&exit);
03548
03549 cc_reg_ = equal;
03550 return;
03551 }
03552 }
03553
03554
03555
03556
03557
03558 UnaryOperation* operation = left->AsUnaryOperation();
03559 if ((op == Token::EQ || op == Token::EQ_STRICT) &&
03560 (operation != NULL && operation->op() == Token::TYPEOF) &&
03561 (right->AsLiteral() != NULL &&
03562 right->AsLiteral()->handle()->IsString())) {
03563 Handle<String> check(String::cast(*right->AsLiteral()->handle()));
03564
03565
03566 LoadTypeofExpression(operation->expression());
03567 frame_->Pop(edx);
03568
03569 if (check->Equals(Heap::number_symbol())) {
03570 __ test(edx, Immediate(kSmiTagMask));
03571 __ j(zero, true_target());
03572 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
03573 __ cmp(edx, Factory::heap_number_map());
03574 cc_reg_ = equal;
03575
03576 } else if (check->Equals(Heap::string_symbol())) {
03577 __ test(edx, Immediate(kSmiTagMask));
03578 __ j(zero, false_target());
03579
03580 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
03581
03582
03583 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
03584 __ and_(ecx, 1 << Map::kIsUndetectable);
03585 __ cmp(ecx, 1 << Map::kIsUndetectable);
03586 __ j(equal, false_target());
03587
03588 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
03589 __ cmp(ecx, FIRST_NONSTRING_TYPE);
03590 cc_reg_ = less;
03591
03592 } else if (check->Equals(Heap::boolean_symbol())) {
03593 __ cmp(edx, Factory::true_value());
03594 __ j(equal, true_target());
03595 __ cmp(edx, Factory::false_value());
03596 cc_reg_ = equal;
03597
03598 } else if (check->Equals(Heap::undefined_symbol())) {
03599 __ cmp(edx, Factory::undefined_value());
03600 __ j(equal, true_target());
03601
03602 __ test(edx, Immediate(kSmiTagMask));
03603 __ j(zero, false_target());
03604
03605
03606 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
03607 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
03608 __ and_(ecx, 1 << Map::kIsUndetectable);
03609 __ cmp(ecx, 1 << Map::kIsUndetectable);
03610
03611 cc_reg_ = equal;
03612
03613 } else if (check->Equals(Heap::function_symbol())) {
03614 __ test(edx, Immediate(kSmiTagMask));
03615 __ j(zero, false_target());
03616 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
03617 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset));
03618 __ cmp(edx, JS_FUNCTION_TYPE);
03619 cc_reg_ = equal;
03620
03621 } else if (check->Equals(Heap::object_symbol())) {
03622 __ test(edx, Immediate(kSmiTagMask));
03623 __ j(zero, false_target());
03624
03625 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
03626 __ cmp(edx, Factory::null_value());
03627 __ j(equal, true_target());
03628
03629
03630 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset));
03631 __ and_(edx, 1 << Map::kIsUndetectable);
03632 __ cmp(edx, 1 << Map::kIsUndetectable);
03633 __ j(equal, false_target());
03634
03635 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
03636 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
03637 __ j(less, false_target());
03638 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
03639 cc_reg_ = less_equal;
03640
03641 } else {
03642
03643
03644 __ jmp(false_target());
03645 }
03646 return;
03647 }
03648
03649 Condition cc = no_condition;
03650 bool strict = false;
03651 switch (op) {
03652 case Token::EQ_STRICT:
03653 strict = true;
03654
03655 case Token::EQ:
03656 cc = equal;
03657 break;
03658 case Token::LT:
03659 cc = less;
03660 break;
03661 case Token::GT:
03662 cc = greater;
03663 break;
03664 case Token::LTE:
03665 cc = less_equal;
03666 break;
03667 case Token::GTE:
03668 cc = greater_equal;
03669 break;
03670 case Token::IN: {
03671 Load(left);
03672 Load(right);
03673 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
03674 frame_->Push(eax);
03675 return;
03676 }
03677 case Token::INSTANCEOF: {
03678 Load(left);
03679 Load(right);
03680 InstanceofStub stub;
03681 __ CallStub(&stub);
03682 __ test(eax, Operand(eax));
03683 cc_reg_ = zero;
03684 return;
03685 }
03686 default:
03687 UNREACHABLE();
03688 }
03689
03690
03691
03692 if (IsInlineSmi(left->AsLiteral())) {
03693 Load(right);
03694 SmiComparison(ReverseCondition(cc), left->AsLiteral()->handle(), strict);
03695 return;
03696 }
03697 if (IsInlineSmi(right->AsLiteral())) {
03698 Load(left);
03699 SmiComparison(cc, right->AsLiteral()->handle(), strict);
03700 return;
03701 }
03702
03703 Load(left);
03704 Load(right);
03705 Comparison(cc, strict);
03706 }
03707
03708
03709 void CodeGenerator::RecordStatementPosition(Node* node) {
03710 if (FLAG_debug_info) {
03711 int pos = node->statement_pos();
03712 if (pos != RelocInfo::kNoPosition) {
03713 __ RecordStatementPosition(pos);
03714 }
03715 }
03716 }
03717
03718
03719 #undef __
03720 #define __ masm->
03721
03722 Handle<String> Reference::GetName() {
03723 ASSERT(type_ == NAMED);
03724 Property* property = expression_->AsProperty();
03725 if (property == NULL) {
03726
03727 VariableProxy* proxy = expression_->AsVariableProxy();
03728 ASSERT(proxy->AsVariable() != NULL);
03729 ASSERT(proxy->AsVariable()->is_global());
03730 return proxy->name();
03731 } else {
03732 MacroAssembler* masm = cgen_->masm();
03733 __ RecordPosition(property->position());
03734 Literal* raw_name = property->key()->AsLiteral();
03735 ASSERT(raw_name != NULL);
03736 return Handle<String>(String::cast(*raw_name->handle()));
03737 }
03738 }
03739
03740
03741 void Reference::GetValue(TypeofState typeof_state) {
03742 ASSERT(!is_illegal());
03743 ASSERT(!cgen_->has_cc());
03744 MacroAssembler* masm = cgen_->masm();
03745 VirtualFrame* frame = cgen_->frame();
03746 switch (type_) {
03747 case SLOT: {
03748 Comment cmnt(masm, "[ Load from Slot");
03749 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
03750 ASSERT(slot != NULL);
03751 cgen_->LoadFromSlot(slot, typeof_state);
03752 break;
03753 }
03754
03755 case NAMED: {
03756
03757
03758
03759
03760
03761 Comment cmnt(masm, "[ Load from named Property");
03762 Handle<String> name(GetName());
03763 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
03764
03765 __ mov(ecx, name);
03766
03767 Variable* var = expression_->AsVariableProxy()->AsVariable();
03768 if (var != NULL) {
03769 ASSERT(var->is_global());
03770 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
03771 } else {
03772 __ call(ic, RelocInfo::CODE_TARGET);
03773 }
03774 frame->Push(eax);
03775 break;
03776 }
03777
03778 case KEYED: {
03779
03780
03781 Comment cmnt(masm, "[ Load from keyed Property");
03782 Property* property = expression_->AsProperty();
03783 ASSERT(property != NULL);
03784 __ RecordPosition(property->position());
03785 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
03786
03787 Variable* var = expression_->AsVariableProxy()->AsVariable();
03788 if (var != NULL) {
03789 ASSERT(var->is_global());
03790 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
03791 } else {
03792 __ call(ic, RelocInfo::CODE_TARGET);
03793 }
03794 frame->Push(eax);
03795 break;
03796 }
03797
03798 default:
03799 UNREACHABLE();
03800 }
03801 }
03802
03803
03804 void Reference::SetValue(InitState init_state) {
03805 ASSERT(!is_illegal());
03806 ASSERT(!cgen_->has_cc());
03807 MacroAssembler* masm = cgen_->masm();
03808 VirtualFrame* frame = cgen_->frame();
03809 switch (type_) {
03810 case SLOT: {
03811 Comment cmnt(masm, "[ Store to Slot");
03812 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
03813 ASSERT(slot != NULL);
03814 if (slot->type() == Slot::LOOKUP) {
03815 ASSERT(slot->var()->mode() == Variable::DYNAMIC);
03816
03817
03818 frame->Push(esi);
03819 frame->Push(Immediate(slot->var()->name()));
03820
03821 if (init_state == CONST_INIT) {
03822
03823
03824
03825
03826
03827
03828
03829
03830
03831
03832
03833
03834
03835
03836
03837 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
03838 } else {
03839 __ CallRuntime(Runtime::kStoreContextSlot, 3);
03840 }
03841
03842
03843
03844 frame->Push(eax);
03845
03846 } else {
03847 ASSERT(slot->var()->mode() != Variable::DYNAMIC);
03848
03849 Label exit;
03850 if (init_state == CONST_INIT) {
03851 ASSERT(slot->var()->mode() == Variable::CONST);
03852
03853
03854
03855 Comment cmnt(masm, "[ Init const");
03856 __ mov(eax, cgen_->SlotOperand(slot, ecx));
03857 __ cmp(eax, Factory::the_hole_value());
03858 __ j(not_equal, &exit);
03859 }
03860
03861
03862
03863
03864
03865
03866
03867
03868
03869 frame->Pop(eax);
03870 __ mov(cgen_->SlotOperand(slot, ecx), eax);
03871 frame->Push(eax);
03872 if (slot->type() == Slot::CONTEXT) {
03873
03874 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
03875 __ RecordWrite(ecx, offset, eax, ebx);
03876 }
03877
03878
03879
03880 if (init_state == CONST_INIT) __ bind(&exit);
03881 }
03882 break;
03883 }
03884
03885 case NAMED: {
03886 Comment cmnt(masm, "[ Store to named Property");
03887
03888 Handle<String> name(GetName());
03889 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
03890
03891 frame->Pop(eax);
03892
03893 __ mov(ecx, name);
03894 __ call(ic, RelocInfo::CODE_TARGET);
03895 frame->Push(eax);
03896 break;
03897 }
03898
03899 case KEYED: {
03900 Comment cmnt(masm, "[ Store to keyed Property");
03901 Property* property = expression_->AsProperty();
03902 ASSERT(property != NULL);
03903 __ RecordPosition(property->position());
03904
03905 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
03906
03907 frame->Pop(eax);
03908 __ call(ic, RelocInfo::CODE_TARGET);
03909 frame->Push(eax);
03910 break;
03911 }
03912
03913 default:
03914 UNREACHABLE();
03915 }
03916 }
03917
03918
03919
03920 void ToBooleanStub::Generate(MacroAssembler* masm) {
03921 Label false_result, true_result, not_string;
03922 __ mov(eax, Operand(esp, 1 * kPointerSize));
03923
03924
03925 __ cmp(eax, Factory::null_value());
03926 __ j(equal, &false_result);
03927
03928
03929 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
03930 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
03931
03932
03933 __ movzx_b(ebx, FieldOperand(edx, Map::kBitFieldOffset));
03934 __ and_(ebx, 1 << Map::kIsUndetectable);
03935 __ j(not_zero, &false_result);
03936
03937
03938 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
03939 __ j(above_equal, &true_result);
03940
03941
03942 __ cmp(ecx, FIRST_NONSTRING_TYPE);
03943 __ j(above_equal, ¬_string);
03944 __ and_(ecx, kStringSizeMask);
03945 __ cmp(ecx, kShortStringTag);
03946 __ j(not_equal, &true_result);
03947 __ mov(edx, FieldOperand(eax, String::kLengthOffset));
03948 __ shr(edx, String::kShortLengthShift);
03949 __ j(zero, &false_result);
03950 __ jmp(&true_result);
03951
03952 __ bind(¬_string);
03953
03954 __ cmp(edx, Factory::heap_number_map());
03955 __ j(not_equal, &true_result);
03956 __ fldz();
03957 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
03958 __ fucompp();
03959 __ push(eax);
03960 __ fnstsw_ax();
03961 __ sahf();
03962 __ pop(eax);
03963 __ j(zero, &false_result);
03964
03965
03966
03967 __ bind(&true_result);
03968 __ mov(eax, 1);
03969 __ ret(1 * kPointerSize);
03970 __ bind(&false_result);
03971 __ mov(eax, 0);
03972 __ ret(1 * kPointerSize);
03973 }
03974
03975
03976 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
03977
03978
03979
03980
03981
03982 __ mov(ecx, Operand(ebx));
03983 __ or_(ecx, Operand(eax));
03984
03985 switch (op_) {
03986 case Token::ADD:
03987 __ add(eax, Operand(ebx));
03988 __ j(overflow, slow, not_taken);
03989 break;
03990
03991 case Token::SUB:
03992 __ sub(eax, Operand(ebx));
03993 __ j(overflow, slow, not_taken);
03994 break;
03995
03996 case Token::DIV:
03997 case Token::MOD:
03998
03999 __ cdq();
04000
04001 __ test(ebx, Operand(ebx));
04002 __ j(zero, slow, not_taken);
04003 break;
04004
04005 default:
04006
04007 break;
04008 }
04009
04010
04011 ASSERT(kSmiTag == 0);
04012 __ test(ecx, Immediate(kSmiTagMask));
04013 __ j(not_zero, slow, not_taken);
04014
04015 switch (op_) {
04016 case Token::ADD:
04017 case Token::SUB:
04018
04019 break;
04020
04021 case Token::MUL:
04022
04023 ASSERT(kSmiTag == 0);
04024
04025 __ sar(eax, kSmiTagSize);
04026
04027 __ imul(eax, Operand(ebx));
04028
04029 __ j(overflow, slow, not_taken);
04030
04031 __ NegativeZeroTest(eax, ecx, slow);
04032 break;
04033
04034 case Token::DIV:
04035
04036 __ idiv(ebx);
04037
04038
04039
04040 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
04041 __ cmp(eax, 0x40000000);
04042 __ j(equal, slow);
04043
04044 __ NegativeZeroTest(eax, ecx, slow);
04045
04046 __ test(edx, Operand(edx));
04047 __ j(not_zero, slow);
04048
04049 ASSERT(kSmiTagSize == times_2);
04050 __ lea(eax, Operand(eax, times_2, kSmiTag));
04051 break;
04052
04053 case Token::MOD:
04054
04055 __ idiv(ebx);
04056
04057 __ NegativeZeroTest(edx, ecx, slow);
04058
04059 __ mov(eax, Operand(edx));
04060 break;
04061
04062 case Token::BIT_OR:
04063 __ or_(eax, Operand(ebx));
04064 break;
04065
04066 case Token::BIT_AND:
04067 __ and_(eax, Operand(ebx));
04068 break;
04069
04070 case Token::BIT_XOR:
04071 __ xor_(eax, Operand(ebx));
04072 break;
04073
04074 case Token::SHL:
04075 case Token::SHR:
04076 case Token::SAR:
04077
04078 __ mov(ecx, Operand(ebx));
04079
04080 __ sar(eax, kSmiTagSize);
04081 __ sar(ecx, kSmiTagSize);
04082
04083 switch (op_) {
04084 case Token::SAR:
04085 __ sar(eax);
04086
04087 break;
04088 case Token::SHR:
04089 __ shr(eax);
04090
04091
04092
04093
04094
04095
04096 __ test(eax, Immediate(0xc0000000));
04097 __ j(not_zero, slow, not_taken);
04098 break;
04099 case Token::SHL:
04100 __ shl(eax);
04101
04102 __ lea(ecx, Operand(eax, 0x40000000));
04103 __ test(ecx, Immediate(0x80000000));
04104 __ j(not_zero, slow, not_taken);
04105 break;
04106 default:
04107 UNREACHABLE();
04108 }
04109
04110 ASSERT(kSmiTagSize == times_2);
04111 __ lea(eax, Operand(eax, times_2, kSmiTag));
04112 break;
04113
04114 default:
04115 UNREACHABLE();
04116 break;
04117 }
04118 }
04119
04120
04121 void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
04122 Label call_runtime;
04123
04124 if (flags_ == SMI_CODE_IN_STUB) {
04125
04126
04127 Label slow;
04128 __ mov(ebx, Operand(esp, 1 * kPointerSize));
04129 __ mov(eax, Operand(esp, 2 * kPointerSize));
04130 GenerateSmiCode(masm, &slow);
04131 __ ret(2 * kPointerSize);
04132
04133
04134 __ bind(&slow);
04135 }
04136
04137
04138 __ mov(eax, Operand(esp, 1 * kPointerSize));
04139 __ mov(edx, Operand(esp, 2 * kPointerSize));
04140
04141
04142 switch (op_) {
04143 case Token::ADD:
04144 case Token::SUB:
04145 case Token::MUL:
04146 case Token::DIV: {
04147
04148
04149 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
04150
04151
04152 Label skip_allocation;
04153 switch (mode_) {
04154 case OVERWRITE_LEFT:
04155 __ mov(eax, Operand(edx));
04156
04157 case OVERWRITE_RIGHT:
04158
04159
04160 __ test(eax, Immediate(kSmiTagMask));
04161 __ j(not_zero, &skip_allocation, not_taken);
04162
04163 case NO_OVERWRITE:
04164 FloatingPointHelper::AllocateHeapNumber(masm,
04165 &call_runtime,
04166 ecx,
04167 edx);
04168 __ bind(&skip_allocation);
04169 break;
04170 default: UNREACHABLE();
04171 }
04172 FloatingPointHelper::LoadFloatOperands(masm, ecx);
04173
04174 switch (op_) {
04175 case Token::ADD: __ faddp(1); break;
04176 case Token::SUB: __ fsubp(1); break;
04177 case Token::MUL: __ fmulp(1); break;
04178 case Token::DIV: __ fdivp(1); break;
04179 default: UNREACHABLE();
04180 }
04181 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
04182 __ ret(2 * kPointerSize);
04183 }
04184 case Token::MOD: {
04185
04186 break;
04187 }
04188 case Token::BIT_OR:
04189 case Token::BIT_AND:
04190 case Token::BIT_XOR:
04191 case Token::SAR:
04192 case Token::SHL:
04193 case Token::SHR: {
04194 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
04195 FloatingPointHelper::LoadFloatOperands(masm, ecx);
04196
04197 Label non_int32_operands, non_smi_result, skip_allocation;
04198
04199 __ sub(Operand(esp), Immediate(2 * kPointerSize));
04200
04201
04202 __ fist_s(Operand(esp, 1 * kPointerSize));
04203 __ fild_s(Operand(esp, 1 * kPointerSize));
04204 __ fucompp();
04205 __ fnstsw_ax();
04206 __ sahf();
04207 __ j(not_zero, &non_int32_operands);
04208 __ j(parity_even, &non_int32_operands);
04209
04210
04211 __ fist_s(Operand(esp, 0 * kPointerSize));
04212 __ fild_s(Operand(esp, 0 * kPointerSize));
04213 __ fucompp();
04214 __ fnstsw_ax();
04215 __ sahf();
04216 __ j(not_zero, &non_int32_operands);
04217 __ j(parity_even, &non_int32_operands);
04218
04219
04220 __ pop(eax);
04221 __ pop(ecx);
04222 switch (op_) {
04223 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break;
04224 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
04225 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
04226 case Token::SAR: __ sar(eax); break;
04227 case Token::SHL: __ shl(eax); break;
04228 case Token::SHR: __ shr(eax); break;
04229 default: UNREACHABLE();
04230 }
04231
04232
04233 __ test(eax, Immediate(0xc0000000));
04234 __ j(not_zero, &non_smi_result);
04235
04236
04237 ASSERT(kSmiTagSize == times_2);
04238 __ lea(eax, Operand(eax, times_2, kSmiTag));
04239 __ ret(2 * kPointerSize);
04240
04241
04242 if (op_ != Token::SHR) {
04243 __ bind(&non_smi_result);
04244
04245 __ mov(ebx, Operand(eax));
04246 switch (mode_) {
04247 case OVERWRITE_LEFT:
04248 case OVERWRITE_RIGHT:
04249
04250
04251 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
04252 1 * kPointerSize : 2 * kPointerSize));
04253 __ test(eax, Immediate(kSmiTagMask));
04254 __ j(not_zero, &skip_allocation, not_taken);
04255
04256 case NO_OVERWRITE:
04257 FloatingPointHelper::AllocateHeapNumber(masm, &call_runtime,
04258 ecx, edx);
04259 __ bind(&skip_allocation);
04260 break;
04261 default: UNREACHABLE();
04262 }
04263
04264 __ mov(Operand(esp, 1 * kPointerSize), ebx);
04265 __ fild_s(Operand(esp, 1 * kPointerSize));
04266 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
04267 __ ret(2 * kPointerSize);
04268 }
04269 __ bind(&non_int32_operands);
04270
04271 __ ffree(0);
04272 __ add(Operand(esp), Immediate(2 * kPointerSize));
04273
04274
04275 if (op_ == Token::SHR) __ bind(&non_smi_result);
04276 __ mov(eax, Operand(esp, 1 * kPointerSize));
04277 __ mov(edx, Operand(esp, 2 * kPointerSize));
04278 break;
04279 }
04280 default: UNREACHABLE(); break;
04281 }
04282
04283
04284
04285 __ bind(&call_runtime);
04286 switch (op_) {
04287 case Token::ADD:
04288 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
04289 break;
04290 case Token::SUB:
04291 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
04292 break;
04293 case Token::MUL:
04294 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
04295 break;
04296 case Token::DIV:
04297 __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
04298 break;
04299 case Token::MOD:
04300 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
04301 break;
04302 case Token::BIT_OR:
04303 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
04304 break;
04305 case Token::BIT_AND:
04306 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
04307 break;
04308 case Token::BIT_XOR:
04309 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
04310 break;
04311 case Token::SAR:
04312 __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
04313 break;
04314 case Token::SHL:
04315 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
04316 break;
04317 case Token::SHR:
04318 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
04319 break;
04320 default:
04321 UNREACHABLE();
04322 }
04323 }
04324
04325
04326 void FloatingPointHelper::AllocateHeapNumber(MacroAssembler* masm,
04327 Label* need_gc,
04328 Register scratch1,
04329 Register scratch2) {
04330 ExternalReference allocation_top =
04331 ExternalReference::new_space_allocation_top_address();
04332 ExternalReference allocation_limit =
04333 ExternalReference::new_space_allocation_limit_address();
04334 __ mov(Operand(scratch1), Immediate(allocation_top));
04335 __ mov(eax, Operand(scratch1, 0));
04336 __ lea(scratch2, Operand(eax, HeapNumber::kSize));
04337 __ cmp(scratch2, Operand::StaticVariable(allocation_limit));
04338 __ j(above, need_gc, not_taken);
04339
04340 __ mov(Operand(scratch1, 0), scratch2);
04341 __ mov(Operand(eax, HeapObject::kMapOffset),
04342 Immediate(Factory::heap_number_map()));
04343
04344 __ add(Operand(eax), Immediate(kHeapObjectTag));
04345 }
04346
04347
04348 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
04349 Register scratch) {
04350 Label load_smi_1, load_smi_2, done_load_1, done;
04351 __ mov(scratch, Operand(esp, 2 * kPointerSize));
04352 __ test(scratch, Immediate(kSmiTagMask));
04353 __ j(zero, &load_smi_1, not_taken);
04354 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
04355 __ bind(&done_load_1);
04356
04357 __ mov(scratch, Operand(esp, 1 * kPointerSize));
04358 __ test(scratch, Immediate(kSmiTagMask));
04359 __ j(zero, &load_smi_2, not_taken);
04360 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
04361 __ jmp(&done);
04362
04363 __ bind(&load_smi_1);
04364 __ sar(scratch, kSmiTagSize);
04365 __ push(scratch);
04366 __ fild_s(Operand(esp, 0));
04367 __ pop(scratch);
04368 __ jmp(&done_load_1);
04369
04370 __ bind(&load_smi_2);
04371 __ sar(scratch, kSmiTagSize);
04372 __ push(scratch);
04373 __ fild_s(Operand(esp, 0));
04374 __ pop(scratch);
04375
04376 __ bind(&done);
04377 }
04378
04379
04380 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm,
04381 Label* non_float,
04382 Register scratch) {
04383 Label test_other, done;
04384
04385
04386 __ test(edx, Immediate(kSmiTagMask));
04387 __ j(zero, &test_other, not_taken);
04388 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset));
04389 __ cmp(scratch, Factory::heap_number_map());
04390 __ j(not_equal, non_float);
04391
04392 __ bind(&test_other);
04393 __ test(eax, Immediate(kSmiTagMask));
04394 __ j(zero, &done);
04395 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset));
04396 __ cmp(scratch, Factory::heap_number_map());
04397 __ j(not_equal, non_float);
04398
04399
04400 __ bind(&done);
04401 }
04402
04403
04404 void UnarySubStub::Generate(MacroAssembler* masm) {
04405 Label undo;
04406 Label slow;
04407 Label done;
04408 Label try_float;
04409
04410
04411 __ test(eax, Immediate(kSmiTagMask));
04412 __ j(not_zero, &try_float, not_taken);
04413
04414
04415
04416 __ test(eax, Operand(eax));
04417 __ j(zero, &slow, not_taken);
04418
04419
04420
04421 __ mov(edx, Operand(eax));
04422 __ Set(eax, Immediate(0));
04423 __ sub(eax, Operand(edx));
04424 __ j(overflow, &undo, not_taken);
04425
04426
04427 __ test(eax, Immediate(kSmiTagMask));
04428 __ j(zero, &done, taken);
04429
04430
04431 __ bind(&undo);
04432 __ mov(eax, Operand(edx));
04433
04434
04435 __ bind(&slow);
04436 __ pop(ecx);
04437 __ push(eax);
04438 __ push(ecx);
04439 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
04440
04441
04442 __ bind(&try_float);
04443 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
04444 __ cmp(edx, Factory::heap_number_map());
04445 __ j(not_equal, &slow);
04446 __ mov(edx, Operand(eax));
04447
04448 FloatingPointHelper::AllocateHeapNumber(masm, &undo, ebx, ecx);
04449
04450 __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
04451 __ fchs();
04452 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
04453
04454 __ bind(&done);
04455
04456 __ StubReturn(1);
04457 }
04458
04459
04460 void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
04461
04462 Label adaptor;
04463 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
04464 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
04465 __ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL);
04466 __ j(equal, &adaptor);
04467
04468
04469
04470 __ ret(0);
04471
04472
04473
04474 __ bind(&adaptor);
04475 __ mov(eax, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
04476 __ ret(0);
04477 }
04478
04479
04480 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
04481
04482
04483
04484 static const int kDisplacement = 1 * kPointerSize;
04485
04486
04487 Label slow;
04488 __ mov(ebx, Operand(esp, 1 * kPointerSize));
04489 __ test(ebx, Immediate(kSmiTagMask));
04490 __ j(not_zero, &slow, not_taken);
04491
04492
04493 Label adaptor;
04494 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
04495 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
04496 __ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL);
04497 __ j(equal, &adaptor);
04498
04499
04500
04501
04502 __ cmp(ebx, Operand(eax));
04503 __ j(above_equal, &slow, not_taken);
04504
04505
04506 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
04507 __ lea(edx, Operand(ebp, eax, times_2, 0));
04508 __ neg(ebx);
04509 __ mov(eax, Operand(edx, ebx, times_2, kDisplacement));
04510 __ ret(0);
04511
04512
04513
04514
04515 __ bind(&adaptor);
04516 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
04517 __ cmp(ebx, Operand(ecx));
04518 __ j(above_equal, &slow, not_taken);
04519
04520
04521 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
04522 __ lea(edx, Operand(edx, ecx, times_2, 0));
04523 __ neg(ebx);
04524 __ mov(eax, Operand(edx, ebx, times_2, kDisplacement));
04525 __ ret(0);
04526
04527
04528
04529 __ bind(&slow);
04530 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
04531 }
04532
04533
04534 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
04535
04536
04537
04538 static const int kDisplacement = 2 * kPointerSize;
04539
04540
04541 Label runtime;
04542 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
04543 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
04544 __ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL);
04545 __ j(not_equal, &runtime);
04546
04547
04548 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
04549 __ mov(Operand(esp, 1 * kPointerSize), ecx);
04550 __ lea(edx, Operand(edx, ecx, times_2, kDisplacement));
04551 __ mov(Operand(esp, 2 * kPointerSize), edx);
04552
04553
04554 __ bind(&runtime);
04555 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3);
04556 }
04557
04558
04559 void CompareStub::Generate(MacroAssembler* masm) {
04560 Label call_builtin, done;
04561
04562
04563
04564
04565 if (strict_) {
04566 Label slow;
04567 __ test(eax, Immediate(kSmiTagMask));
04568 __ j(zero, &slow);
04569
04570
04571 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
04572 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
04573
04574
04575 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
04576 Label non_object;
04577 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
04578 __ j(less, &non_object);
04579 __ sub(eax, Operand(edx));
04580 __ ret(0);
04581
04582
04583 __ bind(&non_object);
04584 __ cmp(ecx, ODDBALL_TYPE);
04585 __ j(not_equal, &slow);
04586
04587
04588
04589
04590 Label undefined;
04591 __ cmp(Operand(eax), Immediate(Factory::undefined_value()));
04592 __ j(equal, &undefined);
04593 __ sub(eax, Operand(edx));
04594 __ ret(0);
04595
04596
04597
04598 Label check_undetectable;
04599 __ bind(&undefined);
04600 __ cmp(Operand(edx), Immediate(Factory::undefined_value()));
04601 __ j(not_equal, &check_undetectable);
04602 __ Set(eax, Immediate(0));
04603 __ ret(0);
04604
04605
04606 Label not_strictly_equal;
04607 __ bind(&check_undetectable);
04608 __ test(edx, Immediate(kSmiTagMask));
04609 __ j(zero, ¬_strictly_equal);
04610 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
04611 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
04612 __ and_(ecx, 1 << Map::kIsUndetectable);
04613 __ cmp(ecx, 1 << Map::kIsUndetectable);
04614 __ j(not_equal, ¬_strictly_equal);
04615 __ Set(eax, Immediate(0));
04616 __ ret(0);
04617
04618
04619
04620 ASSERT(kHeapObjectTag != 0);
04621 __ bind(¬_strictly_equal);
04622 __ ret(0);
04623
04624
04625 __ bind(&slow);
04626 }
04627
04628
04629 __ pop(ecx);
04630
04631
04632 __ push(eax);
04633 __ push(edx);
04634 __ push(ecx);
04635
04636
04637
04638 FloatingPointHelper::CheckFloatOperands(masm, &call_builtin, ebx);
04639 FloatingPointHelper::LoadFloatOperands(masm, ecx);
04640 __ FCmp();
04641
04642
04643 __ j(parity_even, &call_builtin, not_taken);
04644
04645
04646 Label below_lbl, above_lbl;
04647
04648 __ j(below, &below_lbl, not_taken);
04649 __ j(above, &above_lbl, not_taken);
04650
04651 __ xor_(eax, Operand(eax));
04652 __ ret(2 * kPointerSize);
04653
04654 __ bind(&below_lbl);
04655 __ mov(eax, -1);
04656 __ ret(2 * kPointerSize);
04657
04658 __ bind(&above_lbl);
04659 __ mov(eax, 1);
04660 __ ret(2 * kPointerSize);
04661
04662 __ bind(&call_builtin);
04663
04664 __ pop(ecx);
04665 __ pop(edx);
04666 __ pop(eax);
04667 __ push(edx);
04668 __ push(eax);
04669
04670
04671 Builtins::JavaScript builtin;
04672 if (cc_ == equal) {
04673 builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
04674 } else {
04675 builtin = Builtins::COMPARE;
04676 int ncr;
04677 if (cc_ == less || cc_ == less_equal) {
04678 ncr = GREATER;
04679 } else {
04680 ASSERT(cc_ == greater || cc_ == greater_equal);
04681 ncr = LESS;
04682 }
04683 __ push(Immediate(Smi::FromInt(ncr)));
04684 }
04685
04686
04687 __ push(ecx);
04688
04689
04690
04691 __ InvokeBuiltin(builtin, JUMP_FUNCTION);
04692 }
04693
04694
04695 void StackCheckStub::Generate(MacroAssembler* masm) {
04696
04697
04698
04699
04700 __ pop(eax);
04701 __ push(Immediate(Smi::FromInt(0)));
04702 __ push(eax);
04703
04704
04705 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
04706 }
04707
04708
04709 void CallFunctionStub::Generate(MacroAssembler* masm) {
04710 Label slow;
04711
04712
04713
04714 __ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize));
04715
04716
04717 __ test(edi, Immediate(kSmiTagMask));
04718 __ j(zero, &slow, not_taken);
04719
04720 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
04721 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
04722 __ cmp(ecx, JS_FUNCTION_TYPE);
04723 __ j(not_equal, &slow, not_taken);
04724
04725
04726 ParameterCount actual(argc_);
04727 __ InvokeFunction(edi, actual, JUMP_FUNCTION);
04728
04729
04730 __ bind(&slow);
04731 __ Set(eax, Immediate(argc_));
04732 __ Set(ebx, Immediate(0));
04733 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
04734 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
04735 __ jmp(adaptor, RelocInfo::CODE_TARGET);
04736 }
04737
04738
04739 void RevertToNumberStub::Generate(MacroAssembler* masm) {
04740
04741 if (is_increment_) {
04742 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
04743 } else {
04744 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
04745 }
04746
04747 __ pop(ecx);
04748 __ push(eax);
04749 __ push(ecx);
04750 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
04751
04752 }
04753
04754
04755 void CounterOpStub::Generate(MacroAssembler* masm) {
04756
04757
04758 if (is_postfix_) {
04759 __ mov(Operand(esp, result_offset_ + kPointerSize), eax);
04760 }
04761
04762
04763
04764
04765 if (!is_postfix_) {
04766 if (is_increment_) {
04767 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
04768 } else {
04769 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
04770 }
04771 }
04772
04773
04774 __ pop(ecx);
04775 __ push(eax);
04776 __ push(ecx);
04777 Builtins::JavaScript builtin = is_increment_ ? Builtins::INC : Builtins::DEC;
04778 __ InvokeBuiltin(builtin, JUMP_FUNCTION);
04779
04780 }
04781
04782
04783 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
04784 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize);
04785 ExternalReference handler_address(Top::k_handler_address);
04786 __ mov(edx, Operand::StaticVariable(handler_address));
04787 __ mov(ecx, Operand(edx, -1 * kPointerSize));
04788 __ mov(Operand::StaticVariable(handler_address), ecx);
04789 __ mov(esp, Operand(edx));
04790 __ pop(edi);
04791 __ pop(ebp);
04792 __ pop(edx);
04793 __ pop(edx);
04794
04795
04796
04797 __ xor_(esi, Operand(esi));
04798 Label skip;
04799 __ cmp(ebp, 0);
04800 __ j(equal, &skip, not_taken);
04801 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
04802 __ bind(&skip);
04803
04804 __ ret(0);
04805 }
04806
04807
04808 void CEntryStub::GenerateCore(MacroAssembler* masm,
04809 Label* throw_normal_exception,
04810 Label* throw_out_of_memory_exception,
04811 StackFrame::Type frame_type,
04812 bool do_gc,
04813 bool always_allocate_scope) {
04814
04815
04816
04817
04818
04819
04820
04821 if (do_gc) {
04822 __ mov(Operand(esp, 0 * kPointerSize), eax);
04823 __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY);
04824 }
04825
04826 ExternalReference scope_depth =
04827 ExternalReference::heap_always_allocate_scope_depth();
04828 if (always_allocate_scope) {
04829 __ inc(Operand::StaticVariable(scope_depth));
04830 }
04831
04832
04833 __ mov(Operand(esp, 0 * kPointerSize), edi);
04834 __ mov(Operand(esp, 1 * kPointerSize), esi);
04835 __ call(Operand(ebx));
04836
04837
04838 if (always_allocate_scope) {
04839 __ dec(Operand::StaticVariable(scope_depth));
04840 }
04841
04842
04843 Label failure_returned;
04844 ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
04845 __ lea(ecx, Operand(eax, 1));
04846
04847 __ test(ecx, Immediate(kFailureTagMask));
04848 __ j(zero, &failure_returned, not_taken);
04849
04850
04851 __ LeaveExitFrame(frame_type);
04852 __ ret(0);
04853
04854
04855 __ bind(&failure_returned);
04856
04857 Label retry;
04858
04859 ASSERT(Failure::RETRY_AFTER_GC == 0);
04860 __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
04861 __ j(zero, &retry, taken);
04862
04863 Label continue_exception;
04864
04865 __ cmp(eax, reinterpret_cast<int32_t>(Failure::Exception()));
04866 __ j(not_equal, &continue_exception);
04867
04868
04869 ExternalReference pending_exception_address(Top::k_pending_exception_address);
04870 __ mov(eax, Operand::StaticVariable(pending_exception_address));
04871 __ mov(edx,
04872 Operand::StaticVariable(ExternalReference::the_hole_value_location()));
04873 __ mov(Operand::StaticVariable(pending_exception_address), edx);
04874
04875 __ bind(&continue_exception);
04876
04877 __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
04878 __ j(equal, throw_out_of_memory_exception);
04879
04880
04881 __ jmp(throw_normal_exception);
04882
04883
04884 __ bind(&retry);
04885 }
04886
04887
04888 void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
04889
04890 ExternalReference handler_address(Top::k_handler_address);
04891 __ mov(edx, Operand::StaticVariable(handler_address));
04892
04893
04894 Label loop, done;
04895 __ bind(&loop);
04896
04897 const int kStateOffset = StackHandlerConstants::kAddressDisplacement +
04898 StackHandlerConstants::kStateOffset;
04899 __ cmp(Operand(edx, kStateOffset), Immediate(StackHandler::ENTRY));
04900 __ j(equal, &done);
04901
04902 const int kNextOffset = StackHandlerConstants::kAddressDisplacement +
04903 StackHandlerConstants::kNextOffset;
04904 __ mov(edx, Operand(edx, kNextOffset));
04905 __ jmp(&loop);
04906 __ bind(&done);
04907
04908
04909 __ mov(eax, Operand(edx, kNextOffset));
04910 __ mov(Operand::StaticVariable(handler_address), eax);
04911
04912
04913 __ mov(eax, false);
04914 ExternalReference external_caught(Top::k_external_caught_exception_address);
04915 __ mov(Operand::StaticVariable(external_caught), eax);
04916
04917
04918 __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
04919 ExternalReference pending_exception(Top::k_pending_exception_address);
04920 __ mov(Operand::StaticVariable(pending_exception), eax);
04921
04922
04923 __ mov(esp, Operand(edx));
04924
04925
04926 __ xor_(esi, Operand(esi));
04927
04928
04929 __ pop(edi);
04930 __ pop(ebp);
04931 __ pop(edx);
04932 __ pop(edx);
04933
04934 __ ret(0);
04935 }
04936
04937
04938 void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
04939
04940
04941
04942
04943
04944
04945
04946
04947
04948
04949
04950
04951 StackFrame::Type frame_type = is_debug_break ?
04952 StackFrame::EXIT_DEBUG :
04953 StackFrame::EXIT;
04954
04955
04956 __ EnterExitFrame(frame_type);
04957
04958
04959
04960
04961
04962
04963
04964
04965 Label throw_out_of_memory_exception;
04966 Label throw_normal_exception;
04967
04968
04969
04970 if (FLAG_gc_greedy) {
04971 Failure* failure = Failure::RetryAfterGC(0);
04972 __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure)));
04973 }
04974 GenerateCore(masm, &throw_normal_exception,
04975 &throw_out_of_memory_exception,
04976 frame_type,
04977 FLAG_gc_greedy,
04978 false);
04979
04980
04981 GenerateCore(masm,
04982 &throw_normal_exception,
04983 &throw_out_of_memory_exception,
04984 frame_type,
04985 true,
04986 false);
04987
04988
04989 Failure* failure = Failure::InternalError();
04990 __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure)));
04991 GenerateCore(masm,
04992 &throw_normal_exception,
04993 &throw_out_of_memory_exception,
04994 frame_type,
04995 true,
04996 true);
04997
04998 __ bind(&throw_out_of_memory_exception);
04999 GenerateThrowOutOfMemory(masm);
05000
05001
05002 __ bind(&throw_normal_exception);
05003 GenerateThrowTOS(masm);
05004 }
05005
05006
05007 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
05008 Label invoke, exit;
05009
05010
05011 __ push(ebp);
05012 __ mov(ebp, Operand(esp));
05013
05014
05015 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
05016
05017 __ push(Immediate(~ArgumentsAdaptorFrame::SENTINEL));
05018 __ push(Immediate(Smi::FromInt(marker)));
05019 __ push(edi);
05020 __ push(esi);
05021 __ push(ebx);
05022
05023
05024 ExternalReference c_entry_fp(Top::k_c_entry_fp_address);
05025 __ push(Operand::StaticVariable(c_entry_fp));
05026
05027
05028 __ call(&invoke);
05029
05030
05031
05032 ExternalReference pending_exception(Top::k_pending_exception_address);
05033 __ mov(Operand::StaticVariable(pending_exception), eax);
05034 __ mov(eax, Handle<Failure>(Failure::Exception()));
05035 __ jmp(&exit);
05036
05037
05038 __ bind(&invoke);
05039 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
05040 __ push(eax);
05041
05042
05043 __ mov(edx,
05044 Operand::StaticVariable(ExternalReference::the_hole_value_location()));
05045 __ mov(Operand::StaticVariable(pending_exception), edx);
05046
05047
05048 __ push(Immediate(0));
05049
05050
05051
05052
05053
05054 if (is_construct) {
05055 ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
05056 __ mov(Operand(edx), Immediate(construct_entry));
05057 } else {
05058 ExternalReference entry(Builtins::JSEntryTrampoline);
05059 __ mov(Operand(edx), Immediate(entry));
05060 }
05061 __ mov(edx, Operand(edx, 0));
05062 __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
05063 __ call(Operand(edx));
05064
05065
05066 __ pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
05067
05068 __ add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
05069
05070
05071 __ bind(&exit);
05072 __ pop(Operand::StaticVariable(ExternalReference(Top::k_c_entry_fp_address)));
05073
05074
05075 __ pop(ebx);
05076 __ pop(esi);
05077 __ pop(edi);
05078 __ add(Operand(esp), Immediate(2 * kPointerSize));
05079
05080
05081 __ pop(ebp);
05082 __ ret(0);
05083 }
05084
05085
05086 void InstanceofStub::Generate(MacroAssembler* masm) {
05087
05088 Label slow;
05089 __ mov(eax, Operand(esp, 2 * kPointerSize));
05090 __ test(eax, Immediate(kSmiTagMask));
05091 __ j(zero, &slow, not_taken);
05092
05093
05094 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
05095 __ movzx_b(ecx, FieldOperand(eax, Map::kInstanceTypeOffset));
05096 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
05097 __ j(less, &slow, not_taken);
05098 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
05099 __ j(greater, &slow, not_taken);
05100
05101
05102 __ mov(edx, Operand(esp, 1 * kPointerSize));
05103 __ TryGetFunctionPrototype(edx, ebx, ecx, &slow);
05104
05105
05106 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
05107 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
05108 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
05109 __ j(less, &slow, not_taken);
05110 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
05111 __ j(greater, &slow, not_taken);
05112
05113
05114 __ mov(ecx, FieldOperand(eax, Map::kPrototypeOffset));
05115
05116
05117 Label loop, is_instance, is_not_instance;
05118 __ bind(&loop);
05119 __ cmp(ecx, Operand(ebx));
05120 __ j(equal, &is_instance);
05121 __ cmp(Operand(ecx), Immediate(Factory::null_value()));
05122 __ j(equal, &is_not_instance);
05123 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
05124 __ mov(ecx, FieldOperand(ecx, Map::kPrototypeOffset));
05125 __ jmp(&loop);
05126
05127 __ bind(&is_instance);
05128 __ Set(eax, Immediate(0));
05129 __ ret(2 * kPointerSize);
05130
05131 __ bind(&is_not_instance);
05132 __ Set(eax, Immediate(Smi::FromInt(1)));
05133 __ ret(2 * kPointerSize);
05134
05135
05136 __ bind(&slow);
05137 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
05138 }
05139
05140
05141 #undef __
05142
05143 } }