Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 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 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 431 ExternalReference stack_guard_limit = | 431 ExternalReference stack_guard_limit = |
| 432 ExternalReference::address_of_stack_guard_limit(); | 432 ExternalReference::address_of_stack_guard_limit(); |
| 433 __ movq(kScratchRegister, stack_guard_limit); | 433 __ movq(kScratchRegister, stack_guard_limit); |
| 434 __ cmpq(rsp, Operand(kScratchRegister, 0)); | 434 __ cmpq(rsp, Operand(kScratchRegister, 0)); |
| 435 deferred->Branch(below); | 435 deferred->Branch(below); |
| 436 deferred->BindExit(); | 436 deferred->BindExit(); |
| 437 } | 437 } |
| 438 } | 438 } |
| 439 | 439 |
| 440 | 440 |
| 441 void CodeGenerator::VisitAndSpill(Statement* statement) { | |
| 442 // TODO(X64): No architecture specific code. Move to shared location. | |
| 443 ASSERT(in_spilled_code()); | |
| 444 set_in_spilled_code(false); | |
| 445 Visit(statement); | |
| 446 if (frame_ != NULL) { | |
| 447 frame_->SpillAll(); | |
| 448 } | |
| 449 set_in_spilled_code(true); | |
| 450 } | |
| 451 | |
| 452 | |
| 441 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { | 453 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { |
| 442 ASSERT(!in_spilled_code()); | 454 ASSERT(!in_spilled_code()); |
| 443 for (int i = 0; has_valid_frame() && i < statements->length(); i++) { | 455 for (int i = 0; has_valid_frame() && i < statements->length(); i++) { |
| 444 Visit(statements->at(i)); | 456 Visit(statements->at(i)); |
| 445 } | 457 } |
| 446 } | 458 } |
| 447 | 459 |
| 448 | 460 |
| 449 void CodeGenerator::VisitBlock(Block* node) { | 461 void CodeGenerator::VisitBlock(Block* node) { |
| 450 ASSERT(!in_spilled_code()); | 462 ASSERT(!in_spilled_code()); |
| (...skipping 563 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1014 break; | 1026 break; |
| 1015 } | 1027 } |
| 1016 } | 1028 } |
| 1017 | 1029 |
| 1018 DecrementLoopNesting(); | 1030 DecrementLoopNesting(); |
| 1019 node->continue_target()->Unuse(); | 1031 node->continue_target()->Unuse(); |
| 1020 node->break_target()->Unuse(); | 1032 node->break_target()->Unuse(); |
| 1021 } | 1033 } |
| 1022 | 1034 |
| 1023 | 1035 |
| 1024 void CodeGenerator::VisitForInStatement(ForInStatement* a) { | 1036 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| 1025 UNIMPLEMENTED(); | 1037 ASSERT(!in_spilled_code()); |
| 1038 VirtualFrame::SpilledScope spilled_scope; | |
| 1039 Comment cmnt(masm_, "[ ForInStatement"); | |
| 1040 CodeForStatementPosition(node); | |
| 1041 | |
| 1042 JumpTarget primitive; | |
| 1043 JumpTarget jsobject; | |
| 1044 JumpTarget fixed_array; | |
| 1045 JumpTarget entry(JumpTarget::BIDIRECTIONAL); | |
| 1046 JumpTarget end_del_check; | |
| 1047 JumpTarget exit; | |
| 1048 | |
| 1049 // Get the object to enumerate over (converted to JSObject). | |
| 1050 LoadAndSpill(node->enumerable()); | |
| 1051 | |
| 1052 // Both SpiderMonkey and kjs ignore null and undefined in contrast | |
| 1053 // to the specification. 12.6.4 mandates a call to ToObject. | |
| 1054 frame_->EmitPop(rax); | |
| 1055 | |
| 1056 // rax: value to be iterated over | |
| 1057 __ Cmp(rax, Factory::undefined_value()); | |
| 1058 exit.Branch(equal); | |
| 1059 __ Cmp(rax, Factory::null_value()); | |
| 1060 exit.Branch(equal); | |
| 1061 | |
| 1062 // Stack layout in body: | |
| 1063 // [iteration counter (smi)] <- slot 0 | |
| 1064 // [length of array] <- slot 1 | |
| 1065 // [FixedArray] <- slot 2 | |
| 1066 // [Map or 0] <- slot 3 | |
| 1067 // [Object] <- slot 4 | |
| 1068 | |
| 1069 // Check if enumerable is already a JSObject | |
| 1070 // rax: value to be iterated over | |
| 1071 __ testl(rax, Immediate(kSmiTagMask)); | |
| 1072 primitive.Branch(zero); | |
| 1073 __ movq(rcx, FieldOperand(rax, HeapObject::kMapOffset)); | |
| 1074 __ movzxbq(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset)); | |
| 1075 __ cmpq(rcx, Immediate(FIRST_JS_OBJECT_TYPE)); | |
|
William Hesse
2009/06/25 22:39:10
Why not CmpObjectType macro? Or why not movb and
| |
| 1076 jsobject.Branch(above_equal); | |
| 1077 | |
| 1078 primitive.Bind(); | |
| 1079 frame_->EmitPush(rax); | |
| 1080 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1); | |
| 1081 // function call returns the value in rax, which is where we want it below | |
| 1082 | |
| 1083 jsobject.Bind(); | |
| 1084 // Get the set of properties (as a FixedArray or Map). | |
| 1085 // rax: value to be iterated over | |
| 1086 frame_->EmitPush(rax); // push the object being iterated over (slot 4) | |
| 1087 | |
| 1088 frame_->EmitPush(rax); // push the Object (slot 4) for the runtime call | |
| 1089 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); | |
| 1090 | |
| 1091 // If we got a Map, we can do a fast modification check. | |
| 1092 // Otherwise, we got a FixedArray, and we have to do a slow check. | |
| 1093 // rax: map or fixed array (result from call to | |
| 1094 // Runtime::kGetPropertyNamesFast) | |
| 1095 __ movq(rdx, rax); | |
| 1096 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset)); | |
| 1097 __ Cmp(rcx, Factory::meta_map()); | |
| 1098 fixed_array.Branch(not_equal); | |
| 1099 | |
| 1100 // Get enum cache | |
| 1101 // rax: map (result from call to Runtime::kGetPropertyNamesFast) | |
| 1102 __ movq(rcx, rax); | |
| 1103 __ movq(rcx, FieldOperand(rcx, Map::kInstanceDescriptorsOffset)); | |
| 1104 // Get the bridge array held in the enumeration index field. | |
| 1105 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset)); | |
| 1106 // Get the cache from the bridge array. | |
| 1107 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | |
| 1108 | |
| 1109 frame_->EmitPush(rax); // <- slot 3 | |
| 1110 frame_->EmitPush(rdx); // <- slot 2 | |
| 1111 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset)); | |
| 1112 __ shl(rax, Immediate(kSmiTagSize)); | |
| 1113 frame_->EmitPush(rax); // <- slot 1 | |
| 1114 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0 | |
| 1115 entry.Jump(); | |
| 1116 | |
| 1117 fixed_array.Bind(); | |
| 1118 // rax: fixed array (result from call to Runtime::kGetPropertyNamesFast) | |
| 1119 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 3 | |
| 1120 frame_->EmitPush(rax); // <- slot 2 | |
| 1121 | |
| 1122 // Push the length of the array and the initial index onto the stack. | |
| 1123 __ movq(rax, FieldOperand(rax, FixedArray::kLengthOffset)); | |
| 1124 __ shl(rax, Immediate(kSmiTagSize)); | |
| 1125 frame_->EmitPush(rax); // <- slot 1 | |
| 1126 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0 | |
| 1127 | |
| 1128 // Condition. | |
| 1129 entry.Bind(); | |
| 1130 // Grab the current frame's height for the break and continue | |
| 1131 // targets only after all the state is pushed on the frame. | |
| 1132 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); | |
| 1133 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); | |
| 1134 | |
| 1135 __ movq(rax, frame_->ElementAt(0)); // load the current count | |
| 1136 __ cmpq(rax, frame_->ElementAt(1)); // compare to the array length | |
| 1137 node->break_target()->Branch(above_equal); | |
| 1138 | |
| 1139 // Get the i'th entry of the array. | |
| 1140 __ movq(rdx, frame_->ElementAt(2)); | |
| 1141 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | |
| 1142 // Multiplier is times_4 since rax is already a Smi. | |
| 1143 __ movq(rbx, Operand(rdx, rax, times_4, | |
| 1144 FixedArray::kHeaderSize - kHeapObjectTag)); | |
| 1145 | |
| 1146 // Get the expected map from the stack or a zero map in the | |
| 1147 // permanent slow case rax: current iteration count rbx: i'th entry | |
| 1148 // of the enum cache | |
| 1149 __ movq(rdx, frame_->ElementAt(3)); | |
| 1150 // Check if the expected map still matches that of the enumerable. | |
| 1151 // If not, we have to filter the key. | |
| 1152 // rax: current iteration count | |
| 1153 // rbx: i'th entry of the enum cache | |
| 1154 // rdx: expected map value | |
| 1155 __ movq(rcx, frame_->ElementAt(4)); | |
| 1156 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); | |
| 1157 __ cmpq(rcx, rdx); | |
| 1158 end_del_check.Branch(equal); | |
| 1159 | |
| 1160 // Convert the entry to a string (or null if it isn't a property anymore). | |
| 1161 frame_->EmitPush(frame_->ElementAt(4)); // push enumerable | |
| 1162 frame_->EmitPush(rbx); // push entry | |
| 1163 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); | |
| 1164 __ movq(rbx, rax); | |
| 1165 | |
| 1166 // If the property has been removed while iterating, we just skip it. | |
| 1167 __ Cmp(rbx, Factory::null_value()); | |
| 1168 node->continue_target()->Branch(equal); | |
| 1169 | |
| 1170 end_del_check.Bind(); | |
| 1171 // Store the entry in the 'each' expression and take another spin in the | |
| 1172 // loop. rdx: i'th entry of the enum cache (or string there of) | |
| 1173 frame_->EmitPush(rbx); | |
| 1174 { Reference each(this, node->each()); | |
| 1175 // Loading a reference may leave the frame in an unspilled state. | |
| 1176 frame_->SpillAll(); | |
| 1177 if (!each.is_illegal()) { | |
| 1178 if (each.size() > 0) { | |
| 1179 frame_->EmitPush(frame_->ElementAt(each.size())); | |
| 1180 } | |
| 1181 // If the reference was to a slot we rely on the convenient property | |
| 1182 // that it doesn't matter whether a value (eg, ebx pushed above) is | |
| 1183 // right on top of or right underneath a zero-sized reference. | |
| 1184 each.SetValue(NOT_CONST_INIT); | |
| 1185 if (each.size() > 0) { | |
| 1186 // It's safe to pop the value lying on top of the reference before | |
| 1187 // unloading the reference itself (which preserves the top of stack, | |
| 1188 // ie, now the topmost value of the non-zero sized reference), since | |
| 1189 // we will discard the top of stack after unloading the reference | |
| 1190 // anyway. | |
| 1191 frame_->Drop(); | |
| 1192 } | |
| 1193 } | |
| 1194 } | |
| 1195 // Unloading a reference may leave the frame in an unspilled state. | |
| 1196 frame_->SpillAll(); | |
| 1197 | |
| 1198 // Discard the i'th entry pushed above or else the remainder of the | |
| 1199 // reference, whichever is currently on top of the stack. | |
| 1200 frame_->Drop(); | |
| 1201 | |
| 1202 // Body. | |
| 1203 CheckStack(); // TODO(1222600): ignore if body contains calls. | |
| 1204 VisitAndSpill(node->body()); | |
| 1205 | |
| 1206 // Next. Reestablish a spilled frame in case we are coming here via | |
| 1207 // a continue in the body. | |
| 1208 node->continue_target()->Bind(); | |
|
William Hesse
2009/06/25 22:39:10
// TODO(make an issue?) Consider making a SpilledT
| |
| 1209 frame_->SpillAll(); | |
| 1210 frame_->EmitPop(rax); | |
| 1211 __ addq(rax, Immediate(Smi::FromInt(1))); | |
| 1212 frame_->EmitPush(rax); | |
| 1213 entry.Jump(); | |
| 1214 | |
| 1215 // Cleanup. No need to spill because VirtualFrame::Drop is safe for | |
| 1216 // any frame. | |
| 1217 node->break_target()->Bind(); | |
| 1218 frame_->Drop(5); | |
| 1219 | |
| 1220 // Exit. | |
| 1221 exit.Bind(); | |
| 1222 | |
| 1223 node->continue_target()->Unuse(); | |
| 1224 node->break_target()->Unuse(); | |
| 1026 } | 1225 } |
| 1027 | 1226 |
| 1028 void CodeGenerator::VisitTryCatch(TryCatch* a) { | 1227 void CodeGenerator::VisitTryCatch(TryCatch* a) { |
| 1029 UNIMPLEMENTED(); | 1228 UNIMPLEMENTED(); |
| 1030 } | 1229 } |
| 1031 | 1230 |
| 1032 void CodeGenerator::VisitTryFinally(TryFinally* a) { | 1231 void CodeGenerator::VisitTryFinally(TryFinally* a) { |
| 1033 UNIMPLEMENTED(); | 1232 UNIMPLEMENTED(); |
| 1034 } | 1233 } |
| 1035 | 1234 |
| (...skipping 1549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2585 } | 2784 } |
| 2586 | 2785 |
| 2587 | 2786 |
| 2588 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 2787 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| 2589 UNIMPLEMENTED(); | 2788 UNIMPLEMENTED(); |
| 2590 } | 2789 } |
| 2591 | 2790 |
| 2592 // ----------------------------------------------------------------------------- | 2791 // ----------------------------------------------------------------------------- |
| 2593 // CodeGenerator implementation of Expressions | 2792 // CodeGenerator implementation of Expressions |
| 2594 | 2793 |
| 2794 void CodeGenerator::LoadAndSpill(Expression* expression, | |
| 2795 TypeofState typeof_state) { | |
| 2796 // TODO(x64): No architecture specific code. Move to shared location. | |
| 2797 ASSERT(in_spilled_code()); | |
| 2798 set_in_spilled_code(false); | |
| 2799 Load(expression, typeof_state); | |
| 2800 frame_->SpillAll(); | |
| 2801 set_in_spilled_code(true); | |
| 2802 } | |
| 2803 | |
| 2804 | |
| 2595 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 2805 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 2596 #ifdef DEBUG | 2806 #ifdef DEBUG |
| 2597 int original_height = frame_->height(); | 2807 int original_height = frame_->height(); |
| 2598 #endif | 2808 #endif |
| 2599 ASSERT(!in_spilled_code()); | 2809 ASSERT(!in_spilled_code()); |
| 2600 JumpTarget true_target; | 2810 JumpTarget true_target; |
| 2601 JumpTarget false_target; | 2811 JumpTarget false_target; |
| 2602 ControlDestination dest(&true_target, &false_target, true); | 2812 ControlDestination dest(&true_target, &false_target, true); |
| 2603 LoadCondition(x, typeof_state, &dest, false); | 2813 LoadCondition(x, typeof_state, &dest, false); |
| 2604 | 2814 |
| (...skipping 3199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5804 break; | 6014 break; |
| 5805 default: | 6015 default: |
| 5806 UNREACHABLE(); | 6016 UNREACHABLE(); |
| 5807 } | 6017 } |
| 5808 } | 6018 } |
| 5809 | 6019 |
| 5810 | 6020 |
| 5811 #undef __ | 6021 #undef __ |
| 5812 | 6022 |
| 5813 } } // namespace v8::internal | 6023 } } // namespace v8::internal |
| OLD | NEW |