| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 deferred_(8), | 79 deferred_(8), |
| 80 masm_(new MacroAssembler(NULL, buffer_size)), | 80 masm_(new MacroAssembler(NULL, buffer_size)), |
| 81 scope_(NULL), | 81 scope_(NULL), |
| 82 frame_(NULL), | 82 frame_(NULL), |
| 83 allocator_(NULL), | 83 allocator_(NULL), |
| 84 cc_reg_(no_condition), | 84 cc_reg_(no_condition), |
| 85 state_(NULL), | 85 state_(NULL), |
| 86 is_inside_try_(false), | 86 is_inside_try_(false), |
| 87 break_stack_height_(0), | 87 break_stack_height_(0), |
| 88 loop_nesting_(0), | 88 loop_nesting_(0), |
| 89 function_return_is_shadowed_(false) { | 89 function_return_is_shadowed_(false), |
| 90 in_spilled_code_(false) { |
| 90 } | 91 } |
| 91 | 92 |
| 92 | 93 |
| 93 void CodeGenerator::SetFrame(VirtualFrame* new_frame) { | 94 void CodeGenerator::SetFrame(VirtualFrame* new_frame) { |
| 94 if (frame_ != NULL) { | 95 if (frame_ != NULL) { |
| 95 frame_->DetachFromCodeGenerator(); | 96 frame_->DetachFromCodeGenerator(); |
| 96 } | 97 } |
| 97 if (new_frame != NULL) { | 98 if (new_frame != NULL) { |
| 98 new_frame->AttachToCodeGenerator(); | 99 new_frame->AttachToCodeGenerator(); |
| 99 } | 100 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 126 ASSERT(scope_ == NULL); | 127 ASSERT(scope_ == NULL); |
| 127 scope_ = fun->scope(); | 128 scope_ = fun->scope(); |
| 128 ASSERT(allocator_ == NULL); | 129 ASSERT(allocator_ == NULL); |
| 129 RegisterAllocator register_allocator(this); | 130 RegisterAllocator register_allocator(this); |
| 130 allocator_ = ®ister_allocator; | 131 allocator_ = ®ister_allocator; |
| 131 ASSERT(frame_ == NULL); | 132 ASSERT(frame_ == NULL); |
| 132 SetFrame(new VirtualFrame(this)); | 133 SetFrame(new VirtualFrame(this)); |
| 133 cc_reg_ = no_condition; | 134 cc_reg_ = no_condition; |
| 134 function_return_.set_code_generator(this); | 135 function_return_.set_code_generator(this); |
| 135 function_return_is_shadowed_ = false; | 136 function_return_is_shadowed_ = false; |
| 137 set_in_spilled_code(false); |
| 136 | 138 |
| 137 // Adjust for function-level loop nesting. | 139 // Adjust for function-level loop nesting. |
| 138 loop_nesting_ += fun->loop_nesting(); | 140 loop_nesting_ += fun->loop_nesting(); |
| 139 | 141 |
| 140 { | 142 { |
| 141 CodeGenState state(this); | 143 CodeGenState state(this); |
| 142 | 144 |
| 143 // Entry | 145 // Entry |
| 144 // stack: function, receiver, arguments, return address | 146 // stack: function, receiver, arguments, return address |
| 145 // esp: stack pointer | 147 // esp: stack pointer |
| (...skipping 13 matching lines...) Expand all Loading... |
| 159 #endif | 161 #endif |
| 160 | 162 |
| 161 // Allocate space for locals and initialize them. | 163 // Allocate space for locals and initialize them. |
| 162 frame_->AllocateStackSlots(scope_->num_stack_slots()); | 164 frame_->AllocateStackSlots(scope_->num_stack_slots()); |
| 163 | 165 |
| 164 // Allocate the arguments object and copy the parameters into it. | 166 // Allocate the arguments object and copy the parameters into it. |
| 165 if (scope_->arguments() != NULL) { | 167 if (scope_->arguments() != NULL) { |
| 166 ASSERT(scope_->arguments_shadow() != NULL); | 168 ASSERT(scope_->arguments_shadow() != NULL); |
| 167 Comment cmnt(masm_, "[ Allocate arguments object"); | 169 Comment cmnt(masm_, "[ Allocate arguments object"); |
| 168 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 170 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 169 frame_->SpillAll(); | 171 VirtualFrame::SpilledScope spilled_scope(this); |
| 170 __ lea(eax, frame_->Receiver()); | 172 __ lea(eax, frame_->Receiver()); |
| 171 frame_->EmitPush(frame_->Function()); | 173 frame_->EmitPush(frame_->Function()); |
| 172 frame_->EmitPush(eax); | 174 frame_->EmitPush(eax); |
| 173 frame_->EmitPush(Immediate(Smi::FromInt(scope_->num_parameters()))); | 175 frame_->EmitPush(Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 174 frame_->CallStub(&stub, 3); | 176 frame_->CallStub(&stub, 3); |
| 175 frame_->Push(eax); | 177 frame_->Push(eax); |
| 176 } | 178 } |
| 177 | 179 |
| 178 if (scope_->num_heap_slots() > 0) { | 180 if (scope_->num_heap_slots() > 0) { |
| 179 Comment cmnt(masm_, "[ allocate local context"); | 181 Comment cmnt(masm_, "[ allocate local context"); |
| 180 // Allocate local context. | 182 // Allocate local context. |
| 181 // Get outer context and create a new context based on it. | 183 // Get outer context and create a new context based on it. |
| 182 frame_->SpillAll(); | 184 VirtualFrame::SpilledScope spilled_scope(this); |
| 183 frame_->EmitPush(frame_->Function()); | 185 frame_->EmitPush(frame_->Function()); |
| 184 frame_->CallRuntime(Runtime::kNewContext, 1); // eax holds the result | 186 frame_->CallRuntime(Runtime::kNewContext, 1); // eax holds the result |
| 185 | 187 |
| 186 if (kDebug) { | 188 if (kDebug) { |
| 187 JumpTarget verified_true(this); | 189 JumpTarget verified_true(this); |
| 188 // Verify eax and esi are the same in debug mode | 190 // Verify eax and esi are the same in debug mode |
| 189 __ cmp(eax, Operand(esi)); | 191 __ cmp(eax, Operand(esi)); |
| 190 verified_true.Branch(equal); | 192 verified_true.Branch(equal); |
| 191 __ int3(); | 193 __ int3(); |
| 192 verified_true.Bind(); | 194 verified_true.Bind(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 207 // needs to be copied into the context, it must be the last argument | 209 // needs to be copied into the context, it must be the last argument |
| 208 // passed to the parameter that needs to be copied. This is a rare | 210 // passed to the parameter that needs to be copied. This is a rare |
| 209 // case so we don't check for it, instead we rely on the copying | 211 // case so we don't check for it, instead we rely on the copying |
| 210 // order: such a parameter is copied repeatedly into the same | 212 // order: such a parameter is copied repeatedly into the same |
| 211 // context location and thus the last value is what is seen inside | 213 // context location and thus the last value is what is seen inside |
| 212 // the function. | 214 // the function. |
| 213 for (int i = 0; i < scope_->num_parameters(); i++) { | 215 for (int i = 0; i < scope_->num_parameters(); i++) { |
| 214 Variable* par = scope_->parameter(i); | 216 Variable* par = scope_->parameter(i); |
| 215 Slot* slot = par->slot(); | 217 Slot* slot = par->slot(); |
| 216 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 218 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 217 frame_->SpillAll(); | 219 VirtualFrame::SpilledScope spilled_scope(this); |
| 218 ASSERT(!scope_->is_global_scope()); // no parameters in global scope | 220 ASSERT(!scope_->is_global_scope()); // no parameters in global scope |
| 219 __ mov(eax, frame_->ParameterAt(i)); | 221 __ mov(eax, frame_->ParameterAt(i)); |
| 220 // Loads ecx with context; used below in RecordWrite. | 222 // Loads ecx with context; used below in RecordWrite. |
| 221 __ mov(SlotOperand(slot, edx), eax); | 223 __ mov(SlotOperand(slot, edx), eax); |
| 222 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 224 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 223 __ RecordWrite(edx, offset, eax, ebx); | 225 __ RecordWrite(edx, offset, eax, ebx); |
| 224 } | 226 } |
| 225 } | 227 } |
| 226 } | 228 } |
| 227 | 229 |
| 228 // This section stores the pointer to the arguments object that | 230 // This section stores the pointer to the arguments object that |
| 229 // was allocated and copied into above. If the address was not | 231 // was allocated and copied into above. If the address was not |
| 230 // saved to TOS, we push ecx onto the stack. | 232 // saved to TOS, we push ecx onto the stack. |
| 231 // | 233 // |
| 232 // Store the arguments object. This must happen after context | 234 // Store the arguments object. This must happen after context |
| 233 // initialization because the arguments object may be stored in the | 235 // initialization because the arguments object may be stored in the |
| 234 // context. | 236 // context. |
| 235 if (scope_->arguments() != NULL) { | 237 if (scope_->arguments() != NULL) { |
| 236 frame_->SpillAll(); | 238 VirtualFrame::SpilledScope spilled_scope(this); |
| 237 Comment cmnt(masm_, "[ store arguments object"); | 239 Comment cmnt(masm_, "[ store arguments object"); |
| 238 { Reference shadow_ref(this, scope_->arguments_shadow()); | 240 { Reference shadow_ref(this, scope_->arguments_shadow()); |
| 239 ASSERT(shadow_ref.is_slot()); | 241 ASSERT(shadow_ref.is_slot()); |
| 240 { Reference arguments_ref(this, scope_->arguments()); | 242 { Reference arguments_ref(this, scope_->arguments()); |
| 241 ASSERT(arguments_ref.is_slot()); | 243 ASSERT(arguments_ref.is_slot()); |
| 242 // Here we rely on the convenient property that references to slot | 244 // Here we rely on the convenient property that references to slot |
| 243 // take up zero space in the frame (ie, it doesn't matter that the | 245 // take up zero space in the frame (ie, it doesn't matter that the |
| 244 // stored value is actually below the reference on the frame). | 246 // stored value is actually below the reference on the frame). |
| 245 arguments_ref.SetValue(NOT_CONST_INIT); | 247 arguments_ref.SetValue(NOT_CONST_INIT); |
| 246 } | 248 } |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 // (partially) translated into branches, or it may have set the condition | 375 // (partially) translated into branches, or it may have set the condition |
| 374 // code register. If force_cc is set, the value is forced to set the | 376 // code register. If force_cc is set, the value is forced to set the |
| 375 // condition code register and no value is pushed. If the condition code | 377 // condition code register and no value is pushed. If the condition code |
| 376 // register was set, has_cc() is true and cc_reg_ contains the condition to | 378 // register was set, has_cc() is true and cc_reg_ contains the condition to |
| 377 // test for 'true'. | 379 // test for 'true'. |
| 378 void CodeGenerator::LoadCondition(Expression* x, | 380 void CodeGenerator::LoadCondition(Expression* x, |
| 379 TypeofState typeof_state, | 381 TypeofState typeof_state, |
| 380 JumpTarget* true_target, | 382 JumpTarget* true_target, |
| 381 JumpTarget* false_target, | 383 JumpTarget* false_target, |
| 382 bool force_cc) { | 384 bool force_cc) { |
| 385 ASSERT(!in_spilled_code()); |
| 383 ASSERT(!has_cc()); | 386 ASSERT(!has_cc()); |
| 384 | 387 |
| 385 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 388 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| 386 Visit(x); | 389 Visit(x); |
| 387 } | 390 } |
| 388 | 391 |
| 389 if (force_cc && frame_ != NULL && !has_cc()) { | 392 if (force_cc && frame_ != NULL && !has_cc()) { |
| 390 // Convert the TOS value to a boolean in the condition code register. | 393 // Convert the TOS value to a boolean in the condition code register. |
| 391 frame_->SpillAll(); | 394 VirtualFrame::SpilledScope spilled_scope(this); |
| 392 ToBoolean(true_target, false_target); | 395 ToBoolean(true_target, false_target); |
| 393 } | 396 } |
| 394 | 397 |
| 395 ASSERT(!force_cc || frame_ == NULL || has_cc()); | 398 ASSERT(!force_cc || frame_ == NULL || has_cc()); |
| 396 } | 399 } |
| 397 | 400 |
| 398 | 401 |
| 399 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 402 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 403 ASSERT(!in_spilled_code()); |
| 400 JumpTarget true_target(this); | 404 JumpTarget true_target(this); |
| 401 JumpTarget false_target(this); | 405 JumpTarget false_target(this); |
| 402 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 406 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 403 | 407 |
| 404 if (has_cc()) { | 408 if (has_cc()) { |
| 405 ASSERT(frame_ != NULL); | 409 ASSERT(frame_ != NULL); |
| 406 frame_->SpillAll(); | 410 VirtualFrame::SpilledScope spilled_scope(this); |
| 407 // Convert cc_reg_ into a boolean value. | 411 // Convert cc_reg_ into a boolean value. |
| 408 JumpTarget loaded(this); | 412 JumpTarget loaded(this); |
| 409 JumpTarget materialize_true(this); | 413 JumpTarget materialize_true(this); |
| 410 materialize_true.Branch(cc_reg_); | 414 materialize_true.Branch(cc_reg_); |
| 411 frame_->EmitPush(Immediate(Factory::false_value())); | 415 frame_->EmitPush(Immediate(Factory::false_value())); |
| 412 loaded.Jump(); | 416 loaded.Jump(); |
| 413 materialize_true.Bind(); | 417 materialize_true.Bind(); |
| 414 frame_->EmitPush(Immediate(Factory::true_value())); | 418 frame_->EmitPush(Immediate(Factory::true_value())); |
| 415 loaded.Bind(); | 419 loaded.Bind(); |
| 416 cc_reg_ = no_condition; | 420 cc_reg_ = no_condition; |
| 417 } | 421 } |
| 418 | 422 |
| 419 if (true_target.is_linked() || false_target.is_linked()) { | 423 if (true_target.is_linked() || false_target.is_linked()) { |
| 420 // We have at least one condition value that has been "translated" into | 424 // We have at least one condition value that has been "translated" into |
| 421 // a branch, thus it needs to be loaded explicitly. | 425 // a branch, thus it needs to be loaded explicitly. |
| 422 JumpTarget loaded(this); | 426 JumpTarget loaded(this); |
| 423 if (frame_ != NULL) { | 427 if (frame_ != NULL) { |
| 424 loaded.Jump(); // Don't lose the current TOS. | 428 loaded.Jump(); // Don't lose the current TOS. |
| 425 } | 429 } |
| 426 bool both = true_target.is_linked() && false_target.is_linked(); | 430 bool both = true_target.is_linked() && false_target.is_linked(); |
| 427 // Load "true" if necessary. | 431 // Load "true" if necessary. |
| 428 if (true_target.is_linked()) { | 432 if (true_target.is_linked()) { |
| 429 true_target.Bind(); | 433 true_target.Bind(); |
| 430 frame_->SpillAll(); | 434 VirtualFrame::SpilledScope spilled_scope(this); |
| 431 frame_->EmitPush(Immediate(Factory::true_value())); | 435 frame_->EmitPush(Immediate(Factory::true_value())); |
| 432 } | 436 } |
| 433 // If both "true" and "false" need to be reincarnated jump across the | 437 // If both "true" and "false" need to be reincarnated jump across the |
| 434 // code for "false". | 438 // code for "false". |
| 435 if (both) { | 439 if (both) { |
| 436 loaded.Jump(); | 440 loaded.Jump(); |
| 437 } | 441 } |
| 438 // Load "false" if necessary. | 442 // Load "false" if necessary. |
| 439 if (false_target.is_linked()) { | 443 if (false_target.is_linked()) { |
| 440 false_target.Bind(); | 444 false_target.Bind(); |
| 441 frame_->SpillAll(); | 445 VirtualFrame::SpilledScope spilled_scope(this); |
| 442 frame_->EmitPush(Immediate(Factory::false_value())); | 446 frame_->EmitPush(Immediate(Factory::false_value())); |
| 443 } | 447 } |
| 444 // A value is loaded on all paths reaching this point. | 448 // A value is loaded on all paths reaching this point. |
| 445 loaded.Bind(); | 449 loaded.Bind(); |
| 446 } | 450 } |
| 447 ASSERT(frame_ != NULL); | 451 ASSERT(frame_ != NULL); |
| 448 ASSERT(!has_cc()); | 452 ASSERT(!has_cc()); |
| 449 } | 453 } |
| 450 | 454 |
| 451 | 455 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 467 Variable* variable = x->AsVariableProxy()->AsVariable(); | 471 Variable* variable = x->AsVariableProxy()->AsVariable(); |
| 468 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 472 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
| 469 // NOTE: This is somewhat nasty. We force the compiler to load | 473 // NOTE: This is somewhat nasty. We force the compiler to load |
| 470 // the variable as if through '<global>.<variable>' to make sure we | 474 // the variable as if through '<global>.<variable>' to make sure we |
| 471 // do not get reference errors. | 475 // do not get reference errors. |
| 472 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); | 476 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); |
| 473 Literal key(variable->name()); | 477 Literal key(variable->name()); |
| 474 // TODO(1241834): Fetch the position from the variable instead of using | 478 // TODO(1241834): Fetch the position from the variable instead of using |
| 475 // no position. | 479 // no position. |
| 476 Property property(&global, &key, RelocInfo::kNoPosition); | 480 Property property(&global, &key, RelocInfo::kNoPosition); |
| 477 Load(&property); | 481 LoadAndSpill(&property); |
| 478 frame_->SpillAll(); | |
| 479 } else { | 482 } else { |
| 480 Load(x, INSIDE_TYPEOF); | 483 LoadAndSpill(x, INSIDE_TYPEOF); |
| 481 frame_->SpillAll(); | |
| 482 } | 484 } |
| 483 } | 485 } |
| 484 | 486 |
| 485 | 487 |
| 486 Reference::Reference(CodeGenerator* cgen, Expression* expression) | 488 Reference::Reference(CodeGenerator* cgen, Expression* expression) |
| 487 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { | 489 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { |
| 488 cgen->LoadReference(this); | 490 cgen->LoadReference(this); |
| 489 } | 491 } |
| 490 | 492 |
| 491 | 493 |
| 492 Reference::~Reference() { | 494 Reference::~Reference() { |
| 493 cgen_->UnloadReference(this); | 495 cgen_->UnloadReference(this); |
| 494 } | 496 } |
| 495 | 497 |
| 496 | 498 |
| 497 void CodeGenerator::LoadReference(Reference* ref) { | 499 void CodeGenerator::LoadReference(Reference* ref) { |
| 498 Comment cmnt(masm_, "[ LoadReference"); | 500 Comment cmnt(masm_, "[ LoadReference"); |
| 499 Expression* e = ref->expression(); | 501 Expression* e = ref->expression(); |
| 500 Property* property = e->AsProperty(); | 502 Property* property = e->AsProperty(); |
| 501 Variable* var = e->AsVariableProxy()->AsVariable(); | 503 Variable* var = e->AsVariableProxy()->AsVariable(); |
| 502 | 504 |
| 503 if (property != NULL) { | 505 if (property != NULL) { |
| 506 VirtualFrame::SpilledScope spilled_scope(this); |
| 504 // The expression is either a property or a variable proxy that rewrites | 507 // The expression is either a property or a variable proxy that rewrites |
| 505 // to a property. | 508 // to a property. |
| 506 Load(property->obj()); | 509 LoadAndSpill(property->obj()); |
| 507 frame_->SpillAll(); | |
| 508 // We use a named reference if the key is a literal symbol, unless it is | 510 // We use a named reference if the key is a literal symbol, unless it is |
| 509 // a string that can be legally parsed as an integer. This is because | 511 // a string that can be legally parsed as an integer. This is because |
| 510 // otherwise we will not get into the slow case code that handles [] on | 512 // otherwise we will not get into the slow case code that handles [] on |
| 511 // String objects. | 513 // String objects. |
| 512 Literal* literal = property->key()->AsLiteral(); | 514 Literal* literal = property->key()->AsLiteral(); |
| 513 uint32_t dummy; | 515 uint32_t dummy; |
| 514 if (literal != NULL && | 516 if (literal != NULL && |
| 515 literal->handle()->IsSymbol() && | 517 literal->handle()->IsSymbol() && |
| 516 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { | 518 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { |
| 517 ref->set_type(Reference::NAMED); | 519 ref->set_type(Reference::NAMED); |
| 518 } else { | 520 } else { |
| 519 Load(property->key()); | 521 LoadAndSpill(property->key()); |
| 520 frame_->SpillAll(); | |
| 521 ref->set_type(Reference::KEYED); | 522 ref->set_type(Reference::KEYED); |
| 522 } | 523 } |
| 523 } else if (var != NULL) { | 524 } else if (var != NULL) { |
| 524 // The expression is a variable proxy that does not rewrite to a | 525 // The expression is a variable proxy that does not rewrite to a |
| 525 // property. Global variables are treated as named property references. | 526 // property. Global variables are treated as named property references. |
| 526 if (var->is_global()) { | 527 if (var->is_global()) { |
| 527 frame_->SpillAll(); | 528 VirtualFrame::SpilledScope spilled_scope(this); |
| 528 LoadGlobal(); | 529 LoadGlobal(); |
| 529 ref->set_type(Reference::NAMED); | 530 ref->set_type(Reference::NAMED); |
| 530 } else { | 531 } else { |
| 531 ASSERT(var->slot() != NULL); | 532 ASSERT(var->slot() != NULL); |
| 532 ref->set_type(Reference::SLOT); | 533 ref->set_type(Reference::SLOT); |
| 533 } | 534 } |
| 534 } else { | 535 } else { |
| 536 VirtualFrame::SpilledScope spilled_scope(this); |
| 535 // Anything else is a runtime error. | 537 // Anything else is a runtime error. |
| 536 Load(e); | 538 LoadAndSpill(e); |
| 537 frame_->SpillAll(); | |
| 538 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); | 539 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); |
| 539 } | 540 } |
| 540 } | 541 } |
| 541 | 542 |
| 542 | 543 |
| 543 void CodeGenerator::UnloadReference(Reference* ref) { | 544 void CodeGenerator::UnloadReference(Reference* ref) { |
| 544 // Pop a reference from the stack while preserving TOS. | 545 // Pop a reference from the stack while preserving TOS. |
| 545 Comment cmnt(masm_, "[ UnloadReference"); | 546 Comment cmnt(masm_, "[ UnloadReference"); |
| 546 int size = ref->size(); | 547 int size = ref->size(); |
| 547 if (size == 1) { | 548 if (size == 1) { |
| (...skipping 714 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1262 }; | 1263 }; |
| 1263 | 1264 |
| 1264 | 1265 |
| 1265 // Call the function just below TOS on the stack with the given | 1266 // Call the function just below TOS on the stack with the given |
| 1266 // arguments. The receiver is the TOS. | 1267 // arguments. The receiver is the TOS. |
| 1267 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 1268 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
| 1268 int position) { | 1269 int position) { |
| 1269 // Push the arguments ("left-to-right") on the stack. | 1270 // Push the arguments ("left-to-right") on the stack. |
| 1270 int arg_count = args->length(); | 1271 int arg_count = args->length(); |
| 1271 for (int i = 0; i < arg_count; i++) { | 1272 for (int i = 0; i < arg_count; i++) { |
| 1272 Load(args->at(i)); | 1273 LoadAndSpill(args->at(i)); |
| 1273 frame_->SpillAll(); | |
| 1274 } | 1274 } |
| 1275 | 1275 |
| 1276 // Record the position for debugging purposes. | 1276 // Record the position for debugging purposes. |
| 1277 __ RecordPosition(position); | 1277 __ RecordPosition(position); |
| 1278 | 1278 |
| 1279 // Use the shared code stub to call the function. | 1279 // Use the shared code stub to call the function. |
| 1280 CallFunctionStub call_function(arg_count); | 1280 CallFunctionStub call_function(arg_count); |
| 1281 frame_->CallStub(&call_function, arg_count + 1); | 1281 frame_->CallStub(&call_function, arg_count + 1); |
| 1282 | 1282 |
| 1283 // Restore context and pop function from the stack. | 1283 // Restore context and pop function from the stack. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1305 // The stack check can trigger the debugger. Before calling it, all | 1305 // The stack check can trigger the debugger. Before calling it, all |
| 1306 // values including constants must be spilled to the frame. | 1306 // values including constants must be spilled to the frame. |
| 1307 frame_->SpillAll(); | 1307 frame_->SpillAll(); |
| 1308 frame_->CallStub(&stub, 0); | 1308 frame_->CallStub(&stub, 0); |
| 1309 stack_is_ok.Bind(); | 1309 stack_is_ok.Bind(); |
| 1310 } | 1310 } |
| 1311 } | 1311 } |
| 1312 | 1312 |
| 1313 | 1313 |
| 1314 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { | 1314 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { |
| 1315 ASSERT(!in_spilled_code()); |
| 1315 for (int i = 0; frame_ != NULL && i < statements->length(); i++) { | 1316 for (int i = 0; frame_ != NULL && i < statements->length(); i++) { |
| 1316 Visit(statements->at(i)); | 1317 Visit(statements->at(i)); |
| 1317 } | 1318 } |
| 1318 } | 1319 } |
| 1319 | 1320 |
| 1320 | 1321 |
| 1321 void CodeGenerator::VisitBlock(Block* node) { | 1322 void CodeGenerator::VisitBlock(Block* node) { |
| 1323 ASSERT(!in_spilled_code()); |
| 1322 Comment cmnt(masm_, "[ Block"); | 1324 Comment cmnt(masm_, "[ Block"); |
| 1323 RecordStatementPosition(node); | 1325 RecordStatementPosition(node); |
| 1324 node->set_break_stack_height(break_stack_height_); | 1326 node->set_break_stack_height(break_stack_height_); |
| 1325 node->break_target()->set_code_generator(this); | 1327 node->break_target()->set_code_generator(this); |
| 1326 VisitStatements(node->statements()); | 1328 VisitStatements(node->statements()); |
| 1327 if (node->break_target()->is_linked()) { | 1329 if (node->break_target()->is_linked()) { |
| 1328 node->break_target()->Bind(); | 1330 node->break_target()->Bind(); |
| 1329 } | 1331 } |
| 1330 } | 1332 } |
| 1331 | 1333 |
| 1332 | 1334 |
| 1333 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1335 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1334 frame_->SpillAll(); | 1336 VirtualFrame::SpilledScope spilled_scope(this); |
| 1335 frame_->EmitPush(Immediate(pairs)); | 1337 frame_->EmitPush(Immediate(pairs)); |
| 1336 frame_->EmitPush(esi); | 1338 frame_->EmitPush(esi); |
| 1337 frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 1339 frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| 1338 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 1340 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
| 1339 // Return value is ignored. | 1341 // Return value is ignored. |
| 1340 } | 1342 } |
| 1341 | 1343 |
| 1342 | 1344 |
| 1343 void CodeGenerator::VisitDeclaration(Declaration* node) { | 1345 void CodeGenerator::VisitDeclaration(Declaration* node) { |
| 1344 Comment cmnt(masm_, "[ Declaration"); | 1346 Comment cmnt(masm_, "[ Declaration"); |
| 1345 Variable* var = node->proxy()->var(); | 1347 Variable* var = node->proxy()->var(); |
| 1346 ASSERT(var != NULL); // must have been resolved | 1348 ASSERT(var != NULL); // must have been resolved |
| 1347 Slot* slot = var->slot(); | 1349 Slot* slot = var->slot(); |
| 1348 | 1350 |
| 1349 // If it was not possible to allocate the variable at compile time, | 1351 // If it was not possible to allocate the variable at compile time, |
| 1350 // we need to "declare" it at runtime to make sure it actually | 1352 // we need to "declare" it at runtime to make sure it actually |
| 1351 // exists in the local context. | 1353 // exists in the local context. |
| 1352 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1354 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1353 // Variables with a "LOOKUP" slot were introduced as non-locals | 1355 // Variables with a "LOOKUP" slot were introduced as non-locals |
| 1354 // during variable resolution and must have mode DYNAMIC. | 1356 // during variable resolution and must have mode DYNAMIC. |
| 1355 ASSERT(var->mode() == Variable::DYNAMIC); | 1357 ASSERT(var->mode() == Variable::DYNAMIC); |
| 1356 // For now, just do a runtime call. | 1358 // For now, just do a runtime call. |
| 1357 frame_->SpillAll(); | 1359 VirtualFrame::SpilledScope spilled_scope(this); |
| 1358 frame_->EmitPush(esi); | 1360 frame_->EmitPush(esi); |
| 1359 frame_->EmitPush(Immediate(var->name())); | 1361 frame_->EmitPush(Immediate(var->name())); |
| 1360 // Declaration nodes are always introduced in one of two modes. | 1362 // Declaration nodes are always introduced in one of two modes. |
| 1361 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); | 1363 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); |
| 1362 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; | 1364 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; |
| 1363 frame_->EmitPush(Immediate(Smi::FromInt(attr))); | 1365 frame_->EmitPush(Immediate(Smi::FromInt(attr))); |
| 1364 // Push initial value, if any. | 1366 // Push initial value, if any. |
| 1365 // Note: For variables we must not push an initial value (such as | 1367 // Note: For variables we must not push an initial value (such as |
| 1366 // 'undefined') because we may have a (legal) redeclaration and we | 1368 // 'undefined') because we may have a (legal) redeclaration and we |
| 1367 // must not destroy the current value. | 1369 // must not destroy the current value. |
| 1368 if (node->mode() == Variable::CONST) { | 1370 if (node->mode() == Variable::CONST) { |
| 1369 frame_->EmitPush(Immediate(Factory::the_hole_value())); | 1371 frame_->EmitPush(Immediate(Factory::the_hole_value())); |
| 1370 } else if (node->fun() != NULL) { | 1372 } else if (node->fun() != NULL) { |
| 1371 Load(node->fun()); | 1373 LoadAndSpill(node->fun()); |
| 1372 frame_->SpillAll(); | |
| 1373 } else { | 1374 } else { |
| 1374 frame_->EmitPush(Immediate(0)); // no initial value! | 1375 frame_->EmitPush(Immediate(0)); // no initial value! |
| 1375 } | 1376 } |
| 1376 frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); | 1377 frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 1377 // Ignore the return value (declarations are statements). | 1378 // Ignore the return value (declarations are statements). |
| 1378 return; | 1379 return; |
| 1379 } | 1380 } |
| 1380 | 1381 |
| 1381 ASSERT(!var->is_global()); | 1382 ASSERT(!var->is_global()); |
| 1382 | 1383 |
| 1383 // If we have a function or a constant, we need to initialize the variable. | 1384 // If we have a function or a constant, we need to initialize the variable. |
| 1384 Expression* val = NULL; | 1385 Expression* val = NULL; |
| 1385 if (node->mode() == Variable::CONST) { | 1386 if (node->mode() == Variable::CONST) { |
| 1386 val = new Literal(Factory::the_hole_value()); | 1387 val = new Literal(Factory::the_hole_value()); |
| 1387 } else { | 1388 } else { |
| 1388 val = node->fun(); // NULL if we don't have a function | 1389 val = node->fun(); // NULL if we don't have a function |
| 1389 } | 1390 } |
| 1390 | 1391 |
| 1391 if (val != NULL) { | 1392 if (val != NULL) { |
| 1392 frame_->SpillAll(); | 1393 VirtualFrame::SpilledScope spilled_scope(this); |
| 1393 // Set initial value. | 1394 // Set initial value. |
| 1394 Reference target(this, node->proxy()); | 1395 Reference target(this, node->proxy()); |
| 1395 ASSERT(target.is_slot()); | 1396 ASSERT(target.is_slot()); |
| 1396 Load(val); | 1397 LoadAndSpill(val); |
| 1397 frame_->SpillAll(); | |
| 1398 target.SetValue(NOT_CONST_INIT); | 1398 target.SetValue(NOT_CONST_INIT); |
| 1399 // Get rid of the assigned value (declarations are statements). It's | 1399 // Get rid of the assigned value (declarations are statements). It's |
| 1400 // safe to pop the value lying on top of the reference before unloading | 1400 // safe to pop the value lying on top of the reference before unloading |
| 1401 // the reference itself (which preserves the top of stack) because we | 1401 // the reference itself (which preserves the top of stack) because we |
| 1402 // know that it is a zero-sized reference. | 1402 // know that it is a zero-sized reference. |
| 1403 frame_->Drop(); | 1403 frame_->Drop(); |
| 1404 } | 1404 } |
| 1405 } | 1405 } |
| 1406 | 1406 |
| 1407 | 1407 |
| 1408 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1408 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
| 1409 ASSERT(!in_spilled_code()); |
| 1409 Comment cmnt(masm_, "[ ExpressionStatement"); | 1410 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 1410 RecordStatementPosition(node); | 1411 RecordStatementPosition(node); |
| 1411 Expression* expression = node->expression(); | 1412 Expression* expression = node->expression(); |
| 1412 expression->MarkAsStatement(); | 1413 expression->MarkAsStatement(); |
| 1413 Load(expression); | 1414 Load(expression); |
| 1414 // Remove the lingering expression result from the top of stack. | 1415 // Remove the lingering expression result from the top of stack. |
| 1415 frame_->Drop(); | 1416 frame_->Drop(); |
| 1416 } | 1417 } |
| 1417 | 1418 |
| 1418 | 1419 |
| 1419 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { | 1420 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { |
| 1420 frame_->SpillAll(); | 1421 ASSERT(!in_spilled_code()); |
| 1422 VirtualFrame::SpilledScope spilled_scope(this); |
| 1421 Comment cmnt(masm_, "// EmptyStatement"); | 1423 Comment cmnt(masm_, "// EmptyStatement"); |
| 1422 // nothing to do | 1424 // nothing to do |
| 1423 } | 1425 } |
| 1424 | 1426 |
| 1425 | 1427 |
| 1426 void CodeGenerator::VisitIfStatement(IfStatement* node) { | 1428 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
| 1427 frame_->SpillAll(); | 1429 ASSERT(!in_spilled_code()); |
| 1430 VirtualFrame::SpilledScope spilled_scope(this); |
| 1428 Comment cmnt(masm_, "[ IfStatement"); | 1431 Comment cmnt(masm_, "[ IfStatement"); |
| 1429 // Generate different code depending on which parts of the if statement | 1432 // Generate different code depending on which parts of the if statement |
| 1430 // are present or not. | 1433 // are present or not. |
| 1431 bool has_then_stm = node->HasThenStatement(); | 1434 bool has_then_stm = node->HasThenStatement(); |
| 1432 bool has_else_stm = node->HasElseStatement(); | 1435 bool has_else_stm = node->HasElseStatement(); |
| 1433 | 1436 |
| 1434 RecordStatementPosition(node); | 1437 RecordStatementPosition(node); |
| 1435 JumpTarget exit(this); | 1438 JumpTarget exit(this); |
| 1436 if (has_then_stm && has_else_stm) { | 1439 if (has_then_stm && has_else_stm) { |
| 1437 JumpTarget then(this); | 1440 JumpTarget then(this); |
| 1438 JumpTarget else_(this); | 1441 JumpTarget else_(this); |
| 1439 // if (cond) | 1442 // if (cond) |
| 1440 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 1443 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, |
| 1444 &then, &else_, true); |
| 1441 if (frame_ != NULL) { | 1445 if (frame_ != NULL) { |
| 1442 // A NULL frame here indicates that the code for the condition cannot | 1446 // A NULL frame here indicates that the code for the condition cannot |
| 1443 // fall-through, i.e. it causes unconditional branchs to targets. | 1447 // fall-through, i.e. it causes unconditional branchs to targets. |
| 1444 Branch(false, &else_); | 1448 Branch(false, &else_); |
| 1445 } | 1449 } |
| 1446 // then | 1450 // then |
| 1447 if (frame_ != NULL || then.is_linked()) { | 1451 if (frame_ != NULL || then.is_linked()) { |
| 1448 // If control flow can reach the then part via fall-through from the | 1452 // If control flow can reach the then part via fall-through from the |
| 1449 // test or a branch to the target, compile it. | 1453 // test or a branch to the target, compile it. |
| 1450 then.Bind(); | 1454 then.Bind(); |
| 1451 Visit(node->then_statement()); | 1455 VisitAndSpill(node->then_statement()); |
| 1452 } | 1456 } |
| 1453 if (frame_ != NULL) { | 1457 if (frame_ != NULL) { |
| 1454 // A NULL frame here indicates that control did not fall out of the | 1458 // A NULL frame here indicates that control did not fall out of the |
| 1455 // then statement, it escaped on all branches. In that case, a jump | 1459 // then statement, it escaped on all branches. In that case, a jump |
| 1456 // to the exit label would be dead code (and impossible, because we | 1460 // to the exit label would be dead code (and impossible, because we |
| 1457 // don't have a current virtual frame to set at the exit label). | 1461 // don't have a current virtual frame to set at the exit label). |
| 1458 frame_->SpillAll(); | |
| 1459 exit.Jump(); | 1462 exit.Jump(); |
| 1460 } | 1463 } |
| 1461 // else | 1464 // else |
| 1462 if (else_.is_linked()) { | 1465 if (else_.is_linked()) { |
| 1463 // Control flow for if-then-else does not fall-through to the else | 1466 // Control flow for if-then-else does not fall-through to the else |
| 1464 // part, it can only reach here via jump if at all. | 1467 // part, it can only reach here via jump if at all. |
| 1465 else_.Bind(); | 1468 else_.Bind(); |
| 1466 Visit(node->else_statement()); | 1469 VisitAndSpill(node->else_statement()); |
| 1467 } | 1470 } |
| 1468 | 1471 |
| 1469 } else if (has_then_stm) { | 1472 } else if (has_then_stm) { |
| 1470 ASSERT(!has_else_stm); | 1473 ASSERT(!has_else_stm); |
| 1471 JumpTarget then(this); | 1474 JumpTarget then(this); |
| 1472 // if (cond) | 1475 // if (cond) |
| 1473 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); | 1476 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, |
| 1477 &then, &exit, true); |
| 1474 if (frame_ != NULL) { | 1478 if (frame_ != NULL) { |
| 1475 Branch(false, &exit); | 1479 Branch(false, &exit); |
| 1476 } | 1480 } |
| 1477 // then | 1481 // then |
| 1478 if (frame_ != NULL || then.is_linked()) { | 1482 if (frame_ != NULL || then.is_linked()) { |
| 1479 then.Bind(); | 1483 then.Bind(); |
| 1480 Visit(node->then_statement()); | 1484 VisitAndSpill(node->then_statement()); |
| 1481 } | 1485 } |
| 1482 | 1486 |
| 1483 } else if (has_else_stm) { | 1487 } else if (has_else_stm) { |
| 1484 ASSERT(!has_then_stm); | 1488 ASSERT(!has_then_stm); |
| 1485 JumpTarget else_(this); | 1489 JumpTarget else_(this); |
| 1486 // if (!cond) | 1490 // if (!cond) |
| 1487 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); | 1491 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, |
| 1492 &exit, &else_, true); |
| 1488 if (frame_ != NULL) { | 1493 if (frame_ != NULL) { |
| 1489 Branch(true, &exit); | 1494 Branch(true, &exit); |
| 1490 } | 1495 } |
| 1491 // else | 1496 // else |
| 1492 if (frame_ != NULL || else_.is_linked()) { | 1497 if (frame_ != NULL || else_.is_linked()) { |
| 1493 else_.Bind(); | 1498 else_.Bind(); |
| 1494 Visit(node->else_statement()); | 1499 VisitAndSpill(node->else_statement()); |
| 1495 } | 1500 } |
| 1496 | 1501 |
| 1497 } else { | 1502 } else { |
| 1498 ASSERT(!has_then_stm && !has_else_stm); | 1503 ASSERT(!has_then_stm && !has_else_stm); |
| 1499 // if (cond) | 1504 // if (cond) |
| 1500 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); | 1505 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, |
| 1506 &exit, &exit, false); |
| 1501 if (frame_ != NULL) { | 1507 if (frame_ != NULL) { |
| 1502 frame_->SpillAll(); | |
| 1503 if (has_cc()) { | 1508 if (has_cc()) { |
| 1504 cc_reg_ = no_condition; | 1509 cc_reg_ = no_condition; |
| 1505 } else { | 1510 } else { |
| 1506 // No cc value set up, that means the boolean was pushed. | 1511 // No cc value set up, that means the boolean was pushed. |
| 1507 // Pop it again, since it is not going to be used. | 1512 // Pop it again, since it is not going to be used. |
| 1508 frame_->Drop(); | 1513 frame_->Drop(); |
| 1509 } | 1514 } |
| 1510 } | 1515 } |
| 1511 } | 1516 } |
| 1512 | 1517 |
| 1513 // end | 1518 // end |
| 1514 if (exit.is_linked()) { | 1519 if (exit.is_linked()) { |
| 1515 exit.Bind(); | 1520 exit.Bind(); |
| 1516 } | 1521 } |
| 1517 } | 1522 } |
| 1518 | 1523 |
| 1519 | 1524 |
| 1520 void CodeGenerator::CleanStack(int num_bytes) { | 1525 void CodeGenerator::CleanStack(int num_bytes) { |
| 1521 ASSERT(num_bytes % kPointerSize == 0); | 1526 ASSERT(num_bytes % kPointerSize == 0); |
| 1522 frame_->Drop(num_bytes / kPointerSize); | 1527 frame_->Drop(num_bytes / kPointerSize); |
| 1523 } | 1528 } |
| 1524 | 1529 |
| 1525 | 1530 |
| 1526 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1531 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
| 1527 frame_->SpillAll(); | 1532 ASSERT(!in_spilled_code()); |
| 1533 VirtualFrame::SpilledScope spilled_scope(this); |
| 1528 Comment cmnt(masm_, "[ ContinueStatement"); | 1534 Comment cmnt(masm_, "[ ContinueStatement"); |
| 1529 RecordStatementPosition(node); | 1535 RecordStatementPosition(node); |
| 1530 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1536 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1531 node->target()->continue_target()->Jump(); | 1537 node->target()->continue_target()->Jump(); |
| 1532 } | 1538 } |
| 1533 | 1539 |
| 1534 | 1540 |
| 1535 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1541 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
| 1536 frame_->SpillAll(); | 1542 ASSERT(!in_spilled_code()); |
| 1543 VirtualFrame::SpilledScope spilled_scope(this); |
| 1537 Comment cmnt(masm_, "[ BreakStatement"); | 1544 Comment cmnt(masm_, "[ BreakStatement"); |
| 1538 RecordStatementPosition(node); | 1545 RecordStatementPosition(node); |
| 1539 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1546 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1540 node->target()->break_target()->Jump(); | 1547 node->target()->break_target()->Jump(); |
| 1541 } | 1548 } |
| 1542 | 1549 |
| 1543 | 1550 |
| 1544 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1551 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| 1545 frame_->SpillAll(); | 1552 ASSERT(!in_spilled_code()); |
| 1553 VirtualFrame::SpilledScope spilled_scope(this); |
| 1546 Comment cmnt(masm_, "[ ReturnStatement"); | 1554 Comment cmnt(masm_, "[ ReturnStatement"); |
| 1547 RecordStatementPosition(node); | 1555 RecordStatementPosition(node); |
| 1548 Load(node->expression()); | 1556 LoadAndSpill(node->expression()); |
| 1549 frame_->SpillAll(); | |
| 1550 | 1557 |
| 1551 // Move the function result into eax | 1558 // Move the function result into eax |
| 1552 frame_->EmitPop(eax); | 1559 frame_->EmitPop(eax); |
| 1553 | 1560 |
| 1554 // If we're inside a try statement or the return instruction | 1561 // If we're inside a try statement or the return instruction |
| 1555 // sequence has been generated, we just jump to that | 1562 // sequence has been generated, we just jump to that |
| 1556 // point. Otherwise, we generate the return instruction sequence and | 1563 // point. Otherwise, we generate the return instruction sequence and |
| 1557 // bind the function return label. | 1564 // bind the function return label. |
| 1558 if (is_inside_try_ || function_return_.is_bound()) { | 1565 if (is_inside_try_ || function_return_.is_bound()) { |
| 1559 function_return_.Jump(); | 1566 function_return_.Jump(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1576 | 1583 |
| 1577 // Check that the size of the code used for returning matches what is | 1584 // Check that the size of the code used for returning matches what is |
| 1578 // expected by the debugger. | 1585 // expected by the debugger. |
| 1579 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, | 1586 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, |
| 1580 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); | 1587 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 1581 } | 1588 } |
| 1582 } | 1589 } |
| 1583 | 1590 |
| 1584 | 1591 |
| 1585 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1592 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 1586 frame_->SpillAll(); | 1593 ASSERT(!in_spilled_code()); |
| 1594 VirtualFrame::SpilledScope spilled_scope(this); |
| 1587 Comment cmnt(masm_, "[ WithEnterStatement"); | 1595 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 1588 RecordStatementPosition(node); | 1596 RecordStatementPosition(node); |
| 1589 Load(node->expression()); | 1597 LoadAndSpill(node->expression()); |
| 1590 frame_->SpillAll(); | |
| 1591 frame_->CallRuntime(Runtime::kPushContext, 1); | 1598 frame_->CallRuntime(Runtime::kPushContext, 1); |
| 1592 | 1599 |
| 1593 if (kDebug) { | 1600 if (kDebug) { |
| 1594 JumpTarget verified_true(this); | 1601 JumpTarget verified_true(this); |
| 1595 // Verify eax and esi are the same in debug mode | 1602 // Verify eax and esi are the same in debug mode |
| 1596 __ cmp(eax, Operand(esi)); | 1603 __ cmp(eax, Operand(esi)); |
| 1597 verified_true.Branch(equal); | 1604 verified_true.Branch(equal); |
| 1598 __ int3(); | 1605 __ int3(); |
| 1599 verified_true.Bind(); | 1606 verified_true.Bind(); |
| 1600 } | 1607 } |
| 1601 | 1608 |
| 1602 // Update context local. | 1609 // Update context local. |
| 1603 __ mov(frame_->Context(), esi); | 1610 __ mov(frame_->Context(), esi); |
| 1604 } | 1611 } |
| 1605 | 1612 |
| 1606 | 1613 |
| 1607 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | 1614 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { |
| 1608 frame_->SpillAll(); | 1615 ASSERT(!in_spilled_code()); |
| 1616 VirtualFrame::SpilledScope spilled_scope(this); |
| 1609 Comment cmnt(masm_, "[ WithExitStatement"); | 1617 Comment cmnt(masm_, "[ WithExitStatement"); |
| 1610 // Pop context. | 1618 // Pop context. |
| 1611 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); | 1619 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); |
| 1612 // Update context local. | 1620 // Update context local. |
| 1613 __ mov(frame_->Context(), esi); | 1621 __ mov(frame_->Context(), esi); |
| 1614 } | 1622 } |
| 1615 | 1623 |
| 1616 | 1624 |
| 1617 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { | 1625 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { |
| 1618 return kFastSwitchMaxOverheadFactor; | 1626 return kFastSwitchMaxOverheadFactor; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1685 | 1693 |
| 1686 for (int i = 0, entry_pos = table_start.label()->pos(); | 1694 for (int i = 0, entry_pos = table_start.label()->pos(); |
| 1687 i < range; | 1695 i < range; |
| 1688 i++, entry_pos += sizeof(uint32_t)) { | 1696 i++, entry_pos += sizeof(uint32_t)) { |
| 1689 __ WriteInternalReference(entry_pos, *case_targets[i]->label()); | 1697 __ WriteInternalReference(entry_pos, *case_targets[i]->label()); |
| 1690 } | 1698 } |
| 1691 } | 1699 } |
| 1692 | 1700 |
| 1693 | 1701 |
| 1694 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1702 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 1695 frame_->SpillAll(); | 1703 ASSERT(!in_spilled_code()); |
| 1704 VirtualFrame::SpilledScope spilled_scope(this); |
| 1696 Comment cmnt(masm_, "[ SwitchStatement"); | 1705 Comment cmnt(masm_, "[ SwitchStatement"); |
| 1697 RecordStatementPosition(node); | 1706 RecordStatementPosition(node); |
| 1698 node->set_break_stack_height(break_stack_height_); | 1707 node->set_break_stack_height(break_stack_height_); |
| 1699 node->break_target()->set_code_generator(this); | 1708 node->break_target()->set_code_generator(this); |
| 1700 | 1709 |
| 1701 Load(node->tag()); | 1710 LoadAndSpill(node->tag()); |
| 1702 frame_->SpillAll(); | |
| 1703 | 1711 |
| 1704 if (TryGenerateFastCaseSwitchStatement(node)) { | 1712 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1705 return; | 1713 return; |
| 1706 } | 1714 } |
| 1707 | 1715 |
| 1708 JumpTarget next_test(this); | 1716 JumpTarget next_test(this); |
| 1709 JumpTarget fall_through(this); | 1717 JumpTarget fall_through(this); |
| 1710 JumpTarget default_entry(this); | 1718 JumpTarget default_entry(this); |
| 1711 JumpTarget default_exit(this); | 1719 JumpTarget default_exit(this); |
| 1712 ZoneList<CaseClause*>* cases = node->cases(); | 1720 ZoneList<CaseClause*>* cases = node->cases(); |
| 1713 int length = cases->length(); | 1721 int length = cases->length(); |
| 1714 CaseClause* default_clause = NULL; | 1722 CaseClause* default_clause = NULL; |
| 1715 | 1723 |
| 1716 for (int i = 0; i < length; i++) { | 1724 for (int i = 0; i < length; i++) { |
| 1717 CaseClause* clause = cases->at(i); | 1725 CaseClause* clause = cases->at(i); |
| 1718 if (clause->is_default()) { | 1726 if (clause->is_default()) { |
| 1719 // Remember the default clause and compile it at the end. | 1727 // Remember the default clause and compile it at the end. |
| 1720 default_clause = clause; | 1728 default_clause = clause; |
| 1721 continue; | 1729 continue; |
| 1722 } | 1730 } |
| 1723 | 1731 |
| 1724 Comment cmnt(masm_, "[ Case clause"); | 1732 Comment cmnt(masm_, "[ Case clause"); |
| 1725 // Compile the test. | 1733 // Compile the test. |
| 1726 next_test.Bind(); | 1734 next_test.Bind(); |
| 1727 next_test.Unuse(); | 1735 next_test.Unuse(); |
| 1728 // Duplicate TOS. | 1736 // Duplicate TOS. |
| 1729 __ mov(eax, frame_->Top()); | 1737 __ mov(eax, frame_->Top()); |
| 1730 frame_->EmitPush(eax); | 1738 frame_->EmitPush(eax); |
| 1731 Load(clause->label()); | 1739 LoadAndSpill(clause->label()); |
| 1732 frame_->SpillAll(); | |
| 1733 Comparison(equal, true); | 1740 Comparison(equal, true); |
| 1734 Branch(false, &next_test); | 1741 Branch(false, &next_test); |
| 1735 | 1742 |
| 1736 // Before entering the body from the test, remove the switch value from | 1743 // Before entering the body from the test, remove the switch value from |
| 1737 // the stack. | 1744 // the stack. |
| 1738 frame_->Drop(); | 1745 frame_->Drop(); |
| 1739 | 1746 |
| 1740 // Label the body so that fall through is enabled. | 1747 // Label the body so that fall through is enabled. |
| 1741 if (i > 0 && cases->at(i - 1)->is_default()) { | 1748 if (i > 0 && cases->at(i - 1)->is_default()) { |
| 1742 default_exit.Bind(); | 1749 default_exit.Bind(); |
| 1743 } else { | 1750 } else { |
| 1744 fall_through.Bind(); | 1751 fall_through.Bind(); |
| 1745 fall_through.Unuse(); | 1752 fall_through.Unuse(); |
| 1746 } | 1753 } |
| 1747 VisitStatements(clause->statements()); | 1754 VisitStatementsAndSpill(clause->statements()); |
| 1748 | 1755 |
| 1749 // If control flow can fall through from the body, jump to the next body | 1756 // If control flow can fall through from the body, jump to the next body |
| 1750 // or the end of the statement. | 1757 // or the end of the statement. |
| 1751 if (frame_ != NULL) { | 1758 if (frame_ != NULL) { |
| 1752 frame_->SpillAll(); | |
| 1753 if (i < length - 1 && cases->at(i + 1)->is_default()) { | 1759 if (i < length - 1 && cases->at(i + 1)->is_default()) { |
| 1754 default_entry.Jump(); | 1760 default_entry.Jump(); |
| 1755 } else { | 1761 } else { |
| 1756 fall_through.Jump(); | 1762 fall_through.Jump(); |
| 1757 } | 1763 } |
| 1758 } | 1764 } |
| 1759 } | 1765 } |
| 1760 | 1766 |
| 1761 // The final "test" removes the switch value. | 1767 // The final "test" removes the switch value. |
| 1762 next_test.Bind(); | 1768 next_test.Bind(); |
| 1763 frame_->Drop(); | 1769 frame_->Drop(); |
| 1764 | 1770 |
| 1765 // If there is a default clause, compile it. | 1771 // If there is a default clause, compile it. |
| 1766 if (default_clause != NULL) { | 1772 if (default_clause != NULL) { |
| 1767 Comment cmnt(masm_, "[ Default clause"); | 1773 Comment cmnt(masm_, "[ Default clause"); |
| 1768 default_entry.Bind(); | 1774 default_entry.Bind(); |
| 1769 VisitStatements(default_clause->statements()); | 1775 VisitStatementsAndSpill(default_clause->statements()); |
| 1770 if (frame_ != NULL) { | 1776 if (frame_ != NULL) { |
| 1771 frame_->SpillAll(); | |
| 1772 } | 1777 } |
| 1773 // If control flow can fall out of the default and there is a case after | 1778 // If control flow can fall out of the default and there is a case after |
| 1774 // it, jump to that case's body. | 1779 // it, jump to that case's body. |
| 1775 if (frame_ != NULL && default_exit.is_bound()) { | 1780 if (frame_ != NULL && default_exit.is_bound()) { |
| 1776 default_exit.Jump(); | 1781 default_exit.Jump(); |
| 1777 } | 1782 } |
| 1778 } | 1783 } |
| 1779 | 1784 |
| 1780 if (fall_through.is_linked()) { | 1785 if (fall_through.is_linked()) { |
| 1781 fall_through.Bind(); | 1786 fall_through.Bind(); |
| 1782 } | 1787 } |
| 1783 | 1788 |
| 1784 if (node->break_target()->is_linked()) { | 1789 if (node->break_target()->is_linked()) { |
| 1785 node->break_target()->Bind(); | 1790 node->break_target()->Bind(); |
| 1786 } | 1791 } |
| 1787 } | 1792 } |
| 1788 | 1793 |
| 1789 | 1794 |
| 1790 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1795 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 1796 ASSERT(!in_spilled_code()); |
| 1791 Comment cmnt(masm_, "[ LoopStatement"); | 1797 Comment cmnt(masm_, "[ LoopStatement"); |
| 1792 RecordStatementPosition(node); | 1798 RecordStatementPosition(node); |
| 1793 node->set_break_stack_height(break_stack_height_); | 1799 node->set_break_stack_height(break_stack_height_); |
| 1794 node->break_target()->set_code_generator(this); | 1800 node->break_target()->set_code_generator(this); |
| 1795 node->continue_target()->set_code_generator(this); | 1801 node->continue_target()->set_code_generator(this); |
| 1796 | 1802 |
| 1797 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a | 1803 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a |
| 1798 // known result for the test expression, with no side effects. | 1804 // known result for the test expression, with no side effects. |
| 1799 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 1805 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
| 1800 if (node->cond() == NULL) { | 1806 if (node->cond() == NULL) { |
| 1801 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1807 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 1802 info = ALWAYS_TRUE; | 1808 info = ALWAYS_TRUE; |
| 1803 } else { | 1809 } else { |
| 1804 Literal* lit = node->cond()->AsLiteral(); | 1810 Literal* lit = node->cond()->AsLiteral(); |
| 1805 if (lit != NULL) { | 1811 if (lit != NULL) { |
| 1806 if (lit->IsTrue()) { | 1812 if (lit->IsTrue()) { |
| 1807 info = ALWAYS_TRUE; | 1813 info = ALWAYS_TRUE; |
| 1808 } else if (lit->IsFalse()) { | 1814 } else if (lit->IsFalse()) { |
| 1809 info = ALWAYS_FALSE; | 1815 info = ALWAYS_FALSE; |
| 1810 } | 1816 } |
| 1811 } | 1817 } |
| 1812 } | 1818 } |
| 1813 | 1819 |
| 1814 switch (node->type()) { | 1820 switch (node->type()) { |
| 1815 case LoopStatement::DO_LOOP: { | 1821 case LoopStatement::DO_LOOP: { |
| 1816 // The new code generator does not yet compile do loops. | 1822 // The new code generator does not yet compile do loops. |
| 1817 frame_->SpillAll(); | 1823 VirtualFrame::SpilledScope spilled_scope(this); |
| 1818 JumpTarget body(this); | 1824 JumpTarget body(this); |
| 1819 IncrementLoopNesting(); | 1825 IncrementLoopNesting(); |
| 1820 // Label the body. | 1826 // Label the body. |
| 1821 if (info == ALWAYS_TRUE) { | 1827 if (info == ALWAYS_TRUE) { |
| 1822 node->continue_target()->Bind(); | 1828 node->continue_target()->Bind(); |
| 1823 } else if (info == ALWAYS_FALSE) { | 1829 } else if (info == ALWAYS_FALSE) { |
| 1824 // There is no need, we will never jump back. | 1830 // There is no need, we will never jump back. |
| 1825 } else { | 1831 } else { |
| 1826 ASSERT(info == DONT_KNOW); | 1832 ASSERT(info == DONT_KNOW); |
| 1827 body.Bind(); | 1833 body.Bind(); |
| 1828 } | 1834 } |
| 1829 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1835 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1830 Visit(node->body()); | 1836 VisitAndSpill(node->body()); |
| 1831 if (frame_ != NULL) { | |
| 1832 frame_->SpillAll(); | |
| 1833 } | |
| 1834 | 1837 |
| 1835 // Compile the "test". | 1838 // Compile the "test". |
| 1836 if (info == ALWAYS_TRUE) { | 1839 if (info == ALWAYS_TRUE) { |
| 1837 if (frame_ != NULL) { | 1840 if (frame_ != NULL) { |
| 1838 // If control flow can fall off the end of the body, jump back to | 1841 // If control flow can fall off the end of the body, jump back to |
| 1839 // the top. | 1842 // the top. |
| 1840 node->continue_target()->Jump(); | 1843 node->continue_target()->Jump(); |
| 1841 } | 1844 } |
| 1842 } else if (info == ALWAYS_FALSE) { | 1845 } else if (info == ALWAYS_FALSE) { |
| 1843 // If we have a continue in the body, we only have to bind its jump | 1846 // If we have a continue in the body, we only have to bind its jump |
| 1844 // target. | 1847 // target. |
| 1845 if (node->continue_target()->is_linked()) { | 1848 if (node->continue_target()->is_linked()) { |
| 1846 node->continue_target()->Bind(); | 1849 node->continue_target()->Bind(); |
| 1847 } | 1850 } |
| 1848 } else { | 1851 } else { |
| 1849 ASSERT(info == DONT_KNOW); | 1852 ASSERT(info == DONT_KNOW); |
| 1850 // We have to compile the test expression if it can be reached by | 1853 // We have to compile the test expression if it can be reached by |
| 1851 // control flow falling out of the body or via continue. | 1854 // control flow falling out of the body or via continue. |
| 1852 if (frame_ != NULL || node->continue_target()->is_linked()) { | 1855 if (frame_ != NULL || node->continue_target()->is_linked()) { |
| 1853 node->continue_target()->Bind(); | 1856 node->continue_target()->Bind(); |
| 1854 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, | 1857 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, |
| 1855 &body, node->break_target(), true); | 1858 &body, node->break_target(), true); |
| 1856 if (frame_ != NULL) { | 1859 if (frame_ != NULL) { |
| 1857 // A NULL frame here indicates that control flow did not fall | 1860 // A NULL frame here indicates that control flow did not fall |
| 1858 // out of the test expression. | 1861 // out of the test expression. |
| 1859 Branch(true, &body); | 1862 Branch(true, &body); |
| 1860 } | 1863 } |
| 1861 } | 1864 } |
| 1862 } | 1865 } |
| 1863 break; | 1866 break; |
| 1864 } | 1867 } |
| 1865 | 1868 |
| 1866 case LoopStatement::WHILE_LOOP: { | 1869 case LoopStatement::WHILE_LOOP: { |
| 1867 // The new code generator does not yet compile while loops. | 1870 // The new code generator does not yet compile while loops. |
| 1868 frame_->SpillAll(); | 1871 VirtualFrame::SpilledScope spilled_scope(this); |
| 1869 JumpTarget body(this); | 1872 JumpTarget body(this); |
| 1870 IncrementLoopNesting(); | 1873 IncrementLoopNesting(); |
| 1871 // Generate the loop header. | 1874 // Generate the loop header. |
| 1872 if (info == ALWAYS_TRUE) { | 1875 if (info == ALWAYS_TRUE) { |
| 1873 // Merely label the body with the continue target. | 1876 // Merely label the body with the continue target. |
| 1874 node->continue_target()->Bind(); | 1877 node->continue_target()->Bind(); |
| 1875 } else if (info == ALWAYS_FALSE) { | 1878 } else if (info == ALWAYS_FALSE) { |
| 1876 // There is no need to even compile the test or body. | 1879 // There is no need to even compile the test or body. |
| 1877 break; | 1880 break; |
| 1878 } else { | 1881 } else { |
| 1879 // Compile the test labeled with the continue target and label the | 1882 // Compile the test labeled with the continue target and label the |
| 1880 // body with the body target. | 1883 // body with the body target. |
| 1881 ASSERT(info == DONT_KNOW); | 1884 ASSERT(info == DONT_KNOW); |
| 1882 node->continue_target()->Bind(); | 1885 node->continue_target()->Bind(); |
| 1883 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, | 1886 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, |
| 1884 &body, node->break_target(), true); | 1887 &body, node->break_target(), true); |
| 1885 if (frame_ != NULL) { | 1888 if (frame_ != NULL) { |
| 1886 // A NULL frame indicates that control did not fall out of the | 1889 // A NULL frame indicates that control did not fall out of the |
| 1887 // test expression. | 1890 // test expression. |
| 1888 Branch(false, node->break_target()); | 1891 Branch(false, node->break_target()); |
| 1889 } | 1892 } |
| 1890 if (frame_ != NULL || body.is_linked()) { | 1893 if (frame_ != NULL || body.is_linked()) { |
| 1891 body.Bind(); | 1894 body.Bind(); |
| 1892 } | 1895 } |
| 1893 } | 1896 } |
| 1894 if (frame_ != NULL) { | 1897 if (frame_ != NULL) { |
| 1895 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1898 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1896 Visit(node->body()); | 1899 VisitAndSpill(node->body()); |
| 1897 | 1900 |
| 1898 // If control flow can fall out of the body, jump back to the top. | 1901 // If control flow can fall out of the body, jump back to the top. |
| 1899 if (frame_ != NULL) { | 1902 if (frame_ != NULL) { |
| 1900 frame_->SpillAll(); | |
| 1901 node->continue_target()->Jump(); | 1903 node->continue_target()->Jump(); |
| 1902 } | 1904 } |
| 1903 } | 1905 } |
| 1904 break; | 1906 break; |
| 1905 } | 1907 } |
| 1906 | 1908 |
| 1907 case LoopStatement::FOR_LOOP: { | 1909 case LoopStatement::FOR_LOOP: { |
| 1908 JumpTarget loop(this); | 1910 JumpTarget loop(this); |
| 1909 JumpTarget body(this); | 1911 JumpTarget body(this); |
| 1910 if (node->init() != NULL) { | 1912 if (node->init() != NULL) { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1968 } | 1970 } |
| 1969 | 1971 |
| 1970 DecrementLoopNesting(); | 1972 DecrementLoopNesting(); |
| 1971 if (node->break_target()->is_linked()) { | 1973 if (node->break_target()->is_linked()) { |
| 1972 node->break_target()->Bind(); | 1974 node->break_target()->Bind(); |
| 1973 } | 1975 } |
| 1974 } | 1976 } |
| 1975 | 1977 |
| 1976 | 1978 |
| 1977 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 1979 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| 1978 frame_->SpillAll(); | 1980 ASSERT(!in_spilled_code()); |
| 1981 VirtualFrame::SpilledScope spilled_scope(this); |
| 1979 Comment cmnt(masm_, "[ ForInStatement"); | 1982 Comment cmnt(masm_, "[ ForInStatement"); |
| 1980 RecordStatementPosition(node); | 1983 RecordStatementPosition(node); |
| 1981 | 1984 |
| 1982 // We keep stuff on the stack while the body is executing. | 1985 // We keep stuff on the stack while the body is executing. |
| 1983 // Record it, so that a break/continue crossing this statement | 1986 // Record it, so that a break/continue crossing this statement |
| 1984 // can restore the stack. | 1987 // can restore the stack. |
| 1985 const int kForInStackSize = 5 * kPointerSize; | 1988 const int kForInStackSize = 5 * kPointerSize; |
| 1986 break_stack_height_ += kForInStackSize; | 1989 break_stack_height_ += kForInStackSize; |
| 1987 node->set_break_stack_height(break_stack_height_); | 1990 node->set_break_stack_height(break_stack_height_); |
| 1988 node->break_target()->set_code_generator(this); | 1991 node->break_target()->set_code_generator(this); |
| 1989 node->continue_target()->set_code_generator(this); | 1992 node->continue_target()->set_code_generator(this); |
| 1990 | 1993 |
| 1991 JumpTarget primitive(this); | 1994 JumpTarget primitive(this); |
| 1992 JumpTarget jsobject(this); | 1995 JumpTarget jsobject(this); |
| 1993 JumpTarget fixed_array(this); | 1996 JumpTarget fixed_array(this); |
| 1994 JumpTarget entry(this); | 1997 JumpTarget entry(this); |
| 1995 JumpTarget end_del_check(this); | 1998 JumpTarget end_del_check(this); |
| 1996 JumpTarget cleanup(this); | 1999 JumpTarget cleanup(this); |
| 1997 JumpTarget exit(this); | 2000 JumpTarget exit(this); |
| 1998 | 2001 |
| 1999 // Get the object to enumerate over (converted to JSObject). | 2002 // Get the object to enumerate over (converted to JSObject). |
| 2000 Load(node->enumerable()); | 2003 LoadAndSpill(node->enumerable()); |
| 2001 frame_->SpillAll(); | |
| 2002 | 2004 |
| 2003 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 2005 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| 2004 // to the specification. 12.6.4 mandates a call to ToObject. | 2006 // to the specification. 12.6.4 mandates a call to ToObject. |
| 2005 frame_->EmitPop(eax); | 2007 frame_->EmitPop(eax); |
| 2006 | 2008 |
| 2007 // eax: value to be iterated over | 2009 // eax: value to be iterated over |
| 2008 __ cmp(eax, Factory::undefined_value()); | 2010 __ cmp(eax, Factory::undefined_value()); |
| 2009 exit.Branch(equal); | 2011 exit.Branch(equal); |
| 2010 __ cmp(eax, Factory::null_value()); | 2012 __ cmp(eax, Factory::null_value()); |
| 2011 exit.Branch(equal); | 2013 exit.Branch(equal); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2133 frame_->Drop(); | 2135 frame_->Drop(); |
| 2134 } | 2136 } |
| 2135 } | 2137 } |
| 2136 } | 2138 } |
| 2137 // Discard the i'th entry pushed above or else the remainder of the | 2139 // Discard the i'th entry pushed above or else the remainder of the |
| 2138 // reference, whichever is currently on top of the stack. | 2140 // reference, whichever is currently on top of the stack. |
| 2139 frame_->Drop(); | 2141 frame_->Drop(); |
| 2140 | 2142 |
| 2141 // Body. | 2143 // Body. |
| 2142 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2144 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 2143 Visit(node->body()); | 2145 VisitAndSpill(node->body()); |
| 2144 if (frame_ != NULL) { | |
| 2145 frame_->SpillAll(); | |
| 2146 } | |
| 2147 | 2146 |
| 2148 // Next. | 2147 // Next. |
| 2149 node->continue_target()->Bind(); | 2148 node->continue_target()->Bind(); |
| 2150 frame_->EmitPop(eax); | 2149 frame_->EmitPop(eax); |
| 2151 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 2150 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 2152 frame_->EmitPush(eax); | 2151 frame_->EmitPush(eax); |
| 2153 entry.Jump(); | 2152 entry.Jump(); |
| 2154 | 2153 |
| 2155 // Cleanup. | 2154 // Cleanup. |
| 2156 cleanup.Bind(); | 2155 cleanup.Bind(); |
| 2157 node->break_target()->Bind(); | 2156 node->break_target()->Bind(); |
| 2158 frame_->Drop(5); | 2157 frame_->Drop(5); |
| 2159 | 2158 |
| 2160 // Exit. | 2159 // Exit. |
| 2161 exit.Bind(); | 2160 exit.Bind(); |
| 2162 | 2161 |
| 2163 break_stack_height_ -= kForInStackSize; | 2162 break_stack_height_ -= kForInStackSize; |
| 2164 } | 2163 } |
| 2165 | 2164 |
| 2166 | 2165 |
| 2167 void CodeGenerator::VisitTryCatch(TryCatch* node) { | 2166 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
| 2168 frame_->SpillAll(); | 2167 ASSERT(!in_spilled_code()); |
| 2168 VirtualFrame::SpilledScope spilled_scope(this); |
| 2169 Comment cmnt(masm_, "[ TryCatch"); | 2169 Comment cmnt(masm_, "[ TryCatch"); |
| 2170 | 2170 |
| 2171 JumpTarget try_block(this); | 2171 JumpTarget try_block(this); |
| 2172 JumpTarget exit(this); | 2172 JumpTarget exit(this); |
| 2173 | 2173 |
| 2174 try_block.Call(); | 2174 try_block.Call(); |
| 2175 // --- Catch block --- | 2175 // --- Catch block --- |
| 2176 frame_->EmitPush(eax); | 2176 frame_->EmitPush(eax); |
| 2177 | 2177 |
| 2178 // Store the caught exception in the catch variable. | 2178 // Store the caught exception in the catch variable. |
| 2179 { Reference ref(this, node->catch_var()); | 2179 { Reference ref(this, node->catch_var()); |
| 2180 ASSERT(ref.is_slot()); | 2180 ASSERT(ref.is_slot()); |
| 2181 // Load the exception to the top of the stack. Here we make use of the | 2181 // Load the exception to the top of the stack. Here we make use of the |
| 2182 // convenient property that it doesn't matter whether a value is | 2182 // convenient property that it doesn't matter whether a value is |
| 2183 // immediately on top of or underneath a zero-sized reference. | 2183 // immediately on top of or underneath a zero-sized reference. |
| 2184 ref.SetValue(NOT_CONST_INIT); | 2184 ref.SetValue(NOT_CONST_INIT); |
| 2185 } | 2185 } |
| 2186 | 2186 |
| 2187 // Remove the exception from the stack. | 2187 // Remove the exception from the stack. |
| 2188 frame_->Drop(); | 2188 frame_->Drop(); |
| 2189 | 2189 |
| 2190 VisitStatements(node->catch_block()->statements()); | 2190 VisitStatementsAndSpill(node->catch_block()->statements()); |
| 2191 if (frame_ != NULL) { | 2191 if (frame_ != NULL) { |
| 2192 frame_->SpillAll(); | |
| 2193 exit.Jump(); | 2192 exit.Jump(); |
| 2194 } | 2193 } |
| 2195 | 2194 |
| 2196 | 2195 |
| 2197 // --- Try block --- | 2196 // --- Try block --- |
| 2198 try_block.Bind(); | 2197 try_block.Bind(); |
| 2199 | 2198 |
| 2200 frame_->PushTryHandler(TRY_CATCH_HANDLER); | 2199 frame_->PushTryHandler(TRY_CATCH_HANDLER); |
| 2201 int handler_height = frame_->height(); | 2200 int handler_height = frame_->height(); |
| 2202 | 2201 |
| 2203 // Shadow the jump targets for all escapes from the try block, including | 2202 // Shadow the jump targets for all escapes from the try block, including |
| 2204 // returns. During shadowing, the original target is hidden as the | 2203 // returns. During shadowing, the original target is hidden as the |
| 2205 // ShadowTarget and operations on the original actually affect the | 2204 // ShadowTarget and operations on the original actually affect the |
| 2206 // shadowing target. | 2205 // shadowing target. |
| 2207 // | 2206 // |
| 2208 // We should probably try to unify the escaping targets and the return | 2207 // We should probably try to unify the escaping targets and the return |
| 2209 // target. | 2208 // target. |
| 2210 int nof_escapes = node->escaping_targets()->length(); | 2209 int nof_escapes = node->escaping_targets()->length(); |
| 2211 List<ShadowTarget*> shadows(1 + nof_escapes); | 2210 List<ShadowTarget*> shadows(1 + nof_escapes); |
| 2212 shadows.Add(new ShadowTarget(&function_return_)); | 2211 shadows.Add(new ShadowTarget(&function_return_)); |
| 2213 for (int i = 0; i < nof_escapes; i++) { | 2212 for (int i = 0; i < nof_escapes; i++) { |
| 2214 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); | 2213 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); |
| 2215 } | 2214 } |
| 2216 bool function_return_was_shadowed = function_return_is_shadowed_; | 2215 bool function_return_was_shadowed = function_return_is_shadowed_; |
| 2217 function_return_is_shadowed_ = true; | 2216 function_return_is_shadowed_ = true; |
| 2218 | 2217 |
| 2219 // Generate code for the statements in the try block. | 2218 // Generate code for the statements in the try block. |
| 2220 bool was_inside_try = is_inside_try_; | 2219 bool was_inside_try = is_inside_try_; |
| 2221 is_inside_try_ = true; | 2220 is_inside_try_ = true; |
| 2222 VisitStatements(node->try_block()->statements()); | 2221 VisitStatementsAndSpill(node->try_block()->statements()); |
| 2223 if (frame_ != NULL) { | |
| 2224 frame_->SpillAll(); | |
| 2225 } | |
| 2226 is_inside_try_ = was_inside_try; | 2222 is_inside_try_ = was_inside_try; |
| 2227 | 2223 |
| 2228 // Stop the introduced shadowing and count the number of required unlinks. | 2224 // Stop the introduced shadowing and count the number of required unlinks. |
| 2229 // After shadowing stops, the original targets are unshadowed and the | 2225 // After shadowing stops, the original targets are unshadowed and the |
| 2230 // ShadowTargets represent the formerly shadowing targets. | 2226 // ShadowTargets represent the formerly shadowing targets. |
| 2231 int nof_unlinks = 0; | 2227 int nof_unlinks = 0; |
| 2232 for (int i = 0; i <= nof_escapes; i++) { | 2228 for (int i = 0; i <= nof_escapes; i++) { |
| 2233 shadows[i]->StopShadowing(); | 2229 shadows[i]->StopShadowing(); |
| 2234 if (shadows[i]->is_linked()) nof_unlinks++; | 2230 if (shadows[i]->is_linked()) nof_unlinks++; |
| 2235 } | 2231 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2278 // next_sp popped. | 2274 // next_sp popped. |
| 2279 shadows[i]->original_target()->Jump(); | 2275 shadows[i]->original_target()->Jump(); |
| 2280 } | 2276 } |
| 2281 } | 2277 } |
| 2282 | 2278 |
| 2283 exit.Bind(); | 2279 exit.Bind(); |
| 2284 } | 2280 } |
| 2285 | 2281 |
| 2286 | 2282 |
| 2287 void CodeGenerator::VisitTryFinally(TryFinally* node) { | 2283 void CodeGenerator::VisitTryFinally(TryFinally* node) { |
| 2288 frame_->SpillAll(); | 2284 ASSERT(!in_spilled_code()); |
| 2285 VirtualFrame::SpilledScope spilled_scope(this); |
| 2289 Comment cmnt(masm_, "[ TryFinally"); | 2286 Comment cmnt(masm_, "[ TryFinally"); |
| 2290 | 2287 |
| 2291 // State: Used to keep track of reason for entering the finally | 2288 // State: Used to keep track of reason for entering the finally |
| 2292 // block. Should probably be extended to hold information for | 2289 // block. Should probably be extended to hold information for |
| 2293 // break/continue from within the try block. | 2290 // break/continue from within the try block. |
| 2294 enum { FALLING, THROWING, JUMPING }; | 2291 enum { FALLING, THROWING, JUMPING }; |
| 2295 | 2292 |
| 2296 JumpTarget unlink(this); | 2293 JumpTarget unlink(this); |
| 2297 JumpTarget try_block(this); | 2294 JumpTarget try_block(this); |
| 2298 JumpTarget finally_block(this); | 2295 JumpTarget finally_block(this); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2323 shadows.Add(new ShadowTarget(&function_return_)); | 2320 shadows.Add(new ShadowTarget(&function_return_)); |
| 2324 for (int i = 0; i < nof_escapes; i++) { | 2321 for (int i = 0; i < nof_escapes; i++) { |
| 2325 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); | 2322 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); |
| 2326 } | 2323 } |
| 2327 bool function_return_was_shadowed = function_return_is_shadowed_; | 2324 bool function_return_was_shadowed = function_return_is_shadowed_; |
| 2328 function_return_is_shadowed_ = true; | 2325 function_return_is_shadowed_ = true; |
| 2329 | 2326 |
| 2330 // Generate code for the statements in the try block. | 2327 // Generate code for the statements in the try block. |
| 2331 bool was_inside_try = is_inside_try_; | 2328 bool was_inside_try = is_inside_try_; |
| 2332 is_inside_try_ = true; | 2329 is_inside_try_ = true; |
| 2333 VisitStatements(node->try_block()->statements()); | 2330 VisitStatementsAndSpill(node->try_block()->statements()); |
| 2334 if (frame_ != NULL) { | |
| 2335 frame_->SpillAll(); | |
| 2336 } | |
| 2337 is_inside_try_ = was_inside_try; | 2331 is_inside_try_ = was_inside_try; |
| 2338 | 2332 |
| 2339 // Stop the introduced shadowing and count the number of required unlinks. | 2333 // Stop the introduced shadowing and count the number of required unlinks. |
| 2340 // After shadowing stops, the original targets are unshadowed and the | 2334 // After shadowing stops, the original targets are unshadowed and the |
| 2341 // ShadowTargets represent the formerly shadowing targets. | 2335 // ShadowTargets represent the formerly shadowing targets. |
| 2342 int nof_unlinks = 0; | 2336 int nof_unlinks = 0; |
| 2343 for (int i = 0; i <= nof_escapes; i++) { | 2337 for (int i = 0; i <= nof_escapes; i++) { |
| 2344 shadows[i]->StopShadowing(); | 2338 shadows[i]->StopShadowing(); |
| 2345 if (shadows[i]->is_linked()) nof_unlinks++; | 2339 if (shadows[i]->is_linked()) nof_unlinks++; |
| 2346 } | 2340 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2399 frame_->EmitPush(ecx); | 2393 frame_->EmitPush(ecx); |
| 2400 | 2394 |
| 2401 // We keep two elements on the stack - the (possibly faked) result | 2395 // We keep two elements on the stack - the (possibly faked) result |
| 2402 // and the state - while evaluating the finally block. Record it, so | 2396 // and the state - while evaluating the finally block. Record it, so |
| 2403 // that a break/continue crossing this statement can restore the | 2397 // that a break/continue crossing this statement can restore the |
| 2404 // stack. | 2398 // stack. |
| 2405 const int kFinallyStackSize = 2 * kPointerSize; | 2399 const int kFinallyStackSize = 2 * kPointerSize; |
| 2406 break_stack_height_ += kFinallyStackSize; | 2400 break_stack_height_ += kFinallyStackSize; |
| 2407 | 2401 |
| 2408 // Generate code for the statements in the finally block. | 2402 // Generate code for the statements in the finally block. |
| 2409 VisitStatements(node->finally_block()->statements()); | 2403 VisitStatementsAndSpill(node->finally_block()->statements()); |
| 2410 | 2404 |
| 2411 break_stack_height_ -= kFinallyStackSize; | 2405 break_stack_height_ -= kFinallyStackSize; |
| 2412 if (frame_ != NULL) { | 2406 if (frame_ != NULL) { |
| 2413 frame_->SpillAll(); | |
| 2414 JumpTarget exit(this); | 2407 JumpTarget exit(this); |
| 2415 // Restore state and return value or faked TOS. | 2408 // Restore state and return value or faked TOS. |
| 2416 frame_->EmitPop(ecx); | 2409 frame_->EmitPop(ecx); |
| 2417 frame_->EmitPop(eax); | 2410 frame_->EmitPop(eax); |
| 2418 | 2411 |
| 2419 // Generate code to jump to the right destination for all used | 2412 // Generate code to jump to the right destination for all used |
| 2420 // (formerly) shadowing targets. | 2413 // (formerly) shadowing targets. |
| 2421 for (int i = 0; i <= nof_escapes; i++) { | 2414 for (int i = 0; i <= nof_escapes; i++) { |
| 2422 if (shadows[i]->is_bound()) { | 2415 if (shadows[i]->is_bound()) { |
| 2423 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); | 2416 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); |
| 2424 shadows[i]->original_target()->Branch(equal); | 2417 shadows[i]->original_target()->Branch(equal); |
| 2425 } | 2418 } |
| 2426 } | 2419 } |
| 2427 | 2420 |
| 2428 // Check if we need to rethrow the exception. | 2421 // Check if we need to rethrow the exception. |
| 2429 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING))); | 2422 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING))); |
| 2430 exit.Branch(not_equal); | 2423 exit.Branch(not_equal); |
| 2431 | 2424 |
| 2432 // Rethrow exception. | 2425 // Rethrow exception. |
| 2433 frame_->EmitPush(eax); // undo pop from above | 2426 frame_->EmitPush(eax); // undo pop from above |
| 2434 frame_->CallRuntime(Runtime::kReThrow, 1); | 2427 frame_->CallRuntime(Runtime::kReThrow, 1); |
| 2435 | 2428 |
| 2436 // Done. | 2429 // Done. |
| 2437 exit.Bind(); | 2430 exit.Bind(); |
| 2438 } | 2431 } |
| 2439 } | 2432 } |
| 2440 | 2433 |
| 2441 | 2434 |
| 2442 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 2435 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
| 2443 frame_->SpillAll(); | 2436 ASSERT(!in_spilled_code()); |
| 2437 VirtualFrame::SpilledScope spilled_scope(this); |
| 2444 Comment cmnt(masm_, "[ DebuggerStatement"); | 2438 Comment cmnt(masm_, "[ DebuggerStatement"); |
| 2445 RecordStatementPosition(node); | 2439 RecordStatementPosition(node); |
| 2446 frame_->CallRuntime(Runtime::kDebugBreak, 0); | 2440 frame_->CallRuntime(Runtime::kDebugBreak, 0); |
| 2447 // Ignore the return value. | 2441 // Ignore the return value. |
| 2448 } | 2442 } |
| 2449 | 2443 |
| 2450 | 2444 |
| 2451 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 2445 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
| 2452 ASSERT(boilerplate->IsBoilerplate()); | 2446 ASSERT(boilerplate->IsBoilerplate()); |
| 2453 | 2447 |
| 2454 // Push the boilerplate on the stack. | 2448 // Push the boilerplate on the stack. |
| 2455 frame_->EmitPush(Immediate(boilerplate)); | 2449 frame_->EmitPush(Immediate(boilerplate)); |
| 2456 | 2450 |
| 2457 // Create a new closure. | 2451 // Create a new closure. |
| 2458 frame_->EmitPush(esi); | 2452 frame_->EmitPush(esi); |
| 2459 frame_->CallRuntime(Runtime::kNewClosure, 2); | 2453 frame_->CallRuntime(Runtime::kNewClosure, 2); |
| 2460 frame_->EmitPush(eax); | 2454 frame_->EmitPush(eax); |
| 2461 } | 2455 } |
| 2462 | 2456 |
| 2463 | 2457 |
| 2464 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 2458 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
| 2465 frame_->SpillAll(); | 2459 VirtualFrame::SpilledScope spilled_scope(this); |
| 2466 Comment cmnt(masm_, "[ FunctionLiteral"); | 2460 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 2467 | 2461 |
| 2468 // Build the function boilerplate and instantiate it. | 2462 // Build the function boilerplate and instantiate it. |
| 2469 Handle<JSFunction> boilerplate = BuildBoilerplate(node); | 2463 Handle<JSFunction> boilerplate = BuildBoilerplate(node); |
| 2470 // Check for stack-overflow exception. | 2464 // Check for stack-overflow exception. |
| 2471 if (HasStackOverflow()) return; | 2465 if (HasStackOverflow()) return; |
| 2472 InstantiateBoilerplate(boilerplate); | 2466 InstantiateBoilerplate(boilerplate); |
| 2473 } | 2467 } |
| 2474 | 2468 |
| 2475 | 2469 |
| 2476 void CodeGenerator::VisitFunctionBoilerplateLiteral( | 2470 void CodeGenerator::VisitFunctionBoilerplateLiteral( |
| 2477 FunctionBoilerplateLiteral* node) { | 2471 FunctionBoilerplateLiteral* node) { |
| 2478 frame_->SpillAll(); | 2472 VirtualFrame::SpilledScope spilled_scope(this); |
| 2479 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 2473 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
| 2480 InstantiateBoilerplate(node->boilerplate()); | 2474 InstantiateBoilerplate(node->boilerplate()); |
| 2481 } | 2475 } |
| 2482 | 2476 |
| 2483 | 2477 |
| 2484 void CodeGenerator::VisitConditional(Conditional* node) { | 2478 void CodeGenerator::VisitConditional(Conditional* node) { |
| 2485 frame_->SpillAll(); | 2479 VirtualFrame::SpilledScope spilled_scope(this); |
| 2486 Comment cmnt(masm_, "[ Conditional"); | 2480 Comment cmnt(masm_, "[ Conditional"); |
| 2487 JumpTarget then(this); | 2481 JumpTarget then(this); |
| 2488 JumpTarget else_(this); | 2482 JumpTarget else_(this); |
| 2489 JumpTarget exit(this); | 2483 JumpTarget exit(this); |
| 2490 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 2484 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, |
| 2485 &then, &else_, true); |
| 2491 if (frame_ != NULL) { | 2486 if (frame_ != NULL) { |
| 2492 Branch(false, &else_); | 2487 Branch(false, &else_); |
| 2493 } | 2488 } |
| 2494 if (frame_ != NULL || then.is_linked()) { | 2489 if (frame_ != NULL || then.is_linked()) { |
| 2495 then.Bind(); | 2490 then.Bind(); |
| 2496 Load(node->then_expression(), typeof_state()); | 2491 LoadAndSpill(node->then_expression(), typeof_state()); |
| 2497 frame_->SpillAll(); | |
| 2498 exit.Jump(); | 2492 exit.Jump(); |
| 2499 } | 2493 } |
| 2500 if (else_.is_linked()) { | 2494 if (else_.is_linked()) { |
| 2501 else_.Bind(); | 2495 else_.Bind(); |
| 2502 Load(node->else_expression(), typeof_state()); | 2496 LoadAndSpill(node->else_expression(), typeof_state()); |
| 2503 frame_->SpillAll(); | |
| 2504 } | 2497 } |
| 2505 exit.Bind(); | 2498 exit.Bind(); |
| 2506 } | 2499 } |
| 2507 | 2500 |
| 2508 | 2501 |
| 2509 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2502 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 2510 if (slot->type() == Slot::LOOKUP) { | 2503 if (slot->type() == Slot::LOOKUP) { |
| 2511 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2504 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 2512 | 2505 |
| 2513 // For now, just do a runtime call. | 2506 // For now, just do a runtime call. |
| 2514 frame_->SpillAll(); | 2507 VirtualFrame::SpilledScope spilled_scope(this); |
| 2515 frame_->EmitPush(esi); | 2508 frame_->EmitPush(esi); |
| 2516 frame_->EmitPush(Immediate(slot->var()->name())); | 2509 frame_->EmitPush(Immediate(slot->var()->name())); |
| 2517 | 2510 |
| 2518 if (typeof_state == INSIDE_TYPEOF) { | 2511 if (typeof_state == INSIDE_TYPEOF) { |
| 2519 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2512 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 2520 } else { | 2513 } else { |
| 2521 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 2514 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
| 2522 } | 2515 } |
| 2523 frame_->EmitPush(eax); | 2516 frame_->EmitPush(eax); |
| 2524 | 2517 |
| 2525 } else { | 2518 } else { |
| 2526 // Note: We would like to keep the assert below, but it fires because of | 2519 // Note: We would like to keep the assert below, but it fires because of |
| 2527 // some nasty code in LoadTypeofExpression() which should be removed... | 2520 // some nasty code in LoadTypeofExpression() which should be removed... |
| 2528 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 2521 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
| 2529 if (slot->var()->mode() == Variable::CONST) { | 2522 if (slot->var()->mode() == Variable::CONST) { |
| 2530 // Const slots may contain 'the hole' value (the constant hasn't been | 2523 // Const slots may contain 'the hole' value (the constant hasn't been |
| 2531 // initialized yet) which needs to be converted into the 'undefined' | 2524 // initialized yet) which needs to be converted into the 'undefined' |
| 2532 // value. | 2525 // value. |
| 2533 frame_->SpillAll(); | 2526 VirtualFrame::SpilledScope spilled_scope(this); |
| 2534 Comment cmnt(masm_, "[ Load const"); | 2527 Comment cmnt(masm_, "[ Load const"); |
| 2535 JumpTarget exit(this); | 2528 JumpTarget exit(this); |
| 2536 __ mov(eax, SlotOperand(slot, ecx)); | 2529 __ mov(eax, SlotOperand(slot, ecx)); |
| 2537 __ cmp(eax, Factory::the_hole_value()); | 2530 __ cmp(eax, Factory::the_hole_value()); |
| 2538 exit.Branch(not_equal); | 2531 exit.Branch(not_equal); |
| 2539 __ mov(eax, Factory::undefined_value()); | 2532 __ mov(eax, Factory::undefined_value()); |
| 2540 exit.Bind(); | 2533 exit.Bind(); |
| 2541 frame_->EmitPush(eax); | 2534 frame_->EmitPush(eax); |
| 2542 } else { | 2535 } else { |
| 2543 if (slot->type() == Slot::PARAMETER) { | 2536 if (slot->type() == Slot::PARAMETER) { |
| 2544 frame_->LoadParameterAt(slot->index()); | 2537 frame_->LoadParameterAt(slot->index()); |
| 2545 } else if (slot->type() == Slot::LOCAL) { | 2538 } else if (slot->type() == Slot::LOCAL) { |
| 2546 frame_->LoadLocalAt(slot->index()); | 2539 frame_->LoadLocalAt(slot->index()); |
| 2547 } else { | 2540 } else { |
| 2548 // The other remaining slot types (LOOKUP and GLOBAL) cannot reach | 2541 // The other remaining slot types (LOOKUP and GLOBAL) cannot reach |
| 2549 // here. | 2542 // here. |
| 2550 ASSERT(slot->type() == Slot::CONTEXT); | 2543 ASSERT(slot->type() == Slot::CONTEXT); |
| 2551 frame_->SpillAll(); | 2544 VirtualFrame::SpilledScope spilled_scope(this); |
| 2552 frame_->EmitPush(SlotOperand(slot, ecx)); | 2545 frame_->EmitPush(SlotOperand(slot, ecx)); |
| 2553 } | 2546 } |
| 2554 } | 2547 } |
| 2555 } | 2548 } |
| 2556 } | 2549 } |
| 2557 | 2550 |
| 2558 | 2551 |
| 2559 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { | 2552 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { |
| 2560 if (slot->type() == Slot::LOOKUP) { | 2553 if (slot->type() == Slot::LOOKUP) { |
| 2561 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2554 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 2562 | 2555 |
| 2563 // For now, just do a runtime call. | 2556 // For now, just do a runtime call. |
| 2564 frame_->SpillAll(); | 2557 VirtualFrame::SpilledScope spilled_scope(this); |
| 2565 frame_->EmitPush(frame_->Context()); | 2558 frame_->EmitPush(frame_->Context()); |
| 2566 frame_->EmitPush(Immediate(slot->var()->name())); | 2559 frame_->EmitPush(Immediate(slot->var()->name())); |
| 2567 | 2560 |
| 2568 if (init_state == CONST_INIT) { | 2561 if (init_state == CONST_INIT) { |
| 2569 // Same as the case for a normal store, but ignores attribute | 2562 // Same as the case for a normal store, but ignores attribute |
| 2570 // (e.g. READ_ONLY) of context slot so that we can initialize const | 2563 // (e.g. READ_ONLY) of context slot so that we can initialize const |
| 2571 // properties (introduced via eval("const foo = (some expr);")). Also, | 2564 // properties (introduced via eval("const foo = (some expr);")). Also, |
| 2572 // uses the current function context instead of the top context. | 2565 // uses the current function context instead of the top context. |
| 2573 // | 2566 // |
| 2574 // Note that we must declare the foo upon entry of eval(), via a | 2567 // Note that we must declare the foo upon entry of eval(), via a |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2592 } else { | 2585 } else { |
| 2593 ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 2586 ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
| 2594 | 2587 |
| 2595 JumpTarget exit(this); | 2588 JumpTarget exit(this); |
| 2596 if (init_state == CONST_INIT) { | 2589 if (init_state == CONST_INIT) { |
| 2597 ASSERT(slot->var()->mode() == Variable::CONST); | 2590 ASSERT(slot->var()->mode() == Variable::CONST); |
| 2598 // Only the first const initialization must be executed (the slot | 2591 // Only the first const initialization must be executed (the slot |
| 2599 // still contains 'the hole' value). When the assignment is executed, | 2592 // still contains 'the hole' value). When the assignment is executed, |
| 2600 // the code is identical to a normal store (see below). | 2593 // the code is identical to a normal store (see below). |
| 2601 Comment cmnt(masm_, "[ Init const"); | 2594 Comment cmnt(masm_, "[ Init const"); |
| 2602 frame_->SpillAll(); | 2595 VirtualFrame::SpilledScope spilled_scope(this); |
| 2603 __ mov(eax, SlotOperand(slot, ecx)); | 2596 __ mov(eax, SlotOperand(slot, ecx)); |
| 2604 __ cmp(eax, Factory::the_hole_value()); | 2597 __ cmp(eax, Factory::the_hole_value()); |
| 2605 exit.Branch(not_equal); | 2598 exit.Branch(not_equal); |
| 2606 } | 2599 } |
| 2607 | 2600 |
| 2608 // We must execute the store. Storing a variable must keep the (new) | 2601 // We must execute the store. Storing a variable must keep the (new) |
| 2609 // value on the stack. This is necessary for compiling assignment | 2602 // value on the stack. This is necessary for compiling assignment |
| 2610 // expressions. | 2603 // expressions. |
| 2611 // | 2604 // |
| 2612 // Note: We will reach here even with slot->var()->mode() == | 2605 // Note: We will reach here even with slot->var()->mode() == |
| 2613 // Variable::CONST because of const declarations which will initialize | 2606 // Variable::CONST because of const declarations which will initialize |
| 2614 // consts to 'the hole' value and by doing so, end up calling this code. | 2607 // consts to 'the hole' value and by doing so, end up calling this code. |
| 2615 if (slot->type() == Slot::PARAMETER) { | 2608 if (slot->type() == Slot::PARAMETER) { |
| 2616 frame_->StoreToParameterAt(slot->index()); | 2609 frame_->StoreToParameterAt(slot->index()); |
| 2617 } else if (slot->type() == Slot::LOCAL) { | 2610 } else if (slot->type() == Slot::LOCAL) { |
| 2618 frame_->StoreToLocalAt(slot->index()); | 2611 frame_->StoreToLocalAt(slot->index()); |
| 2619 } else { | 2612 } else { |
| 2620 // The other slot types (LOOKUP and GLOBAL) cannot reach here. | 2613 // The other slot types (LOOKUP and GLOBAL) cannot reach here. |
| 2621 ASSERT(slot->type() == Slot::CONTEXT); | 2614 ASSERT(slot->type() == Slot::CONTEXT); |
| 2622 frame_->SpillAll(); | 2615 VirtualFrame::SpilledScope spilled_scope(this); |
| 2623 frame_->EmitPop(eax); | 2616 frame_->EmitPop(eax); |
| 2624 __ mov(SlotOperand(slot, ecx), eax); | 2617 __ mov(SlotOperand(slot, ecx), eax); |
| 2625 frame_->EmitPush(eax); // RecordWrite may destroy the value in eax. | 2618 frame_->EmitPush(eax); // RecordWrite may destroy the value in eax. |
| 2626 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 2619 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 2627 __ RecordWrite(ecx, offset, eax, ebx); | 2620 __ RecordWrite(ecx, offset, eax, ebx); |
| 2628 } | 2621 } |
| 2629 | 2622 |
| 2630 // If we definitely did not jump over the assignment, we do not need | 2623 // If we definitely did not jump over the assignment, we do not need |
| 2631 // to bind the exit label. Doing so can defeat peephole | 2624 // to bind the exit label. Doing so can defeat peephole |
| 2632 // optimization. | 2625 // optimization. |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2706 // RegExp pattern (2). | 2699 // RegExp pattern (2). |
| 2707 __ push(Immediate(node_->pattern())); | 2700 __ push(Immediate(node_->pattern())); |
| 2708 // RegExp flags (3). | 2701 // RegExp flags (3). |
| 2709 __ push(Immediate(node_->flags())); | 2702 __ push(Immediate(node_->flags())); |
| 2710 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 2703 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 2711 __ mov(ebx, Operand(eax)); // "caller" expects result in ebx | 2704 __ mov(ebx, Operand(eax)); // "caller" expects result in ebx |
| 2712 } | 2705 } |
| 2713 | 2706 |
| 2714 | 2707 |
| 2715 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 2708 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { |
| 2716 frame_->SpillAll(); | 2709 VirtualFrame::SpilledScope spilled_scope(this); |
| 2717 Comment cmnt(masm_, "[ RegExp Literal"); | 2710 Comment cmnt(masm_, "[ RegExp Literal"); |
| 2718 RegExpDeferred* deferred = new RegExpDeferred(this, node); | 2711 RegExpDeferred* deferred = new RegExpDeferred(this, node); |
| 2719 | 2712 |
| 2720 // Retrieve the literal array and check the allocated entry. | 2713 // Retrieve the literal array and check the allocated entry. |
| 2721 | 2714 |
| 2722 // Load the function of this activation. | 2715 // Load the function of this activation. |
| 2723 __ mov(ecx, frame_->Function()); | 2716 __ mov(ecx, frame_->Function()); |
| 2724 | 2717 |
| 2725 // Load the literals array of the function. | 2718 // Load the literals array of the function. |
| 2726 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2719 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2767 // Literal index (1). | 2760 // Literal index (1). |
| 2768 __ push(Immediate(Smi::FromInt(node_->literal_index()))); | 2761 __ push(Immediate(Smi::FromInt(node_->literal_index()))); |
| 2769 // Constant properties (2). | 2762 // Constant properties (2). |
| 2770 __ push(Immediate(node_->constant_properties())); | 2763 __ push(Immediate(node_->constant_properties())); |
| 2771 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); | 2764 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); |
| 2772 __ mov(ebx, Operand(eax)); | 2765 __ mov(ebx, Operand(eax)); |
| 2773 } | 2766 } |
| 2774 | 2767 |
| 2775 | 2768 |
| 2776 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 2769 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
| 2777 frame_->SpillAll(); | 2770 VirtualFrame::SpilledScope spilled_scope(this); |
| 2778 Comment cmnt(masm_, "[ ObjectLiteral"); | 2771 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 2779 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); | 2772 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); |
| 2780 | 2773 |
| 2781 // Retrieve the literal array and check the allocated entry. | 2774 // Retrieve the literal array and check the allocated entry. |
| 2782 | 2775 |
| 2783 // Load the function of this activation. | 2776 // Load the function of this activation. |
| 2784 __ mov(ecx, frame_->Function()); | 2777 __ mov(ecx, frame_->Function()); |
| 2785 | 2778 |
| 2786 // Load the literals array of the function. | 2779 // Load the literals array of the function. |
| 2787 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2780 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2808 for (int i = 0; i < node->properties()->length(); i++) { | 2801 for (int i = 0; i < node->properties()->length(); i++) { |
| 2809 ObjectLiteral::Property* property = node->properties()->at(i); | 2802 ObjectLiteral::Property* property = node->properties()->at(i); |
| 2810 switch (property->kind()) { | 2803 switch (property->kind()) { |
| 2811 case ObjectLiteral::Property::CONSTANT: break; | 2804 case ObjectLiteral::Property::CONSTANT: break; |
| 2812 case ObjectLiteral::Property::COMPUTED: { | 2805 case ObjectLiteral::Property::COMPUTED: { |
| 2813 Handle<Object> key(property->key()->handle()); | 2806 Handle<Object> key(property->key()->handle()); |
| 2814 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 2807 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 2815 if (key->IsSymbol()) { | 2808 if (key->IsSymbol()) { |
| 2816 __ mov(eax, frame_->Top()); | 2809 __ mov(eax, frame_->Top()); |
| 2817 frame_->EmitPush(eax); | 2810 frame_->EmitPush(eax); |
| 2818 Load(property->value()); | 2811 LoadAndSpill(property->value()); |
| 2819 frame_->SpillAll(); | |
| 2820 frame_->EmitPop(eax); | 2812 frame_->EmitPop(eax); |
| 2821 __ Set(ecx, Immediate(key)); | 2813 __ Set(ecx, Immediate(key)); |
| 2822 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 2814 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 2823 frame_->Drop(); | 2815 frame_->Drop(); |
| 2824 // Ignore result. | 2816 // Ignore result. |
| 2825 break; | 2817 break; |
| 2826 } | 2818 } |
| 2827 // Fall through | 2819 // Fall through |
| 2828 } | 2820 } |
| 2829 case ObjectLiteral::Property::PROTOTYPE: { | 2821 case ObjectLiteral::Property::PROTOTYPE: { |
| 2830 __ mov(eax, frame_->Top()); | 2822 __ mov(eax, frame_->Top()); |
| 2831 frame_->EmitPush(eax); | 2823 frame_->EmitPush(eax); |
| 2832 Load(property->key()); | 2824 LoadAndSpill(property->key()); |
| 2833 frame_->SpillAll(); | 2825 LoadAndSpill(property->value()); |
| 2834 Load(property->value()); | |
| 2835 frame_->SpillAll(); | |
| 2836 frame_->CallRuntime(Runtime::kSetProperty, 3); | 2826 frame_->CallRuntime(Runtime::kSetProperty, 3); |
| 2837 // Ignore result. | 2827 // Ignore result. |
| 2838 break; | 2828 break; |
| 2839 } | 2829 } |
| 2840 case ObjectLiteral::Property::SETTER: { | 2830 case ObjectLiteral::Property::SETTER: { |
| 2841 // Duplicate the resulting object on the stack. The runtime | 2831 // Duplicate the resulting object on the stack. The runtime |
| 2842 // function will pop the three arguments passed in. | 2832 // function will pop the three arguments passed in. |
| 2843 __ mov(eax, frame_->Top()); | 2833 __ mov(eax, frame_->Top()); |
| 2844 frame_->EmitPush(eax); | 2834 frame_->EmitPush(eax); |
| 2845 Load(property->key()); | 2835 LoadAndSpill(property->key()); |
| 2846 frame_->SpillAll(); | |
| 2847 frame_->EmitPush(Immediate(Smi::FromInt(1))); | 2836 frame_->EmitPush(Immediate(Smi::FromInt(1))); |
| 2848 Load(property->value()); | 2837 LoadAndSpill(property->value()); |
| 2849 frame_->SpillAll(); | |
| 2850 frame_->CallRuntime(Runtime::kDefineAccessor, 4); | 2838 frame_->CallRuntime(Runtime::kDefineAccessor, 4); |
| 2851 // Ignore result. | 2839 // Ignore result. |
| 2852 break; | 2840 break; |
| 2853 } | 2841 } |
| 2854 case ObjectLiteral::Property::GETTER: { | 2842 case ObjectLiteral::Property::GETTER: { |
| 2855 // Duplicate the resulting object on the stack. The runtime | 2843 // Duplicate the resulting object on the stack. The runtime |
| 2856 // function will pop the three arguments passed in. | 2844 // function will pop the three arguments passed in. |
| 2857 __ mov(eax, frame_->Top()); | 2845 __ mov(eax, frame_->Top()); |
| 2858 frame_->EmitPush(eax); | 2846 frame_->EmitPush(eax); |
| 2859 Load(property->key()); | 2847 LoadAndSpill(property->key()); |
| 2860 frame_->SpillAll(); | |
| 2861 frame_->EmitPush(Immediate(Smi::FromInt(0))); | 2848 frame_->EmitPush(Immediate(Smi::FromInt(0))); |
| 2862 Load(property->value()); | 2849 LoadAndSpill(property->value()); |
| 2863 frame_->SpillAll(); | |
| 2864 frame_->CallRuntime(Runtime::kDefineAccessor, 4); | 2850 frame_->CallRuntime(Runtime::kDefineAccessor, 4); |
| 2865 // Ignore result. | 2851 // Ignore result. |
| 2866 break; | 2852 break; |
| 2867 } | 2853 } |
| 2868 default: UNREACHABLE(); | 2854 default: UNREACHABLE(); |
| 2869 } | 2855 } |
| 2870 } | 2856 } |
| 2871 } | 2857 } |
| 2872 | 2858 |
| 2873 | 2859 |
| 2874 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 2860 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
| 2875 frame_->SpillAll(); | 2861 VirtualFrame::SpilledScope spilled_scope(this); |
| 2876 Comment cmnt(masm_, "[ ArrayLiteral"); | 2862 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 2877 | 2863 |
| 2878 // Call runtime to create the array literal. | 2864 // Call runtime to create the array literal. |
| 2879 frame_->EmitPush(Immediate(node->literals())); | 2865 frame_->EmitPush(Immediate(node->literals())); |
| 2880 // Load the function of this frame. | 2866 // Load the function of this frame. |
| 2881 __ mov(ecx, frame_->Function()); | 2867 __ mov(ecx, frame_->Function()); |
| 2882 // Load the literals array of the function. | 2868 // Load the literals array of the function. |
| 2883 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2869 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
| 2884 frame_->EmitPush(ecx); | 2870 frame_->EmitPush(ecx); |
| 2885 frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2); | 2871 frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2); |
| 2886 | 2872 |
| 2887 // Push the resulting array literal on the stack. | 2873 // Push the resulting array literal on the stack. |
| 2888 frame_->EmitPush(eax); | 2874 frame_->EmitPush(eax); |
| 2889 | 2875 |
| 2890 // Generate code to set the elements in the array that are not | 2876 // Generate code to set the elements in the array that are not |
| 2891 // literals. | 2877 // literals. |
| 2892 for (int i = 0; i < node->values()->length(); i++) { | 2878 for (int i = 0; i < node->values()->length(); i++) { |
| 2893 Expression* value = node->values()->at(i); | 2879 Expression* value = node->values()->at(i); |
| 2894 | 2880 |
| 2895 // If value is literal the property value is already | 2881 // If value is literal the property value is already |
| 2896 // set in the boilerplate object. | 2882 // set in the boilerplate object. |
| 2897 if (value->AsLiteral() == NULL) { | 2883 if (value->AsLiteral() == NULL) { |
| 2898 // The property must be set by generated code. | 2884 // The property must be set by generated code. |
| 2899 Load(value); | 2885 LoadAndSpill(value); |
| 2900 frame_->SpillAll(); | |
| 2901 | 2886 |
| 2902 // Get the value off the stack. | 2887 // Get the value off the stack. |
| 2903 frame_->EmitPop(eax); | 2888 frame_->EmitPop(eax); |
| 2904 // Fetch the object literal while leaving on the stack. | 2889 // Fetch the object literal while leaving on the stack. |
| 2905 __ mov(ecx, frame_->Top()); | 2890 __ mov(ecx, frame_->Top()); |
| 2906 // Get the elements array. | 2891 // Get the elements array. |
| 2907 __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); | 2892 __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); |
| 2908 | 2893 |
| 2909 // Write to the indexed properties array. | 2894 // Write to the indexed properties array. |
| 2910 int offset = i * kPointerSize + Array::kHeaderSize; | 2895 int offset = i * kPointerSize + Array::kHeaderSize; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2935 frame_->EmitPush(Immediate(Smi::FromInt(0))); | 2920 frame_->EmitPush(Immediate(Smi::FromInt(0))); |
| 2936 return; | 2921 return; |
| 2937 } | 2922 } |
| 2938 | 2923 |
| 2939 if (node->op() == Token::ASSIGN || | 2924 if (node->op() == Token::ASSIGN || |
| 2940 node->op() == Token::INIT_VAR || | 2925 node->op() == Token::INIT_VAR || |
| 2941 node->op() == Token::INIT_CONST) { | 2926 node->op() == Token::INIT_CONST) { |
| 2942 Load(node->value()); | 2927 Load(node->value()); |
| 2943 | 2928 |
| 2944 } else { | 2929 } else { |
| 2945 frame_->SpillAll(); | 2930 VirtualFrame::SpilledScope spilled_scope(this); |
| 2946 target.GetValue(NOT_INSIDE_TYPEOF); | 2931 target.GetValueAndSpill(NOT_INSIDE_TYPEOF); |
| 2947 frame_->SpillAll(); | |
| 2948 Literal* literal = node->value()->AsLiteral(); | 2932 Literal* literal = node->value()->AsLiteral(); |
| 2949 if (IsInlineSmi(literal)) { | 2933 if (IsInlineSmi(literal)) { |
| 2950 SmiOperation(node->binary_op(), node->type(), literal->handle(), false, | 2934 SmiOperation(node->binary_op(), node->type(), literal->handle(), false, |
| 2951 NO_OVERWRITE); | 2935 NO_OVERWRITE); |
| 2952 } else { | 2936 } else { |
| 2953 Load(node->value()); | 2937 LoadAndSpill(node->value()); |
| 2954 frame_->SpillAll(); | |
| 2955 GenericBinaryOperation(node->binary_op(), node->type()); | 2938 GenericBinaryOperation(node->binary_op(), node->type()); |
| 2956 } | 2939 } |
| 2957 } | 2940 } |
| 2958 | 2941 |
| 2959 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 2942 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
| 2960 if (var != NULL && | 2943 if (var != NULL && |
| 2961 var->mode() == Variable::CONST && | 2944 var->mode() == Variable::CONST && |
| 2962 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { | 2945 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { |
| 2963 // Assignment ignored - leave the value on the stack. | 2946 // Assignment ignored - leave the value on the stack. |
| 2964 } else { | 2947 } else { |
| 2965 __ RecordPosition(node->position()); | 2948 __ RecordPosition(node->position()); |
| 2966 if (node->op() == Token::INIT_CONST) { | 2949 if (node->op() == Token::INIT_CONST) { |
| 2967 // Dynamic constant initializations must use the function context | 2950 // Dynamic constant initializations must use the function context |
| 2968 // and initialize the actual constant declared. Dynamic variable | 2951 // and initialize the actual constant declared. Dynamic variable |
| 2969 // initializations are simply assignments and use SetValue. | 2952 // initializations are simply assignments and use SetValue. |
| 2970 target.SetValue(CONST_INIT); | 2953 target.SetValue(CONST_INIT); |
| 2971 } else { | 2954 } else { |
| 2972 target.SetValue(NOT_CONST_INIT); | 2955 target.SetValue(NOT_CONST_INIT); |
| 2973 } | 2956 } |
| 2974 } | 2957 } |
| 2975 } | 2958 } |
| 2976 } | 2959 } |
| 2977 | 2960 |
| 2978 | 2961 |
| 2979 void CodeGenerator::VisitThrow(Throw* node) { | 2962 void CodeGenerator::VisitThrow(Throw* node) { |
| 2980 frame_->SpillAll(); | 2963 VirtualFrame::SpilledScope spilled_scope(this); |
| 2981 Comment cmnt(masm_, "[ Throw"); | 2964 Comment cmnt(masm_, "[ Throw"); |
| 2982 | 2965 |
| 2983 Load(node->exception()); | 2966 LoadAndSpill(node->exception()); |
| 2984 frame_->SpillAll(); | |
| 2985 __ RecordPosition(node->position()); | 2967 __ RecordPosition(node->position()); |
| 2986 frame_->CallRuntime(Runtime::kThrow, 1); | 2968 frame_->CallRuntime(Runtime::kThrow, 1); |
| 2987 frame_->EmitPush(eax); | 2969 frame_->EmitPush(eax); |
| 2988 } | 2970 } |
| 2989 | 2971 |
| 2990 | 2972 |
| 2991 void CodeGenerator::VisitProperty(Property* node) { | 2973 void CodeGenerator::VisitProperty(Property* node) { |
| 2992 frame_->SpillAll(); | 2974 VirtualFrame::SpilledScope spilled_scope(this); |
| 2993 Comment cmnt(masm_, "[ Property"); | 2975 Comment cmnt(masm_, "[ Property"); |
| 2994 Reference property(this, node); | 2976 Reference property(this, node); |
| 2995 property.GetValue(typeof_state()); | 2977 property.GetValueAndSpill(typeof_state()); |
| 2996 } | 2978 } |
| 2997 | 2979 |
| 2998 | 2980 |
| 2999 void CodeGenerator::VisitCall(Call* node) { | 2981 void CodeGenerator::VisitCall(Call* node) { |
| 3000 frame_->SpillAll(); | 2982 VirtualFrame::SpilledScope spilled_scope(this); |
| 3001 Comment cmnt(masm_, "[ Call"); | 2983 Comment cmnt(masm_, "[ Call"); |
| 3002 | 2984 |
| 3003 ZoneList<Expression*>* args = node->arguments(); | 2985 ZoneList<Expression*>* args = node->arguments(); |
| 3004 | 2986 |
| 3005 RecordStatementPosition(node); | 2987 RecordStatementPosition(node); |
| 3006 | 2988 |
| 3007 // Check if the function is a variable or a property. | 2989 // Check if the function is a variable or a property. |
| 3008 Expression* function = node->expression(); | 2990 Expression* function = node->expression(); |
| 3009 Variable* var = function->AsVariableProxy()->AsVariable(); | 2991 Variable* var = function->AsVariableProxy()->AsVariable(); |
| 3010 Property* property = function->AsProperty(); | 2992 Property* property = function->AsProperty(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3026 // Push the name of the function and the receiver onto the stack. | 3008 // Push the name of the function and the receiver onto the stack. |
| 3027 frame_->EmitPush(Immediate(var->name())); | 3009 frame_->EmitPush(Immediate(var->name())); |
| 3028 | 3010 |
| 3029 // Pass the global object as the receiver and let the IC stub | 3011 // Pass the global object as the receiver and let the IC stub |
| 3030 // patch the stack to use the global proxy as 'this' in the | 3012 // patch the stack to use the global proxy as 'this' in the |
| 3031 // invoked function. | 3013 // invoked function. |
| 3032 LoadGlobal(); | 3014 LoadGlobal(); |
| 3033 // Load the arguments. | 3015 // Load the arguments. |
| 3034 int arg_count = args->length(); | 3016 int arg_count = args->length(); |
| 3035 for (int i = 0; i < arg_count; i++) { | 3017 for (int i = 0; i < arg_count; i++) { |
| 3036 Load(args->at(i)); | 3018 LoadAndSpill(args->at(i)); |
| 3037 frame_->SpillAll(); | |
| 3038 } | 3019 } |
| 3039 | 3020 |
| 3040 // Setup the receiver register and call the IC initialization code. | 3021 // Setup the receiver register and call the IC initialization code. |
| 3041 Handle<Code> stub = (loop_nesting() > 0) | 3022 Handle<Code> stub = (loop_nesting() > 0) |
| 3042 ? ComputeCallInitializeInLoop(arg_count) | 3023 ? ComputeCallInitializeInLoop(arg_count) |
| 3043 : ComputeCallInitialize(arg_count); | 3024 : ComputeCallInitialize(arg_count); |
| 3044 __ RecordPosition(node->position()); | 3025 __ RecordPosition(node->position()); |
| 3045 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT, | 3026 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT, |
| 3046 arg_count + 1); | 3027 arg_count + 1); |
| 3047 __ mov(esi, frame_->Context()); | 3028 __ mov(esi, frame_->Context()); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 3072 // Check if the key is a literal string. | 3053 // Check if the key is a literal string. |
| 3073 Literal* literal = property->key()->AsLiteral(); | 3054 Literal* literal = property->key()->AsLiteral(); |
| 3074 | 3055 |
| 3075 if (literal != NULL && literal->handle()->IsSymbol()) { | 3056 if (literal != NULL && literal->handle()->IsSymbol()) { |
| 3076 // ------------------------------------------------------------------ | 3057 // ------------------------------------------------------------------ |
| 3077 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' | 3058 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' |
| 3078 // ------------------------------------------------------------------ | 3059 // ------------------------------------------------------------------ |
| 3079 | 3060 |
| 3080 // Push the name of the function and the receiver onto the stack. | 3061 // Push the name of the function and the receiver onto the stack. |
| 3081 frame_->EmitPush(Immediate(literal->handle())); | 3062 frame_->EmitPush(Immediate(literal->handle())); |
| 3082 Load(property->obj()); | 3063 LoadAndSpill(property->obj()); |
| 3083 frame_->SpillAll(); | |
| 3084 | 3064 |
| 3085 // Load the arguments. | 3065 // Load the arguments. |
| 3086 int arg_count = args->length(); | 3066 int arg_count = args->length(); |
| 3087 for (int i = 0; i < arg_count; i++) { | 3067 for (int i = 0; i < arg_count; i++) { |
| 3088 Load(args->at(i)); | 3068 LoadAndSpill(args->at(i)); |
| 3089 frame_->SpillAll(); | |
| 3090 } | 3069 } |
| 3091 | 3070 |
| 3092 // Call the IC initialization code. | 3071 // Call the IC initialization code. |
| 3093 Handle<Code> stub = (loop_nesting() > 0) | 3072 Handle<Code> stub = (loop_nesting() > 0) |
| 3094 ? ComputeCallInitializeInLoop(arg_count) | 3073 ? ComputeCallInitializeInLoop(arg_count) |
| 3095 : ComputeCallInitialize(arg_count); | 3074 : ComputeCallInitialize(arg_count); |
| 3096 __ RecordPosition(node->position()); | 3075 __ RecordPosition(node->position()); |
| 3097 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); | 3076 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); |
| 3098 __ mov(esi, frame_->Context()); | 3077 __ mov(esi, frame_->Context()); |
| 3099 | 3078 |
| 3100 // Overwrite the function on the stack with the result. | 3079 // Overwrite the function on the stack with the result. |
| 3101 __ mov(frame_->Top(), eax); | 3080 __ mov(frame_->Top(), eax); |
| 3102 | 3081 |
| 3103 } else { | 3082 } else { |
| 3104 // ------------------------------------------- | 3083 // ------------------------------------------- |
| 3105 // JavaScript example: 'array[index](1, 2, 3)' | 3084 // JavaScript example: 'array[index](1, 2, 3)' |
| 3106 // ------------------------------------------- | 3085 // ------------------------------------------- |
| 3107 | 3086 |
| 3108 // Load the function to call from the property through a reference. | 3087 // Load the function to call from the property through a reference. |
| 3109 Reference ref(this, property); | 3088 Reference ref(this, property); |
| 3110 ref.GetValue(NOT_INSIDE_TYPEOF); | 3089 ref.GetValueAndSpill(NOT_INSIDE_TYPEOF); |
| 3111 frame_->SpillAll(); | |
| 3112 | 3090 |
| 3113 // Pass receiver to called function. | 3091 // Pass receiver to called function. |
| 3114 // The reference's size is non-negative. | 3092 // The reference's size is non-negative. |
| 3115 frame_->EmitPush(frame_->ElementAt(ref.size())); | 3093 frame_->EmitPush(frame_->ElementAt(ref.size())); |
| 3116 | 3094 |
| 3117 // Call the function. | 3095 // Call the function. |
| 3118 CallWithArguments(args, node->position()); | 3096 CallWithArguments(args, node->position()); |
| 3119 } | 3097 } |
| 3120 | 3098 |
| 3121 } else { | 3099 } else { |
| 3122 // ---------------------------------- | 3100 // ---------------------------------- |
| 3123 // JavaScript example: 'foo(1, 2, 3)' // foo is not global | 3101 // JavaScript example: 'foo(1, 2, 3)' // foo is not global |
| 3124 // ---------------------------------- | 3102 // ---------------------------------- |
| 3125 | 3103 |
| 3126 // Load the function. | 3104 // Load the function. |
| 3127 Load(function); | 3105 LoadAndSpill(function); |
| 3128 frame_->SpillAll(); | |
| 3129 | 3106 |
| 3130 // Pass the global proxy as the receiver. | 3107 // Pass the global proxy as the receiver. |
| 3131 LoadGlobalReceiver(eax); | 3108 LoadGlobalReceiver(eax); |
| 3132 | 3109 |
| 3133 // Call the function. | 3110 // Call the function. |
| 3134 CallWithArguments(args, node->position()); | 3111 CallWithArguments(args, node->position()); |
| 3135 } | 3112 } |
| 3136 } | 3113 } |
| 3137 | 3114 |
| 3138 | 3115 |
| 3139 void CodeGenerator::VisitCallNew(CallNew* node) { | 3116 void CodeGenerator::VisitCallNew(CallNew* node) { |
| 3140 frame_->SpillAll(); | 3117 VirtualFrame::SpilledScope spilled_scope(this); |
| 3141 Comment cmnt(masm_, "[ CallNew"); | 3118 Comment cmnt(masm_, "[ CallNew"); |
| 3142 | 3119 |
| 3143 // According to ECMA-262, section 11.2.2, page 44, the function | 3120 // According to ECMA-262, section 11.2.2, page 44, the function |
| 3144 // expression in new calls must be evaluated before the | 3121 // expression in new calls must be evaluated before the |
| 3145 // arguments. This is different from ordinary calls, where the | 3122 // arguments. This is different from ordinary calls, where the |
| 3146 // actual function to call is resolved after the arguments have been | 3123 // actual function to call is resolved after the arguments have been |
| 3147 // evaluated. | 3124 // evaluated. |
| 3148 | 3125 |
| 3149 // Compute function to call and use the global object as the | 3126 // Compute function to call and use the global object as the |
| 3150 // receiver. There is no need to use the global proxy here because | 3127 // receiver. There is no need to use the global proxy here because |
| 3151 // it will always be replaced with a newly allocated object. | 3128 // it will always be replaced with a newly allocated object. |
| 3152 Load(node->expression()); | 3129 LoadAndSpill(node->expression()); |
| 3153 frame_->SpillAll(); | |
| 3154 LoadGlobal(); | 3130 LoadGlobal(); |
| 3155 | 3131 |
| 3156 // Push the arguments ("left-to-right") on the stack. | 3132 // Push the arguments ("left-to-right") on the stack. |
| 3157 ZoneList<Expression*>* args = node->arguments(); | 3133 ZoneList<Expression*>* args = node->arguments(); |
| 3158 int arg_count = args->length(); | 3134 int arg_count = args->length(); |
| 3159 for (int i = 0; i < arg_count; i++) { | 3135 for (int i = 0; i < arg_count; i++) { |
| 3160 Load(args->at(i)); | 3136 LoadAndSpill(args->at(i)); |
| 3161 frame_->SpillAll(); | |
| 3162 } | 3137 } |
| 3163 | 3138 |
| 3164 // Constructors are called with the number of arguments in register | 3139 // Constructors are called with the number of arguments in register |
| 3165 // eax for now. Another option would be to have separate construct | 3140 // eax for now. Another option would be to have separate construct |
| 3166 // call trampolines per different arguments counts encountered. | 3141 // call trampolines per different arguments counts encountered. |
| 3167 __ Set(eax, Immediate(arg_count)); | 3142 __ Set(eax, Immediate(arg_count)); |
| 3168 | 3143 |
| 3169 // Load the function into temporary function slot as per calling | 3144 // Load the function into temporary function slot as per calling |
| 3170 // convention. | 3145 // convention. |
| 3171 __ mov(edi, frame_->ElementAt(arg_count + 1)); | 3146 __ mov(edi, frame_->ElementAt(arg_count + 1)); |
| 3172 | 3147 |
| 3173 // Call the construct call builtin that handles allocation and | 3148 // Call the construct call builtin that handles allocation and |
| 3174 // constructor invocation. | 3149 // constructor invocation. |
| 3175 __ RecordPosition(node->position()); | 3150 __ RecordPosition(node->position()); |
| 3176 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); | 3151 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); |
| 3177 frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, args->length() + 1); | 3152 frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, args->length() + 1); |
| 3178 // Discard the function and "push" the newly created object. | 3153 // Discard the function and "push" the newly created object. |
| 3179 __ mov(frame_->Top(), eax); | 3154 __ mov(frame_->Top(), eax); |
| 3180 } | 3155 } |
| 3181 | 3156 |
| 3182 | 3157 |
| 3183 void CodeGenerator::VisitCallEval(CallEval* node) { | 3158 void CodeGenerator::VisitCallEval(CallEval* node) { |
| 3184 frame_->SpillAll(); | 3159 VirtualFrame::SpilledScope spilled_scope(this); |
| 3185 Comment cmnt(masm_, "[ CallEval"); | 3160 Comment cmnt(masm_, "[ CallEval"); |
| 3186 | 3161 |
| 3187 // In a call to eval, we first call %ResolvePossiblyDirectEval to resolve | 3162 // In a call to eval, we first call %ResolvePossiblyDirectEval to resolve |
| 3188 // the function we need to call and the receiver of the call. | 3163 // the function we need to call and the receiver of the call. |
| 3189 // Then we call the resolved function using the given arguments. | 3164 // Then we call the resolved function using the given arguments. |
| 3190 | 3165 |
| 3191 ZoneList<Expression*>* args = node->arguments(); | 3166 ZoneList<Expression*>* args = node->arguments(); |
| 3192 Expression* function = node->expression(); | 3167 Expression* function = node->expression(); |
| 3193 | 3168 |
| 3194 RecordStatementPosition(node); | 3169 RecordStatementPosition(node); |
| 3195 | 3170 |
| 3196 // Prepare stack for call to resolved function. | 3171 // Prepare stack for call to resolved function. |
| 3197 Load(function); | 3172 LoadAndSpill(function); |
| 3198 frame_->SpillAll(); | |
| 3199 // Allocate a frame slot for the receiver. | 3173 // Allocate a frame slot for the receiver. |
| 3200 frame_->EmitPush(Immediate(Factory::undefined_value())); | 3174 frame_->EmitPush(Immediate(Factory::undefined_value())); |
| 3201 int arg_count = args->length(); | 3175 int arg_count = args->length(); |
| 3202 for (int i = 0; i < arg_count; i++) { | 3176 for (int i = 0; i < arg_count; i++) { |
| 3203 Load(args->at(i)); | 3177 LoadAndSpill(args->at(i)); |
| 3204 frame_->SpillAll(); | |
| 3205 } | 3178 } |
| 3206 | 3179 |
| 3207 // Prepare stack for call to ResolvePossiblyDirectEval. | 3180 // Prepare stack for call to ResolvePossiblyDirectEval. |
| 3208 frame_->EmitPush(frame_->ElementAt(arg_count + 1)); | 3181 frame_->EmitPush(frame_->ElementAt(arg_count + 1)); |
| 3209 if (arg_count > 0) { | 3182 if (arg_count > 0) { |
| 3210 frame_->EmitPush(frame_->ElementAt(arg_count)); | 3183 frame_->EmitPush(frame_->ElementAt(arg_count)); |
| 3211 } else { | 3184 } else { |
| 3212 frame_->EmitPush(Immediate(Factory::undefined_value())); | 3185 frame_->EmitPush(Immediate(Factory::undefined_value())); |
| 3213 } | 3186 } |
| 3214 | 3187 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3228 frame_->CallStub(&call_function, arg_count + 1); | 3201 frame_->CallStub(&call_function, arg_count + 1); |
| 3229 | 3202 |
| 3230 // Restore context and pop function from the stack. | 3203 // Restore context and pop function from the stack. |
| 3231 __ mov(esi, frame_->Context()); | 3204 __ mov(esi, frame_->Context()); |
| 3232 __ mov(frame_->Top(), eax); | 3205 __ mov(frame_->Top(), eax); |
| 3233 } | 3206 } |
| 3234 | 3207 |
| 3235 | 3208 |
| 3236 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 3209 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| 3237 ASSERT(args->length() == 1); | 3210 ASSERT(args->length() == 1); |
| 3238 Load(args->at(0)); | 3211 LoadAndSpill(args->at(0)); |
| 3239 frame_->SpillAll(); | |
| 3240 frame_->EmitPop(eax); | 3212 frame_->EmitPop(eax); |
| 3241 __ test(eax, Immediate(kSmiTagMask)); | 3213 __ test(eax, Immediate(kSmiTagMask)); |
| 3242 cc_reg_ = zero; | 3214 cc_reg_ = zero; |
| 3243 } | 3215 } |
| 3244 | 3216 |
| 3245 | 3217 |
| 3246 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 3218 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 3247 ASSERT(args->length() == 1); | 3219 ASSERT(args->length() == 1); |
| 3248 Load(args->at(0)); | 3220 LoadAndSpill(args->at(0)); |
| 3249 frame_->SpillAll(); | |
| 3250 frame_->EmitPop(eax); | 3221 frame_->EmitPop(eax); |
| 3251 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); | 3222 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); |
| 3252 cc_reg_ = zero; | 3223 cc_reg_ = zero; |
| 3253 } | 3224 } |
| 3254 | 3225 |
| 3255 | 3226 |
| 3256 // This generates code that performs a charCodeAt() call or returns | 3227 // This generates code that performs a charCodeAt() call or returns |
| 3257 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 3228 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
| 3258 // It can handle flat and sliced strings, 8 and 16 bit characters and | 3229 // It can handle flat and sliced strings, 8 and 16 bit characters and |
| 3259 // cons strings where the answer is found in the left hand branch of the | 3230 // cons strings where the answer is found in the left hand branch of the |
| 3260 // cons. The slow case will flatten the string, which will ensure that | 3231 // cons. The slow case will flatten the string, which will ensure that |
| 3261 // the answer is in the left hand side the next time around. | 3232 // the answer is in the left hand side the next time around. |
| 3262 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 3233 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| 3263 ASSERT(args->length() == 2); | 3234 ASSERT(args->length() == 2); |
| 3264 | 3235 |
| 3265 JumpTarget slow_case(this); | 3236 JumpTarget slow_case(this); |
| 3266 JumpTarget end(this); | 3237 JumpTarget end(this); |
| 3267 JumpTarget not_a_flat_string(this); | 3238 JumpTarget not_a_flat_string(this); |
| 3268 JumpTarget not_a_cons_string_either(this); | 3239 JumpTarget not_a_cons_string_either(this); |
| 3269 JumpTarget try_again_with_new_string(this); | 3240 JumpTarget try_again_with_new_string(this); |
| 3270 JumpTarget ascii_string(this); | 3241 JumpTarget ascii_string(this); |
| 3271 JumpTarget got_char_code(this); | 3242 JumpTarget got_char_code(this); |
| 3272 | 3243 |
| 3273 // Load the string into eax and the index into ebx. | 3244 // Load the string into eax and the index into ebx. |
| 3274 Load(args->at(0)); | 3245 LoadAndSpill(args->at(0)); |
| 3275 frame_->SpillAll(); | 3246 LoadAndSpill(args->at(1)); |
| 3276 Load(args->at(1)); | |
| 3277 frame_->SpillAll(); | |
| 3278 frame_->EmitPop(ebx); | 3247 frame_->EmitPop(ebx); |
| 3279 frame_->EmitPop(eax); | 3248 frame_->EmitPop(eax); |
| 3280 // If the receiver is a smi return undefined. | 3249 // If the receiver is a smi return undefined. |
| 3281 ASSERT(kSmiTag == 0); | 3250 ASSERT(kSmiTag == 0); |
| 3282 __ test(eax, Immediate(kSmiTagMask)); | 3251 __ test(eax, Immediate(kSmiTagMask)); |
| 3283 slow_case.Branch(zero, not_taken); | 3252 slow_case.Branch(zero, not_taken); |
| 3284 | 3253 |
| 3285 // Check for negative or non-smi index. | 3254 // Check for negative or non-smi index. |
| 3286 ASSERT(kSmiTag == 0); | 3255 ASSERT(kSmiTag == 0); |
| 3287 __ test(ebx, Immediate(kSmiTagMask | 0x80000000)); | 3256 __ test(ebx, Immediate(kSmiTagMask | 0x80000000)); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3367 | 3336 |
| 3368 slow_case.Bind(); | 3337 slow_case.Bind(); |
| 3369 frame_->EmitPush(Immediate(Factory::undefined_value())); | 3338 frame_->EmitPush(Immediate(Factory::undefined_value())); |
| 3370 | 3339 |
| 3371 end.Bind(); | 3340 end.Bind(); |
| 3372 } | 3341 } |
| 3373 | 3342 |
| 3374 | 3343 |
| 3375 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 3344 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 3376 ASSERT(args->length() == 1); | 3345 ASSERT(args->length() == 1); |
| 3377 Load(args->at(0)); | 3346 LoadAndSpill(args->at(0)); |
| 3378 frame_->SpillAll(); | |
| 3379 JumpTarget answer(this); | 3347 JumpTarget answer(this); |
| 3380 // We need the CC bits to come out as not_equal in the case where the | 3348 // We need the CC bits to come out as not_equal in the case where the |
| 3381 // object is a smi. This can't be done with the usual test opcode so | 3349 // object is a smi. This can't be done with the usual test opcode so |
| 3382 // we copy the object to ecx and do some destructive ops on it that | 3350 // we copy the object to ecx and do some destructive ops on it that |
| 3383 // result in the right CC bits. | 3351 // result in the right CC bits. |
| 3384 frame_->EmitPop(eax); | 3352 frame_->EmitPop(eax); |
| 3385 __ mov(ecx, Operand(eax)); | 3353 __ mov(ecx, Operand(eax)); |
| 3386 __ and_(ecx, kSmiTagMask); | 3354 __ and_(ecx, kSmiTagMask); |
| 3387 __ xor_(ecx, kSmiTagMask); | 3355 __ xor_(ecx, kSmiTagMask); |
| 3388 answer.Branch(not_equal, not_taken); | 3356 answer.Branch(not_equal, not_taken); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 3407 // Call the shared stub to get to the arguments.length. | 3375 // Call the shared stub to get to the arguments.length. |
| 3408 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); | 3376 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
| 3409 frame_->CallStub(&stub, 0); | 3377 frame_->CallStub(&stub, 0); |
| 3410 frame_->EmitPush(eax); | 3378 frame_->EmitPush(eax); |
| 3411 } | 3379 } |
| 3412 | 3380 |
| 3413 | 3381 |
| 3414 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 3382 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| 3415 ASSERT(args->length() == 1); | 3383 ASSERT(args->length() == 1); |
| 3416 JumpTarget leave(this); | 3384 JumpTarget leave(this); |
| 3417 Load(args->at(0)); // Load the object. | 3385 LoadAndSpill(args->at(0)); // Load the object. |
| 3418 frame_->SpillAll(); | |
| 3419 __ mov(eax, frame_->Top()); | 3386 __ mov(eax, frame_->Top()); |
| 3420 // if (object->IsSmi()) return object. | 3387 // if (object->IsSmi()) return object. |
| 3421 __ test(eax, Immediate(kSmiTagMask)); | 3388 __ test(eax, Immediate(kSmiTagMask)); |
| 3422 leave.Branch(zero, taken); | 3389 leave.Branch(zero, taken); |
| 3423 // It is a heap object - get map. | 3390 // It is a heap object - get map. |
| 3424 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 3391 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3425 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 3392 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 3426 // if (!object->IsJSValue()) return object. | 3393 // if (!object->IsJSValue()) return object. |
| 3427 __ cmp(ecx, JS_VALUE_TYPE); | 3394 __ cmp(ecx, JS_VALUE_TYPE); |
| 3428 leave.Branch(not_equal, not_taken); | 3395 leave.Branch(not_equal, not_taken); |
| 3429 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); | 3396 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); |
| 3430 __ mov(frame_->Top(), eax); | 3397 __ mov(frame_->Top(), eax); |
| 3431 leave.Bind(); | 3398 leave.Bind(); |
| 3432 } | 3399 } |
| 3433 | 3400 |
| 3434 | 3401 |
| 3435 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { | 3402 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { |
| 3436 ASSERT(args->length() == 2); | 3403 ASSERT(args->length() == 2); |
| 3437 JumpTarget leave(this); | 3404 JumpTarget leave(this); |
| 3438 Load(args->at(0)); // Load the object. | 3405 LoadAndSpill(args->at(0)); // Load the object. |
| 3439 frame_->SpillAll(); | 3406 LoadAndSpill(args->at(1)); // Load the value. |
| 3440 Load(args->at(1)); // Load the value. | |
| 3441 frame_->SpillAll(); | |
| 3442 __ mov(eax, frame_->ElementAt(1)); | 3407 __ mov(eax, frame_->ElementAt(1)); |
| 3443 __ mov(ecx, frame_->Top()); | 3408 __ mov(ecx, frame_->Top()); |
| 3444 // if (object->IsSmi()) return object. | 3409 // if (object->IsSmi()) return object. |
| 3445 __ test(eax, Immediate(kSmiTagMask)); | 3410 __ test(eax, Immediate(kSmiTagMask)); |
| 3446 leave.Branch(zero, taken); | 3411 leave.Branch(zero, taken); |
| 3447 // It is a heap object - get map. | 3412 // It is a heap object - get map. |
| 3448 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 3413 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3449 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 3414 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 3450 // if (!object->IsJSValue()) return object. | 3415 // if (!object->IsJSValue()) return object. |
| 3451 __ cmp(ebx, JS_VALUE_TYPE); | 3416 __ cmp(ebx, JS_VALUE_TYPE); |
| 3452 leave.Branch(not_equal, not_taken); | 3417 leave.Branch(not_equal, not_taken); |
| 3453 // Store the value. | 3418 // Store the value. |
| 3454 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); | 3419 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); |
| 3455 // Update the write barrier. | 3420 // Update the write barrier. |
| 3456 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); | 3421 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); |
| 3457 // Leave. | 3422 // Leave. |
| 3458 leave.Bind(); | 3423 leave.Bind(); |
| 3459 __ mov(ecx, frame_->Top()); | 3424 __ mov(ecx, frame_->Top()); |
| 3460 frame_->Drop(); | 3425 frame_->Drop(); |
| 3461 __ mov(frame_->Top(), ecx); | 3426 __ mov(frame_->Top(), ecx); |
| 3462 } | 3427 } |
| 3463 | 3428 |
| 3464 | 3429 |
| 3465 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 3430 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
| 3466 ASSERT(args->length() == 1); | 3431 ASSERT(args->length() == 1); |
| 3467 | 3432 |
| 3468 // Load the key onto the stack and set register eax to the formal | 3433 // Load the key onto the stack and set register eax to the formal |
| 3469 // parameters count for the currently executing function. | 3434 // parameters count for the currently executing function. |
| 3470 Load(args->at(0)); | 3435 LoadAndSpill(args->at(0)); |
| 3471 frame_->SpillAll(); | |
| 3472 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); | 3436 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 3473 | 3437 |
| 3474 // Call the shared stub to get to arguments[key]. | 3438 // Call the shared stub to get to arguments[key]. |
| 3475 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 3439 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 3476 frame_->CallStub(&stub, 0); | 3440 frame_->CallStub(&stub, 0); |
| 3477 __ mov(frame_->Top(), eax); | 3441 __ mov(frame_->Top(), eax); |
| 3478 } | 3442 } |
| 3479 | 3443 |
| 3480 | 3444 |
| 3481 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 3445 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
| 3482 ASSERT(args->length() == 2); | 3446 ASSERT(args->length() == 2); |
| 3483 | 3447 |
| 3484 // Load the two objects into registers and perform the comparison. | 3448 // Load the two objects into registers and perform the comparison. |
| 3485 Load(args->at(0)); | 3449 LoadAndSpill(args->at(0)); |
| 3486 frame_->SpillAll(); | 3450 LoadAndSpill(args->at(1)); |
| 3487 Load(args->at(1)); | |
| 3488 frame_->SpillAll(); | |
| 3489 frame_->EmitPop(eax); | 3451 frame_->EmitPop(eax); |
| 3490 frame_->EmitPop(ecx); | 3452 frame_->EmitPop(ecx); |
| 3491 __ cmp(eax, Operand(ecx)); | 3453 __ cmp(eax, Operand(ecx)); |
| 3492 cc_reg_ = equal; | 3454 cc_reg_ = equal; |
| 3493 } | 3455 } |
| 3494 | 3456 |
| 3495 | 3457 |
| 3496 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 3458 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 3497 frame_->SpillAll(); | 3459 VirtualFrame::SpilledScope spilled_scope(this); |
| 3498 if (CheckForInlineRuntimeCall(node)) { | 3460 if (CheckForInlineRuntimeCall(node)) { |
| 3499 return; | 3461 return; |
| 3500 } | 3462 } |
| 3501 | 3463 |
| 3502 ZoneList<Expression*>* args = node->arguments(); | 3464 ZoneList<Expression*>* args = node->arguments(); |
| 3503 Comment cmnt(masm_, "[ CallRuntime"); | 3465 Comment cmnt(masm_, "[ CallRuntime"); |
| 3504 Runtime::Function* function = node->function(); | 3466 Runtime::Function* function = node->function(); |
| 3505 | 3467 |
| 3506 if (function == NULL) { | 3468 if (function == NULL) { |
| 3507 // Prepare stack for calling JS runtime function. | 3469 // Prepare stack for calling JS runtime function. |
| 3508 frame_->EmitPush(Immediate(node->name())); | 3470 frame_->EmitPush(Immediate(node->name())); |
| 3509 // Push the builtins object found in the current global object. | 3471 // Push the builtins object found in the current global object. |
| 3510 __ mov(edx, GlobalObject()); | 3472 __ mov(edx, GlobalObject()); |
| 3511 frame_->EmitPush(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); | 3473 frame_->EmitPush(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); |
| 3512 } | 3474 } |
| 3513 | 3475 |
| 3514 // Push the arguments ("left-to-right"). | 3476 // Push the arguments ("left-to-right"). |
| 3515 int arg_count = args->length(); | 3477 int arg_count = args->length(); |
| 3516 for (int i = 0; i < arg_count; i++) { | 3478 for (int i = 0; i < arg_count; i++) { |
| 3517 Load(args->at(i)); | 3479 LoadAndSpill(args->at(i)); |
| 3518 frame_->SpillAll(); | |
| 3519 } | 3480 } |
| 3520 | 3481 |
| 3521 if (function == NULL) { | 3482 if (function == NULL) { |
| 3522 // Call the JS runtime function. | 3483 // Call the JS runtime function. |
| 3523 Handle<Code> stub = ComputeCallInitialize(arg_count); | 3484 Handle<Code> stub = ComputeCallInitialize(arg_count); |
| 3524 __ Set(eax, Immediate(args->length())); | 3485 __ Set(eax, Immediate(args->length())); |
| 3525 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); | 3486 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); |
| 3526 __ mov(esi, frame_->Context()); | 3487 __ mov(esi, frame_->Context()); |
| 3527 __ mov(frame_->Top(), eax); | 3488 __ mov(frame_->Top(), eax); |
| 3528 } else { | 3489 } else { |
| 3529 // Call the C runtime function. | 3490 // Call the C runtime function. |
| 3530 frame_->CallRuntime(function, arg_count); | 3491 frame_->CallRuntime(function, arg_count); |
| 3531 frame_->EmitPush(eax); | 3492 frame_->EmitPush(eax); |
| 3532 } | 3493 } |
| 3533 } | 3494 } |
| 3534 | 3495 |
| 3535 | 3496 |
| 3536 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 3497 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| 3537 frame_->SpillAll(); | 3498 VirtualFrame::SpilledScope spilled_scope(this); |
| 3538 // Note that because of NOT and an optimization in comparison of a typeof | 3499 // Note that because of NOT and an optimization in comparison of a typeof |
| 3539 // expression to a literal string, this function can fail to leave a value | 3500 // expression to a literal string, this function can fail to leave a value |
| 3540 // on top of the frame or in the cc register. | 3501 // on top of the frame or in the cc register. |
| 3541 Comment cmnt(masm_, "[ UnaryOperation"); | 3502 Comment cmnt(masm_, "[ UnaryOperation"); |
| 3542 | 3503 |
| 3543 Token::Value op = node->op(); | 3504 Token::Value op = node->op(); |
| 3544 | 3505 |
| 3545 if (op == Token::NOT) { | 3506 if (op == Token::NOT) { |
| 3546 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, | 3507 LoadConditionAndSpill(node->expression(), NOT_INSIDE_TYPEOF, |
| 3547 false_target(), true_target(), true); | 3508 false_target(), true_target(), true); |
| 3548 cc_reg_ = NegateCondition(cc_reg_); | 3509 cc_reg_ = NegateCondition(cc_reg_); |
| 3549 | 3510 |
| 3550 } else if (op == Token::DELETE) { | 3511 } else if (op == Token::DELETE) { |
| 3551 Property* property = node->expression()->AsProperty(); | 3512 Property* property = node->expression()->AsProperty(); |
| 3552 if (property != NULL) { | 3513 if (property != NULL) { |
| 3553 Load(property->obj()); | 3514 LoadAndSpill(property->obj()); |
| 3554 frame_->SpillAll(); | 3515 LoadAndSpill(property->key()); |
| 3555 Load(property->key()); | |
| 3556 frame_->SpillAll(); | |
| 3557 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); | 3516 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
| 3558 frame_->EmitPush(eax); | 3517 frame_->EmitPush(eax); |
| 3559 return; | 3518 return; |
| 3560 } | 3519 } |
| 3561 | 3520 |
| 3562 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); | 3521 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); |
| 3563 if (variable != NULL) { | 3522 if (variable != NULL) { |
| 3564 Slot* slot = variable->slot(); | 3523 Slot* slot = variable->slot(); |
| 3565 if (variable->is_global()) { | 3524 if (variable->is_global()) { |
| 3566 LoadGlobal(); | 3525 LoadGlobal(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3581 frame_->EmitPush(eax); | 3540 frame_->EmitPush(eax); |
| 3582 return; | 3541 return; |
| 3583 } | 3542 } |
| 3584 | 3543 |
| 3585 // Default: Result of deleting non-global, not dynamically | 3544 // Default: Result of deleting non-global, not dynamically |
| 3586 // introduced variables is false. | 3545 // introduced variables is false. |
| 3587 frame_->EmitPush(Immediate(Factory::false_value())); | 3546 frame_->EmitPush(Immediate(Factory::false_value())); |
| 3588 | 3547 |
| 3589 } else { | 3548 } else { |
| 3590 // Default: Result of deleting expressions is true. | 3549 // Default: Result of deleting expressions is true. |
| 3591 Load(node->expression()); // may have side-effects | 3550 LoadAndSpill(node->expression()); // may have side-effects |
| 3592 frame_->SpillAll(); | |
| 3593 __ Set(frame_->Top(), Immediate(Factory::true_value())); | 3551 __ Set(frame_->Top(), Immediate(Factory::true_value())); |
| 3594 } | 3552 } |
| 3595 | 3553 |
| 3596 } else if (op == Token::TYPEOF) { | 3554 } else if (op == Token::TYPEOF) { |
| 3597 // Special case for loading the typeof expression; see comment on | 3555 // Special case for loading the typeof expression; see comment on |
| 3598 // LoadTypeofExpression(). | 3556 // LoadTypeofExpression(). |
| 3599 LoadTypeofExpression(node->expression()); | 3557 LoadTypeofExpression(node->expression()); |
| 3600 frame_->CallRuntime(Runtime::kTypeof, 1); | 3558 frame_->CallRuntime(Runtime::kTypeof, 1); |
| 3601 frame_->EmitPush(eax); | 3559 frame_->EmitPush(eax); |
| 3602 | 3560 |
| 3603 } else { | 3561 } else { |
| 3604 Load(node->expression()); | 3562 LoadAndSpill(node->expression()); |
| 3605 frame_->SpillAll(); | |
| 3606 switch (op) { | 3563 switch (op) { |
| 3607 case Token::NOT: | 3564 case Token::NOT: |
| 3608 case Token::DELETE: | 3565 case Token::DELETE: |
| 3609 case Token::TYPEOF: | 3566 case Token::TYPEOF: |
| 3610 UNREACHABLE(); // handled above | 3567 UNREACHABLE(); // handled above |
| 3611 break; | 3568 break; |
| 3612 | 3569 |
| 3613 case Token::SUB: { | 3570 case Token::SUB: { |
| 3614 UnarySubStub stub; | 3571 UnarySubStub stub; |
| 3615 // TODO(1222589): remove dependency of TOS being cached inside stub | 3572 // TODO(1222589): remove dependency of TOS being cached inside stub |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3744 if (is_postfix_) { | 3701 if (is_postfix_) { |
| 3745 RevertToNumberStub to_number_stub(is_increment_); | 3702 RevertToNumberStub to_number_stub(is_increment_); |
| 3746 __ CallStub(&to_number_stub); | 3703 __ CallStub(&to_number_stub); |
| 3747 } | 3704 } |
| 3748 CounterOpStub stub(result_offset_, is_postfix_, is_increment_); | 3705 CounterOpStub stub(result_offset_, is_postfix_, is_increment_); |
| 3749 __ CallStub(&stub); | 3706 __ CallStub(&stub); |
| 3750 } | 3707 } |
| 3751 | 3708 |
| 3752 | 3709 |
| 3753 void CodeGenerator::VisitCountOperation(CountOperation* node) { | 3710 void CodeGenerator::VisitCountOperation(CountOperation* node) { |
| 3754 frame_->SpillAll(); | 3711 VirtualFrame::SpilledScope spilled_scope(this); |
| 3755 Comment cmnt(masm_, "[ CountOperation"); | 3712 Comment cmnt(masm_, "[ CountOperation"); |
| 3756 | 3713 |
| 3757 bool is_postfix = node->is_postfix(); | 3714 bool is_postfix = node->is_postfix(); |
| 3758 bool is_increment = node->op() == Token::INC; | 3715 bool is_increment = node->op() == Token::INC; |
| 3759 | 3716 |
| 3760 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 3717 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
| 3761 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 3718 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
| 3762 | 3719 |
| 3763 // Postfix: Make room for the result. | 3720 // Postfix: Make room for the result. |
| 3764 if (is_postfix) { | 3721 if (is_postfix) { |
| 3765 frame_->EmitPush(Immediate(0)); | 3722 frame_->EmitPush(Immediate(0)); |
| 3766 } | 3723 } |
| 3767 | 3724 |
| 3768 { Reference target(this, node->expression()); | 3725 { Reference target(this, node->expression()); |
| 3769 if (target.is_illegal()) { | 3726 if (target.is_illegal()) { |
| 3770 // Spoof the virtual frame to have the expected height (one higher | 3727 // Spoof the virtual frame to have the expected height (one higher |
| 3771 // than on entry). | 3728 // than on entry). |
| 3772 if (!is_postfix) { | 3729 if (!is_postfix) { |
| 3773 frame_->EmitPush(Immediate(Smi::FromInt(0))); | 3730 frame_->EmitPush(Immediate(Smi::FromInt(0))); |
| 3774 } | 3731 } |
| 3775 return; | 3732 return; |
| 3776 } | 3733 } |
| 3777 target.GetValue(NOT_INSIDE_TYPEOF); | 3734 target.GetValueAndSpill(NOT_INSIDE_TYPEOF); |
| 3778 frame_->SpillAll(); | |
| 3779 | 3735 |
| 3780 CountOperationDeferred* deferred = | 3736 CountOperationDeferred* deferred = |
| 3781 new CountOperationDeferred(this, is_postfix, is_increment, | 3737 new CountOperationDeferred(this, is_postfix, is_increment, |
| 3782 target.size() * kPointerSize); | 3738 target.size() * kPointerSize); |
| 3783 | 3739 |
| 3784 frame_->EmitPop(eax); // Load TOS into eax for calculations below | 3740 frame_->EmitPop(eax); // Load TOS into eax for calculations below |
| 3785 | 3741 |
| 3786 // Postfix: Store the old value as the result. | 3742 // Postfix: Store the old value as the result. |
| 3787 if (is_postfix) { | 3743 if (is_postfix) { |
| 3788 __ mov(frame_->ElementAt(target.size()), eax); | 3744 __ mov(frame_->ElementAt(target.size()), eax); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 3809 } | 3765 } |
| 3810 | 3766 |
| 3811 // Postfix: Discard the new value and use the old. | 3767 // Postfix: Discard the new value and use the old. |
| 3812 if (is_postfix) { | 3768 if (is_postfix) { |
| 3813 frame_->Drop(); | 3769 frame_->Drop(); |
| 3814 } | 3770 } |
| 3815 } | 3771 } |
| 3816 | 3772 |
| 3817 | 3773 |
| 3818 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 3774 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
| 3819 frame_->SpillAll(); | 3775 VirtualFrame::SpilledScope spilled_scope(this); |
| 3820 // Note that due to an optimization in comparison operations (typeof | 3776 // Note that due to an optimization in comparison operations (typeof |
| 3821 // compared to a string literal), we can evaluate a binary expression such | 3777 // compared to a string literal), we can evaluate a binary expression such |
| 3822 // as AND or OR and not leave a value on the frame or in the cc register. | 3778 // as AND or OR and not leave a value on the frame or in the cc register. |
| 3823 Comment cmnt(masm_, "[ BinaryOperation"); | 3779 Comment cmnt(masm_, "[ BinaryOperation"); |
| 3824 Token::Value op = node->op(); | 3780 Token::Value op = node->op(); |
| 3825 | 3781 |
| 3826 // According to ECMA-262 section 11.11, page 58, the binary logical | 3782 // According to ECMA-262 section 11.11, page 58, the binary logical |
| 3827 // operators must yield the result of one of the two expressions | 3783 // operators must yield the result of one of the two expressions |
| 3828 // before any ToBoolean() conversions. This means that the value | 3784 // before any ToBoolean() conversions. This means that the value |
| 3829 // produced by a && or || operator is not necessarily a boolean. | 3785 // produced by a && or || operator is not necessarily a boolean. |
| 3830 | 3786 |
| 3831 // NOTE: If the left hand side produces a materialized value (not in | 3787 // NOTE: If the left hand side produces a materialized value (not in |
| 3832 // the CC register), we force the right hand side to do the | 3788 // the CC register), we force the right hand side to do the |
| 3833 // same. This is necessary because we may have to branch to the exit | 3789 // same. This is necessary because we may have to branch to the exit |
| 3834 // after evaluating the left hand side (due to the shortcut | 3790 // after evaluating the left hand side (due to the shortcut |
| 3835 // semantics), but the compiler must (statically) know if the result | 3791 // semantics), but the compiler must (statically) know if the result |
| 3836 // of compiling the binary operation is materialized or not. | 3792 // of compiling the binary operation is materialized or not. |
| 3837 | 3793 |
| 3838 if (op == Token::AND) { | 3794 if (op == Token::AND) { |
| 3839 JumpTarget is_true(this); | 3795 JumpTarget is_true(this); |
| 3840 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &is_true, | 3796 LoadConditionAndSpill(node->left(), NOT_INSIDE_TYPEOF, |
| 3841 false_target(), false); | 3797 &is_true, false_target(), false); |
| 3842 if (has_cc() || frame_ == NULL) { | 3798 if (has_cc() || frame_ == NULL) { |
| 3843 if (has_cc()) { | 3799 if (has_cc()) { |
| 3844 ASSERT(frame_ != NULL); | 3800 ASSERT(frame_ != NULL); |
| 3845 Branch(false, false_target()); | 3801 Branch(false, false_target()); |
| 3846 } | 3802 } |
| 3847 | 3803 |
| 3848 if (frame_ != NULL || is_true.is_linked()) { | 3804 if (frame_ != NULL || is_true.is_linked()) { |
| 3849 // Evaluate right side expression. | 3805 // Evaluate right side expression. |
| 3850 is_true.Bind(); | 3806 is_true.Bind(); |
| 3851 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), | 3807 LoadConditionAndSpill(node->right(), NOT_INSIDE_TYPEOF, |
| 3852 false_target(), false); | 3808 true_target(), false_target(), false); |
| 3853 } | 3809 } |
| 3854 } else { | 3810 } else { |
| 3855 frame_->SpillAll(); | |
| 3856 // We have a materialized value on the frame. | 3811 // We have a materialized value on the frame. |
| 3857 JumpTarget pop_and_continue(this); | 3812 JumpTarget pop_and_continue(this); |
| 3858 JumpTarget exit(this); | 3813 JumpTarget exit(this); |
| 3859 | 3814 |
| 3860 // Avoid popping the result if it converts to 'false' using the | 3815 // Avoid popping the result if it converts to 'false' using the |
| 3861 // standard ToBoolean() conversion as described in ECMA-262, section | 3816 // standard ToBoolean() conversion as described in ECMA-262, section |
| 3862 // 9.2, page 30. | 3817 // 9.2, page 30. |
| 3863 // | 3818 // |
| 3864 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 3819 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 3865 __ mov(eax, frame_->Top()); | 3820 __ mov(eax, frame_->Top()); |
| 3866 frame_->EmitPush(eax); | 3821 frame_->EmitPush(eax); |
| 3867 ToBoolean(&pop_and_continue, &exit); | 3822 ToBoolean(&pop_and_continue, &exit); |
| 3868 Branch(false, &exit); | 3823 Branch(false, &exit); |
| 3869 | 3824 |
| 3870 // Pop the result of evaluating the first part. | 3825 // Pop the result of evaluating the first part. |
| 3871 pop_and_continue.Bind(); | 3826 pop_and_continue.Bind(); |
| 3872 frame_->Drop(); | 3827 frame_->Drop(); |
| 3873 | 3828 |
| 3874 // Evaluate right side expression. | 3829 // Evaluate right side expression. |
| 3875 is_true.Bind(); | 3830 is_true.Bind(); |
| 3876 Load(node->right()); | 3831 LoadAndSpill(node->right()); |
| 3877 frame_->SpillAll(); | |
| 3878 | 3832 |
| 3879 // Exit (always with a materialized value). | 3833 // Exit (always with a materialized value). |
| 3880 exit.Bind(); | 3834 exit.Bind(); |
| 3881 } | 3835 } |
| 3882 | 3836 |
| 3883 } else if (op == Token::OR) { | 3837 } else if (op == Token::OR) { |
| 3884 JumpTarget is_false(this); | 3838 JumpTarget is_false(this); |
| 3885 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(), | 3839 LoadConditionAndSpill(node->left(), NOT_INSIDE_TYPEOF, |
| 3886 &is_false, false); | 3840 true_target(), &is_false, false); |
| 3887 if (has_cc() || frame_ == NULL) { | 3841 if (has_cc() || frame_ == NULL) { |
| 3888 if (has_cc()) { | 3842 if (has_cc()) { |
| 3889 ASSERT(frame_ != NULL); | 3843 ASSERT(frame_ != NULL); |
| 3890 Branch(true, true_target()); | 3844 Branch(true, true_target()); |
| 3891 } | 3845 } |
| 3892 | 3846 |
| 3893 if (frame_ != NULL || is_false.is_linked()) { | 3847 if (frame_ != NULL || is_false.is_linked()) { |
| 3894 // Evaluate right side expression. | 3848 // Evaluate right side expression. |
| 3895 is_false.Bind(); | 3849 is_false.Bind(); |
| 3896 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), | 3850 LoadConditionAndSpill(node->right(), NOT_INSIDE_TYPEOF, |
| 3897 false_target(), false); | 3851 true_target(), false_target(), false); |
| 3898 } | 3852 } |
| 3899 | 3853 |
| 3900 } else { | 3854 } else { |
| 3901 frame_->SpillAll(); | |
| 3902 // We have a materialized value on the frame. | 3855 // We have a materialized value on the frame. |
| 3903 JumpTarget pop_and_continue(this); | 3856 JumpTarget pop_and_continue(this); |
| 3904 JumpTarget exit(this); | 3857 JumpTarget exit(this); |
| 3905 | 3858 |
| 3906 // Avoid popping the result if it converts to 'true' using the | 3859 // Avoid popping the result if it converts to 'true' using the |
| 3907 // standard ToBoolean() conversion as described in ECMA-262, | 3860 // standard ToBoolean() conversion as described in ECMA-262, |
| 3908 // section 9.2, page 30. | 3861 // section 9.2, page 30. |
| 3909 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 3862 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 3910 __ mov(eax, frame_->Top()); | 3863 __ mov(eax, frame_->Top()); |
| 3911 frame_->EmitPush(eax); | 3864 frame_->EmitPush(eax); |
| 3912 ToBoolean(&exit, &pop_and_continue); | 3865 ToBoolean(&exit, &pop_and_continue); |
| 3913 Branch(true, &exit); | 3866 Branch(true, &exit); |
| 3914 | 3867 |
| 3915 // Pop the result of evaluating the first part. | 3868 // Pop the result of evaluating the first part. |
| 3916 pop_and_continue.Bind(); | 3869 pop_and_continue.Bind(); |
| 3917 frame_->Drop(); | 3870 frame_->Drop(); |
| 3918 | 3871 |
| 3919 // Evaluate right side expression. | 3872 // Evaluate right side expression. |
| 3920 is_false.Bind(); | 3873 is_false.Bind(); |
| 3921 Load(node->right()); | 3874 LoadAndSpill(node->right()); |
| 3922 frame_->SpillAll(); | |
| 3923 | 3875 |
| 3924 // Exit (always with a materialized value). | 3876 // Exit (always with a materialized value). |
| 3925 exit.Bind(); | 3877 exit.Bind(); |
| 3926 } | 3878 } |
| 3927 | 3879 |
| 3928 } else { | 3880 } else { |
| 3929 // NOTE: The code below assumes that the slow cases (calls to runtime) | 3881 // NOTE: The code below assumes that the slow cases (calls to runtime) |
| 3930 // never return a constant/immutable object. | 3882 // never return a constant/immutable object. |
| 3931 OverwriteMode overwrite_mode = NO_OVERWRITE; | 3883 OverwriteMode overwrite_mode = NO_OVERWRITE; |
| 3932 if (node->left()->AsBinaryOperation() != NULL && | 3884 if (node->left()->AsBinaryOperation() != NULL && |
| 3933 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { | 3885 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { |
| 3934 overwrite_mode = OVERWRITE_LEFT; | 3886 overwrite_mode = OVERWRITE_LEFT; |
| 3935 } else if (node->right()->AsBinaryOperation() != NULL && | 3887 } else if (node->right()->AsBinaryOperation() != NULL && |
| 3936 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) { | 3888 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) { |
| 3937 overwrite_mode = OVERWRITE_RIGHT; | 3889 overwrite_mode = OVERWRITE_RIGHT; |
| 3938 } | 3890 } |
| 3939 | 3891 |
| 3940 // Optimize for the case where (at least) one of the expressions | 3892 // Optimize for the case where (at least) one of the expressions |
| 3941 // is a literal small integer. | 3893 // is a literal small integer. |
| 3942 Literal* lliteral = node->left()->AsLiteral(); | 3894 Literal* lliteral = node->left()->AsLiteral(); |
| 3943 Literal* rliteral = node->right()->AsLiteral(); | 3895 Literal* rliteral = node->right()->AsLiteral(); |
| 3944 | 3896 |
| 3945 if (IsInlineSmi(rliteral)) { | 3897 if (IsInlineSmi(rliteral)) { |
| 3946 Load(node->left()); | 3898 LoadAndSpill(node->left()); |
| 3947 frame_->SpillAll(); | |
| 3948 SmiOperation(node->op(), node->type(), rliteral->handle(), false, | 3899 SmiOperation(node->op(), node->type(), rliteral->handle(), false, |
| 3949 overwrite_mode); | 3900 overwrite_mode); |
| 3950 } else if (IsInlineSmi(lliteral)) { | 3901 } else if (IsInlineSmi(lliteral)) { |
| 3951 Load(node->right()); | 3902 LoadAndSpill(node->right()); |
| 3952 frame_->SpillAll(); | |
| 3953 SmiOperation(node->op(), node->type(), lliteral->handle(), true, | 3903 SmiOperation(node->op(), node->type(), lliteral->handle(), true, |
| 3954 overwrite_mode); | 3904 overwrite_mode); |
| 3955 } else { | 3905 } else { |
| 3956 Load(node->left()); | 3906 LoadAndSpill(node->left()); |
| 3957 frame_->SpillAll(); | 3907 LoadAndSpill(node->right()); |
| 3958 Load(node->right()); | |
| 3959 frame_->SpillAll(); | |
| 3960 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); | 3908 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); |
| 3961 } | 3909 } |
| 3962 } | 3910 } |
| 3963 } | 3911 } |
| 3964 | 3912 |
| 3965 | 3913 |
| 3966 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 3914 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 3967 frame_->SpillAll(); | 3915 VirtualFrame::SpilledScope spilled_scope(this); |
| 3968 frame_->EmitPush(frame_->Function()); | 3916 frame_->EmitPush(frame_->Function()); |
| 3969 } | 3917 } |
| 3970 | 3918 |
| 3971 | 3919 |
| 3972 class InstanceofStub: public CodeStub { | 3920 class InstanceofStub: public CodeStub { |
| 3973 public: | 3921 public: |
| 3974 InstanceofStub() { } | 3922 InstanceofStub() { } |
| 3975 | 3923 |
| 3976 void Generate(MacroAssembler* masm); | 3924 void Generate(MacroAssembler* masm); |
| 3977 | 3925 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3993 // literal 'null'. If so, we optimize the code by inlining a null check | 3941 // literal 'null'. If so, we optimize the code by inlining a null check |
| 3994 // instead of calling the (very) general runtime routine for checking | 3942 // instead of calling the (very) general runtime routine for checking |
| 3995 // equality. | 3943 // equality. |
| 3996 if (op == Token::EQ || op == Token::EQ_STRICT) { | 3944 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 3997 bool left_is_null = | 3945 bool left_is_null = |
| 3998 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); | 3946 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); |
| 3999 bool right_is_null = | 3947 bool right_is_null = |
| 4000 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); | 3948 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); |
| 4001 // The 'null' value can only be equal to 'null' or 'undefined'. | 3949 // The 'null' value can only be equal to 'null' or 'undefined'. |
| 4002 if (left_is_null || right_is_null) { | 3950 if (left_is_null || right_is_null) { |
| 4003 frame_->SpillAll(); | 3951 VirtualFrame::SpilledScope spilled_scope(this); |
| 4004 Load(left_is_null ? right : left); | 3952 LoadAndSpill(left_is_null ? right : left); |
| 4005 frame_->SpillAll(); | |
| 4006 frame_->EmitPop(eax); | 3953 frame_->EmitPop(eax); |
| 4007 __ cmp(eax, Factory::null_value()); | 3954 __ cmp(eax, Factory::null_value()); |
| 4008 | 3955 |
| 4009 // The 'null' value is only equal to 'undefined' if using non-strict | 3956 // The 'null' value is only equal to 'undefined' if using non-strict |
| 4010 // comparisons. | 3957 // comparisons. |
| 4011 if (op != Token::EQ_STRICT) { | 3958 if (op != Token::EQ_STRICT) { |
| 4012 true_target()->Branch(equal); | 3959 true_target()->Branch(equal); |
| 4013 | 3960 |
| 4014 __ cmp(eax, Factory::undefined_value()); | 3961 __ cmp(eax, Factory::undefined_value()); |
| 4015 true_target()->Branch(equal); | 3962 true_target()->Branch(equal); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 4032 // To make typeof testing for natives implemented in JavaScript really | 3979 // To make typeof testing for natives implemented in JavaScript really |
| 4033 // efficient, we generate special code for expressions of the form: | 3980 // efficient, we generate special code for expressions of the form: |
| 4034 // 'typeof <expression> == <string>'. | 3981 // 'typeof <expression> == <string>'. |
| 4035 UnaryOperation* operation = left->AsUnaryOperation(); | 3982 UnaryOperation* operation = left->AsUnaryOperation(); |
| 4036 if ((op == Token::EQ || op == Token::EQ_STRICT) && | 3983 if ((op == Token::EQ || op == Token::EQ_STRICT) && |
| 4037 (operation != NULL && operation->op() == Token::TYPEOF) && | 3984 (operation != NULL && operation->op() == Token::TYPEOF) && |
| 4038 (right->AsLiteral() != NULL && | 3985 (right->AsLiteral() != NULL && |
| 4039 right->AsLiteral()->handle()->IsString())) { | 3986 right->AsLiteral()->handle()->IsString())) { |
| 4040 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 3987 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 4041 | 3988 |
| 4042 frame_->SpillAll(); | 3989 VirtualFrame::SpilledScope spilled_scope(this); |
| 4043 // Load the operand and move it to register edx. | 3990 // Load the operand and move it to register edx. |
| 4044 LoadTypeofExpression(operation->expression()); | 3991 LoadTypeofExpression(operation->expression()); |
| 4045 frame_->SpillAll(); | |
| 4046 frame_->EmitPop(edx); | 3992 frame_->EmitPop(edx); |
| 4047 | 3993 |
| 4048 if (check->Equals(Heap::number_symbol())) { | 3994 if (check->Equals(Heap::number_symbol())) { |
| 4049 __ test(edx, Immediate(kSmiTagMask)); | 3995 __ test(edx, Immediate(kSmiTagMask)); |
| 4050 true_target()->Branch(zero); | 3996 true_target()->Branch(zero); |
| 4051 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3997 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 4052 __ cmp(edx, Factory::heap_number_map()); | 3998 __ cmp(edx, Factory::heap_number_map()); |
| 4053 cc_reg_ = equal; | 3999 cc_reg_ = equal; |
| 4054 | 4000 |
| 4055 } else if (check->Equals(Heap::string_symbol())) { | 4001 } else if (check->Equals(Heap::string_symbol())) { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4142 case Token::GT: | 4088 case Token::GT: |
| 4143 cc = greater; | 4089 cc = greater; |
| 4144 break; | 4090 break; |
| 4145 case Token::LTE: | 4091 case Token::LTE: |
| 4146 cc = less_equal; | 4092 cc = less_equal; |
| 4147 break; | 4093 break; |
| 4148 case Token::GTE: | 4094 case Token::GTE: |
| 4149 cc = greater_equal; | 4095 cc = greater_equal; |
| 4150 break; | 4096 break; |
| 4151 case Token::IN: { | 4097 case Token::IN: { |
| 4152 frame_->SpillAll(); | 4098 VirtualFrame::SpilledScope spilled_scope(this); |
| 4153 Load(left); | 4099 LoadAndSpill(left); |
| 4154 frame_->SpillAll(); | 4100 LoadAndSpill(right); |
| 4155 Load(right); | |
| 4156 frame_->SpillAll(); | |
| 4157 frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2); | 4101 frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2); |
| 4158 frame_->EmitPush(eax); // push the result | 4102 frame_->EmitPush(eax); // push the result |
| 4159 return; | 4103 return; |
| 4160 } | 4104 } |
| 4161 case Token::INSTANCEOF: { | 4105 case Token::INSTANCEOF: { |
| 4162 frame_->SpillAll(); | 4106 VirtualFrame::SpilledScope spilled_scope(this); |
| 4163 Load(left); | 4107 LoadAndSpill(left); |
| 4164 frame_->SpillAll(); | 4108 LoadAndSpill(right); |
| 4165 Load(right); | |
| 4166 frame_->SpillAll(); | |
| 4167 InstanceofStub stub; | 4109 InstanceofStub stub; |
| 4168 frame_->CallStub(&stub, 2); | 4110 frame_->CallStub(&stub, 2); |
| 4169 __ test(eax, Operand(eax)); | 4111 __ test(eax, Operand(eax)); |
| 4170 cc_reg_ = zero; | 4112 cc_reg_ = zero; |
| 4171 return; | 4113 return; |
| 4172 } | 4114 } |
| 4173 default: | 4115 default: |
| 4174 UNREACHABLE(); | 4116 UNREACHABLE(); |
| 4175 } | 4117 } |
| 4176 | 4118 |
| 4177 // Optimize for the case where (at least) one of the expressions | 4119 // Optimize for the case where (at least) one of the expressions |
| 4178 // is a literal small integer. | 4120 // is a literal small integer. |
| 4179 if (IsInlineSmi(left->AsLiteral())) { | 4121 if (IsInlineSmi(left->AsLiteral())) { |
| 4180 frame_->SpillAll(); | |
| 4181 Load(right); | 4122 Load(right); |
| 4182 frame_->SpillAll(); | |
| 4183 SmiComparison(ReverseCondition(cc), left->AsLiteral()->handle(), strict); | 4123 SmiComparison(ReverseCondition(cc), left->AsLiteral()->handle(), strict); |
| 4184 return; | 4124 return; |
| 4185 } | 4125 } |
| 4186 if (IsInlineSmi(right->AsLiteral())) { | 4126 if (IsInlineSmi(right->AsLiteral())) { |
| 4187 Load(left); | 4127 Load(left); |
| 4188 SmiComparison(cc, right->AsLiteral()->handle(), strict); | 4128 SmiComparison(cc, right->AsLiteral()->handle(), strict); |
| 4189 return; | 4129 return; |
| 4190 } | 4130 } |
| 4191 | 4131 |
| 4192 frame_->SpillAll(); | 4132 VirtualFrame::SpilledScope spilled_scope(this); |
| 4193 Load(left); | 4133 LoadAndSpill(left); |
| 4194 frame_->SpillAll(); | 4134 LoadAndSpill(right); |
| 4195 Load(right); | |
| 4196 frame_->SpillAll(); | |
| 4197 Comparison(cc, strict); | 4135 Comparison(cc, strict); |
| 4198 } | 4136 } |
| 4199 | 4137 |
| 4200 | 4138 |
| 4201 void CodeGenerator::RecordStatementPosition(Node* node) { | 4139 void CodeGenerator::RecordStatementPosition(Node* node) { |
| 4202 if (FLAG_debug_info) { | 4140 if (FLAG_debug_info) { |
| 4203 int pos = node->statement_pos(); | 4141 int pos = node->statement_pos(); |
| 4204 if (pos != RelocInfo::kNoPosition) { | 4142 if (pos != RelocInfo::kNoPosition) { |
| 4205 __ RecordStatementPosition(pos); | 4143 __ RecordStatementPosition(pos); |
| 4206 } | 4144 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 4229 MacroAssembler* masm = cgen_->masm(); | 4167 MacroAssembler* masm = cgen_->masm(); |
| 4230 __ RecordPosition(property->position()); | 4168 __ RecordPosition(property->position()); |
| 4231 Literal* raw_name = property->key()->AsLiteral(); | 4169 Literal* raw_name = property->key()->AsLiteral(); |
| 4232 ASSERT(raw_name != NULL); | 4170 ASSERT(raw_name != NULL); |
| 4233 return Handle<String>(String::cast(*raw_name->handle())); | 4171 return Handle<String>(String::cast(*raw_name->handle())); |
| 4234 } | 4172 } |
| 4235 } | 4173 } |
| 4236 | 4174 |
| 4237 | 4175 |
| 4238 void Reference::GetValue(TypeofState typeof_state) { | 4176 void Reference::GetValue(TypeofState typeof_state) { |
| 4177 ASSERT(!cgen_->in_spilled_code()); |
| 4239 ASSERT(!is_illegal()); | 4178 ASSERT(!is_illegal()); |
| 4240 ASSERT(!cgen_->has_cc()); | 4179 ASSERT(!cgen_->has_cc()); |
| 4241 MacroAssembler* masm = cgen_->masm(); | 4180 MacroAssembler* masm = cgen_->masm(); |
| 4242 VirtualFrame* frame = cgen_->frame(); | 4181 VirtualFrame* frame = cgen_->frame(); |
| 4243 switch (type_) { | 4182 switch (type_) { |
| 4244 case SLOT: { | 4183 case SLOT: { |
| 4245 Comment cmnt(masm, "[ Load from Slot"); | 4184 Comment cmnt(masm, "[ Load from Slot"); |
| 4246 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 4185 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
| 4247 ASSERT(slot != NULL); | 4186 ASSERT(slot != NULL); |
| 4248 cgen_->LoadFromSlot(slot, typeof_state); | 4187 cgen_->LoadFromSlot(slot, typeof_state); |
| 4249 break; | 4188 break; |
| 4250 } | 4189 } |
| 4251 | 4190 |
| 4252 case NAMED: { | 4191 case NAMED: { |
| 4253 // TODO(1241834): Make sure that this it is safe to ignore the | 4192 // TODO(1241834): Make sure that this it is safe to ignore the |
| 4254 // distinction between expressions in a typeof and not in a typeof. If | 4193 // distinction between expressions in a typeof and not in a typeof. If |
| 4255 // there is a chance that reference errors can be thrown below, we | 4194 // there is a chance that reference errors can be thrown below, we |
| 4256 // must distinguish between the two kinds of loads (typeof expression | 4195 // must distinguish between the two kinds of loads (typeof expression |
| 4257 // loads must not throw a reference error). | 4196 // loads must not throw a reference error). |
| 4258 frame->SpillAll(); | 4197 VirtualFrame::SpilledScope spilled_scope(cgen_); |
| 4259 Comment cmnt(masm, "[ Load from named Property"); | 4198 Comment cmnt(masm, "[ Load from named Property"); |
| 4260 Handle<String> name(GetName()); | 4199 Handle<String> name(GetName()); |
| 4261 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 4200 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 4262 // Setup the name register. | 4201 // Setup the name register. |
| 4263 __ mov(ecx, name); | 4202 __ mov(ecx, name); |
| 4264 | 4203 |
| 4265 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 4204 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 4266 if (var != NULL) { | 4205 if (var != NULL) { |
| 4267 ASSERT(var->is_global()); | 4206 ASSERT(var->is_global()); |
| 4268 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); | 4207 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
| 4269 } else { | 4208 } else { |
| 4270 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4209 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4271 } | 4210 } |
| 4272 frame->EmitPush(eax); // IC call leaves result in eax, push it out | 4211 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| 4273 break; | 4212 break; |
| 4274 } | 4213 } |
| 4275 | 4214 |
| 4276 case KEYED: { | 4215 case KEYED: { |
| 4277 // TODO(1241834): Make sure that this it is safe to ignore the | 4216 // TODO(1241834): Make sure that this it is safe to ignore the |
| 4278 // distinction between expressions in a typeof and not in a typeof. | 4217 // distinction between expressions in a typeof and not in a typeof. |
| 4279 frame->SpillAll(); | 4218 VirtualFrame::SpilledScope spilled_scope(cgen_); |
| 4280 Comment cmnt(masm, "[ Load from keyed Property"); | 4219 Comment cmnt(masm, "[ Load from keyed Property"); |
| 4281 Property* property = expression_->AsProperty(); | 4220 Property* property = expression_->AsProperty(); |
| 4282 ASSERT(property != NULL); | 4221 ASSERT(property != NULL); |
| 4283 __ RecordPosition(property->position()); | 4222 __ RecordPosition(property->position()); |
| 4284 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 4223 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 4285 | 4224 |
| 4286 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 4225 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 4287 if (var != NULL) { | 4226 if (var != NULL) { |
| 4288 ASSERT(var->is_global()); | 4227 ASSERT(var->is_global()); |
| 4289 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); | 4228 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 4308 switch (type_) { | 4247 switch (type_) { |
| 4309 case SLOT: { | 4248 case SLOT: { |
| 4310 Comment cmnt(masm, "[ Store to Slot"); | 4249 Comment cmnt(masm, "[ Store to Slot"); |
| 4311 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 4250 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
| 4312 ASSERT(slot != NULL); | 4251 ASSERT(slot != NULL); |
| 4313 cgen_->StoreToSlot(slot, init_state); | 4252 cgen_->StoreToSlot(slot, init_state); |
| 4314 break; | 4253 break; |
| 4315 } | 4254 } |
| 4316 | 4255 |
| 4317 case NAMED: { | 4256 case NAMED: { |
| 4318 frame->SpillAll(); | 4257 VirtualFrame::SpilledScope spilled_scope(cgen_); |
| 4319 Comment cmnt(masm, "[ Store to named Property"); | 4258 Comment cmnt(masm, "[ Store to named Property"); |
| 4320 // Call the appropriate IC code. | 4259 // Call the appropriate IC code. |
| 4321 Handle<String> name(GetName()); | 4260 Handle<String> name(GetName()); |
| 4322 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 4261 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 4323 // TODO(1222589): Make the IC grab the values from the stack. | 4262 // TODO(1222589): Make the IC grab the values from the stack. |
| 4324 frame->EmitPop(eax); | 4263 frame->EmitPop(eax); |
| 4325 // Setup the name register. | 4264 // Setup the name register. |
| 4326 __ mov(ecx, name); | 4265 __ mov(ecx, name); |
| 4327 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4266 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4328 frame->EmitPush(eax); // IC call leaves result in eax, push it out | 4267 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| 4329 break; | 4268 break; |
| 4330 } | 4269 } |
| 4331 | 4270 |
| 4332 case KEYED: { | 4271 case KEYED: { |
| 4333 frame->SpillAll(); | 4272 VirtualFrame::SpilledScope spilled_scope(cgen_); |
| 4334 Comment cmnt(masm, "[ Store to keyed Property"); | 4273 Comment cmnt(masm, "[ Store to keyed Property"); |
| 4335 Property* property = expression_->AsProperty(); | 4274 Property* property = expression_->AsProperty(); |
| 4336 ASSERT(property != NULL); | 4275 ASSERT(property != NULL); |
| 4337 __ RecordPosition(property->position()); | 4276 __ RecordPosition(property->position()); |
| 4338 // Call IC code. | 4277 // Call IC code. |
| 4339 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 4278 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 4340 // TODO(1222589): Make the IC grab the values from the stack. | 4279 // TODO(1222589): Make the IC grab the values from the stack. |
| 4341 frame->EmitPop(eax); | 4280 frame->EmitPop(eax); |
| 4342 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4281 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4343 frame->EmitPush(eax); // IC call leaves result in eax, push it out | 4282 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| (...skipping 1380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5724 | 5663 |
| 5725 // Slow-case: Go through the JavaScript implementation. | 5664 // Slow-case: Go through the JavaScript implementation. |
| 5726 __ bind(&slow); | 5665 __ bind(&slow); |
| 5727 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5666 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5728 } | 5667 } |
| 5729 | 5668 |
| 5730 | 5669 |
| 5731 #undef __ | 5670 #undef __ |
| 5732 | 5671 |
| 5733 } } // namespace v8::internal | 5672 } } // namespace v8::internal |
| OLD | NEW |