| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 typeof_state_(NOT_INSIDE_TYPEOF), | 57 typeof_state_(NOT_INSIDE_TYPEOF), |
| 58 true_target_(NULL), | 58 true_target_(NULL), |
| 59 false_target_(NULL), | 59 false_target_(NULL), |
| 60 previous_(NULL) { | 60 previous_(NULL) { |
| 61 owner_->set_state(this); | 61 owner_->set_state(this); |
| 62 } | 62 } |
| 63 | 63 |
| 64 | 64 |
| 65 CodeGenState::CodeGenState(CodeGenerator* owner, | 65 CodeGenState::CodeGenState(CodeGenerator* owner, |
| 66 TypeofState typeof_state, | 66 TypeofState typeof_state, |
| 67 Label* true_target, | 67 JumpTarget* true_target, |
| 68 Label* false_target) | 68 JumpTarget* false_target) |
| 69 : owner_(owner), | 69 : owner_(owner), |
| 70 typeof_state_(typeof_state), | 70 typeof_state_(typeof_state), |
| 71 true_target_(true_target), | 71 true_target_(true_target), |
| 72 false_target_(false_target), | 72 false_target_(false_target), |
| 73 previous_(owner->state()) { | 73 previous_(owner->state()) { |
| 74 owner_->set_state(this); | 74 owner_->set_state(this); |
| 75 } | 75 } |
| 76 | 76 |
| 77 | 77 |
| 78 CodeGenState::~CodeGenState() { | 78 CodeGenState::~CodeGenState() { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 109 void CodeGenerator::GenCode(FunctionLiteral* fun) { | 109 void CodeGenerator::GenCode(FunctionLiteral* fun) { |
| 110 ZoneList<Statement*>* body = fun->body(); | 110 ZoneList<Statement*>* body = fun->body(); |
| 111 | 111 |
| 112 // Initialize state. | 112 // Initialize state. |
| 113 ASSERT(scope_ == NULL); | 113 ASSERT(scope_ == NULL); |
| 114 scope_ = fun->scope(); | 114 scope_ = fun->scope(); |
| 115 ASSERT(frame_ == NULL); | 115 ASSERT(frame_ == NULL); |
| 116 VirtualFrame virtual_frame(this); | 116 VirtualFrame virtual_frame(this); |
| 117 frame_ = &virtual_frame; | 117 frame_ = &virtual_frame; |
| 118 cc_reg_ = al; | 118 cc_reg_ = al; |
| 119 function_return_.set_code_generator(this); |
| 119 { | 120 { |
| 120 CodeGenState state(this); | 121 CodeGenState state(this); |
| 121 | 122 |
| 122 // Entry | 123 // Entry |
| 123 // stack: function, receiver, arguments, return address | 124 // stack: function, receiver, arguments, return address |
| 124 // r0: number of arguments | 125 // r0: number of arguments |
| 125 // sp: stack pointer | 126 // sp: stack pointer |
| 126 // fp: frame pointer | 127 // fp: frame pointer |
| 127 // pp: caller's parameter pointer | 128 // pp: caller's parameter pointer |
| 128 // cp: callee's context | 129 // cp: callee's context |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 } | 266 } |
| 266 | 267 |
| 267 // exit | 268 // exit |
| 268 // r0: result | 269 // r0: result |
| 269 // sp: stack pointer | 270 // sp: stack pointer |
| 270 // fp: frame pointer | 271 // fp: frame pointer |
| 271 // pp: parameter pointer | 272 // pp: parameter pointer |
| 272 // cp: callee's context | 273 // cp: callee's context |
| 273 __ mov(r0, Operand(Factory::undefined_value())); | 274 __ mov(r0, Operand(Factory::undefined_value())); |
| 274 | 275 |
| 275 __ bind(&function_return_); | 276 function_return_.Bind(); |
| 276 if (FLAG_trace) { | 277 if (FLAG_trace) { |
| 277 // Push the return value on the stack as the parameter. | 278 // Push the return value on the stack as the parameter. |
| 278 // Runtime::TraceExit returns the parameter as it is. | 279 // Runtime::TraceExit returns the parameter as it is. |
| 279 __ push(r0); | 280 __ push(r0); |
| 280 __ CallRuntime(Runtime::kTraceExit, 1); | 281 __ CallRuntime(Runtime::kTraceExit, 1); |
| 281 } | 282 } |
| 282 | 283 |
| 283 // Tear down the frame which will restore the caller's frame pointer and the | 284 // Tear down the frame which will restore the caller's frame pointer and the |
| 284 // link register. | 285 // link register. |
| 285 ExitJSFrame(); | 286 ExitJSFrame(); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 } | 346 } |
| 346 } | 347 } |
| 347 | 348 |
| 348 | 349 |
| 349 // Loads a value on the stack. If it is a boolean value, the result may have | 350 // Loads a value on the stack. If it is a boolean value, the result may have |
| 350 // been (partially) translated into branches, or it may have set the condition | 351 // been (partially) translated into branches, or it may have set the condition |
| 351 // code register. If force_cc is set, the value is forced to set the condition | 352 // code register. If force_cc is set, the value is forced to set the condition |
| 352 // code register and no value is pushed. If the condition code register was set, | 353 // code register and no value is pushed. If the condition code register was set, |
| 353 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. | 354 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. |
| 354 void CodeGenerator::LoadCondition(Expression* x, | 355 void CodeGenerator::LoadCondition(Expression* x, |
| 355 TypeofState typeof_state, | 356 TypeofState typeof_state, |
| 356 Label* true_target, | 357 JumpTarget* true_target, |
| 357 Label* false_target, | 358 JumpTarget* false_target, |
| 358 bool force_cc) { | 359 bool force_cc) { |
| 359 ASSERT(!has_cc()); | 360 ASSERT(!has_cc()); |
| 360 | 361 |
| 361 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 362 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| 362 Visit(x); | 363 Visit(x); |
| 363 } | 364 } |
| 364 if (force_cc && !has_cc()) { | 365 if (force_cc && !has_cc()) { |
| 365 // Convert the TOS value to a boolean in the condition code register. | 366 // Convert the TOS value to a boolean in the condition code register. |
| 366 ToBoolean(true_target, false_target); | 367 ToBoolean(true_target, false_target); |
| 367 } | 368 } |
| 368 ASSERT(has_cc() || !force_cc); | 369 ASSERT(has_cc() || !force_cc); |
| 369 } | 370 } |
| 370 | 371 |
| 371 | 372 |
| 372 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 373 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 373 Label true_target; | 374 JumpTarget true_target(this); |
| 374 Label false_target; | 375 JumpTarget false_target(this); |
| 375 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 376 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 376 | 377 |
| 377 if (has_cc()) { | 378 if (has_cc()) { |
| 378 // convert cc_reg_ into a bool | 379 // convert cc_reg_ into a bool |
| 379 Label loaded, materialize_true; | 380 Label loaded, materialize_true; |
| 380 __ b(cc_reg_, &materialize_true); | 381 __ b(cc_reg_, &materialize_true); |
| 381 __ mov(r0, Operand(Factory::false_value())); | 382 __ mov(r0, Operand(Factory::false_value())); |
| 382 __ push(r0); | 383 __ push(r0); |
| 383 __ b(&loaded); | 384 __ b(&loaded); |
| 384 __ bind(&materialize_true); | 385 __ bind(&materialize_true); |
| 385 __ mov(r0, Operand(Factory::true_value())); | 386 __ mov(r0, Operand(Factory::true_value())); |
| 386 __ push(r0); | 387 __ push(r0); |
| 387 __ bind(&loaded); | 388 __ bind(&loaded); |
| 388 cc_reg_ = al; | 389 cc_reg_ = al; |
| 389 } | 390 } |
| 390 | 391 |
| 391 if (true_target.is_linked() || false_target.is_linked()) { | 392 if (true_target.is_linked() || false_target.is_linked()) { |
| 392 // we have at least one condition value | 393 // we have at least one condition value |
| 393 // that has been "translated" into a branch, | 394 // that has been "translated" into a branch, |
| 394 // thus it needs to be loaded explicitly again | 395 // thus it needs to be loaded explicitly again |
| 395 Label loaded; | 396 Label loaded; |
| 396 __ b(&loaded); // don't lose current TOS | 397 __ b(&loaded); // don't lose current TOS |
| 397 bool both = true_target.is_linked() && false_target.is_linked(); | 398 bool both = true_target.is_linked() && false_target.is_linked(); |
| 398 // reincarnate "true", if necessary | 399 // reincarnate "true", if necessary |
| 399 if (true_target.is_linked()) { | 400 if (true_target.is_linked()) { |
| 400 __ bind(&true_target); | 401 true_target.Bind(); |
| 401 __ mov(r0, Operand(Factory::true_value())); | 402 __ mov(r0, Operand(Factory::true_value())); |
| 402 __ push(r0); | 403 __ push(r0); |
| 403 } | 404 } |
| 404 // if both "true" and "false" need to be reincarnated, | 405 // if both "true" and "false" need to be reincarnated, |
| 405 // jump across code for "false" | 406 // jump across code for "false" |
| 406 if (both) | 407 if (both) |
| 407 __ b(&loaded); | 408 __ b(&loaded); |
| 408 // reincarnate "false", if necessary | 409 // reincarnate "false", if necessary |
| 409 if (false_target.is_linked()) { | 410 if (false_target.is_linked()) { |
| 410 __ bind(&false_target); | 411 false_target.Bind(); |
| 411 __ mov(r0, Operand(Factory::false_value())); | 412 __ mov(r0, Operand(Factory::false_value())); |
| 412 __ push(r0); | 413 __ push(r0); |
| 413 } | 414 } |
| 414 // everything is loaded at this point | 415 // everything is loaded at this point |
| 415 __ bind(&loaded); | 416 __ bind(&loaded); |
| 416 } | 417 } |
| 417 ASSERT(!has_cc()); | 418 ASSERT(!has_cc()); |
| 418 } | 419 } |
| 419 | 420 |
| 420 | 421 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 __ pop(r0); | 517 __ pop(r0); |
| 517 __ add(sp, sp, Operand(size * kPointerSize)); | 518 __ add(sp, sp, Operand(size * kPointerSize)); |
| 518 __ push(r0); | 519 __ push(r0); |
| 519 } | 520 } |
| 520 } | 521 } |
| 521 | 522 |
| 522 | 523 |
| 523 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given | 524 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given |
| 524 // register to a boolean in the condition code register. The code | 525 // register to a boolean in the condition code register. The code |
| 525 // may jump to 'false_target' in case the register converts to 'false'. | 526 // may jump to 'false_target' in case the register converts to 'false'. |
| 526 void CodeGenerator::ToBoolean(Label* true_target, | 527 void CodeGenerator::ToBoolean(JumpTarget* true_target, |
| 527 Label* false_target) { | 528 JumpTarget* false_target) { |
| 528 // Note: The generated code snippet does not change stack variables. | 529 // Note: The generated code snippet does not change stack variables. |
| 529 // Only the condition code should be set. | 530 // Only the condition code should be set. |
| 530 __ pop(r0); | 531 __ pop(r0); |
| 531 | 532 |
| 532 // Fast case checks | 533 // Fast case checks |
| 533 | 534 |
| 534 // Check if the value is 'false'. | 535 // Check if the value is 'false'. |
| 535 __ cmp(r0, Operand(Factory::false_value())); | 536 __ cmp(r0, Operand(Factory::false_value())); |
| 536 __ b(eq, false_target); | 537 false_target->Branch(eq); |
| 537 | 538 |
| 538 // Check if the value is 'true'. | 539 // Check if the value is 'true'. |
| 539 __ cmp(r0, Operand(Factory::true_value())); | 540 __ cmp(r0, Operand(Factory::true_value())); |
| 540 __ b(eq, true_target); | 541 true_target->Branch(eq); |
| 541 | 542 |
| 542 // Check if the value is 'undefined'. | 543 // Check if the value is 'undefined'. |
| 543 __ cmp(r0, Operand(Factory::undefined_value())); | 544 __ cmp(r0, Operand(Factory::undefined_value())); |
| 544 __ b(eq, false_target); | 545 false_target->Branch(eq); |
| 545 | 546 |
| 546 // Check if the value is a smi. | 547 // Check if the value is a smi. |
| 547 __ cmp(r0, Operand(Smi::FromInt(0))); | 548 __ cmp(r0, Operand(Smi::FromInt(0))); |
| 548 __ b(eq, false_target); | 549 false_target->Branch(eq); |
| 549 __ tst(r0, Operand(kSmiTagMask)); | 550 __ tst(r0, Operand(kSmiTagMask)); |
| 550 __ b(eq, true_target); | 551 true_target->Branch(eq); |
| 551 | 552 |
| 552 // Slow case: call the runtime. | 553 // Slow case: call the runtime. |
| 553 __ push(r0); | 554 __ push(r0); |
| 554 __ CallRuntime(Runtime::kToBool, 1); | 555 __ CallRuntime(Runtime::kToBool, 1); |
| 555 | 556 |
| 556 // Convert result (r0) to condition code | 557 // Convert result (r0) to condition code |
| 557 __ cmp(r0, Operand(Factory::false_value())); | 558 __ cmp(r0, Operand(Factory::false_value())); |
| 558 | 559 |
| 559 cc_reg_ = ne; | 560 cc_reg_ = ne; |
| 560 } | 561 } |
| (...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 992 // Use the shared code stub to call the function. | 993 // Use the shared code stub to call the function. |
| 993 CallFunctionStub call_function(args->length()); | 994 CallFunctionStub call_function(args->length()); |
| 994 __ CallStub(&call_function); | 995 __ CallStub(&call_function); |
| 995 | 996 |
| 996 // Restore context and pop function from the stack. | 997 // Restore context and pop function from the stack. |
| 997 __ ldr(cp, frame_->Context()); | 998 __ ldr(cp, frame_->Context()); |
| 998 __ pop(); // discard the TOS | 999 __ pop(); // discard the TOS |
| 999 } | 1000 } |
| 1000 | 1001 |
| 1001 | 1002 |
| 1002 void CodeGenerator::Branch(bool if_true, Label* L) { | 1003 void CodeGenerator::Branch(bool if_true, JumpTarget* target) { |
| 1003 ASSERT(has_cc()); | 1004 ASSERT(has_cc()); |
| 1004 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); | 1005 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); |
| 1005 __ b(cc, L); | 1006 target->Branch(cc); |
| 1006 cc_reg_ = al; | 1007 cc_reg_ = al; |
| 1007 } | 1008 } |
| 1008 | 1009 |
| 1009 | 1010 |
| 1010 void CodeGenerator::CheckStack() { | 1011 void CodeGenerator::CheckStack() { |
| 1011 if (FLAG_check_stack) { | 1012 if (FLAG_check_stack) { |
| 1012 Comment cmnt(masm_, "[ check stack"); | 1013 Comment cmnt(masm_, "[ check stack"); |
| 1013 StackCheckStub stub; | 1014 StackCheckStub stub; |
| 1014 __ CallStub(&stub); | 1015 __ CallStub(&stub); |
| 1015 } | 1016 } |
| 1016 } | 1017 } |
| 1017 | 1018 |
| 1018 | 1019 |
| 1019 void CodeGenerator::VisitBlock(Block* node) { | 1020 void CodeGenerator::VisitBlock(Block* node) { |
| 1020 Comment cmnt(masm_, "[ Block"); | 1021 Comment cmnt(masm_, "[ Block"); |
| 1021 if (FLAG_debug_info) RecordStatementPosition(node); | 1022 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1022 node->set_break_stack_height(break_stack_height_); | 1023 node->set_break_stack_height(break_stack_height_); |
| 1024 node->break_target()->set_code_generator(this); |
| 1023 VisitStatements(node->statements()); | 1025 VisitStatements(node->statements()); |
| 1024 __ bind(node->break_target()); | 1026 node->break_target()->Bind(); |
| 1025 } | 1027 } |
| 1026 | 1028 |
| 1027 | 1029 |
| 1028 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1030 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1029 __ mov(r0, Operand(pairs)); | 1031 __ mov(r0, Operand(pairs)); |
| 1030 __ push(r0); | 1032 __ push(r0); |
| 1031 __ push(cp); | 1033 __ push(cp); |
| 1032 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); | 1034 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); |
| 1033 __ push(r0); | 1035 __ push(r0); |
| 1034 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 1036 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1119 | 1121 |
| 1120 void CodeGenerator::VisitIfStatement(IfStatement* node) { | 1122 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
| 1121 Comment cmnt(masm_, "[ IfStatement"); | 1123 Comment cmnt(masm_, "[ IfStatement"); |
| 1122 // Generate different code depending on which | 1124 // Generate different code depending on which |
| 1123 // parts of the if statement are present or not. | 1125 // parts of the if statement are present or not. |
| 1124 bool has_then_stm = node->HasThenStatement(); | 1126 bool has_then_stm = node->HasThenStatement(); |
| 1125 bool has_else_stm = node->HasElseStatement(); | 1127 bool has_else_stm = node->HasElseStatement(); |
| 1126 | 1128 |
| 1127 if (FLAG_debug_info) RecordStatementPosition(node); | 1129 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1128 | 1130 |
| 1129 Label exit; | 1131 JumpTarget exit(this); |
| 1130 if (has_then_stm && has_else_stm) { | 1132 if (has_then_stm && has_else_stm) { |
| 1131 Comment cmnt(masm_, "[ IfThenElse"); | 1133 Comment cmnt(masm_, "[ IfThenElse"); |
| 1132 Label then; | 1134 JumpTarget then(this); |
| 1133 Label else_; | 1135 JumpTarget else_(this); |
| 1134 // if (cond) | 1136 // if (cond) |
| 1135 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 1137 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| 1136 Branch(false, &else_); | 1138 Branch(false, &else_); |
| 1137 // then | 1139 // then |
| 1138 __ bind(&then); | 1140 then.Bind(); |
| 1139 Visit(node->then_statement()); | 1141 Visit(node->then_statement()); |
| 1140 __ b(&exit); | 1142 exit.Jump(); |
| 1141 // else | 1143 // else |
| 1142 __ bind(&else_); | 1144 else_.Bind(); |
| 1143 Visit(node->else_statement()); | 1145 Visit(node->else_statement()); |
| 1144 | 1146 |
| 1145 } else if (has_then_stm) { | 1147 } else if (has_then_stm) { |
| 1146 Comment cmnt(masm_, "[ IfThen"); | 1148 Comment cmnt(masm_, "[ IfThen"); |
| 1147 ASSERT(!has_else_stm); | 1149 ASSERT(!has_else_stm); |
| 1148 Label then; | 1150 JumpTarget then(this); |
| 1149 // if (cond) | 1151 // if (cond) |
| 1150 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); | 1152 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); |
| 1151 Branch(false, &exit); | 1153 Branch(false, &exit); |
| 1152 // then | 1154 // then |
| 1153 __ bind(&then); | 1155 then.Bind(); |
| 1154 Visit(node->then_statement()); | 1156 Visit(node->then_statement()); |
| 1155 | 1157 |
| 1156 } else if (has_else_stm) { | 1158 } else if (has_else_stm) { |
| 1157 Comment cmnt(masm_, "[ IfElse"); | 1159 Comment cmnt(masm_, "[ IfElse"); |
| 1158 ASSERT(!has_then_stm); | 1160 ASSERT(!has_then_stm); |
| 1159 Label else_; | 1161 JumpTarget else_(this); |
| 1160 // if (!cond) | 1162 // if (!cond) |
| 1161 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); | 1163 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); |
| 1162 Branch(true, &exit); | 1164 Branch(true, &exit); |
| 1163 // else | 1165 // else |
| 1164 __ bind(&else_); | 1166 else_.Bind(); |
| 1165 Visit(node->else_statement()); | 1167 Visit(node->else_statement()); |
| 1166 | 1168 |
| 1167 } else { | 1169 } else { |
| 1168 Comment cmnt(masm_, "[ If"); | 1170 Comment cmnt(masm_, "[ If"); |
| 1169 ASSERT(!has_then_stm && !has_else_stm); | 1171 ASSERT(!has_then_stm && !has_else_stm); |
| 1170 // if (cond) | 1172 // if (cond) |
| 1171 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); | 1173 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); |
| 1172 if (has_cc()) { | 1174 if (has_cc()) { |
| 1173 cc_reg_ = al; | 1175 cc_reg_ = al; |
| 1174 } else { | 1176 } else { |
| 1175 __ pop(r0); // __ Pop(no_reg) | 1177 __ pop(r0); // __ Pop(no_reg) |
| 1176 } | 1178 } |
| 1177 } | 1179 } |
| 1178 | 1180 |
| 1179 // end | 1181 // end |
| 1180 __ bind(&exit); | 1182 exit.Bind(); |
| 1181 } | 1183 } |
| 1182 | 1184 |
| 1183 | 1185 |
| 1184 void CodeGenerator::CleanStack(int num_bytes) { | 1186 void CodeGenerator::CleanStack(int num_bytes) { |
| 1185 ASSERT(num_bytes >= 0); | 1187 ASSERT(num_bytes >= 0); |
| 1186 if (num_bytes > 0) { | 1188 if (num_bytes > 0) { |
| 1187 __ add(sp, sp, Operand(num_bytes)); | 1189 __ add(sp, sp, Operand(num_bytes)); |
| 1188 } | 1190 } |
| 1189 } | 1191 } |
| 1190 | 1192 |
| 1191 | 1193 |
| 1192 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1194 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
| 1193 Comment cmnt(masm_, "[ ContinueStatement"); | 1195 Comment cmnt(masm_, "[ ContinueStatement"); |
| 1194 if (FLAG_debug_info) RecordStatementPosition(node); | 1196 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1195 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1197 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1196 __ b(node->target()->continue_target()); | 1198 node->target()->continue_target()->Jump(); |
| 1197 } | 1199 } |
| 1198 | 1200 |
| 1199 | 1201 |
| 1200 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1202 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
| 1201 Comment cmnt(masm_, "[ BreakStatement"); | 1203 Comment cmnt(masm_, "[ BreakStatement"); |
| 1202 if (FLAG_debug_info) RecordStatementPosition(node); | 1204 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1203 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1205 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1204 __ b(node->target()->break_target()); | 1206 node->target()->break_target()->Jump(); |
| 1205 } | 1207 } |
| 1206 | 1208 |
| 1207 | 1209 |
| 1208 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1210 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| 1209 Comment cmnt(masm_, "[ ReturnStatement"); | 1211 Comment cmnt(masm_, "[ ReturnStatement"); |
| 1210 if (FLAG_debug_info) RecordStatementPosition(node); | 1212 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1211 Load(node->expression()); | 1213 Load(node->expression()); |
| 1212 // Move the function result into r0. | 1214 // Move the function result into r0. |
| 1213 __ pop(r0); | 1215 __ pop(r0); |
| 1214 | 1216 |
| 1215 __ b(&function_return_); | 1217 function_return_.Jump(); |
| 1216 } | 1218 } |
| 1217 | 1219 |
| 1218 | 1220 |
| 1219 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1221 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 1220 Comment cmnt(masm_, "[ WithEnterStatement"); | 1222 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 1221 if (FLAG_debug_info) RecordStatementPosition(node); | 1223 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1222 Load(node->expression()); | 1224 Load(node->expression()); |
| 1223 __ CallRuntime(Runtime::kPushContext, 1); | 1225 __ CallRuntime(Runtime::kPushContext, 1); |
| 1224 if (kDebug) { | 1226 if (kDebug) { |
| 1225 Label verified_true; | 1227 Label verified_true; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1248 | 1250 |
| 1249 int CodeGenerator::FastCaseSwitchMinCaseCount() { | 1251 int CodeGenerator::FastCaseSwitchMinCaseCount() { |
| 1250 return kFastSwitchMinCaseCount; | 1252 return kFastSwitchMinCaseCount; |
| 1251 } | 1253 } |
| 1252 | 1254 |
| 1253 | 1255 |
| 1254 void CodeGenerator::GenerateFastCaseSwitchJumpTable( | 1256 void CodeGenerator::GenerateFastCaseSwitchJumpTable( |
| 1255 SwitchStatement* node, | 1257 SwitchStatement* node, |
| 1256 int min_index, | 1258 int min_index, |
| 1257 int range, | 1259 int range, |
| 1258 Label* fail_label, | 1260 JumpTarget* fail_label, |
| 1259 Vector<Label*> case_targets, | 1261 Vector<JumpTarget*> case_targets, |
| 1260 Vector<Label> case_labels) { | 1262 Vector<JumpTarget> case_labels) { |
| 1261 | 1263 |
| 1262 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2); | 1264 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2); |
| 1263 | 1265 |
| 1264 __ pop(r0); | 1266 __ pop(r0); |
| 1265 | 1267 |
| 1266 // Test for a Smi value in a HeapNumber. | 1268 // Test for a Smi value in a HeapNumber. |
| 1267 Label is_smi; | 1269 Label is_smi; |
| 1268 __ tst(r0, Operand(kSmiTagMask)); | 1270 __ tst(r0, Operand(kSmiTagMask)); |
| 1269 __ b(eq, &is_smi); | 1271 __ b(eq, &is_smi); |
| 1270 __ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag)); | 1272 __ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag)); |
| 1271 __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag)); | 1273 __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag)); |
| 1272 __ cmp(r1, Operand(HEAP_NUMBER_TYPE)); | 1274 __ cmp(r1, Operand(HEAP_NUMBER_TYPE)); |
| 1273 __ b(ne, fail_label); | 1275 fail_label->Branch(ne); |
| 1274 __ push(r0); | 1276 __ push(r0); |
| 1275 __ CallRuntime(Runtime::kNumberToSmi, 1); | 1277 __ CallRuntime(Runtime::kNumberToSmi, 1); |
| 1276 __ bind(&is_smi); | 1278 __ bind(&is_smi); |
| 1277 | 1279 |
| 1278 if (min_index != 0) { | 1280 if (min_index != 0) { |
| 1279 // Small positive numbers can be immediate operands. | 1281 // Small positive numbers can be immediate operands. |
| 1280 if (min_index < 0) { | 1282 if (min_index < 0) { |
| 1281 // If min_index is Smi::kMinValue, -min_index is not a Smi. | 1283 // If min_index is Smi::kMinValue, -min_index is not a Smi. |
| 1282 if (Smi::IsValid(-min_index)) { | 1284 if (Smi::IsValid(-min_index)) { |
| 1283 __ add(r0, r0, Operand(Smi::FromInt(-min_index))); | 1285 __ add(r0, r0, Operand(Smi::FromInt(-min_index))); |
| 1284 } else { | 1286 } else { |
| 1285 __ add(r0, r0, Operand(Smi::FromInt(-min_index - 1))); | 1287 __ add(r0, r0, Operand(Smi::FromInt(-min_index - 1))); |
| 1286 __ add(r0, r0, Operand(Smi::FromInt(1))); | 1288 __ add(r0, r0, Operand(Smi::FromInt(1))); |
| 1287 } | 1289 } |
| 1288 } else { | 1290 } else { |
| 1289 __ sub(r0, r0, Operand(Smi::FromInt(min_index))); | 1291 __ sub(r0, r0, Operand(Smi::FromInt(min_index))); |
| 1290 } | 1292 } |
| 1291 } | 1293 } |
| 1292 __ tst(r0, Operand(0x80000000 | kSmiTagMask)); | 1294 __ tst(r0, Operand(0x80000000 | kSmiTagMask)); |
| 1293 __ b(ne, fail_label); | 1295 fail_label->Branch(ne); |
| 1294 __ cmp(r0, Operand(Smi::FromInt(range))); | 1296 __ cmp(r0, Operand(Smi::FromInt(range))); |
| 1295 __ b(ge, fail_label); | 1297 fail_label->Branch(ge); |
| 1296 __ add(pc, pc, Operand(r0, LSL, 2 - kSmiTagSize)); | 1298 __ add(pc, pc, Operand(r0, LSL, 2 - kSmiTagSize)); |
| 1297 // One extra instruction offsets the table, so the table's start address is | 1299 // One extra instruction offsets the table, so the table's start address is |
| 1298 // the pc-register at the above add. | 1300 // the pc-register at the above add. |
| 1299 __ stop("Unreachable: Switch table alignment"); | 1301 __ stop("Unreachable: Switch table alignment"); |
| 1300 | 1302 |
| 1303 JumpTarget table_start(this); |
| 1304 table_start.Bind(); |
| 1301 // Table containing branch operations. | 1305 // Table containing branch operations. |
| 1302 for (int i = 0; i < range; i++) { | 1306 for (int i = 0; i < range; i++) { |
| 1303 __ b(case_targets[i]); | 1307 case_targets[i]->Jump(); |
| 1304 } | 1308 } |
| 1305 | 1309 |
| 1306 GenerateFastCaseSwitchCases(node, case_labels); | 1310 GenerateFastCaseSwitchCases(node, case_labels, &table_start); |
| 1307 } | 1311 } |
| 1308 | 1312 |
| 1309 | 1313 |
| 1310 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1314 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 1311 Comment cmnt(masm_, "[ SwitchStatement"); | 1315 Comment cmnt(masm_, "[ SwitchStatement"); |
| 1312 if (FLAG_debug_info) RecordStatementPosition(node); | 1316 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1313 node->set_break_stack_height(break_stack_height_); | 1317 node->set_break_stack_height(break_stack_height_); |
| 1318 node->break_target()->set_code_generator(this); |
| 1314 | 1319 |
| 1315 Load(node->tag()); | 1320 Load(node->tag()); |
| 1316 | 1321 |
| 1317 if (TryGenerateFastCaseSwitchStatement(node)) { | 1322 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1318 return; | 1323 return; |
| 1319 } | 1324 } |
| 1320 | 1325 |
| 1321 Label next, fall_through, default_case; | 1326 JumpTarget next(this); |
| 1327 Label fall_through, default_case; |
| 1322 ZoneList<CaseClause*>* cases = node->cases(); | 1328 ZoneList<CaseClause*>* cases = node->cases(); |
| 1323 int length = cases->length(); | 1329 int length = cases->length(); |
| 1324 | 1330 |
| 1325 for (int i = 0; i < length; i++) { | 1331 for (int i = 0; i < length; i++) { |
| 1326 CaseClause* clause = cases->at(i); | 1332 CaseClause* clause = cases->at(i); |
| 1327 | 1333 |
| 1328 Comment cmnt(masm_, "[ case clause"); | 1334 Comment cmnt(masm_, "[ case clause"); |
| 1329 | 1335 |
| 1330 if (clause->is_default()) { | 1336 if (clause->is_default()) { |
| 1331 // Continue matching cases. The program will execute the default case's | 1337 // Continue matching cases. The program will execute the default case's |
| 1332 // statements if it does not match any of the cases. | 1338 // statements if it does not match any of the cases. |
| 1333 __ b(&next); | 1339 next.Jump(); |
| 1334 | 1340 |
| 1335 // Bind the default case label, so we can branch to it when we | 1341 // Bind the default case label, so we can branch to it when we |
| 1336 // have compared against all other cases. | 1342 // have compared against all other cases. |
| 1337 ASSERT(default_case.is_unused()); // at most one default clause | 1343 ASSERT(default_case.is_unused()); // at most one default clause |
| 1338 __ bind(&default_case); | 1344 __ bind(&default_case); |
| 1339 } else { | 1345 } else { |
| 1340 __ bind(&next); | 1346 next.Bind(); |
| 1341 next.Unuse(); | 1347 next.Unuse(); |
| 1342 __ ldr(r0, frame_->Top()); | 1348 __ ldr(r0, frame_->Top()); |
| 1343 __ push(r0); // duplicate TOS | 1349 __ push(r0); // duplicate TOS |
| 1344 Load(clause->label()); | 1350 Load(clause->label()); |
| 1345 Comparison(eq, true); | 1351 Comparison(eq, true); |
| 1346 Branch(false, &next); | 1352 Branch(false, &next); |
| 1347 } | 1353 } |
| 1348 | 1354 |
| 1349 // Entering the case statement for the first time. Remove the switch value | 1355 // Entering the case statement for the first time. Remove the switch value |
| 1350 // from the stack. | 1356 // from the stack. |
| 1351 __ pop(r0); | 1357 __ pop(r0); |
| 1352 | 1358 |
| 1353 // Generate code for the body. | 1359 // Generate code for the body. |
| 1354 // This is also the target for the fall through from the previous case's | 1360 // This is also the target for the fall through from the previous case's |
| 1355 // statements which has to skip over the matching code and the popping of | 1361 // statements which has to skip over the matching code and the popping of |
| 1356 // the switch value. | 1362 // the switch value. |
| 1357 __ bind(&fall_through); | 1363 __ bind(&fall_through); |
| 1358 fall_through.Unuse(); | 1364 fall_through.Unuse(); |
| 1359 VisitStatements(clause->statements()); | 1365 VisitStatements(clause->statements()); |
| 1360 __ b(&fall_through); | 1366 __ b(&fall_through); |
| 1361 } | 1367 } |
| 1362 | 1368 |
| 1363 __ bind(&next); | 1369 next.Bind(); |
| 1364 // Reached the end of the case statements without matching any of the cases. | 1370 // Reached the end of the case statements without matching any of the cases. |
| 1365 if (default_case.is_bound()) { | 1371 if (default_case.is_bound()) { |
| 1366 // A default case exists -> execute its statements. | 1372 // A default case exists -> execute its statements. |
| 1367 __ b(&default_case); | 1373 __ b(&default_case); |
| 1368 } else { | 1374 } else { |
| 1369 // Remove the switch value from the stack. | 1375 // Remove the switch value from the stack. |
| 1370 __ pop(r0); | 1376 __ pop(r0); |
| 1371 } | 1377 } |
| 1372 | 1378 |
| 1373 __ bind(&fall_through); | 1379 __ bind(&fall_through); |
| 1374 __ bind(node->break_target()); | 1380 node->break_target()->Bind(); |
| 1375 } | 1381 } |
| 1376 | 1382 |
| 1377 | 1383 |
| 1378 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1384 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 1379 Comment cmnt(masm_, "[ LoopStatement"); | 1385 Comment cmnt(masm_, "[ LoopStatement"); |
| 1380 if (FLAG_debug_info) RecordStatementPosition(node); | 1386 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1381 node->set_break_stack_height(break_stack_height_); | 1387 node->set_break_stack_height(break_stack_height_); |
| 1388 node->break_target()->set_code_generator(this); |
| 1389 node->continue_target()->set_code_generator(this); |
| 1382 | 1390 |
| 1383 // simple condition analysis | 1391 // simple condition analysis |
| 1384 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 1392 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
| 1385 if (node->cond() == NULL) { | 1393 if (node->cond() == NULL) { |
| 1386 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1394 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 1387 info = ALWAYS_TRUE; | 1395 info = ALWAYS_TRUE; |
| 1388 } else { | 1396 } else { |
| 1389 Literal* lit = node->cond()->AsLiteral(); | 1397 Literal* lit = node->cond()->AsLiteral(); |
| 1390 if (lit != NULL) { | 1398 if (lit != NULL) { |
| 1391 if (lit->IsTrue()) { | 1399 if (lit->IsTrue()) { |
| 1392 info = ALWAYS_TRUE; | 1400 info = ALWAYS_TRUE; |
| 1393 } else if (lit->IsFalse()) { | 1401 } else if (lit->IsFalse()) { |
| 1394 info = ALWAYS_FALSE; | 1402 info = ALWAYS_FALSE; |
| 1395 } | 1403 } |
| 1396 } | 1404 } |
| 1397 } | 1405 } |
| 1398 | 1406 |
| 1399 Label loop, entry; | 1407 JumpTarget loop(this); |
| 1408 Label entry; |
| 1400 | 1409 |
| 1401 // init | 1410 // init |
| 1402 if (node->init() != NULL) { | 1411 if (node->init() != NULL) { |
| 1403 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1412 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 1404 Visit(node->init()); | 1413 Visit(node->init()); |
| 1405 } | 1414 } |
| 1406 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) { | 1415 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) { |
| 1407 __ b(&entry); | 1416 __ b(&entry); |
| 1408 } | 1417 } |
| 1409 | 1418 |
| 1410 // body | 1419 // body |
| 1411 __ bind(&loop); | 1420 loop.Bind(); |
| 1412 Visit(node->body()); | 1421 Visit(node->body()); |
| 1413 | 1422 |
| 1414 // next | 1423 // next |
| 1415 __ bind(node->continue_target()); | 1424 node->continue_target()->Bind(); |
| 1416 if (node->next() != NULL) { | 1425 if (node->next() != NULL) { |
| 1417 // Record source position of the statement as this code which is after the | 1426 // Record source position of the statement as this code which is after the |
| 1418 // code for the body actually belongs to the loop statement and not the | 1427 // code for the body actually belongs to the loop statement and not the |
| 1419 // body. | 1428 // body. |
| 1420 if (FLAG_debug_info) __ RecordPosition(node->statement_pos()); | 1429 if (FLAG_debug_info) __ RecordPosition(node->statement_pos()); |
| 1421 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1430 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 1422 Visit(node->next()); | 1431 Visit(node->next()); |
| 1423 } | 1432 } |
| 1424 | 1433 |
| 1425 // cond | 1434 // cond |
| 1426 __ bind(&entry); | 1435 __ bind(&entry); |
| 1427 switch (info) { | 1436 switch (info) { |
| 1428 case ALWAYS_TRUE: | 1437 case ALWAYS_TRUE: |
| 1429 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1438 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1430 __ b(&loop); | 1439 loop.Jump(); |
| 1431 break; | 1440 break; |
| 1432 case ALWAYS_FALSE: | 1441 case ALWAYS_FALSE: |
| 1433 break; | 1442 break; |
| 1434 case DONT_KNOW: | 1443 case DONT_KNOW: |
| 1435 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1444 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1436 LoadCondition(node->cond(), | 1445 LoadCondition(node->cond(), |
| 1437 NOT_INSIDE_TYPEOF, | 1446 NOT_INSIDE_TYPEOF, |
| 1438 &loop, | 1447 &loop, |
| 1439 node->break_target(), | 1448 node->break_target(), |
| 1440 true); | 1449 true); |
| 1441 Branch(true, &loop); | 1450 Branch(true, &loop); |
| 1442 break; | 1451 break; |
| 1443 } | 1452 } |
| 1444 | 1453 |
| 1445 // exit | 1454 // exit |
| 1446 __ bind(node->break_target()); | 1455 node->break_target()->Bind(); |
| 1447 } | 1456 } |
| 1448 | 1457 |
| 1449 | 1458 |
| 1450 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 1459 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| 1451 Comment cmnt(masm_, "[ ForInStatement"); | 1460 Comment cmnt(masm_, "[ ForInStatement"); |
| 1452 if (FLAG_debug_info) RecordStatementPosition(node); | 1461 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1453 | 1462 |
| 1454 // We keep stuff on the stack while the body is executing. | 1463 // We keep stuff on the stack while the body is executing. |
| 1455 // Record it, so that a break/continue crossing this statement | 1464 // Record it, so that a break/continue crossing this statement |
| 1456 // can restore the stack. | 1465 // can restore the stack. |
| 1457 const int kForInStackSize = 5 * kPointerSize; | 1466 const int kForInStackSize = 5 * kPointerSize; |
| 1458 break_stack_height_ += kForInStackSize; | 1467 break_stack_height_ += kForInStackSize; |
| 1459 node->set_break_stack_height(break_stack_height_); | 1468 node->set_break_stack_height(break_stack_height_); |
| 1469 node->break_target()->set_code_generator(this); |
| 1470 node->continue_target()->set_code_generator(this); |
| 1460 | 1471 |
| 1461 Label loop, next, entry, cleanup, exit, primitive, jsobject; | 1472 Label loop, next, entry, cleanup, exit, primitive, jsobject; |
| 1462 Label filter_key, end_del_check, fixed_array, non_string; | 1473 Label filter_key, end_del_check, fixed_array, non_string; |
| 1463 | 1474 |
| 1464 // Get the object to enumerate over (converted to JSObject). | 1475 // Get the object to enumerate over (converted to JSObject). |
| 1465 Load(node->enumerable()); | 1476 Load(node->enumerable()); |
| 1466 __ pop(r0); | 1477 __ pop(r0); |
| 1467 | 1478 |
| 1468 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 1479 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| 1469 // to the specification. 12.6.4 mandates a call to ToObject. | 1480 // to the specification. 12.6.4 mandates a call to ToObject. |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1537 __ mov(r0, Operand(Smi::FromInt(0))); // init index | 1548 __ mov(r0, Operand(Smi::FromInt(0))); // init index |
| 1538 __ push(r0); | 1549 __ push(r0); |
| 1539 | 1550 |
| 1540 __ b(&entry); | 1551 __ b(&entry); |
| 1541 | 1552 |
| 1542 // Body. | 1553 // Body. |
| 1543 __ bind(&loop); | 1554 __ bind(&loop); |
| 1544 Visit(node->body()); | 1555 Visit(node->body()); |
| 1545 | 1556 |
| 1546 // Next. | 1557 // Next. |
| 1547 __ bind(node->continue_target()); | 1558 node->continue_target()->Bind(); |
| 1548 __ bind(&next); | 1559 __ bind(&next); |
| 1549 __ pop(r0); | 1560 __ pop(r0); |
| 1550 __ add(r0, r0, Operand(Smi::FromInt(1))); | 1561 __ add(r0, r0, Operand(Smi::FromInt(1))); |
| 1551 __ push(r0); | 1562 __ push(r0); |
| 1552 | 1563 |
| 1553 // Condition. | 1564 // Condition. |
| 1554 __ bind(&entry); | 1565 __ bind(&entry); |
| 1555 | 1566 |
| 1556 // sp[0] : index | 1567 // sp[0] : index |
| 1557 // sp[1] : array/enum cache length | 1568 // sp[1] : array/enum cache length |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1618 } | 1629 } |
| 1619 } | 1630 } |
| 1620 // Discard the i'th entry pushed above or else the remainder of the | 1631 // Discard the i'th entry pushed above or else the remainder of the |
| 1621 // reference, whichever is currently on top of the stack. | 1632 // reference, whichever is currently on top of the stack. |
| 1622 __ pop(); | 1633 __ pop(); |
| 1623 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1634 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1624 __ jmp(&loop); | 1635 __ jmp(&loop); |
| 1625 | 1636 |
| 1626 // Cleanup. | 1637 // Cleanup. |
| 1627 __ bind(&cleanup); | 1638 __ bind(&cleanup); |
| 1628 __ bind(node->break_target()); | 1639 node->break_target()->Bind(); |
| 1629 __ add(sp, sp, Operand(5 * kPointerSize)); | 1640 __ add(sp, sp, Operand(5 * kPointerSize)); |
| 1630 | 1641 |
| 1631 // Exit. | 1642 // Exit. |
| 1632 __ bind(&exit); | 1643 __ bind(&exit); |
| 1633 | 1644 |
| 1634 break_stack_height_ -= kForInStackSize; | 1645 break_stack_height_ -= kForInStackSize; |
| 1635 } | 1646 } |
| 1636 | 1647 |
| 1637 | 1648 |
| 1638 void CodeGenerator::VisitTryCatch(TryCatch* node) { | 1649 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1666 | 1677 |
| 1667 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); | 1678 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); |
| 1668 | 1679 |
| 1669 // Shadow the labels for all escapes from the try block, including | 1680 // Shadow the labels for all escapes from the try block, including |
| 1670 // returns. During shadowing, the original label is hidden as the | 1681 // returns. During shadowing, the original label is hidden as the |
| 1671 // LabelShadow and operations on the original actually affect the | 1682 // LabelShadow and operations on the original actually affect the |
| 1672 // shadowing label. | 1683 // shadowing label. |
| 1673 // | 1684 // |
| 1674 // We should probably try to unify the escaping labels and the return | 1685 // We should probably try to unify the escaping labels and the return |
| 1675 // label. | 1686 // label. |
| 1676 int nof_escapes = node->escaping_labels()->length(); | 1687 int nof_escapes = node->escaping_targets()->length(); |
| 1677 List<LabelShadow*> shadows(1 + nof_escapes); | 1688 List<ShadowTarget*> shadows(1 + nof_escapes); |
| 1678 shadows.Add(new LabelShadow(&function_return_)); | 1689 shadows.Add(new ShadowTarget(&function_return_)); |
| 1679 for (int i = 0; i < nof_escapes; i++) { | 1690 for (int i = 0; i < nof_escapes; i++) { |
| 1680 shadows.Add(new LabelShadow(node->escaping_labels()->at(i))); | 1691 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); |
| 1681 } | 1692 } |
| 1682 | 1693 |
| 1683 // Generate code for the statements in the try block. | 1694 // Generate code for the statements in the try block. |
| 1684 VisitStatements(node->try_block()->statements()); | 1695 VisitStatements(node->try_block()->statements()); |
| 1685 __ pop(r0); // Discard the result. | 1696 __ pop(r0); // Discard the result. |
| 1686 | 1697 |
| 1687 // Stop the introduced shadowing and count the number of required unlinks. | 1698 // Stop the introduced shadowing and count the number of required unlinks. |
| 1688 // After shadowing stops, the original labels are unshadowed and the | 1699 // After shadowing stops, the original labels are unshadowed and the |
| 1689 // LabelShadows represent the formerly shadowing labels. | 1700 // LabelShadows represent the formerly shadowing labels. |
| 1690 int nof_unlinks = 0; | 1701 int nof_unlinks = 0; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1704 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code | 1715 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code |
| 1705 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); | 1716 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); |
| 1706 // Code slot popped. | 1717 // Code slot popped. |
| 1707 if (nof_unlinks > 0) __ b(&exit); | 1718 if (nof_unlinks > 0) __ b(&exit); |
| 1708 | 1719 |
| 1709 // Generate unlink code for the (formerly) shadowing labels that have been | 1720 // Generate unlink code for the (formerly) shadowing labels that have been |
| 1710 // jumped to. | 1721 // jumped to. |
| 1711 for (int i = 0; i <= nof_escapes; i++) { | 1722 for (int i = 0; i <= nof_escapes; i++) { |
| 1712 if (shadows[i]->is_linked()) { | 1723 if (shadows[i]->is_linked()) { |
| 1713 // Unlink from try chain; | 1724 // Unlink from try chain; |
| 1714 __ bind(shadows[i]); | 1725 shadows[i]->Bind(); |
| 1715 | 1726 |
| 1716 // Reload sp from the top handler, because some statements that we | 1727 // Reload sp from the top handler, because some statements that we |
| 1717 // break from (eg, for...in) may have left stuff on the stack. | 1728 // break from (eg, for...in) may have left stuff on the stack. |
| 1718 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); | 1729 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
| 1719 __ ldr(sp, MemOperand(r3)); | 1730 __ ldr(sp, MemOperand(r3)); |
| 1720 | 1731 |
| 1721 __ ldr(r1, frame_->Element(kNextIndex)); | 1732 __ ldr(r1, frame_->Element(kNextIndex)); |
| 1722 __ str(r1, MemOperand(r3)); | 1733 __ str(r1, MemOperand(r3)); |
| 1723 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code | 1734 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code |
| 1724 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); | 1735 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); |
| 1725 // Code slot popped. | 1736 // Code slot popped. |
| 1726 | 1737 |
| 1727 __ b(shadows[i]->original_label()); | 1738 shadows[i]->original_target()->Jump(); |
| 1728 } | 1739 } |
| 1729 } | 1740 } |
| 1730 | 1741 |
| 1731 __ bind(&exit); | 1742 __ bind(&exit); |
| 1732 } | 1743 } |
| 1733 | 1744 |
| 1734 | 1745 |
| 1735 void CodeGenerator::VisitTryFinally(TryFinally* node) { | 1746 void CodeGenerator::VisitTryFinally(TryFinally* node) { |
| 1736 Comment cmnt(masm_, "[ TryFinally"); | 1747 Comment cmnt(masm_, "[ TryFinally"); |
| 1737 | 1748 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1754 __ bind(&try_block); | 1765 __ bind(&try_block); |
| 1755 | 1766 |
| 1756 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER); | 1767 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER); |
| 1757 | 1768 |
| 1758 // Shadow the labels for all escapes from the try block, including | 1769 // Shadow the labels for all escapes from the try block, including |
| 1759 // returns. Shadowing hides the original label as the LabelShadow and | 1770 // returns. Shadowing hides the original label as the LabelShadow and |
| 1760 // operations on the original actually affect the shadowing label. | 1771 // operations on the original actually affect the shadowing label. |
| 1761 // | 1772 // |
| 1762 // We should probably try to unify the escaping labels and the return | 1773 // We should probably try to unify the escaping labels and the return |
| 1763 // label. | 1774 // label. |
| 1764 int nof_escapes = node->escaping_labels()->length(); | 1775 int nof_escapes = node->escaping_targets()->length(); |
| 1765 List<LabelShadow*> shadows(1 + nof_escapes); | 1776 List<ShadowTarget*> shadows(1 + nof_escapes); |
| 1766 shadows.Add(new LabelShadow(&function_return_)); | 1777 shadows.Add(new ShadowTarget(&function_return_)); |
| 1767 for (int i = 0; i < nof_escapes; i++) { | 1778 for (int i = 0; i < nof_escapes; i++) { |
| 1768 shadows.Add(new LabelShadow(node->escaping_labels()->at(i))); | 1779 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); |
| 1769 } | 1780 } |
| 1770 | 1781 |
| 1771 // Generate code for the statements in the try block. | 1782 // Generate code for the statements in the try block. |
| 1772 VisitStatements(node->try_block()->statements()); | 1783 VisitStatements(node->try_block()->statements()); |
| 1773 | 1784 |
| 1774 // Stop the introduced shadowing and count the number of required unlinks. | 1785 // Stop the introduced shadowing and count the number of required unlinks. |
| 1775 // After shadowing stops, the original labels are unshadowed and the | 1786 // After shadowing stops, the original labels are unshadowed and the |
| 1776 // LabelShadows represent the formerly shadowing labels. | 1787 // LabelShadows represent the formerly shadowing labels. |
| 1777 int nof_unlinks = 0; | 1788 int nof_unlinks = 0; |
| 1778 for (int i = 0; i <= nof_escapes; i++) { | 1789 for (int i = 0; i <= nof_escapes; i++) { |
| 1779 shadows[i]->StopShadowing(); | 1790 shadows[i]->StopShadowing(); |
| 1780 if (shadows[i]->is_linked()) nof_unlinks++; | 1791 if (shadows[i]->is_linked()) nof_unlinks++; |
| 1781 } | 1792 } |
| 1782 | 1793 |
| 1783 // Set the state on the stack to FALLING. | 1794 // Set the state on the stack to FALLING. |
| 1784 __ mov(r0, Operand(Factory::undefined_value())); // fake TOS | 1795 __ mov(r0, Operand(Factory::undefined_value())); // fake TOS |
| 1785 __ push(r0); | 1796 __ push(r0); |
| 1786 __ mov(r2, Operand(Smi::FromInt(FALLING))); | 1797 __ mov(r2, Operand(Smi::FromInt(FALLING))); |
| 1787 if (nof_unlinks > 0) __ b(&unlink); | 1798 if (nof_unlinks > 0) __ b(&unlink); |
| 1788 | 1799 |
| 1789 // Generate code to set the state for the (formerly) shadowing labels that | 1800 // Generate code to set the state for the (formerly) shadowing labels that |
| 1790 // have been jumped to. | 1801 // have been jumped to. |
| 1791 for (int i = 0; i <= nof_escapes; i++) { | 1802 for (int i = 0; i <= nof_escapes; i++) { |
| 1792 if (shadows[i]->is_linked()) { | 1803 if (shadows[i]->is_linked()) { |
| 1793 __ bind(shadows[i]); | 1804 shadows[i]->Bind(); |
| 1794 if (shadows[i]->original_label() == &function_return_) { | 1805 if (shadows[i]->original_target() == &function_return_) { |
| 1795 // If this label shadowed the function return, materialize the | 1806 // If this label shadowed the function return, materialize the |
| 1796 // return value on the stack. | 1807 // return value on the stack. |
| 1797 __ push(r0); | 1808 __ push(r0); |
| 1798 } else { | 1809 } else { |
| 1799 // Fake TOS for labels that shadowed breaks and continues. | 1810 // Fake TOS for labels that shadowed breaks and continues. |
| 1800 __ mov(r0, Operand(Factory::undefined_value())); | 1811 __ mov(r0, Operand(Factory::undefined_value())); |
| 1801 __ push(r0); | 1812 __ push(r0); |
| 1802 } | 1813 } |
| 1803 __ mov(r2, Operand(Smi::FromInt(JUMPING + i))); | 1814 __ mov(r2, Operand(Smi::FromInt(JUMPING + i))); |
| 1804 __ b(&unlink); | 1815 __ b(&unlink); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1842 // Restore state and return value or faked TOS. | 1853 // Restore state and return value or faked TOS. |
| 1843 __ pop(r2); | 1854 __ pop(r2); |
| 1844 __ pop(r0); | 1855 __ pop(r0); |
| 1845 break_stack_height_ -= kFinallyStackSize; | 1856 break_stack_height_ -= kFinallyStackSize; |
| 1846 | 1857 |
| 1847 // Generate code to jump to the right destination for all used (formerly) | 1858 // Generate code to jump to the right destination for all used (formerly) |
| 1848 // shadowing labels. | 1859 // shadowing labels. |
| 1849 for (int i = 0; i <= nof_escapes; i++) { | 1860 for (int i = 0; i <= nof_escapes; i++) { |
| 1850 if (shadows[i]->is_bound()) { | 1861 if (shadows[i]->is_bound()) { |
| 1851 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i))); | 1862 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i))); |
| 1852 if (shadows[i]->original_label() != &function_return_) { | 1863 if (shadows[i]->original_target() != &function_return_) { |
| 1853 Label next; | 1864 Label next; |
| 1854 __ b(ne, &next); | 1865 __ b(ne, &next); |
| 1855 __ b(shadows[i]->original_label()); | 1866 shadows[i]->original_target()->Jump(); |
| 1856 __ bind(&next); | 1867 __ bind(&next); |
| 1857 } else { | 1868 } else { |
| 1858 __ b(eq, shadows[i]->original_label()); | 1869 shadows[i]->original_target()->Branch(eq); |
| 1859 } | 1870 } |
| 1860 } | 1871 } |
| 1861 } | 1872 } |
| 1862 | 1873 |
| 1863 // Check if we need to rethrow the exception. | 1874 // Check if we need to rethrow the exception. |
| 1864 __ cmp(r2, Operand(Smi::FromInt(THROWING))); | 1875 __ cmp(r2, Operand(Smi::FromInt(THROWING))); |
| 1865 __ b(ne, &exit); | 1876 __ b(ne, &exit); |
| 1866 | 1877 |
| 1867 // Rethrow exception. | 1878 // Rethrow exception. |
| 1868 __ push(r0); | 1879 __ push(r0); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1908 | 1919 |
| 1909 void CodeGenerator::VisitFunctionBoilerplateLiteral( | 1920 void CodeGenerator::VisitFunctionBoilerplateLiteral( |
| 1910 FunctionBoilerplateLiteral* node) { | 1921 FunctionBoilerplateLiteral* node) { |
| 1911 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 1922 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
| 1912 InstantiateBoilerplate(node->boilerplate()); | 1923 InstantiateBoilerplate(node->boilerplate()); |
| 1913 } | 1924 } |
| 1914 | 1925 |
| 1915 | 1926 |
| 1916 void CodeGenerator::VisitConditional(Conditional* node) { | 1927 void CodeGenerator::VisitConditional(Conditional* node) { |
| 1917 Comment cmnt(masm_, "[ Conditional"); | 1928 Comment cmnt(masm_, "[ Conditional"); |
| 1918 Label then, else_, exit; | 1929 JumpTarget then(this); |
| 1930 JumpTarget else_(this); |
| 1931 Label exit; |
| 1919 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 1932 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| 1920 Branch(false, &else_); | 1933 Branch(false, &else_); |
| 1921 __ bind(&then); | 1934 then.Bind(); |
| 1922 Load(node->then_expression(), typeof_state()); | 1935 Load(node->then_expression(), typeof_state()); |
| 1923 __ b(&exit); | 1936 __ b(&exit); |
| 1924 __ bind(&else_); | 1937 else_.Bind(); |
| 1925 Load(node->else_expression(), typeof_state()); | 1938 Load(node->else_expression(), typeof_state()); |
| 1926 __ bind(&exit); | 1939 __ bind(&exit); |
| 1927 } | 1940 } |
| 1928 | 1941 |
| 1929 | 1942 |
| 1930 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 1943 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 1931 if (slot->type() == Slot::LOOKUP) { | 1944 if (slot->type() == Slot::LOOKUP) { |
| 1932 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 1945 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 1933 | 1946 |
| 1934 // For now, just do a runtime call. | 1947 // For now, just do a runtime call. |
| (...skipping 871 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2806 // produced by a && or || operator is not necessarily a boolean. | 2819 // produced by a && or || operator is not necessarily a boolean. |
| 2807 | 2820 |
| 2808 // NOTE: If the left hand side produces a materialized value (not in | 2821 // NOTE: If the left hand side produces a materialized value (not in |
| 2809 // the CC register), we force the right hand side to do the | 2822 // the CC register), we force the right hand side to do the |
| 2810 // same. This is necessary because we may have to branch to the exit | 2823 // same. This is necessary because we may have to branch to the exit |
| 2811 // after evaluating the left hand side (due to the shortcut | 2824 // after evaluating the left hand side (due to the shortcut |
| 2812 // semantics), but the compiler must (statically) know if the result | 2825 // semantics), but the compiler must (statically) know if the result |
| 2813 // of compiling the binary operation is materialized or not. | 2826 // of compiling the binary operation is materialized or not. |
| 2814 | 2827 |
| 2815 if (op == Token::AND) { | 2828 if (op == Token::AND) { |
| 2816 Label is_true; | 2829 JumpTarget is_true(this); |
| 2817 LoadCondition(node->left(), | 2830 LoadCondition(node->left(), |
| 2818 NOT_INSIDE_TYPEOF, | 2831 NOT_INSIDE_TYPEOF, |
| 2819 &is_true, | 2832 &is_true, |
| 2820 false_target(), | 2833 false_target(), |
| 2821 false); | 2834 false); |
| 2822 if (has_cc()) { | 2835 if (has_cc()) { |
| 2823 Branch(false, false_target()); | 2836 Branch(false, false_target()); |
| 2824 | 2837 |
| 2825 // Evaluate right side expression. | 2838 // Evaluate right side expression. |
| 2826 __ bind(&is_true); | 2839 is_true.Bind(); |
| 2827 LoadCondition(node->right(), | 2840 LoadCondition(node->right(), |
| 2828 NOT_INSIDE_TYPEOF, | 2841 NOT_INSIDE_TYPEOF, |
| 2829 true_target(), | 2842 true_target(), |
| 2830 false_target(), | 2843 false_target(), |
| 2831 false); | 2844 false); |
| 2832 | 2845 |
| 2833 } else { | 2846 } else { |
| 2834 Label pop_and_continue, exit; | 2847 JumpTarget pop_and_continue(this); |
| 2848 JumpTarget exit(this); |
| 2835 | 2849 |
| 2836 __ ldr(r0, frame_->Top()); // dup the stack top | 2850 __ ldr(r0, frame_->Top()); // dup the stack top |
| 2837 __ push(r0); | 2851 __ push(r0); |
| 2838 // Avoid popping the result if it converts to 'false' using the | 2852 // Avoid popping the result if it converts to 'false' using the |
| 2839 // standard ToBoolean() conversion as described in ECMA-262, | 2853 // standard ToBoolean() conversion as described in ECMA-262, |
| 2840 // section 9.2, page 30. | 2854 // section 9.2, page 30. |
| 2841 ToBoolean(&pop_and_continue, &exit); | 2855 ToBoolean(&pop_and_continue, &exit); |
| 2842 Branch(false, &exit); | 2856 Branch(false, &exit); |
| 2843 | 2857 |
| 2844 // Pop the result of evaluating the first part. | 2858 // Pop the result of evaluating the first part. |
| 2845 __ bind(&pop_and_continue); | 2859 pop_and_continue.Bind(); |
| 2846 __ pop(r0); | 2860 __ pop(r0); |
| 2847 | 2861 |
| 2848 // Evaluate right side expression. | 2862 // Evaluate right side expression. |
| 2849 __ bind(&is_true); | 2863 is_true.Bind(); |
| 2850 Load(node->right()); | 2864 Load(node->right()); |
| 2851 | 2865 |
| 2852 // Exit (always with a materialized value). | 2866 // Exit (always with a materialized value). |
| 2853 __ bind(&exit); | 2867 exit.Bind(); |
| 2854 } | 2868 } |
| 2855 | 2869 |
| 2856 } else if (op == Token::OR) { | 2870 } else if (op == Token::OR) { |
| 2857 Label is_false; | 2871 JumpTarget is_false(this); |
| 2858 LoadCondition(node->left(), | 2872 LoadCondition(node->left(), |
| 2859 NOT_INSIDE_TYPEOF, | 2873 NOT_INSIDE_TYPEOF, |
| 2860 true_target(), | 2874 true_target(), |
| 2861 &is_false, | 2875 &is_false, |
| 2862 false); | 2876 false); |
| 2863 if (has_cc()) { | 2877 if (has_cc()) { |
| 2864 Branch(true, true_target()); | 2878 Branch(true, true_target()); |
| 2865 | 2879 |
| 2866 // Evaluate right side expression. | 2880 // Evaluate right side expression. |
| 2867 __ bind(&is_false); | 2881 is_false.Bind(); |
| 2868 LoadCondition(node->right(), | 2882 LoadCondition(node->right(), |
| 2869 NOT_INSIDE_TYPEOF, | 2883 NOT_INSIDE_TYPEOF, |
| 2870 true_target(), | 2884 true_target(), |
| 2871 false_target(), | 2885 false_target(), |
| 2872 false); | 2886 false); |
| 2873 | 2887 |
| 2874 } else { | 2888 } else { |
| 2875 Label pop_and_continue, exit; | 2889 JumpTarget pop_and_continue(this); |
| 2890 JumpTarget exit(this); |
| 2876 | 2891 |
| 2877 __ ldr(r0, frame_->Top()); | 2892 __ ldr(r0, frame_->Top()); |
| 2878 __ push(r0); | 2893 __ push(r0); |
| 2879 // Avoid popping the result if it converts to 'true' using the | 2894 // Avoid popping the result if it converts to 'true' using the |
| 2880 // standard ToBoolean() conversion as described in ECMA-262, | 2895 // standard ToBoolean() conversion as described in ECMA-262, |
| 2881 // section 9.2, page 30. | 2896 // section 9.2, page 30. |
| 2882 ToBoolean(&exit, &pop_and_continue); | 2897 ToBoolean(&exit, &pop_and_continue); |
| 2883 Branch(true, &exit); | 2898 Branch(true, &exit); |
| 2884 | 2899 |
| 2885 // Pop the result of evaluating the first part. | 2900 // Pop the result of evaluating the first part. |
| 2886 __ bind(&pop_and_continue); | 2901 pop_and_continue.Bind(); |
| 2887 __ pop(r0); | 2902 __ pop(r0); |
| 2888 | 2903 |
| 2889 // Evaluate right side expression. | 2904 // Evaluate right side expression. |
| 2890 __ bind(&is_false); | 2905 is_false.Bind(); |
| 2891 Load(node->right()); | 2906 Load(node->right()); |
| 2892 | 2907 |
| 2893 // Exit (always with a materialized value). | 2908 // Exit (always with a materialized value). |
| 2894 __ bind(&exit); | 2909 exit.Bind(); |
| 2895 } | 2910 } |
| 2896 | 2911 |
| 2897 } else { | 2912 } else { |
| 2898 // Optimize for the case where (at least) one of the expressions | 2913 // Optimize for the case where (at least) one of the expressions |
| 2899 // is a literal small integer. | 2914 // is a literal small integer. |
| 2900 Literal* lliteral = node->left()->AsLiteral(); | 2915 Literal* lliteral = node->left()->AsLiteral(); |
| 2901 Literal* rliteral = node->right()->AsLiteral(); | 2916 Literal* rliteral = node->right()->AsLiteral(); |
| 2902 | 2917 |
| 2903 if (rliteral != NULL && rliteral->handle()->IsSmi()) { | 2918 if (rliteral != NULL && rliteral->handle()->IsSmi()) { |
| 2904 Load(node->left()); | 2919 Load(node->left()); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2953 // non-strict comparisons. | 2968 // non-strict comparisons. |
| 2954 if (op != Token::EQ_STRICT) { | 2969 if (op != Token::EQ_STRICT) { |
| 2955 __ b(eq, &exit); | 2970 __ b(eq, &exit); |
| 2956 __ cmp(r0, Operand(Factory::undefined_value())); | 2971 __ cmp(r0, Operand(Factory::undefined_value())); |
| 2957 | 2972 |
| 2958 // NOTE: it can be undetectable object. | 2973 // NOTE: it can be undetectable object. |
| 2959 __ b(eq, &exit); | 2974 __ b(eq, &exit); |
| 2960 __ tst(r0, Operand(kSmiTagMask)); | 2975 __ tst(r0, Operand(kSmiTagMask)); |
| 2961 | 2976 |
| 2962 __ b(ne, &undetectable); | 2977 __ b(ne, &undetectable); |
| 2963 __ b(false_target()); | 2978 false_target()->Jump(); |
| 2964 | 2979 |
| 2965 __ bind(&undetectable); | 2980 __ bind(&undetectable); |
| 2966 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 2981 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 2967 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); | 2982 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); |
| 2968 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); | 2983 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); |
| 2969 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); | 2984 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); |
| 2970 } | 2985 } |
| 2971 | 2986 |
| 2972 __ bind(&exit); | 2987 __ bind(&exit); |
| 2973 | 2988 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2987 (right->AsLiteral() != NULL && | 3002 (right->AsLiteral() != NULL && |
| 2988 right->AsLiteral()->handle()->IsString())) { | 3003 right->AsLiteral()->handle()->IsString())) { |
| 2989 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 3004 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 2990 | 3005 |
| 2991 // Load the operand, move it to register r1. | 3006 // Load the operand, move it to register r1. |
| 2992 LoadTypeofExpression(operation->expression()); | 3007 LoadTypeofExpression(operation->expression()); |
| 2993 __ pop(r1); | 3008 __ pop(r1); |
| 2994 | 3009 |
| 2995 if (check->Equals(Heap::number_symbol())) { | 3010 if (check->Equals(Heap::number_symbol())) { |
| 2996 __ tst(r1, Operand(kSmiTagMask)); | 3011 __ tst(r1, Operand(kSmiTagMask)); |
| 2997 __ b(eq, true_target()); | 3012 true_target()->Branch(eq); |
| 2998 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3013 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 2999 __ cmp(r1, Operand(Factory::heap_number_map())); | 3014 __ cmp(r1, Operand(Factory::heap_number_map())); |
| 3000 cc_reg_ = eq; | 3015 cc_reg_ = eq; |
| 3001 | 3016 |
| 3002 } else if (check->Equals(Heap::string_symbol())) { | 3017 } else if (check->Equals(Heap::string_symbol())) { |
| 3003 __ tst(r1, Operand(kSmiTagMask)); | 3018 __ tst(r1, Operand(kSmiTagMask)); |
| 3004 __ b(eq, false_target()); | 3019 false_target()->Branch(eq); |
| 3005 | 3020 |
| 3006 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3021 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3007 | 3022 |
| 3008 // NOTE: it might be an undetectable string object | 3023 // NOTE: it might be an undetectable string object |
| 3009 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); | 3024 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); |
| 3010 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); | 3025 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); |
| 3011 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); | 3026 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); |
| 3012 __ b(eq, false_target()); | 3027 false_target()->Branch(eq); |
| 3013 | 3028 |
| 3014 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 3029 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 3015 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE)); | 3030 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE)); |
| 3016 cc_reg_ = lt; | 3031 cc_reg_ = lt; |
| 3017 | 3032 |
| 3018 } else if (check->Equals(Heap::boolean_symbol())) { | 3033 } else if (check->Equals(Heap::boolean_symbol())) { |
| 3019 __ cmp(r1, Operand(Factory::true_value())); | 3034 __ cmp(r1, Operand(Factory::true_value())); |
| 3020 __ b(eq, true_target()); | 3035 true_target()->Branch(eq); |
| 3021 __ cmp(r1, Operand(Factory::false_value())); | 3036 __ cmp(r1, Operand(Factory::false_value())); |
| 3022 cc_reg_ = eq; | 3037 cc_reg_ = eq; |
| 3023 | 3038 |
| 3024 } else if (check->Equals(Heap::undefined_symbol())) { | 3039 } else if (check->Equals(Heap::undefined_symbol())) { |
| 3025 __ cmp(r1, Operand(Factory::undefined_value())); | 3040 __ cmp(r1, Operand(Factory::undefined_value())); |
| 3026 __ b(eq, true_target()); | 3041 true_target()->Branch(eq); |
| 3027 | 3042 |
| 3028 __ tst(r1, Operand(kSmiTagMask)); | 3043 __ tst(r1, Operand(kSmiTagMask)); |
| 3029 __ b(eq, false_target()); | 3044 false_target()->Branch(eq); |
| 3030 | 3045 |
| 3031 // NOTE: it can be undetectable object. | 3046 // NOTE: it can be undetectable object. |
| 3032 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3047 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3033 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); | 3048 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); |
| 3034 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); | 3049 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); |
| 3035 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); | 3050 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); |
| 3036 | 3051 |
| 3037 cc_reg_ = eq; | 3052 cc_reg_ = eq; |
| 3038 | 3053 |
| 3039 } else if (check->Equals(Heap::function_symbol())) { | 3054 } else if (check->Equals(Heap::function_symbol())) { |
| 3040 __ tst(r1, Operand(kSmiTagMask)); | 3055 __ tst(r1, Operand(kSmiTagMask)); |
| 3041 __ b(eq, false_target()); | 3056 false_target()->Branch(eq); |
| 3042 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3057 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3043 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 3058 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 3044 __ cmp(r1, Operand(JS_FUNCTION_TYPE)); | 3059 __ cmp(r1, Operand(JS_FUNCTION_TYPE)); |
| 3045 cc_reg_ = eq; | 3060 cc_reg_ = eq; |
| 3046 | 3061 |
| 3047 } else if (check->Equals(Heap::object_symbol())) { | 3062 } else if (check->Equals(Heap::object_symbol())) { |
| 3048 __ tst(r1, Operand(kSmiTagMask)); | 3063 __ tst(r1, Operand(kSmiTagMask)); |
| 3049 __ b(eq, false_target()); | 3064 false_target()->Branch(eq); |
| 3050 | 3065 |
| 3051 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3066 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3052 __ cmp(r1, Operand(Factory::null_value())); | 3067 __ cmp(r1, Operand(Factory::null_value())); |
| 3053 __ b(eq, true_target()); | 3068 true_target()->Branch(eq); |
| 3054 | 3069 |
| 3055 // NOTE: it might be an undetectable object. | 3070 // NOTE: it might be an undetectable object. |
| 3056 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset)); | 3071 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset)); |
| 3057 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); | 3072 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); |
| 3058 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); | 3073 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); |
| 3059 __ b(eq, false_target()); | 3074 false_target()->Branch(eq); |
| 3060 | 3075 |
| 3061 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 3076 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| 3062 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); | 3077 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); |
| 3063 __ b(lt, false_target()); | 3078 false_target()->Branch(lt); |
| 3064 __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE)); | 3079 __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE)); |
| 3065 cc_reg_ = le; | 3080 cc_reg_ = le; |
| 3066 | 3081 |
| 3067 } else { | 3082 } else { |
| 3068 // Uncommon case: Typeof testing against a string literal that | 3083 // Uncommon case: Typeof testing against a string literal that |
| 3069 // is never returned from the typeof operator. | 3084 // is never returned from the typeof operator. |
| 3070 __ b(false_target()); | 3085 false_target()->Jump(); |
| 3071 } | 3086 } |
| 3072 return; | 3087 return; |
| 3073 } | 3088 } |
| 3074 | 3089 |
| 3075 Load(left); | 3090 Load(left); |
| 3076 Load(right); | 3091 Load(right); |
| 3077 switch (op) { | 3092 switch (op) { |
| 3078 case Token::EQ: | 3093 case Token::EQ: |
| 3079 Comparison(eq, false); | 3094 Comparison(eq, false); |
| 3080 break; | 3095 break; |
| (...skipping 1167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4248 // Slow-case: Non-function called. | 4263 // Slow-case: Non-function called. |
| 4249 __ bind(&slow); | 4264 __ bind(&slow); |
| 4250 __ mov(r0, Operand(argc_)); // Setup the number of arguments. | 4265 __ mov(r0, Operand(argc_)); // Setup the number of arguments. |
| 4251 __ InvokeBuiltin(Builtins::CALL_NON_FUNCTION, JUMP_JS); | 4266 __ InvokeBuiltin(Builtins::CALL_NON_FUNCTION, JUMP_JS); |
| 4252 } | 4267 } |
| 4253 | 4268 |
| 4254 | 4269 |
| 4255 #undef __ | 4270 #undef __ |
| 4256 | 4271 |
| 4257 } } // namespace v8::internal | 4272 } } // namespace v8::internal |
| OLD | NEW |