| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 |
| 11 // with the distribution. | 11 // with the distribution. |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 } | 164 } |
| 165 // Visit all the explicit declarations unless there is an illegal | 165 // Visit all the explicit declarations unless there is an illegal |
| 166 // redeclaration. | 166 // redeclaration. |
| 167 if (scope()->HasIllegalRedeclaration()) { | 167 if (scope()->HasIllegalRedeclaration()) { |
| 168 scope()->VisitIllegalRedeclaration(this); | 168 scope()->VisitIllegalRedeclaration(this); |
| 169 } else { | 169 } else { |
| 170 VisitDeclarations(scope()->declarations()); | 170 VisitDeclarations(scope()->declarations()); |
| 171 } | 171 } |
| 172 } | 172 } |
| 173 | 173 |
| 174 // Check the stack for overflow or break request. | |
| 175 { Comment cmnt(masm_, "[ Stack check"); | |
| 176 __ LoadRoot(r2, Heap::kStackLimitRootIndex); | |
| 177 __ cmp(sp, Operand(r2)); | |
| 178 StackCheckStub stub; | |
| 179 __ mov(ip, | |
| 180 Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()), | |
| 181 RelocInfo::CODE_TARGET), | |
| 182 LeaveCC, | |
| 183 lo); | |
| 184 __ Call(ip, lo); | |
| 185 } | |
| 186 | |
| 187 if (FLAG_trace) { | 174 if (FLAG_trace) { |
| 188 __ CallRuntime(Runtime::kTraceEnter, 0); | 175 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 189 } | 176 } |
| 190 | 177 |
| 178 // Check the stack for overflow or break request. |
| 179 { Comment cmnt(masm_, "[ Stack check"); |
| 180 PrepareForBailout(info->function(), NO_REGISTERS); |
| 181 Label ok; |
| 182 __ LoadRoot(ip, Heap::kStackLimitRootIndex); |
| 183 __ cmp(sp, Operand(ip)); |
| 184 __ b(hs, &ok); |
| 185 StackCheckStub stub; |
| 186 __ CallStub(&stub); |
| 187 __ bind(&ok); |
| 188 } |
| 189 |
| 191 { Comment cmnt(masm_, "[ Body"); | 190 { Comment cmnt(masm_, "[ Body"); |
| 192 ASSERT(loop_depth() == 0); | 191 ASSERT(loop_depth() == 0); |
| 193 VisitStatements(function()->body()); | 192 VisitStatements(function()->body()); |
| 194 ASSERT(loop_depth() == 0); | 193 ASSERT(loop_depth() == 0); |
| 195 } | 194 } |
| 196 | 195 |
| 197 { Comment cmnt(masm_, "[ return <undefined>;"); | 196 { Comment cmnt(masm_, "[ return <undefined>;"); |
| 198 // Emit a 'return undefined' in case control fell off the end of the | 197 // Emit a 'return undefined' in case control fell off the end of the |
| 199 // body. | 198 // body. |
| 200 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 199 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
| 201 } | 200 } |
| 202 EmitReturnSequence(); | 201 EmitReturnSequence(); |
| 202 |
| 203 // Force emit the constant pool, so it doesn't get emitted in the middle |
| 204 // of the stack check table. |
| 205 masm()->CheckConstPool(true, false); |
| 203 } | 206 } |
| 204 | 207 |
| 205 | 208 |
| 209 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) { |
| 210 Comment cmnt(masm_, "[ Stack check"); |
| 211 Label ok; |
| 212 __ LoadRoot(ip, Heap::kStackLimitRootIndex); |
| 213 __ cmp(sp, Operand(ip)); |
| 214 __ b(hs, &ok); |
| 215 StackCheckStub stub; |
| 216 __ CallStub(&stub); |
| 217 __ bind(&ok); |
| 218 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
| 219 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS); |
| 220 RecordStackCheck(stmt->OsrEntryId()); |
| 221 } |
| 222 |
| 223 |
| 206 void FullCodeGenerator::EmitReturnSequence() { | 224 void FullCodeGenerator::EmitReturnSequence() { |
| 207 Comment cmnt(masm_, "[ Return sequence"); | 225 Comment cmnt(masm_, "[ Return sequence"); |
| 208 if (return_label_.is_bound()) { | 226 if (return_label_.is_bound()) { |
| 209 __ b(&return_label_); | 227 __ b(&return_label_); |
| 210 } else { | 228 } else { |
| 211 __ bind(&return_label_); | 229 __ bind(&return_label_); |
| 212 if (FLAG_trace) { | 230 if (FLAG_trace) { |
| 213 // Push the return value on the stack as the parameter. | 231 // Push the return value on the stack as the parameter. |
| 214 // Runtime::TraceExit returns its parameter in r0. | 232 // Runtime::TraceExit returns its parameter in r0. |
| 215 __ push(r0); | 233 __ push(r0); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 | 286 |
| 269 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { | 287 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { |
| 270 codegen()->Move(result_register(), slot); | 288 codegen()->Move(result_register(), slot); |
| 271 __ push(result_register()); | 289 __ push(result_register()); |
| 272 } | 290 } |
| 273 | 291 |
| 274 | 292 |
| 275 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { | 293 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { |
| 276 // For simplicity we always test the accumulator register. | 294 // For simplicity we always test the accumulator register. |
| 277 codegen()->Move(result_register(), slot); | 295 codegen()->Move(result_register(), slot); |
| 296 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 278 codegen()->DoTest(true_label_, false_label_, fall_through_); | 297 codegen()->DoTest(true_label_, false_label_, fall_through_); |
| 279 } | 298 } |
| 280 | 299 |
| 281 | 300 |
| 282 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { | 301 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { |
| 283 } | 302 } |
| 284 | 303 |
| 285 | 304 |
| 286 void FullCodeGenerator::AccumulatorValueContext::Plug( | 305 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 287 Heap::RootListIndex index) const { | 306 Heap::RootListIndex index) const { |
| 288 __ LoadRoot(result_register(), index); | 307 __ LoadRoot(result_register(), index); |
| 289 } | 308 } |
| 290 | 309 |
| 291 | 310 |
| 292 void FullCodeGenerator::StackValueContext::Plug( | 311 void FullCodeGenerator::StackValueContext::Plug( |
| 293 Heap::RootListIndex index) const { | 312 Heap::RootListIndex index) const { |
| 294 __ LoadRoot(result_register(), index); | 313 __ LoadRoot(result_register(), index); |
| 295 __ push(result_register()); | 314 __ push(result_register()); |
| 296 } | 315 } |
| 297 | 316 |
| 298 | 317 |
| 299 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const { | 318 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const { |
| 319 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, |
| 320 true, |
| 321 true_label_, |
| 322 false_label_); |
| 300 if (index == Heap::kUndefinedValueRootIndex || | 323 if (index == Heap::kUndefinedValueRootIndex || |
| 301 index == Heap::kNullValueRootIndex || | 324 index == Heap::kNullValueRootIndex || |
| 302 index == Heap::kFalseValueRootIndex) { | 325 index == Heap::kFalseValueRootIndex) { |
| 303 __ b(false_label_); | 326 if (false_label_ != fall_through_) __ b(false_label_); |
| 304 } else if (index == Heap::kTrueValueRootIndex) { | 327 } else if (index == Heap::kTrueValueRootIndex) { |
| 305 __ b(true_label_); | 328 if (true_label_ != fall_through_) __ b(true_label_); |
| 306 } else { | 329 } else { |
| 307 __ LoadRoot(result_register(), index); | 330 __ LoadRoot(result_register(), index); |
| 308 codegen()->DoTest(true_label_, false_label_, fall_through_); | 331 codegen()->DoTest(true_label_, false_label_, fall_through_); |
| 309 } | 332 } |
| 310 } | 333 } |
| 311 | 334 |
| 312 | 335 |
| 313 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { | 336 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { |
| 314 } | 337 } |
| 315 | 338 |
| 316 | 339 |
| 317 void FullCodeGenerator::AccumulatorValueContext::Plug( | 340 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 318 Handle<Object> lit) const { | 341 Handle<Object> lit) const { |
| 319 __ mov(result_register(), Operand(lit)); | 342 __ mov(result_register(), Operand(lit)); |
| 320 } | 343 } |
| 321 | 344 |
| 322 | 345 |
| 323 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const { | 346 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const { |
| 324 // Immediates can be pushed directly. | 347 // Immediates cannot be pushed directly. |
| 325 __ mov(result_register(), Operand(lit)); | 348 __ mov(result_register(), Operand(lit)); |
| 326 __ push(result_register()); | 349 __ push(result_register()); |
| 327 } | 350 } |
| 328 | 351 |
| 329 | 352 |
| 330 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const { | 353 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const { |
| 354 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, |
| 355 true, |
| 356 true_label_, |
| 357 false_label_); |
| 331 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals. | 358 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals. |
| 332 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) { | 359 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) { |
| 333 __ b(false_label_); | 360 if (false_label_ != fall_through_) __ b(false_label_); |
| 334 } else if (lit->IsTrue() || lit->IsJSObject()) { | 361 } else if (lit->IsTrue() || lit->IsJSObject()) { |
| 335 __ b(true_label_); | 362 if (true_label_ != fall_through_) __ b(true_label_); |
| 336 } else if (lit->IsString()) { | 363 } else if (lit->IsString()) { |
| 337 if (String::cast(*lit)->length() == 0) { | 364 if (String::cast(*lit)->length() == 0) { |
| 365 if (false_label_ != fall_through_) __ b(false_label_); |
| 338 __ b(false_label_); | 366 __ b(false_label_); |
| 339 } else { | 367 } else { |
| 340 __ b(true_label_); | 368 if (true_label_ != fall_through_) __ b(true_label_); |
| 341 } | 369 } |
| 342 } else if (lit->IsSmi()) { | 370 } else if (lit->IsSmi()) { |
| 343 if (Smi::cast(*lit)->value() == 0) { | 371 if (Smi::cast(*lit)->value() == 0) { |
| 344 __ b(false_label_); | 372 if (false_label_ != fall_through_) __ b(false_label_); |
| 345 } else { | 373 } else { |
| 346 __ b(true_label_); | 374 if (true_label_ != fall_through_) __ b(true_label_); |
| 347 } | 375 } |
| 348 } else { | 376 } else { |
| 349 // For simplicity we always test the accumulator register. | 377 // For simplicity we always test the accumulator register. |
| 350 __ mov(result_register(), Operand(lit)); | 378 __ mov(result_register(), Operand(lit)); |
| 351 codegen()->DoTest(true_label_, false_label_, fall_through_); | 379 codegen()->DoTest(true_label_, false_label_, fall_through_); |
| 352 } | 380 } |
| 353 } | 381 } |
| 354 | 382 |
| 355 | 383 |
| 356 void FullCodeGenerator::EffectContext::DropAndPlug(int count, | 384 void FullCodeGenerator::EffectContext::DropAndPlug(int count, |
| (...skipping 19 matching lines...) Expand all Loading... |
| 376 __ str(reg, MemOperand(sp, 0)); | 404 __ str(reg, MemOperand(sp, 0)); |
| 377 } | 405 } |
| 378 | 406 |
| 379 | 407 |
| 380 void FullCodeGenerator::TestContext::DropAndPlug(int count, | 408 void FullCodeGenerator::TestContext::DropAndPlug(int count, |
| 381 Register reg) const { | 409 Register reg) const { |
| 382 ASSERT(count > 0); | 410 ASSERT(count > 0); |
| 383 // For simplicity we always test the accumulator register. | 411 // For simplicity we always test the accumulator register. |
| 384 __ Drop(count); | 412 __ Drop(count); |
| 385 __ Move(result_register(), reg); | 413 __ Move(result_register(), reg); |
| 414 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 386 codegen()->DoTest(true_label_, false_label_, fall_through_); | 415 codegen()->DoTest(true_label_, false_label_, fall_through_); |
| 387 } | 416 } |
| 388 | 417 |
| 389 | 418 |
| 390 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, | 419 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, |
| 391 Label* materialize_false) const { | 420 Label* materialize_false) const { |
| 392 ASSERT_EQ(materialize_true, materialize_false); | 421 ASSERT(materialize_true == materialize_false); |
| 393 __ bind(materialize_true); | 422 __ bind(materialize_true); |
| 394 } | 423 } |
| 395 | 424 |
| 396 | 425 |
| 397 void FullCodeGenerator::AccumulatorValueContext::Plug( | 426 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 398 Label* materialize_true, | 427 Label* materialize_true, |
| 399 Label* materialize_false) const { | 428 Label* materialize_false) const { |
| 400 Label done; | 429 Label done; |
| 401 __ bind(materialize_true); | 430 __ bind(materialize_true); |
| 402 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex); | 431 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 417 __ jmp(&done); | 446 __ jmp(&done); |
| 418 __ bind(materialize_false); | 447 __ bind(materialize_false); |
| 419 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 448 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
| 420 __ push(ip); | 449 __ push(ip); |
| 421 __ bind(&done); | 450 __ bind(&done); |
| 422 } | 451 } |
| 423 | 452 |
| 424 | 453 |
| 425 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, | 454 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, |
| 426 Label* materialize_false) const { | 455 Label* materialize_false) const { |
| 456 ASSERT(materialize_true == true_label_); |
| 427 ASSERT(materialize_false == false_label_); | 457 ASSERT(materialize_false == false_label_); |
| 428 ASSERT(materialize_true == true_label_); | |
| 429 } | 458 } |
| 430 | 459 |
| 431 | 460 |
| 432 void FullCodeGenerator::EffectContext::Plug(bool flag) const { | 461 void FullCodeGenerator::EffectContext::Plug(bool flag) const { |
| 433 } | 462 } |
| 434 | 463 |
| 435 | 464 |
| 436 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const { | 465 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const { |
| 437 Heap::RootListIndex value_root_index = | 466 Heap::RootListIndex value_root_index = |
| 438 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; | 467 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; |
| 439 __ LoadRoot(result_register(), value_root_index); | 468 __ LoadRoot(result_register(), value_root_index); |
| 440 } | 469 } |
| 441 | 470 |
| 442 | 471 |
| 443 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { | 472 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { |
| 444 Heap::RootListIndex value_root_index = | 473 Heap::RootListIndex value_root_index = |
| 445 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; | 474 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; |
| 446 __ LoadRoot(ip, value_root_index); | 475 __ LoadRoot(ip, value_root_index); |
| 447 __ push(ip); | 476 __ push(ip); |
| 448 } | 477 } |
| 449 | 478 |
| 450 | 479 |
| 451 void FullCodeGenerator::TestContext::Plug(bool flag) const { | 480 void FullCodeGenerator::TestContext::Plug(bool flag) const { |
| 481 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, |
| 482 true, |
| 483 true_label_, |
| 484 false_label_); |
| 452 if (flag) { | 485 if (flag) { |
| 453 if (true_label_ != fall_through_) __ b(true_label_); | 486 if (true_label_ != fall_through_) __ b(true_label_); |
| 454 } else { | 487 } else { |
| 455 if (false_label_ != fall_through_) __ b(false_label_); | 488 if (false_label_ != fall_through_) __ b(false_label_); |
| 456 } | 489 } |
| 457 } | 490 } |
| 458 | 491 |
| 459 | 492 |
| 460 void FullCodeGenerator::DoTest(Label* if_true, | 493 void FullCodeGenerator::DoTest(Label* if_true, |
| 461 Label* if_false, | 494 Label* if_false, |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 // Emit the write barrier code if the location is in the heap. | 555 // Emit the write barrier code if the location is in the heap. |
| 523 if (dst->type() == Slot::CONTEXT) { | 556 if (dst->type() == Slot::CONTEXT) { |
| 524 __ RecordWrite(scratch1, | 557 __ RecordWrite(scratch1, |
| 525 Operand(Context::SlotOffset(dst->index())), | 558 Operand(Context::SlotOffset(dst->index())), |
| 526 scratch2, | 559 scratch2, |
| 527 src); | 560 src); |
| 528 } | 561 } |
| 529 } | 562 } |
| 530 | 563 |
| 531 | 564 |
| 565 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
| 566 bool should_normalize, |
| 567 Label* if_true, |
| 568 Label* if_false) { |
| 569 // Only prepare for bailouts before splits if we're in a test |
| 570 // context. Otherwise, we let the Visit function deal with the |
| 571 // preparation to avoid preparing with the same AST id twice. |
| 572 if (!context()->IsTest() || !info_->IsOptimizable()) return; |
| 573 |
| 574 Label skip; |
| 575 if (should_normalize) __ b(&skip); |
| 576 |
| 577 ForwardBailoutStack* current = forward_bailout_stack_; |
| 578 while (current != NULL) { |
| 579 PrepareForBailout(current->expr(), state); |
| 580 current = current->parent(); |
| 581 } |
| 582 |
| 583 if (should_normalize) { |
| 584 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 585 __ cmp(r0, ip); |
| 586 Split(eq, if_true, if_false, NULL); |
| 587 __ bind(&skip); |
| 588 } |
| 589 } |
| 590 |
| 591 |
| 532 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 592 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
| 533 Variable::Mode mode, | 593 Variable::Mode mode, |
| 534 FunctionLiteral* function) { | 594 FunctionLiteral* function) { |
| 535 Comment cmnt(masm_, "[ Declaration"); | 595 Comment cmnt(masm_, "[ Declaration"); |
| 536 ASSERT(variable != NULL); // Must have been resolved. | 596 ASSERT(variable != NULL); // Must have been resolved. |
| 537 Slot* slot = variable->AsSlot(); | 597 Slot* slot = variable->AsSlot(); |
| 538 Property* prop = variable->AsProperty(); | 598 Property* prop = variable->AsProperty(); |
| 539 | 599 |
| 540 if (slot != NULL) { | 600 if (slot != NULL) { |
| 541 switch (slot->type()) { | 601 switch (slot->type()) { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 645 } | 705 } |
| 646 | 706 |
| 647 | 707 |
| 648 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 708 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
| 649 Comment cmnt(masm_, "[ SwitchStatement"); | 709 Comment cmnt(masm_, "[ SwitchStatement"); |
| 650 Breakable nested_statement(this, stmt); | 710 Breakable nested_statement(this, stmt); |
| 651 SetStatementPosition(stmt); | 711 SetStatementPosition(stmt); |
| 652 // Keep the switch value on the stack until a case matches. | 712 // Keep the switch value on the stack until a case matches. |
| 653 VisitForStackValue(stmt->tag()); | 713 VisitForStackValue(stmt->tag()); |
| 654 | 714 |
| 715 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
| 716 |
| 655 ZoneList<CaseClause*>* clauses = stmt->cases(); | 717 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 656 CaseClause* default_clause = NULL; // Can occur anywhere in the list. | 718 CaseClause* default_clause = NULL; // Can occur anywhere in the list. |
| 657 | 719 |
| 658 Label next_test; // Recycled for each test. | 720 Label next_test; // Recycled for each test. |
| 659 // Compile all the tests with branches to their bodies. | 721 // Compile all the tests with branches to their bodies. |
| 660 for (int i = 0; i < clauses->length(); i++) { | 722 for (int i = 0; i < clauses->length(); i++) { |
| 661 CaseClause* clause = clauses->at(i); | 723 CaseClause* clause = clauses->at(i); |
| 662 // The default is not a test, but remember it as final fall through. | 724 // The default is not a test, but remember it as final fall through. |
| 663 if (clause->is_default()) { | 725 if (clause->is_default()) { |
| 664 default_clause = clause; | 726 default_clause = clause; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 | 772 |
| 711 // Compile all the case bodies. | 773 // Compile all the case bodies. |
| 712 for (int i = 0; i < clauses->length(); i++) { | 774 for (int i = 0; i < clauses->length(); i++) { |
| 713 Comment cmnt(masm_, "[ Case body"); | 775 Comment cmnt(masm_, "[ Case body"); |
| 714 CaseClause* clause = clauses->at(i); | 776 CaseClause* clause = clauses->at(i); |
| 715 __ bind(clause->body_target()->entry_label()); | 777 __ bind(clause->body_target()->entry_label()); |
| 716 VisitStatements(clause->statements()); | 778 VisitStatements(clause->statements()); |
| 717 } | 779 } |
| 718 | 780 |
| 719 __ bind(nested_statement.break_target()); | 781 __ bind(nested_statement.break_target()); |
| 782 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 720 } | 783 } |
| 721 | 784 |
| 722 | 785 |
| 723 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 786 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 724 Comment cmnt(masm_, "[ ForInStatement"); | 787 Comment cmnt(masm_, "[ ForInStatement"); |
| 725 SetStatementPosition(stmt); | 788 SetStatementPosition(stmt); |
| 726 | 789 |
| 727 Label loop, exit; | 790 Label loop, exit; |
| 728 ForIn loop_statement(this, stmt); | 791 ForIn loop_statement(this, stmt); |
| 729 increment_loop_depth(); | 792 increment_loop_depth(); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 824 __ b(eq, loop_statement.continue_target()); | 887 __ b(eq, loop_statement.continue_target()); |
| 825 | 888 |
| 826 // Update the 'each' property or variable from the possibly filtered | 889 // Update the 'each' property or variable from the possibly filtered |
| 827 // entry in register r3. | 890 // entry in register r3. |
| 828 __ bind(&update_each); | 891 __ bind(&update_each); |
| 829 __ mov(result_register(), r3); | 892 __ mov(result_register(), r3); |
| 830 // Perform the assignment as if via '='. | 893 // Perform the assignment as if via '='. |
| 831 EmitAssignment(stmt->each()); | 894 EmitAssignment(stmt->each()); |
| 832 | 895 |
| 833 // Generate code for the body of the loop. | 896 // Generate code for the body of the loop. |
| 834 Label stack_limit_hit, stack_check_done; | |
| 835 Visit(stmt->body()); | 897 Visit(stmt->body()); |
| 836 | 898 |
| 837 __ StackLimitCheck(&stack_limit_hit); | |
| 838 __ bind(&stack_check_done); | |
| 839 | |
| 840 // Generate code for the going to the next element by incrementing | 899 // Generate code for the going to the next element by incrementing |
| 841 // the index (smi) stored on top of the stack. | 900 // the index (smi) stored on top of the stack. |
| 842 __ bind(loop_statement.continue_target()); | 901 __ bind(loop_statement.continue_target()); |
| 843 __ pop(r0); | 902 __ pop(r0); |
| 844 __ add(r0, r0, Operand(Smi::FromInt(1))); | 903 __ add(r0, r0, Operand(Smi::FromInt(1))); |
| 845 __ push(r0); | 904 __ push(r0); |
| 905 |
| 906 EmitStackCheck(stmt); |
| 846 __ b(&loop); | 907 __ b(&loop); |
| 847 | 908 |
| 848 // Slow case for the stack limit check. | |
| 849 StackCheckStub stack_check_stub; | |
| 850 __ bind(&stack_limit_hit); | |
| 851 __ CallStub(&stack_check_stub); | |
| 852 __ b(&stack_check_done); | |
| 853 | |
| 854 // Remove the pointers stored on the stack. | 909 // Remove the pointers stored on the stack. |
| 855 __ bind(loop_statement.break_target()); | 910 __ bind(loop_statement.break_target()); |
| 856 __ Drop(5); | 911 __ Drop(5); |
| 857 | 912 |
| 858 // Exit and decrement the loop depth. | 913 // Exit and decrement the loop depth. |
| 859 __ bind(&exit); | 914 __ bind(&exit); |
| 860 decrement_loop_depth(); | 915 decrement_loop_depth(); |
| 861 } | 916 } |
| 862 | 917 |
| 863 | 918 |
| (...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1193 result_saved = true; | 1248 result_saved = true; |
| 1194 } | 1249 } |
| 1195 switch (property->kind()) { | 1250 switch (property->kind()) { |
| 1196 case ObjectLiteral::Property::CONSTANT: | 1251 case ObjectLiteral::Property::CONSTANT: |
| 1197 UNREACHABLE(); | 1252 UNREACHABLE(); |
| 1198 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1253 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 1199 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); | 1254 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); |
| 1200 // Fall through. | 1255 // Fall through. |
| 1201 case ObjectLiteral::Property::COMPUTED: | 1256 case ObjectLiteral::Property::COMPUTED: |
| 1202 if (key->handle()->IsSymbol()) { | 1257 if (key->handle()->IsSymbol()) { |
| 1203 VisitForAccumulatorValue(value); | |
| 1204 __ mov(r2, Operand(key->handle())); | |
| 1205 __ ldr(r1, MemOperand(sp)); | |
| 1206 if (property->emit_store()) { | 1258 if (property->emit_store()) { |
| 1259 VisitForAccumulatorValue(value); |
| 1260 __ mov(r2, Operand(key->handle())); |
| 1261 __ ldr(r1, MemOperand(sp)); |
| 1207 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 1262 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
| 1208 Builtins::StoreIC_Initialize)); | 1263 Builtins::StoreIC_Initialize)); |
| 1209 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1264 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1265 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1266 } else { |
| 1267 VisitForEffect(value); |
| 1210 } | 1268 } |
| 1211 break; | 1269 break; |
| 1212 } | 1270 } |
| 1213 // Fall through. | 1271 // Fall through. |
| 1214 case ObjectLiteral::Property::PROTOTYPE: | 1272 case ObjectLiteral::Property::PROTOTYPE: |
| 1215 // Duplicate receiver on stack. | 1273 // Duplicate receiver on stack. |
| 1216 __ ldr(r0, MemOperand(sp)); | 1274 __ ldr(r0, MemOperand(sp)); |
| 1217 __ push(r0); | 1275 __ push(r0); |
| 1218 VisitForStackValue(key); | 1276 VisitForStackValue(key); |
| 1219 VisitForStackValue(value); | 1277 VisitForStackValue(value); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1294 | 1352 |
| 1295 // Store the subexpression value in the array's elements. | 1353 // Store the subexpression value in the array's elements. |
| 1296 __ ldr(r1, MemOperand(sp)); // Copy of array literal. | 1354 __ ldr(r1, MemOperand(sp)); // Copy of array literal. |
| 1297 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); | 1355 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); |
| 1298 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1356 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
| 1299 __ str(result_register(), FieldMemOperand(r1, offset)); | 1357 __ str(result_register(), FieldMemOperand(r1, offset)); |
| 1300 | 1358 |
| 1301 // Update the write barrier for the array store with r0 as the scratch | 1359 // Update the write barrier for the array store with r0 as the scratch |
| 1302 // register. | 1360 // register. |
| 1303 __ RecordWrite(r1, Operand(offset), r2, result_register()); | 1361 __ RecordWrite(r1, Operand(offset), r2, result_register()); |
| 1362 |
| 1363 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
| 1304 } | 1364 } |
| 1305 | 1365 |
| 1306 if (result_saved) { | 1366 if (result_saved) { |
| 1307 context()->PlugTOS(); | 1367 context()->PlugTOS(); |
| 1308 } else { | 1368 } else { |
| 1309 context()->Plug(r0); | 1369 context()->Plug(r0); |
| 1310 } | 1370 } |
| 1311 } | 1371 } |
| 1312 | 1372 |
| 1313 | 1373 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1340 if (expr->is_compound()) { | 1400 if (expr->is_compound()) { |
| 1341 // We need the receiver both on the stack and in the accumulator. | 1401 // We need the receiver both on the stack and in the accumulator. |
| 1342 VisitForAccumulatorValue(property->obj()); | 1402 VisitForAccumulatorValue(property->obj()); |
| 1343 __ push(result_register()); | 1403 __ push(result_register()); |
| 1344 } else { | 1404 } else { |
| 1345 VisitForStackValue(property->obj()); | 1405 VisitForStackValue(property->obj()); |
| 1346 } | 1406 } |
| 1347 break; | 1407 break; |
| 1348 case KEYED_PROPERTY: | 1408 case KEYED_PROPERTY: |
| 1349 if (expr->is_compound()) { | 1409 if (expr->is_compound()) { |
| 1350 VisitForStackValue(property->obj()); | 1410 if (property->is_arguments_access()) { |
| 1351 VisitForAccumulatorValue(property->key()); | 1411 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1412 __ ldr(r0, EmitSlotSearch(obj_proxy->var()->AsSlot(), r0)); |
| 1413 __ push(r0); |
| 1414 __ mov(r0, Operand(property->key()->AsLiteral()->handle())); |
| 1415 } else { |
| 1416 VisitForStackValue(property->obj()); |
| 1417 VisitForAccumulatorValue(property->key()); |
| 1418 } |
| 1352 __ ldr(r1, MemOperand(sp, 0)); | 1419 __ ldr(r1, MemOperand(sp, 0)); |
| 1353 __ push(r0); | 1420 __ push(r0); |
| 1354 } else { | 1421 } else { |
| 1355 VisitForStackValue(property->obj()); | 1422 if (property->is_arguments_access()) { |
| 1356 VisitForStackValue(property->key()); | 1423 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1424 __ ldr(r1, EmitSlotSearch(obj_proxy->var()->AsSlot(), r0)); |
| 1425 __ mov(r0, Operand(property->key()->AsLiteral()->handle())); |
| 1426 __ Push(r1, r0); |
| 1427 } else { |
| 1428 VisitForStackValue(property->obj()); |
| 1429 VisitForStackValue(property->key()); |
| 1430 } |
| 1357 } | 1431 } |
| 1358 break; | 1432 break; |
| 1359 } | 1433 } |
| 1360 | 1434 |
| 1361 if (expr->is_compound()) { | 1435 if (expr->is_compound()) { |
| 1362 { AccumulatorValueContext context(this); | 1436 { AccumulatorValueContext context(this); |
| 1363 switch (assign_type) { | 1437 switch (assign_type) { |
| 1364 case VARIABLE: | 1438 case VARIABLE: |
| 1365 EmitVariableLoad(expr->target()->AsVariableProxy()->var()); | 1439 EmitVariableLoad(expr->target()->AsVariableProxy()->var()); |
| 1366 break; | 1440 break; |
| 1367 case NAMED_PROPERTY: | 1441 case NAMED_PROPERTY: |
| 1368 EmitNamedPropertyLoad(property); | 1442 EmitNamedPropertyLoad(property); |
| 1369 break; | 1443 break; |
| 1370 case KEYED_PROPERTY: | 1444 case KEYED_PROPERTY: |
| 1371 EmitKeyedPropertyLoad(property); | 1445 EmitKeyedPropertyLoad(property); |
| 1372 break; | 1446 break; |
| 1373 } | 1447 } |
| 1374 } | 1448 } |
| 1375 | 1449 |
| 1450 // For property compound assignments we need another deoptimization |
| 1451 // point after the property load. |
| 1452 if (property != NULL) { |
| 1453 PrepareForBailoutForId(expr->compound_bailout_id(), TOS_REG); |
| 1454 } |
| 1455 |
| 1376 Token::Value op = expr->binary_op(); | 1456 Token::Value op = expr->binary_op(); |
| 1377 ConstantOperand constant = ShouldInlineSmiCase(op) | 1457 ConstantOperand constant = ShouldInlineSmiCase(op) |
| 1378 ? GetConstantOperand(op, expr->target(), expr->value()) | 1458 ? GetConstantOperand(op, expr->target(), expr->value()) |
| 1379 : kNoConstants; | 1459 : kNoConstants; |
| 1380 ASSERT(constant == kRightConstant || constant == kNoConstants); | 1460 ASSERT(constant == kRightConstant || constant == kNoConstants); |
| 1381 if (constant == kNoConstants) { | 1461 if (constant == kNoConstants) { |
| 1382 __ push(r0); // Left operand goes on the stack. | 1462 __ push(r0); // Left operand goes on the stack. |
| 1383 VisitForAccumulatorValue(expr->value()); | 1463 VisitForAccumulatorValue(expr->value()); |
| 1384 } | 1464 } |
| 1385 | 1465 |
| 1386 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() | 1466 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() |
| 1387 ? OVERWRITE_RIGHT | 1467 ? OVERWRITE_RIGHT |
| 1388 : NO_OVERWRITE; | 1468 : NO_OVERWRITE; |
| 1389 SetSourcePosition(expr->position() + 1); | 1469 SetSourcePosition(expr->position() + 1); |
| 1390 AccumulatorValueContext context(this); | 1470 AccumulatorValueContext context(this); |
| 1391 if (ShouldInlineSmiCase(op)) { | 1471 if (ShouldInlineSmiCase(op)) { |
| 1392 EmitInlineSmiBinaryOp(expr, | 1472 EmitInlineSmiBinaryOp(expr, |
| 1393 op, | 1473 op, |
| 1394 mode, | 1474 mode, |
| 1395 expr->target(), | 1475 expr->target(), |
| 1396 expr->value(), | 1476 expr->value(), |
| 1397 constant); | 1477 constant); |
| 1398 } else { | 1478 } else { |
| 1399 EmitBinaryOp(op, mode); | 1479 EmitBinaryOp(op, mode); |
| 1400 } | 1480 } |
| 1481 |
| 1482 // Deoptimization point in case the binary operation may have side effects. |
| 1483 PrepareForBailout(expr->binary_operation(), TOS_REG); |
| 1401 } else { | 1484 } else { |
| 1402 VisitForAccumulatorValue(expr->value()); | 1485 VisitForAccumulatorValue(expr->value()); |
| 1403 } | 1486 } |
| 1404 | 1487 |
| 1405 // Record source position before possible IC call. | 1488 // Record source position before possible IC call. |
| 1406 SetSourcePosition(expr->position()); | 1489 SetSourcePosition(expr->position()); |
| 1407 | 1490 |
| 1408 // Store the value. | 1491 // Store the value. |
| 1409 switch (assign_type) { | 1492 switch (assign_type) { |
| 1410 case VARIABLE: | 1493 case VARIABLE: |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1682 } | 1765 } |
| 1683 | 1766 |
| 1684 | 1767 |
| 1685 void FullCodeGenerator::VisitProperty(Property* expr) { | 1768 void FullCodeGenerator::VisitProperty(Property* expr) { |
| 1686 Comment cmnt(masm_, "[ Property"); | 1769 Comment cmnt(masm_, "[ Property"); |
| 1687 Expression* key = expr->key(); | 1770 Expression* key = expr->key(); |
| 1688 | 1771 |
| 1689 if (key->IsPropertyName()) { | 1772 if (key->IsPropertyName()) { |
| 1690 VisitForAccumulatorValue(expr->obj()); | 1773 VisitForAccumulatorValue(expr->obj()); |
| 1691 EmitNamedPropertyLoad(expr); | 1774 EmitNamedPropertyLoad(expr); |
| 1775 context()->Plug(r0); |
| 1692 } else { | 1776 } else { |
| 1693 VisitForStackValue(expr->obj()); | 1777 VisitForStackValue(expr->obj()); |
| 1694 VisitForAccumulatorValue(expr->key()); | 1778 VisitForAccumulatorValue(expr->key()); |
| 1695 __ pop(r1); | 1779 __ pop(r1); |
| 1696 EmitKeyedPropertyLoad(expr); | 1780 EmitKeyedPropertyLoad(expr); |
| 1781 context()->Plug(r0); |
| 1697 } | 1782 } |
| 1698 context()->Plug(r0); | |
| 1699 } | 1783 } |
| 1700 | 1784 |
| 1701 void FullCodeGenerator::EmitCallWithIC(Call* expr, | 1785 void FullCodeGenerator::EmitCallWithIC(Call* expr, |
| 1702 Handle<Object> name, | 1786 Handle<Object> name, |
| 1703 RelocInfo::Mode mode) { | 1787 RelocInfo::Mode mode) { |
| 1704 // Code common for calls using the IC. | 1788 // Code common for calls using the IC. |
| 1705 ZoneList<Expression*>* args = expr->arguments(); | 1789 ZoneList<Expression*>* args = expr->arguments(); |
| 1706 int arg_count = args->length(); | 1790 int arg_count = args->length(); |
| 1707 { PreservePositionScope scope(masm()->positions_recorder()); | 1791 { PreservePositionScope scope(masm()->positions_recorder()); |
| 1708 for (int i = 0; i < arg_count; i++) { | 1792 for (int i = 0; i < arg_count; i++) { |
| 1709 VisitForStackValue(args->at(i)); | 1793 VisitForStackValue(args->at(i)); |
| 1710 } | 1794 } |
| 1711 __ mov(r2, Operand(name)); | 1795 __ mov(r2, Operand(name)); |
| 1712 } | 1796 } |
| 1713 // Record source position for debugger. | 1797 // Record source position for debugger. |
| 1714 SetSourcePosition(expr->position()); | 1798 SetSourcePosition(expr->position()); |
| 1715 // Call the IC initialization code. | 1799 // Call the IC initialization code. |
| 1716 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1800 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1717 Handle<Code> ic = | 1801 Handle<Code> ic = |
| 1718 ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop); | 1802 ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop); |
| 1719 EmitCallIC(ic, mode); | 1803 EmitCallIC(ic, mode); |
| 1804 RecordJSReturnSite(expr); |
| 1720 // Restore context register. | 1805 // Restore context register. |
| 1721 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1806 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 1722 context()->Plug(r0); | 1807 context()->Plug(r0); |
| 1723 } | 1808 } |
| 1724 | 1809 |
| 1725 | 1810 |
| 1726 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 1811 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 1727 Expression* key, | 1812 Expression* key, |
| 1728 RelocInfo::Mode mode) { | 1813 RelocInfo::Mode mode) { |
| 1729 // Load the key. | 1814 // Load the key. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1744 } | 1829 } |
| 1745 } | 1830 } |
| 1746 // Record source position for debugger. | 1831 // Record source position for debugger. |
| 1747 SetSourcePosition(expr->position()); | 1832 SetSourcePosition(expr->position()); |
| 1748 // Call the IC initialization code. | 1833 // Call the IC initialization code. |
| 1749 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1834 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1750 Handle<Code> ic = | 1835 Handle<Code> ic = |
| 1751 ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop); | 1836 ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop); |
| 1752 __ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key. | 1837 __ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key. |
| 1753 EmitCallIC(ic, mode); | 1838 EmitCallIC(ic, mode); |
| 1839 RecordJSReturnSite(expr); |
| 1754 // Restore context register. | 1840 // Restore context register. |
| 1755 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1841 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 1756 context()->DropAndPlug(1, r0); // Drop the key still on the stack. | 1842 context()->DropAndPlug(1, r0); // Drop the key still on the stack. |
| 1757 } | 1843 } |
| 1758 | 1844 |
| 1759 | 1845 |
| 1760 void FullCodeGenerator::EmitCallWithStub(Call* expr) { | 1846 void FullCodeGenerator::EmitCallWithStub(Call* expr) { |
| 1761 // Code common for calls using the call stub. | 1847 // Code common for calls using the call stub. |
| 1762 ZoneList<Expression*>* args = expr->arguments(); | 1848 ZoneList<Expression*>* args = expr->arguments(); |
| 1763 int arg_count = args->length(); | 1849 int arg_count = args->length(); |
| 1764 { PreservePositionScope scope(masm()->positions_recorder()); | 1850 { PreservePositionScope scope(masm()->positions_recorder()); |
| 1765 for (int i = 0; i < arg_count; i++) { | 1851 for (int i = 0; i < arg_count; i++) { |
| 1766 VisitForStackValue(args->at(i)); | 1852 VisitForStackValue(args->at(i)); |
| 1767 } | 1853 } |
| 1768 } | 1854 } |
| 1769 // Record source position for debugger. | 1855 // Record source position for debugger. |
| 1770 SetSourcePosition(expr->position()); | 1856 SetSourcePosition(expr->position()); |
| 1771 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1857 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1772 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 1858 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| 1773 __ CallStub(&stub); | 1859 __ CallStub(&stub); |
| 1860 RecordJSReturnSite(expr); |
| 1774 // Restore context register. | 1861 // Restore context register. |
| 1775 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1862 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 1776 context()->DropAndPlug(1, r0); | 1863 context()->DropAndPlug(1, r0); |
| 1777 } | 1864 } |
| 1778 | 1865 |
| 1779 | 1866 |
| 1780 void FullCodeGenerator::VisitCall(Call* expr) { | 1867 void FullCodeGenerator::VisitCall(Call* expr) { |
| 1868 #ifdef DEBUG |
| 1869 // We want to verify that RecordJSReturnSite gets called on all paths |
| 1870 // through this function. Avoid early returns. |
| 1871 expr->return_is_recorded_ = false; |
| 1872 #endif |
| 1873 |
| 1781 Comment cmnt(masm_, "[ Call"); | 1874 Comment cmnt(masm_, "[ Call"); |
| 1782 Expression* fun = expr->expression(); | 1875 Expression* fun = expr->expression(); |
| 1783 Variable* var = fun->AsVariableProxy()->AsVariable(); | 1876 Variable* var = fun->AsVariableProxy()->AsVariable(); |
| 1784 | 1877 |
| 1785 if (var != NULL && var->is_possibly_eval()) { | 1878 if (var != NULL && var->is_possibly_eval()) { |
| 1786 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 1879 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
| 1787 // resolve the function we need to call and the receiver of the | 1880 // resolve the function we need to call and the receiver of the |
| 1788 // call. Then we call the resolved function using the given | 1881 // call. Then we call the resolved function using the given |
| 1789 // arguments. | 1882 // arguments. |
| 1790 ZoneList<Expression*>* args = expr->arguments(); | 1883 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1822 // r1 (receiver). Touch up the stack with the right values. | 1915 // r1 (receiver). Touch up the stack with the right values. |
| 1823 __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize)); | 1916 __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 1824 __ str(r1, MemOperand(sp, arg_count * kPointerSize)); | 1917 __ str(r1, MemOperand(sp, arg_count * kPointerSize)); |
| 1825 } | 1918 } |
| 1826 | 1919 |
| 1827 // Record source position for debugger. | 1920 // Record source position for debugger. |
| 1828 SetSourcePosition(expr->position()); | 1921 SetSourcePosition(expr->position()); |
| 1829 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1922 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1830 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 1923 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| 1831 __ CallStub(&stub); | 1924 __ CallStub(&stub); |
| 1925 RecordJSReturnSite(expr); |
| 1832 // Restore context register. | 1926 // Restore context register. |
| 1833 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1927 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 1834 context()->DropAndPlug(1, r0); | 1928 context()->DropAndPlug(1, r0); |
| 1835 } else if (var != NULL && !var->is_this() && var->is_global()) { | 1929 } else if (var != NULL && !var->is_this() && var->is_global()) { |
| 1836 // Push global object as receiver for the call IC. | 1930 // Push global object as receiver for the call IC. |
| 1837 __ ldr(r0, GlobalObjectOperand()); | 1931 __ ldr(r0, GlobalObjectOperand()); |
| 1838 __ push(r0); | 1932 __ push(r0); |
| 1839 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); | 1933 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); |
| 1840 } else if (var != NULL && var->AsSlot() != NULL && | 1934 } else if (var != NULL && var->AsSlot() != NULL && |
| 1841 var->AsSlot()->type() == Slot::LOOKUP) { | 1935 var->AsSlot()->type() == Slot::LOOKUP) { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1927 { PreservePositionScope scope(masm()->positions_recorder()); | 2021 { PreservePositionScope scope(masm()->positions_recorder()); |
| 1928 VisitForStackValue(fun); | 2022 VisitForStackValue(fun); |
| 1929 } | 2023 } |
| 1930 // Load global receiver object. | 2024 // Load global receiver object. |
| 1931 __ ldr(r1, GlobalObjectOperand()); | 2025 __ ldr(r1, GlobalObjectOperand()); |
| 1932 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); | 2026 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); |
| 1933 __ push(r1); | 2027 __ push(r1); |
| 1934 // Emit function call. | 2028 // Emit function call. |
| 1935 EmitCallWithStub(expr); | 2029 EmitCallWithStub(expr); |
| 1936 } | 2030 } |
| 2031 |
| 2032 #ifdef DEBUG |
| 2033 // RecordJSReturnSite should have been called. |
| 2034 ASSERT(expr->return_is_recorded_); |
| 2035 #endif |
| 1937 } | 2036 } |
| 1938 | 2037 |
| 1939 | 2038 |
| 1940 void FullCodeGenerator::VisitCallNew(CallNew* expr) { | 2039 void FullCodeGenerator::VisitCallNew(CallNew* expr) { |
| 1941 Comment cmnt(masm_, "[ CallNew"); | 2040 Comment cmnt(masm_, "[ CallNew"); |
| 1942 // According to ECMA-262, section 11.2.2, page 44, the function | 2041 // According to ECMA-262, section 11.2.2, page 44, the function |
| 1943 // expression in new calls must be evaluated before the | 2042 // expression in new calls must be evaluated before the |
| 1944 // arguments. | 2043 // arguments. |
| 1945 | 2044 |
| 1946 // Push constructor on the stack. If it's not a function it's used as | 2045 // Push constructor on the stack. If it's not a function it's used as |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1975 | 2074 |
| 1976 VisitForAccumulatorValue(args->at(0)); | 2075 VisitForAccumulatorValue(args->at(0)); |
| 1977 | 2076 |
| 1978 Label materialize_true, materialize_false; | 2077 Label materialize_true, materialize_false; |
| 1979 Label* if_true = NULL; | 2078 Label* if_true = NULL; |
| 1980 Label* if_false = NULL; | 2079 Label* if_false = NULL; |
| 1981 Label* fall_through = NULL; | 2080 Label* fall_through = NULL; |
| 1982 context()->PrepareTest(&materialize_true, &materialize_false, | 2081 context()->PrepareTest(&materialize_true, &materialize_false, |
| 1983 &if_true, &if_false, &fall_through); | 2082 &if_true, &if_false, &fall_through); |
| 1984 | 2083 |
| 1985 __ BranchOnSmi(r0, if_true); | 2084 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 1986 __ b(if_false); | 2085 __ tst(r0, Operand(kSmiTagMask)); |
| 2086 Split(eq, if_true, if_false, fall_through); |
| 1987 | 2087 |
| 1988 context()->Plug(if_true, if_false); | 2088 context()->Plug(if_true, if_false); |
| 1989 } | 2089 } |
| 1990 | 2090 |
| 1991 | 2091 |
| 1992 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { | 2092 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 1993 ASSERT(args->length() == 1); | 2093 ASSERT(args->length() == 1); |
| 1994 | 2094 |
| 1995 VisitForAccumulatorValue(args->at(0)); | 2095 VisitForAccumulatorValue(args->at(0)); |
| 1996 | 2096 |
| 1997 Label materialize_true, materialize_false; | 2097 Label materialize_true, materialize_false; |
| 1998 Label* if_true = NULL; | 2098 Label* if_true = NULL; |
| 1999 Label* if_false = NULL; | 2099 Label* if_false = NULL; |
| 2000 Label* fall_through = NULL; | 2100 Label* fall_through = NULL; |
| 2001 context()->PrepareTest(&materialize_true, &materialize_false, | 2101 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2002 &if_true, &if_false, &fall_through); | 2102 &if_true, &if_false, &fall_through); |
| 2003 | 2103 |
| 2104 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2004 __ tst(r0, Operand(kSmiTagMask | 0x80000000)); | 2105 __ tst(r0, Operand(kSmiTagMask | 0x80000000)); |
| 2005 Split(eq, if_true, if_false, fall_through); | 2106 Split(eq, if_true, if_false, fall_through); |
| 2006 | 2107 |
| 2007 context()->Plug(if_true, if_false); | 2108 context()->Plug(if_true, if_false); |
| 2008 } | 2109 } |
| 2009 | 2110 |
| 2010 | 2111 |
| 2011 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { | 2112 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { |
| 2012 ASSERT(args->length() == 1); | 2113 ASSERT(args->length() == 1); |
| 2013 | 2114 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2026 __ b(eq, if_true); | 2127 __ b(eq, if_true); |
| 2027 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); | 2128 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 2028 // Undetectable objects behave like undefined when tested with typeof. | 2129 // Undetectable objects behave like undefined when tested with typeof. |
| 2029 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset)); | 2130 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset)); |
| 2030 __ tst(r1, Operand(1 << Map::kIsUndetectable)); | 2131 __ tst(r1, Operand(1 << Map::kIsUndetectable)); |
| 2031 __ b(ne, if_false); | 2132 __ b(ne, if_false); |
| 2032 __ ldrb(r1, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 2133 __ ldrb(r1, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| 2033 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); | 2134 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); |
| 2034 __ b(lt, if_false); | 2135 __ b(lt, if_false); |
| 2035 __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); | 2136 __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); |
| 2137 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2036 Split(le, if_true, if_false, fall_through); | 2138 Split(le, if_true, if_false, fall_through); |
| 2037 | 2139 |
| 2038 context()->Plug(if_true, if_false); | 2140 context()->Plug(if_true, if_false); |
| 2039 } | 2141 } |
| 2040 | 2142 |
| 2041 | 2143 |
| 2042 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { | 2144 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { |
| 2043 ASSERT(args->length() == 1); | 2145 ASSERT(args->length() == 1); |
| 2044 | 2146 |
| 2045 VisitForAccumulatorValue(args->at(0)); | 2147 VisitForAccumulatorValue(args->at(0)); |
| 2046 | 2148 |
| 2047 Label materialize_true, materialize_false; | 2149 Label materialize_true, materialize_false; |
| 2048 Label* if_true = NULL; | 2150 Label* if_true = NULL; |
| 2049 Label* if_false = NULL; | 2151 Label* if_false = NULL; |
| 2050 Label* fall_through = NULL; | 2152 Label* fall_through = NULL; |
| 2051 context()->PrepareTest(&materialize_true, &materialize_false, | 2153 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2052 &if_true, &if_false, &fall_through); | 2154 &if_true, &if_false, &fall_through); |
| 2053 | 2155 |
| 2054 __ BranchOnSmi(r0, if_false); | 2156 __ BranchOnSmi(r0, if_false); |
| 2055 __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE); | 2157 __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE); |
| 2158 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2056 Split(ge, if_true, if_false, fall_through); | 2159 Split(ge, if_true, if_false, fall_through); |
| 2057 | 2160 |
| 2058 context()->Plug(if_true, if_false); | 2161 context()->Plug(if_true, if_false); |
| 2059 } | 2162 } |
| 2060 | 2163 |
| 2061 | 2164 |
| 2062 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { | 2165 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { |
| 2063 ASSERT(args->length() == 1); | 2166 ASSERT(args->length() == 1); |
| 2064 | 2167 |
| 2065 VisitForAccumulatorValue(args->at(0)); | 2168 VisitForAccumulatorValue(args->at(0)); |
| 2066 | 2169 |
| 2067 Label materialize_true, materialize_false; | 2170 Label materialize_true, materialize_false; |
| 2068 Label* if_true = NULL; | 2171 Label* if_true = NULL; |
| 2069 Label* if_false = NULL; | 2172 Label* if_false = NULL; |
| 2070 Label* fall_through = NULL; | 2173 Label* fall_through = NULL; |
| 2071 context()->PrepareTest(&materialize_true, &materialize_false, | 2174 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2072 &if_true, &if_false, &fall_through); | 2175 &if_true, &if_false, &fall_through); |
| 2073 | 2176 |
| 2074 __ BranchOnSmi(r0, if_false); | 2177 __ BranchOnSmi(r0, if_false); |
| 2075 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 2178 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 2076 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset)); | 2179 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset)); |
| 2077 __ tst(r1, Operand(1 << Map::kIsUndetectable)); | 2180 __ tst(r1, Operand(1 << Map::kIsUndetectable)); |
| 2181 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2078 Split(ne, if_true, if_false, fall_through); | 2182 Split(ne, if_true, if_false, fall_through); |
| 2079 | 2183 |
| 2080 context()->Plug(if_true, if_false); | 2184 context()->Plug(if_true, if_false); |
| 2081 } | 2185 } |
| 2082 | 2186 |
| 2083 | 2187 |
| 2084 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( | 2188 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( |
| 2085 ZoneList<Expression*>* args) { | 2189 ZoneList<Expression*>* args) { |
| 2086 | 2190 |
| 2087 ASSERT(args->length() == 1); | 2191 ASSERT(args->length() == 1); |
| 2088 | 2192 |
| 2089 VisitForAccumulatorValue(args->at(0)); | 2193 VisitForAccumulatorValue(args->at(0)); |
| 2090 | 2194 |
| 2091 Label materialize_true, materialize_false; | 2195 Label materialize_true, materialize_false; |
| 2092 Label* if_true = NULL; | 2196 Label* if_true = NULL; |
| 2093 Label* if_false = NULL; | 2197 Label* if_false = NULL; |
| 2094 Label* fall_through = NULL; | 2198 Label* fall_through = NULL; |
| 2095 context()->PrepareTest(&materialize_true, &materialize_false, | 2199 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2096 &if_true, &if_false, &fall_through); | 2200 &if_true, &if_false, &fall_through); |
| 2097 | 2201 |
| 2098 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only | 2202 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only |
| 2099 // used in a few functions in runtime.js which should not normally be hit by | 2203 // used in a few functions in runtime.js which should not normally be hit by |
| 2100 // this compiler. | 2204 // this compiler. |
| 2205 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2101 __ jmp(if_false); | 2206 __ jmp(if_false); |
| 2102 context()->Plug(if_true, if_false); | 2207 context()->Plug(if_true, if_false); |
| 2103 } | 2208 } |
| 2104 | 2209 |
| 2105 | 2210 |
| 2106 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { | 2211 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { |
| 2107 ASSERT(args->length() == 1); | 2212 ASSERT(args->length() == 1); |
| 2108 | 2213 |
| 2109 VisitForAccumulatorValue(args->at(0)); | 2214 VisitForAccumulatorValue(args->at(0)); |
| 2110 | 2215 |
| 2111 Label materialize_true, materialize_false; | 2216 Label materialize_true, materialize_false; |
| 2112 Label* if_true = NULL; | 2217 Label* if_true = NULL; |
| 2113 Label* if_false = NULL; | 2218 Label* if_false = NULL; |
| 2114 Label* fall_through = NULL; | 2219 Label* fall_through = NULL; |
| 2115 context()->PrepareTest(&materialize_true, &materialize_false, | 2220 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2116 &if_true, &if_false, &fall_through); | 2221 &if_true, &if_false, &fall_through); |
| 2117 | 2222 |
| 2118 __ BranchOnSmi(r0, if_false); | 2223 __ BranchOnSmi(r0, if_false); |
| 2119 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE); | 2224 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE); |
| 2225 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2120 Split(eq, if_true, if_false, fall_through); | 2226 Split(eq, if_true, if_false, fall_through); |
| 2121 | 2227 |
| 2122 context()->Plug(if_true, if_false); | 2228 context()->Plug(if_true, if_false); |
| 2123 } | 2229 } |
| 2124 | 2230 |
| 2125 | 2231 |
| 2126 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { | 2232 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { |
| 2127 ASSERT(args->length() == 1); | 2233 ASSERT(args->length() == 1); |
| 2128 | 2234 |
| 2129 VisitForAccumulatorValue(args->at(0)); | 2235 VisitForAccumulatorValue(args->at(0)); |
| 2130 | 2236 |
| 2131 Label materialize_true, materialize_false; | 2237 Label materialize_true, materialize_false; |
| 2132 Label* if_true = NULL; | 2238 Label* if_true = NULL; |
| 2133 Label* if_false = NULL; | 2239 Label* if_false = NULL; |
| 2134 Label* fall_through = NULL; | 2240 Label* fall_through = NULL; |
| 2135 context()->PrepareTest(&materialize_true, &materialize_false, | 2241 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2136 &if_true, &if_false, &fall_through); | 2242 &if_true, &if_false, &fall_through); |
| 2137 | 2243 |
| 2138 __ BranchOnSmi(r0, if_false); | 2244 __ BranchOnSmi(r0, if_false); |
| 2139 __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE); | 2245 __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE); |
| 2246 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2140 Split(eq, if_true, if_false, fall_through); | 2247 Split(eq, if_true, if_false, fall_through); |
| 2141 | 2248 |
| 2142 context()->Plug(if_true, if_false); | 2249 context()->Plug(if_true, if_false); |
| 2143 } | 2250 } |
| 2144 | 2251 |
| 2145 | 2252 |
| 2146 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { | 2253 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { |
| 2147 ASSERT(args->length() == 1); | 2254 ASSERT(args->length() == 1); |
| 2148 | 2255 |
| 2149 VisitForAccumulatorValue(args->at(0)); | 2256 VisitForAccumulatorValue(args->at(0)); |
| 2150 | 2257 |
| 2151 Label materialize_true, materialize_false; | 2258 Label materialize_true, materialize_false; |
| 2152 Label* if_true = NULL; | 2259 Label* if_true = NULL; |
| 2153 Label* if_false = NULL; | 2260 Label* if_false = NULL; |
| 2154 Label* fall_through = NULL; | 2261 Label* fall_through = NULL; |
| 2155 context()->PrepareTest(&materialize_true, &materialize_false, | 2262 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2156 &if_true, &if_false, &fall_through); | 2263 &if_true, &if_false, &fall_through); |
| 2157 | 2264 |
| 2158 __ BranchOnSmi(r0, if_false); | 2265 __ BranchOnSmi(r0, if_false); |
| 2159 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); | 2266 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); |
| 2267 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2160 Split(eq, if_true, if_false, fall_through); | 2268 Split(eq, if_true, if_false, fall_through); |
| 2161 | 2269 |
| 2162 context()->Plug(if_true, if_false); | 2270 context()->Plug(if_true, if_false); |
| 2163 } | 2271 } |
| 2164 | 2272 |
| 2165 | 2273 |
| 2166 | 2274 |
| 2167 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { | 2275 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { |
| 2168 ASSERT(args->length() == 0); | 2276 ASSERT(args->length() == 0); |
| 2169 | 2277 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2181 Label check_frame_marker; | 2289 Label check_frame_marker; |
| 2182 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kContextOffset)); | 2290 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kContextOffset)); |
| 2183 __ cmp(r1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 2291 __ cmp(r1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2184 __ b(ne, &check_frame_marker); | 2292 __ b(ne, &check_frame_marker); |
| 2185 __ ldr(r2, MemOperand(r2, StandardFrameConstants::kCallerFPOffset)); | 2293 __ ldr(r2, MemOperand(r2, StandardFrameConstants::kCallerFPOffset)); |
| 2186 | 2294 |
| 2187 // Check the marker in the calling frame. | 2295 // Check the marker in the calling frame. |
| 2188 __ bind(&check_frame_marker); | 2296 __ bind(&check_frame_marker); |
| 2189 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset)); | 2297 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset)); |
| 2190 __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT))); | 2298 __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT))); |
| 2299 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2191 Split(eq, if_true, if_false, fall_through); | 2300 Split(eq, if_true, if_false, fall_through); |
| 2192 | 2301 |
| 2193 context()->Plug(if_true, if_false); | 2302 context()->Plug(if_true, if_false); |
| 2194 } | 2303 } |
| 2195 | 2304 |
| 2196 | 2305 |
| 2197 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { | 2306 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { |
| 2198 ASSERT(args->length() == 2); | 2307 ASSERT(args->length() == 2); |
| 2199 | 2308 |
| 2200 // Load the two objects into registers and perform the comparison. | 2309 // Load the two objects into registers and perform the comparison. |
| 2201 VisitForStackValue(args->at(0)); | 2310 VisitForStackValue(args->at(0)); |
| 2202 VisitForAccumulatorValue(args->at(1)); | 2311 VisitForAccumulatorValue(args->at(1)); |
| 2203 | 2312 |
| 2204 Label materialize_true, materialize_false; | 2313 Label materialize_true, materialize_false; |
| 2205 Label* if_true = NULL; | 2314 Label* if_true = NULL; |
| 2206 Label* if_false = NULL; | 2315 Label* if_false = NULL; |
| 2207 Label* fall_through = NULL; | 2316 Label* fall_through = NULL; |
| 2208 context()->PrepareTest(&materialize_true, &materialize_false, | 2317 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2209 &if_true, &if_false, &fall_through); | 2318 &if_true, &if_false, &fall_through); |
| 2210 | 2319 |
| 2211 __ pop(r1); | 2320 __ pop(r1); |
| 2212 __ cmp(r0, r1); | 2321 __ cmp(r0, r1); |
| 2322 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2213 Split(eq, if_true, if_false, fall_through); | 2323 Split(eq, if_true, if_false, fall_through); |
| 2214 | 2324 |
| 2215 context()->Plug(if_true, if_false); | 2325 context()->Plug(if_true, if_false); |
| 2216 } | 2326 } |
| 2217 | 2327 |
| 2218 | 2328 |
| 2219 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2329 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
| 2220 ASSERT(args->length() == 1); | 2330 ASSERT(args->length() == 1); |
| 2221 | 2331 |
| 2222 // ArgumentsAccessStub expects the key in edx and the formal | 2332 // ArgumentsAccessStub expects the key in edx and the formal |
| (...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2656 // InvokeFunction requires function in r1. Move it in there. | 2766 // InvokeFunction requires function in r1. Move it in there. |
| 2657 if (!result_register().is(r1)) __ mov(r1, result_register()); | 2767 if (!result_register().is(r1)) __ mov(r1, result_register()); |
| 2658 ParameterCount count(arg_count); | 2768 ParameterCount count(arg_count); |
| 2659 __ InvokeFunction(r1, count, CALL_FUNCTION); | 2769 __ InvokeFunction(r1, count, CALL_FUNCTION); |
| 2660 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2770 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2661 context()->Plug(r0); | 2771 context()->Plug(r0); |
| 2662 } | 2772 } |
| 2663 | 2773 |
| 2664 | 2774 |
| 2665 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) { | 2775 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) { |
| 2776 RegExpConstructResultStub stub; |
| 2666 ASSERT(args->length() == 3); | 2777 ASSERT(args->length() == 3); |
| 2667 VisitForStackValue(args->at(0)); | 2778 VisitForStackValue(args->at(0)); |
| 2668 VisitForStackValue(args->at(1)); | 2779 VisitForStackValue(args->at(1)); |
| 2669 VisitForStackValue(args->at(2)); | 2780 VisitForStackValue(args->at(2)); |
| 2670 __ CallRuntime(Runtime::kRegExpConstructResult, 3); | 2781 __ CallStub(&stub); |
| 2671 context()->Plug(r0); | 2782 context()->Plug(r0); |
| 2672 } | 2783 } |
| 2673 | 2784 |
| 2674 | 2785 |
| 2675 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) { | 2786 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) { |
| 2676 ASSERT(args->length() == 3); | 2787 ASSERT(args->length() == 3); |
| 2677 VisitForStackValue(args->at(0)); | 2788 VisitForStackValue(args->at(0)); |
| 2678 VisitForStackValue(args->at(1)); | 2789 VisitForStackValue(args->at(1)); |
| 2679 VisitForStackValue(args->at(2)); | 2790 VisitForStackValue(args->at(2)); |
| 2680 __ CallRuntime(Runtime::kSwapElements, 3); | 2791 __ CallRuntime(Runtime::kSwapElements, 3); |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2779 | 2890 |
| 2780 Label materialize_true, materialize_false; | 2891 Label materialize_true, materialize_false; |
| 2781 Label* if_true = NULL; | 2892 Label* if_true = NULL; |
| 2782 Label* if_false = NULL; | 2893 Label* if_false = NULL; |
| 2783 Label* fall_through = NULL; | 2894 Label* fall_through = NULL; |
| 2784 context()->PrepareTest(&materialize_true, &materialize_false, | 2895 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2785 &if_true, &if_false, &fall_through); | 2896 &if_true, &if_false, &fall_through); |
| 2786 | 2897 |
| 2787 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); | 2898 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); |
| 2788 __ tst(r0, Operand(String::kContainsCachedArrayIndexMask)); | 2899 __ tst(r0, Operand(String::kContainsCachedArrayIndexMask)); |
| 2789 | 2900 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2790 __ b(eq, if_true); | 2901 Split(eq, if_true, if_false, fall_through); |
| 2791 __ b(if_false); | |
| 2792 | 2902 |
| 2793 context()->Plug(if_true, if_false); | 2903 context()->Plug(if_true, if_false); |
| 2794 } | 2904 } |
| 2795 | 2905 |
| 2796 | 2906 |
| 2797 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { | 2907 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { |
| 2798 ASSERT(args->length() == 1); | 2908 ASSERT(args->length() == 1); |
| 2799 VisitForAccumulatorValue(args->at(0)); | 2909 VisitForAccumulatorValue(args->at(0)); |
| 2800 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); | 2910 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); |
| 2801 __ IndexFromHash(r0, r0); | 2911 __ IndexFromHash(r0, r0); |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2905 case Token::NOT: { | 3015 case Token::NOT: { |
| 2906 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 3016 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
| 2907 Label materialize_true, materialize_false; | 3017 Label materialize_true, materialize_false; |
| 2908 Label* if_true = NULL; | 3018 Label* if_true = NULL; |
| 2909 Label* if_false = NULL; | 3019 Label* if_false = NULL; |
| 2910 Label* fall_through = NULL; | 3020 Label* fall_through = NULL; |
| 2911 | 3021 |
| 2912 // Notice that the labels are swapped. | 3022 // Notice that the labels are swapped. |
| 2913 context()->PrepareTest(&materialize_true, &materialize_false, | 3023 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2914 &if_false, &if_true, &fall_through); | 3024 &if_false, &if_true, &fall_through); |
| 3025 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 2915 VisitForControl(expr->expression(), if_true, if_false, fall_through); | 3026 VisitForControl(expr->expression(), if_true, if_false, fall_through); |
| 2916 context()->Plug(if_false, if_true); // Labels swapped. | 3027 context()->Plug(if_false, if_true); // Labels swapped. |
| 2917 break; | 3028 break; |
| 2918 } | 3029 } |
| 2919 | 3030 |
| 2920 case Token::TYPEOF: { | 3031 case Token::TYPEOF: { |
| 2921 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 3032 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
| 2922 { StackValueContext context(this); | 3033 { StackValueContext context(this); |
| 2923 VisitForTypeofValue(expr->expression()); | 3034 VisitForTypeofValue(expr->expression()); |
| 2924 } | 3035 } |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3024 if (expr->is_postfix() && !context()->IsEffect()) { | 3135 if (expr->is_postfix() && !context()->IsEffect()) { |
| 3025 __ mov(ip, Operand(Smi::FromInt(0))); | 3136 __ mov(ip, Operand(Smi::FromInt(0))); |
| 3026 __ push(ip); | 3137 __ push(ip); |
| 3027 } | 3138 } |
| 3028 if (assign_type == NAMED_PROPERTY) { | 3139 if (assign_type == NAMED_PROPERTY) { |
| 3029 // Put the object both on the stack and in the accumulator. | 3140 // Put the object both on the stack and in the accumulator. |
| 3030 VisitForAccumulatorValue(prop->obj()); | 3141 VisitForAccumulatorValue(prop->obj()); |
| 3031 __ push(r0); | 3142 __ push(r0); |
| 3032 EmitNamedPropertyLoad(prop); | 3143 EmitNamedPropertyLoad(prop); |
| 3033 } else { | 3144 } else { |
| 3034 VisitForStackValue(prop->obj()); | 3145 if (prop->is_arguments_access()) { |
| 3035 VisitForAccumulatorValue(prop->key()); | 3146 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); |
| 3147 __ ldr(r0, EmitSlotSearch(obj_proxy->var()->AsSlot(), r0)); |
| 3148 __ push(r0); |
| 3149 __ mov(r0, Operand(prop->key()->AsLiteral()->handle())); |
| 3150 } else { |
| 3151 VisitForStackValue(prop->obj()); |
| 3152 VisitForAccumulatorValue(prop->key()); |
| 3153 } |
| 3036 __ ldr(r1, MemOperand(sp, 0)); | 3154 __ ldr(r1, MemOperand(sp, 0)); |
| 3037 __ push(r0); | 3155 __ push(r0); |
| 3038 EmitKeyedPropertyLoad(prop); | 3156 EmitKeyedPropertyLoad(prop); |
| 3039 } | 3157 } |
| 3040 } | 3158 } |
| 3041 | 3159 |
| 3160 // We need a second deoptimization point after loading the value |
| 3161 // in case evaluating the property load my have a side effect. |
| 3162 PrepareForBailout(expr->increment(), TOS_REG); |
| 3163 |
| 3042 // Call ToNumber only if operand is not a smi. | 3164 // Call ToNumber only if operand is not a smi. |
| 3043 Label no_conversion; | 3165 Label no_conversion; |
| 3044 __ BranchOnSmi(r0, &no_conversion); | 3166 __ BranchOnSmi(r0, &no_conversion); |
| 3045 __ push(r0); | 3167 __ push(r0); |
| 3046 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); | 3168 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); |
| 3047 __ bind(&no_conversion); | 3169 __ bind(&no_conversion); |
| 3048 | 3170 |
| 3049 // Save result for postfix expressions. | 3171 // Save result for postfix expressions. |
| 3050 if (expr->is_postfix()) { | 3172 if (expr->is_postfix()) { |
| 3051 if (!context()->IsEffect()) { | 3173 if (!context()->IsEffect()) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3074 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC); | 3196 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC); |
| 3075 __ b(vs, &stub_call); | 3197 __ b(vs, &stub_call); |
| 3076 // We could eliminate this smi check if we split the code at | 3198 // We could eliminate this smi check if we split the code at |
| 3077 // the first smi check before calling ToNumber. | 3199 // the first smi check before calling ToNumber. |
| 3078 __ BranchOnSmi(r0, &done); | 3200 __ BranchOnSmi(r0, &done); |
| 3079 __ bind(&stub_call); | 3201 __ bind(&stub_call); |
| 3080 // Call stub. Undo operation first. | 3202 // Call stub. Undo operation first. |
| 3081 __ sub(r0, r0, Operand(Smi::FromInt(count_value))); | 3203 __ sub(r0, r0, Operand(Smi::FromInt(count_value))); |
| 3082 } | 3204 } |
| 3083 __ mov(r1, Operand(Smi::FromInt(count_value))); | 3205 __ mov(r1, Operand(Smi::FromInt(count_value))); |
| 3206 |
| 3207 // Record position before stub call. |
| 3208 SetSourcePosition(expr->position()); |
| 3209 |
| 3084 GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE, r1, r0); | 3210 GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE, r1, r0); |
| 3085 __ CallStub(&stub); | 3211 __ CallStub(&stub); |
| 3086 __ bind(&done); | 3212 __ bind(&done); |
| 3087 | 3213 |
| 3088 // Store the value returned in r0. | 3214 // Store the value returned in r0. |
| 3089 switch (assign_type) { | 3215 switch (assign_type) { |
| 3090 case VARIABLE: | 3216 case VARIABLE: |
| 3091 if (expr->is_postfix()) { | 3217 if (expr->is_postfix()) { |
| 3092 { EffectContext context(this); | 3218 { EffectContext context(this); |
| 3093 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3219 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3143 VariableProxy* proxy = expr->AsVariableProxy(); | 3269 VariableProxy* proxy = expr->AsVariableProxy(); |
| 3144 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { | 3270 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { |
| 3145 Comment cmnt(masm_, "Global variable"); | 3271 Comment cmnt(masm_, "Global variable"); |
| 3146 __ ldr(r0, GlobalObjectOperand()); | 3272 __ ldr(r0, GlobalObjectOperand()); |
| 3147 __ mov(r2, Operand(proxy->name())); | 3273 __ mov(r2, Operand(proxy->name())); |
| 3148 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 3274 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
| 3149 Builtins::LoadIC_Initialize)); | 3275 Builtins::LoadIC_Initialize)); |
| 3150 // Use a regular load, not a contextual load, to avoid a reference | 3276 // Use a regular load, not a contextual load, to avoid a reference |
| 3151 // error. | 3277 // error. |
| 3152 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3278 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3279 PrepareForBailout(expr, TOS_REG); |
| 3153 context()->Plug(r0); | 3280 context()->Plug(r0); |
| 3154 } else if (proxy != NULL && | 3281 } else if (proxy != NULL && |
| 3155 proxy->var()->AsSlot() != NULL && | 3282 proxy->var()->AsSlot() != NULL && |
| 3156 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { | 3283 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { |
| 3157 Label done, slow; | 3284 Label done, slow; |
| 3158 | 3285 |
| 3159 // Generate code for loading from variables potentially shadowed | 3286 // Generate code for loading from variables potentially shadowed |
| 3160 // by eval-introduced variables. | 3287 // by eval-introduced variables. |
| 3161 Slot* slot = proxy->var()->AsSlot(); | 3288 Slot* slot = proxy->var()->AsSlot(); |
| 3162 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); | 3289 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); |
| 3163 | 3290 |
| 3164 __ bind(&slow); | 3291 __ bind(&slow); |
| 3165 __ mov(r0, Operand(proxy->name())); | 3292 __ mov(r0, Operand(proxy->name())); |
| 3166 __ Push(cp, r0); | 3293 __ Push(cp, r0); |
| 3167 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3294 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 3295 PrepareForBailout(expr, TOS_REG); |
| 3168 __ bind(&done); | 3296 __ bind(&done); |
| 3169 | 3297 |
| 3170 context()->Plug(r0); | 3298 context()->Plug(r0); |
| 3171 } else { | 3299 } else { |
| 3172 // This expression cannot throw a reference error at the top level. | 3300 // This expression cannot throw a reference error at the top level. |
| 3173 Visit(expr); | 3301 context()->HandleExpression(expr); |
| 3174 } | 3302 } |
| 3175 } | 3303 } |
| 3176 | 3304 |
| 3177 | 3305 |
| 3178 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, | 3306 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, |
| 3179 Expression* left, | 3307 Expression* left, |
| 3180 Expression* right, | 3308 Expression* right, |
| 3181 Label* if_true, | 3309 Label* if_true, |
| 3182 Label* if_false, | 3310 Label* if_false, |
| 3183 Label* fall_through) { | 3311 Label* fall_through) { |
| 3184 if (op != Token::EQ && op != Token::EQ_STRICT) return false; | 3312 if (op != Token::EQ && op != Token::EQ_STRICT) return false; |
| 3185 | 3313 |
| 3186 // Check for the pattern: typeof <expression> == <string literal>. | 3314 // Check for the pattern: typeof <expression> == <string literal>. |
| 3187 Literal* right_literal = right->AsLiteral(); | 3315 Literal* right_literal = right->AsLiteral(); |
| 3188 if (right_literal == NULL) return false; | 3316 if (right_literal == NULL) return false; |
| 3189 Handle<Object> right_literal_value = right_literal->handle(); | 3317 Handle<Object> right_literal_value = right_literal->handle(); |
| 3190 if (!right_literal_value->IsString()) return false; | 3318 if (!right_literal_value->IsString()) return false; |
| 3191 UnaryOperation* left_unary = left->AsUnaryOperation(); | 3319 UnaryOperation* left_unary = left->AsUnaryOperation(); |
| 3192 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | 3320 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; |
| 3193 Handle<String> check = Handle<String>::cast(right_literal_value); | 3321 Handle<String> check = Handle<String>::cast(right_literal_value); |
| 3194 | 3322 |
| 3195 { AccumulatorValueContext context(this); | 3323 { AccumulatorValueContext context(this); |
| 3196 VisitForTypeofValue(left_unary->expression()); | 3324 VisitForTypeofValue(left_unary->expression()); |
| 3197 } | 3325 } |
| 3326 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3327 |
| 3198 if (check->Equals(HEAP->number_symbol())) { | 3328 if (check->Equals(HEAP->number_symbol())) { |
| 3199 __ tst(r0, Operand(kSmiTagMask)); | 3329 __ tst(r0, Operand(kSmiTagMask)); |
| 3200 __ b(eq, if_true); | 3330 __ b(eq, if_true); |
| 3201 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); | 3331 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 3202 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | 3332 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); |
| 3203 __ cmp(r0, ip); | 3333 __ cmp(r0, ip); |
| 3204 Split(eq, if_true, if_false, fall_through); | 3334 Split(eq, if_true, if_false, fall_through); |
| 3205 } else if (check->Equals(HEAP->string_symbol())) { | 3335 } else if (check->Equals(HEAP->string_symbol())) { |
| 3206 __ tst(r0, Operand(kSmiTagMask)); | 3336 __ tst(r0, Operand(kSmiTagMask)); |
| 3207 __ b(eq, if_false); | 3337 __ b(eq, if_false); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3291 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { | 3421 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { |
| 3292 context()->Plug(if_true, if_false); | 3422 context()->Plug(if_true, if_false); |
| 3293 return; | 3423 return; |
| 3294 } | 3424 } |
| 3295 | 3425 |
| 3296 VisitForStackValue(expr->left()); | 3426 VisitForStackValue(expr->left()); |
| 3297 switch (op) { | 3427 switch (op) { |
| 3298 case Token::IN: | 3428 case Token::IN: |
| 3299 VisitForStackValue(expr->right()); | 3429 VisitForStackValue(expr->right()); |
| 3300 __ InvokeBuiltin(Builtins::IN, CALL_JS); | 3430 __ InvokeBuiltin(Builtins::IN, CALL_JS); |
| 3431 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 3301 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 3432 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 3302 __ cmp(r0, ip); | 3433 __ cmp(r0, ip); |
| 3303 Split(eq, if_true, if_false, fall_through); | 3434 Split(eq, if_true, if_false, fall_through); |
| 3304 break; | 3435 break; |
| 3305 | 3436 |
| 3306 case Token::INSTANCEOF: { | 3437 case Token::INSTANCEOF: { |
| 3307 VisitForStackValue(expr->right()); | 3438 VisitForStackValue(expr->right()); |
| 3308 InstanceofStub stub; | 3439 InstanceofStub stub; |
| 3309 __ CallStub(&stub); | 3440 __ CallStub(&stub); |
| 3441 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3310 // The stub returns 0 for true. | 3442 // The stub returns 0 for true. |
| 3311 __ tst(r0, r0); | 3443 __ tst(r0, r0); |
| 3312 Split(eq, if_true, if_false, fall_through); | 3444 Split(eq, if_true, if_false, fall_through); |
| 3313 break; | 3445 break; |
| 3314 } | 3446 } |
| 3315 | 3447 |
| 3316 default: { | 3448 default: { |
| 3317 VisitForAccumulatorValue(expr->right()); | 3449 VisitForAccumulatorValue(expr->right()); |
| 3318 Condition cc = eq; | 3450 Condition cc = eq; |
| 3319 bool strict = false; | 3451 bool strict = false; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3358 __ BranchOnNotSmi(r2, &slow_case); | 3490 __ BranchOnNotSmi(r2, &slow_case); |
| 3359 __ cmp(r1, r0); | 3491 __ cmp(r1, r0); |
| 3360 Split(cc, if_true, if_false, NULL); | 3492 Split(cc, if_true, if_false, NULL); |
| 3361 __ bind(&slow_case); | 3493 __ bind(&slow_case); |
| 3362 } | 3494 } |
| 3363 CompareFlags flags = inline_smi_code | 3495 CompareFlags flags = inline_smi_code |
| 3364 ? NO_SMI_COMPARE_IN_STUB | 3496 ? NO_SMI_COMPARE_IN_STUB |
| 3365 : NO_COMPARE_FLAGS; | 3497 : NO_COMPARE_FLAGS; |
| 3366 CompareStub stub(cc, strict, flags, r1, r0); | 3498 CompareStub stub(cc, strict, flags, r1, r0); |
| 3367 __ CallStub(&stub); | 3499 __ CallStub(&stub); |
| 3500 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3368 __ cmp(r0, Operand(0, RelocInfo::NONE)); | 3501 __ cmp(r0, Operand(0, RelocInfo::NONE)); |
| 3369 Split(cc, if_true, if_false, fall_through); | 3502 Split(cc, if_true, if_false, fall_through); |
| 3370 } | 3503 } |
| 3371 } | 3504 } |
| 3372 | 3505 |
| 3373 // Convert the result of the comparison into one expected for this | 3506 // Convert the result of the comparison into one expected for this |
| 3374 // expression's context. | 3507 // expression's context. |
| 3375 context()->Plug(if_true, if_false); | 3508 context()->Plug(if_true, if_false); |
| 3376 } | 3509 } |
| 3377 | 3510 |
| 3378 | 3511 |
| 3379 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { | 3512 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { |
| 3380 Comment cmnt(masm_, "[ CompareToNull"); | 3513 Comment cmnt(masm_, "[ CompareToNull"); |
| 3381 Label materialize_true, materialize_false; | 3514 Label materialize_true, materialize_false; |
| 3382 Label* if_true = NULL; | 3515 Label* if_true = NULL; |
| 3383 Label* if_false = NULL; | 3516 Label* if_false = NULL; |
| 3384 Label* fall_through = NULL; | 3517 Label* fall_through = NULL; |
| 3385 context()->PrepareTest(&materialize_true, &materialize_false, | 3518 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3386 &if_true, &if_false, &fall_through); | 3519 &if_true, &if_false, &fall_through); |
| 3387 | 3520 |
| 3388 VisitForAccumulatorValue(expr->expression()); | 3521 VisitForAccumulatorValue(expr->expression()); |
| 3522 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3389 __ LoadRoot(r1, Heap::kNullValueRootIndex); | 3523 __ LoadRoot(r1, Heap::kNullValueRootIndex); |
| 3390 __ cmp(r0, r1); | 3524 __ cmp(r0, r1); |
| 3391 if (expr->is_strict()) { | 3525 if (expr->is_strict()) { |
| 3392 Split(eq, if_true, if_false, fall_through); | 3526 Split(eq, if_true, if_false, fall_through); |
| 3393 } else { | 3527 } else { |
| 3394 __ b(eq, if_true); | 3528 __ b(eq, if_true); |
| 3395 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); | 3529 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); |
| 3396 __ cmp(r0, r1); | 3530 __ cmp(r0, r1); |
| 3397 __ b(eq, if_true); | 3531 __ b(eq, if_true); |
| 3398 __ tst(r0, Operand(kSmiTagMask)); | 3532 __ tst(r0, Operand(kSmiTagMask)); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3468 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 3602 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
| 3469 __ add(pc, r1, Operand(masm_->CodeObject())); | 3603 __ add(pc, r1, Operand(masm_->CodeObject())); |
| 3470 } | 3604 } |
| 3471 | 3605 |
| 3472 | 3606 |
| 3473 #undef __ | 3607 #undef __ |
| 3474 | 3608 |
| 3475 } } // namespace v8::internal | 3609 } } // namespace v8::internal |
| 3476 | 3610 |
| 3477 #endif // V8_TARGET_ARCH_ARM | 3611 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |