Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 274 #endif | 274 #endif |
| 275 VisitStatements(body); | 275 VisitStatements(body); |
| 276 | 276 |
| 277 // Handle the return from the function. | 277 // Handle the return from the function. |
| 278 if (has_valid_frame()) { | 278 if (has_valid_frame()) { |
| 279 // If there is a valid frame, control flow can fall off the end of | 279 // If there is a valid frame, control flow can fall off the end of |
| 280 // the body. In that case there is an implicit return statement. | 280 // the body. In that case there is an implicit return statement. |
| 281 ASSERT(!function_return_is_shadowed_); | 281 ASSERT(!function_return_is_shadowed_); |
| 282 CodeForReturnPosition(fun); | 282 CodeForReturnPosition(fun); |
| 283 frame_->PrepareForReturn(); | 283 frame_->PrepareForReturn(); |
| 284 Result undefined(Factory::undefined_value(), this); | 284 Result undefined(Factory::undefined_value()); |
| 285 if (function_return_.is_bound()) { | 285 if (function_return_.is_bound()) { |
| 286 function_return_.Jump(&undefined); | 286 function_return_.Jump(&undefined); |
| 287 } else { | 287 } else { |
| 288 // Though this is a (possibly) backward block, the frames | 288 // Though this is a (possibly) backward block, the frames |
| 289 // can only differ on their top element. | 289 // can only differ on their top element. |
| 290 function_return_.Bind(&undefined, 1); | 290 function_return_.Bind(&undefined, 1); |
| 291 GenerateReturnSequence(&undefined); | 291 GenerateReturnSequence(&undefined); |
| 292 } | 292 } |
| 293 } else if (function_return_.is_linked()) { | 293 } else if (function_return_.is_linked()) { |
| 294 // If the return target has dangling jumps to it, then we have not | 294 // If the return target has dangling jumps to it, then we have not |
| 295 // yet generated the return sequence. This can happen when (a) | 295 // yet generated the return sequence. This can happen when (a) |
| 296 // control does not flow off the end of the body so we did not | 296 // control does not flow off the end of the body so we did not |
| 297 // compile an artificial return statement just above, and (b) there | 297 // compile an artificial return statement just above, and (b) there |
| 298 // are return statements in the body but (c) they are all shadowed. | 298 // are return statements in the body but (c) they are all shadowed. |
| 299 Result return_value(this); | 299 Result return_value; |
| 300 // Though this is a (possibly) backward block, the frames can | 300 // Though this is a (possibly) backward block, the frames can |
| 301 // only differ on their top element. | 301 // only differ on their top element. |
| 302 function_return_.Bind(&return_value, 1); | 302 function_return_.Bind(&return_value, 1); |
| 303 GenerateReturnSequence(&return_value); | 303 GenerateReturnSequence(&return_value); |
| 304 } | 304 } |
| 305 } | 305 } |
| 306 } | 306 } |
| 307 | 307 |
| 308 // Adjust for function-level loop nesting. | 308 // Adjust for function-level loop nesting. |
| 309 loop_nesting_ -= fun->loop_nesting(); | 309 loop_nesting_ -= fun->loop_nesting(); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 381 return Operand(eax); | 381 return Operand(eax); |
| 382 } | 382 } |
| 383 } | 383 } |
| 384 | 384 |
| 385 | 385 |
| 386 Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot, | 386 Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot, |
| 387 Result tmp, | 387 Result tmp, |
| 388 JumpTarget* slow) { | 388 JumpTarget* slow) { |
| 389 ASSERT(slot->type() == Slot::CONTEXT); | 389 ASSERT(slot->type() == Slot::CONTEXT); |
| 390 ASSERT(tmp.is_register()); | 390 ASSERT(tmp.is_register()); |
| 391 Result context(esi, this); | 391 Result context(esi); |
| 392 | 392 |
| 393 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { | 393 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { |
| 394 if (s->num_heap_slots() > 0) { | 394 if (s->num_heap_slots() > 0) { |
| 395 if (s->calls_eval()) { | 395 if (s->calls_eval()) { |
| 396 // Check that extension is NULL. | 396 // Check that extension is NULL. |
| 397 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX), | 397 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX), |
| 398 Immediate(0)); | 398 Immediate(0)); |
| 399 slow->Branch(not_equal, not_taken); | 399 slow->Branch(not_equal, not_taken); |
| 400 } | 400 } |
| 401 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::CLOSURE_INDEX)); | 401 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::CLOSURE_INDEX)); |
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 796 | 796 |
| 797 virtual void Generate(); | 797 virtual void Generate(); |
| 798 | 798 |
| 799 private: | 799 private: |
| 800 GenericBinaryOpStub stub_; | 800 GenericBinaryOpStub stub_; |
| 801 Token::Value op_; | 801 Token::Value op_; |
| 802 }; | 802 }; |
| 803 | 803 |
| 804 | 804 |
| 805 void DeferredInlineBinaryOperation::Generate() { | 805 void DeferredInlineBinaryOperation::Generate() { |
| 806 Result left(generator()); | 806 Result left; |
|
Kevin Millikin (Chromium)
2009/05/15 10:50:49
A separate cleanup, since we have it now, is to us
| |
| 807 Result right(generator()); | 807 Result right; |
| 808 enter()->Bind(&left, &right); | 808 enter()->Bind(&left, &right); |
| 809 generator()->frame()->Push(&left); | 809 generator()->frame()->Push(&left); |
| 810 generator()->frame()->Push(&right); | 810 generator()->frame()->Push(&right); |
| 811 Result answer = generator()->frame()->CallStub(&stub_, 2); | 811 Result answer = generator()->frame()->CallStub(&stub_, 2); |
| 812 exit_.Jump(&answer); | 812 exit_.Jump(&answer); |
| 813 } | 813 } |
| 814 | 814 |
| 815 | 815 |
| 816 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 816 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
| 817 SmiAnalysis* type, | 817 SmiAnalysis* type, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 852 | 852 |
| 853 Result right = frame_->Pop(); | 853 Result right = frame_->Pop(); |
| 854 Result left = frame_->Pop(); | 854 Result left = frame_->Pop(); |
| 855 | 855 |
| 856 if (op == Token::ADD) { | 856 if (op == Token::ADD) { |
| 857 bool left_is_string = left.static_type().is_jsstring(); | 857 bool left_is_string = left.static_type().is_jsstring(); |
| 858 bool right_is_string = right.static_type().is_jsstring(); | 858 bool right_is_string = right.static_type().is_jsstring(); |
| 859 if (left_is_string || right_is_string) { | 859 if (left_is_string || right_is_string) { |
| 860 frame_->Push(&left); | 860 frame_->Push(&left); |
| 861 frame_->Push(&right); | 861 frame_->Push(&right); |
| 862 Result answer(this); | 862 Result answer; |
| 863 if (left_is_string) { | 863 if (left_is_string) { |
| 864 if (right_is_string) { | 864 if (right_is_string) { |
| 865 // TODO(lrn): if (left.is_constant() && right.is_constant()) | 865 // TODO(lrn): if (left.is_constant() && right.is_constant()) |
| 866 // -- do a compile time cons, if allocation during codegen is allowed. | 866 // -- do a compile time cons, if allocation during codegen is allowed. |
| 867 answer = frame_->CallRuntime(Runtime::kStringAdd, 2); | 867 answer = frame_->CallRuntime(Runtime::kStringAdd, 2); |
| 868 } else { | 868 } else { |
| 869 answer = | 869 answer = |
| 870 frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2); | 870 frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2); |
| 871 } | 871 } |
| 872 } else if (right_is_string) { | 872 } else if (right_is_string) { |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1038 virtual void Generate(); | 1038 virtual void Generate(); |
| 1039 | 1039 |
| 1040 private: | 1040 private: |
| 1041 Token::Value op_; | 1041 Token::Value op_; |
| 1042 Smi* value_; | 1042 Smi* value_; |
| 1043 OverwriteMode overwrite_mode_; | 1043 OverwriteMode overwrite_mode_; |
| 1044 }; | 1044 }; |
| 1045 | 1045 |
| 1046 | 1046 |
| 1047 void DeferredInlineSmiOperation::Generate() { | 1047 void DeferredInlineSmiOperation::Generate() { |
| 1048 Result left(generator()); | 1048 Result left; |
| 1049 enter()->Bind(&left); | 1049 enter()->Bind(&left); |
| 1050 generator()->frame()->Push(&left); | 1050 generator()->frame()->Push(&left); |
| 1051 generator()->frame()->Push(value_); | 1051 generator()->frame()->Push(value_); |
| 1052 GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED); | 1052 GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED); |
| 1053 Result answer = generator()->frame()->CallStub(&igostub, 2); | 1053 Result answer = generator()->frame()->CallStub(&igostub, 2); |
| 1054 exit_.Jump(&answer); | 1054 exit_.Jump(&answer); |
| 1055 } | 1055 } |
| 1056 | 1056 |
| 1057 | 1057 |
| 1058 class DeferredInlineSmiOperationReversed: public DeferredCode { | 1058 class DeferredInlineSmiOperationReversed: public DeferredCode { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1071 virtual void Generate(); | 1071 virtual void Generate(); |
| 1072 | 1072 |
| 1073 private: | 1073 private: |
| 1074 Token::Value op_; | 1074 Token::Value op_; |
| 1075 Smi* value_; | 1075 Smi* value_; |
| 1076 OverwriteMode overwrite_mode_; | 1076 OverwriteMode overwrite_mode_; |
| 1077 }; | 1077 }; |
| 1078 | 1078 |
| 1079 | 1079 |
| 1080 void DeferredInlineSmiOperationReversed::Generate() { | 1080 void DeferredInlineSmiOperationReversed::Generate() { |
| 1081 Result right(generator()); | 1081 Result right; |
| 1082 enter()->Bind(&right); | 1082 enter()->Bind(&right); |
| 1083 generator()->frame()->Push(value_); | 1083 generator()->frame()->Push(value_); |
| 1084 generator()->frame()->Push(&right); | 1084 generator()->frame()->Push(&right); |
| 1085 GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED); | 1085 GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED); |
| 1086 Result answer = generator()->frame()->CallStub(&igostub, 2); | 1086 Result answer = generator()->frame()->CallStub(&igostub, 2); |
| 1087 exit_.Jump(&answer); | 1087 exit_.Jump(&answer); |
| 1088 } | 1088 } |
| 1089 | 1089 |
| 1090 | 1090 |
| 1091 class DeferredInlineSmiAdd: public DeferredCode { | 1091 class DeferredInlineSmiAdd: public DeferredCode { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 1102 virtual void Generate(); | 1102 virtual void Generate(); |
| 1103 | 1103 |
| 1104 private: | 1104 private: |
| 1105 Smi* value_; | 1105 Smi* value_; |
| 1106 OverwriteMode overwrite_mode_; | 1106 OverwriteMode overwrite_mode_; |
| 1107 }; | 1107 }; |
| 1108 | 1108 |
| 1109 | 1109 |
| 1110 void DeferredInlineSmiAdd::Generate() { | 1110 void DeferredInlineSmiAdd::Generate() { |
| 1111 // Undo the optimistic add operation and call the shared stub. | 1111 // Undo the optimistic add operation and call the shared stub. |
| 1112 Result left(generator()); // Initially left + value_. | 1112 Result left; // Initially left + value_. |
| 1113 enter()->Bind(&left); | 1113 enter()->Bind(&left); |
| 1114 left.ToRegister(); | 1114 left.ToRegister(); |
| 1115 generator()->frame()->Spill(left.reg()); | 1115 generator()->frame()->Spill(left.reg()); |
| 1116 __ sub(Operand(left.reg()), Immediate(value_)); | 1116 __ sub(Operand(left.reg()), Immediate(value_)); |
| 1117 generator()->frame()->Push(&left); | 1117 generator()->frame()->Push(&left); |
| 1118 generator()->frame()->Push(value_); | 1118 generator()->frame()->Push(value_); |
| 1119 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED); | 1119 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED); |
| 1120 Result answer = generator()->frame()->CallStub(&igostub, 2); | 1120 Result answer = generator()->frame()->CallStub(&igostub, 2); |
| 1121 exit_.Jump(&answer); | 1121 exit_.Jump(&answer); |
| 1122 } | 1122 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1136 virtual void Generate(); | 1136 virtual void Generate(); |
| 1137 | 1137 |
| 1138 private: | 1138 private: |
| 1139 Smi* value_; | 1139 Smi* value_; |
| 1140 OverwriteMode overwrite_mode_; | 1140 OverwriteMode overwrite_mode_; |
| 1141 }; | 1141 }; |
| 1142 | 1142 |
| 1143 | 1143 |
| 1144 void DeferredInlineSmiAddReversed::Generate() { | 1144 void DeferredInlineSmiAddReversed::Generate() { |
| 1145 // Undo the optimistic add operation and call the shared stub. | 1145 // Undo the optimistic add operation and call the shared stub. |
| 1146 Result right(generator()); // Initially value_ + right. | 1146 Result right; // Initially value_ + right. |
| 1147 enter()->Bind(&right); | 1147 enter()->Bind(&right); |
| 1148 right.ToRegister(); | 1148 right.ToRegister(); |
| 1149 generator()->frame()->Spill(right.reg()); | 1149 generator()->frame()->Spill(right.reg()); |
| 1150 __ sub(Operand(right.reg()), Immediate(value_)); | 1150 __ sub(Operand(right.reg()), Immediate(value_)); |
| 1151 generator()->frame()->Push(value_); | 1151 generator()->frame()->Push(value_); |
| 1152 generator()->frame()->Push(&right); | 1152 generator()->frame()->Push(&right); |
| 1153 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED); | 1153 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED); |
| 1154 Result answer = generator()->frame()->CallStub(&igostub, 2); | 1154 Result answer = generator()->frame()->CallStub(&igostub, 2); |
| 1155 exit_.Jump(&answer); | 1155 exit_.Jump(&answer); |
| 1156 } | 1156 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1170 virtual void Generate(); | 1170 virtual void Generate(); |
| 1171 | 1171 |
| 1172 private: | 1172 private: |
| 1173 Smi* value_; | 1173 Smi* value_; |
| 1174 OverwriteMode overwrite_mode_; | 1174 OverwriteMode overwrite_mode_; |
| 1175 }; | 1175 }; |
| 1176 | 1176 |
| 1177 | 1177 |
| 1178 void DeferredInlineSmiSub::Generate() { | 1178 void DeferredInlineSmiSub::Generate() { |
| 1179 // Undo the optimistic sub operation and call the shared stub. | 1179 // Undo the optimistic sub operation and call the shared stub. |
| 1180 Result left(generator()); // Initially left - value_. | 1180 Result left; // Initially left - value_. |
| 1181 enter()->Bind(&left); | 1181 enter()->Bind(&left); |
| 1182 left.ToRegister(); | 1182 left.ToRegister(); |
| 1183 generator()->frame()->Spill(left.reg()); | 1183 generator()->frame()->Spill(left.reg()); |
| 1184 __ add(Operand(left.reg()), Immediate(value_)); | 1184 __ add(Operand(left.reg()), Immediate(value_)); |
| 1185 generator()->frame()->Push(&left); | 1185 generator()->frame()->Push(&left); |
| 1186 generator()->frame()->Push(value_); | 1186 generator()->frame()->Push(value_); |
| 1187 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED); | 1187 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED); |
| 1188 Result answer = generator()->frame()->CallStub(&igostub, 2); | 1188 Result answer = generator()->frame()->CallStub(&igostub, 2); |
| 1189 exit_.Jump(&answer); | 1189 exit_.Jump(&answer); |
| 1190 } | 1190 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1204 virtual void Generate(); | 1204 virtual void Generate(); |
| 1205 | 1205 |
| 1206 private: | 1206 private: |
| 1207 Smi* value_; | 1207 Smi* value_; |
| 1208 OverwriteMode overwrite_mode_; | 1208 OverwriteMode overwrite_mode_; |
| 1209 }; | 1209 }; |
| 1210 | 1210 |
| 1211 | 1211 |
| 1212 void DeferredInlineSmiSubReversed::Generate() { | 1212 void DeferredInlineSmiSubReversed::Generate() { |
| 1213 // Call the shared stub. | 1213 // Call the shared stub. |
| 1214 Result right(generator()); | 1214 Result right; |
| 1215 enter()->Bind(&right); | 1215 enter()->Bind(&right); |
| 1216 generator()->frame()->Push(value_); | 1216 generator()->frame()->Push(value_); |
| 1217 generator()->frame()->Push(&right); | 1217 generator()->frame()->Push(&right); |
| 1218 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED); | 1218 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED); |
| 1219 Result answer = generator()->frame()->CallStub(&igostub, 2); | 1219 Result answer = generator()->frame()->CallStub(&igostub, 2); |
| 1220 exit_.Jump(&answer); | 1220 exit_.Jump(&answer); |
| 1221 } | 1221 } |
| 1222 | 1222 |
| 1223 | 1223 |
| 1224 void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, | 1224 void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| 1225 Result* operand, | 1225 Result* operand, |
| 1226 Handle<Object> value, | 1226 Handle<Object> value, |
| 1227 SmiAnalysis* type, | 1227 SmiAnalysis* type, |
| 1228 bool reversed, | 1228 bool reversed, |
| 1229 OverwriteMode overwrite_mode) { | 1229 OverwriteMode overwrite_mode) { |
| 1230 // NOTE: This is an attempt to inline (a bit) more of the code for | 1230 // NOTE: This is an attempt to inline (a bit) more of the code for |
| 1231 // some possible smi operations (like + and -) when (at least) one | 1231 // some possible smi operations (like + and -) when (at least) one |
| 1232 // of the operands is a constant smi. | 1232 // of the operands is a constant smi. |
| 1233 // Consumes the argument "operand". | 1233 // Consumes the argument "operand". |
| 1234 | 1234 |
| 1235 // TODO(199): Optimize some special cases of operations involving a | 1235 // TODO(199): Optimize some special cases of operations involving a |
| 1236 // smi literal (multiply by 2, shift by 0, etc.). | 1236 // smi literal (multiply by 2, shift by 0, etc.). |
| 1237 if (IsUnsafeSmi(value)) { | 1237 if (IsUnsafeSmi(value)) { |
| 1238 Result unsafe_operand(value, this); | 1238 Result unsafe_operand(value); |
| 1239 if (reversed) { | 1239 if (reversed) { |
| 1240 LikelySmiBinaryOperation(op, &unsafe_operand, operand, | 1240 LikelySmiBinaryOperation(op, &unsafe_operand, operand, |
| 1241 overwrite_mode); | 1241 overwrite_mode); |
| 1242 } else { | 1242 } else { |
| 1243 LikelySmiBinaryOperation(op, operand, &unsafe_operand, | 1243 LikelySmiBinaryOperation(op, operand, &unsafe_operand, |
| 1244 overwrite_mode); | 1244 overwrite_mode); |
| 1245 } | 1245 } |
| 1246 ASSERT(!operand->is_valid()); | 1246 ASSERT(!operand->is_valid()); |
| 1247 return; | 1247 return; |
| 1248 } | 1248 } |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 1268 deferred->enter()->Branch(overflow, operand, not_taken); | 1268 deferred->enter()->Branch(overflow, operand, not_taken); |
| 1269 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1269 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1270 deferred->enter()->Branch(not_zero, operand, not_taken); | 1270 deferred->enter()->Branch(not_zero, operand, not_taken); |
| 1271 deferred->BindExit(operand); | 1271 deferred->BindExit(operand); |
| 1272 frame_->Push(operand); | 1272 frame_->Push(operand); |
| 1273 break; | 1273 break; |
| 1274 } | 1274 } |
| 1275 | 1275 |
| 1276 case Token::SUB: { | 1276 case Token::SUB: { |
| 1277 DeferredCode* deferred = NULL; | 1277 DeferredCode* deferred = NULL; |
| 1278 Result answer(this); // Only allocate a new register if reversed. | 1278 Result answer; // Only allocate a new register if reversed. |
| 1279 if (reversed) { | 1279 if (reversed) { |
| 1280 answer = allocator()->Allocate(); | 1280 answer = allocator()->Allocate(); |
| 1281 ASSERT(answer.is_valid()); | 1281 ASSERT(answer.is_valid()); |
| 1282 deferred = new DeferredInlineSmiSubReversed(this, smi_value, | 1282 deferred = new DeferredInlineSmiSubReversed(this, smi_value, |
| 1283 overwrite_mode); | 1283 overwrite_mode); |
| 1284 __ Set(answer.reg(), Immediate(value)); | 1284 __ Set(answer.reg(), Immediate(value)); |
| 1285 // We are in the reversed case so they can't both be Smi constants. | 1285 // We are in the reversed case so they can't both be Smi constants. |
| 1286 ASSERT(operand->is_register()); | 1286 ASSERT(operand->is_register()); |
| 1287 __ sub(answer.reg(), Operand(operand->reg())); | 1287 __ sub(answer.reg(), Operand(operand->reg())); |
| 1288 } else { | 1288 } else { |
| 1289 operand->ToRegister(); | 1289 operand->ToRegister(); |
| 1290 frame_->Spill(operand->reg()); | 1290 frame_->Spill(operand->reg()); |
| 1291 deferred = new DeferredInlineSmiSub(this, smi_value, overwrite_mode); | 1291 deferred = new DeferredInlineSmiSub(this, smi_value, overwrite_mode); |
| 1292 __ sub(Operand(operand->reg()), Immediate(value)); | 1292 __ sub(Operand(operand->reg()), Immediate(value)); |
| 1293 answer = *operand; | 1293 answer = *operand; |
| 1294 } | 1294 } |
| 1295 deferred->SetEntryFrame(operand); | 1295 deferred->SetEntryFrame(operand); |
| 1296 deferred->enter()->Branch(overflow, operand, not_taken); | 1296 deferred->enter()->Branch(overflow, operand, not_taken); |
| 1297 __ test(answer.reg(), Immediate(kSmiTagMask)); | 1297 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 1298 deferred->enter()->Branch(not_zero, operand, not_taken); | 1298 deferred->enter()->Branch(not_zero, operand, not_taken); |
| 1299 operand->Unuse(); | 1299 operand->Unuse(); |
| 1300 deferred->BindExit(&answer); | 1300 deferred->BindExit(&answer); |
| 1301 frame_->Push(&answer); | 1301 frame_->Push(&answer); |
| 1302 break; | 1302 break; |
| 1303 } | 1303 } |
| 1304 | 1304 |
| 1305 case Token::SAR: { | 1305 case Token::SAR: { |
| 1306 if (reversed) { | 1306 if (reversed) { |
| 1307 Result constant_operand(value, this); | 1307 Result constant_operand(value); |
| 1308 LikelySmiBinaryOperation(op, &constant_operand, operand, | 1308 LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 1309 overwrite_mode); | 1309 overwrite_mode); |
| 1310 } else { | 1310 } else { |
| 1311 // Only the least significant 5 bits of the shift value are used. | 1311 // Only the least significant 5 bits of the shift value are used. |
| 1312 // In the slow case, this masking is done inside the runtime call. | 1312 // In the slow case, this masking is done inside the runtime call. |
| 1313 int shift_value = int_value & 0x1f; | 1313 int shift_value = int_value & 0x1f; |
| 1314 DeferredCode* deferred = | 1314 DeferredCode* deferred = |
| 1315 new DeferredInlineSmiOperation(this, Token::SAR, smi_value, | 1315 new DeferredInlineSmiOperation(this, Token::SAR, smi_value, |
| 1316 overwrite_mode); | 1316 overwrite_mode); |
| 1317 operand->ToRegister(); | 1317 operand->ToRegister(); |
| 1318 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1318 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1319 deferred->enter()->Branch(not_zero, operand, not_taken); | 1319 deferred->enter()->Branch(not_zero, operand, not_taken); |
| 1320 if (shift_value > 0) { | 1320 if (shift_value > 0) { |
| 1321 frame_->Spill(operand->reg()); | 1321 frame_->Spill(operand->reg()); |
| 1322 __ sar(operand->reg(), shift_value); | 1322 __ sar(operand->reg(), shift_value); |
| 1323 __ and_(operand->reg(), ~kSmiTagMask); | 1323 __ and_(operand->reg(), ~kSmiTagMask); |
| 1324 } | 1324 } |
| 1325 deferred->BindExit(operand); | 1325 deferred->BindExit(operand); |
| 1326 frame_->Push(operand); | 1326 frame_->Push(operand); |
| 1327 } | 1327 } |
| 1328 break; | 1328 break; |
| 1329 } | 1329 } |
| 1330 | 1330 |
| 1331 case Token::SHR: { | 1331 case Token::SHR: { |
| 1332 if (reversed) { | 1332 if (reversed) { |
| 1333 Result constant_operand(value, this); | 1333 Result constant_operand(value); |
| 1334 LikelySmiBinaryOperation(op, &constant_operand, operand, | 1334 LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 1335 overwrite_mode); | 1335 overwrite_mode); |
| 1336 } else { | 1336 } else { |
| 1337 // Only the least significant 5 bits of the shift value are used. | 1337 // Only the least significant 5 bits of the shift value are used. |
| 1338 // In the slow case, this masking is done inside the runtime call. | 1338 // In the slow case, this masking is done inside the runtime call. |
| 1339 int shift_value = int_value & 0x1f; | 1339 int shift_value = int_value & 0x1f; |
| 1340 DeferredCode* deferred = | 1340 DeferredCode* deferred = |
| 1341 new DeferredInlineSmiOperation(this, Token::SHR, smi_value, | 1341 new DeferredInlineSmiOperation(this, Token::SHR, smi_value, |
| 1342 overwrite_mode); | 1342 overwrite_mode); |
| 1343 operand->ToRegister(); | 1343 operand->ToRegister(); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1358 __ lea(answer.reg(), | 1358 __ lea(answer.reg(), |
| 1359 Operand(answer.reg(), answer.reg(), times_1, kSmiTag)); | 1359 Operand(answer.reg(), answer.reg(), times_1, kSmiTag)); |
| 1360 deferred->BindExit(&answer); | 1360 deferred->BindExit(&answer); |
| 1361 frame_->Push(&answer); | 1361 frame_->Push(&answer); |
| 1362 } | 1362 } |
| 1363 break; | 1363 break; |
| 1364 } | 1364 } |
| 1365 | 1365 |
| 1366 case Token::SHL: { | 1366 case Token::SHL: { |
| 1367 if (reversed) { | 1367 if (reversed) { |
| 1368 Result constant_operand(value, this); | 1368 Result constant_operand(value); |
| 1369 LikelySmiBinaryOperation(op, &constant_operand, operand, | 1369 LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 1370 overwrite_mode); | 1370 overwrite_mode); |
| 1371 } else { | 1371 } else { |
| 1372 // Only the least significant 5 bits of the shift value are used. | 1372 // Only the least significant 5 bits of the shift value are used. |
| 1373 // In the slow case, this masking is done inside the runtime call. | 1373 // In the slow case, this masking is done inside the runtime call. |
| 1374 int shift_value = int_value & 0x1f; | 1374 int shift_value = int_value & 0x1f; |
| 1375 DeferredCode* deferred = | 1375 DeferredCode* deferred = |
| 1376 new DeferredInlineSmiOperation(this, Token::SHL, smi_value, | 1376 new DeferredInlineSmiOperation(this, Token::SHL, smi_value, |
| 1377 overwrite_mode); | 1377 overwrite_mode); |
| 1378 operand->ToRegister(); | 1378 operand->ToRegister(); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1428 if (int_value != 0) { | 1428 if (int_value != 0) { |
| 1429 __ or_(Operand(operand->reg()), Immediate(value)); | 1429 __ or_(Operand(operand->reg()), Immediate(value)); |
| 1430 } | 1430 } |
| 1431 } | 1431 } |
| 1432 deferred->BindExit(operand); | 1432 deferred->BindExit(operand); |
| 1433 frame_->Push(operand); | 1433 frame_->Push(operand); |
| 1434 break; | 1434 break; |
| 1435 } | 1435 } |
| 1436 | 1436 |
| 1437 default: { | 1437 default: { |
| 1438 Result constant_operand(value, this); | 1438 Result constant_operand(value); |
| 1439 if (reversed) { | 1439 if (reversed) { |
| 1440 LikelySmiBinaryOperation(op, &constant_operand, operand, | 1440 LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 1441 overwrite_mode); | 1441 overwrite_mode); |
| 1442 } else { | 1442 } else { |
| 1443 LikelySmiBinaryOperation(op, operand, &constant_operand, | 1443 LikelySmiBinaryOperation(op, operand, &constant_operand, |
| 1444 overwrite_mode); | 1444 overwrite_mode); |
| 1445 } | 1445 } |
| 1446 break; | 1446 break; |
| 1447 } | 1447 } |
| 1448 } | 1448 } |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 1477 #endif | 1477 #endif |
| 1478 }; | 1478 }; |
| 1479 | 1479 |
| 1480 | 1480 |
| 1481 void CodeGenerator::Comparison(Condition cc, | 1481 void CodeGenerator::Comparison(Condition cc, |
| 1482 bool strict, | 1482 bool strict, |
| 1483 ControlDestination* dest) { | 1483 ControlDestination* dest) { |
| 1484 // Strict only makes sense for equality comparisons. | 1484 // Strict only makes sense for equality comparisons. |
| 1485 ASSERT(!strict || cc == equal); | 1485 ASSERT(!strict || cc == equal); |
| 1486 | 1486 |
| 1487 Result left_side(this); | 1487 Result left_side; |
| 1488 Result right_side(this); | 1488 Result right_side; |
| 1489 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 1489 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
| 1490 if (cc == greater || cc == less_equal) { | 1490 if (cc == greater || cc == less_equal) { |
| 1491 cc = ReverseCondition(cc); | 1491 cc = ReverseCondition(cc); |
| 1492 left_side = frame_->Pop(); | 1492 left_side = frame_->Pop(); |
| 1493 right_side = frame_->Pop(); | 1493 right_side = frame_->Pop(); |
| 1494 } else { | 1494 } else { |
| 1495 right_side = frame_->Pop(); | 1495 right_side = frame_->Pop(); |
| 1496 left_side = frame_->Pop(); | 1496 left_side = frame_->Pop(); |
| 1497 } | 1497 } |
| 1498 ASSERT(cc == less || cc == equal || cc == greater_equal); | 1498 ASSERT(cc == less || cc == equal || cc == greater_equal); |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1762 node->break_target()->Bind(); | 1762 node->break_target()->Bind(); |
| 1763 } | 1763 } |
| 1764 node->break_target()->Unuse(); | 1764 node->break_target()->Unuse(); |
| 1765 } | 1765 } |
| 1766 | 1766 |
| 1767 | 1767 |
| 1768 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1768 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1769 frame_->Push(pairs); | 1769 frame_->Push(pairs); |
| 1770 | 1770 |
| 1771 // Duplicate the context register. | 1771 // Duplicate the context register. |
| 1772 Result context(esi, this); | 1772 Result context(esi); |
| 1773 frame_->Push(&context); | 1773 frame_->Push(&context); |
| 1774 | 1774 |
| 1775 frame_->Push(Smi::FromInt(is_eval() ? 1 : 0)); | 1775 frame_->Push(Smi::FromInt(is_eval() ? 1 : 0)); |
| 1776 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 1776 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
| 1777 // Return value is ignored. | 1777 // Return value is ignored. |
| 1778 } | 1778 } |
| 1779 | 1779 |
| 1780 | 1780 |
| 1781 void CodeGenerator::VisitDeclaration(Declaration* node) { | 1781 void CodeGenerator::VisitDeclaration(Declaration* node) { |
| 1782 Comment cmnt(masm_, "[ Declaration"); | 1782 Comment cmnt(masm_, "[ Declaration"); |
| 1783 CodeForStatementPosition(node); | 1783 CodeForStatementPosition(node); |
| 1784 Variable* var = node->proxy()->var(); | 1784 Variable* var = node->proxy()->var(); |
| 1785 ASSERT(var != NULL); // must have been resolved | 1785 ASSERT(var != NULL); // must have been resolved |
| 1786 Slot* slot = var->slot(); | 1786 Slot* slot = var->slot(); |
| 1787 | 1787 |
| 1788 // If it was not possible to allocate the variable at compile time, | 1788 // If it was not possible to allocate the variable at compile time, |
| 1789 // we need to "declare" it at runtime to make sure it actually | 1789 // we need to "declare" it at runtime to make sure it actually |
| 1790 // exists in the local context. | 1790 // exists in the local context. |
| 1791 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1791 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1792 // Variables with a "LOOKUP" slot were introduced as non-locals | 1792 // Variables with a "LOOKUP" slot were introduced as non-locals |
| 1793 // during variable resolution and must have mode DYNAMIC. | 1793 // during variable resolution and must have mode DYNAMIC. |
| 1794 ASSERT(var->is_dynamic()); | 1794 ASSERT(var->is_dynamic()); |
| 1795 // For now, just do a runtime call. Duplicate the context register. | 1795 // For now, just do a runtime call. Duplicate the context register. |
| 1796 Result context(esi, this); | 1796 Result context(esi); |
| 1797 frame_->Push(&context); | 1797 frame_->Push(&context); |
| 1798 frame_->Push(var->name()); | 1798 frame_->Push(var->name()); |
| 1799 // Declaration nodes are always introduced in one of two modes. | 1799 // Declaration nodes are always introduced in one of two modes. |
| 1800 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); | 1800 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); |
| 1801 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; | 1801 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; |
| 1802 frame_->Push(Smi::FromInt(attr)); | 1802 frame_->Push(Smi::FromInt(attr)); |
| 1803 // Push initial value, if any. | 1803 // Push initial value, if any. |
| 1804 // Note: For variables we must not push an initial value (such as | 1804 // Note: For variables we must not push an initial value (such as |
| 1805 // 'undefined') because we may have a (legal) redeclaration and we | 1805 // 'undefined') because we may have a (legal) redeclaration and we |
| 1806 // must not destroy the current value. | 1806 // must not destroy the current value. |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2025 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, | 2025 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, |
| 2026 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 2026 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 2027 } | 2027 } |
| 2028 | 2028 |
| 2029 | 2029 |
| 2030 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 2030 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 2031 ASSERT(!in_spilled_code()); | 2031 ASSERT(!in_spilled_code()); |
| 2032 Comment cmnt(masm_, "[ WithEnterStatement"); | 2032 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 2033 CodeForStatementPosition(node); | 2033 CodeForStatementPosition(node); |
| 2034 Load(node->expression()); | 2034 Load(node->expression()); |
| 2035 Result context(this); | 2035 Result context; |
| 2036 if (node->is_catch_block()) { | 2036 if (node->is_catch_block()) { |
| 2037 context = frame_->CallRuntime(Runtime::kPushCatchContext, 1); | 2037 context = frame_->CallRuntime(Runtime::kPushCatchContext, 1); |
| 2038 } else { | 2038 } else { |
| 2039 context = frame_->CallRuntime(Runtime::kPushContext, 1); | 2039 context = frame_->CallRuntime(Runtime::kPushContext, 1); |
| 2040 } | 2040 } |
| 2041 | 2041 |
| 2042 // Update context local. | 2042 // Update context local. |
| 2043 frame_->SaveContextRegister(); | 2043 frame_->SaveContextRegister(); |
| 2044 | 2044 |
| 2045 // Verify that the runtime call result and esi agree. | 2045 // Verify that the runtime call result and esi agree. |
| (...skipping 888 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2934 // frame. | 2934 // frame. |
| 2935 frame_->EmitPop(Operand::StaticVariable(handler_address)); | 2935 frame_->EmitPop(Operand::StaticVariable(handler_address)); |
| 2936 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2936 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2937 if (has_unlinks) { | 2937 if (has_unlinks) { |
| 2938 exit.Jump(); | 2938 exit.Jump(); |
| 2939 } | 2939 } |
| 2940 } | 2940 } |
| 2941 | 2941 |
| 2942 // Generate unlink code for the (formerly) shadowing targets that | 2942 // Generate unlink code for the (formerly) shadowing targets that |
| 2943 // have been jumped to. Deallocate each shadow target. | 2943 // have been jumped to. Deallocate each shadow target. |
| 2944 Result return_value(this); | 2944 Result return_value; |
| 2945 for (int i = 0; i < shadows.length(); i++) { | 2945 for (int i = 0; i < shadows.length(); i++) { |
| 2946 if (shadows[i]->is_linked()) { | 2946 if (shadows[i]->is_linked()) { |
| 2947 // Unlink from try chain; be careful not to destroy the TOS if | 2947 // Unlink from try chain; be careful not to destroy the TOS if |
| 2948 // there is one. | 2948 // there is one. |
| 2949 if (i == kReturnShadowIndex) { | 2949 if (i == kReturnShadowIndex) { |
| 2950 shadows[i]->Bind(&return_value); | 2950 shadows[i]->Bind(&return_value); |
| 2951 return_value.ToRegister(eax); | 2951 return_value.ToRegister(eax); |
| 2952 } else { | 2952 } else { |
| 2953 shadows[i]->Bind(); | 2953 shadows[i]->Bind(); |
| 2954 } | 2954 } |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3066 } | 3066 } |
| 3067 | 3067 |
| 3068 // Generate code to unlink and set the state for the (formerly) | 3068 // Generate code to unlink and set the state for the (formerly) |
| 3069 // shadowing targets that have been jumped to. | 3069 // shadowing targets that have been jumped to. |
| 3070 for (int i = 0; i < shadows.length(); i++) { | 3070 for (int i = 0; i < shadows.length(); i++) { |
| 3071 if (shadows[i]->is_linked()) { | 3071 if (shadows[i]->is_linked()) { |
| 3072 // If we have come from the shadowed return, the return value is | 3072 // If we have come from the shadowed return, the return value is |
| 3073 // on the virtual frame. We must preserve it until it is | 3073 // on the virtual frame. We must preserve it until it is |
| 3074 // pushed. | 3074 // pushed. |
| 3075 if (i == kReturnShadowIndex) { | 3075 if (i == kReturnShadowIndex) { |
| 3076 Result return_value(this); | 3076 Result return_value; |
| 3077 shadows[i]->Bind(&return_value); | 3077 shadows[i]->Bind(&return_value); |
| 3078 return_value.ToRegister(eax); | 3078 return_value.ToRegister(eax); |
| 3079 } else { | 3079 } else { |
| 3080 shadows[i]->Bind(); | 3080 shadows[i]->Bind(); |
| 3081 } | 3081 } |
| 3082 // Because we can be jumping here (to spilled code) from | 3082 // Because we can be jumping here (to spilled code) from |
| 3083 // unspilled code, we need to reestablish a spilled frame at | 3083 // unspilled code, we need to reestablish a spilled frame at |
| 3084 // this block. | 3084 // this block. |
| 3085 frame_->SpillAll(); | 3085 frame_->SpillAll(); |
| 3086 | 3086 |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3249 exit.Bind(); | 3249 exit.Bind(); |
| 3250 } | 3250 } |
| 3251 | 3251 |
| 3252 | 3252 |
| 3253 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 3253 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 3254 if (slot->type() == Slot::LOOKUP) { | 3254 if (slot->type() == Slot::LOOKUP) { |
| 3255 ASSERT(slot->var()->is_dynamic()); | 3255 ASSERT(slot->var()->is_dynamic()); |
| 3256 | 3256 |
| 3257 JumpTarget slow(this); | 3257 JumpTarget slow(this); |
| 3258 JumpTarget done(this); | 3258 JumpTarget done(this); |
| 3259 Result value(this); | 3259 Result value; |
| 3260 | 3260 |
| 3261 // Generate fast-case code for variables that might be shadowed by | 3261 // Generate fast-case code for variables that might be shadowed by |
| 3262 // eval-introduced variables. Eval is used a lot without | 3262 // eval-introduced variables. Eval is used a lot without |
| 3263 // introducing variables. In those cases, we do not want to | 3263 // introducing variables. In those cases, we do not want to |
| 3264 // perform a runtime call for all variables in the scope | 3264 // perform a runtime call for all variables in the scope |
| 3265 // containing the eval. | 3265 // containing the eval. |
| 3266 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | 3266 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 3267 value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow); | 3267 value = LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow); |
| 3268 // If there was no control flow to slow, we can exit early. | 3268 // If there was no control flow to slow, we can exit early. |
| 3269 if (!slow.is_linked()) { | 3269 if (!slow.is_linked()) { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3349 } | 3349 } |
| 3350 } | 3350 } |
| 3351 | 3351 |
| 3352 | 3352 |
| 3353 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( | 3353 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( |
| 3354 Slot* slot, | 3354 Slot* slot, |
| 3355 TypeofState typeof_state, | 3355 TypeofState typeof_state, |
| 3356 JumpTarget* slow) { | 3356 JumpTarget* slow) { |
| 3357 // Check that no extension objects have been created by calls to | 3357 // Check that no extension objects have been created by calls to |
| 3358 // eval from the current scope to the global scope. | 3358 // eval from the current scope to the global scope. |
| 3359 Result context(esi, this); | 3359 Result context(esi); |
| 3360 Result tmp = allocator_->Allocate(); | 3360 Result tmp = allocator_->Allocate(); |
| 3361 ASSERT(tmp.is_valid()); // All non-reserved registers were available. | 3361 ASSERT(tmp.is_valid()); // All non-reserved registers were available. |
| 3362 | 3362 |
| 3363 Scope* s = scope(); | 3363 Scope* s = scope(); |
| 3364 while (s != NULL) { | 3364 while (s != NULL) { |
| 3365 if (s->num_heap_slots() > 0) { | 3365 if (s->num_heap_slots() > 0) { |
| 3366 if (s->calls_eval()) { | 3366 if (s->calls_eval()) { |
| 3367 // Check that extension is NULL. | 3367 // Check that extension is NULL. |
| 3368 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX), | 3368 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX), |
| 3369 Immediate(0)); | 3369 Immediate(0)); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3424 | 3424 |
| 3425 | 3425 |
| 3426 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { | 3426 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { |
| 3427 if (slot->type() == Slot::LOOKUP) { | 3427 if (slot->type() == Slot::LOOKUP) { |
| 3428 ASSERT(slot->var()->is_dynamic()); | 3428 ASSERT(slot->var()->is_dynamic()); |
| 3429 | 3429 |
| 3430 // For now, just do a runtime call. | 3430 // For now, just do a runtime call. |
| 3431 frame_->Push(esi); | 3431 frame_->Push(esi); |
| 3432 frame_->Push(slot->var()->name()); | 3432 frame_->Push(slot->var()->name()); |
| 3433 | 3433 |
| 3434 Result value(this); | 3434 Result value; |
| 3435 if (init_state == CONST_INIT) { | 3435 if (init_state == CONST_INIT) { |
| 3436 // Same as the case for a normal store, but ignores attribute | 3436 // Same as the case for a normal store, but ignores attribute |
| 3437 // (e.g. READ_ONLY) of context slot so that we can initialize const | 3437 // (e.g. READ_ONLY) of context slot so that we can initialize const |
| 3438 // properties (introduced via eval("const foo = (some expr);")). Also, | 3438 // properties (introduced via eval("const foo = (some expr);")). Also, |
| 3439 // uses the current function context instead of the top context. | 3439 // uses the current function context instead of the top context. |
| 3440 // | 3440 // |
| 3441 // Note that we must declare the foo upon entry of eval(), via a | 3441 // Note that we must declare the foo upon entry of eval(), via a |
| 3442 // context slot declaration, but we cannot initialize it at the same | 3442 // context slot declaration, but we cannot initialize it at the same |
| 3443 // time, because the const declaration may be at the end of the eval | 3443 // time, because the const declaration may be at the end of the eval |
| 3444 // code (sigh...) and the const variable may have been used before | 3444 // code (sigh...) and the const variable may have been used before |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3567 } | 3567 } |
| 3568 | 3568 |
| 3569 virtual void Generate(); | 3569 virtual void Generate(); |
| 3570 | 3570 |
| 3571 private: | 3571 private: |
| 3572 RegExpLiteral* node_; | 3572 RegExpLiteral* node_; |
| 3573 }; | 3573 }; |
| 3574 | 3574 |
| 3575 | 3575 |
| 3576 void DeferredRegExpLiteral::Generate() { | 3576 void DeferredRegExpLiteral::Generate() { |
| 3577 Result literals(generator()); | 3577 Result literals; |
| 3578 enter()->Bind(&literals); | 3578 enter()->Bind(&literals); |
| 3579 // Since the entry is undefined we call the runtime system to | 3579 // Since the entry is undefined we call the runtime system to |
| 3580 // compute the literal. | 3580 // compute the literal. |
| 3581 | 3581 |
| 3582 VirtualFrame* frame = generator()->frame(); | 3582 VirtualFrame* frame = generator()->frame(); |
| 3583 // Literal array (0). | 3583 // Literal array (0). |
| 3584 frame->Push(&literals); | 3584 frame->Push(&literals); |
| 3585 // Literal index (1). | 3585 // Literal index (1). |
| 3586 frame->Push(Smi::FromInt(node_->literal_index())); | 3586 frame->Push(Smi::FromInt(node_->literal_index())); |
| 3587 // RegExp pattern (2). | 3587 // RegExp pattern (2). |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3644 } | 3644 } |
| 3645 | 3645 |
| 3646 virtual void Generate(); | 3646 virtual void Generate(); |
| 3647 | 3647 |
| 3648 private: | 3648 private: |
| 3649 ObjectLiteral* node_; | 3649 ObjectLiteral* node_; |
| 3650 }; | 3650 }; |
| 3651 | 3651 |
| 3652 | 3652 |
| 3653 void DeferredObjectLiteral::Generate() { | 3653 void DeferredObjectLiteral::Generate() { |
| 3654 Result literals(generator()); | 3654 Result literals; |
| 3655 enter()->Bind(&literals); | 3655 enter()->Bind(&literals); |
| 3656 // Since the entry is undefined we call the runtime system to | 3656 // Since the entry is undefined we call the runtime system to |
| 3657 // compute the literal. | 3657 // compute the literal. |
| 3658 | 3658 |
| 3659 VirtualFrame* frame = generator()->frame(); | 3659 VirtualFrame* frame = generator()->frame(); |
| 3660 // Literal array (0). | 3660 // Literal array (0). |
| 3661 frame->Push(&literals); | 3661 frame->Push(&literals); |
| 3662 // Literal index (1). | 3662 // Literal index (1). |
| 3663 frame->Push(Smi::FromInt(node_->literal_index())); | 3663 frame->Push(Smi::FromInt(node_->literal_index())); |
| 3664 // Constant properties (2). | 3664 // Constant properties (2). |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3782 } | 3782 } |
| 3783 | 3783 |
| 3784 virtual void Generate(); | 3784 virtual void Generate(); |
| 3785 | 3785 |
| 3786 private: | 3786 private: |
| 3787 ArrayLiteral* node_; | 3787 ArrayLiteral* node_; |
| 3788 }; | 3788 }; |
| 3789 | 3789 |
| 3790 | 3790 |
| 3791 void DeferredArrayLiteral::Generate() { | 3791 void DeferredArrayLiteral::Generate() { |
| 3792 Result literals(generator()); | 3792 Result literals; |
| 3793 enter()->Bind(&literals); | 3793 enter()->Bind(&literals); |
| 3794 // Since the entry is undefined we call the runtime system to | 3794 // Since the entry is undefined we call the runtime system to |
| 3795 // compute the literal. | 3795 // compute the literal. |
| 3796 | 3796 |
| 3797 VirtualFrame* frame = generator()->frame(); | 3797 VirtualFrame* frame = generator()->frame(); |
| 3798 // Literal array (0). | 3798 // Literal array (0). |
| 3799 frame->Push(&literals); | 3799 frame->Push(&literals); |
| 3800 // Literal index (1). | 3800 // Literal index (1). |
| 3801 frame->Push(Smi::FromInt(node_->literal_index())); | 3801 frame->Push(Smi::FromInt(node_->literal_index())); |
| 3802 // Constant properties (2). | 3802 // Constant properties (2). |
| (...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4431 value.Unuse(); | 4431 value.Unuse(); |
| 4432 temp.Unuse(); | 4432 temp.Unuse(); |
| 4433 destination()->Split(equal); | 4433 destination()->Split(equal); |
| 4434 } | 4434 } |
| 4435 | 4435 |
| 4436 | 4436 |
| 4437 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { | 4437 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { |
| 4438 ASSERT(args->length() == 0); | 4438 ASSERT(args->length() == 0); |
| 4439 // ArgumentsAccessStub takes the parameter count as an input argument | 4439 // ArgumentsAccessStub takes the parameter count as an input argument |
| 4440 // in register eax. Create a constant result for it. | 4440 // in register eax. Create a constant result for it. |
| 4441 Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters())), this); | 4441 Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters()))); |
| 4442 // Call the shared stub to get to the arguments.length. | 4442 // Call the shared stub to get to the arguments.length. |
| 4443 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); | 4443 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
| 4444 Result result = frame_->CallStub(&stub, &count); | 4444 Result result = frame_->CallStub(&stub, &count); |
| 4445 frame_->Push(&result); | 4445 frame_->Push(&result); |
| 4446 } | 4446 } |
| 4447 | 4447 |
| 4448 | 4448 |
| 4449 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 4449 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| 4450 ASSERT(args->length() == 1); | 4450 ASSERT(args->length() == 1); |
| 4451 JumpTarget leave(this); | 4451 JumpTarget leave(this); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4514 | 4514 |
| 4515 | 4515 |
| 4516 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 4516 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
| 4517 ASSERT(args->length() == 1); | 4517 ASSERT(args->length() == 1); |
| 4518 | 4518 |
| 4519 // ArgumentsAccessStub expects the key in edx and the formal | 4519 // ArgumentsAccessStub expects the key in edx and the formal |
| 4520 // parameter count in eax. | 4520 // parameter count in eax. |
| 4521 Load(args->at(0)); | 4521 Load(args->at(0)); |
| 4522 Result key = frame_->Pop(); | 4522 Result key = frame_->Pop(); |
| 4523 // Explicitly create a constant result. | 4523 // Explicitly create a constant result. |
| 4524 Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters())), this); | 4524 Result count(Handle<Smi>(Smi::FromInt(scope_->num_parameters()))); |
| 4525 // Call the shared stub to get to arguments[key]. | 4525 // Call the shared stub to get to arguments[key]. |
| 4526 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 4526 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 4527 Result result = frame_->CallStub(&stub, &key, &count); | 4527 Result result = frame_->CallStub(&stub, &key, &count); |
| 4528 frame_->Push(&result); | 4528 frame_->Push(&result); |
| 4529 } | 4529 } |
| 4530 | 4530 |
| 4531 | 4531 |
| 4532 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 4532 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
| 4533 ASSERT(args->length() == 2); | 4533 ASSERT(args->length() == 2); |
| 4534 | 4534 |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4764 | 4764 |
| 4765 private: | 4765 private: |
| 4766 bool is_postfix_; | 4766 bool is_postfix_; |
| 4767 bool is_increment_; | 4767 bool is_increment_; |
| 4768 int target_size_; | 4768 int target_size_; |
| 4769 }; | 4769 }; |
| 4770 | 4770 |
| 4771 | 4771 |
| 4772 void DeferredCountOperation::Generate() { | 4772 void DeferredCountOperation::Generate() { |
| 4773 CodeGenerator* cgen = generator(); | 4773 CodeGenerator* cgen = generator(); |
| 4774 Result value(cgen); | 4774 Result value; |
| 4775 enter()->Bind(&value); | 4775 enter()->Bind(&value); |
| 4776 VirtualFrame* frame = cgen->frame(); | 4776 VirtualFrame* frame = cgen->frame(); |
| 4777 // Undo the optimistic smi operation. | 4777 // Undo the optimistic smi operation. |
| 4778 value.ToRegister(); | 4778 value.ToRegister(); |
| 4779 frame->Spill(value.reg()); | 4779 frame->Spill(value.reg()); |
| 4780 if (is_increment_) { | 4780 if (is_increment_) { |
| 4781 __ sub(Operand(value.reg()), Immediate(Smi::FromInt(1))); | 4781 __ sub(Operand(value.reg()), Immediate(Smi::FromInt(1))); |
| 4782 } else { | 4782 } else { |
| 4783 __ add(Operand(value.reg()), Immediate(Smi::FromInt(1))); | 4783 __ add(Operand(value.reg()), Immediate(Smi::FromInt(1))); |
| 4784 } | 4784 } |
| (...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5262 Label* patch_site() { return &patch_site_; } | 5262 Label* patch_site() { return &patch_site_; } |
| 5263 | 5263 |
| 5264 private: | 5264 private: |
| 5265 Label patch_site_; | 5265 Label patch_site_; |
| 5266 Handle<String> name_; | 5266 Handle<String> name_; |
| 5267 }; | 5267 }; |
| 5268 | 5268 |
| 5269 | 5269 |
| 5270 void DeferredReferenceGetNamedValue::Generate() { | 5270 void DeferredReferenceGetNamedValue::Generate() { |
| 5271 CodeGenerator* cgen = generator(); | 5271 CodeGenerator* cgen = generator(); |
| 5272 Result receiver(cgen); | 5272 Result receiver; |
| 5273 enter()->Bind(&receiver); | 5273 enter()->Bind(&receiver); |
| 5274 | 5274 |
| 5275 cgen->frame()->Push(&receiver); | 5275 cgen->frame()->Push(&receiver); |
| 5276 cgen->frame()->Push(name_); | 5276 cgen->frame()->Push(name_); |
| 5277 Result answer = cgen->frame()->CallLoadIC(RelocInfo::CODE_TARGET); | 5277 Result answer = cgen->frame()->CallLoadIC(RelocInfo::CODE_TARGET); |
| 5278 // The call must be followed by a test eax instruction to indicate | 5278 // The call must be followed by a test eax instruction to indicate |
| 5279 // that the inobject property case was inlined. | 5279 // that the inobject property case was inlined. |
| 5280 ASSERT(answer.is_register() && answer.reg().is(eax)); | 5280 ASSERT(answer.is_register() && answer.reg().is(eax)); |
| 5281 // Store the delta to the map check instruction here in the test instruction. | 5281 // Store the delta to the map check instruction here in the test instruction. |
| 5282 // Use masm_-> instead of the double underscore macro since the latter can't | 5282 // Use masm_-> instead of the double underscore macro since the latter can't |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 5304 Label* patch_site() { return &patch_site_; } | 5304 Label* patch_site() { return &patch_site_; } |
| 5305 | 5305 |
| 5306 private: | 5306 private: |
| 5307 Label patch_site_; | 5307 Label patch_site_; |
| 5308 bool is_global_; | 5308 bool is_global_; |
| 5309 }; | 5309 }; |
| 5310 | 5310 |
| 5311 | 5311 |
| 5312 void DeferredReferenceGetKeyedValue::Generate() { | 5312 void DeferredReferenceGetKeyedValue::Generate() { |
| 5313 CodeGenerator* cgen = generator(); | 5313 CodeGenerator* cgen = generator(); |
| 5314 Result receiver(cgen); | 5314 Result receiver; |
| 5315 Result key(cgen); | 5315 Result key; |
| 5316 enter()->Bind(&receiver, &key); | 5316 enter()->Bind(&receiver, &key); |
| 5317 cgen->frame()->Push(&receiver); // First IC argument. | 5317 cgen->frame()->Push(&receiver); // First IC argument. |
| 5318 cgen->frame()->Push(&key); // Second IC argument. | 5318 cgen->frame()->Push(&key); // Second IC argument. |
| 5319 | 5319 |
| 5320 // Calculate the delta from the IC call instruction to the map check | 5320 // Calculate the delta from the IC call instruction to the map check |
| 5321 // cmp instruction in the inlined version. This delta is stored in | 5321 // cmp instruction in the inlined version. This delta is stored in |
| 5322 // a test(eax, delta) instruction after the call so that we can find | 5322 // a test(eax, delta) instruction after the call so that we can find |
| 5323 // it in the IC initialization code and patch the cmp instruction. | 5323 // it in the IC initialization code and patch the cmp instruction. |
| 5324 // This means that we cannot allow test instructions after calls to | 5324 // This means that we cannot allow test instructions after calls to |
| 5325 // KeyedLoadIC stubs in other places. | 5325 // KeyedLoadIC stubs in other places. |
| (...skipping 1912 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7238 | 7238 |
| 7239 // Slow-case: Go through the JavaScript implementation. | 7239 // Slow-case: Go through the JavaScript implementation. |
| 7240 __ bind(&slow); | 7240 __ bind(&slow); |
| 7241 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 7241 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 7242 } | 7242 } |
| 7243 | 7243 |
| 7244 | 7244 |
| 7245 #undef __ | 7245 #undef __ |
| 7246 | 7246 |
| 7247 } } // namespace v8::internal | 7247 } } // namespace v8::internal |
| OLD | NEW |