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