OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 891 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
902 int LCodeGen::GetNextEmittedBlock(int block) { | 902 int LCodeGen::GetNextEmittedBlock(int block) { |
903 for (int i = block + 1; i < graph()->blocks()->length(); ++i) { | 903 for (int i = block + 1; i < graph()->blocks()->length(); ++i) { |
904 LLabel* label = chunk_->GetLabel(i); | 904 LLabel* label = chunk_->GetLabel(i); |
905 if (!label->HasReplacement()) return i; | 905 if (!label->HasReplacement()) return i; |
906 } | 906 } |
907 return -1; | 907 return -1; |
908 } | 908 } |
909 | 909 |
910 | 910 |
911 void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) { | 911 void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) { |
912 Abort("Unimplemented: %s", "EmitBranch"); | 912 int next_block = GetNextEmittedBlock(current_block_); |
913 right_block = chunk_->LookupDestination(right_block); | |
914 left_block = chunk_->LookupDestination(left_block); | |
915 | |
916 if (right_block == left_block) { | |
917 EmitGoto(left_block); | |
918 } else if (left_block == next_block) { | |
919 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block)); | |
920 } else if (right_block == next_block) { | |
921 __ j(cc, chunk_->GetAssemblyLabel(left_block)); | |
922 } else { | |
923 __ j(cc, chunk_->GetAssemblyLabel(left_block)); | |
924 if (cc != always) { | |
925 __ jmp(chunk_->GetAssemblyLabel(right_block)); | |
926 } | |
927 } | |
913 } | 928 } |
914 | 929 |
915 | 930 |
916 void LCodeGen::DoBranch(LBranch* instr) { | 931 void LCodeGen::DoBranch(LBranch* instr) { |
917 Abort("Unimplemented: %s", "DoBranch"); | 932 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
933 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
934 | |
935 Representation r = instr->hydrogen()->representation(); | |
936 if (r.IsInteger32()) { | |
937 Register reg = ToRegister(instr->InputAt(0)); | |
938 __ testl(reg, reg); | |
939 EmitBranch(true_block, false_block, not_zero); | |
940 } else if (r.IsDouble()) { | |
941 XMMRegister reg = ToDoubleRegister(instr->InputAt(0)); | |
942 __ xorpd(xmm0, xmm0); | |
943 __ ucomisd(reg, xmm0); | |
944 EmitBranch(true_block, false_block, not_equal); | |
945 } else { | |
946 ASSERT(r.IsTagged()); | |
947 Register reg = ToRegister(instr->InputAt(0)); | |
948 HType type = instr->hydrogen()->type(); | |
949 if (type.IsBoolean()) { | |
950 __ Cmp(reg, Factory::true_value()); | |
951 EmitBranch(true_block, false_block, equal); | |
952 } else if (type.IsSmi()) { | |
953 __ SmiCompare(reg, Smi::FromInt(0)); | |
954 EmitBranch(true_block, false_block, not_equal); | |
955 } else { | |
956 Label* true_label = chunk_->GetAssemblyLabel(true_block); | |
957 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
958 | |
959 __ Cmp(reg, Factory::undefined_value()); | |
960 __ j(equal, false_label); | |
961 __ Cmp(reg, Factory::true_value()); | |
962 __ j(equal, true_label); | |
963 __ Cmp(reg, Factory::false_value()); | |
964 __ j(equal, false_label); | |
965 __ SmiCompare(reg, Smi::FromInt(0)); | |
966 __ j(equal, false_label); | |
967 __ JumpIfSmi(reg, true_label); | |
968 | |
969 // Test for double values. Plus/minus zero are false. NaN is handled | |
970 // in the stub. | |
971 NearLabel call_stub; | |
972 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), | |
973 Factory::heap_number_map()); | |
974 __ j(not_equal, &call_stub); | |
975 __ movq(kScratchRegister, FieldOperand(reg, HeapNumber::kValueOffset)); | |
976 __ shl(kScratchRegister, Immediate(1)); // Shift out the sign bit. | |
977 __ j(zero, false_label); // Zero or negative zero. | |
978 __ jmp(true_label); | |
979 | |
980 // The conversion stub doesn't cause garbage collections so it's | |
981 // safe to not record a safepoint after the call. | |
982 __ bind(&call_stub); | |
983 ToBooleanStub stub; | |
984 __ Pushad(); | |
985 __ push(reg); | |
986 __ CallStub(&stub); | |
987 __ testq(rax, rax); | |
988 __ Popad(); | |
989 EmitBranch(true_block, false_block, not_zero); | |
990 } | |
991 } | |
918 } | 992 } |
919 | 993 |
920 | 994 |
921 void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) { | 995 void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) { |
922 block = chunk_->LookupDestination(block); | 996 block = chunk_->LookupDestination(block); |
923 int next_block = GetNextEmittedBlock(current_block_); | 997 int next_block = GetNextEmittedBlock(current_block_); |
924 if (block != next_block) { | 998 if (block != next_block) { |
925 // Perform stack overflow check if this goto needs it before jumping. | 999 // Perform stack overflow check if this goto needs it before jumping. |
926 if (deferred_stack_check != NULL) { | 1000 if (deferred_stack_check != NULL) { |
927 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 1001 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
(...skipping 23 matching lines...) Expand all Loading... | |
951 }; | 1025 }; |
952 | 1026 |
953 DeferredStackCheck* deferred = NULL; | 1027 DeferredStackCheck* deferred = NULL; |
954 if (instr->include_stack_check()) { | 1028 if (instr->include_stack_check()) { |
955 deferred = new DeferredStackCheck(this, instr); | 1029 deferred = new DeferredStackCheck(this, instr); |
956 } | 1030 } |
957 EmitGoto(instr->block_id(), deferred); | 1031 EmitGoto(instr->block_id(), deferred); |
958 } | 1032 } |
959 | 1033 |
960 | 1034 |
961 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { | 1035 inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { |
William Hesse
2011/01/18 14:01:50
If this is inline, it should be defined in the hea
Lasse Reichstein
2011/01/19 09:20:35
It's only used in this file, so it's declared here
| |
962 Condition cond = no_condition; | 1036 Condition cond = no_condition; |
963 switch (op) { | 1037 switch (op) { |
964 case Token::EQ: | 1038 case Token::EQ: |
965 case Token::EQ_STRICT: | 1039 case Token::EQ_STRICT: |
966 cond = equal; | 1040 cond = equal; |
967 break; | 1041 break; |
968 case Token::LT: | 1042 case Token::LT: |
969 cond = is_unsigned ? below : less; | 1043 cond = is_unsigned ? below : less; |
970 break; | 1044 break; |
971 case Token::GT: | 1045 case Token::GT: |
972 cond = is_unsigned ? above : greater; | 1046 cond = is_unsigned ? above : greater; |
973 break; | 1047 break; |
974 case Token::LTE: | 1048 case Token::LTE: |
975 cond = is_unsigned ? below_equal : less_equal; | 1049 cond = is_unsigned ? below_equal : less_equal; |
976 break; | 1050 break; |
977 case Token::GTE: | 1051 case Token::GTE: |
978 cond = is_unsigned ? above_equal : greater_equal; | 1052 cond = is_unsigned ? above_equal : greater_equal; |
979 break; | 1053 break; |
980 case Token::IN: | 1054 case Token::IN: |
981 case Token::INSTANCEOF: | 1055 case Token::INSTANCEOF: |
982 default: | 1056 default: |
983 UNREACHABLE(); | 1057 UNREACHABLE(); |
984 } | 1058 } |
985 return cond; | 1059 return cond; |
986 } | 1060 } |
987 | 1061 |
988 | 1062 |
989 void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { | 1063 void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { |
990 Abort("Unimplemented: %s", "EmitCmpI"); | 1064 if (right->IsConstantOperand()) { |
1065 if (left->IsRegister()) { | |
1066 __ Cmp(ToRegister(left), ToHandle(LConstantOperand::cast(right))); | |
William Hesse
2011/01/18 14:01:50
Shouldn't you use Immediate(Int32Value(LConstantOp
Lasse Reichstein
2011/01/19 09:20:35
I probably should. We know that the constant is a
| |
1067 } else { | |
1068 __ Cmp(ToOperand(left), ToHandle(LConstantOperand::cast(right))); | |
1069 } | |
1070 } else if (right->IsRegister()) { | |
1071 __ cmpq(ToRegister(left), ToRegister(right)); | |
1072 } else { | |
1073 __ cmpq(ToRegister(left), ToOperand(right)); | |
1074 } | |
991 } | 1075 } |
992 | 1076 |
993 | 1077 |
994 void LCodeGen::DoCmpID(LCmpID* instr) { | 1078 void LCodeGen::DoCmpID(LCmpID* instr) { |
995 Abort("Unimplemented: %s", "DoCmpID"); | 1079 LOperand* left = instr->InputAt(0); |
1080 LOperand* right = instr->InputAt(1); | |
1081 LOperand* result = instr->result(); | |
1082 | |
1083 NearLabel unordered; | |
1084 if (instr->is_double()) { | |
1085 // Don't base result on EFLAGS when a NaN is involved. Instead | |
1086 // jump to the unordered case, which produces a false value. | |
1087 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); | |
1088 __ j(parity_even, &unordered); | |
1089 } else { | |
1090 EmitCmpI(left, right); | |
1091 } | |
1092 | |
1093 NearLabel done; | |
1094 Condition cc = TokenToCondition(instr->op(), instr->is_double()); | |
1095 __ LoadRoot(ToRegister(result), Heap::kTrueValueRootIndex); | |
1096 __ j(cc, &done); | |
1097 | |
1098 __ bind(&unordered); | |
1099 __ LoadRoot(ToRegister(result), Heap::kFalseValueRootIndex); | |
1100 __ bind(&done); | |
996 } | 1101 } |
997 | 1102 |
998 | 1103 |
999 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { | 1104 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
1000 Abort("Unimplemented: %s", "DoCmpIDAndBranch"); | 1105 LOperand* left = instr->InputAt(0); |
1106 LOperand* right = instr->InputAt(1); | |
1107 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
1108 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
1109 | |
1110 if (instr->is_double()) { | |
1111 // Don't base result on EFLAGS when a NaN is involved. Instead | |
1112 // jump to the false block. | |
1113 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); | |
1114 __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); | |
1115 } else { | |
1116 EmitCmpI(left, right); | |
1117 } | |
1118 | |
1119 Condition cc = TokenToCondition(instr->op(), instr->is_double()); | |
1120 EmitBranch(true_block, false_block, cc); | |
1001 } | 1121 } |
1002 | 1122 |
1003 | 1123 |
1004 void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) { | 1124 void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) { |
1005 Abort("Unimplemented: %s", "DoCmpJSObjectEq"); | 1125 Abort("Unimplemented: %s", "DoCmpJSObjectEq"); |
1006 } | 1126 } |
1007 | 1127 |
1008 | 1128 |
1009 void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { | 1129 void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { |
1010 Abort("Unimplemented: %s", "DoCmpJSObjectAndBranch"); | 1130 Register left = ToRegister(instr->InputAt(0)); |
1131 Register right = ToRegister(instr->InputAt(1)); | |
1132 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
1133 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
1134 | |
1135 __ cmpq(left, right); | |
1136 EmitBranch(true_block, false_block, equal); | |
1011 } | 1137 } |
1012 | 1138 |
1013 | 1139 |
1014 void LCodeGen::DoIsNull(LIsNull* instr) { | 1140 void LCodeGen::DoIsNull(LIsNull* instr) { |
1015 Abort("Unimplemented: %s", "DoIsNull"); | 1141 Abort("Unimplemented: %s", "DoIsNull"); |
1016 } | 1142 } |
1017 | 1143 |
1018 | 1144 |
1019 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { | 1145 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { |
1020 Abort("Unimplemented: %s", "DoIsNullAndBranch"); | 1146 Register reg = ToRegister(instr->InputAt(0)); |
1147 | |
1148 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
1149 | |
1150 if (instr->hydrogen()->representation().IsSpecialization() || | |
1151 instr->hydrogen()->type().IsSmi()) { | |
1152 // If the expression is known to untagged or smi, then it's definitely | |
1153 // not null, and it can't be a an undetectable object. | |
1154 // Jump directly to the false block. | |
1155 EmitGoto(false_block); | |
1156 return; | |
1157 } | |
1158 | |
1159 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
1160 | |
1161 __ Cmp(reg, Factory::null_value()); | |
1162 if (instr->is_strict()) { | |
1163 EmitBranch(true_block, false_block, equal); | |
1164 } else { | |
1165 Label* true_label = chunk_->GetAssemblyLabel(true_block); | |
1166 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
1167 __ j(equal, true_label); | |
1168 __ Cmp(reg, Factory::undefined_value()); | |
1169 __ j(equal, true_label); | |
1170 __ JumpIfSmi(reg, false_label); | |
1171 // Check for undetectable objects by looking in the bit field in | |
1172 // the map. The object has already been smi checked. | |
1173 Register scratch = ToRegister(instr->TempAt(0)); | |
1174 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); | |
1175 __ testb(FieldOperand(scratch, Map::kBitFieldOffset), | |
1176 Immediate(1 << Map::kIsUndetectable)); | |
1177 EmitBranch(true_block, false_block, not_zero); | |
1178 } | |
1021 } | 1179 } |
1022 | 1180 |
1023 | 1181 |
1024 Condition LCodeGen::EmitIsObject(Register input, | 1182 Condition LCodeGen::EmitIsObject(Register input, |
1025 Register temp1, | 1183 Register temp1, |
1026 Register temp2, | 1184 Register temp2, |
1027 Label* is_not_object, | 1185 Label* is_not_object, |
1028 Label* is_object) { | 1186 Label* is_object) { |
1029 Abort("Unimplemented: %s", "EmitIsObject"); | 1187 ASSERT(!input.is(temp1)); |
1188 ASSERT(!input.is(temp2)); | |
1189 ASSERT(!temp1.is(temp2)); | |
1190 | |
1191 __ JumpIfSmi(input, is_not_object); | |
1192 | |
1193 __ Cmp(input, Factory::null_value()); | |
1194 __ j(equal, is_object); | |
1195 | |
1196 __ movq(temp1, FieldOperand(input, HeapObject::kMapOffset)); | |
1197 // Undetectable objects behave like undefined. | |
1198 __ testb(FieldOperand(temp1, Map::kBitFieldOffset), | |
1199 Immediate(1 << Map::kIsUndetectable)); | |
1200 __ j(not_zero, is_not_object); | |
1201 | |
1202 __ movzxbl(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset)); | |
1203 __ cmpb(temp2, Immediate(FIRST_JS_OBJECT_TYPE)); | |
1204 __ j(below, is_not_object); | |
1205 __ cmpb(temp2, Immediate(LAST_JS_OBJECT_TYPE)); | |
1030 return below_equal; | 1206 return below_equal; |
1031 } | 1207 } |
1032 | 1208 |
1033 | 1209 |
1034 void LCodeGen::DoIsObject(LIsObject* instr) { | 1210 void LCodeGen::DoIsObject(LIsObject* instr) { |
1035 Abort("Unimplemented: %s", "DoIsObject"); | 1211 Abort("Unimplemented: %s", "DoIsObject"); |
1036 } | 1212 } |
1037 | 1213 |
1038 | 1214 |
1039 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { | 1215 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { |
1040 Abort("Unimplemented: %s", "DoIsObjectAndBranch"); | 1216 Register reg = ToRegister(instr->InputAt(0)); |
1217 Register temp = ToRegister(instr->TempAt(0)); | |
1218 Register temp2 = ToRegister(instr->TempAt(1)); | |
1219 | |
1220 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
1221 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
1222 Label* true_label = chunk_->GetAssemblyLabel(true_block); | |
1223 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
1224 | |
1225 Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label); | |
1226 | |
1227 EmitBranch(true_block, false_block, true_cond); | |
1041 } | 1228 } |
1042 | 1229 |
1043 | 1230 |
1044 void LCodeGen::DoIsSmi(LIsSmi* instr) { | 1231 void LCodeGen::DoIsSmi(LIsSmi* instr) { |
1045 Abort("Unimplemented: %s", "DoIsSmi"); | 1232 Abort("Unimplemented: %s", "DoIsSmi"); |
1046 } | 1233 } |
1047 | 1234 |
1048 | 1235 |
1049 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { | 1236 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { |
1050 Abort("Unimplemented: %s", "DoIsSmiAndBranch"); | 1237 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
1238 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
1239 | |
1240 Condition is_smi; | |
1241 if (instr->InputAt(0)->IsRegister()) { | |
1242 Register input = ToRegister(instr->InputAt(0)); | |
1243 is_smi = masm()->CheckSmi(input); | |
1244 } else { | |
1245 Operand input = ToOperand(instr->InputAt(0)); | |
1246 is_smi = masm()->CheckSmi(input); | |
1247 } | |
1248 EmitBranch(true_block, false_block, is_smi); | |
1051 } | 1249 } |
1052 | 1250 |
1053 | 1251 |
1252 static InstanceType TestType(HHasInstanceType* instr) { | |
1253 InstanceType from = instr->from(); | |
1254 InstanceType to = instr->to(); | |
1255 if (from == FIRST_TYPE) return to; | |
1256 ASSERT(from == to || to == LAST_TYPE); | |
1257 return from; | |
1258 } | |
1259 | |
1260 | |
1261 static Condition BranchCondition(HHasInstanceType* instr) { | |
1262 InstanceType from = instr->from(); | |
1263 InstanceType to = instr->to(); | |
1264 if (from == to) return equal; | |
1265 if (to == LAST_TYPE) return above_equal; | |
1266 if (from == FIRST_TYPE) return below_equal; | |
1267 UNREACHABLE(); | |
1268 return equal; | |
1269 } | |
1270 | |
1271 | |
1054 void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { | 1272 void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { |
1055 Abort("Unimplemented: %s", "DoHasInstanceType"); | 1273 Abort("Unimplemented: %s", "DoHasInstanceType"); |
1056 } | 1274 } |
1057 | 1275 |
1058 | 1276 |
1059 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { | 1277 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { |
1060 Abort("Unimplemented: %s", "DoHasInstanceTypeAndBranch"); | 1278 Register input = ToRegister(instr->InputAt(0)); |
1279 Register temp = ToRegister(instr->TempAt(0)); | |
William Hesse
2011/01/18 14:01:50
Unless we are using instr->temp after this instruc
Lasse Reichstein
2011/01/19 09:20:35
It should be safe. We only use it as scratch regis
| |
1280 | |
1281 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
1282 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
1283 | |
1284 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
1285 | |
1286 __ JumpIfSmi(input, false_label); | |
1287 | |
1288 __ CmpObjectType(input, TestType(instr->hydrogen()), temp); | |
1289 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); | |
1061 } | 1290 } |
1062 | 1291 |
1063 | 1292 |
1064 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { | 1293 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { |
1065 Abort("Unimplemented: %s", "DoHasCachedArrayIndex"); | 1294 Abort("Unimplemented: %s", "DoHasCachedArrayIndex"); |
1066 } | 1295 } |
1067 | 1296 |
1068 | 1297 |
1069 void LCodeGen::DoHasCachedArrayIndexAndBranch( | 1298 void LCodeGen::DoHasCachedArrayIndexAndBranch( |
1070 LHasCachedArrayIndexAndBranch* instr) { | 1299 LHasCachedArrayIndexAndBranch* instr) { |
1071 Abort("Unimplemented: %s", "DoHasCachedArrayIndexAndBranch"); | 1300 Register input = ToRegister(instr->InputAt(0)); |
1301 | |
1302 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
1303 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
1304 | |
1305 __ testl(FieldOperand(input, String::kHashFieldOffset), | |
1306 Immediate(String::kContainsCachedArrayIndexMask)); | |
1307 EmitBranch(true_block, false_block, not_equal); | |
1072 } | 1308 } |
1073 | 1309 |
1074 | 1310 |
1075 // Branches to a label or falls through with the answer in the z flag. Trashes | 1311 // Branches to a label or falls through with the answer in the z flag. Trashes |
1076 // the temp registers, but not the input. Only input and temp2 may alias. | 1312 // the temp registers, but not the input. Only input and temp2 may alias. |
1077 void LCodeGen::EmitClassOfTest(Label* is_true, | 1313 void LCodeGen::EmitClassOfTest(Label* is_true, |
1078 Label* is_false, | 1314 Label* is_false, |
1079 Handle<String>class_name, | 1315 Handle<String> class_name, |
1080 Register input, | 1316 Register input, |
1081 Register temp, | 1317 Register temp, |
1082 Register temp2) { | 1318 Register temp2) { |
1083 Abort("Unimplemented: %s", "EmitClassOfTest"); | 1319 ASSERT(!input.is(temp)); |
1320 ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register. | |
1321 __ JumpIfSmi(input, is_false); | |
1322 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, temp); | |
1323 __ j(below, is_false); | |
1324 | |
1325 // Map is now in temp. | |
1326 // Functions have class 'Function'. | |
1327 __ CmpInstanceType(temp, JS_FUNCTION_TYPE); | |
1328 if (class_name->IsEqualTo(CStrVector("Function"))) { | |
1329 __ j(equal, is_true); | |
1330 } else { | |
1331 __ j(equal, is_false); | |
1332 } | |
1333 | |
1334 // Check if the constructor in the map is a function. | |
1335 __ movq(temp, FieldOperand(temp, Map::kConstructorOffset)); | |
1336 | |
1337 // As long as JS_FUNCTION_TYPE is the last instance type and it is | |
1338 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for | |
1339 // LAST_JS_OBJECT_TYPE. | |
1340 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | |
1341 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | |
1342 | |
1343 // Objects with a non-function constructor have class 'Object'. | |
1344 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2); | |
William Hesse
2011/01/18 14:01:50
We can use kScratchRegister here.
Lasse Reichstein
2011/01/19 09:20:35
We can, but the current implementation uses the fa
Lasse Reichstein
2011/01/19 10:14:53
I removed the second temp register, and just stopp
| |
1345 if (class_name->IsEqualTo(CStrVector("Object"))) { | |
1346 __ j(not_equal, is_true); | |
1347 } else { | |
1348 __ j(not_equal, is_false); | |
1349 } | |
1350 | |
1351 // temp now contains the constructor function. Grab the | |
1352 // instance class name from there. | |
1353 __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); | |
1354 __ movq(temp, FieldOperand(temp, | |
1355 SharedFunctionInfo::kInstanceClassNameOffset)); | |
1356 // The class name we are testing against is a symbol because it's a literal. | |
William Hesse
2011/01/18 14:01:50
Could we assert that this is a symbol?
Lasse Reichstein
2011/01/19 09:20:35
Done.
| |
1357 // The name in the constructor is a symbol because of the way the context is | |
1358 // booted. This routine isn't expected to work for random API-created | |
1359 // classes and it doesn't have to because you can't access it with natives | |
1360 // syntax. Since both sides are symbols it is sufficient to use an identity | |
1361 // comparison. | |
1362 __ Cmp(temp, class_name); | |
1363 // End with the answer in the z flag. | |
1084 } | 1364 } |
1085 | 1365 |
1086 | 1366 |
1087 void LCodeGen::DoClassOfTest(LClassOfTest* instr) { | 1367 void LCodeGen::DoClassOfTest(LClassOfTest* instr) { |
1088 Abort("Unimplemented: %s", "DoClassOfTest"); | 1368 Abort("Unimplemented: %s", "DoClassOfTest"); |
1089 } | 1369 } |
1090 | 1370 |
1091 | 1371 |
1092 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { | 1372 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
1093 Abort("Unimplemented: %s", "DoClassOfTestAndBranch"); | 1373 Register input = ToRegister(instr->InputAt(0)); |
1374 Register temp = ToRegister(instr->TempAt(0)); | |
1375 Register temp2 = ToRegister(instr->TempAt(1)); | |
1376 if (input.is(temp)) { | |
1377 // Swap. | |
1378 Register swapper = temp; | |
1379 temp = temp2; | |
William Hesse
2011/01/18 14:01:50
We probably don't need two temp registers here.
Lasse Reichstein
2011/01/19 09:20:35
This is the place where we seem that we do need th
| |
1380 temp2 = swapper; | |
1381 } | |
1382 Handle<String> class_name = instr->hydrogen()->class_name(); | |
1383 | |
1384 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
1385 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
1386 | |
1387 Label* true_label = chunk_->GetAssemblyLabel(true_block); | |
1388 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
1389 | |
1390 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2); | |
1391 | |
1392 EmitBranch(true_block, false_block, equal); | |
1094 } | 1393 } |
1095 | 1394 |
1096 | 1395 |
1097 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { | 1396 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { |
1098 Abort("Unimplemented: %s", "DoCmpMapAndBranch"); | 1397 Abort("Unimplemented: %s", "DoCmpMapAndBranch"); |
1099 } | 1398 } |
1100 | 1399 |
1101 | 1400 |
1102 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { | 1401 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { |
1103 Abort("Unimplemented: %s", "DoInstanceOf"); | 1402 Abort("Unimplemented: %s", "DoInstanceOf"); |
1104 } | 1403 } |
1105 | 1404 |
1106 | 1405 |
1107 void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { | 1406 void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { |
1108 Abort("Unimplemented: %s", "DoInstanceOfAndBranch"); | 1407 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
1408 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
1409 | |
1410 InstanceofStub stub(InstanceofStub::kArgsInRegisters); | |
1411 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | |
1412 __ testq(rax, rax); | |
1413 EmitBranch(true_block, false_block, zero); | |
1109 } | 1414 } |
1110 | 1415 |
1111 | 1416 |
1112 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { | 1417 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { |
1113 Abort("Unimplemented: %s", "DoInstanceOfKnowGLobal"); | 1418 Abort("Unimplemented: %s", "DoInstanceOfKnowGLobal"); |
1114 } | 1419 } |
1115 | 1420 |
1116 | 1421 |
1117 void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, | 1422 void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, |
1118 Label* map_check) { | 1423 Label* map_check) { |
1119 Abort("Unimplemented: %s", "DoDeferredLInstanceOfKnownGlobakl"); | 1424 Abort("Unimplemented: %s", "DoDeferredLInstanceOfKnownGlobakl"); |
1120 } | 1425 } |
1121 | 1426 |
1122 | 1427 |
1123 void LCodeGen::DoCmpT(LCmpT* instr) { | 1428 void LCodeGen::DoCmpT(LCmpT* instr) { |
1124 Abort("Unimplemented: %s", "DoCmpT"); | 1429 Token::Value op = instr->op(); |
1430 | |
1431 Handle<Code> ic = CompareIC::GetUninitialized(op); | |
1432 CallCode(ic, RelocInfo::CODE_TARGET, instr); | |
1433 | |
1434 Condition condition = TokenToCondition(op, false); | |
1435 if (op == Token::GT || op == Token::LTE) { | |
1436 condition = ReverseCondition(condition); | |
1437 } | |
1438 NearLabel true_value, done; | |
1439 __ testq(rax, rax); | |
1440 __ j(condition, &true_value); | |
1441 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); | |
1442 __ jmp(&done); | |
1443 __ bind(&true_value); | |
1444 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); | |
1445 __ bind(&done); | |
1125 } | 1446 } |
1126 | 1447 |
1127 | 1448 |
1128 void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) { | 1449 void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) { |
1129 Abort("Unimplemented: %s", "DoCmpTAndBranch"); | 1450 Token::Value op = instr->op(); |
1451 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
1452 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
1453 | |
1454 Handle<Code> ic = CompareIC::GetUninitialized(op); | |
1455 CallCode(ic, RelocInfo::CODE_TARGET, instr); | |
1456 | |
1457 // The compare stub expects compare condition and the input operands | |
1458 // reversed for GT and LTE. | |
1459 Condition condition = TokenToCondition(op, false); | |
1460 if (op == Token::GT || op == Token::LTE) { | |
1461 condition = ReverseCondition(condition); | |
1462 } | |
1463 __ testq(rax, rax); | |
1464 EmitBranch(true_block, false_block, condition); | |
1130 } | 1465 } |
1131 | 1466 |
1132 | 1467 |
1133 void LCodeGen::DoReturn(LReturn* instr) { | 1468 void LCodeGen::DoReturn(LReturn* instr) { |
1134 if (FLAG_trace) { | 1469 if (FLAG_trace) { |
1135 // Preserve the return value on the stack and rely on the runtime | 1470 // Preserve the return value on the stack and rely on the runtime |
1136 // call to return the value in the same register. | 1471 // call to return the value in the same register. |
1137 __ push(rax); | 1472 __ push(rax); |
1138 __ CallRuntime(Runtime::kTraceExit, 1); | 1473 __ CallRuntime(Runtime::kTraceExit, 1); |
1139 } | 1474 } |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1466 Abort("Unimplemented: %s", "DoTypeof"); | 1801 Abort("Unimplemented: %s", "DoTypeof"); |
1467 } | 1802 } |
1468 | 1803 |
1469 | 1804 |
1470 void LCodeGen::DoTypeofIs(LTypeofIs* instr) { | 1805 void LCodeGen::DoTypeofIs(LTypeofIs* instr) { |
1471 Abort("Unimplemented: %s", "DoTypeofIs"); | 1806 Abort("Unimplemented: %s", "DoTypeofIs"); |
1472 } | 1807 } |
1473 | 1808 |
1474 | 1809 |
1475 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { | 1810 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { |
1476 Abort("Unimplemented: %s", "DoTypeofIsAndBranch"); | 1811 Register input = ToRegister(instr->InputAt(0)); |
1812 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
1813 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
1814 Label* true_label = chunk_->GetAssemblyLabel(true_block); | |
1815 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
1816 | |
1817 Condition final_branch_condition = EmitTypeofIs(true_label, | |
1818 false_label, | |
1819 input, | |
1820 instr->type_literal()); | |
1821 | |
1822 EmitBranch(true_block, false_block, final_branch_condition); | |
1477 } | 1823 } |
1478 | 1824 |
1479 | 1825 |
1480 Condition LCodeGen::EmitTypeofIs(Label* true_label, | 1826 Condition LCodeGen::EmitTypeofIs(Label* true_label, |
1481 Label* false_label, | 1827 Label* false_label, |
1482 Register input, | 1828 Register input, |
1483 Handle<String> type_name) { | 1829 Handle<String> type_name) { |
1484 Abort("Unimplemented: %s", "EmitTypeofIs"); | 1830 Condition final_branch_condition = no_condition; |
1485 return no_condition; | 1831 if (type_name->Equals(Heap::number_symbol())) { |
1832 __ JumpIfSmi(input, true_label); | |
1833 __ Cmp(FieldOperand(input, HeapObject::kMapOffset), | |
1834 Factory::heap_number_map()); | |
1835 final_branch_condition = equal; | |
1836 | |
1837 } else if (type_name->Equals(Heap::string_symbol())) { | |
1838 __ JumpIfSmi(input, false_label); | |
1839 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); | |
1840 __ testb(FieldOperand(input, Map::kBitFieldOffset), | |
1841 Immediate(1 << Map::kIsUndetectable)); | |
1842 __ j(not_zero, false_label); | |
1843 __ CmpInstanceType(input, FIRST_NONSTRING_TYPE); | |
1844 final_branch_condition = below; | |
1845 | |
1846 } else if (type_name->Equals(Heap::boolean_symbol())) { | |
1847 __ Cmp(input, Handle<Object>(Heap::true_value())); | |
William Hesse
2011/01/18 14:01:50
Can we use the root array here?
Lasse Reichstein
2011/01/19 09:20:35
Done, both.
| |
1848 __ j(equal, true_label); | |
1849 __ Cmp(input, Handle<Object>(Heap::false_value())); | |
1850 final_branch_condition = equal; | |
1851 | |
1852 } else if (type_name->Equals(Heap::undefined_symbol())) { | |
William Hesse
2011/01/18 14:01:50
Root array.
Lasse Reichstein
2011/01/19 09:20:35
Done.
| |
1853 __ Cmp(input, Factory::undefined_value()); | |
1854 __ j(equal, true_label); | |
1855 __ JumpIfSmi(input, false_label); | |
1856 // Check for undetectable objects => true. | |
1857 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); | |
1858 __ testb(FieldOperand(input, Map::kBitFieldOffset), | |
1859 Immediate(1 << Map::kIsUndetectable)); | |
1860 final_branch_condition = not_zero; | |
1861 | |
1862 } else if (type_name->Equals(Heap::function_symbol())) { | |
1863 __ JumpIfSmi(input, false_label); | |
1864 __ CmpObjectType(input, FIRST_FUNCTION_CLASS_TYPE, input); | |
1865 final_branch_condition = above_equal; | |
1866 | |
1867 } else if (type_name->Equals(Heap::object_symbol())) { | |
1868 __ JumpIfSmi(input, false_label); | |
1869 __ Cmp(input, Factory::null_value()); | |
1870 __ j(equal, true_label); | |
1871 // Check for undetectable objects => false. | |
1872 __ testb(FieldOperand(input, Map::kBitFieldOffset), | |
1873 Immediate(1 << Map::kIsUndetectable)); | |
1874 __ j(not_zero, false_label); | |
1875 // Check for JS objects that are not RegExp or Function => true. | |
1876 __ CmpInstanceType(input, FIRST_JS_OBJECT_TYPE); | |
1877 __ j(below, false_label); | |
1878 __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE); | |
1879 final_branch_condition = below_equal; | |
1880 | |
1881 } else { | |
1882 final_branch_condition = never; | |
1883 __ jmp(false_label); | |
1884 } | |
1885 | |
1886 return final_branch_condition; | |
1486 } | 1887 } |
1487 | 1888 |
1488 | 1889 |
1489 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { | 1890 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { |
1490 // No code for lazy bailout instruction. Used to capture environment after a | 1891 // No code for lazy bailout instruction. Used to capture environment after a |
1491 // call for populating the safepoint data with deoptimization data. | 1892 // call for populating the safepoint data with deoptimization data. |
1492 } | 1893 } |
1493 | 1894 |
1494 | 1895 |
1495 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { | 1896 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { |
(...skipping 21 matching lines...) Expand all Loading... | |
1517 | 1918 |
1518 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { | 1919 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { |
1519 Abort("Unimplemented: %s", "DoOsrEntry"); | 1920 Abort("Unimplemented: %s", "DoOsrEntry"); |
1520 } | 1921 } |
1521 | 1922 |
1522 #undef __ | 1923 #undef __ |
1523 | 1924 |
1524 } } // namespace v8::internal | 1925 } } // namespace v8::internal |
1525 | 1926 |
1526 #endif // V8_TARGET_ARCH_X64 | 1927 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |