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 4947 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4958 // assign the exception value to the catch variable. | 4958 // assign the exception value to the catch variable. |
4959 Comment cmnt(masm_, "[ CatchExtensionObject"); | 4959 Comment cmnt(masm_, "[ CatchExtensionObject"); |
4960 Load(node->key()); | 4960 Load(node->key()); |
4961 Load(node->value()); | 4961 Load(node->value()); |
4962 Result result = | 4962 Result result = |
4963 frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2); | 4963 frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2); |
4964 frame_->Push(&result); | 4964 frame_->Push(&result); |
4965 } | 4965 } |
4966 | 4966 |
4967 | 4967 |
| 4968 void CodeGenerator::EmitSlotAssignment(Assignment* node) { |
| 4969 #ifdef DEBUG |
| 4970 int original_height = frame()->height(); |
| 4971 #endif |
| 4972 Comment cmnt(masm(), "[ Variable Assignment"); |
| 4973 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
| 4974 ASSERT(var != NULL); |
| 4975 Slot* slot = var->slot(); |
| 4976 ASSERT(slot != NULL); |
| 4977 |
| 4978 // Evaluate the right-hand side. |
| 4979 if (node->is_compound()) { |
| 4980 // For a compound assignment the right-hand side is a binary operation |
| 4981 // between the current property value and the actual right-hand side. |
| 4982 LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF); |
| 4983 Load(node->value()); |
| 4984 |
| 4985 // Perform the binary operation. |
| 4986 bool overwrite_value = |
| 4987 (node->value()->AsBinaryOperation() != NULL && |
| 4988 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 4989 // Construct the implicit binary operation. |
| 4990 BinaryOperation expr(node, node->binary_op(), node->target(), |
| 4991 node->value()); |
| 4992 GenericBinaryOperation(&expr, |
| 4993 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
| 4994 } else { |
| 4995 // For non-compound assignment just load the right-hand side. |
| 4996 Load(node->value()); |
| 4997 } |
| 4998 |
| 4999 // Perform the assignment. |
| 5000 if (var->mode() != Variable::CONST || node->op() == Token::INIT_CONST) { |
| 5001 CodeForSourcePosition(node->position()); |
| 5002 StoreToSlot(slot, |
| 5003 node->op() == Token::INIT_CONST ? CONST_INIT : NOT_CONST_INIT); |
| 5004 } |
| 5005 ASSERT(frame()->height() == original_height + 1); |
| 5006 } |
| 5007 |
| 5008 |
4968 void CodeGenerator::VisitAssignment(Assignment* node) { | 5009 void CodeGenerator::VisitAssignment(Assignment* node) { |
4969 Comment cmnt(masm_, "[ Assignment"); | 5010 #ifdef DEBUG |
| 5011 int original_height = frame()->height(); |
| 5012 #endif |
| 5013 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
| 5014 // Property* prop = node->target()->AsProperty(); |
4970 | 5015 |
4971 { Reference target(this, node->target(), node->is_compound()); | 5016 if (var != NULL && !var->is_global()) { |
4972 if (target.is_illegal()) { | 5017 EmitSlotAssignment(node); |
4973 // Fool the virtual frame into thinking that we left the assignment's | |
4974 // value on the frame. | |
4975 frame_->Push(Smi::FromInt(0)); | |
4976 return; | |
4977 } | |
4978 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | |
4979 | 5018 |
4980 if (node->starts_initialization_block()) { | 5019 } else { |
4981 ASSERT(target.type() == Reference::NAMED || | 5020 Comment cmnt(masm_, "[ Assignment"); |
4982 target.type() == Reference::KEYED); | |
4983 // Change to slow case in the beginning of an initialization | |
4984 // block to avoid the quadratic behavior of repeatedly adding | |
4985 // fast properties. | |
4986 | 5021 |
4987 // The receiver is the argument to the runtime call. It is the | 5022 { Reference target(this, node->target(), node->is_compound()); |
4988 // first value pushed when the reference was loaded to the | 5023 if (target.is_illegal()) { |
4989 // frame. | 5024 // Fool the virtual frame into thinking that we left the assignment's |
4990 frame_->PushElementAt(target.size() - 1); | 5025 // value on the frame. |
4991 Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); | 5026 frame_->Push(Smi::FromInt(0)); |
4992 } | 5027 return; |
4993 if (node->ends_initialization_block()) { | |
4994 // Add an extra copy of the receiver to the frame, so that it can be | |
4995 // converted back to fast case after the assignment. | |
4996 ASSERT(target.type() == Reference::NAMED || | |
4997 target.type() == Reference::KEYED); | |
4998 if (target.type() == Reference::NAMED) { | |
4999 frame_->Dup(); | |
5000 // Dup target receiver on stack. | |
5001 } else { | |
5002 ASSERT(target.type() == Reference::KEYED); | |
5003 Result temp = frame_->Pop(); | |
5004 frame_->Dup(); | |
5005 frame_->Push(&temp); | |
5006 } | 5028 } |
5007 } | |
5008 if (node->op() == Token::ASSIGN || | |
5009 node->op() == Token::INIT_VAR || | |
5010 node->op() == Token::INIT_CONST) { | |
5011 Load(node->value()); | |
5012 | 5029 |
5013 } else { // Assignment is a compound assignment. | 5030 if (node->starts_initialization_block()) { |
5014 Literal* literal = node->value()->AsLiteral(); | 5031 ASSERT(target.type() == Reference::NAMED || |
5015 bool overwrite_value = | 5032 target.type() == Reference::KEYED); |
5016 (node->value()->AsBinaryOperation() != NULL && | 5033 // Change to slow case in the beginning of an initialization |
5017 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 5034 // block to avoid the quadratic behavior of repeatedly adding |
5018 Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); | 5035 // fast properties. |
5019 // There are two cases where the target is not read in the right hand | |
5020 // side, that are easy to test for: the right hand side is a literal, | |
5021 // or the right hand side is a different variable. TakeValue invalidates | |
5022 // the target, with an implicit promise that it will be written to again | |
5023 // before it is read. | |
5024 if (literal != NULL || (right_var != NULL && right_var != var)) { | |
5025 target.TakeValue(); | |
5026 } else { | |
5027 target.GetValue(); | |
5028 } | |
5029 Load(node->value()); | |
5030 BinaryOperation expr(node, node->binary_op(), node->target(), | |
5031 node->value()); | |
5032 GenericBinaryOperation(&expr, | |
5033 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | |
5034 } | |
5035 | 5036 |
5036 if (var != NULL && | 5037 // The receiver is the argument to the runtime call. It is the |
5037 var->mode() == Variable::CONST && | 5038 // first value pushed when the reference was loaded to the |
5038 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { | 5039 // frame. |
5039 // Assignment ignored - leave the value on the stack. | 5040 frame_->PushElementAt(target.size() - 1); |
5040 UnloadReference(&target); | 5041 Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); |
5041 } else { | |
5042 CodeForSourcePosition(node->position()); | |
5043 if (node->op() == Token::INIT_CONST) { | |
5044 // Dynamic constant initializations must use the function context | |
5045 // and initialize the actual constant declared. Dynamic variable | |
5046 // initializations are simply assignments and use SetValue. | |
5047 target.SetValue(CONST_INIT); | |
5048 } else { | |
5049 target.SetValue(NOT_CONST_INIT); | |
5050 } | 5042 } |
5051 if (node->ends_initialization_block()) { | 5043 if (node->ends_initialization_block()) { |
5052 ASSERT(target.type() == Reference::UNLOADED); | 5044 // Add an extra copy of the receiver to the frame, so that it can be |
5053 // End of initialization block. Revert to fast case. The | 5045 // converted back to fast case after the assignment. |
5054 // argument to the runtime call is the extra copy of the receiver, | 5046 ASSERT(target.type() == Reference::NAMED || |
5055 // which is below the value of the assignment. | 5047 target.type() == Reference::KEYED); |
5056 // Swap the receiver and the value of the assignment expression. | 5048 if (target.type() == Reference::NAMED) { |
5057 Result lhs = frame_->Pop(); | 5049 frame_->Dup(); |
5058 Result receiver = frame_->Pop(); | 5050 // Dup target receiver on stack. |
5059 frame_->Push(&lhs); | 5051 } else { |
5060 frame_->Push(&receiver); | 5052 ASSERT(target.type() == Reference::KEYED); |
5061 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); | 5053 Result temp = frame_->Pop(); |
| 5054 frame_->Dup(); |
| 5055 frame_->Push(&temp); |
| 5056 } |
| 5057 } |
| 5058 if (node->op() == Token::ASSIGN || |
| 5059 node->op() == Token::INIT_VAR || |
| 5060 node->op() == Token::INIT_CONST) { |
| 5061 Load(node->value()); |
| 5062 |
| 5063 } else { // Assignment is a compound assignment. |
| 5064 Literal* literal = node->value()->AsLiteral(); |
| 5065 bool overwrite_value = |
| 5066 (node->value()->AsBinaryOperation() != NULL && |
| 5067 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 5068 Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); |
| 5069 // There are two cases where the target is not read in the right hand |
| 5070 // side, that are easy to test for: the right hand side is a literal, |
| 5071 // or the right hand side is a different variable. TakeValue |
| 5072 // invalidates the target, with an implicit promise that it will be |
| 5073 // written to again |
| 5074 // before it is read. |
| 5075 if (literal != NULL || (right_var != NULL && right_var != var)) { |
| 5076 target.TakeValue(); |
| 5077 } else { |
| 5078 target.GetValue(); |
| 5079 } |
| 5080 Load(node->value()); |
| 5081 BinaryOperation expr(node, node->binary_op(), node->target(), |
| 5082 node->value()); |
| 5083 GenericBinaryOperation( |
| 5084 &expr, overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
| 5085 } |
| 5086 if (var != NULL && |
| 5087 var->mode() == Variable::CONST && |
| 5088 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { |
| 5089 // Assignment ignored - leave the value on the stack. |
| 5090 UnloadReference(&target); |
| 5091 } else { |
| 5092 CodeForSourcePosition(node->position()); |
| 5093 if (node->op() == Token::INIT_CONST) { |
| 5094 // Dynamic constant initializations must use the function context |
| 5095 // and initialize the actual constant declared. Dynamic variable |
| 5096 // initializations are simply assignments and use SetValue. |
| 5097 target.SetValue(CONST_INIT); |
| 5098 } else { |
| 5099 target.SetValue(NOT_CONST_INIT); |
| 5100 } |
| 5101 if (node->ends_initialization_block()) { |
| 5102 ASSERT(target.type() == Reference::UNLOADED); |
| 5103 // End of initialization block. Revert to fast case. The |
| 5104 // argument to the runtime call is the extra copy of the receiver, |
| 5105 // which is below the value of the assignment. |
| 5106 // Swap the receiver and the value of the assignment expression. |
| 5107 Result lhs = frame_->Pop(); |
| 5108 Result receiver = frame_->Pop(); |
| 5109 frame_->Push(&lhs); |
| 5110 frame_->Push(&receiver); |
| 5111 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
| 5112 } |
5062 } | 5113 } |
5063 } | 5114 } |
5064 } | 5115 } |
| 5116 // Stack layout: |
| 5117 // [tos] : result |
| 5118 |
| 5119 ASSERT(frame()->height() == original_height + 1); |
5065 } | 5120 } |
5066 | 5121 |
5067 | 5122 |
5068 void CodeGenerator::VisitThrow(Throw* node) { | 5123 void CodeGenerator::VisitThrow(Throw* node) { |
5069 Comment cmnt(masm_, "[ Throw"); | 5124 Comment cmnt(masm_, "[ Throw"); |
5070 Load(node->exception()); | 5125 Load(node->exception()); |
5071 Result result = frame_->CallRuntime(Runtime::kThrow, 1); | 5126 Result result = frame_->CallRuntime(Runtime::kThrow, 1); |
5072 frame_->Push(&result); | 5127 frame_->Push(&result); |
5073 } | 5128 } |
5074 | 5129 |
(...skipping 7040 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12115 #undef __ | 12170 #undef __ |
12116 | 12171 |
12117 void RecordWriteStub::Generate(MacroAssembler* masm) { | 12172 void RecordWriteStub::Generate(MacroAssembler* masm) { |
12118 masm->RecordWriteHelper(object_, addr_, scratch_); | 12173 masm->RecordWriteHelper(object_, addr_, scratch_); |
12119 masm->ret(0); | 12174 masm->ret(0); |
12120 } | 12175 } |
12121 | 12176 |
12122 } } // namespace v8::internal | 12177 } } // namespace v8::internal |
12123 | 12178 |
12124 #endif // V8_TARGET_ARCH_X64 | 12179 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |