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