Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Side by Side Diff: src/x64/lithium-codegen-x64.cc

Issue 6374002: X64 Crank: Implemented DoBranch and all *AndBranch comparisons. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge/build-x64
Patch Set: Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698