OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 5351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5362 int original_height = frame()->height(); | 5362 int original_height = frame()->height(); |
5363 #endif | 5363 #endif |
5364 Comment cmnt(masm(), "[ Variable Assignment"); | 5364 Comment cmnt(masm(), "[ Variable Assignment"); |
5365 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 5365 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
5366 ASSERT(var != NULL); | 5366 ASSERT(var != NULL); |
5367 Slot* slot = var->slot(); | 5367 Slot* slot = var->slot(); |
5368 ASSERT(slot != NULL); | 5368 ASSERT(slot != NULL); |
5369 | 5369 |
5370 // Evaluate the right-hand side. | 5370 // Evaluate the right-hand side. |
5371 if (node->is_compound()) { | 5371 if (node->is_compound()) { |
| 5372 // For a compound assignment the right-hand side is a binary operation |
| 5373 // between the current property value and the actual right-hand side. |
5372 Result result = LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF); | 5374 Result result = LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF); |
5373 frame()->Push(&result); | 5375 frame()->Push(&result); |
5374 Load(node->value()); | 5376 Load(node->value()); |
5375 | 5377 |
| 5378 // Perform the binary operation. |
5376 bool overwrite_value = | 5379 bool overwrite_value = |
5377 (node->value()->AsBinaryOperation() != NULL && | 5380 (node->value()->AsBinaryOperation() != NULL && |
5378 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 5381 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
5379 // Construct the implicit binary operation. | 5382 // Construct the implicit binary operation. |
5380 BinaryOperation expr(node, node->binary_op(), node->target(), | 5383 BinaryOperation expr(node, node->binary_op(), node->target(), |
5381 node->value()); | 5384 node->value()); |
5382 GenericBinaryOperation(&expr, | 5385 GenericBinaryOperation(&expr, |
5383 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 5386 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
5384 } else { | 5387 } else { |
| 5388 // For non-compound assignment just load the right-hand side. |
5385 Load(node->value()); | 5389 Load(node->value()); |
5386 } | 5390 } |
5387 | 5391 |
5388 // Perform the assignment. | 5392 // Perform the assignment. |
5389 if (var->mode() != Variable::CONST || node->op() == Token::INIT_CONST) { | 5393 if (var->mode() != Variable::CONST || node->op() == Token::INIT_CONST) { |
5390 CodeForSourcePosition(node->position()); | 5394 CodeForSourcePosition(node->position()); |
5391 StoreToSlot(slot, | 5395 StoreToSlot(slot, |
5392 node->op() == Token::INIT_CONST ? CONST_INIT : NOT_CONST_INIT); | 5396 node->op() == Token::INIT_CONST ? CONST_INIT : NOT_CONST_INIT); |
5393 } | 5397 } |
5394 ASSERT(frame()->height() == original_height + 1); | 5398 ASSERT(frame()->height() == original_height + 1); |
5395 } | 5399 } |
5396 | 5400 |
5397 | 5401 |
5398 void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { | 5402 void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { |
5399 #ifdef DEBUG | 5403 #ifdef DEBUG |
5400 int original_height = frame()->height(); | 5404 int original_height = frame()->height(); |
5401 #endif | 5405 #endif |
5402 Comment cmnt(masm(), "[ Named Property Assignment"); | 5406 Comment cmnt(masm(), "[ Named Property Assignment"); |
5403 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 5407 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
5404 Property* prop = node->target()->AsProperty(); | 5408 Property* prop = node->target()->AsProperty(); |
5405 ASSERT(var == NULL || (prop == NULL && var->is_global())); | 5409 ASSERT(var == NULL || (prop == NULL && var->is_global())); |
5406 | 5410 |
5407 // Initialize name and evaluate the receiver subexpression if necessary. | 5411 // Initialize name and evaluate the receiver sub-expression if necessary. If |
| 5412 // the receiver is trivial it is not placed on the stack at this point, but |
| 5413 // loaded whenever actually needed. |
5408 Handle<String> name; | 5414 Handle<String> name; |
5409 bool is_trivial_receiver = false; | 5415 bool is_trivial_receiver = false; |
5410 if (var != NULL) { | 5416 if (var != NULL) { |
5411 name = var->name(); | 5417 name = var->name(); |
5412 } else { | 5418 } else { |
5413 Literal* lit = prop->key()->AsLiteral(); | 5419 Literal* lit = prop->key()->AsLiteral(); |
5414 ASSERT_NOT_NULL(lit); | 5420 ASSERT_NOT_NULL(lit); |
5415 name = Handle<String>::cast(lit->handle()); | 5421 name = Handle<String>::cast(lit->handle()); |
5416 // Do not materialize the receiver on the frame if it is trivial. | 5422 // Do not materialize the receiver on the frame if it is trivial. |
5417 is_trivial_receiver = prop->obj()->IsTrivial(); | 5423 is_trivial_receiver = prop->obj()->IsTrivial(); |
5418 if (!is_trivial_receiver) Load(prop->obj()); | 5424 if (!is_trivial_receiver) Load(prop->obj()); |
5419 } | 5425 } |
5420 | 5426 |
| 5427 // Change to slow case in the beginning of an initialization block to |
| 5428 // avoid the quadratic behavior of repeatedly adding fast properties. |
5421 if (node->starts_initialization_block()) { | 5429 if (node->starts_initialization_block()) { |
| 5430 // Initialization block consists of assignments of the form expr.x = ..., so |
| 5431 // this will never be an assignment to a variable, so there must be a |
| 5432 // receiver object. |
5422 ASSERT_EQ(NULL, var); | 5433 ASSERT_EQ(NULL, var); |
5423 // Change to slow case in the beginning of an initialization block to | |
5424 // avoid the quadratic behavior of repeatedly adding fast properties. | |
5425 if (is_trivial_receiver) { | 5434 if (is_trivial_receiver) { |
5426 frame()->Push(prop->obj()); | 5435 frame()->Push(prop->obj()); |
5427 } else { | 5436 } else { |
5428 frame()->Dup(); | 5437 frame()->Dup(); |
5429 } | 5438 } |
5430 Result ignored = frame()->CallRuntime(Runtime::kToSlowProperties, 1); | 5439 Result ignored = frame()->CallRuntime(Runtime::kToSlowProperties, 1); |
5431 } | 5440 } |
5432 | 5441 |
| 5442 // Change to fast case at the end of an initialization block. To prepare for |
| 5443 // that add an extra copy of the receiver to the frame, so that it can be |
| 5444 // converted back to fast case after the assignment. |
5433 if (node->ends_initialization_block() && !is_trivial_receiver) { | 5445 if (node->ends_initialization_block() && !is_trivial_receiver) { |
5434 // Add an extra copy of the receiver to the frame, so that it can be | |
5435 // converted back to fast case after the assignment. | |
5436 frame()->Dup(); | 5446 frame()->Dup(); |
5437 } | 5447 } |
5438 | 5448 |
| 5449 // Stack layout: |
| 5450 // [tos] : receiver (only materialized if non-trivial) |
| 5451 // [tos+1] : receiver if at the end of an initialization block |
| 5452 |
5439 // Evaluate the right-hand side. | 5453 // Evaluate the right-hand side. |
5440 if (node->is_compound()) { | 5454 if (node->is_compound()) { |
| 5455 // For a compound assignment the right-hand side is a binary operation |
| 5456 // between the current property value and the actual right-hand side. |
5441 if (is_trivial_receiver) { | 5457 if (is_trivial_receiver) { |
5442 frame()->Push(prop->obj()); | 5458 frame()->Push(prop->obj()); |
5443 } else if (var != NULL) { | 5459 } else if (var != NULL) { |
5444 // The LoadIC stub expects the object in eax. | 5460 // The LoadIC stub expects the object in eax. |
5445 // Freeing eax causes the code generator to load the global into it. | 5461 // Freeing eax causes the code generator to load the global into it. |
5446 frame_->Spill(eax); | 5462 frame_->Spill(eax); |
5447 LoadGlobal(); | 5463 LoadGlobal(); |
5448 } else { | 5464 } else { |
5449 frame()->Dup(); | 5465 frame()->Dup(); |
5450 } | 5466 } |
5451 Result value = EmitNamedLoad(name, var != NULL); | 5467 Result value = EmitNamedLoad(name, var != NULL); |
5452 frame()->Push(&value); | 5468 frame()->Push(&value); |
5453 Load(node->value()); | 5469 Load(node->value()); |
5454 | 5470 |
5455 bool overwrite_value = | 5471 bool overwrite_value = |
5456 (node->value()->AsBinaryOperation() != NULL && | 5472 (node->value()->AsBinaryOperation() != NULL && |
5457 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 5473 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
5458 // Construct the implicit binary operation. | 5474 // Construct the implicit binary operation. |
5459 BinaryOperation expr(node, node->binary_op(), node->target(), | 5475 BinaryOperation expr(node, node->binary_op(), node->target(), |
5460 node->value()); | 5476 node->value()); |
5461 GenericBinaryOperation(&expr, | 5477 GenericBinaryOperation(&expr, |
5462 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 5478 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
5463 } else { | 5479 } else { |
| 5480 // For non-compound assignment just load the right-hand side. |
5464 Load(node->value()); | 5481 Load(node->value()); |
5465 } | 5482 } |
5466 | 5483 |
| 5484 // Stack layout: |
| 5485 // [tos] : value |
| 5486 // [tos+1] : receiver (only materialized if non-trivial) |
| 5487 // [tos+2] : receiver if at the end of an initialization block |
| 5488 |
5467 // Perform the assignment. It is safe to ignore constants here. | 5489 // Perform the assignment. It is safe to ignore constants here. |
5468 ASSERT(var == NULL || var->mode() != Variable::CONST); | 5490 ASSERT(var == NULL || var->mode() != Variable::CONST); |
5469 ASSERT_NE(Token::INIT_CONST, node->op()); | 5491 ASSERT_NE(Token::INIT_CONST, node->op()); |
5470 if (is_trivial_receiver) { | 5492 if (is_trivial_receiver) { |
5471 Result value = frame()->Pop(); | 5493 Result value = frame()->Pop(); |
5472 frame()->Push(prop->obj()); | 5494 frame()->Push(prop->obj()); |
5473 frame()->Push(&value); | 5495 frame()->Push(&value); |
5474 } | 5496 } |
5475 CodeForSourcePosition(node->position()); | 5497 CodeForSourcePosition(node->position()); |
5476 bool is_contextual = (var != NULL); | 5498 bool is_contextual = (var != NULL); |
5477 Result answer = EmitNamedStore(name, is_contextual); | 5499 Result answer = EmitNamedStore(name, is_contextual); |
5478 frame()->Push(&answer); | 5500 frame()->Push(&answer); |
5479 | 5501 |
| 5502 // Stack layout: |
| 5503 // [tos] : result |
| 5504 // [tos+1] : receiver if at the end of an initialization block |
| 5505 |
5480 if (node->ends_initialization_block()) { | 5506 if (node->ends_initialization_block()) { |
5481 ASSERT_EQ(NULL, var); | 5507 ASSERT_EQ(NULL, var); |
5482 // The argument to the runtime call is the receiver. | 5508 // The argument to the runtime call is the receiver. |
5483 if (is_trivial_receiver) { | 5509 if (is_trivial_receiver) { |
5484 frame()->Push(prop->obj()); | 5510 frame()->Push(prop->obj()); |
5485 } else { | 5511 } else { |
5486 // A copy of the receiver is below the value of the assignment. Swap | 5512 // A copy of the receiver is below the value of the assignment. Swap |
5487 // the receiver and the value of the assignment expression. | 5513 // the receiver and the value of the assignment expression. |
5488 Result result = frame()->Pop(); | 5514 Result result = frame()->Pop(); |
5489 Result receiver = frame()->Pop(); | 5515 Result receiver = frame()->Pop(); |
5490 frame()->Push(&result); | 5516 frame()->Push(&result); |
5491 frame()->Push(&receiver); | 5517 frame()->Push(&receiver); |
5492 } | 5518 } |
5493 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); | 5519 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
5494 } | 5520 } |
5495 | 5521 |
| 5522 // Stack layout: |
| 5523 // [tos] : result |
| 5524 |
5496 ASSERT_EQ(frame()->height(), original_height + 1); | 5525 ASSERT_EQ(frame()->height(), original_height + 1); |
5497 } | 5526 } |
5498 | 5527 |
5499 | 5528 |
5500 void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) { | 5529 void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) { |
5501 #ifdef DEBUG | 5530 #ifdef DEBUG |
5502 int original_height = frame()->height(); | 5531 int original_height = frame()->height(); |
5503 #endif | 5532 #endif |
5504 Comment cmnt(masm_, "[ Named Property Assignment"); | 5533 Comment cmnt(masm_, "[ Keyed Property Assignment"); |
5505 Property* prop = node->target()->AsProperty(); | 5534 Property* prop = node->target()->AsProperty(); |
5506 ASSERT_NOT_NULL(prop); | 5535 ASSERT_NOT_NULL(prop); |
5507 | 5536 |
5508 // Evaluate the receiver subexpression. | 5537 // Evaluate the receiver subexpression. |
5509 Load(prop->obj()); | 5538 Load(prop->obj()); |
5510 | 5539 |
| 5540 // Change to slow case in the beginning of an initialization block to |
| 5541 // avoid the quadratic behavior of repeatedly adding fast properties. |
5511 if (node->starts_initialization_block()) { | 5542 if (node->starts_initialization_block()) { |
5512 // Change to slow case in the beginning of an initialization block to | |
5513 // avoid the quadratic behavior of repeatedly adding fast properties. | |
5514 frame_->Dup(); | 5543 frame_->Dup(); |
5515 Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); | 5544 Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); |
5516 } | 5545 } |
5517 | 5546 |
| 5547 // Change to fast case at the end of an initialization block. To prepare for |
| 5548 // that add an extra copy of the receiver to the frame, so that it can be |
| 5549 // converted back to fast case after the assignment. |
5518 if (node->ends_initialization_block()) { | 5550 if (node->ends_initialization_block()) { |
5519 // Add an extra copy of the receiver to the frame, so that it can be | |
5520 // converted back to fast case after the assignment. | |
5521 frame_->Dup(); | 5551 frame_->Dup(); |
5522 } | 5552 } |
5523 | 5553 |
5524 // Evaluate the key subexpression. | 5554 // Evaluate the key subexpression. |
5525 Load(prop->key()); | 5555 Load(prop->key()); |
5526 | 5556 |
| 5557 // Stack layout: |
| 5558 // [tos] : key |
| 5559 // [tos+1] : receiver |
| 5560 // [tos+2] : receiver if at the end of an initialization block |
| 5561 |
5527 // Evaluate the right-hand side. | 5562 // Evaluate the right-hand side. |
5528 if (node->is_compound()) { | 5563 if (node->is_compound()) { |
5529 // Duplicate receiver and key. | 5564 // For a compound assignment the right-hand side is a binary operation |
| 5565 // between the current property value and the actual right-hand side. |
| 5566 // Duplicate receiver and key for loading the current property value. |
5530 frame()->PushElementAt(1); | 5567 frame()->PushElementAt(1); |
5531 frame()->PushElementAt(1); | 5568 frame()->PushElementAt(1); |
5532 Result value = EmitKeyedLoad(); | 5569 Result value = EmitKeyedLoad(); |
5533 frame()->Push(&value); | 5570 frame()->Push(&value); |
5534 Load(node->value()); | 5571 Load(node->value()); |
5535 | 5572 |
| 5573 // Perform the binary operation. |
5536 bool overwrite_value = | 5574 bool overwrite_value = |
5537 (node->value()->AsBinaryOperation() != NULL && | 5575 (node->value()->AsBinaryOperation() != NULL && |
5538 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 5576 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
5539 BinaryOperation expr(node, node->binary_op(), node->target(), | 5577 BinaryOperation expr(node, node->binary_op(), node->target(), |
5540 node->value()); | 5578 node->value()); |
5541 GenericBinaryOperation(&expr, | 5579 GenericBinaryOperation(&expr, |
5542 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 5580 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
5543 } else { | 5581 } else { |
| 5582 // For non-compound assignment just load the right-hand side. |
5544 Load(node->value()); | 5583 Load(node->value()); |
5545 } | 5584 } |
5546 | 5585 |
| 5586 // Stack layout: |
| 5587 // [tos] : value |
| 5588 // [tos+1] : key |
| 5589 // [tos+2] : receiver |
| 5590 // [tos+3] : receiver if at the end of an initialization block |
| 5591 |
5547 // Perform the assignment. It is safe to ignore constants here. | 5592 // Perform the assignment. It is safe to ignore constants here. |
5548 ASSERT(node->op() != Token::INIT_CONST); | 5593 ASSERT(node->op() != Token::INIT_CONST); |
5549 CodeForSourcePosition(node->position()); | 5594 CodeForSourcePosition(node->position()); |
5550 Result answer = EmitKeyedStore(prop->key()->type()); | 5595 Result answer = EmitKeyedStore(prop->key()->type()); |
5551 frame()->Push(&answer); | 5596 frame()->Push(&answer); |
5552 | 5597 |
| 5598 // Stack layout: |
| 5599 // [tos] : result |
| 5600 // [tos+1] : receiver if at the end of an initialization block |
| 5601 |
| 5602 // Change to fast case at the end of an initialization block. |
5553 if (node->ends_initialization_block()) { | 5603 if (node->ends_initialization_block()) { |
5554 // The argument to the runtime call is the extra copy of the receiver, | 5604 // The argument to the runtime call is the extra copy of the receiver, |
5555 // which is below the value of the assignment. Swap the receiver and | 5605 // which is below the value of the assignment. Swap the receiver and |
5556 // the value of the assignment expression. | 5606 // the value of the assignment expression. |
5557 Result result = frame()->Pop(); | 5607 Result result = frame()->Pop(); |
5558 Result receiver = frame()->Pop(); | 5608 Result receiver = frame()->Pop(); |
5559 frame()->Push(&result); | 5609 frame()->Push(&result); |
5560 frame()->Push(&receiver); | 5610 frame()->Push(&receiver); |
5561 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); | 5611 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
5562 } | 5612 } |
5563 | 5613 |
| 5614 // Stack layout: |
| 5615 // [tos] : result |
| 5616 |
5564 ASSERT(frame()->height() == original_height + 1); | 5617 ASSERT(frame()->height() == original_height + 1); |
5565 } | 5618 } |
5566 | 5619 |
5567 | 5620 |
5568 void CodeGenerator::VisitAssignment(Assignment* node) { | 5621 void CodeGenerator::VisitAssignment(Assignment* node) { |
5569 ASSERT(!in_safe_int32_mode()); | 5622 ASSERT(!in_safe_int32_mode()); |
5570 #ifdef DEBUG | 5623 #ifdef DEBUG |
5571 int original_height = frame()->height(); | 5624 int original_height = frame()->height(); |
5572 #endif | 5625 #endif |
5573 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 5626 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
(...skipping 7490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13064 | 13117 |
13065 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 13118 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
13066 // tagged as a small integer. | 13119 // tagged as a small integer. |
13067 __ bind(&runtime); | 13120 __ bind(&runtime); |
13068 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 13121 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
13069 } | 13122 } |
13070 | 13123 |
13071 #undef __ | 13124 #undef __ |
13072 | 13125 |
13073 } } // namespace v8::internal | 13126 } } // namespace v8::internal |
OLD | NEW |