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
00039
00040
00041 CodeGenState::CodeGenState(CodeGenerator* owner)
00042 : owner_(owner),
00043 typeof_state_(NOT_INSIDE_TYPEOF),
00044 true_target_(NULL),
00045 false_target_(NULL),
00046 previous_(NULL) {
00047 owner_->set_state(this);
00048 }
00049
00050
00051 CodeGenState::CodeGenState(CodeGenerator* owner,
00052 TypeofState typeof_state,
00053 Label* true_target,
00054 Label* false_target)
00055 : owner_(owner),
00056 typeof_state_(typeof_state),
00057 true_target_(true_target),
00058 false_target_(false_target),
00059 previous_(owner->state()) {
00060 owner_->set_state(this);
00061 }
00062
00063
00064 CodeGenState::~CodeGenState() {
00065 ASSERT(owner_->state() == this);
00066 owner_->set_state(previous_);
00067 }
00068
00069
00070
00071
00072
00073 #define __ masm_->
00074
00075 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
00076 bool is_eval)
00077 : is_eval_(is_eval),
00078 script_(script),
00079 deferred_(8),
00080 masm_(new MacroAssembler(NULL, buffer_size)),
00081 scope_(NULL),
00082 cc_reg_(al),
00083 state_(NULL),
00084 break_stack_height_(0) {
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 void CodeGenerator::GenCode(FunctionLiteral* fun) {
00097 Scope* scope = fun->scope();
00098 ZoneList<Statement*>* body = fun->body();
00099
00100
00101 { CodeGenState state(this);
00102 scope_ = scope;
00103 cc_reg_ = al;
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 { Comment cmnt(masm_, "[ enter JS frame");
00114 EnterJSFrame();
00115 }
00116
00117 #ifdef DEBUG
00118 if (strlen(FLAG_stop_at) > 0 &&
00119 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
00120 __ stop("stop-at");
00121 }
00122 #endif
00123
00124
00125 if (scope->num_stack_slots() > 0) {
00126 Comment cmnt(masm_, "[ allocate space for locals");
00127
00128 __ mov(ip, Operand(Factory::undefined_value()));
00129 for (int i = 0; i < scope->num_stack_slots(); i++) {
00130 __ push(ip);
00131 }
00132 }
00133
00134 if (scope->num_heap_slots() > 0) {
00135
00136
00137 __ ldr(r0, FunctionOperand());
00138 __ push(r0);
00139 __ CallRuntime(Runtime::kNewContext, 1);
00140
00141 if (kDebug) {
00142 Label verified_true;
00143 __ cmp(r0, Operand(cp));
00144 __ b(eq, &verified_true);
00145 __ stop("NewContext: r0 is expected to be the same as cp");
00146 __ bind(&verified_true);
00147 }
00148
00149 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
00150 }
00151
00152
00153
00154
00155
00156 {
00157 Comment cmnt2(masm_, "[ copy context parameters into .context");
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 for (int i = 0; i < scope->num_parameters(); i++) {
00168 Variable* par = scope->parameter(i);
00169 Slot* slot = par->slot();
00170 if (slot != NULL && slot->type() == Slot::CONTEXT) {
00171 ASSERT(!scope->is_global_scope());
00172 __ ldr(r1, ParameterOperand(i));
00173
00174 __ str(r1, SlotOperand(slot, r2));
00175
00176 int slot_offset =
00177 FixedArray::kHeaderSize + slot->index() * kPointerSize;
00178 __ mov(r3, Operand(slot_offset));
00179 __ RecordWrite(r2, r3, r1);
00180 }
00181 }
00182 }
00183
00184
00185
00186
00187 if (scope->arguments() != NULL) {
00188 ASSERT(scope->arguments_shadow() != NULL);
00189 Comment cmnt(masm_, "[ allocate arguments object");
00190 { Reference shadow_ref(this, scope->arguments_shadow());
00191 { Reference arguments_ref(this, scope->arguments());
00192 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
00193 __ ldr(r2, FunctionOperand());
00194
00195
00196 const int kReceiverDisplacement = 2 + scope->num_parameters();
00197 __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize));
00198 __ mov(r0, Operand(Smi::FromInt(scope->num_parameters())));
00199 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
00200 __ CallStub(&stub);
00201 __ push(r0);
00202 arguments_ref.SetValue(NOT_CONST_INIT);
00203 }
00204 shadow_ref.SetValue(NOT_CONST_INIT);
00205 }
00206 __ pop(r0);
00207 }
00208
00209
00210
00211
00212
00213 if (scope->HasIllegalRedeclaration()) {
00214 Comment cmnt(masm_, "[ illegal redeclarations");
00215 scope->VisitIllegalRedeclaration(this);
00216 } else {
00217 Comment cmnt(masm_, "[ declarations");
00218
00219 ProcessDeclarations(scope->declarations());
00220
00221
00222
00223 if (HasStackOverflow()) return;
00224 }
00225
00226 if (FLAG_trace) {
00227
00228
00229 __ CallRuntime(Runtime::kTraceEnter, 0);
00230 }
00231 CheckStack();
00232
00233
00234
00235
00236 if (!scope->HasIllegalRedeclaration()) {
00237 Comment cmnt(masm_, "[ function body");
00238 #ifdef DEBUG
00239 bool is_builtin = Bootstrapper::IsActive();
00240 bool should_trace =
00241 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
00242 if (should_trace) {
00243 __ CallRuntime(Runtime::kDebugTrace, 0);
00244 }
00245 #endif
00246 VisitStatements(body);
00247 }
00248 }
00249
00250
00251
00252
00253
00254
00255
00256 __ mov(r0, Operand(Factory::undefined_value()));
00257
00258 __ bind(&function_return_);
00259 if (FLAG_trace) {
00260
00261
00262 __ push(r0);
00263 __ CallRuntime(Runtime::kTraceExit, 1);
00264 }
00265
00266
00267
00268 ExitJSFrame();
00269
00270 __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize));
00271 __ mov(pc, lr);
00272
00273
00274 scope_ = NULL;
00275 ASSERT(!has_cc());
00276 ASSERT(state_ == NULL);
00277 }
00278
00279
00280 MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
00281
00282
00283
00284
00285
00286
00287
00288
00289 ASSERT(slot != NULL);
00290 int index = slot->index();
00291 switch (slot->type()) {
00292 case Slot::PARAMETER:
00293 return ParameterOperand(index);
00294
00295 case Slot::LOCAL: {
00296 ASSERT(0 <= index && index < scope()->num_stack_slots());
00297 const int kLocalOffset = JavaScriptFrameConstants::kLocal0Offset;
00298 return MemOperand(fp, kLocalOffset - index * kPointerSize);
00299 }
00300
00301 case Slot::CONTEXT: {
00302
00303 ASSERT(!tmp.is(cp));
00304 Register context = cp;
00305 int chain_length = scope()->ContextChainLength(slot->var()->scope());
00306 for (int i = chain_length; i-- > 0;) {
00307
00308
00309
00310
00311 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
00312
00313 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
00314 context = tmp;
00315 }
00316
00317
00318
00319
00320
00321
00322
00323 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
00324 return ContextOperand(tmp, index);
00325 }
00326
00327 default:
00328 UNREACHABLE();
00329 return MemOperand(r0, 0);
00330 }
00331 }
00332
00333
00334
00335
00336
00337
00338
00339 void CodeGenerator::LoadCondition(Expression* x,
00340 TypeofState typeof_state,
00341 Label* true_target,
00342 Label* false_target,
00343 bool force_cc) {
00344 ASSERT(!has_cc());
00345
00346 { CodeGenState new_state(this, typeof_state, true_target, false_target);
00347 Visit(x);
00348 }
00349 if (force_cc && !has_cc()) {
00350
00351 ToBoolean(true_target, false_target);
00352 }
00353 ASSERT(has_cc() || !force_cc);
00354 }
00355
00356
00357 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
00358 Label true_target;
00359 Label false_target;
00360 LoadCondition(x, typeof_state, &true_target, &false_target, false);
00361
00362 if (has_cc()) {
00363
00364 Label loaded, materialize_true;
00365 __ b(cc_reg_, &materialize_true);
00366 __ mov(r0, Operand(Factory::false_value()));
00367 __ push(r0);
00368 __ b(&loaded);
00369 __ bind(&materialize_true);
00370 __ mov(r0, Operand(Factory::true_value()));
00371 __ push(r0);
00372 __ bind(&loaded);
00373 cc_reg_ = al;
00374 }
00375
00376 if (true_target.is_linked() || false_target.is_linked()) {
00377
00378
00379
00380 Label loaded;
00381 __ b(&loaded);
00382 bool both = true_target.is_linked() && false_target.is_linked();
00383
00384 if (true_target.is_linked()) {
00385 __ bind(&true_target);
00386 __ mov(r0, Operand(Factory::true_value()));
00387 __ push(r0);
00388 }
00389
00390
00391 if (both)
00392 __ b(&loaded);
00393
00394 if (false_target.is_linked()) {
00395 __ bind(&false_target);
00396 __ mov(r0, Operand(Factory::false_value()));
00397 __ push(r0);
00398 }
00399
00400 __ bind(&loaded);
00401 }
00402 ASSERT(!has_cc());
00403 }
00404
00405
00406 void CodeGenerator::LoadGlobal() {
00407 __ ldr(r0, GlobalObject());
00408 __ push(r0);
00409 }
00410
00411
00412 void CodeGenerator::LoadGlobalReceiver(Register s) {
00413 __ ldr(s, ContextOperand(cp, Context::GLOBAL_INDEX));
00414 __ ldr(s, FieldMemOperand(s, GlobalObject::kGlobalReceiverOffset));
00415 __ push(s);
00416 }
00417
00418
00419
00420
00421
00422 void CodeGenerator::LoadTypeofExpression(Expression* x) {
00423 Variable* variable = x->AsVariableProxy()->AsVariable();
00424 if (variable != NULL && !variable->is_this() && variable->is_global()) {
00425
00426
00427
00428 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX);
00429 Literal key(variable->name());
00430
00431
00432 Property property(&global, &key, RelocInfo::kNoPosition);
00433 Load(&property);
00434 } else {
00435 Load(x, INSIDE_TYPEOF);
00436 }
00437 }
00438
00439
00440 Reference::Reference(CodeGenerator* cgen, Expression* expression)
00441 : cgen_(cgen), expression_(expression), type_(ILLEGAL) {
00442 cgen->LoadReference(this);
00443 }
00444
00445
00446 Reference::~Reference() {
00447 cgen_->UnloadReference(this);
00448 }
00449
00450
00451 void CodeGenerator::LoadReference(Reference* ref) {
00452 Comment cmnt(masm_, "[ LoadReference");
00453
00454 Expression* e = ref->expression();
00455 Property* property = e->AsProperty();
00456 Variable* var = e->AsVariableProxy()->AsVariable();
00457
00458 if (property != NULL) {
00459
00460
00461 Load(property->obj());
00462
00463
00464
00465
00466 Literal* literal = property->key()->AsLiteral();
00467 uint32_t dummy;
00468 if (literal != NULL &&
00469 literal->handle()->IsSymbol() &&
00470 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
00471 ref->set_type(Reference::NAMED);
00472 } else {
00473 Load(property->key());
00474 ref->set_type(Reference::KEYED);
00475 }
00476 } else if (var != NULL) {
00477
00478
00479 if (var->is_global()) {
00480 LoadGlobal();
00481 ref->set_type(Reference::NAMED);
00482 } else {
00483 ASSERT(var->slot() != NULL);
00484 ref->set_type(Reference::SLOT);
00485 }
00486 } else {
00487
00488 Load(e);
00489 __ CallRuntime(Runtime::kThrowReferenceError, 1);
00490 }
00491 }
00492
00493
00494 void CodeGenerator::UnloadReference(Reference* ref) {
00495 Comment cmnt(masm_, "[ UnloadReference");
00496
00497 int size = ref->size();
00498 if (size <= 0) {
00499
00500 } else {
00501 __ pop(r0);
00502 __ add(sp, sp, Operand(size * kPointerSize));
00503 __ push(r0);
00504 }
00505 }
00506
00507
00508
00509
00510
00511 void CodeGenerator::ToBoolean(Label* true_target,
00512 Label* false_target) {
00513
00514
00515 __ pop(r0);
00516
00517
00518
00519
00520 __ cmp(r0, Operand(Factory::false_value()));
00521 __ b(eq, false_target);
00522
00523
00524 __ cmp(r0, Operand(Factory::true_value()));
00525 __ b(eq, true_target);
00526
00527
00528 __ cmp(r0, Operand(Factory::undefined_value()));
00529 __ b(eq, false_target);
00530
00531
00532 __ cmp(r0, Operand(Smi::FromInt(0)));
00533 __ b(eq, false_target);
00534 __ tst(r0, Operand(kSmiTagMask));
00535 __ b(eq, true_target);
00536
00537
00538 __ push(r0);
00539 __ CallRuntime(Runtime::kToBool, 1);
00540
00541
00542 __ cmp(r0, Operand(Factory::false_value()));
00543
00544 cc_reg_ = ne;
00545 }
00546
00547
00548 class GetPropertyStub : public CodeStub {
00549 public:
00550 GetPropertyStub() { }
00551
00552 private:
00553 Major MajorKey() { return GetProperty; }
00554 int MinorKey() { return 0; }
00555 void Generate(MacroAssembler* masm);
00556 };
00557
00558
00559 class SetPropertyStub : public CodeStub {
00560 public:
00561 SetPropertyStub() { }
00562
00563 private:
00564 Major MajorKey() { return SetProperty; }
00565 int MinorKey() { return 0; }
00566 void Generate(MacroAssembler* masm);
00567 };
00568
00569
00570 class GenericBinaryOpStub : public CodeStub {
00571 public:
00572 explicit GenericBinaryOpStub(Token::Value op) : op_(op) { }
00573
00574 private:
00575 Token::Value op_;
00576
00577 Major MajorKey() { return GenericBinaryOp; }
00578 int MinorKey() { return static_cast<int>(op_); }
00579 void Generate(MacroAssembler* masm);
00580
00581 const char* GetName() {
00582 switch (op_) {
00583 case Token::ADD: return "GenericBinaryOpStub_ADD";
00584 case Token::SUB: return "GenericBinaryOpStub_SUB";
00585 case Token::MUL: return "GenericBinaryOpStub_MUL";
00586 case Token::DIV: return "GenericBinaryOpStub_DIV";
00587 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
00588 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
00589 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
00590 case Token::SAR: return "GenericBinaryOpStub_SAR";
00591 case Token::SHL: return "GenericBinaryOpStub_SHL";
00592 case Token::SHR: return "GenericBinaryOpStub_SHR";
00593 default: return "GenericBinaryOpStub";
00594 }
00595 }
00596
00597 #ifdef DEBUG
00598 void Print() { PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); }
00599 #endif
00600 };
00601
00602
00603 class InvokeBuiltinStub : public CodeStub {
00604 public:
00605 enum Kind { Inc, Dec, ToNumber };
00606 InvokeBuiltinStub(Kind kind, int argc) : kind_(kind), argc_(argc) { }
00607
00608 private:
00609 Kind kind_;
00610 int argc_;
00611
00612 Major MajorKey() { return InvokeBuiltin; }
00613 int MinorKey() { return (argc_ << 3) | static_cast<int>(kind_); }
00614 void Generate(MacroAssembler* masm);
00615
00616 #ifdef DEBUG
00617 void Print() {
00618 PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n",
00619 static_cast<int>(kind_),
00620 argc_);
00621 }
00622 #endif
00623 };
00624
00625
00626 void CodeGenerator::GenericBinaryOperation(Token::Value op) {
00627
00628
00629
00630
00631
00632 switch (op) {
00633 case Token::ADD:
00634 case Token::SUB:
00635 case Token::MUL:
00636 case Token::BIT_OR:
00637 case Token::BIT_AND:
00638 case Token::BIT_XOR:
00639 case Token::SHL:
00640 case Token::SHR:
00641 case Token::SAR: {
00642 __ pop(r0);
00643 __ pop(r1);
00644 GenericBinaryOpStub stub(op);
00645 __ CallStub(&stub);
00646 break;
00647 }
00648
00649 case Token::DIV: {
00650 __ mov(r0, Operand(1));
00651 __ InvokeBuiltin(Builtins::DIV, CALL_JS);
00652 break;
00653 }
00654
00655 case Token::MOD: {
00656 __ mov(r0, Operand(1));
00657 __ InvokeBuiltin(Builtins::MOD, CALL_JS);
00658 break;
00659 }
00660
00661 case Token::COMMA:
00662 __ pop(r0);
00663
00664 __ pop();
00665 break;
00666
00667 default:
00668
00669 UNREACHABLE();
00670 break;
00671 }
00672 }
00673
00674
00675 class DeferredInlinedSmiOperation: public DeferredCode {
00676 public:
00677 DeferredInlinedSmiOperation(CodeGenerator* generator, Token::Value op,
00678 int value, bool reversed) :
00679 DeferredCode(generator), op_(op), value_(value), reversed_(reversed) {
00680 set_comment("[ DeferredInlinedSmiOperation");
00681 }
00682
00683 virtual void Generate() {
00684 switch (op_) {
00685 case Token::ADD: {
00686 if (reversed_) {
00687
00688 __ sub(r0, r0, Operand(Smi::FromInt(value_)));
00689 __ mov(r1, Operand(Smi::FromInt(value_)));
00690 } else {
00691
00692 __ sub(r1, r0, Operand(Smi::FromInt(value_)));
00693 __ mov(r0, Operand(Smi::FromInt(value_)));
00694 }
00695 break;
00696 }
00697
00698 case Token::SUB: {
00699 if (reversed_) {
00700
00701 __ rsb(r0, r0, Operand(Smi::FromInt(value_)));
00702 __ mov(r1, Operand(Smi::FromInt(value_)));
00703 } else {
00704 __ add(r1, r0, Operand(Smi::FromInt(value_)));
00705 __ mov(r0, Operand(Smi::FromInt(value_)));
00706 }
00707 break;
00708 }
00709
00710 case Token::BIT_OR:
00711 case Token::BIT_XOR:
00712 case Token::BIT_AND: {
00713 if (reversed_) {
00714 __ mov(r1, Operand(Smi::FromInt(value_)));
00715 } else {
00716 __ mov(r1, Operand(r0));
00717 __ mov(r0, Operand(Smi::FromInt(value_)));
00718 }
00719 break;
00720 }
00721
00722 case Token::SHL:
00723 case Token::SHR:
00724 case Token::SAR: {
00725 if (!reversed_) {
00726 __ mov(r1, Operand(r0));
00727 __ mov(r0, Operand(Smi::FromInt(value_)));
00728 } else {
00729 UNREACHABLE();
00730 }
00731 break;
00732 }
00733
00734 default:
00735
00736 UNREACHABLE();
00737 break;
00738 }
00739
00740 GenericBinaryOpStub igostub(op_);
00741 __ CallStub(&igostub);
00742 }
00743
00744 private:
00745 Token::Value op_;
00746 int value_;
00747 bool reversed_;
00748 };
00749
00750
00751 void CodeGenerator::SmiOperation(Token::Value op,
00752 Handle<Object> value,
00753 bool reversed) {
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763 int int_value = Smi::cast(*value)->value();
00764
00765 Label exit;
00766 __ pop(r0);
00767
00768 switch (op) {
00769 case Token::ADD: {
00770 DeferredCode* deferred =
00771 new DeferredInlinedSmiOperation(this, op, int_value, reversed);
00772
00773 __ add(r0, r0, Operand(value), SetCC);
00774 __ b(vs, deferred->enter());
00775 __ tst(r0, Operand(kSmiTagMask));
00776 __ b(ne, deferred->enter());
00777 __ bind(deferred->exit());
00778 break;
00779 }
00780
00781 case Token::SUB: {
00782 DeferredCode* deferred =
00783 new DeferredInlinedSmiOperation(this, op, int_value, reversed);
00784
00785 if (!reversed) {
00786 __ sub(r0, r0, Operand(value), SetCC);
00787 } else {
00788 __ rsb(r0, r0, Operand(value), SetCC);
00789 }
00790 __ b(vs, deferred->enter());
00791 __ tst(r0, Operand(kSmiTagMask));
00792 __ b(ne, deferred->enter());
00793 __ bind(deferred->exit());
00794 break;
00795 }
00796
00797 case Token::BIT_OR:
00798 case Token::BIT_XOR:
00799 case Token::BIT_AND: {
00800 DeferredCode* deferred =
00801 new DeferredInlinedSmiOperation(this, op, int_value, reversed);
00802 __ tst(r0, Operand(kSmiTagMask));
00803 __ b(ne, deferred->enter());
00804 switch (op) {
00805 case Token::BIT_OR: __ orr(r0, r0, Operand(value)); break;
00806 case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break;
00807 case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break;
00808 default: UNREACHABLE();
00809 }
00810 __ bind(deferred->exit());
00811 break;
00812 }
00813
00814 case Token::SHL:
00815 case Token::SHR:
00816 case Token::SAR: {
00817 if (reversed) {
00818 __ mov(ip, Operand(value));
00819 __ push(ip);
00820 __ push(r0);
00821 GenericBinaryOperation(op);
00822
00823 } else {
00824 int shift_value = int_value & 0x1f;
00825 DeferredCode* deferred =
00826 new DeferredInlinedSmiOperation(this, op, shift_value, false);
00827 __ tst(r0, Operand(kSmiTagMask));
00828 __ b(ne, deferred->enter());
00829 __ mov(r2, Operand(r0, ASR, kSmiTagSize));
00830 switch (op) {
00831 case Token::SHL: {
00832 __ mov(r2, Operand(r2, LSL, shift_value));
00833
00834 __ add(r3, r2, Operand(0x40000000), SetCC);
00835 __ b(mi, deferred->enter());
00836 break;
00837 }
00838 case Token::SHR: {
00839
00840 if (shift_value != 0) {
00841 __ mov(r2, Operand(r2, LSR, shift_value));
00842 }
00843
00844
00845
00846
00847
00848
00849 __ and_(r3, r2, Operand(0xc0000000), SetCC);
00850 __ b(ne, deferred->enter());
00851 break;
00852 }
00853 case Token::SAR: {
00854 if (shift_value != 0) {
00855
00856 __ mov(r2, Operand(r2, ASR, shift_value));
00857 }
00858 break;
00859 }
00860 default: UNREACHABLE();
00861 }
00862 __ mov(r0, Operand(r2, LSL, kSmiTagSize));
00863 __ bind(deferred->exit());
00864 }
00865 break;
00866 }
00867
00868 default:
00869 if (!reversed) {
00870 __ push(r0);
00871 __ mov(r0, Operand(value));
00872 __ push(r0);
00873 } else {
00874 __ mov(ip, Operand(value));
00875 __ push(ip);
00876 __ push(r0);
00877 }
00878 GenericBinaryOperation(op);
00879 break;
00880 }
00881
00882 __ bind(&exit);
00883 }
00884
00885
00886 void CodeGenerator::Comparison(Condition cc, bool strict) {
00887
00888
00889
00890
00891
00892 ASSERT(!strict || cc == eq);
00893
00894 Label exit, smi;
00895
00896 if (cc == gt || cc == le) {
00897 cc = ReverseCondition(cc);
00898 __ pop(r1);
00899 __ pop(r0);
00900 } else {
00901 __ pop(r0);
00902 __ pop(r1);
00903 }
00904 __ orr(r2, r0, Operand(r1));
00905 __ tst(r2, Operand(kSmiTagMask));
00906 __ b(eq, &smi);
00907
00908
00909 __ push(r1);
00910
00911
00912 Builtins::JavaScript native;
00913 int argc;
00914 if (cc == eq) {
00915 native = strict ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
00916 argc = 1;
00917 } else {
00918 native = Builtins::COMPARE;
00919 int ncr;
00920 if (cc == lt || cc == le) {
00921 ncr = GREATER;
00922 } else {
00923 ASSERT(cc == gt || cc == ge);
00924 ncr = LESS;
00925 }
00926 __ push(r0);
00927 __ mov(r0, Operand(Smi::FromInt(ncr)));
00928 argc = 2;
00929 }
00930
00931
00932
00933 __ push(r0);
00934 __ mov(r0, Operand(argc));
00935 __ InvokeBuiltin(native, CALL_JS);
00936 __ cmp(r0, Operand(0));
00937 __ b(&exit);
00938
00939
00940 __ bind(&smi);
00941 __ cmp(r1, Operand(r0));
00942
00943 __ bind(&exit);
00944 cc_reg_ = cc;
00945 }
00946
00947
00948 class CallFunctionStub: public CodeStub {
00949 public:
00950 explicit CallFunctionStub(int argc) : argc_(argc) {}
00951
00952 void Generate(MacroAssembler* masm);
00953
00954 private:
00955 int argc_;
00956
00957 #if defined(DEBUG)
00958 void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); }
00959 #endif // defined(DEBUG)
00960
00961 Major MajorKey() { return CallFunction; }
00962 int MinorKey() { return argc_; }
00963 };
00964
00965
00966
00967 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
00968 int position) {
00969
00970 for (int i = 0; i < args->length(); i++) {
00971 Load(args->at(i));
00972 }
00973
00974
00975 __ RecordPosition(position);
00976
00977
00978 CallFunctionStub call_function(args->length());
00979 __ CallStub(&call_function);
00980
00981
00982 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
00983 __ pop();
00984 }
00985
00986
00987 void CodeGenerator::Branch(bool if_true, Label* L) {
00988 ASSERT(has_cc());
00989 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
00990 __ b(cc, L);
00991 cc_reg_ = al;
00992 }
00993
00994
00995 void CodeGenerator::CheckStack() {
00996 if (FLAG_check_stack) {
00997 Comment cmnt(masm_, "[ check stack");
00998 StackCheckStub stub;
00999 __ CallStub(&stub);
01000 }
01001 }
01002
01003
01004 void CodeGenerator::VisitBlock(Block* node) {
01005 Comment cmnt(masm_, "[ Block");
01006 if (FLAG_debug_info) RecordStatementPosition(node);
01007 node->set_break_stack_height(break_stack_height_);
01008 VisitStatements(node->statements());
01009 __ bind(node->break_target());
01010 }
01011
01012
01013 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
01014 __ mov(r0, Operand(pairs));
01015 __ push(r0);
01016 __ push(cp);
01017 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
01018 __ push(r0);
01019 __ CallRuntime(Runtime::kDeclareGlobals, 3);
01020
01021 }
01022
01023
01024 void CodeGenerator::VisitDeclaration(Declaration* node) {
01025 Comment cmnt(masm_, "[ Declaration");
01026 Variable* var = node->proxy()->var();
01027 ASSERT(var != NULL);
01028 Slot* slot = var->slot();
01029
01030
01031
01032
01033 if (slot != NULL && slot->type() == Slot::LOOKUP) {
01034
01035
01036 ASSERT(var->mode() == Variable::DYNAMIC);
01037
01038 __ push(cp);
01039 __ mov(r0, Operand(var->name()));
01040 __ push(r0);
01041
01042 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
01043 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
01044 __ mov(r0, Operand(Smi::FromInt(attr)));
01045 __ push(r0);
01046
01047
01048
01049
01050 if (node->mode() == Variable::CONST) {
01051 __ mov(r0, Operand(Factory::the_hole_value()));
01052 __ push(r0);
01053 } else if (node->fun() != NULL) {
01054 Load(node->fun());
01055 } else {
01056 __ mov(r0, Operand(0));
01057 __ push(r0);
01058 }
01059 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
01060
01061 return;
01062 }
01063
01064 ASSERT(!var->is_global());
01065
01066
01067 Expression* val = NULL;
01068 if (node->mode() == Variable::CONST) {
01069 val = new Literal(Factory::the_hole_value());
01070 } else {
01071 val = node->fun();
01072 }
01073
01074 if (val != NULL) {
01075
01076 Reference target(this, node->proxy());
01077 ASSERT(target.is_slot());
01078 Load(val);
01079 target.SetValue(NOT_CONST_INIT);
01080
01081
01082
01083
01084 __ pop();
01085 }
01086 }
01087
01088
01089 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
01090 Comment cmnt(masm_, "[ ExpressionStatement");
01091 if (FLAG_debug_info) RecordStatementPosition(node);
01092 Expression* expression = node->expression();
01093 expression->MarkAsStatement();
01094 Load(expression);
01095 __ pop();
01096 }
01097
01098
01099 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
01100 Comment cmnt(masm_, "// EmptyStatement");
01101
01102 }
01103
01104
01105 void CodeGenerator::VisitIfStatement(IfStatement* node) {
01106 Comment cmnt(masm_, "[ IfStatement");
01107
01108
01109 bool has_then_stm = node->HasThenStatement();
01110 bool has_else_stm = node->HasElseStatement();
01111
01112 if (FLAG_debug_info) RecordStatementPosition(node);
01113
01114 Label exit;
01115 if (has_then_stm && has_else_stm) {
01116 Comment cmnt(masm_, "[ IfThenElse");
01117 Label then;
01118 Label else_;
01119
01120 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
01121 Branch(false, &else_);
01122
01123 __ bind(&then);
01124 Visit(node->then_statement());
01125 __ b(&exit);
01126
01127 __ bind(&else_);
01128 Visit(node->else_statement());
01129
01130 } else if (has_then_stm) {
01131 Comment cmnt(masm_, "[ IfThen");
01132 ASSERT(!has_else_stm);
01133 Label then;
01134
01135 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true);
01136 Branch(false, &exit);
01137
01138 __ bind(&then);
01139 Visit(node->then_statement());
01140
01141 } else if (has_else_stm) {
01142 Comment cmnt(masm_, "[ IfElse");
01143 ASSERT(!has_then_stm);
01144 Label else_;
01145
01146 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true);
01147 Branch(true, &exit);
01148
01149 __ bind(&else_);
01150 Visit(node->else_statement());
01151
01152 } else {
01153 Comment cmnt(masm_, "[ If");
01154 ASSERT(!has_then_stm && !has_else_stm);
01155
01156 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false);
01157 if (has_cc()) {
01158 cc_reg_ = al;
01159 } else {
01160 __ pop(r0);
01161 }
01162 }
01163
01164
01165 __ bind(&exit);
01166 }
01167
01168
01169 void CodeGenerator::CleanStack(int num_bytes) {
01170 ASSERT(num_bytes >= 0);
01171 if (num_bytes > 0) {
01172 __ add(sp, sp, Operand(num_bytes));
01173 }
01174 }
01175
01176
01177 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
01178 Comment cmnt(masm_, "[ ContinueStatement");
01179 if (FLAG_debug_info) RecordStatementPosition(node);
01180 CleanStack(break_stack_height_ - node->target()->break_stack_height());
01181 __ b(node->target()->continue_target());
01182 }
01183
01184
01185 void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
01186 Comment cmnt(masm_, "[ BreakStatement");
01187 if (FLAG_debug_info) RecordStatementPosition(node);
01188 CleanStack(break_stack_height_ - node->target()->break_stack_height());
01189 __ b(node->target()->break_target());
01190 }
01191
01192
01193 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
01194 Comment cmnt(masm_, "[ ReturnStatement");
01195 if (FLAG_debug_info) RecordStatementPosition(node);
01196 Load(node->expression());
01197
01198 __ pop(r0);
01199
01200 __ b(&function_return_);
01201 }
01202
01203
01204 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
01205 Comment cmnt(masm_, "[ WithEnterStatement");
01206 if (FLAG_debug_info) RecordStatementPosition(node);
01207 Load(node->expression());
01208 __ CallRuntime(Runtime::kPushContext, 1);
01209 if (kDebug) {
01210 Label verified_true;
01211 __ cmp(r0, Operand(cp));
01212 __ b(eq, &verified_true);
01213 __ stop("PushContext: r0 is expected to be the same as cp");
01214 __ bind(&verified_true);
01215 }
01216
01217 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
01218 }
01219
01220
01221 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
01222 Comment cmnt(masm_, "[ WithExitStatement");
01223
01224 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
01225
01226 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
01227 }
01228
01229
01230 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
01231 return kFastSwitchMaxOverheadFactor;
01232 }
01233
01234 int CodeGenerator::FastCaseSwitchMinCaseCount() {
01235 return kFastSwitchMinCaseCount;
01236 }
01237
01238
01239 void CodeGenerator::GenerateFastCaseSwitchJumpTable(
01240 SwitchStatement* node,
01241 int min_index,
01242 int range,
01243 Label* fail_label,
01244 Vector<Label*> case_targets,
01245 Vector<Label> case_labels) {
01246
01247 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);
01248
01249 __ pop(r0);
01250 if (min_index != 0) {
01251
01252 if (min_index < 0) {
01253 __ add(r0, r0, Operand(Smi::FromInt(-min_index)));
01254 } else {
01255 __ sub(r0, r0, Operand(Smi::FromInt(min_index)));
01256 }
01257 }
01258 __ tst(r0, Operand(0x80000000 | kSmiTagMask));
01259 __ b(ne, fail_label);
01260 __ cmp(r0, Operand(Smi::FromInt(range)));
01261 __ b(ge, fail_label);
01262 __ add(pc, pc, Operand(r0, LSL, 2 - kSmiTagSize));
01263
01264
01265 __ stop("Unreachable: Switch table alignment");
01266
01267
01268 for (int i = 0; i < range; i++) {
01269 __ b(case_targets[i]);
01270 }
01271
01272 GenerateFastCaseSwitchCases(node, case_labels);
01273 }
01274
01275
01276 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
01277 Comment cmnt(masm_, "[ SwitchStatement");
01278 if (FLAG_debug_info) RecordStatementPosition(node);
01279 node->set_break_stack_height(break_stack_height_);
01280
01281 Load(node->tag());
01282
01283 if (TryGenerateFastCaseSwitchStatement(node)) {
01284 return;
01285 }
01286
01287 Label next, fall_through, default_case;
01288 ZoneList<CaseClause*>* cases = node->cases();
01289 int length = cases->length();
01290
01291 for (int i = 0; i < length; i++) {
01292 CaseClause* clause = cases->at(i);
01293
01294 Comment cmnt(masm_, "[ case clause");
01295
01296 if (clause->is_default()) {
01297
01298
01299 __ b(&next);
01300
01301
01302
01303 ASSERT(default_case.is_unused());
01304 __ bind(&default_case);
01305 } else {
01306 __ bind(&next);
01307 next.Unuse();
01308 __ ldr(r0, MemOperand(sp, 0));
01309 __ push(r0);
01310 Load(clause->label());
01311 Comparison(eq, true);
01312 Branch(false, &next);
01313 }
01314
01315
01316
01317 __ pop(r0);
01318
01319
01320
01321
01322
01323 __ bind(&fall_through);
01324 fall_through.Unuse();
01325 VisitStatements(clause->statements());
01326 __ b(&fall_through);
01327 }
01328
01329 __ bind(&next);
01330
01331 if (default_case.is_bound()) {
01332
01333 __ b(&default_case);
01334 } else {
01335
01336 __ pop(r0);
01337 }
01338
01339 __ bind(&fall_through);
01340 __ bind(node->break_target());
01341 }
01342
01343
01344 void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
01345 Comment cmnt(masm_, "[ LoopStatement");
01346 if (FLAG_debug_info) RecordStatementPosition(node);
01347 node->set_break_stack_height(break_stack_height_);
01348
01349
01350 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
01351 if (node->cond() == NULL) {
01352 ASSERT(node->type() == LoopStatement::FOR_LOOP);
01353 info = ALWAYS_TRUE;
01354 } else {
01355 Literal* lit = node->cond()->AsLiteral();
01356 if (lit != NULL) {
01357 if (lit->IsTrue()) {
01358 info = ALWAYS_TRUE;
01359 } else if (lit->IsFalse()) {
01360 info = ALWAYS_FALSE;
01361 }
01362 }
01363 }
01364
01365 Label loop, entry;
01366
01367
01368 if (node->init() != NULL) {
01369 ASSERT(node->type() == LoopStatement::FOR_LOOP);
01370 Visit(node->init());
01371 }
01372 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) {
01373 __ b(&entry);
01374 }
01375
01376
01377 __ bind(&loop);
01378 Visit(node->body());
01379
01380
01381 __ bind(node->continue_target());
01382 if (node->next() != NULL) {
01383
01384
01385
01386 if (FLAG_debug_info) __ RecordPosition(node->statement_pos());
01387 ASSERT(node->type() == LoopStatement::FOR_LOOP);
01388 Visit(node->next());
01389 }
01390
01391
01392 __ bind(&entry);
01393 switch (info) {
01394 case ALWAYS_TRUE:
01395 CheckStack();
01396 __ b(&loop);
01397 break;
01398 case ALWAYS_FALSE:
01399 break;
01400 case DONT_KNOW:
01401 CheckStack();
01402 LoadCondition(node->cond(),
01403 NOT_INSIDE_TYPEOF,
01404 &loop,
01405 node->break_target(),
01406 true);
01407 Branch(true, &loop);
01408 break;
01409 }
01410
01411
01412 __ bind(node->break_target());
01413 }
01414
01415
01416 void CodeGenerator::VisitForInStatement(ForInStatement* node) {
01417 Comment cmnt(masm_, "[ ForInStatement");
01418 if (FLAG_debug_info) RecordStatementPosition(node);
01419
01420
01421
01422
01423 const int kForInStackSize = 5 * kPointerSize;
01424 break_stack_height_ += kForInStackSize;
01425 node->set_break_stack_height(break_stack_height_);
01426
01427 Label loop, next, entry, cleanup, exit, primitive, jsobject;
01428 Label filter_key, end_del_check, fixed_array, non_string;
01429
01430
01431 Load(node->enumerable());
01432 __ pop(r0);
01433
01434
01435
01436 __ cmp(r0, Operand(Factory::undefined_value()));
01437 __ b(eq, &exit);
01438 __ cmp(r0, Operand(Factory::null_value()));
01439 __ b(eq, &exit);
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449 __ tst(r0, Operand(kSmiTagMask));
01450 __ b(eq, &primitive);
01451 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
01452 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
01453 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
01454 __ b(hs, &jsobject);
01455
01456 __ bind(&primitive);
01457 __ push(r0);
01458 __ mov(r0, Operand(0));
01459 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
01460
01461
01462 __ bind(&jsobject);
01463
01464
01465 __ push(r0);
01466 __ push(r0);
01467 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
01468
01469
01470
01471 __ mov(r2, Operand(r0));
01472 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
01473 __ cmp(r1, Operand(Factory::meta_map()));
01474 __ b(ne, &fixed_array);
01475
01476
01477 __ mov(r1, Operand(r0));
01478 __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
01479 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
01480 __ ldr(r2,
01481 FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
01482
01483 __ push(r0);
01484 __ push(r2);
01485 __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset));
01486 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
01487 __ push(r0);
01488 __ mov(r0, Operand(Smi::FromInt(0)));
01489 __ push(r0);
01490 __ b(&entry);
01491
01492
01493 __ bind(&fixed_array);
01494
01495 __ mov(r1, Operand(Smi::FromInt(0)));
01496 __ push(r1);
01497 __ push(r0);
01498
01499
01500 __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset));
01501 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
01502 __ push(r0);
01503 __ mov(r0, Operand(Smi::FromInt(0)));
01504 __ push(r0);
01505
01506 __ b(&entry);
01507
01508
01509 __ bind(&loop);
01510 Visit(node->body());
01511
01512
01513 __ bind(node->continue_target());
01514 __ bind(&next);
01515 __ pop(r0);
01516 __ add(r0, r0, Operand(Smi::FromInt(1)));
01517 __ push(r0);
01518
01519
01520 __ bind(&entry);
01521
01522
01523
01524
01525
01526
01527 __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
01528 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
01529 __ cmp(r0, Operand(r1));
01530 __ b(hs, &cleanup);
01531
01532 __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
01533
01534
01535 __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
01536 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
01537 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
01538
01539
01540 __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
01541
01542
01543 __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
01544 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
01545 __ cmp(r1, Operand(r2));
01546 __ b(eq, &end_del_check);
01547
01548
01549 __ ldr(r0, MemOperand(sp, 4 * kPointerSize));
01550 __ push(r0);
01551 __ push(r3);
01552 __ mov(r0, Operand(1));
01553 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS);
01554 __ mov(r3, Operand(r0));
01555
01556
01557 __ cmp(r3, Operand(Factory::null_value()));
01558 __ b(eq, &next);
01559
01560
01561 __ bind(&end_del_check);
01562
01563
01564
01565 __ push(r3);
01566 { Reference each(this, node->each());
01567 if (!each.is_illegal()) {
01568 if (each.size() > 0) {
01569 __ ldr(r0, MemOperand(sp, kPointerSize * each.size()));
01570 __ push(r0);
01571 }
01572
01573
01574
01575 each.SetValue(NOT_CONST_INIT);
01576 if (each.size() > 0) {
01577
01578
01579
01580
01581
01582 __ pop(r0);
01583 }
01584 }
01585 }
01586
01587
01588 __ pop();
01589 CheckStack();
01590 __ jmp(&loop);
01591
01592
01593 __ bind(&cleanup);
01594 __ bind(node->break_target());
01595 __ add(sp, sp, Operand(5 * kPointerSize));
01596
01597
01598 __ bind(&exit);
01599
01600 break_stack_height_ -= kForInStackSize;
01601 }
01602
01603
01604 void CodeGenerator::VisitTryCatch(TryCatch* node) {
01605 Comment cmnt(masm_, "[ TryCatch");
01606
01607 Label try_block, exit;
01608
01609 __ bl(&try_block);
01610
01611
01612
01613
01614 __ push(r0);
01615 { Reference ref(this, node->catch_var());
01616 ASSERT(ref.is_slot());
01617
01618
01619
01620 ref.SetValue(NOT_CONST_INIT);
01621 }
01622
01623
01624 __ pop();
01625
01626 VisitStatements(node->catch_block()->statements());
01627 __ b(&exit);
01628
01629
01630
01631 __ bind(&try_block);
01632
01633 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
01634
01635
01636
01637
01638
01639
01640
01641
01642 int nof_escapes = node->escaping_labels()->length();
01643 List<LabelShadow*> shadows(1 + nof_escapes);
01644 shadows.Add(new LabelShadow(&function_return_));
01645 for (int i = 0; i < nof_escapes; i++) {
01646 shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
01647 }
01648
01649
01650 VisitStatements(node->try_block()->statements());
01651 __ pop(r0);
01652
01653
01654
01655
01656 int nof_unlinks = 0;
01657 for (int i = 0; i <= nof_escapes; i++) {
01658 shadows[i]->StopShadowing();
01659 if (shadows[i]->is_linked()) nof_unlinks++;
01660 }
01661
01662
01663
01664 const int kNextOffset = StackHandlerConstants::kNextOffset +
01665 StackHandlerConstants::kAddressDisplacement;
01666 __ ldr(r1, MemOperand(sp, kNextOffset));
01667 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
01668 __ str(r1, MemOperand(r3));
01669 ASSERT(StackHandlerConstants::kCodeOffset == 0);
01670 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
01671
01672 if (nof_unlinks > 0) __ b(&exit);
01673
01674
01675
01676 for (int i = 0; i <= nof_escapes; i++) {
01677 if (shadows[i]->is_linked()) {
01678
01679 __ bind(shadows[i]);
01680
01681
01682
01683 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
01684 __ ldr(sp, MemOperand(r3));
01685
01686 __ ldr(r1, MemOperand(sp, kNextOffset));
01687 __ str(r1, MemOperand(r3));
01688 ASSERT(StackHandlerConstants::kCodeOffset == 0);
01689 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
01690
01691
01692 __ b(shadows[i]->original_label());
01693 }
01694 }
01695
01696 __ bind(&exit);
01697 }
01698
01699
01700 void CodeGenerator::VisitTryFinally(TryFinally* node) {
01701 Comment cmnt(masm_, "[ TryFinally");
01702
01703
01704
01705
01706 enum { FALLING, THROWING, JUMPING };
01707
01708 Label exit, unlink, try_block, finally_block;
01709
01710 __ bl(&try_block);
01711
01712 __ push(r0);
01713
01714 __ mov(r2, Operand(Smi::FromInt(THROWING)));
01715 __ b(&finally_block);
01716
01717
01718
01719 __ bind(&try_block);
01720
01721 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
01722
01723
01724
01725
01726
01727
01728
01729 int nof_escapes = node->escaping_labels()->length();
01730 List<LabelShadow*> shadows(1 + nof_escapes);
01731 shadows.Add(new LabelShadow(&function_return_));
01732 for (int i = 0; i < nof_escapes; i++) {
01733 shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
01734 }
01735
01736
01737 VisitStatements(node->try_block()->statements());
01738
01739
01740
01741
01742 int nof_unlinks = 0;
01743 for (int i = 0; i <= nof_escapes; i++) {
01744 shadows[i]->StopShadowing();
01745 if (shadows[i]->is_linked()) nof_unlinks++;
01746 }
01747
01748
01749 __ mov(r0, Operand(Factory::undefined_value()));
01750 __ push(r0);
01751 __ mov(r2, Operand(Smi::FromInt(FALLING)));
01752 if (nof_unlinks > 0) __ b(&unlink);
01753
01754
01755
01756 for (int i = 0; i <= nof_escapes; i++) {
01757 if (shadows[i]->is_linked()) {
01758 __ bind(shadows[i]);
01759 if (shadows[i]->original_label() == &function_return_) {
01760
01761
01762 __ push(r0);
01763 } else {
01764
01765 __ mov(r0, Operand(Factory::undefined_value()));
01766 __ push(r0);
01767 }
01768 __ mov(r2, Operand(Smi::FromInt(JUMPING + i)));
01769 __ b(&unlink);
01770 }
01771 }
01772
01773
01774 __ bind(&unlink);
01775
01776 __ pop(r0);
01777
01778
01779 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
01780 __ ldr(sp, MemOperand(r3));
01781 const int kNextOffset = StackHandlerConstants::kNextOffset +
01782 StackHandlerConstants::kAddressDisplacement;
01783 __ ldr(r1, MemOperand(sp, kNextOffset));
01784 __ str(r1, MemOperand(r3));
01785 ASSERT(StackHandlerConstants::kCodeOffset == 0);
01786 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
01787
01788 __ push(r0);
01789
01790
01791 __ bind(&finally_block);
01792
01793
01794 __ push(r2);
01795
01796
01797
01798
01799
01800 const int kFinallyStackSize = 2 * kPointerSize;
01801 break_stack_height_ += kFinallyStackSize;
01802
01803
01804 VisitStatements(node->finally_block()->statements());
01805
01806
01807 __ pop(r2);
01808 __ pop(r0);
01809 break_stack_height_ -= kFinallyStackSize;
01810
01811
01812
01813 for (int i = 0; i <= nof_escapes; i++) {
01814 if (shadows[i]->is_bound()) {
01815 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i)));
01816 if (shadows[i]->original_label() != &function_return_) {
01817 Label next;
01818 __ b(ne, &next);
01819 __ b(shadows[i]->original_label());
01820 __ bind(&next);
01821 } else {
01822 __ b(eq, shadows[i]->original_label());
01823 }
01824 }
01825 }
01826
01827
01828 __ cmp(r2, Operand(Smi::FromInt(THROWING)));
01829 __ b(ne, &exit);
01830
01831
01832 __ push(r0);
01833 __ CallRuntime(Runtime::kReThrow, 1);
01834
01835
01836 __ bind(&exit);
01837 }
01838
01839
01840 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
01841 Comment cmnt(masm_, "[ DebuggerStatament");
01842 if (FLAG_debug_info) RecordStatementPosition(node);
01843 __ CallRuntime(Runtime::kDebugBreak, 0);
01844
01845 }
01846
01847
01848 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
01849 ASSERT(boilerplate->IsBoilerplate());
01850
01851
01852 __ mov(r0, Operand(boilerplate));
01853 __ push(r0);
01854
01855
01856 __ push(cp);
01857 __ CallRuntime(Runtime::kNewClosure, 2);
01858 __ push(r0);
01859 }
01860
01861
01862 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
01863 Comment cmnt(masm_, "[ FunctionLiteral");
01864
01865
01866 Handle<JSFunction> boilerplate = BuildBoilerplate(node);
01867
01868 if (HasStackOverflow()) return;
01869 InstantiateBoilerplate(boilerplate);
01870 }
01871
01872
01873 void CodeGenerator::VisitFunctionBoilerplateLiteral(
01874 FunctionBoilerplateLiteral* node) {
01875 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
01876 InstantiateBoilerplate(node->boilerplate());
01877 }
01878
01879
01880 void CodeGenerator::VisitConditional(Conditional* node) {
01881 Comment cmnt(masm_, "[ Conditional");
01882 Label then, else_, exit;
01883 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
01884 Branch(false, &else_);
01885 __ bind(&then);
01886 Load(node->then_expression(), typeof_state());
01887 __ b(&exit);
01888 __ bind(&else_);
01889 Load(node->else_expression(), typeof_state());
01890 __ bind(&exit);
01891 }
01892
01893
01894 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
01895 if (slot->type() == Slot::LOOKUP) {
01896 ASSERT(slot->var()->mode() == Variable::DYNAMIC);
01897
01898
01899 __ push(cp);
01900 __ mov(r0, Operand(slot->var()->name()));
01901 __ push(r0);
01902
01903 if (typeof_state == INSIDE_TYPEOF) {
01904 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
01905 } else {
01906 __ CallRuntime(Runtime::kLoadContextSlot, 2);
01907 }
01908 __ push(r0);
01909
01910 } else {
01911
01912
01913
01914
01915
01916 __ ldr(r0, SlotOperand(slot, r2));
01917 __ push(r0);
01918 if (slot->var()->mode() == Variable::CONST) {
01919
01920
01921
01922 Comment cmnt(masm_, "[ Unhole const");
01923 __ pop(r0);
01924 __ cmp(r0, Operand(Factory::the_hole_value()));
01925 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
01926 __ push(r0);
01927 }
01928 }
01929 }
01930
01931
01932 void CodeGenerator::VisitSlot(Slot* node) {
01933 Comment cmnt(masm_, "[ Slot");
01934 LoadFromSlot(node, typeof_state());
01935 }
01936
01937
01938 void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
01939 Comment cmnt(masm_, "[ VariableProxy");
01940
01941 Variable* var = node->var();
01942 Expression* expr = var->rewrite();
01943 if (expr != NULL) {
01944 Visit(expr);
01945 } else {
01946 ASSERT(var->is_global());
01947 Reference ref(this, node);
01948 ref.GetValue(typeof_state());
01949 }
01950 }
01951
01952
01953 void CodeGenerator::VisitLiteral(Literal* node) {
01954 Comment cmnt(masm_, "[ Literal");
01955 __ mov(r0, Operand(node->handle()));
01956 __ push(r0);
01957 }
01958
01959
01960 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
01961 Comment cmnt(masm_, "[ RexExp Literal");
01962
01963
01964
01965
01966 __ ldr(r1, FunctionOperand());
01967
01968
01969 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
01970
01971
01972 int literal_offset =
01973 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
01974 __ ldr(r2, FieldMemOperand(r1, literal_offset));
01975
01976 Label done;
01977 __ cmp(r2, Operand(Factory::undefined_value()));
01978 __ b(ne, &done);
01979
01980
01981
01982 __ push(r1);
01983 __ mov(r0, Operand(Smi::FromInt(node->literal_index())));
01984 __ push(r0);
01985 __ mov(r0, Operand(node->pattern()));
01986 __ push(r0);
01987 __ mov(r0, Operand(node->flags()));
01988 __ push(r0);
01989 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
01990 __ mov(r2, Operand(r0));
01991
01992 __ bind(&done);
01993
01994 __ push(r2);
01995 }
01996
01997
01998
01999
02000
02001
02002 class ObjectLiteralDeferred: public DeferredCode {
02003 public:
02004 ObjectLiteralDeferred(CodeGenerator* generator, ObjectLiteral* node)
02005 : DeferredCode(generator), node_(node) {
02006 set_comment("[ ObjectLiteralDeferred");
02007 }
02008 virtual void Generate();
02009 private:
02010 ObjectLiteral* node_;
02011 };
02012
02013
02014 void ObjectLiteralDeferred::Generate() {
02015
02016
02017
02018
02019 __ push(r1);
02020
02021 __ mov(r0, Operand(Smi::FromInt(node_->literal_index())));
02022 __ push(r0);
02023
02024 __ mov(r0, Operand(node_->constant_properties()));
02025 __ push(r0);
02026 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
02027 __ mov(r2, Operand(r0));
02028 }
02029
02030
02031 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
02032 Comment cmnt(masm_, "[ ObjectLiteral");
02033
02034 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node);
02035
02036
02037
02038
02039 __ ldr(r1, FunctionOperand());
02040
02041
02042 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
02043
02044
02045 int literal_offset =
02046 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
02047 __ ldr(r2, FieldMemOperand(r1, literal_offset));
02048
02049
02050
02051 __ cmp(r2, Operand(Factory::undefined_value()));
02052 __ b(eq, deferred->enter());
02053 __ bind(deferred->exit());
02054
02055
02056 __ push(r2);
02057
02058
02059 __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
02060 __ push(r0);
02061
02062
02063 for (int i = 0; i < node->properties()->length(); i++) {
02064 ObjectLiteral::Property* property = node->properties()->at(i);
02065 Literal* key = property->key();
02066 Expression* value = property->value();
02067 switch (property->kind()) {
02068 case ObjectLiteral::Property::CONSTANT: break;
02069 case ObjectLiteral::Property::COMPUTED:
02070 case ObjectLiteral::Property::PROTOTYPE: {
02071 __ push(r0);
02072 Load(key);
02073 Load(value);
02074 __ CallRuntime(Runtime::kSetProperty, 3);
02075
02076 __ ldr(r0, MemOperand(sp, 0));
02077 break;
02078 }
02079 case ObjectLiteral::Property::SETTER: {
02080 __ push(r0);
02081 Load(key);
02082 __ mov(r0, Operand(Smi::FromInt(1)));
02083 __ push(r0);
02084 Load(value);
02085 __ CallRuntime(Runtime::kDefineAccessor, 4);
02086 __ ldr(r0, MemOperand(sp, 0));
02087 break;
02088 }
02089 case ObjectLiteral::Property::GETTER: {
02090 __ push(r0);
02091 Load(key);
02092 __ mov(r0, Operand(Smi::FromInt(0)));
02093 __ push(r0);
02094 Load(value);
02095 __ CallRuntime(Runtime::kDefineAccessor, 4);
02096 __ ldr(r0, MemOperand(sp, 0));
02097 break;
02098 }
02099 }
02100 }
02101 }
02102
02103
02104 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
02105 Comment cmnt(masm_, "[ ArrayLiteral");
02106
02107
02108 __ mov(r0, Operand(node->literals()));
02109 __ push(r0);
02110
02111 __ ldr(r0, FunctionOperand());
02112 __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
02113 __ push(r0);
02114 __ CallRuntime(Runtime::kCreateArrayLiteral, 2);
02115
02116
02117 __ push(r0);
02118
02119
02120
02121 for (int i = 0; i < node->values()->length(); i++) {
02122 Expression* value = node->values()->at(i);
02123
02124
02125
02126 if (value->AsLiteral() == NULL) {
02127
02128 Load(value);
02129 __ pop(r0);
02130
02131
02132 __ ldr(r1, MemOperand(sp, 0));
02133
02134 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
02135
02136
02137 int offset = i * kPointerSize + Array::kHeaderSize;
02138 __ str(r0, FieldMemOperand(r1, offset));
02139
02140
02141 __ mov(r3, Operand(offset));
02142 __ RecordWrite(r1, r3, r2);
02143 }
02144 }
02145 }
02146
02147
02148 void CodeGenerator::VisitAssignment(Assignment* node) {
02149 Comment cmnt(masm_, "[ Assignment");
02150 if (FLAG_debug_info) RecordStatementPosition(node);
02151
02152 Reference target(this, node->target());
02153 if (target.is_illegal()) return;
02154
02155 if (node->op() == Token::ASSIGN ||
02156 node->op() == Token::INIT_VAR ||
02157 node->op() == Token::INIT_CONST) {
02158 Load(node->value());
02159
02160 } else {
02161 target.GetValue(NOT_INSIDE_TYPEOF);
02162 Literal* literal = node->value()->AsLiteral();
02163 if (literal != NULL && literal->handle()->IsSmi()) {
02164 SmiOperation(node->binary_op(), literal->handle(), false);
02165 __ push(r0);
02166
02167 } else {
02168 Load(node->value());
02169 GenericBinaryOperation(node->binary_op());
02170 __ push(r0);
02171 }
02172 }
02173
02174 Variable* var = node->target()->AsVariableProxy()->AsVariable();
02175 if (var != NULL &&
02176 (var->mode() == Variable::CONST) &&
02177 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
02178
02179
02180 } else {
02181 __ RecordPosition(node->position());
02182 if (node->op() == Token::INIT_CONST) {
02183
02184
02185
02186 target.SetValue(CONST_INIT);
02187 } else {
02188 target.SetValue(NOT_CONST_INIT);
02189 }
02190 }
02191 }
02192
02193
02194 void CodeGenerator::VisitThrow(Throw* node) {
02195 Comment cmnt(masm_, "[ Throw");
02196
02197 Load(node->exception());
02198 __ RecordPosition(node->position());
02199 __ CallRuntime(Runtime::kThrow, 1);
02200 __ push(r0);
02201 }
02202
02203
02204 void CodeGenerator::VisitProperty(Property* node) {
02205 Comment cmnt(masm_, "[ Property");
02206
02207 Reference property(this, node);
02208 property.GetValue(typeof_state());
02209 }
02210
02211
02212 void CodeGenerator::VisitCall(Call* node) {
02213 Comment cmnt(masm_, "[ Call");
02214
02215 ZoneList<Expression*>* args = node->arguments();
02216
02217 if (FLAG_debug_info) RecordStatementPosition(node);
02218
02219
02220
02221 Expression* function = node->expression();
02222 Variable* var = function->AsVariableProxy()->AsVariable();
02223 Property* property = function->AsProperty();
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233
02234 if (var != NULL && !var->is_this() && var->is_global()) {
02235
02236
02237
02238
02239
02240 __ mov(r0, Operand(var->name()));
02241 __ push(r0);
02242
02243
02244
02245
02246 LoadGlobal();
02247
02248
02249 for (int i = 0; i < args->length(); i++) Load(args->at(i));
02250
02251
02252 Handle<Code> stub = ComputeCallInitialize(args->length());
02253 __ RecordPosition(node->position());
02254 __ Call(stub, RelocInfo::CODE_TARGET_CONTEXT);
02255 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
02256
02257 __ pop();
02258 __ push(r0);
02259
02260 } else if (var != NULL && var->slot() != NULL &&
02261 var->slot()->type() == Slot::LOOKUP) {
02262
02263
02264
02265
02266
02267 __ push(cp);
02268 __ mov(r0, Operand(var->name()));
02269 __ push(r0);
02270 __ CallRuntime(Runtime::kLoadContextSlot, 2);
02271
02272
02273
02274 __ push(r0);
02275 __ push(r1);
02276
02277
02278 CallWithArguments(args, node->position());
02279 __ push(r0);
02280
02281 } else if (property != NULL) {
02282
02283 Literal* literal = property->key()->AsLiteral();
02284
02285 if (literal != NULL && literal->handle()->IsSymbol()) {
02286
02287
02288
02289
02290
02291 __ mov(r0, Operand(literal->handle()));
02292 __ push(r0);
02293 Load(property->obj());
02294
02295
02296 for (int i = 0; i < args->length(); i++) Load(args->at(i));
02297
02298
02299 Handle<Code> stub = ComputeCallInitialize(args->length());
02300 __ RecordPosition(node->position());
02301 __ Call(stub, RelocInfo::CODE_TARGET);
02302 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
02303
02304
02305 __ pop();
02306
02307 __ push(r0);
02308
02309 } else {
02310
02311
02312
02313
02314
02315 Reference ref(this, property);
02316 ref.GetValue(NOT_INSIDE_TYPEOF);
02317
02318
02319 __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
02320 __ push(r0);
02321
02322 CallWithArguments(args, node->position());
02323 __ push(r0);
02324 }
02325
02326 } else {
02327
02328
02329
02330
02331
02332 Load(function);
02333
02334
02335 LoadGlobalReceiver(r0);
02336
02337
02338 CallWithArguments(args, node->position());
02339 __ push(r0);
02340 }
02341 }
02342
02343
02344 void CodeGenerator::VisitCallNew(CallNew* node) {
02345 Comment cmnt(masm_, "[ CallNew");
02346
02347
02348
02349
02350
02351
02352
02353
02354
02355
02356 Load(node->expression());
02357 LoadGlobal();
02358
02359
02360 ZoneList<Expression*>* args = node->arguments();
02361 for (int i = 0; i < args->length(); i++) Load(args->at(i));
02362
02363
02364 __ mov(r0, Operand(args->length()));
02365
02366
02367 __ ldr(r1, MemOperand(sp, (args->length() + 1) * kPointerSize));
02368
02369
02370
02371 __ RecordPosition(RelocInfo::POSITION);
02372 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
02373 RelocInfo::CONSTRUCT_CALL);
02374
02375
02376 __ str(r0, MemOperand(sp, 0 * kPointerSize));
02377 }
02378
02379
02380 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
02381 ASSERT(args->length() == 1);
02382 Label leave;
02383 Load(args->at(0));
02384 __ pop(r0);
02385
02386 __ tst(r0, Operand(kSmiTagMask));
02387 __ b(eq, &leave);
02388
02389 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
02390 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
02391
02392 __ cmp(r1, Operand(JS_VALUE_TYPE));
02393 __ b(ne, &leave);
02394
02395 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
02396 __ bind(&leave);
02397 __ push(r0);
02398 }
02399
02400
02401 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
02402 ASSERT(args->length() == 2);
02403 Label leave;
02404 Load(args->at(0));
02405 Load(args->at(1));
02406 __ pop(r0);
02407 __ pop(r1);
02408
02409 __ tst(r1, Operand(kSmiTagMask));
02410 __ b(eq, &leave);
02411
02412 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
02413 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
02414
02415 __ cmp(r2, Operand(JS_VALUE_TYPE));
02416 __ b(ne, &leave);
02417
02418 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
02419
02420 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag));
02421 __ RecordWrite(r1, r2, r3);
02422
02423 __ bind(&leave);
02424 __ push(r0);
02425 }
02426
02427
02428 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
02429 ASSERT(args->length() == 1);
02430 Load(args->at(0));
02431 __ pop(r0);
02432 __ tst(r0, Operand(kSmiTagMask));
02433 cc_reg_ = eq;
02434 }
02435
02436
02437 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
02438 ASSERT(args->length() == 1);
02439 Load(args->at(0));
02440 __ pop(r0);
02441 __ tst(r0, Operand(kSmiTagMask | 0x80000000));
02442 cc_reg_ = eq;
02443 }
02444
02445
02446
02447
02448
02449 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
02450 ASSERT(args->length() == 2);
02451 __ mov(r0, Operand(Factory::undefined_value()));
02452 __ push(r0);
02453 }
02454
02455
02456 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
02457 ASSERT(args->length() == 1);
02458 Load(args->at(0));
02459 Label answer;
02460
02461
02462
02463 __ pop(r0);
02464 __ and_(r1, r0, Operand(kSmiTagMask));
02465 __ eor(r1, r1, Operand(kSmiTagMask), SetCC);
02466 __ b(ne, &answer);
02467
02468 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
02469 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
02470
02471 __ cmp(r1, Operand(JS_ARRAY_TYPE));
02472 __ bind(&answer);
02473 cc_reg_ = eq;
02474 }
02475
02476
02477 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
02478 ASSERT(args->length() == 0);
02479
02480
02481
02482 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
02483
02484
02485 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
02486 __ CallStub(&stub);
02487 __ push(r0);
02488 }
02489
02490
02491 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
02492 ASSERT(args->length() == 1);
02493
02494
02495
02496 Load(args->at(0));
02497 __ pop(r1);
02498 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
02499
02500
02501 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
02502 __ CallStub(&stub);
02503 __ push(r0);
02504 }
02505
02506
02507 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
02508 ASSERT(args->length() == 2);
02509
02510
02511 Load(args->at(0));
02512 Load(args->at(1));
02513 __ pop(r0);
02514 __ pop(r1);
02515 __ cmp(r0, Operand(r1));
02516 cc_reg_ = eq;
02517 }
02518
02519
02520 void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
02521 if (CheckForInlineRuntimeCall(node)) return;
02522
02523 ZoneList<Expression*>* args = node->arguments();
02524 Comment cmnt(masm_, "[ CallRuntime");
02525 Runtime::Function* function = node->function();
02526
02527 if (function != NULL) {
02528
02529 for (int i = 0; i < args->length(); i++) Load(args->at(i));
02530
02531
02532 __ CallRuntime(function, args->length());
02533 __ push(r0);
02534
02535 } else {
02536
02537 __ mov(r0, Operand(node->name()));
02538 __ push(r0);
02539
02540 __ ldr(r1, GlobalObject());
02541 __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
02542 __ push(r0);
02543
02544 for (int i = 0; i < args->length(); i++) Load(args->at(i));
02545
02546
02547 Handle<Code> stub = ComputeCallInitialize(args->length());
02548 __ Call(stub, RelocInfo::CODE_TARGET);
02549 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
02550 __ pop();
02551 __ push(r0);
02552 }
02553 }
02554
02555
02556 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
02557 Comment cmnt(masm_, "[ UnaryOperation");
02558
02559 Token::Value op = node->op();
02560
02561 if (op == Token::NOT) {
02562 LoadCondition(node->expression(),
02563 NOT_INSIDE_TYPEOF,
02564 false_target(),
02565 true_target(),
02566 true);
02567 cc_reg_ = NegateCondition(cc_reg_);
02568
02569 } else if (op == Token::DELETE) {
02570 Property* property = node->expression()->AsProperty();
02571 Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
02572 if (property != NULL) {
02573 Load(property->obj());
02574 Load(property->key());
02575 __ mov(r0, Operand(1));
02576 __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
02577
02578 } else if (variable != NULL) {
02579 Slot* slot = variable->slot();
02580 if (variable->is_global()) {
02581 LoadGlobal();
02582 __ mov(r0, Operand(variable->name()));
02583 __ push(r0);
02584 __ mov(r0, Operand(1));
02585 __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
02586
02587 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
02588
02589 __ push(cp);
02590 __ mov(r0, Operand(variable->name()));
02591 __ push(r0);
02592 __ CallRuntime(Runtime::kLookupContext, 2);
02593
02594 __ push(r0);
02595 __ mov(r0, Operand(variable->name()));
02596 __ push(r0);
02597 __ mov(r0, Operand(1));
02598 __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
02599
02600 } else {
02601
02602
02603 __ mov(r0, Operand(Factory::false_value()));
02604 }
02605
02606 } else {
02607
02608 Load(node->expression());
02609 __ pop();
02610 __ mov(r0, Operand(Factory::true_value()));
02611 }
02612 __ push(r0);
02613
02614 } else if (op == Token::TYPEOF) {
02615
02616
02617 LoadTypeofExpression(node->expression());
02618 __ CallRuntime(Runtime::kTypeof, 1);
02619 __ push(r0);
02620
02621 } else {
02622 Load(node->expression());
02623 __ pop(r0);
02624 switch (op) {
02625 case Token::NOT:
02626 case Token::DELETE:
02627 case Token::TYPEOF:
02628 UNREACHABLE();
02629 break;
02630
02631 case Token::SUB: {
02632 UnarySubStub stub;
02633 __ CallStub(&stub);
02634 break;
02635 }
02636
02637 case Token::BIT_NOT: {
02638
02639 Label smi_label;
02640 Label continue_label;
02641 __ tst(r0, Operand(kSmiTagMask));
02642 __ b(eq, &smi_label);
02643
02644 __ push(r0);
02645 __ mov(r0, Operand(0));
02646 __ InvokeBuiltin(Builtins::BIT_NOT, CALL_JS);
02647
02648 __ b(&continue_label);
02649 __ bind(&smi_label);
02650 __ mvn(r0, Operand(r0));
02651 __ bic(r0, r0, Operand(kSmiTagMask));
02652 __ bind(&continue_label);
02653 break;
02654 }
02655
02656 case Token::VOID:
02657
02658
02659 __ mov(r0, Operand(Factory::undefined_value()));
02660 break;
02661
02662 case Token::ADD: {
02663
02664 Label continue_label;
02665 __ tst(r0, Operand(kSmiTagMask));
02666 __ b(eq, &continue_label);
02667 __ push(r0);
02668 __ mov(r0, Operand(0));
02669 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
02670 __ bind(&continue_label);
02671 break;
02672 }
02673 default:
02674 UNREACHABLE();
02675 }
02676 __ push(r0);
02677 }
02678 }
02679
02680
02681 void CodeGenerator::VisitCountOperation(CountOperation* node) {
02682 Comment cmnt(masm_, "[ CountOperation");
02683
02684 bool is_postfix = node->is_postfix();
02685 bool is_increment = node->op() == Token::INC;
02686
02687 Variable* var = node->expression()->AsVariableProxy()->AsVariable();
02688 bool is_const = (var != NULL && var->mode() == Variable::CONST);
02689
02690
02691 if (is_postfix) {
02692 __ mov(r0, Operand(0));
02693 __ push(r0);
02694 }
02695
02696 { Reference target(this, node->expression());
02697 if (target.is_illegal()) return;
02698 target.GetValue(NOT_INSIDE_TYPEOF);
02699 __ pop(r0);
02700
02701 Label slow, exit;
02702
02703
02704 __ mov(r1, Operand(Smi::FromInt(1)));
02705
02706
02707 __ tst(r0, Operand(kSmiTagMask));
02708 __ b(ne, &slow);
02709
02710
02711 if (is_postfix) __ str(r0, MemOperand(sp, target.size() * kPointerSize));
02712
02713
02714 if (is_increment) {
02715 __ add(r0, r0, Operand(r1), SetCC);
02716 } else {
02717 __ sub(r0, r0, Operand(r1), SetCC);
02718 }
02719
02720
02721 __ b(vc, &exit);
02722
02723
02724 if (is_increment) {
02725 __ sub(r0, r0, Operand(r1));
02726 } else {
02727 __ add(r0, r0, Operand(r1));
02728 }
02729
02730
02731 __ bind(&slow);
02732
02733
02734 if (is_postfix) {
02735 InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2);
02736 __ CallStub(&stub);
02737
02738 __ str(r0, MemOperand(sp, target.size() * kPointerSize));
02739 }
02740
02741
02742 if (is_increment) {
02743 InvokeBuiltinStub stub(InvokeBuiltinStub::Inc, 1);
02744 __ CallStub(&stub);
02745 } else {
02746 InvokeBuiltinStub stub(InvokeBuiltinStub::Dec, 1);
02747 __ CallStub(&stub);
02748 }
02749
02750
02751 __ bind(&exit);
02752 __ push(r0);
02753 if (!is_const) target.SetValue(NOT_CONST_INIT);
02754 }
02755
02756
02757 if (is_postfix) __ pop(r0);
02758 }
02759
02760
02761 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
02762 Comment cmnt(masm_, "[ BinaryOperation");
02763 Token::Value op = node->op();
02764
02765
02766
02767
02768
02769
02770
02771
02772
02773
02774
02775
02776
02777 if (op == Token::AND) {
02778 Label is_true;
02779 LoadCondition(node->left(),
02780 NOT_INSIDE_TYPEOF,
02781 &is_true,
02782 false_target(),
02783 false);
02784 if (has_cc()) {
02785 Branch(false, false_target());
02786
02787
02788 __ bind(&is_true);
02789 LoadCondition(node->right(),
02790 NOT_INSIDE_TYPEOF,
02791 true_target(),
02792 false_target(),
02793 false);
02794
02795 } else {
02796 Label pop_and_continue, exit;
02797
02798 __ ldr(r0, MemOperand(sp, 0));
02799 __ push(r0);
02800
02801
02802
02803 ToBoolean(&pop_and_continue, &exit);
02804 Branch(false, &exit);
02805
02806
02807 __ bind(&pop_and_continue);
02808 __ pop(r0);
02809
02810
02811 __ bind(&is_true);
02812 Load(node->right());
02813
02814
02815 __ bind(&exit);
02816 }
02817
02818 } else if (op == Token::OR) {
02819 Label is_false;
02820 LoadCondition(node->left(),
02821 NOT_INSIDE_TYPEOF,
02822 true_target(),
02823 &is_false,
02824 false);
02825 if (has_cc()) {
02826 Branch(true, true_target());
02827
02828
02829 __ bind(&is_false);
02830 LoadCondition(node->right(),
02831 NOT_INSIDE_TYPEOF,
02832 true_target(),
02833 false_target(),
02834 false);
02835
02836 } else {
02837 Label pop_and_continue, exit;
02838
02839 __ ldr(r0, MemOperand(sp, 0));
02840 __ push(r0);
02841
02842
02843
02844 ToBoolean(&exit, &pop_and_continue);
02845 Branch(true, &exit);
02846
02847
02848 __ bind(&pop_and_continue);
02849 __ pop(r0);
02850
02851
02852 __ bind(&is_false);
02853 Load(node->right());
02854
02855
02856 __ bind(&exit);
02857 }
02858
02859 } else {
02860
02861
02862 Literal* lliteral = node->left()->AsLiteral();
02863 Literal* rliteral = node->right()->AsLiteral();
02864
02865 if (rliteral != NULL && rliteral->handle()->IsSmi()) {
02866 Load(node->left());
02867 SmiOperation(node->op(), rliteral->handle(), false);
02868
02869 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) {
02870 Load(node->right());
02871 SmiOperation(node->op(), lliteral->handle(), true);
02872
02873 } else {
02874 Load(node->left());
02875 Load(node->right());
02876 GenericBinaryOperation(node->op());
02877 }
02878 __ push(r0);
02879 }
02880 }
02881
02882
02883 void CodeGenerator::VisitThisFunction(ThisFunction* node) {
02884 __ ldr(r0, FunctionOperand());
02885 __ push(r0);
02886 }
02887
02888
02889 void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
02890 Comment cmnt(masm_, "[ CompareOperation");
02891
02892
02893 Expression* left = node->left();
02894 Expression* right = node->right();
02895 Token::Value op = node->op();
02896
02897
02898
02899
02900
02901
02902 if (op == Token::EQ || op == Token::EQ_STRICT) {
02903 bool left_is_null =
02904 left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
02905 bool right_is_null =
02906 right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
02907
02908 if (left_is_null || right_is_null) {
02909 Load(left_is_null ? right : left);
02910 Label exit, undetectable;
02911 __ pop(r0);
02912 __ cmp(r0, Operand(Factory::null_value()));
02913
02914
02915
02916 if (op != Token::EQ_STRICT) {
02917 __ b(eq, &exit);
02918 __ cmp(r0, Operand(Factory::undefined_value()));
02919
02920
02921 __ b(eq, &exit);
02922 __ tst(r0, Operand(kSmiTagMask));
02923
02924 __ b(ne, &undetectable);
02925 __ b(false_target());
02926
02927 __ bind(&undetectable);
02928 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
02929 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
02930 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
02931 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
02932 }
02933
02934 __ bind(&exit);
02935
02936 cc_reg_ = eq;
02937 return;
02938 }
02939 }
02940
02941
02942
02943
02944
02945
02946 UnaryOperation* operation = left->AsUnaryOperation();
02947 if ((op == Token::EQ || op == Token::EQ_STRICT) &&
02948 (operation != NULL && operation->op() == Token::TYPEOF) &&
02949 (right->AsLiteral() != NULL &&
02950 right->AsLiteral()->handle()->IsString())) {
02951 Handle<String> check(String::cast(*right->AsLiteral()->handle()));
02952
02953
02954 LoadTypeofExpression(operation->expression());
02955 __ pop(r1);
02956
02957 if (check->Equals(Heap::number_symbol())) {
02958 __ tst(r1, Operand(kSmiTagMask));
02959 __ b(eq, true_target());
02960 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
02961 __ cmp(r1, Operand(Factory::heap_number_map()));
02962 cc_reg_ = eq;
02963
02964 } else if (check->Equals(Heap::string_symbol())) {
02965 __ tst(r1, Operand(kSmiTagMask));
02966 __ b(eq, false_target());
02967
02968 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
02969
02970
02971 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
02972 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
02973 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
02974 __ b(eq, false_target());
02975
02976 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset));
02977 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE));
02978 cc_reg_ = lt;
02979
02980 } else if (check->Equals(Heap::boolean_symbol())) {
02981 __ cmp(r1, Operand(Factory::true_value()));
02982 __ b(eq, true_target());
02983 __ cmp(r1, Operand(Factory::false_value()));
02984 cc_reg_ = eq;
02985
02986 } else if (check->Equals(Heap::undefined_symbol())) {
02987 __ cmp(r1, Operand(Factory::undefined_value()));
02988 __ b(eq, true_target());
02989
02990 __ tst(r1, Operand(kSmiTagMask));
02991 __ b(eq, false_target());
02992
02993
02994 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
02995 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
02996 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
02997 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
02998
02999 cc_reg_ = eq;
03000
03001 } else if (check->Equals(Heap::function_symbol())) {
03002 __ tst(r1, Operand(kSmiTagMask));
03003 __ b(eq, false_target());
03004 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
03005 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
03006 __ cmp(r1, Operand(JS_FUNCTION_TYPE));
03007 cc_reg_ = eq;
03008
03009 } else if (check->Equals(Heap::object_symbol())) {
03010 __ tst(r1, Operand(kSmiTagMask));
03011 __ b(eq, false_target());
03012
03013 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
03014 __ cmp(r1, Operand(Factory::null_value()));
03015 __ b(eq, true_target());
03016
03017
03018 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
03019 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
03020 __ cmp(r1, Operand(1 << Map::kIsUndetectable));
03021 __ b(eq, false_target());
03022
03023 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
03024 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
03025 __ b(lt, false_target());
03026 __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE));
03027 cc_reg_ = le;
03028
03029 } else {
03030
03031
03032 __ b(false_target());
03033 }
03034 return;
03035 }
03036
03037 Load(left);
03038 Load(right);
03039 switch (op) {
03040 case Token::EQ:
03041 Comparison(eq, false);
03042 break;
03043
03044 case Token::LT:
03045 Comparison(lt);
03046 break;
03047
03048 case Token::GT:
03049 Comparison(gt);
03050 break;
03051
03052 case Token::LTE:
03053 Comparison(le);
03054 break;
03055
03056 case Token::GTE:
03057 Comparison(ge);
03058 break;
03059
03060 case Token::EQ_STRICT:
03061 Comparison(eq, true);
03062 break;
03063
03064 case Token::IN:
03065 __ mov(r0, Operand(1));
03066 __ InvokeBuiltin(Builtins::IN, CALL_JS);
03067 __ push(r0);
03068 break;
03069
03070 case Token::INSTANCEOF:
03071 __ mov(r0, Operand(1));
03072 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_JS);
03073 __ tst(r0, Operand(r0));
03074 cc_reg_ = eq;
03075 break;
03076
03077 default:
03078 UNREACHABLE();
03079 }
03080 }
03081
03082
03083 void CodeGenerator::RecordStatementPosition(Node* node) {
03084 if (FLAG_debug_info) {
03085 int statement_pos = node->statement_pos();
03086 if (statement_pos == RelocInfo::kNoPosition) return;
03087 __ RecordStatementPosition(statement_pos);
03088 }
03089 }
03090
03091
03092 void CodeGenerator::EnterJSFrame() {
03093 #if defined(DEBUG)
03094 { Label done, fail;
03095 __ tst(r1, Operand(kSmiTagMask));
03096 __ b(eq, &fail);
03097 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
03098 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
03099 __ cmp(r2, Operand(JS_FUNCTION_TYPE));
03100 __ b(eq, &done);
03101 __ bind(&fail);
03102 __ stop("CodeGenerator::EnterJSFrame - r1 not a function");
03103 __ bind(&done);
03104 }
03105 #endif // DEBUG
03106
03107 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
03108 __ add(fp, sp, Operand(2 * kPointerSize));
03109 }
03110
03111
03112 void CodeGenerator::ExitJSFrame() {
03113
03114
03115 __ mov(sp, fp);
03116 __ ldm(ia_w, sp, fp.bit() | lr.bit());
03117 }
03118
03119
03120 #undef __
03121 #define __ masm->
03122
03123 Handle<String> Reference::GetName() {
03124 ASSERT(type_ == NAMED);
03125 Property* property = expression_->AsProperty();
03126 if (property == NULL) {
03127
03128 VariableProxy* proxy = expression_->AsVariableProxy();
03129 ASSERT(proxy->AsVariable() != NULL);
03130 ASSERT(proxy->AsVariable()->is_global());
03131 return proxy->name();
03132 } else {
03133 Literal* raw_name = property->key()->AsLiteral();
03134 ASSERT(raw_name != NULL);
03135 return Handle<String>(String::cast(*raw_name->handle()));
03136 }
03137 }
03138
03139
03140 void Reference::GetValue(TypeofState typeof_state) {
03141 ASSERT(!is_illegal());
03142 ASSERT(!cgen_->has_cc());
03143 MacroAssembler* masm = cgen_->masm();
03144 Property* property = expression_->AsProperty();
03145 if (property != NULL) {
03146 __ RecordPosition(property->position());
03147 }
03148
03149 switch (type_) {
03150 case SLOT: {
03151 Comment cmnt(masm, "[ Load from Slot");
03152 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
03153 ASSERT(slot != NULL);
03154 cgen_->LoadFromSlot(slot, typeof_state);
03155 break;
03156 }
03157
03158 case NAMED: {
03159
03160
03161
03162
03163
03164 Comment cmnt(masm, "[ Load from named Property");
03165
03166 Handle<String> name(GetName());
03167 __ mov(r2, Operand(name));
03168 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
03169
03170 Variable* var = expression_->AsVariableProxy()->AsVariable();
03171 if (var != NULL) {
03172 ASSERT(var->is_global());
03173 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
03174 } else {
03175 __ Call(ic, RelocInfo::CODE_TARGET);
03176 }
03177 __ push(r0);
03178 break;
03179 }
03180
03181 case KEYED: {
03182
03183
03184 Comment cmnt(masm, "[ Load from keyed Property");
03185 ASSERT(property != NULL);
03186
03187 GetPropertyStub stub;
03188 __ CallStub(&stub);
03189 __ push(r0);
03190 break;
03191 }
03192
03193 default:
03194 UNREACHABLE();
03195 }
03196 }
03197
03198
03199 void Reference::SetValue(InitState init_state) {
03200 ASSERT(!is_illegal());
03201 ASSERT(!cgen_->has_cc());
03202 MacroAssembler* masm = cgen_->masm();
03203 Property* property = expression_->AsProperty();
03204 if (property != NULL) {
03205 __ RecordPosition(property->position());
03206 }
03207
03208 switch (type_) {
03209 case SLOT: {
03210 Comment cmnt(masm, "[ Store to Slot");
03211 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
03212 ASSERT(slot != NULL);
03213 if (slot->type() == Slot::LOOKUP) {
03214 ASSERT(slot->var()->mode() == Variable::DYNAMIC);
03215
03216
03217 __ push(cp);
03218 __ mov(r0, Operand(slot->var()->name()));
03219 __ push(r0);
03220
03221 if (init_state == CONST_INIT) {
03222
03223
03224
03225
03226
03227
03228
03229
03230
03231
03232
03233
03234
03235
03236
03237 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
03238 } else {
03239 __ CallRuntime(Runtime::kStoreContextSlot, 3);
03240 }
03241
03242
03243 __ push(r0);
03244
03245 } else {
03246 ASSERT(slot->var()->mode() != Variable::DYNAMIC);
03247
03248 Label exit;
03249 if (init_state == CONST_INIT) {
03250 ASSERT(slot->var()->mode() == Variable::CONST);
03251
03252
03253
03254 Comment cmnt(masm, "[ Init const");
03255 __ ldr(r2, cgen_->SlotOperand(slot, r2));
03256 __ cmp(r2, Operand(Factory::the_hole_value()));
03257 __ b(ne, &exit);
03258 }
03259
03260
03261
03262
03263
03264
03265
03266
03267
03268
03269 __ pop(r0);
03270 __ str(r0, cgen_->SlotOperand(slot, r2));
03271 __ push(r0);
03272 if (slot->type() == Slot::CONTEXT) {
03273
03274 __ tst(r0, Operand(kSmiTagMask));
03275 __ b(eq, &exit);
03276
03277 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
03278 __ mov(r3, Operand(offset));
03279 __ RecordWrite(r2, r3, r1);
03280 }
03281
03282
03283
03284 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) {
03285 __ bind(&exit);
03286 }
03287 }
03288 break;
03289 }
03290
03291 case NAMED: {
03292 Comment cmnt(masm, "[ Store to named Property");
03293
03294 __ pop(r0);
03295
03296 Handle<String> name(GetName());
03297 __ mov(r2, Operand(name));
03298 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
03299 __ Call(ic, RelocInfo::CODE_TARGET);
03300 __ push(r0);
03301 break;
03302 }
03303
03304 case KEYED: {
03305 Comment cmnt(masm, "[ Store to keyed Property");
03306 Property* property = expression_->AsProperty();
03307 ASSERT(property != NULL);
03308 __ RecordPosition(property->position());
03309 __ pop(r0);
03310 SetPropertyStub stub;
03311 __ CallStub(&stub);
03312 __ push(r0);
03313 break;
03314 }
03315
03316 default:
03317 UNREACHABLE();
03318 }
03319 }
03320
03321
03322 void GetPropertyStub::Generate(MacroAssembler* masm) {
03323
03324
03325 Label slow, fast;
03326
03327 __ ldm(ia, sp, r0.bit() | r1.bit());
03328
03329 __ tst(r0, Operand(kSmiTagMask));
03330 __ b(ne, &slow);
03331 __ mov(r0, Operand(r0, ASR, kSmiTagSize));
03332
03333 __ tst(r1, Operand(kSmiTagMask));
03334 __ b(eq, &slow);
03335
03336
03337
03338
03339
03340 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
03341 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
03342 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
03343 __ cmp(r2, Operand(JS_OBJECT_TYPE));
03344 __ b(lt, &slow);
03345
03346
03347 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
03348
03349 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
03350 __ cmp(r3, Operand(Factory::hash_table_map()));
03351 __ b(eq, &slow);
03352
03353 __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
03354 __ cmp(r0, Operand(r3));
03355 __ b(lo, &fast);
03356
03357
03358 __ bind(&slow);
03359 __ ldm(ia, sp, r0.bit() | r1.bit());
03360 __ stm(db_w, sp, r0.bit() | r1.bit());
03361
03362 __ TailCallRuntime(ExternalReference(Runtime::kGetProperty), 2);
03363
03364
03365 __ bind(&fast);
03366 __ add(r3, r1, Operand(Array::kHeaderSize - kHeapObjectTag));
03367 __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
03368 __ cmp(r0, Operand(Factory::the_hole_value()));
03369
03370
03371 __ b(eq, &slow);
03372
03373 __ StubReturn(1);
03374 }
03375
03376
03377 void SetPropertyStub::Generate(MacroAssembler* masm) {
03378
03379
03380
03381
03382 Label slow, fast, array, extra, exit;
03383
03384 __ ldm(ia, sp, r1.bit() | r3.bit());
03385
03386 __ tst(r1, Operand(kSmiTagMask));
03387 __ b(ne, &slow);
03388
03389 __ tst(r3, Operand(kSmiTagMask));
03390 __ b(eq, &slow);
03391
03392 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
03393 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
03394
03395 __ cmp(r2, Operand(JS_ARRAY_TYPE));
03396 __ b(eq, &array);
03397
03398 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
03399 __ b(lt, &slow);
03400
03401
03402
03403 __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset));
03404
03405 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
03406 __ cmp(r2, Operand(Factory::hash_table_map()));
03407 __ b(eq, &slow);
03408
03409 __ mov(r1, Operand(r1, ASR, kSmiTagSize));
03410
03411 __ add(r2, r3, Operand(Array::kHeaderSize - kHeapObjectTag));
03412 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2));
03413 __ ldr(ip, FieldMemOperand(r3, Array::kLengthOffset));
03414 __ cmp(r1, Operand(ip));
03415 __ b(lo, &fast);
03416
03417
03418
03419 __ bind(&slow);
03420 __ ldm(ia, sp, r1.bit() | r3.bit());
03421 __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit());
03422
03423 __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
03424
03425
03426
03427
03428
03429
03430 __ bind(&extra);
03431 __ b(ne, &slow);
03432 __ mov(r1, Operand(r1, ASR, kSmiTagSize));
03433 __ ldr(ip, FieldMemOperand(r2, Array::kLengthOffset));
03434 __ cmp(r1, Operand(ip));
03435 __ b(hs, &slow);
03436 __ mov(r1, Operand(r1, LSL, kSmiTagSize));
03437 __ add(r1, r1, Operand(1 << kSmiTagSize));
03438 __ str(r1, FieldMemOperand(r3, JSArray::kLengthOffset));
03439 __ mov(r3, Operand(r2));
03440
03441
03442 int displacement = Array::kHeaderSize - kHeapObjectTag -
03443 ((1 << kSmiTagSize) * 2);
03444 __ add(r2, r2, Operand(displacement));
03445 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
03446 __ b(&fast);
03447
03448
03449
03450
03451
03452
03453 __ bind(&array);
03454 __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset));
03455 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
03456 __ cmp(r1, Operand(Factory::hash_table_map()));
03457 __ b(eq, &slow);
03458
03459
03460
03461 __ ldr(r1, MemOperand(sp));
03462
03463 __ ldr(ip, FieldMemOperand(r3, JSArray::kLengthOffset));
03464 __ cmp(r1, Operand(ip));
03465 __ b(hs, &extra);
03466 __ mov(r3, Operand(r2));
03467 __ add(r2, r2, Operand(Array::kHeaderSize - kHeapObjectTag));
03468 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
03469
03470
03471
03472
03473 __ bind(&fast);
03474 __ str(r0, MemOperand(r2));
03475
03476 __ tst(r0, Operand(kSmiTagMask));
03477 __ b(eq, &exit);
03478
03479 __ sub(r1, r2, Operand(r3));
03480 __ RecordWrite(r3, r1, r2);
03481 __ bind(&exit);
03482 __ StubReturn(1);
03483 }
03484
03485
03486 void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
03487
03488
03489
03490
03491 switch (op_) {
03492 case Token::ADD: {
03493 Label slow, exit;
03494
03495 __ orr(r2, r1, Operand(r0));
03496 __ add(r0, r1, Operand(r0), SetCC);
03497
03498 __ b(vs, &slow);
03499
03500 ASSERT(kSmiTag == 0);
03501 __ tst(r2, Operand(kSmiTagMask));
03502 __ b(eq, &exit);
03503
03504 __ bind(&slow);
03505 __ sub(r0, r0, Operand(r1));
03506 __ push(r1);
03507 __ push(r0);
03508 __ mov(r0, Operand(1));
03509 __ InvokeBuiltin(Builtins::ADD, JUMP_JS);
03510
03511 __ bind(&exit);
03512 break;
03513 }
03514
03515 case Token::SUB: {
03516 Label slow, exit;
03517
03518 __ orr(r2, r1, Operand(r0));
03519 __ sub(r3, r1, Operand(r0), SetCC);
03520
03521 __ b(vs, &slow);
03522
03523 ASSERT(kSmiTag == 0);
03524 __ tst(r2, Operand(kSmiTagMask));
03525 __ mov(r0, Operand(r3), LeaveCC, eq);
03526 __ b(eq, &exit);
03527
03528 __ bind(&slow);
03529 __ push(r1);
03530 __ push(r0);
03531 __ mov(r0, Operand(1));
03532 __ InvokeBuiltin(Builtins::SUB, JUMP_JS);
03533
03534 __ bind(&exit);
03535 break;
03536 }
03537
03538 case Token::MUL: {
03539 Label slow, exit;
03540
03541 __ orr(r2, r1, Operand(r0));
03542 ASSERT(kSmiTag == 0);
03543 __ tst(r2, Operand(kSmiTagMask));
03544 __ b(ne, &slow);
03545
03546 __ mov(ip, Operand(r0, ASR, kSmiTagSize));
03547
03548 __ smull(r3, r2, r1, ip);
03549
03550 __ mov(ip, Operand(r3, ASR, 31));
03551 __ cmp(ip, Operand(r2));
03552 __ b(ne, &slow);
03553
03554 __ tst(r3, Operand(r3));
03555 __ mov(r0, Operand(r3), LeaveCC, ne);
03556 __ b(ne, &exit);
03557
03558 __ bind(&slow);
03559 __ push(r1);
03560 __ push(r0);
03561 __ mov(r0, Operand(1));
03562 __ InvokeBuiltin(Builtins::MUL, JUMP_JS);
03563
03564 __ bind(&exit);
03565 break;
03566 }
03567
03568 case Token::BIT_OR:
03569 case Token::BIT_AND:
03570 case Token::BIT_XOR: {
03571 Label slow, exit;
03572
03573 __ orr(r2, r1, Operand(r0));
03574 ASSERT(kSmiTag == 0);
03575 __ tst(r2, Operand(kSmiTagMask));
03576 __ b(ne, &slow);
03577 switch (op_) {
03578 case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break;
03579 case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break;
03580 case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break;
03581 default: UNREACHABLE();
03582 }
03583 __ b(&exit);
03584 __ bind(&slow);
03585 __ push(r1);
03586 __ push(r0);
03587 __ mov(r0, Operand(1));
03588 switch (op_) {
03589 case Token::BIT_OR:
03590 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_JS);
03591 break;
03592 case Token::BIT_AND:
03593 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_JS);
03594 break;
03595 case Token::BIT_XOR:
03596 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_JS);
03597 break;
03598 default:
03599 UNREACHABLE();
03600 }
03601 __ bind(&exit);
03602 break;
03603 }
03604
03605 case Token::SHL:
03606 case Token::SHR:
03607 case Token::SAR: {
03608 Label slow, exit;
03609
03610 __ orr(r2, r1, Operand(r0));
03611 ASSERT(kSmiTag == 0);
03612 __ tst(r2, Operand(kSmiTagMask));
03613 __ b(ne, &slow);
03614
03615 __ mov(r3, Operand(r1, ASR, kSmiTagSize));
03616 __ mov(r2, Operand(r0, ASR, kSmiTagSize));
03617
03618 __ and_(r2, r2, Operand(0x1f));
03619
03620 switch (op_) {
03621 case Token::SAR:
03622 __ mov(r3, Operand(r3, ASR, r2));
03623
03624 break;
03625
03626 case Token::SHR:
03627 __ mov(r3, Operand(r3, LSR, r2));
03628
03629
03630
03631
03632
03633
03634 __ and_(r2, r3, Operand(0xc0000000), SetCC);
03635 __ b(ne, &slow);
03636 break;
03637
03638 case Token::SHL:
03639 __ mov(r3, Operand(r3, LSL, r2));
03640
03641 __ add(r2, r3, Operand(0x40000000), SetCC);
03642 __ b(mi, &slow);
03643 break;
03644
03645 default: UNREACHABLE();
03646 }
03647
03648 ASSERT(kSmiTag == 0);
03649 __ mov(r0, Operand(r3, LSL, kSmiTagSize));
03650 __ b(&exit);
03651
03652 __ bind(&slow);
03653 __ push(r1);
03654 __ push(r0);
03655 __ mov(r0, Operand(1));
03656 switch (op_) {
03657 case Token::SAR: __ InvokeBuiltin(Builtins::SAR, JUMP_JS); break;
03658 case Token::SHR: __ InvokeBuiltin(Builtins::SHR, JUMP_JS); break;
03659 case Token::SHL: __ InvokeBuiltin(Builtins::SHL, JUMP_JS); break;
03660 default: UNREACHABLE();
03661 }
03662 __ bind(&exit);
03663 break;
03664 }
03665
03666 default: UNREACHABLE();
03667 }
03668 __ Ret();
03669 }
03670
03671
03672 void StackCheckStub::Generate(MacroAssembler* masm) {
03673 Label within_limit;
03674 __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit()));
03675 __ ldr(ip, MemOperand(ip));
03676 __ cmp(sp, Operand(ip));
03677 __ b(hs, &within_limit);
03678
03679 __ push(r0);
03680 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
03681 __ bind(&within_limit);
03682
03683 __ StubReturn(1);
03684 }
03685
03686
03687 void UnarySubStub::Generate(MacroAssembler* masm) {
03688 Label undo;
03689 Label slow;
03690 Label done;
03691
03692
03693 __ tst(r0, Operand(kSmiTagMask));
03694 __ b(ne, &slow);
03695
03696
03697
03698 __ cmp(r0, Operand(0));
03699 __ b(eq, &slow);
03700
03701
03702
03703 __ rsb(r1, r0, Operand(0), SetCC);
03704 __ b(vs, &slow);
03705
03706
03707 __ tst(r1, Operand(kSmiTagMask));
03708 __ mov(r0, Operand(r1), LeaveCC, eq);
03709 __ b(eq, &done);
03710
03711
03712 __ bind(&slow);
03713 __ push(r0);
03714 __ mov(r0, Operand(0));
03715 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS);
03716
03717 __ bind(&done);
03718 __ StubReturn(1);
03719 }
03720
03721
03722 void InvokeBuiltinStub::Generate(MacroAssembler* masm) {
03723 __ push(r0);
03724 __ mov(r0, Operand(0));
03725 switch (kind_) {
03726 case ToNumber: __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_JS); break;
03727 case Inc: __ InvokeBuiltin(Builtins::INC, JUMP_JS); break;
03728 case Dec: __ InvokeBuiltin(Builtins::DEC, JUMP_JS); break;
03729 default: UNREACHABLE();
03730 }
03731 __ StubReturn(argc_);
03732 }
03733
03734
03735 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
03736
03737 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize);
03738 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
03739 __ ldr(sp, MemOperand(r3));
03740 __ pop(r2);
03741 __ str(r2, MemOperand(r3));
03742
03743 __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
03744
03745
03746 __ cmp(fp, Operand(0));
03747
03748 __ mov(cp, Operand(0), LeaveCC, eq);
03749
03750 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
03751 if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
03752 __ pop(pc);
03753 }
03754
03755
03756 void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
03757
03758 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
03759 __ ldr(r3, MemOperand(r3));
03760
03761
03762 Label loop, done;
03763 __ bind(&loop);
03764
03765 const int kStateOffset = StackHandlerConstants::kAddressDisplacement +
03766 StackHandlerConstants::kStateOffset;
03767 __ ldr(r2, MemOperand(r3, kStateOffset));
03768 __ cmp(r2, Operand(StackHandler::ENTRY));
03769 __ b(eq, &done);
03770
03771 const int kNextOffset = StackHandlerConstants::kAddressDisplacement +
03772 StackHandlerConstants::kNextOffset;
03773 __ ldr(r3, MemOperand(r3, kNextOffset));
03774 __ jmp(&loop);
03775 __ bind(&done);
03776
03777
03778 __ ldr(r0, MemOperand(r3, kNextOffset));
03779 __ mov(r2, Operand(ExternalReference(Top::k_handler_address)));
03780 __ str(r0, MemOperand(r2));
03781
03782
03783 __ mov(r0, Operand(false));
03784 ExternalReference external_caught(Top::k_external_caught_exception_address);
03785 __ mov(r2, Operand(external_caught));
03786 __ str(r0, MemOperand(r2));
03787
03788
03789 Failure* out_of_memory = Failure::OutOfMemoryException();
03790 __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
03791 __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
03792 __ str(r0, MemOperand(r2));
03793
03794
03795 __ mov(sp, Operand(r3));
03796
03797
03798 __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
03799
03800
03801 __ cmp(fp, Operand(0));
03802
03803 __ mov(cp, Operand(0), LeaveCC, eq);
03804
03805 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
03806 if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
03807 __ pop(pc);
03808 }
03809
03810
03811 void CEntryStub::GenerateCore(MacroAssembler* masm,
03812 Label* throw_normal_exception,
03813 Label* throw_out_of_memory_exception,
03814 StackFrame::Type frame_type,
03815 bool do_gc,
03816 bool always_allocate) {
03817
03818
03819
03820
03821
03822 if (do_gc) {
03823
03824 __ Call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY);
03825 }
03826
03827 ExternalReference scope_depth =
03828 ExternalReference::heap_always_allocate_scope_depth();
03829 if (always_allocate) {
03830 __ mov(r0, Operand(scope_depth));
03831 __ ldr(r1, MemOperand(r0));
03832 __ add(r1, r1, Operand(1));
03833 __ str(r1, MemOperand(r0));
03834 }
03835
03836
03837
03838 __ mov(r0, Operand(r4));
03839 __ mov(r1, Operand(r6));
03840
03841
03842
03843
03844
03845
03846
03847
03848 __ add(lr, pc, Operand(4));
03849 __ push(lr);
03850 #if !defined(__arm__)
03851
03852 __ swi(assembler::arm::call_rt_r5);
03853 #else
03854 __ mov(pc, Operand(r5));
03855 #endif
03856
03857 if (always_allocate) {
03858
03859
03860 __ mov(r2, Operand(scope_depth));
03861 __ ldr(r3, MemOperand(r2));
03862 __ sub(r3, r3, Operand(1));
03863 __ str(r3, MemOperand(r2));
03864 }
03865
03866
03867 Label failure_returned;
03868 ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
03869
03870 __ add(r2, r0, Operand(1));
03871 __ tst(r2, Operand(kFailureTagMask));
03872 __ b(eq, &failure_returned);
03873
03874
03875
03876
03877
03878
03879 __ LeaveExitFrame(frame_type);
03880
03881
03882 Label retry;
03883 __ bind(&failure_returned);
03884 ASSERT(Failure::RETRY_AFTER_GC == 0);
03885 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
03886 __ b(eq, &retry);
03887
03888 Label continue_exception;
03889
03890 __ cmp(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
03891 __ b(ne, &continue_exception);
03892
03893
03894 __ mov(ip, Operand(Factory::the_hole_value().location()));
03895 __ ldr(r3, MemOperand(ip));
03896 __ mov(ip, Operand(Top::pending_exception_address()));
03897 __ ldr(r0, MemOperand(ip));
03898 __ str(r3, MemOperand(ip));
03899
03900 __ bind(&continue_exception);
03901
03902 Failure* out_of_memory = Failure::OutOfMemoryException();
03903 __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
03904 __ b(eq, throw_out_of_memory_exception);
03905
03906
03907 __ jmp(throw_normal_exception);
03908
03909 __ bind(&retry);
03910 }
03911
03912
03913 void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
03914
03915
03916
03917
03918
03919
03920
03921
03922
03923
03924
03925
03926
03927 StackFrame::Type frame_type = is_debug_break
03928 ? StackFrame::EXIT_DEBUG
03929 : StackFrame::EXIT;
03930
03931
03932 __ EnterExitFrame(frame_type);
03933
03934
03935
03936
03937
03938 Label throw_out_of_memory_exception;
03939 Label throw_normal_exception;
03940
03941
03942
03943 if (FLAG_gc_greedy) {
03944 Failure* failure = Failure::RetryAfterGC(0);
03945 __ mov(r0, Operand(reinterpret_cast<intptr_t>(failure)));
03946 }
03947 GenerateCore(masm, &throw_normal_exception,
03948 &throw_out_of_memory_exception,
03949 frame_type,
03950 FLAG_gc_greedy,
03951 false);
03952
03953
03954 GenerateCore(masm,
03955 &throw_normal_exception,
03956 &throw_out_of_memory_exception,
03957 frame_type,
03958 true,
03959 false);
03960
03961
03962 Failure* failure = Failure::InternalError();
03963 __ mov(r0, Operand(reinterpret_cast<int32_t>(failure)));
03964 GenerateCore(masm,
03965 &throw_normal_exception,
03966 &throw_out_of_memory_exception,
03967 frame_type,
03968 true,
03969 true);
03970
03971 __ bind(&throw_out_of_memory_exception);
03972 GenerateThrowOutOfMemory(masm);
03973
03974
03975 __ bind(&throw_normal_exception);
03976 GenerateThrowTOS(masm);
03977 }
03978
03979
03980 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
03981
03982
03983
03984
03985
03986
03987 Label invoke, exit;
03988
03989
03990
03991
03992 __ stm(db_w, sp, kCalleeSaved | lr.bit());
03993
03994
03995
03996
03997
03998
03999 __ add(r4, sp, Operand((kNumCalleeSaved + 1)*kPointerSize));
04000 __ ldr(r4, MemOperand(r4));
04001
04002
04003
04004
04005
04006
04007
04008 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
04009 __ mov(r8, Operand(-1));
04010 __ mov(r7, Operand(~ArgumentsAdaptorFrame::SENTINEL));
04011 __ mov(r6, Operand(Smi::FromInt(marker)));
04012 __ mov(r5, Operand(ExternalReference(Top::k_c_entry_fp_address)));
04013 __ ldr(r5, MemOperand(r5));
04014 __ stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | r8.bit());
04015
04016
04017 __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
04018
04019
04020 __ bl(&invoke);
04021
04022
04023
04024
04025
04026 __ mov(ip, Operand(Top::pending_exception_address()));
04027 __ str(r0, MemOperand(ip));
04028 __ mov(r0, Operand(Handle<Failure>(Failure::Exception())));
04029 __ b(&exit);
04030
04031
04032 __ bind(&invoke);
04033
04034 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
04035
04036
04037
04038
04039
04040
04041 __ mov(ip, Operand(ExternalReference::the_hole_value_location()));
04042 __ ldr(r5, MemOperand(ip));
04043 __ mov(ip, Operand(Top::pending_exception_address()));
04044 __ str(r5, MemOperand(ip));
04045
04046
04047
04048
04049
04050
04051
04052
04053
04054
04055
04056 if (is_construct) {
04057 ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
04058 __ mov(ip, Operand(construct_entry));
04059 } else {
04060 ExternalReference entry(Builtins::JSEntryTrampoline);
04061 __ mov(ip, Operand(entry));
04062 }
04063 __ ldr(ip, MemOperand(ip));
04064
04065
04066 __ mov(lr, Operand(pc));
04067 __ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
04068
04069
04070
04071
04072
04073 __ ldr(r3, MemOperand(sp, StackHandlerConstants::kNextOffset));
04074 __ mov(ip, Operand(ExternalReference(Top::k_handler_address)));
04075 __ str(r3, MemOperand(ip));
04076
04077 __ add(sp, sp, Operand(StackHandlerConstants::kSize));
04078
04079 __ bind(&exit);
04080
04081 __ pop(r3);
04082 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
04083 __ str(r3, MemOperand(ip));
04084
04085
04086 __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
04087
04088
04089 #ifdef DEBUG
04090 if (FLAG_debug_code) __ mov(lr, Operand(pc));
04091 #endif
04092 __ ldm(ia_w, sp, kCalleeSaved | pc.bit());
04093 }
04094
04095
04096 void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
04097
04098 Label adaptor;
04099 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
04100 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
04101 __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
04102 __ b(eq, &adaptor);
04103
04104
04105
04106 __ mov(pc, lr);
04107
04108
04109
04110 __ bind(&adaptor);
04111 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
04112 __ mov(pc, lr);
04113 }
04114
04115
04116 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
04117
04118
04119 static const int kDisplacement =
04120 StandardFrameConstants::kCallerSPOffset - kPointerSize;
04121
04122
04123 Label slow;
04124 __ tst(r1, Operand(kSmiTagMask));
04125 __ b(ne, &slow);
04126
04127
04128 Label adaptor;
04129 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
04130 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
04131 __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
04132 __ b(eq, &adaptor);
04133
04134
04135
04136
04137 __ cmp(r1, r0);
04138 __ b(cs, &slow);
04139
04140
04141 __ sub(r3, r0, r1);
04142 __ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
04143 __ ldr(r0, MemOperand(r3, kDisplacement));
04144 __ mov(pc, lr);
04145
04146
04147
04148
04149 __ bind(&adaptor);
04150 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
04151 __ cmp(r1, r0);
04152 __ b(cs, &slow);
04153
04154
04155 __ sub(r3, r0, r1);
04156 __ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
04157 __ ldr(r0, MemOperand(r3, kDisplacement));
04158 __ mov(pc, lr);
04159
04160
04161
04162 __ bind(&slow);
04163 __ push(r1);
04164 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
04165 }
04166
04167
04168 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
04169
04170 Label runtime;
04171 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
04172 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
04173 __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
04174 __ b(ne, &runtime);
04175
04176
04177 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
04178 __ str(r0, MemOperand(sp, 0 * kPointerSize));
04179 __ add(r3, r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
04180 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
04181 __ str(r3, MemOperand(sp, 1 * kPointerSize));
04182
04183
04184 __ bind(&runtime);
04185 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3);
04186 }
04187
04188
04189 void CallFunctionStub::Generate(MacroAssembler* masm) {
04190 Label slow;
04191
04192
04193 __ ldr(r1, MemOperand(sp, (argc_ + 1) * kPointerSize));
04194
04195
04196
04197 __ tst(r1, Operand(kSmiTagMask));
04198 __ b(eq, &slow);
04199
04200 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
04201 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
04202 __ cmp(r2, Operand(JS_FUNCTION_TYPE));
04203 __ b(ne, &slow);
04204
04205
04206
04207 ParameterCount actual(argc_);
04208 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
04209
04210
04211 __ bind(&slow);
04212 __ mov(r0, Operand(argc_));
04213 __ InvokeBuiltin(Builtins::CALL_NON_FUNCTION, JUMP_JS);
04214 }
04215
04216
04217 #undef __
04218
04219 } }