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