| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) { | 56 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) { |
| 57 #ifdef DEBUG | 57 #ifdef DEBUG |
| 58 info_emitted_ = false; | 58 info_emitted_ = false; |
| 59 #endif | 59 #endif |
| 60 } | 60 } |
| 61 | 61 |
| 62 ~JumpPatchSite() { | 62 ~JumpPatchSite() { |
| 63 ASSERT(patch_site_.is_bound() == info_emitted_); | 63 ASSERT(patch_site_.is_bound() == info_emitted_); |
| 64 } | 64 } |
| 65 | 65 |
| 66 void EmitJumpIfNotSmi(Register reg, NearLabel* target) { | 66 void EmitJumpIfNotSmi(Register reg, |
| 67 Label* target, |
| 68 Label::Distance distance = Label::kFar) { |
| 67 __ test(reg, Immediate(kSmiTagMask)); | 69 __ test(reg, Immediate(kSmiTagMask)); |
| 68 EmitJump(not_carry, target); // Always taken before patched. | 70 EmitJump(not_carry, target, distance); // Always taken before patched. |
| 69 } | 71 } |
| 70 | 72 |
| 71 void EmitJumpIfSmi(Register reg, NearLabel* target) { | 73 void EmitJumpIfSmi(Register reg, |
| 74 Label* target, |
| 75 Label::Distance distance = Label::kFar) { |
| 72 __ test(reg, Immediate(kSmiTagMask)); | 76 __ test(reg, Immediate(kSmiTagMask)); |
| 73 EmitJump(carry, target); // Never taken before patched. | 77 EmitJump(carry, target, distance); // Never taken before patched. |
| 74 } | 78 } |
| 75 | 79 |
| 76 void EmitPatchInfo() { | 80 void EmitPatchInfo() { |
| 77 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_); | 81 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_); |
| 78 ASSERT(is_int8(delta_to_patch_site)); | 82 ASSERT(is_int8(delta_to_patch_site)); |
| 79 __ test(eax, Immediate(delta_to_patch_site)); | 83 __ test(eax, Immediate(delta_to_patch_site)); |
| 80 #ifdef DEBUG | 84 #ifdef DEBUG |
| 81 info_emitted_ = true; | 85 info_emitted_ = true; |
| 82 #endif | 86 #endif |
| 83 } | 87 } |
| 84 | 88 |
| 85 bool is_bound() const { return patch_site_.is_bound(); } | 89 bool is_bound() const { return patch_site_.is_bound(); } |
| 86 | 90 |
| 87 private: | 91 private: |
| 88 // jc will be patched with jz, jnc will become jnz. | 92 // jc will be patched with jz, jnc will become jnz. |
| 89 void EmitJump(Condition cc, NearLabel* target) { | 93 void EmitJump(Condition cc, Label* target, Label::Distance distance) { |
| 90 ASSERT(!patch_site_.is_bound() && !info_emitted_); | 94 ASSERT(!patch_site_.is_bound() && !info_emitted_); |
| 91 ASSERT(cc == carry || cc == not_carry); | 95 ASSERT(cc == carry || cc == not_carry); |
| 92 __ bind(&patch_site_); | 96 __ bind(&patch_site_); |
| 93 __ j(cc, target); | 97 __ j(cc, target, distance); |
| 94 } | 98 } |
| 95 | 99 |
| 96 MacroAssembler* masm_; | 100 MacroAssembler* masm_; |
| 97 Label patch_site_; | 101 Label patch_site_; |
| 98 #ifdef DEBUG | 102 #ifdef DEBUG |
| 99 bool info_emitted_; | 103 bool info_emitted_; |
| 100 #endif | 104 #endif |
| 101 }; | 105 }; |
| 102 | 106 |
| 103 | 107 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 if (function_in_register) { | 196 if (function_in_register) { |
| 193 __ push(edi); | 197 __ push(edi); |
| 194 } else { | 198 } else { |
| 195 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 199 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 196 } | 200 } |
| 197 // Receiver is just before the parameters on the caller's stack. | 201 // Receiver is just before the parameters on the caller's stack. |
| 198 int offset = scope()->num_parameters() * kPointerSize; | 202 int offset = scope()->num_parameters() * kPointerSize; |
| 199 __ lea(edx, | 203 __ lea(edx, |
| 200 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); | 204 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); |
| 201 __ push(edx); | 205 __ push(edx); |
| 202 __ push(Immediate(Smi::FromInt(scope()->num_parameters()))); | 206 __ SafePush(Immediate(Smi::FromInt(scope()->num_parameters()))); |
| 203 // Arguments to ArgumentsAccessStub: | 207 // Arguments to ArgumentsAccessStub: |
| 204 // function, receiver address, parameter count. | 208 // function, receiver address, parameter count. |
| 205 // The stub will rewrite receiver and parameter count if the previous | 209 // The stub will rewrite receiver and parameter count if the previous |
| 206 // stack frame was an arguments adapter frame. | 210 // stack frame was an arguments adapter frame. |
| 207 ArgumentsAccessStub stub( | 211 ArgumentsAccessStub stub( |
| 208 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT | 212 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT |
| 209 : ArgumentsAccessStub::NEW_NON_STRICT); | 213 : ArgumentsAccessStub::NEW_NON_STRICT); |
| 210 __ CallStub(&stub); | 214 __ CallStub(&stub); |
| 211 | 215 |
| 212 Variable* arguments_shadow = scope()->arguments_shadow(); | 216 Variable* arguments_shadow = scope()->arguments_shadow(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 232 // For named function expressions, declare the function name as a | 236 // For named function expressions, declare the function name as a |
| 233 // constant. | 237 // constant. |
| 234 if (scope()->is_function_scope() && scope()->function() != NULL) { | 238 if (scope()->is_function_scope() && scope()->function() != NULL) { |
| 235 EmitDeclaration(scope()->function(), Variable::CONST, NULL); | 239 EmitDeclaration(scope()->function(), Variable::CONST, NULL); |
| 236 } | 240 } |
| 237 VisitDeclarations(scope()->declarations()); | 241 VisitDeclarations(scope()->declarations()); |
| 238 } | 242 } |
| 239 | 243 |
| 240 { Comment cmnt(masm_, "[ Stack check"); | 244 { Comment cmnt(masm_, "[ Stack check"); |
| 241 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); | 245 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); |
| 242 NearLabel ok; | 246 Label ok; |
| 243 ExternalReference stack_limit = | 247 ExternalReference stack_limit = |
| 244 ExternalReference::address_of_stack_limit(isolate()); | 248 ExternalReference::address_of_stack_limit(isolate()); |
| 245 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 249 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
| 246 __ j(above_equal, &ok, taken); | 250 __ j(above_equal, &ok, Label::kNear); |
| 247 StackCheckStub stub; | 251 StackCheckStub stub; |
| 248 __ CallStub(&stub); | 252 __ CallStub(&stub); |
| 249 __ bind(&ok); | 253 __ bind(&ok); |
| 250 } | 254 } |
| 251 | 255 |
| 252 { Comment cmnt(masm_, "[ Body"); | 256 { Comment cmnt(masm_, "[ Body"); |
| 253 ASSERT(loop_depth() == 0); | 257 ASSERT(loop_depth() == 0); |
| 254 VisitStatements(function()->body()); | 258 VisitStatements(function()->body()); |
| 255 ASSERT(loop_depth() == 0); | 259 ASSERT(loop_depth() == 0); |
| 256 } | 260 } |
| 257 } | 261 } |
| 258 | 262 |
| 259 // Always emit a 'return undefined' in case control fell off the end of | 263 // Always emit a 'return undefined' in case control fell off the end of |
| 260 // the body. | 264 // the body. |
| 261 { Comment cmnt(masm_, "[ return <undefined>;"); | 265 { Comment cmnt(masm_, "[ return <undefined>;"); |
| 262 __ mov(eax, isolate()->factory()->undefined_value()); | 266 __ mov(eax, isolate()->factory()->undefined_value()); |
| 263 EmitReturnSequence(); | 267 EmitReturnSequence(); |
| 264 } | 268 } |
| 265 } | 269 } |
| 266 | 270 |
| 267 | 271 |
| 268 void FullCodeGenerator::ClearAccumulator() { | 272 void FullCodeGenerator::ClearAccumulator() { |
| 269 __ Set(eax, Immediate(Smi::FromInt(0))); | 273 __ Set(eax, Immediate(Smi::FromInt(0))); |
| 270 } | 274 } |
| 271 | 275 |
| 272 | 276 |
| 273 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) { | 277 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) { |
| 274 Comment cmnt(masm_, "[ Stack check"); | 278 Comment cmnt(masm_, "[ Stack check"); |
| 275 NearLabel ok; | 279 Label ok; |
| 276 ExternalReference stack_limit = | 280 ExternalReference stack_limit = |
| 277 ExternalReference::address_of_stack_limit(isolate()); | 281 ExternalReference::address_of_stack_limit(isolate()); |
| 278 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 282 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
| 279 __ j(above_equal, &ok, taken); | 283 __ j(above_equal, &ok, Label::kNear); |
| 280 StackCheckStub stub; | 284 StackCheckStub stub; |
| 281 __ CallStub(&stub); | 285 __ CallStub(&stub); |
| 282 // Record a mapping of this PC offset to the OSR id. This is used to find | 286 // Record a mapping of this PC offset to the OSR id. This is used to find |
| 283 // the AST id from the unoptimized code in order to use it as a key into | 287 // the AST id from the unoptimized code in order to use it as a key into |
| 284 // the deoptimization input data found in the optimized code. | 288 // the deoptimization input data found in the optimized code. |
| 285 RecordStackCheck(stmt->OsrEntryId()); | 289 RecordStackCheck(stmt->OsrEntryId()); |
| 286 | 290 |
| 287 // Loop stack checks can be patched to perform on-stack replacement. In | 291 // Loop stack checks can be patched to perform on-stack replacement. In |
| 288 // order to decide whether or not to perform OSR we embed the loop depth | 292 // order to decide whether or not to perform OSR we embed the loop depth |
| 289 // in a test instruction after the call so we can extract it from the OSR | 293 // in a test instruction after the call so we can extract it from the OSR |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 381 UNREACHABLE(); // Not used on IA32. | 385 UNREACHABLE(); // Not used on IA32. |
| 382 } | 386 } |
| 383 | 387 |
| 384 | 388 |
| 385 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { | 389 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { |
| 386 } | 390 } |
| 387 | 391 |
| 388 | 392 |
| 389 void FullCodeGenerator::AccumulatorValueContext::Plug( | 393 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 390 Handle<Object> lit) const { | 394 Handle<Object> lit) const { |
| 391 __ Set(result_register(), Immediate(lit)); | 395 if (lit->IsSmi()) { |
| 396 __ SafeSet(result_register(), Immediate(lit)); |
| 397 } else { |
| 398 __ Set(result_register(), Immediate(lit)); |
| 399 } |
| 392 } | 400 } |
| 393 | 401 |
| 394 | 402 |
| 395 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const { | 403 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const { |
| 396 // Immediates can be pushed directly. | 404 if (lit->IsSmi()) { |
| 397 __ push(Immediate(lit)); | 405 __ SafePush(Immediate(lit)); |
| 406 } else { |
| 407 __ push(Immediate(lit)); |
| 408 } |
| 398 } | 409 } |
| 399 | 410 |
| 400 | 411 |
| 401 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const { | 412 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const { |
| 402 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, | 413 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, |
| 403 true, | 414 true, |
| 404 true_label_, | 415 true_label_, |
| 405 false_label_); | 416 false_label_); |
| 406 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals. | 417 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals. |
| 407 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) { | 418 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 466 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, | 477 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, |
| 467 Label* materialize_false) const { | 478 Label* materialize_false) const { |
| 468 ASSERT(materialize_true == materialize_false); | 479 ASSERT(materialize_true == materialize_false); |
| 469 __ bind(materialize_true); | 480 __ bind(materialize_true); |
| 470 } | 481 } |
| 471 | 482 |
| 472 | 483 |
| 473 void FullCodeGenerator::AccumulatorValueContext::Plug( | 484 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 474 Label* materialize_true, | 485 Label* materialize_true, |
| 475 Label* materialize_false) const { | 486 Label* materialize_false) const { |
| 476 NearLabel done; | 487 Label done; |
| 477 __ bind(materialize_true); | 488 __ bind(materialize_true); |
| 478 __ mov(result_register(), isolate()->factory()->true_value()); | 489 __ mov(result_register(), isolate()->factory()->true_value()); |
| 479 __ jmp(&done); | 490 __ jmp(&done, Label::kNear); |
| 480 __ bind(materialize_false); | 491 __ bind(materialize_false); |
| 481 __ mov(result_register(), isolate()->factory()->false_value()); | 492 __ mov(result_register(), isolate()->factory()->false_value()); |
| 482 __ bind(&done); | 493 __ bind(&done); |
| 483 } | 494 } |
| 484 | 495 |
| 485 | 496 |
| 486 void FullCodeGenerator::StackValueContext::Plug( | 497 void FullCodeGenerator::StackValueContext::Plug( |
| 487 Label* materialize_true, | 498 Label* materialize_true, |
| 488 Label* materialize_false) const { | 499 Label* materialize_false) const { |
| 489 NearLabel done; | 500 Label done; |
| 490 __ bind(materialize_true); | 501 __ bind(materialize_true); |
| 491 __ push(Immediate(isolate()->factory()->true_value())); | 502 __ push(Immediate(isolate()->factory()->true_value())); |
| 492 __ jmp(&done); | 503 __ jmp(&done, Label::kNear); |
| 493 __ bind(materialize_false); | 504 __ bind(materialize_false); |
| 494 __ push(Immediate(isolate()->factory()->false_value())); | 505 __ push(Immediate(isolate()->factory()->false_value())); |
| 495 __ bind(&done); | 506 __ bind(&done); |
| 496 } | 507 } |
| 497 | 508 |
| 498 | 509 |
| 499 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, | 510 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, |
| 500 Label* materialize_false) const { | 511 Label* materialize_false) const { |
| 501 ASSERT(materialize_true == true_label_); | 512 ASSERT(materialize_true == true_label_); |
| 502 ASSERT(materialize_false == false_label_); | 513 ASSERT(materialize_false == false_label_); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 532 if (true_label_ != fall_through_) __ jmp(true_label_); | 543 if (true_label_ != fall_through_) __ jmp(true_label_); |
| 533 } else { | 544 } else { |
| 534 if (false_label_ != fall_through_) __ jmp(false_label_); | 545 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 535 } | 546 } |
| 536 } | 547 } |
| 537 | 548 |
| 538 | 549 |
| 539 void FullCodeGenerator::DoTest(Label* if_true, | 550 void FullCodeGenerator::DoTest(Label* if_true, |
| 540 Label* if_false, | 551 Label* if_false, |
| 541 Label* fall_through) { | 552 Label* fall_through) { |
| 542 // Emit the inlined tests assumed by the stub. | |
| 543 __ cmp(result_register(), isolate()->factory()->undefined_value()); | |
| 544 __ j(equal, if_false); | |
| 545 __ cmp(result_register(), isolate()->factory()->true_value()); | |
| 546 __ j(equal, if_true); | |
| 547 __ cmp(result_register(), isolate()->factory()->false_value()); | |
| 548 __ j(equal, if_false); | |
| 549 STATIC_ASSERT(kSmiTag == 0); | |
| 550 __ test(result_register(), Operand(result_register())); | |
| 551 __ j(zero, if_false); | |
| 552 __ test(result_register(), Immediate(kSmiTagMask)); | |
| 553 __ j(zero, if_true); | |
| 554 | |
| 555 // Call the ToBoolean stub for all other cases. | |
| 556 ToBooleanStub stub; | 553 ToBooleanStub stub; |
| 557 __ push(result_register()); | 554 __ push(result_register()); |
| 558 __ CallStub(&stub); | 555 __ CallStub(&stub); |
| 559 __ test(eax, Operand(eax)); | 556 __ test(eax, Operand(eax)); |
| 560 | |
| 561 // The stub returns nonzero for true. | 557 // The stub returns nonzero for true. |
| 562 Split(not_zero, if_true, if_false, fall_through); | 558 Split(not_zero, if_true, if_false, fall_through); |
| 563 } | 559 } |
| 564 | 560 |
| 565 | 561 |
| 566 void FullCodeGenerator::Split(Condition cc, | 562 void FullCodeGenerator::Split(Condition cc, |
| 567 Label* if_true, | 563 Label* if_true, |
| 568 Label* if_false, | 564 Label* if_false, |
| 569 Label* fall_through) { | 565 Label* fall_through) { |
| 570 if (if_false == fall_through) { | 566 if (if_false == fall_through) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 | 619 |
| 624 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 620 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
| 625 bool should_normalize, | 621 bool should_normalize, |
| 626 Label* if_true, | 622 Label* if_true, |
| 627 Label* if_false) { | 623 Label* if_false) { |
| 628 // Only prepare for bailouts before splits if we're in a test | 624 // Only prepare for bailouts before splits if we're in a test |
| 629 // context. Otherwise, we let the Visit function deal with the | 625 // context. Otherwise, we let the Visit function deal with the |
| 630 // preparation to avoid preparing with the same AST id twice. | 626 // preparation to avoid preparing with the same AST id twice. |
| 631 if (!context()->IsTest() || !info_->IsOptimizable()) return; | 627 if (!context()->IsTest() || !info_->IsOptimizable()) return; |
| 632 | 628 |
| 633 NearLabel skip; | 629 Label skip; |
| 634 if (should_normalize) __ jmp(&skip); | 630 if (should_normalize) __ jmp(&skip, Label::kNear); |
| 635 | 631 |
| 636 ForwardBailoutStack* current = forward_bailout_stack_; | 632 ForwardBailoutStack* current = forward_bailout_stack_; |
| 637 while (current != NULL) { | 633 while (current != NULL) { |
| 638 PrepareForBailout(current->expr(), state); | 634 PrepareForBailout(current->expr(), state); |
| 639 current = current->parent(); | 635 current = current->parent(); |
| 640 } | 636 } |
| 641 | 637 |
| 642 if (should_normalize) { | 638 if (should_normalize) { |
| 643 __ cmp(eax, isolate()->factory()->true_value()); | 639 __ cmp(eax, isolate()->factory()->true_value()); |
| 644 Split(equal, if_true, if_false, NULL); | 640 Split(equal, if_true, if_false, NULL); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 if (function != NULL) { | 730 if (function != NULL) { |
| 735 __ push(eax); | 731 __ push(eax); |
| 736 VisitForAccumulatorValue(function); | 732 VisitForAccumulatorValue(function); |
| 737 __ pop(edx); | 733 __ pop(edx); |
| 738 } else { | 734 } else { |
| 739 __ mov(edx, eax); | 735 __ mov(edx, eax); |
| 740 __ mov(eax, isolate()->factory()->the_hole_value()); | 736 __ mov(eax, isolate()->factory()->the_hole_value()); |
| 741 } | 737 } |
| 742 ASSERT(prop->key()->AsLiteral() != NULL && | 738 ASSERT(prop->key()->AsLiteral() != NULL && |
| 743 prop->key()->AsLiteral()->handle()->IsSmi()); | 739 prop->key()->AsLiteral()->handle()->IsSmi()); |
| 744 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); | 740 __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle())); |
| 745 | 741 |
| 746 Handle<Code> ic = is_strict_mode() | 742 Handle<Code> ic = is_strict_mode() |
| 747 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 743 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 748 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 744 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 749 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 745 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); |
| 750 } | 746 } |
| 751 } | 747 } |
| 752 } | 748 } |
| 753 | 749 |
| 754 | 750 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 797 next_test.Unuse(); | 793 next_test.Unuse(); |
| 798 | 794 |
| 799 // Compile the label expression. | 795 // Compile the label expression. |
| 800 VisitForAccumulatorValue(clause->label()); | 796 VisitForAccumulatorValue(clause->label()); |
| 801 | 797 |
| 802 // Perform the comparison as if via '==='. | 798 // Perform the comparison as if via '==='. |
| 803 __ mov(edx, Operand(esp, 0)); // Switch value. | 799 __ mov(edx, Operand(esp, 0)); // Switch value. |
| 804 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT); | 800 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT); |
| 805 JumpPatchSite patch_site(masm_); | 801 JumpPatchSite patch_site(masm_); |
| 806 if (inline_smi_code) { | 802 if (inline_smi_code) { |
| 807 NearLabel slow_case; | 803 Label slow_case; |
| 808 __ mov(ecx, edx); | 804 __ mov(ecx, edx); |
| 809 __ or_(ecx, Operand(eax)); | 805 __ or_(ecx, Operand(eax)); |
| 810 patch_site.EmitJumpIfNotSmi(ecx, &slow_case); | 806 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); |
| 811 | 807 |
| 812 __ cmp(edx, Operand(eax)); | 808 __ cmp(edx, Operand(eax)); |
| 813 __ j(not_equal, &next_test); | 809 __ j(not_equal, &next_test); |
| 814 __ Drop(1); // Switch value is no longer needed. | 810 __ Drop(1); // Switch value is no longer needed. |
| 815 __ jmp(clause->body_target()); | 811 __ jmp(clause->body_target()); |
| 816 __ bind(&slow_case); | 812 __ bind(&slow_case); |
| 817 } | 813 } |
| 818 | 814 |
| 819 // Record position before stub call for type feedback. | 815 // Record position before stub call for type feedback. |
| 820 SetSourcePosition(clause->position()); | 816 SetSourcePosition(clause->position()); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 861 // Get the object to enumerate over. Both SpiderMonkey and JSC | 857 // Get the object to enumerate over. Both SpiderMonkey and JSC |
| 862 // ignore null and undefined in contrast to the specification; see | 858 // ignore null and undefined in contrast to the specification; see |
| 863 // ECMA-262 section 12.6.4. | 859 // ECMA-262 section 12.6.4. |
| 864 VisitForAccumulatorValue(stmt->enumerable()); | 860 VisitForAccumulatorValue(stmt->enumerable()); |
| 865 __ cmp(eax, isolate()->factory()->undefined_value()); | 861 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 866 __ j(equal, &exit); | 862 __ j(equal, &exit); |
| 867 __ cmp(eax, isolate()->factory()->null_value()); | 863 __ cmp(eax, isolate()->factory()->null_value()); |
| 868 __ j(equal, &exit); | 864 __ j(equal, &exit); |
| 869 | 865 |
| 870 // Convert the object to a JS object. | 866 // Convert the object to a JS object. |
| 871 NearLabel convert, done_convert; | 867 Label convert, done_convert; |
| 872 __ test(eax, Immediate(kSmiTagMask)); | 868 __ test(eax, Immediate(kSmiTagMask)); |
| 873 __ j(zero, &convert); | 869 __ j(zero, &convert, Label::kNear); |
| 874 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | 870 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
| 875 __ j(above_equal, &done_convert); | 871 __ j(above_equal, &done_convert, Label::kNear); |
| 876 __ bind(&convert); | 872 __ bind(&convert); |
| 877 __ push(eax); | 873 __ push(eax); |
| 878 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 874 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 879 __ bind(&done_convert); | 875 __ bind(&done_convert); |
| 880 __ push(eax); | 876 __ push(eax); |
| 881 | 877 |
| 882 // Check cache validity in generated code. This is a fast case for | 878 // Check cache validity in generated code. This is a fast case for |
| 883 // the JSObject::IsSimpleEnum cache validity checks. If we cannot | 879 // the JSObject::IsSimpleEnum cache validity checks. If we cannot |
| 884 // guarantee cache validity, call the runtime system to check cache | 880 // guarantee cache validity, call the runtime system to check cache |
| 885 // validity or get the property names in a fixed array. | 881 // validity or get the property names in a fixed array. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 902 __ j(equal, &call_runtime); | 898 __ j(equal, &call_runtime); |
| 903 | 899 |
| 904 // Check that there is an enum cache in the non-empty instance | 900 // Check that there is an enum cache in the non-empty instance |
| 905 // descriptors (edx). This is the case if the next enumeration | 901 // descriptors (edx). This is the case if the next enumeration |
| 906 // index field does not contain a smi. | 902 // index field does not contain a smi. |
| 907 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); | 903 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); |
| 908 __ test(edx, Immediate(kSmiTagMask)); | 904 __ test(edx, Immediate(kSmiTagMask)); |
| 909 __ j(zero, &call_runtime); | 905 __ j(zero, &call_runtime); |
| 910 | 906 |
| 911 // For all objects but the receiver, check that the cache is empty. | 907 // For all objects but the receiver, check that the cache is empty. |
| 912 NearLabel check_prototype; | 908 Label check_prototype; |
| 913 __ cmp(ecx, Operand(eax)); | 909 __ cmp(ecx, Operand(eax)); |
| 914 __ j(equal, &check_prototype); | 910 __ j(equal, &check_prototype, Label::kNear); |
| 915 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 911 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 916 __ cmp(edx, isolate()->factory()->empty_fixed_array()); | 912 __ cmp(edx, isolate()->factory()->empty_fixed_array()); |
| 917 __ j(not_equal, &call_runtime); | 913 __ j(not_equal, &call_runtime); |
| 918 | 914 |
| 919 // Load the prototype from the map and loop if non-null. | 915 // Load the prototype from the map and loop if non-null. |
| 920 __ bind(&check_prototype); | 916 __ bind(&check_prototype); |
| 921 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); | 917 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); |
| 922 __ cmp(ecx, isolate()->factory()->null_value()); | 918 __ cmp(ecx, isolate()->factory()->null_value()); |
| 923 __ j(not_equal, &next); | 919 __ j(not_equal, &next); |
| 924 | 920 |
| 925 // The enum cache is valid. Load the map of the object being | 921 // The enum cache is valid. Load the map of the object being |
| 926 // iterated over and use the cache for the iteration. | 922 // iterated over and use the cache for the iteration. |
| 927 NearLabel use_cache; | 923 Label use_cache; |
| 928 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 924 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 929 __ jmp(&use_cache); | 925 __ jmp(&use_cache, Label::kNear); |
| 930 | 926 |
| 931 // Get the set of properties to enumerate. | 927 // Get the set of properties to enumerate. |
| 932 __ bind(&call_runtime); | 928 __ bind(&call_runtime); |
| 933 __ push(eax); // Duplicate the enumerable object on the stack. | 929 __ push(eax); // Duplicate the enumerable object on the stack. |
| 934 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 930 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 935 | 931 |
| 936 // If we got a map from the runtime call, we can do a fast | 932 // If we got a map from the runtime call, we can do a fast |
| 937 // modification check. Otherwise, we got a fixed array, and we have | 933 // modification check. Otherwise, we got a fixed array, and we have |
| 938 // to do a slow check. | 934 // to do a slow check. |
| 939 NearLabel fixed_array; | 935 Label fixed_array; |
| 940 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 936 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 941 isolate()->factory()->meta_map()); | 937 isolate()->factory()->meta_map()); |
| 942 __ j(not_equal, &fixed_array); | 938 __ j(not_equal, &fixed_array, Label::kNear); |
| 943 | 939 |
| 944 // We got a map in register eax. Get the enumeration cache from it. | 940 // We got a map in register eax. Get the enumeration cache from it. |
| 945 __ bind(&use_cache); | 941 __ bind(&use_cache); |
| 946 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset)); | 942 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset)); |
| 947 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); | 943 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); |
| 948 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 944 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 949 | 945 |
| 950 // Setup the four remaining stack slots. | 946 // Setup the four remaining stack slots. |
| 951 __ push(eax); // Map. | 947 __ push(eax); // Map. |
| 952 __ push(edx); // Enumeration cache. | 948 __ push(edx); // Enumeration cache. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 972 // Get the current entry of the array into register ebx. | 968 // Get the current entry of the array into register ebx. |
| 973 __ mov(ebx, Operand(esp, 2 * kPointerSize)); | 969 __ mov(ebx, Operand(esp, 2 * kPointerSize)); |
| 974 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize)); | 970 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize)); |
| 975 | 971 |
| 976 // Get the expected map from the stack or a zero map in the | 972 // Get the expected map from the stack or a zero map in the |
| 977 // permanent slow case into register edx. | 973 // permanent slow case into register edx. |
| 978 __ mov(edx, Operand(esp, 3 * kPointerSize)); | 974 __ mov(edx, Operand(esp, 3 * kPointerSize)); |
| 979 | 975 |
| 980 // Check if the expected map still matches that of the enumerable. | 976 // Check if the expected map still matches that of the enumerable. |
| 981 // If not, we have to filter the key. | 977 // If not, we have to filter the key. |
| 982 NearLabel update_each; | 978 Label update_each; |
| 983 __ mov(ecx, Operand(esp, 4 * kPointerSize)); | 979 __ mov(ecx, Operand(esp, 4 * kPointerSize)); |
| 984 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset)); | 980 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 985 __ j(equal, &update_each); | 981 __ j(equal, &update_each, Label::kNear); |
| 986 | 982 |
| 987 // Convert the entry to a string or null if it isn't a property | 983 // Convert the entry to a string or null if it isn't a property |
| 988 // anymore. If the property has been removed while iterating, we | 984 // anymore. If the property has been removed while iterating, we |
| 989 // just skip it. | 985 // just skip it. |
| 990 __ push(ecx); // Enumerable. | 986 __ push(ecx); // Enumerable. |
| 991 __ push(ebx); // Current entry. | 987 __ push(ebx); // Current entry. |
| 992 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); | 988 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); |
| 993 __ test(eax, Operand(eax)); | 989 __ test(eax, Operand(eax)); |
| 994 __ j(equal, loop_statement.continue_target()); | 990 __ j(equal, loop_statement.continue_target()); |
| 995 __ mov(ebx, Operand(eax)); | 991 __ mov(ebx, Operand(eax)); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1083 // If no outer scope calls eval, we do not need to check more | 1079 // If no outer scope calls eval, we do not need to check more |
| 1084 // context extensions. If we have reached an eval scope, we check | 1080 // context extensions. If we have reached an eval scope, we check |
| 1085 // all extensions from this point. | 1081 // all extensions from this point. |
| 1086 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; | 1082 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; |
| 1087 s = s->outer_scope(); | 1083 s = s->outer_scope(); |
| 1088 } | 1084 } |
| 1089 | 1085 |
| 1090 if (s != NULL && s->is_eval_scope()) { | 1086 if (s != NULL && s->is_eval_scope()) { |
| 1091 // Loop up the context chain. There is no frame effect so it is | 1087 // Loop up the context chain. There is no frame effect so it is |
| 1092 // safe to use raw labels here. | 1088 // safe to use raw labels here. |
| 1093 NearLabel next, fast; | 1089 Label next, fast; |
| 1094 if (!context.is(temp)) { | 1090 if (!context.is(temp)) { |
| 1095 __ mov(temp, context); | 1091 __ mov(temp, context); |
| 1096 } | 1092 } |
| 1097 __ bind(&next); | 1093 __ bind(&next); |
| 1098 // Terminate at global context. | 1094 // Terminate at global context. |
| 1099 __ cmp(FieldOperand(temp, HeapObject::kMapOffset), | 1095 __ cmp(FieldOperand(temp, HeapObject::kMapOffset), |
| 1100 Immediate(isolate()->factory()->global_context_map())); | 1096 Immediate(isolate()->factory()->global_context_map())); |
| 1101 __ j(equal, &fast); | 1097 __ j(equal, &fast, Label::kNear); |
| 1102 // Check that extension is NULL. | 1098 // Check that extension is NULL. |
| 1103 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); | 1099 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); |
| 1104 __ j(not_equal, slow); | 1100 __ j(not_equal, slow); |
| 1105 // Load next context in chain. | 1101 // Load next context in chain. |
| 1106 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX)); | 1102 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX)); |
| 1107 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); | 1103 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
| 1108 __ jmp(&next); | 1104 __ jmp(&next); |
| 1109 __ bind(&fast); | 1105 __ bind(&fast); |
| 1110 } | 1106 } |
| 1111 | 1107 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1188 if (obj_proxy != NULL && | 1184 if (obj_proxy != NULL && |
| 1189 key_literal != NULL && | 1185 key_literal != NULL && |
| 1190 obj_proxy->IsArguments() && | 1186 obj_proxy->IsArguments() && |
| 1191 key_literal->handle()->IsSmi()) { | 1187 key_literal->handle()->IsSmi()) { |
| 1192 // Load arguments object if there are no eval-introduced | 1188 // Load arguments object if there are no eval-introduced |
| 1193 // variables. Then load the argument from the arguments | 1189 // variables. Then load the argument from the arguments |
| 1194 // object using keyed load. | 1190 // object using keyed load. |
| 1195 __ mov(edx, | 1191 __ mov(edx, |
| 1196 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), | 1192 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), |
| 1197 slow)); | 1193 slow)); |
| 1198 __ mov(eax, Immediate(key_literal->handle())); | 1194 __ SafeSet(eax, Immediate(key_literal->handle())); |
| 1199 Handle<Code> ic = | 1195 Handle<Code> ic = |
| 1200 isolate()->builtins()->KeyedLoadIC_Initialize(); | 1196 isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 1201 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); | 1197 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); |
| 1202 __ jmp(done); | 1198 __ jmp(done); |
| 1203 } | 1199 } |
| 1204 } | 1200 } |
| 1205 } | 1201 } |
| 1206 } | 1202 } |
| 1207 } | 1203 } |
| 1208 | 1204 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1240 | 1236 |
| 1241 context()->Plug(eax); | 1237 context()->Plug(eax); |
| 1242 | 1238 |
| 1243 } else if (slot != NULL) { | 1239 } else if (slot != NULL) { |
| 1244 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1240 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 1245 ? "Context slot" | 1241 ? "Context slot" |
| 1246 : "Stack slot"); | 1242 : "Stack slot"); |
| 1247 if (var->mode() == Variable::CONST) { | 1243 if (var->mode() == Variable::CONST) { |
| 1248 // Constants may be the hole value if they have not been initialized. | 1244 // Constants may be the hole value if they have not been initialized. |
| 1249 // Unhole them. | 1245 // Unhole them. |
| 1250 NearLabel done; | 1246 Label done; |
| 1251 MemOperand slot_operand = EmitSlotSearch(slot, eax); | 1247 MemOperand slot_operand = EmitSlotSearch(slot, eax); |
| 1252 __ mov(eax, slot_operand); | 1248 __ mov(eax, slot_operand); |
| 1253 __ cmp(eax, isolate()->factory()->the_hole_value()); | 1249 __ cmp(eax, isolate()->factory()->the_hole_value()); |
| 1254 __ j(not_equal, &done); | 1250 __ j(not_equal, &done, Label::kNear); |
| 1255 __ mov(eax, isolate()->factory()->undefined_value()); | 1251 __ mov(eax, isolate()->factory()->undefined_value()); |
| 1256 __ bind(&done); | 1252 __ bind(&done); |
| 1257 context()->Plug(eax); | 1253 context()->Plug(eax); |
| 1258 } else { | 1254 } else { |
| 1259 context()->Plug(slot); | 1255 context()->Plug(slot); |
| 1260 } | 1256 } |
| 1261 | 1257 |
| 1262 } else { | 1258 } else { |
| 1263 Comment cmnt(masm_, "Rewritten parameter"); | 1259 Comment cmnt(masm_, "Rewritten parameter"); |
| 1264 ASSERT_NOT_NULL(property); | 1260 ASSERT_NOT_NULL(property); |
| 1265 // Rewritten parameter accesses are of the form "slot[literal]". | 1261 // Rewritten parameter accesses are of the form "slot[literal]". |
| 1266 | 1262 |
| 1267 // Assert that the object is in a slot. | 1263 // Assert that the object is in a slot. |
| 1268 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); | 1264 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); |
| 1269 ASSERT_NOT_NULL(object_var); | 1265 ASSERT_NOT_NULL(object_var); |
| 1270 Slot* object_slot = object_var->AsSlot(); | 1266 Slot* object_slot = object_var->AsSlot(); |
| 1271 ASSERT_NOT_NULL(object_slot); | 1267 ASSERT_NOT_NULL(object_slot); |
| 1272 | 1268 |
| 1273 // Load the object. | 1269 // Load the object. |
| 1274 MemOperand object_loc = EmitSlotSearch(object_slot, eax); | 1270 MemOperand object_loc = EmitSlotSearch(object_slot, eax); |
| 1275 __ mov(edx, object_loc); | 1271 __ mov(edx, object_loc); |
| 1276 | 1272 |
| 1277 // Assert that the key is a smi. | 1273 // Assert that the key is a smi. |
| 1278 Literal* key_literal = property->key()->AsLiteral(); | 1274 Literal* key_literal = property->key()->AsLiteral(); |
| 1279 ASSERT_NOT_NULL(key_literal); | 1275 ASSERT_NOT_NULL(key_literal); |
| 1280 ASSERT(key_literal->handle()->IsSmi()); | 1276 ASSERT(key_literal->handle()->IsSmi()); |
| 1281 | 1277 |
| 1282 // Load the key. | 1278 // Load the key. |
| 1283 __ mov(eax, Immediate(key_literal->handle())); | 1279 __ SafeSet(eax, Immediate(key_literal->handle())); |
| 1284 | 1280 |
| 1285 // Do a keyed property load. | 1281 // Do a keyed property load. |
| 1286 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 1282 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 1287 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); | 1283 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); |
| 1288 | 1284 |
| 1289 // Drop key and object left on the stack by IC. | 1285 // Drop key and object left on the stack by IC. |
| 1290 context()->Plug(eax); | 1286 context()->Plug(eax); |
| 1291 } | 1287 } |
| 1292 } | 1288 } |
| 1293 | 1289 |
| 1294 | 1290 |
| 1295 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1291 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 1296 Comment cmnt(masm_, "[ RegExpLiteral"); | 1292 Comment cmnt(masm_, "[ RegExpLiteral"); |
| 1297 NearLabel materialized; | 1293 Label materialized; |
| 1298 // Registers will be used as follows: | 1294 // Registers will be used as follows: |
| 1299 // edi = JS function. | 1295 // edi = JS function. |
| 1300 // ecx = literals array. | 1296 // ecx = literals array. |
| 1301 // ebx = regexp literal. | 1297 // ebx = regexp literal. |
| 1302 // eax = regexp literal clone. | 1298 // eax = regexp literal clone. |
| 1303 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 1299 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 1304 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset)); | 1300 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset)); |
| 1305 int literal_offset = | 1301 int literal_offset = |
| 1306 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 1302 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
| 1307 __ mov(ebx, FieldOperand(ecx, literal_offset)); | 1303 __ mov(ebx, FieldOperand(ecx, literal_offset)); |
| 1308 __ cmp(ebx, isolate()->factory()->undefined_value()); | 1304 __ cmp(ebx, isolate()->factory()->undefined_value()); |
| 1309 __ j(not_equal, &materialized); | 1305 __ j(not_equal, &materialized, Label::kNear); |
| 1310 | 1306 |
| 1311 // Create regexp literal using runtime function | 1307 // Create regexp literal using runtime function |
| 1312 // Result will be in eax. | 1308 // Result will be in eax. |
| 1313 __ push(ecx); | 1309 __ push(ecx); |
| 1314 __ push(Immediate(Smi::FromInt(expr->literal_index()))); | 1310 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
| 1315 __ push(Immediate(expr->pattern())); | 1311 __ push(Immediate(expr->pattern())); |
| 1316 __ push(Immediate(expr->flags())); | 1312 __ push(Immediate(expr->flags())); |
| 1317 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 1313 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 1318 __ mov(ebx, eax); | 1314 __ mov(ebx, eax); |
| 1319 | 1315 |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1544 VisitForStackValue(property->obj()); | 1540 VisitForStackValue(property->obj()); |
| 1545 } | 1541 } |
| 1546 break; | 1542 break; |
| 1547 case KEYED_PROPERTY: { | 1543 case KEYED_PROPERTY: { |
| 1548 if (expr->is_compound()) { | 1544 if (expr->is_compound()) { |
| 1549 if (property->is_arguments_access()) { | 1545 if (property->is_arguments_access()) { |
| 1550 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1546 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1551 MemOperand slot_operand = | 1547 MemOperand slot_operand = |
| 1552 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); | 1548 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); |
| 1553 __ push(slot_operand); | 1549 __ push(slot_operand); |
| 1554 __ mov(eax, Immediate(property->key()->AsLiteral()->handle())); | 1550 __ SafeSet(eax, Immediate(property->key()->AsLiteral()->handle())); |
| 1555 } else { | 1551 } else { |
| 1556 VisitForStackValue(property->obj()); | 1552 VisitForStackValue(property->obj()); |
| 1557 VisitForAccumulatorValue(property->key()); | 1553 VisitForAccumulatorValue(property->key()); |
| 1558 } | 1554 } |
| 1559 __ mov(edx, Operand(esp, 0)); | 1555 __ mov(edx, Operand(esp, 0)); |
| 1560 __ push(eax); | 1556 __ push(eax); |
| 1561 } else { | 1557 } else { |
| 1562 if (property->is_arguments_access()) { | 1558 if (property->is_arguments_access()) { |
| 1563 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1559 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1564 MemOperand slot_operand = | 1560 MemOperand slot_operand = |
| 1565 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); | 1561 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); |
| 1566 __ push(slot_operand); | 1562 __ push(slot_operand); |
| 1567 __ push(Immediate(property->key()->AsLiteral()->handle())); | 1563 __ SafePush(Immediate(property->key()->AsLiteral()->handle())); |
| 1568 } else { | 1564 } else { |
| 1569 VisitForStackValue(property->obj()); | 1565 VisitForStackValue(property->obj()); |
| 1570 VisitForStackValue(property->key()); | 1566 VisitForStackValue(property->key()); |
| 1571 } | 1567 } |
| 1572 } | 1568 } |
| 1573 break; | 1569 break; |
| 1574 } | 1570 } |
| 1575 } | 1571 } |
| 1576 | 1572 |
| 1577 // For compound assignments we need another deoptimization point after the | 1573 // For compound assignments we need another deoptimization point after the |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1636 case KEYED_PROPERTY: | 1632 case KEYED_PROPERTY: |
| 1637 EmitKeyedPropertyAssignment(expr); | 1633 EmitKeyedPropertyAssignment(expr); |
| 1638 break; | 1634 break; |
| 1639 } | 1635 } |
| 1640 } | 1636 } |
| 1641 | 1637 |
| 1642 | 1638 |
| 1643 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { | 1639 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
| 1644 SetSourcePosition(prop->position()); | 1640 SetSourcePosition(prop->position()); |
| 1645 Literal* key = prop->key()->AsLiteral(); | 1641 Literal* key = prop->key()->AsLiteral(); |
| 1642 ASSERT(!key->handle()->IsSmi()); |
| 1646 __ mov(ecx, Immediate(key->handle())); | 1643 __ mov(ecx, Immediate(key->handle())); |
| 1647 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1644 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 1648 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | 1645 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); |
| 1649 } | 1646 } |
| 1650 | 1647 |
| 1651 | 1648 |
| 1652 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 1649 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 1653 SetSourcePosition(prop->position()); | 1650 SetSourcePosition(prop->position()); |
| 1654 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 1651 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 1655 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | 1652 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); |
| 1656 } | 1653 } |
| 1657 | 1654 |
| 1658 | 1655 |
| 1659 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, | 1656 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, |
| 1660 Token::Value op, | 1657 Token::Value op, |
| 1661 OverwriteMode mode, | 1658 OverwriteMode mode, |
| 1662 Expression* left, | 1659 Expression* left, |
| 1663 Expression* right) { | 1660 Expression* right) { |
| 1664 // Do combined smi check of the operands. Left operand is on the | 1661 // Do combined smi check of the operands. Left operand is on the |
| 1665 // stack. Right operand is in eax. | 1662 // stack. Right operand is in eax. |
| 1666 NearLabel done, smi_case, stub_call; | 1663 Label smi_case, done, stub_call; |
| 1667 __ pop(edx); | 1664 __ pop(edx); |
| 1668 __ mov(ecx, eax); | 1665 __ mov(ecx, eax); |
| 1669 __ or_(eax, Operand(edx)); | 1666 __ or_(eax, Operand(edx)); |
| 1670 JumpPatchSite patch_site(masm_); | 1667 JumpPatchSite patch_site(masm_); |
| 1671 patch_site.EmitJumpIfSmi(eax, &smi_case); | 1668 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear); |
| 1672 | 1669 |
| 1673 __ bind(&stub_call); | 1670 __ bind(&stub_call); |
| 1674 __ mov(eax, ecx); | 1671 __ mov(eax, ecx); |
| 1675 TypeRecordingBinaryOpStub stub(op, mode); | 1672 TypeRecordingBinaryOpStub stub(op, mode); |
| 1676 EmitCallIC(stub.GetCode(), &patch_site, expr->id()); | 1673 EmitCallIC(stub.GetCode(), &patch_site, expr->id()); |
| 1677 __ jmp(&done); | 1674 __ jmp(&done, Label::kNear); |
| 1678 | 1675 |
| 1679 // Smi case. | 1676 // Smi case. |
| 1680 __ bind(&smi_case); | 1677 __ bind(&smi_case); |
| 1681 __ mov(eax, edx); // Copy left operand in case of a stub call. | 1678 __ mov(eax, edx); // Copy left operand in case of a stub call. |
| 1682 | 1679 |
| 1683 switch (op) { | 1680 switch (op) { |
| 1684 case Token::SAR: | 1681 case Token::SAR: |
| 1685 __ SmiUntag(eax); | 1682 __ SmiUntag(eax); |
| 1686 __ SmiUntag(ecx); | 1683 __ SmiUntag(ecx); |
| 1687 __ sar_cl(eax); // No checks of result necessary | 1684 __ sar_cl(eax); // No checks of result necessary |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1720 break; | 1717 break; |
| 1721 case Token::SUB: | 1718 case Token::SUB: |
| 1722 __ sub(eax, Operand(ecx)); | 1719 __ sub(eax, Operand(ecx)); |
| 1723 __ j(overflow, &stub_call); | 1720 __ j(overflow, &stub_call); |
| 1724 break; | 1721 break; |
| 1725 case Token::MUL: { | 1722 case Token::MUL: { |
| 1726 __ SmiUntag(eax); | 1723 __ SmiUntag(eax); |
| 1727 __ imul(eax, Operand(ecx)); | 1724 __ imul(eax, Operand(ecx)); |
| 1728 __ j(overflow, &stub_call); | 1725 __ j(overflow, &stub_call); |
| 1729 __ test(eax, Operand(eax)); | 1726 __ test(eax, Operand(eax)); |
| 1730 __ j(not_zero, &done, taken); | 1727 __ j(not_zero, &done, Label::kNear); |
| 1731 __ mov(ebx, edx); | 1728 __ mov(ebx, edx); |
| 1732 __ or_(ebx, Operand(ecx)); | 1729 __ or_(ebx, Operand(ecx)); |
| 1733 __ j(negative, &stub_call); | 1730 __ j(negative, &stub_call); |
| 1734 break; | 1731 break; |
| 1735 } | 1732 } |
| 1736 case Token::BIT_OR: | 1733 case Token::BIT_OR: |
| 1737 __ or_(eax, Operand(ecx)); | 1734 __ or_(eax, Operand(ecx)); |
| 1738 break; | 1735 break; |
| 1739 case Token::BIT_AND: | 1736 case Token::BIT_AND: |
| 1740 __ and_(eax, Operand(ecx)); | 1737 __ and_(eax, Operand(ecx)); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1802 } | 1799 } |
| 1803 case KEYED_PROPERTY: { | 1800 case KEYED_PROPERTY: { |
| 1804 __ push(eax); // Preserve value. | 1801 __ push(eax); // Preserve value. |
| 1805 if (prop->is_synthetic()) { | 1802 if (prop->is_synthetic()) { |
| 1806 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 1803 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 1807 ASSERT(prop->key()->AsLiteral() != NULL); | 1804 ASSERT(prop->key()->AsLiteral() != NULL); |
| 1808 { AccumulatorValueContext for_object(this); | 1805 { AccumulatorValueContext for_object(this); |
| 1809 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | 1806 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); |
| 1810 } | 1807 } |
| 1811 __ mov(edx, eax); | 1808 __ mov(edx, eax); |
| 1812 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); | 1809 __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle())); |
| 1813 } else { | 1810 } else { |
| 1814 VisitForStackValue(prop->obj()); | 1811 VisitForStackValue(prop->obj()); |
| 1815 VisitForAccumulatorValue(prop->key()); | 1812 VisitForAccumulatorValue(prop->key()); |
| 1816 __ mov(ecx, eax); | 1813 __ mov(ecx, eax); |
| 1817 __ pop(edx); | 1814 __ pop(edx); |
| 1818 } | 1815 } |
| 1819 __ pop(eax); // Restore value. | 1816 __ pop(eax); // Restore value. |
| 1820 Handle<Code> ic = is_strict_mode() | 1817 Handle<Code> ic = is_strict_mode() |
| 1821 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 1818 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 1822 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 1819 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| (...skipping 493 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2316 int arg_count = args->length(); | 2313 int arg_count = args->length(); |
| 2317 for (int i = 0; i < arg_count; i++) { | 2314 for (int i = 0; i < arg_count; i++) { |
| 2318 VisitForStackValue(args->at(i)); | 2315 VisitForStackValue(args->at(i)); |
| 2319 } | 2316 } |
| 2320 | 2317 |
| 2321 // Call the construct call builtin that handles allocation and | 2318 // Call the construct call builtin that handles allocation and |
| 2322 // constructor invocation. | 2319 // constructor invocation. |
| 2323 SetSourcePosition(expr->position()); | 2320 SetSourcePosition(expr->position()); |
| 2324 | 2321 |
| 2325 // Load function and argument count into edi and eax. | 2322 // Load function and argument count into edi and eax. |
| 2326 __ Set(eax, Immediate(arg_count)); | 2323 __ SafeSet(eax, Immediate(arg_count)); |
| 2327 __ mov(edi, Operand(esp, arg_count * kPointerSize)); | 2324 __ mov(edi, Operand(esp, arg_count * kPointerSize)); |
| 2328 | 2325 |
| 2329 Handle<Code> construct_builtin = | 2326 Handle<Code> construct_builtin = |
| 2330 isolate()->builtins()->JSConstructCall(); | 2327 isolate()->builtins()->JSConstructCall(); |
| 2331 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); | 2328 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); |
| 2332 context()->Plug(eax); | 2329 context()->Plug(eax); |
| 2333 } | 2330 } |
| 2334 | 2331 |
| 2335 | 2332 |
| 2336 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) { | 2333 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) { |
| (...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2656 } | 2653 } |
| 2657 | 2654 |
| 2658 | 2655 |
| 2659 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2656 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
| 2660 ASSERT(args->length() == 1); | 2657 ASSERT(args->length() == 1); |
| 2661 | 2658 |
| 2662 // ArgumentsAccessStub expects the key in edx and the formal | 2659 // ArgumentsAccessStub expects the key in edx and the formal |
| 2663 // parameter count in eax. | 2660 // parameter count in eax. |
| 2664 VisitForAccumulatorValue(args->at(0)); | 2661 VisitForAccumulatorValue(args->at(0)); |
| 2665 __ mov(edx, eax); | 2662 __ mov(edx, eax); |
| 2666 __ mov(eax, Immediate(Smi::FromInt(scope()->num_parameters()))); | 2663 __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters()))); |
| 2667 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 2664 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 2668 __ CallStub(&stub); | 2665 __ CallStub(&stub); |
| 2669 context()->Plug(eax); | 2666 context()->Plug(eax); |
| 2670 } | 2667 } |
| 2671 | 2668 |
| 2672 | 2669 |
| 2673 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { | 2670 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { |
| 2674 ASSERT(args->length() == 0); | 2671 ASSERT(args->length() == 0); |
| 2675 | 2672 |
| 2676 Label exit; | 2673 Label exit; |
| 2677 // Get the number of formal parameters. | 2674 // Get the number of formal parameters. |
| 2678 __ Set(eax, Immediate(Smi::FromInt(scope()->num_parameters()))); | 2675 __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters()))); |
| 2679 | 2676 |
| 2680 // Check if the calling frame is an arguments adaptor frame. | 2677 // Check if the calling frame is an arguments adaptor frame. |
| 2681 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 2678 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
| 2682 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset), | 2679 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset), |
| 2683 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 2680 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2684 __ j(not_equal, &exit); | 2681 __ j(not_equal, &exit); |
| 2685 | 2682 |
| 2686 // Arguments adaptor case: Read the arguments length from the | 2683 // Arguments adaptor case: Read the arguments length from the |
| 2687 // adaptor frame. | 2684 // adaptor frame. |
| 2688 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 2685 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2843 __ CallStub(&stub); | 2840 __ CallStub(&stub); |
| 2844 context()->Plug(eax); | 2841 context()->Plug(eax); |
| 2845 } | 2842 } |
| 2846 | 2843 |
| 2847 | 2844 |
| 2848 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) { | 2845 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) { |
| 2849 ASSERT(args->length() == 1); | 2846 ASSERT(args->length() == 1); |
| 2850 | 2847 |
| 2851 VisitForAccumulatorValue(args->at(0)); // Load the object. | 2848 VisitForAccumulatorValue(args->at(0)); // Load the object. |
| 2852 | 2849 |
| 2853 NearLabel done; | 2850 Label done; |
| 2854 // If the object is a smi return the object. | 2851 // If the object is a smi return the object. |
| 2855 __ test(eax, Immediate(kSmiTagMask)); | 2852 __ test(eax, Immediate(kSmiTagMask)); |
| 2856 __ j(zero, &done); | 2853 __ j(zero, &done, Label::kNear); |
| 2857 // If the object is not a value type, return the object. | 2854 // If the object is not a value type, return the object. |
| 2858 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx); | 2855 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx); |
| 2859 __ j(not_equal, &done); | 2856 __ j(not_equal, &done, Label::kNear); |
| 2860 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); | 2857 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); |
| 2861 | 2858 |
| 2862 __ bind(&done); | 2859 __ bind(&done); |
| 2863 context()->Plug(eax); | 2860 context()->Plug(eax); |
| 2864 } | 2861 } |
| 2865 | 2862 |
| 2866 | 2863 |
| 2867 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) { | 2864 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) { |
| 2868 // Load the arguments on the stack and call the runtime function. | 2865 // Load the arguments on the stack and call the runtime function. |
| 2869 ASSERT(args->length() == 2); | 2866 ASSERT(args->length() == 2); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2883 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { | 2880 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { |
| 2884 ASSERT(args->length() == 2); | 2881 ASSERT(args->length() == 2); |
| 2885 | 2882 |
| 2886 VisitForStackValue(args->at(0)); // Load the object. | 2883 VisitForStackValue(args->at(0)); // Load the object. |
| 2887 VisitForAccumulatorValue(args->at(1)); // Load the value. | 2884 VisitForAccumulatorValue(args->at(1)); // Load the value. |
| 2888 __ pop(ebx); // eax = value. ebx = object. | 2885 __ pop(ebx); // eax = value. ebx = object. |
| 2889 | 2886 |
| 2890 Label done; | 2887 Label done; |
| 2891 // If the object is a smi, return the value. | 2888 // If the object is a smi, return the value. |
| 2892 __ test(ebx, Immediate(kSmiTagMask)); | 2889 __ test(ebx, Immediate(kSmiTagMask)); |
| 2893 __ j(zero, &done); | 2890 __ j(zero, &done, Label::kNear); |
| 2894 | 2891 |
| 2895 // If the object is not a value type, return the value. | 2892 // If the object is not a value type, return the value. |
| 2896 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx); | 2893 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx); |
| 2897 __ j(not_equal, &done); | 2894 __ j(not_equal, &done, Label::kNear); |
| 2898 | 2895 |
| 2899 // Store the value. | 2896 // Store the value. |
| 2900 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax); | 2897 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax); |
| 2901 | 2898 |
| 2902 // Update the write barrier. Save the value as it will be | 2899 // Update the write barrier. Save the value as it will be |
| 2903 // overwritten by the write barrier code and is needed afterward. | 2900 // overwritten by the write barrier code and is needed afterward. |
| 2904 __ mov(edx, eax); | 2901 __ mov(edx, eax); |
| 2905 __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs); | 2902 __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs); |
| 2906 | 2903 |
| 2907 __ bind(&done); | 2904 __ bind(&done); |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3177 // Bring addresses into index1 and index2. | 3174 // Bring addresses into index1 and index2. |
| 3178 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1)); | 3175 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1)); |
| 3179 __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2)); | 3176 __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2)); |
| 3180 | 3177 |
| 3181 // Swap elements. Use object and temp as scratch registers. | 3178 // Swap elements. Use object and temp as scratch registers. |
| 3182 __ mov(object, Operand(index_1, 0)); | 3179 __ mov(object, Operand(index_1, 0)); |
| 3183 __ mov(temp, Operand(index_2, 0)); | 3180 __ mov(temp, Operand(index_2, 0)); |
| 3184 __ mov(Operand(index_2, 0), object); | 3181 __ mov(Operand(index_2, 0), object); |
| 3185 __ mov(Operand(index_1, 0), temp); | 3182 __ mov(Operand(index_1, 0), temp); |
| 3186 | 3183 |
| 3187 NearLabel no_remembered_set; | 3184 Label no_remembered_set; |
| 3188 __ InNewSpace(elements, temp, equal, &no_remembered_set); | 3185 __ InNewSpace(elements, temp, equal, &no_remembered_set, Label::kNear); |
| 3189 __ CheckPageFlag(elements, | 3186 __ CheckPageFlag(elements, |
| 3190 temp, | 3187 temp, |
| 3191 MemoryChunk::SCAN_ON_SCAVENGE, | 3188 MemoryChunk::SCAN_ON_SCAVENGE, |
| 3192 not_zero, | 3189 not_zero, |
| 3193 &no_remembered_set); | 3190 &no_remembered_set, |
| 3191 Label::kNear); |
| 3194 | 3192 |
| 3195 __ mov(object, elements); | 3193 __ mov(object, elements); |
| 3196 // Since we are swapping two objects, the incremental marker is not disturbed, | 3194 // Since we are swapping two objects, the incremental marker is not disturbed, |
| 3197 // so we don't call the stub that handles this. TODO(gc): Optimize by | 3195 // so we don't call the stub that handles this. TODO(gc): Optimize by |
| 3198 // checking the scan_on_scavenge flag, probably by calling the stub. | 3196 // checking the scan_on_scavenge flag, probably by calling the stub. |
| 3199 __ RememberedSetHelper(index_1, temp, kDontSaveFPRegs); | 3197 __ RememberedSetHelper(index_1, temp, kDontSaveFPRegs); |
| 3200 __ RememberedSetHelper(index_2, temp, kDontSaveFPRegs); | 3198 __ RememberedSetHelper(index_2, temp, kDontSaveFPRegs); |
| 3201 | 3199 |
| 3202 __ bind(&no_remembered_set); | 3200 __ bind(&no_remembered_set); |
| 3203 | 3201 |
| (...skipping 615 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3819 // Put the object both on the stack and in the accumulator. | 3817 // Put the object both on the stack and in the accumulator. |
| 3820 VisitForAccumulatorValue(prop->obj()); | 3818 VisitForAccumulatorValue(prop->obj()); |
| 3821 __ push(eax); | 3819 __ push(eax); |
| 3822 EmitNamedPropertyLoad(prop); | 3820 EmitNamedPropertyLoad(prop); |
| 3823 } else { | 3821 } else { |
| 3824 if (prop->is_arguments_access()) { | 3822 if (prop->is_arguments_access()) { |
| 3825 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); | 3823 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); |
| 3826 MemOperand slot_operand = | 3824 MemOperand slot_operand = |
| 3827 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); | 3825 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); |
| 3828 __ push(slot_operand); | 3826 __ push(slot_operand); |
| 3829 __ mov(eax, Immediate(prop->key()->AsLiteral()->handle())); | 3827 __ SafeSet(eax, Immediate(prop->key()->AsLiteral()->handle())); |
| 3830 } else { | 3828 } else { |
| 3831 VisitForStackValue(prop->obj()); | 3829 VisitForStackValue(prop->obj()); |
| 3832 VisitForAccumulatorValue(prop->key()); | 3830 VisitForAccumulatorValue(prop->key()); |
| 3833 } | 3831 } |
| 3834 __ mov(edx, Operand(esp, 0)); | 3832 __ mov(edx, Operand(esp, 0)); |
| 3835 __ push(eax); | 3833 __ push(eax); |
| 3836 EmitKeyedPropertyLoad(prop); | 3834 EmitKeyedPropertyLoad(prop); |
| 3837 } | 3835 } |
| 3838 } | 3836 } |
| 3839 | 3837 |
| 3840 // We need a second deoptimization point after loading the value | 3838 // We need a second deoptimization point after loading the value |
| 3841 // in case evaluating the property load my have a side effect. | 3839 // in case evaluating the property load my have a side effect. |
| 3842 if (assign_type == VARIABLE) { | 3840 if (assign_type == VARIABLE) { |
| 3843 PrepareForBailout(expr->expression(), TOS_REG); | 3841 PrepareForBailout(expr->expression(), TOS_REG); |
| 3844 } else { | 3842 } else { |
| 3845 PrepareForBailoutForId(expr->CountId(), TOS_REG); | 3843 PrepareForBailoutForId(expr->CountId(), TOS_REG); |
| 3846 } | 3844 } |
| 3847 | 3845 |
| 3848 // Call ToNumber only if operand is not a smi. | 3846 // Call ToNumber only if operand is not a smi. |
| 3849 NearLabel no_conversion; | 3847 Label no_conversion; |
| 3850 if (ShouldInlineSmiCase(expr->op())) { | 3848 if (ShouldInlineSmiCase(expr->op())) { |
| 3851 __ test(eax, Immediate(kSmiTagMask)); | 3849 __ test(eax, Immediate(kSmiTagMask)); |
| 3852 __ j(zero, &no_conversion); | 3850 __ j(zero, &no_conversion, Label::kNear); |
| 3853 } | 3851 } |
| 3854 ToNumberStub convert_stub; | 3852 ToNumberStub convert_stub; |
| 3855 __ CallStub(&convert_stub); | 3853 __ CallStub(&convert_stub); |
| 3856 __ bind(&no_conversion); | 3854 __ bind(&no_conversion); |
| 3857 | 3855 |
| 3858 // Save result for postfix expressions. | 3856 // Save result for postfix expressions. |
| 3859 if (expr->is_postfix()) { | 3857 if (expr->is_postfix()) { |
| 3860 if (!context()->IsEffect()) { | 3858 if (!context()->IsEffect()) { |
| 3861 // Save the result on the stack. If we have a named or keyed property | 3859 // Save the result on the stack. If we have a named or keyed property |
| 3862 // we store the result under the receiver that is currently on top | 3860 // we store the result under the receiver that is currently on top |
| 3863 // of the stack. | 3861 // of the stack. |
| 3864 switch (assign_type) { | 3862 switch (assign_type) { |
| 3865 case VARIABLE: | 3863 case VARIABLE: |
| 3866 __ push(eax); | 3864 __ push(eax); |
| 3867 break; | 3865 break; |
| 3868 case NAMED_PROPERTY: | 3866 case NAMED_PROPERTY: |
| 3869 __ mov(Operand(esp, kPointerSize), eax); | 3867 __ mov(Operand(esp, kPointerSize), eax); |
| 3870 break; | 3868 break; |
| 3871 case KEYED_PROPERTY: | 3869 case KEYED_PROPERTY: |
| 3872 __ mov(Operand(esp, 2 * kPointerSize), eax); | 3870 __ mov(Operand(esp, 2 * kPointerSize), eax); |
| 3873 break; | 3871 break; |
| 3874 } | 3872 } |
| 3875 } | 3873 } |
| 3876 } | 3874 } |
| 3877 | 3875 |
| 3878 // Inline smi case if we are in a loop. | 3876 // Inline smi case if we are in a loop. |
| 3879 NearLabel stub_call, done; | 3877 Label done, stub_call; |
| 3880 JumpPatchSite patch_site(masm_); | 3878 JumpPatchSite patch_site(masm_); |
| 3881 | 3879 |
| 3882 if (ShouldInlineSmiCase(expr->op())) { | 3880 if (ShouldInlineSmiCase(expr->op())) { |
| 3883 if (expr->op() == Token::INC) { | 3881 if (expr->op() == Token::INC) { |
| 3884 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 3882 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 3885 } else { | 3883 } else { |
| 3886 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); | 3884 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); |
| 3887 } | 3885 } |
| 3888 __ j(overflow, &stub_call); | 3886 __ j(overflow, &stub_call, Label::kNear); |
| 3889 // We could eliminate this smi check if we split the code at | 3887 // We could eliminate this smi check if we split the code at |
| 3890 // the first smi check before calling ToNumber. | 3888 // the first smi check before calling ToNumber. |
| 3891 patch_site.EmitJumpIfSmi(eax, &done); | 3889 patch_site.EmitJumpIfSmi(eax, &done, Label::kNear); |
| 3892 | 3890 |
| 3893 __ bind(&stub_call); | 3891 __ bind(&stub_call); |
| 3894 // Call stub. Undo operation first. | 3892 // Call stub. Undo operation first. |
| 3895 if (expr->op() == Token::INC) { | 3893 if (expr->op() == Token::INC) { |
| 3896 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); | 3894 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); |
| 3897 } else { | 3895 } else { |
| 3898 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 3896 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 3899 } | 3897 } |
| 3900 } | 3898 } |
| 3901 | 3899 |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4164 break; | 4162 break; |
| 4165 case Token::IN: | 4163 case Token::IN: |
| 4166 case Token::INSTANCEOF: | 4164 case Token::INSTANCEOF: |
| 4167 default: | 4165 default: |
| 4168 UNREACHABLE(); | 4166 UNREACHABLE(); |
| 4169 } | 4167 } |
| 4170 | 4168 |
| 4171 bool inline_smi_code = ShouldInlineSmiCase(op); | 4169 bool inline_smi_code = ShouldInlineSmiCase(op); |
| 4172 JumpPatchSite patch_site(masm_); | 4170 JumpPatchSite patch_site(masm_); |
| 4173 if (inline_smi_code) { | 4171 if (inline_smi_code) { |
| 4174 NearLabel slow_case; | 4172 Label slow_case; |
| 4175 __ mov(ecx, Operand(edx)); | 4173 __ mov(ecx, Operand(edx)); |
| 4176 __ or_(ecx, Operand(eax)); | 4174 __ or_(ecx, Operand(eax)); |
| 4177 patch_site.EmitJumpIfNotSmi(ecx, &slow_case); | 4175 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); |
| 4178 __ cmp(edx, Operand(eax)); | 4176 __ cmp(edx, Operand(eax)); |
| 4179 Split(cc, if_true, if_false, NULL); | 4177 Split(cc, if_true, if_false, NULL); |
| 4180 __ bind(&slow_case); | 4178 __ bind(&slow_case); |
| 4181 } | 4179 } |
| 4182 | 4180 |
| 4183 // Record position and call the compare IC. | 4181 // Record position and call the compare IC. |
| 4184 SetSourcePosition(expr->position()); | 4182 SetSourcePosition(expr->position()); |
| 4185 Handle<Code> ic = CompareIC::GetUninitialized(op); | 4183 Handle<Code> ic = CompareIC::GetUninitialized(op); |
| 4186 EmitCallIC(ic, &patch_site, expr->id()); | 4184 EmitCallIC(ic, &patch_site, expr->id()); |
| 4187 | 4185 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4335 // And return. | 4333 // And return. |
| 4336 __ ret(0); | 4334 __ ret(0); |
| 4337 } | 4335 } |
| 4338 | 4336 |
| 4339 | 4337 |
| 4340 #undef __ | 4338 #undef __ |
| 4341 | 4339 |
| 4342 } } // namespace v8::internal | 4340 } } // namespace v8::internal |
| 4343 | 4341 |
| 4344 #endif // V8_TARGET_ARCH_IA32 | 4342 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |