| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_IA32 | 7 #if V8_TARGET_ARCH_IA32 |
| 8 | 8 |
| 9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
| 10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
| (...skipping 1103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1114 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); | 1114 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); |
| 1115 Label dividend_is_not_negative, done; | 1115 Label dividend_is_not_negative, done; |
| 1116 if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) { | 1116 if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) { |
| 1117 __ test(dividend, dividend); | 1117 __ test(dividend, dividend); |
| 1118 __ j(not_sign, ÷nd_is_not_negative, Label::kNear); | 1118 __ j(not_sign, ÷nd_is_not_negative, Label::kNear); |
| 1119 // Note that this is correct even for kMinInt operands. | 1119 // Note that this is correct even for kMinInt operands. |
| 1120 __ neg(dividend); | 1120 __ neg(dividend); |
| 1121 __ and_(dividend, mask); | 1121 __ and_(dividend, mask); |
| 1122 __ neg(dividend); | 1122 __ neg(dividend); |
| 1123 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1123 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1124 DeoptimizeIf(zero, instr); | 1124 DeoptimizeIf(zero, instr, "minus zero"); |
| 1125 } | 1125 } |
| 1126 __ jmp(&done, Label::kNear); | 1126 __ jmp(&done, Label::kNear); |
| 1127 } | 1127 } |
| 1128 | 1128 |
| 1129 __ bind(÷nd_is_not_negative); | 1129 __ bind(÷nd_is_not_negative); |
| 1130 __ and_(dividend, mask); | 1130 __ and_(dividend, mask); |
| 1131 __ bind(&done); | 1131 __ bind(&done); |
| 1132 } | 1132 } |
| 1133 | 1133 |
| 1134 | 1134 |
| 1135 void LCodeGen::DoModByConstI(LModByConstI* instr) { | 1135 void LCodeGen::DoModByConstI(LModByConstI* instr) { |
| 1136 Register dividend = ToRegister(instr->dividend()); | 1136 Register dividend = ToRegister(instr->dividend()); |
| 1137 int32_t divisor = instr->divisor(); | 1137 int32_t divisor = instr->divisor(); |
| 1138 DCHECK(ToRegister(instr->result()).is(eax)); | 1138 DCHECK(ToRegister(instr->result()).is(eax)); |
| 1139 | 1139 |
| 1140 if (divisor == 0) { | 1140 if (divisor == 0) { |
| 1141 DeoptimizeIf(no_condition, instr); | 1141 DeoptimizeIf(no_condition, instr, "division by zero"); |
| 1142 return; | 1142 return; |
| 1143 } | 1143 } |
| 1144 | 1144 |
| 1145 __ TruncatingDiv(dividend, Abs(divisor)); | 1145 __ TruncatingDiv(dividend, Abs(divisor)); |
| 1146 __ imul(edx, edx, Abs(divisor)); | 1146 __ imul(edx, edx, Abs(divisor)); |
| 1147 __ mov(eax, dividend); | 1147 __ mov(eax, dividend); |
| 1148 __ sub(eax, edx); | 1148 __ sub(eax, edx); |
| 1149 | 1149 |
| 1150 // Check for negative zero. | 1150 // Check for negative zero. |
| 1151 HMod* hmod = instr->hydrogen(); | 1151 HMod* hmod = instr->hydrogen(); |
| 1152 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1152 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1153 Label remainder_not_zero; | 1153 Label remainder_not_zero; |
| 1154 __ j(not_zero, &remainder_not_zero, Label::kNear); | 1154 __ j(not_zero, &remainder_not_zero, Label::kNear); |
| 1155 __ cmp(dividend, Immediate(0)); | 1155 __ cmp(dividend, Immediate(0)); |
| 1156 DeoptimizeIf(less, instr); | 1156 DeoptimizeIf(less, instr, "minus zero"); |
| 1157 __ bind(&remainder_not_zero); | 1157 __ bind(&remainder_not_zero); |
| 1158 } | 1158 } |
| 1159 } | 1159 } |
| 1160 | 1160 |
| 1161 | 1161 |
| 1162 void LCodeGen::DoModI(LModI* instr) { | 1162 void LCodeGen::DoModI(LModI* instr) { |
| 1163 HMod* hmod = instr->hydrogen(); | 1163 HMod* hmod = instr->hydrogen(); |
| 1164 | 1164 |
| 1165 Register left_reg = ToRegister(instr->left()); | 1165 Register left_reg = ToRegister(instr->left()); |
| 1166 DCHECK(left_reg.is(eax)); | 1166 DCHECK(left_reg.is(eax)); |
| 1167 Register right_reg = ToRegister(instr->right()); | 1167 Register right_reg = ToRegister(instr->right()); |
| 1168 DCHECK(!right_reg.is(eax)); | 1168 DCHECK(!right_reg.is(eax)); |
| 1169 DCHECK(!right_reg.is(edx)); | 1169 DCHECK(!right_reg.is(edx)); |
| 1170 Register result_reg = ToRegister(instr->result()); | 1170 Register result_reg = ToRegister(instr->result()); |
| 1171 DCHECK(result_reg.is(edx)); | 1171 DCHECK(result_reg.is(edx)); |
| 1172 | 1172 |
| 1173 Label done; | 1173 Label done; |
| 1174 // Check for x % 0, idiv would signal a divide error. We have to | 1174 // Check for x % 0, idiv would signal a divide error. We have to |
| 1175 // deopt in this case because we can't return a NaN. | 1175 // deopt in this case because we can't return a NaN. |
| 1176 if (hmod->CheckFlag(HValue::kCanBeDivByZero)) { | 1176 if (hmod->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1177 __ test(right_reg, Operand(right_reg)); | 1177 __ test(right_reg, Operand(right_reg)); |
| 1178 DeoptimizeIf(zero, instr); | 1178 DeoptimizeIf(zero, instr, "division by zero"); |
| 1179 } | 1179 } |
| 1180 | 1180 |
| 1181 // Check for kMinInt % -1, idiv would signal a divide error. We | 1181 // Check for kMinInt % -1, idiv would signal a divide error. We |
| 1182 // have to deopt if we care about -0, because we can't return that. | 1182 // have to deopt if we care about -0, because we can't return that. |
| 1183 if (hmod->CheckFlag(HValue::kCanOverflow)) { | 1183 if (hmod->CheckFlag(HValue::kCanOverflow)) { |
| 1184 Label no_overflow_possible; | 1184 Label no_overflow_possible; |
| 1185 __ cmp(left_reg, kMinInt); | 1185 __ cmp(left_reg, kMinInt); |
| 1186 __ j(not_equal, &no_overflow_possible, Label::kNear); | 1186 __ j(not_equal, &no_overflow_possible, Label::kNear); |
| 1187 __ cmp(right_reg, -1); | 1187 __ cmp(right_reg, -1); |
| 1188 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1188 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1189 DeoptimizeIf(equal, instr); | 1189 DeoptimizeIf(equal, instr, "minus zero"); |
| 1190 } else { | 1190 } else { |
| 1191 __ j(not_equal, &no_overflow_possible, Label::kNear); | 1191 __ j(not_equal, &no_overflow_possible, Label::kNear); |
| 1192 __ Move(result_reg, Immediate(0)); | 1192 __ Move(result_reg, Immediate(0)); |
| 1193 __ jmp(&done, Label::kNear); | 1193 __ jmp(&done, Label::kNear); |
| 1194 } | 1194 } |
| 1195 __ bind(&no_overflow_possible); | 1195 __ bind(&no_overflow_possible); |
| 1196 } | 1196 } |
| 1197 | 1197 |
| 1198 // Sign extend dividend in eax into edx:eax. | 1198 // Sign extend dividend in eax into edx:eax. |
| 1199 __ cdq(); | 1199 __ cdq(); |
| 1200 | 1200 |
| 1201 // If we care about -0, test if the dividend is <0 and the result is 0. | 1201 // If we care about -0, test if the dividend is <0 and the result is 0. |
| 1202 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1202 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1203 Label positive_left; | 1203 Label positive_left; |
| 1204 __ test(left_reg, Operand(left_reg)); | 1204 __ test(left_reg, Operand(left_reg)); |
| 1205 __ j(not_sign, &positive_left, Label::kNear); | 1205 __ j(not_sign, &positive_left, Label::kNear); |
| 1206 __ idiv(right_reg); | 1206 __ idiv(right_reg); |
| 1207 __ test(result_reg, Operand(result_reg)); | 1207 __ test(result_reg, Operand(result_reg)); |
| 1208 DeoptimizeIf(zero, instr); | 1208 DeoptimizeIf(zero, instr, "minus zero"); |
| 1209 __ jmp(&done, Label::kNear); | 1209 __ jmp(&done, Label::kNear); |
| 1210 __ bind(&positive_left); | 1210 __ bind(&positive_left); |
| 1211 } | 1211 } |
| 1212 __ idiv(right_reg); | 1212 __ idiv(right_reg); |
| 1213 __ bind(&done); | 1213 __ bind(&done); |
| 1214 } | 1214 } |
| 1215 | 1215 |
| 1216 | 1216 |
| 1217 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) { | 1217 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) { |
| 1218 Register dividend = ToRegister(instr->dividend()); | 1218 Register dividend = ToRegister(instr->dividend()); |
| 1219 int32_t divisor = instr->divisor(); | 1219 int32_t divisor = instr->divisor(); |
| 1220 Register result = ToRegister(instr->result()); | 1220 Register result = ToRegister(instr->result()); |
| 1221 DCHECK(divisor == kMinInt || base::bits::IsPowerOfTwo32(Abs(divisor))); | 1221 DCHECK(divisor == kMinInt || base::bits::IsPowerOfTwo32(Abs(divisor))); |
| 1222 DCHECK(!result.is(dividend)); | 1222 DCHECK(!result.is(dividend)); |
| 1223 | 1223 |
| 1224 // Check for (0 / -x) that will produce negative zero. | 1224 // Check for (0 / -x) that will produce negative zero. |
| 1225 HDiv* hdiv = instr->hydrogen(); | 1225 HDiv* hdiv = instr->hydrogen(); |
| 1226 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { | 1226 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { |
| 1227 __ test(dividend, dividend); | 1227 __ test(dividend, dividend); |
| 1228 DeoptimizeIf(zero, instr); | 1228 DeoptimizeIf(zero, instr, "minus zero"); |
| 1229 } | 1229 } |
| 1230 // Check for (kMinInt / -1). | 1230 // Check for (kMinInt / -1). |
| 1231 if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) { | 1231 if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) { |
| 1232 __ cmp(dividend, kMinInt); | 1232 __ cmp(dividend, kMinInt); |
| 1233 DeoptimizeIf(zero, instr); | 1233 DeoptimizeIf(zero, instr, "overflow"); |
| 1234 } | 1234 } |
| 1235 // Deoptimize if remainder will not be 0. | 1235 // Deoptimize if remainder will not be 0. |
| 1236 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && | 1236 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && |
| 1237 divisor != 1 && divisor != -1) { | 1237 divisor != 1 && divisor != -1) { |
| 1238 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); | 1238 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); |
| 1239 __ test(dividend, Immediate(mask)); | 1239 __ test(dividend, Immediate(mask)); |
| 1240 DeoptimizeIf(not_zero, instr); | 1240 DeoptimizeIf(not_zero, instr, "lost precision"); |
| 1241 } | 1241 } |
| 1242 __ Move(result, dividend); | 1242 __ Move(result, dividend); |
| 1243 int32_t shift = WhichPowerOf2Abs(divisor); | 1243 int32_t shift = WhichPowerOf2Abs(divisor); |
| 1244 if (shift > 0) { | 1244 if (shift > 0) { |
| 1245 // The arithmetic shift is always OK, the 'if' is an optimization only. | 1245 // The arithmetic shift is always OK, the 'if' is an optimization only. |
| 1246 if (shift > 1) __ sar(result, 31); | 1246 if (shift > 1) __ sar(result, 31); |
| 1247 __ shr(result, 32 - shift); | 1247 __ shr(result, 32 - shift); |
| 1248 __ add(result, dividend); | 1248 __ add(result, dividend); |
| 1249 __ sar(result, shift); | 1249 __ sar(result, shift); |
| 1250 } | 1250 } |
| 1251 if (divisor < 0) __ neg(result); | 1251 if (divisor < 0) __ neg(result); |
| 1252 } | 1252 } |
| 1253 | 1253 |
| 1254 | 1254 |
| 1255 void LCodeGen::DoDivByConstI(LDivByConstI* instr) { | 1255 void LCodeGen::DoDivByConstI(LDivByConstI* instr) { |
| 1256 Register dividend = ToRegister(instr->dividend()); | 1256 Register dividend = ToRegister(instr->dividend()); |
| 1257 int32_t divisor = instr->divisor(); | 1257 int32_t divisor = instr->divisor(); |
| 1258 DCHECK(ToRegister(instr->result()).is(edx)); | 1258 DCHECK(ToRegister(instr->result()).is(edx)); |
| 1259 | 1259 |
| 1260 if (divisor == 0) { | 1260 if (divisor == 0) { |
| 1261 DeoptimizeIf(no_condition, instr); | 1261 DeoptimizeIf(no_condition, instr, "division by zero"); |
| 1262 return; | 1262 return; |
| 1263 } | 1263 } |
| 1264 | 1264 |
| 1265 // Check for (0 / -x) that will produce negative zero. | 1265 // Check for (0 / -x) that will produce negative zero. |
| 1266 HDiv* hdiv = instr->hydrogen(); | 1266 HDiv* hdiv = instr->hydrogen(); |
| 1267 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { | 1267 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { |
| 1268 __ test(dividend, dividend); | 1268 __ test(dividend, dividend); |
| 1269 DeoptimizeIf(zero, instr); | 1269 DeoptimizeIf(zero, instr, "minus zero"); |
| 1270 } | 1270 } |
| 1271 | 1271 |
| 1272 __ TruncatingDiv(dividend, Abs(divisor)); | 1272 __ TruncatingDiv(dividend, Abs(divisor)); |
| 1273 if (divisor < 0) __ neg(edx); | 1273 if (divisor < 0) __ neg(edx); |
| 1274 | 1274 |
| 1275 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { | 1275 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { |
| 1276 __ mov(eax, edx); | 1276 __ mov(eax, edx); |
| 1277 __ imul(eax, eax, divisor); | 1277 __ imul(eax, eax, divisor); |
| 1278 __ sub(eax, dividend); | 1278 __ sub(eax, dividend); |
| 1279 DeoptimizeIf(not_equal, instr); | 1279 DeoptimizeIf(not_equal, instr, "lost precision"); |
| 1280 } | 1280 } |
| 1281 } | 1281 } |
| 1282 | 1282 |
| 1283 | 1283 |
| 1284 // TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI. | 1284 // TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI. |
| 1285 void LCodeGen::DoDivI(LDivI* instr) { | 1285 void LCodeGen::DoDivI(LDivI* instr) { |
| 1286 HBinaryOperation* hdiv = instr->hydrogen(); | 1286 HBinaryOperation* hdiv = instr->hydrogen(); |
| 1287 Register dividend = ToRegister(instr->dividend()); | 1287 Register dividend = ToRegister(instr->dividend()); |
| 1288 Register divisor = ToRegister(instr->divisor()); | 1288 Register divisor = ToRegister(instr->divisor()); |
| 1289 Register remainder = ToRegister(instr->temp()); | 1289 Register remainder = ToRegister(instr->temp()); |
| 1290 DCHECK(dividend.is(eax)); | 1290 DCHECK(dividend.is(eax)); |
| 1291 DCHECK(remainder.is(edx)); | 1291 DCHECK(remainder.is(edx)); |
| 1292 DCHECK(ToRegister(instr->result()).is(eax)); | 1292 DCHECK(ToRegister(instr->result()).is(eax)); |
| 1293 DCHECK(!divisor.is(eax)); | 1293 DCHECK(!divisor.is(eax)); |
| 1294 DCHECK(!divisor.is(edx)); | 1294 DCHECK(!divisor.is(edx)); |
| 1295 | 1295 |
| 1296 // Check for x / 0. | 1296 // Check for x / 0. |
| 1297 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) { | 1297 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1298 __ test(divisor, divisor); | 1298 __ test(divisor, divisor); |
| 1299 DeoptimizeIf(zero, instr); | 1299 DeoptimizeIf(zero, instr, "division by zero"); |
| 1300 } | 1300 } |
| 1301 | 1301 |
| 1302 // Check for (0 / -x) that will produce negative zero. | 1302 // Check for (0 / -x) that will produce negative zero. |
| 1303 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1303 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1304 Label dividend_not_zero; | 1304 Label dividend_not_zero; |
| 1305 __ test(dividend, dividend); | 1305 __ test(dividend, dividend); |
| 1306 __ j(not_zero, ÷nd_not_zero, Label::kNear); | 1306 __ j(not_zero, ÷nd_not_zero, Label::kNear); |
| 1307 __ test(divisor, divisor); | 1307 __ test(divisor, divisor); |
| 1308 DeoptimizeIf(sign, instr); | 1308 DeoptimizeIf(sign, instr, "minus zero"); |
| 1309 __ bind(÷nd_not_zero); | 1309 __ bind(÷nd_not_zero); |
| 1310 } | 1310 } |
| 1311 | 1311 |
| 1312 // Check for (kMinInt / -1). | 1312 // Check for (kMinInt / -1). |
| 1313 if (hdiv->CheckFlag(HValue::kCanOverflow)) { | 1313 if (hdiv->CheckFlag(HValue::kCanOverflow)) { |
| 1314 Label dividend_not_min_int; | 1314 Label dividend_not_min_int; |
| 1315 __ cmp(dividend, kMinInt); | 1315 __ cmp(dividend, kMinInt); |
| 1316 __ j(not_zero, ÷nd_not_min_int, Label::kNear); | 1316 __ j(not_zero, ÷nd_not_min_int, Label::kNear); |
| 1317 __ cmp(divisor, -1); | 1317 __ cmp(divisor, -1); |
| 1318 DeoptimizeIf(zero, instr); | 1318 DeoptimizeIf(zero, instr, "overflow"); |
| 1319 __ bind(÷nd_not_min_int); | 1319 __ bind(÷nd_not_min_int); |
| 1320 } | 1320 } |
| 1321 | 1321 |
| 1322 // Sign extend to edx (= remainder). | 1322 // Sign extend to edx (= remainder). |
| 1323 __ cdq(); | 1323 __ cdq(); |
| 1324 __ idiv(divisor); | 1324 __ idiv(divisor); |
| 1325 | 1325 |
| 1326 if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) { | 1326 if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) { |
| 1327 // Deoptimize if remainder is not 0. | 1327 // Deoptimize if remainder is not 0. |
| 1328 __ test(remainder, remainder); | 1328 __ test(remainder, remainder); |
| 1329 DeoptimizeIf(not_zero, instr); | 1329 DeoptimizeIf(not_zero, instr, "lost precision"); |
| 1330 } | 1330 } |
| 1331 } | 1331 } |
| 1332 | 1332 |
| 1333 | 1333 |
| 1334 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) { | 1334 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) { |
| 1335 Register dividend = ToRegister(instr->dividend()); | 1335 Register dividend = ToRegister(instr->dividend()); |
| 1336 int32_t divisor = instr->divisor(); | 1336 int32_t divisor = instr->divisor(); |
| 1337 DCHECK(dividend.is(ToRegister(instr->result()))); | 1337 DCHECK(dividend.is(ToRegister(instr->result()))); |
| 1338 | 1338 |
| 1339 // If the divisor is positive, things are easy: There can be no deopts and we | 1339 // If the divisor is positive, things are easy: There can be no deopts and we |
| 1340 // can simply do an arithmetic right shift. | 1340 // can simply do an arithmetic right shift. |
| 1341 if (divisor == 1) return; | 1341 if (divisor == 1) return; |
| 1342 int32_t shift = WhichPowerOf2Abs(divisor); | 1342 int32_t shift = WhichPowerOf2Abs(divisor); |
| 1343 if (divisor > 1) { | 1343 if (divisor > 1) { |
| 1344 __ sar(dividend, shift); | 1344 __ sar(dividend, shift); |
| 1345 return; | 1345 return; |
| 1346 } | 1346 } |
| 1347 | 1347 |
| 1348 // If the divisor is negative, we have to negate and handle edge cases. | 1348 // If the divisor is negative, we have to negate and handle edge cases. |
| 1349 __ neg(dividend); | 1349 __ neg(dividend); |
| 1350 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1350 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1351 DeoptimizeIf(zero, instr); | 1351 DeoptimizeIf(zero, instr, "minus zero"); |
| 1352 } | 1352 } |
| 1353 | 1353 |
| 1354 // Dividing by -1 is basically negation, unless we overflow. | 1354 // Dividing by -1 is basically negation, unless we overflow. |
| 1355 if (divisor == -1) { | 1355 if (divisor == -1) { |
| 1356 if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { | 1356 if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { |
| 1357 DeoptimizeIf(overflow, instr); | 1357 DeoptimizeIf(overflow, instr, "overflow"); |
| 1358 } | 1358 } |
| 1359 return; | 1359 return; |
| 1360 } | 1360 } |
| 1361 | 1361 |
| 1362 // If the negation could not overflow, simply shifting is OK. | 1362 // If the negation could not overflow, simply shifting is OK. |
| 1363 if (!instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { | 1363 if (!instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { |
| 1364 __ sar(dividend, shift); | 1364 __ sar(dividend, shift); |
| 1365 return; | 1365 return; |
| 1366 } | 1366 } |
| 1367 | 1367 |
| 1368 Label not_kmin_int, done; | 1368 Label not_kmin_int, done; |
| 1369 __ j(no_overflow, ¬_kmin_int, Label::kNear); | 1369 __ j(no_overflow, ¬_kmin_int, Label::kNear); |
| 1370 __ mov(dividend, Immediate(kMinInt / divisor)); | 1370 __ mov(dividend, Immediate(kMinInt / divisor)); |
| 1371 __ jmp(&done, Label::kNear); | 1371 __ jmp(&done, Label::kNear); |
| 1372 __ bind(¬_kmin_int); | 1372 __ bind(¬_kmin_int); |
| 1373 __ sar(dividend, shift); | 1373 __ sar(dividend, shift); |
| 1374 __ bind(&done); | 1374 __ bind(&done); |
| 1375 } | 1375 } |
| 1376 | 1376 |
| 1377 | 1377 |
| 1378 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) { | 1378 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) { |
| 1379 Register dividend = ToRegister(instr->dividend()); | 1379 Register dividend = ToRegister(instr->dividend()); |
| 1380 int32_t divisor = instr->divisor(); | 1380 int32_t divisor = instr->divisor(); |
| 1381 DCHECK(ToRegister(instr->result()).is(edx)); | 1381 DCHECK(ToRegister(instr->result()).is(edx)); |
| 1382 | 1382 |
| 1383 if (divisor == 0) { | 1383 if (divisor == 0) { |
| 1384 DeoptimizeIf(no_condition, instr); | 1384 DeoptimizeIf(no_condition, instr, "division by zero"); |
| 1385 return; | 1385 return; |
| 1386 } | 1386 } |
| 1387 | 1387 |
| 1388 // Check for (0 / -x) that will produce negative zero. | 1388 // Check for (0 / -x) that will produce negative zero. |
| 1389 HMathFloorOfDiv* hdiv = instr->hydrogen(); | 1389 HMathFloorOfDiv* hdiv = instr->hydrogen(); |
| 1390 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { | 1390 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { |
| 1391 __ test(dividend, dividend); | 1391 __ test(dividend, dividend); |
| 1392 DeoptimizeIf(zero, instr); | 1392 DeoptimizeIf(zero, instr, "minus zero"); |
| 1393 } | 1393 } |
| 1394 | 1394 |
| 1395 // Easy case: We need no dynamic check for the dividend and the flooring | 1395 // Easy case: We need no dynamic check for the dividend and the flooring |
| 1396 // division is the same as the truncating division. | 1396 // division is the same as the truncating division. |
| 1397 if ((divisor > 0 && !hdiv->CheckFlag(HValue::kLeftCanBeNegative)) || | 1397 if ((divisor > 0 && !hdiv->CheckFlag(HValue::kLeftCanBeNegative)) || |
| 1398 (divisor < 0 && !hdiv->CheckFlag(HValue::kLeftCanBePositive))) { | 1398 (divisor < 0 && !hdiv->CheckFlag(HValue::kLeftCanBePositive))) { |
| 1399 __ TruncatingDiv(dividend, Abs(divisor)); | 1399 __ TruncatingDiv(dividend, Abs(divisor)); |
| 1400 if (divisor < 0) __ neg(edx); | 1400 if (divisor < 0) __ neg(edx); |
| 1401 return; | 1401 return; |
| 1402 } | 1402 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1429 Register result = ToRegister(instr->result()); | 1429 Register result = ToRegister(instr->result()); |
| 1430 DCHECK(dividend.is(eax)); | 1430 DCHECK(dividend.is(eax)); |
| 1431 DCHECK(remainder.is(edx)); | 1431 DCHECK(remainder.is(edx)); |
| 1432 DCHECK(result.is(eax)); | 1432 DCHECK(result.is(eax)); |
| 1433 DCHECK(!divisor.is(eax)); | 1433 DCHECK(!divisor.is(eax)); |
| 1434 DCHECK(!divisor.is(edx)); | 1434 DCHECK(!divisor.is(edx)); |
| 1435 | 1435 |
| 1436 // Check for x / 0. | 1436 // Check for x / 0. |
| 1437 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) { | 1437 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1438 __ test(divisor, divisor); | 1438 __ test(divisor, divisor); |
| 1439 DeoptimizeIf(zero, instr); | 1439 DeoptimizeIf(zero, instr, "division by zero"); |
| 1440 } | 1440 } |
| 1441 | 1441 |
| 1442 // Check for (0 / -x) that will produce negative zero. | 1442 // Check for (0 / -x) that will produce negative zero. |
| 1443 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1443 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1444 Label dividend_not_zero; | 1444 Label dividend_not_zero; |
| 1445 __ test(dividend, dividend); | 1445 __ test(dividend, dividend); |
| 1446 __ j(not_zero, ÷nd_not_zero, Label::kNear); | 1446 __ j(not_zero, ÷nd_not_zero, Label::kNear); |
| 1447 __ test(divisor, divisor); | 1447 __ test(divisor, divisor); |
| 1448 DeoptimizeIf(sign, instr); | 1448 DeoptimizeIf(sign, instr, "minus zero"); |
| 1449 __ bind(÷nd_not_zero); | 1449 __ bind(÷nd_not_zero); |
| 1450 } | 1450 } |
| 1451 | 1451 |
| 1452 // Check for (kMinInt / -1). | 1452 // Check for (kMinInt / -1). |
| 1453 if (hdiv->CheckFlag(HValue::kCanOverflow)) { | 1453 if (hdiv->CheckFlag(HValue::kCanOverflow)) { |
| 1454 Label dividend_not_min_int; | 1454 Label dividend_not_min_int; |
| 1455 __ cmp(dividend, kMinInt); | 1455 __ cmp(dividend, kMinInt); |
| 1456 __ j(not_zero, ÷nd_not_min_int, Label::kNear); | 1456 __ j(not_zero, ÷nd_not_min_int, Label::kNear); |
| 1457 __ cmp(divisor, -1); | 1457 __ cmp(divisor, -1); |
| 1458 DeoptimizeIf(zero, instr); | 1458 DeoptimizeIf(zero, instr, "overflow"); |
| 1459 __ bind(÷nd_not_min_int); | 1459 __ bind(÷nd_not_min_int); |
| 1460 } | 1460 } |
| 1461 | 1461 |
| 1462 // Sign extend to edx (= remainder). | 1462 // Sign extend to edx (= remainder). |
| 1463 __ cdq(); | 1463 __ cdq(); |
| 1464 __ idiv(divisor); | 1464 __ idiv(divisor); |
| 1465 | 1465 |
| 1466 Label done; | 1466 Label done; |
| 1467 __ test(remainder, remainder); | 1467 __ test(remainder, remainder); |
| 1468 __ j(zero, &done, Label::kNear); | 1468 __ j(zero, &done, Label::kNear); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1526 __ imul(left, left, constant); | 1526 __ imul(left, left, constant); |
| 1527 } | 1527 } |
| 1528 } else { | 1528 } else { |
| 1529 if (instr->hydrogen()->representation().IsSmi()) { | 1529 if (instr->hydrogen()->representation().IsSmi()) { |
| 1530 __ SmiUntag(left); | 1530 __ SmiUntag(left); |
| 1531 } | 1531 } |
| 1532 __ imul(left, ToOperand(right)); | 1532 __ imul(left, ToOperand(right)); |
| 1533 } | 1533 } |
| 1534 | 1534 |
| 1535 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | 1535 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
| 1536 DeoptimizeIf(overflow, instr); | 1536 DeoptimizeIf(overflow, instr, "overflow"); |
| 1537 } | 1537 } |
| 1538 | 1538 |
| 1539 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1539 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1540 // Bail out if the result is supposed to be negative zero. | 1540 // Bail out if the result is supposed to be negative zero. |
| 1541 Label done; | 1541 Label done; |
| 1542 __ test(left, Operand(left)); | 1542 __ test(left, Operand(left)); |
| 1543 __ j(not_zero, &done, Label::kNear); | 1543 __ j(not_zero, &done, Label::kNear); |
| 1544 if (right->IsConstantOperand()) { | 1544 if (right->IsConstantOperand()) { |
| 1545 if (ToInteger32(LConstantOperand::cast(right)) < 0) { | 1545 if (ToInteger32(LConstantOperand::cast(right)) < 0) { |
| 1546 DeoptimizeIf(no_condition, instr); | 1546 DeoptimizeIf(no_condition, instr, "minus zero"); |
| 1547 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) { | 1547 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) { |
| 1548 __ cmp(ToRegister(instr->temp()), Immediate(0)); | 1548 __ cmp(ToRegister(instr->temp()), Immediate(0)); |
| 1549 DeoptimizeIf(less, instr); | 1549 DeoptimizeIf(less, instr, "minus zero"); |
| 1550 } | 1550 } |
| 1551 } else { | 1551 } else { |
| 1552 // Test the non-zero operand for negative sign. | 1552 // Test the non-zero operand for negative sign. |
| 1553 __ or_(ToRegister(instr->temp()), ToOperand(right)); | 1553 __ or_(ToRegister(instr->temp()), ToOperand(right)); |
| 1554 DeoptimizeIf(sign, instr); | 1554 DeoptimizeIf(sign, instr, "minus zero"); |
| 1555 } | 1555 } |
| 1556 __ bind(&done); | 1556 __ bind(&done); |
| 1557 } | 1557 } |
| 1558 } | 1558 } |
| 1559 | 1559 |
| 1560 | 1560 |
| 1561 void LCodeGen::DoBitI(LBitI* instr) { | 1561 void LCodeGen::DoBitI(LBitI* instr) { |
| 1562 LOperand* left = instr->left(); | 1562 LOperand* left = instr->left(); |
| 1563 LOperand* right = instr->right(); | 1563 LOperand* right = instr->right(); |
| 1564 DCHECK(left->Equals(instr->result())); | 1564 DCHECK(left->Equals(instr->result())); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1617 case Token::ROR: | 1617 case Token::ROR: |
| 1618 __ ror_cl(ToRegister(left)); | 1618 __ ror_cl(ToRegister(left)); |
| 1619 break; | 1619 break; |
| 1620 case Token::SAR: | 1620 case Token::SAR: |
| 1621 __ sar_cl(ToRegister(left)); | 1621 __ sar_cl(ToRegister(left)); |
| 1622 break; | 1622 break; |
| 1623 case Token::SHR: | 1623 case Token::SHR: |
| 1624 __ shr_cl(ToRegister(left)); | 1624 __ shr_cl(ToRegister(left)); |
| 1625 if (instr->can_deopt()) { | 1625 if (instr->can_deopt()) { |
| 1626 __ test(ToRegister(left), ToRegister(left)); | 1626 __ test(ToRegister(left), ToRegister(left)); |
| 1627 DeoptimizeIf(sign, instr); | 1627 DeoptimizeIf(sign, instr, "negative value"); |
| 1628 } | 1628 } |
| 1629 break; | 1629 break; |
| 1630 case Token::SHL: | 1630 case Token::SHL: |
| 1631 __ shl_cl(ToRegister(left)); | 1631 __ shl_cl(ToRegister(left)); |
| 1632 break; | 1632 break; |
| 1633 default: | 1633 default: |
| 1634 UNREACHABLE(); | 1634 UNREACHABLE(); |
| 1635 break; | 1635 break; |
| 1636 } | 1636 } |
| 1637 } else { | 1637 } else { |
| 1638 int value = ToInteger32(LConstantOperand::cast(right)); | 1638 int value = ToInteger32(LConstantOperand::cast(right)); |
| 1639 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); | 1639 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); |
| 1640 switch (instr->op()) { | 1640 switch (instr->op()) { |
| 1641 case Token::ROR: | 1641 case Token::ROR: |
| 1642 if (shift_count == 0 && instr->can_deopt()) { | 1642 if (shift_count == 0 && instr->can_deopt()) { |
| 1643 __ test(ToRegister(left), ToRegister(left)); | 1643 __ test(ToRegister(left), ToRegister(left)); |
| 1644 DeoptimizeIf(sign, instr); | 1644 DeoptimizeIf(sign, instr, "negative value"); |
| 1645 } else { | 1645 } else { |
| 1646 __ ror(ToRegister(left), shift_count); | 1646 __ ror(ToRegister(left), shift_count); |
| 1647 } | 1647 } |
| 1648 break; | 1648 break; |
| 1649 case Token::SAR: | 1649 case Token::SAR: |
| 1650 if (shift_count != 0) { | 1650 if (shift_count != 0) { |
| 1651 __ sar(ToRegister(left), shift_count); | 1651 __ sar(ToRegister(left), shift_count); |
| 1652 } | 1652 } |
| 1653 break; | 1653 break; |
| 1654 case Token::SHR: | 1654 case Token::SHR: |
| 1655 if (shift_count != 0) { | 1655 if (shift_count != 0) { |
| 1656 __ shr(ToRegister(left), shift_count); | 1656 __ shr(ToRegister(left), shift_count); |
| 1657 } else if (instr->can_deopt()) { | 1657 } else if (instr->can_deopt()) { |
| 1658 __ test(ToRegister(left), ToRegister(left)); | 1658 __ test(ToRegister(left), ToRegister(left)); |
| 1659 DeoptimizeIf(sign, instr); | 1659 DeoptimizeIf(sign, instr, "negative value"); |
| 1660 } | 1660 } |
| 1661 break; | 1661 break; |
| 1662 case Token::SHL: | 1662 case Token::SHL: |
| 1663 if (shift_count != 0) { | 1663 if (shift_count != 0) { |
| 1664 if (instr->hydrogen_value()->representation().IsSmi() && | 1664 if (instr->hydrogen_value()->representation().IsSmi() && |
| 1665 instr->can_deopt()) { | 1665 instr->can_deopt()) { |
| 1666 if (shift_count != 1) { | 1666 if (shift_count != 1) { |
| 1667 __ shl(ToRegister(left), shift_count - 1); | 1667 __ shl(ToRegister(left), shift_count - 1); |
| 1668 } | 1668 } |
| 1669 __ SmiTag(ToRegister(left)); | 1669 __ SmiTag(ToRegister(left)); |
| 1670 DeoptimizeIf(overflow, instr); | 1670 DeoptimizeIf(overflow, instr, "overflow"); |
| 1671 } else { | 1671 } else { |
| 1672 __ shl(ToRegister(left), shift_count); | 1672 __ shl(ToRegister(left), shift_count); |
| 1673 } | 1673 } |
| 1674 } | 1674 } |
| 1675 break; | 1675 break; |
| 1676 default: | 1676 default: |
| 1677 UNREACHABLE(); | 1677 UNREACHABLE(); |
| 1678 break; | 1678 break; |
| 1679 } | 1679 } |
| 1680 } | 1680 } |
| 1681 } | 1681 } |
| 1682 | 1682 |
| 1683 | 1683 |
| 1684 void LCodeGen::DoSubI(LSubI* instr) { | 1684 void LCodeGen::DoSubI(LSubI* instr) { |
| 1685 LOperand* left = instr->left(); | 1685 LOperand* left = instr->left(); |
| 1686 LOperand* right = instr->right(); | 1686 LOperand* right = instr->right(); |
| 1687 DCHECK(left->Equals(instr->result())); | 1687 DCHECK(left->Equals(instr->result())); |
| 1688 | 1688 |
| 1689 if (right->IsConstantOperand()) { | 1689 if (right->IsConstantOperand()) { |
| 1690 __ sub(ToOperand(left), | 1690 __ sub(ToOperand(left), |
| 1691 ToImmediate(right, instr->hydrogen()->representation())); | 1691 ToImmediate(right, instr->hydrogen()->representation())); |
| 1692 } else { | 1692 } else { |
| 1693 __ sub(ToRegister(left), ToOperand(right)); | 1693 __ sub(ToRegister(left), ToOperand(right)); |
| 1694 } | 1694 } |
| 1695 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | 1695 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
| 1696 DeoptimizeIf(overflow, instr); | 1696 DeoptimizeIf(overflow, instr, "overflow"); |
| 1697 } | 1697 } |
| 1698 } | 1698 } |
| 1699 | 1699 |
| 1700 | 1700 |
| 1701 void LCodeGen::DoConstantI(LConstantI* instr) { | 1701 void LCodeGen::DoConstantI(LConstantI* instr) { |
| 1702 __ Move(ToRegister(instr->result()), Immediate(instr->value())); | 1702 __ Move(ToRegister(instr->result()), Immediate(instr->value())); |
| 1703 } | 1703 } |
| 1704 | 1704 |
| 1705 | 1705 |
| 1706 void LCodeGen::DoConstantS(LConstantS* instr) { | 1706 void LCodeGen::DoConstantS(LConstantS* instr) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1770 void LCodeGen::DoDateField(LDateField* instr) { | 1770 void LCodeGen::DoDateField(LDateField* instr) { |
| 1771 Register object = ToRegister(instr->date()); | 1771 Register object = ToRegister(instr->date()); |
| 1772 Register result = ToRegister(instr->result()); | 1772 Register result = ToRegister(instr->result()); |
| 1773 Register scratch = ToRegister(instr->temp()); | 1773 Register scratch = ToRegister(instr->temp()); |
| 1774 Smi* index = instr->index(); | 1774 Smi* index = instr->index(); |
| 1775 Label runtime, done; | 1775 Label runtime, done; |
| 1776 DCHECK(object.is(result)); | 1776 DCHECK(object.is(result)); |
| 1777 DCHECK(object.is(eax)); | 1777 DCHECK(object.is(eax)); |
| 1778 | 1778 |
| 1779 __ test(object, Immediate(kSmiTagMask)); | 1779 __ test(object, Immediate(kSmiTagMask)); |
| 1780 DeoptimizeIf(zero, instr); | 1780 DeoptimizeIf(zero, instr, "Smi"); |
| 1781 __ CmpObjectType(object, JS_DATE_TYPE, scratch); | 1781 __ CmpObjectType(object, JS_DATE_TYPE, scratch); |
| 1782 DeoptimizeIf(not_equal, instr); | 1782 DeoptimizeIf(not_equal, instr, "not a date object"); |
| 1783 | 1783 |
| 1784 if (index->value() == 0) { | 1784 if (index->value() == 0) { |
| 1785 __ mov(result, FieldOperand(object, JSDate::kValueOffset)); | 1785 __ mov(result, FieldOperand(object, JSDate::kValueOffset)); |
| 1786 } else { | 1786 } else { |
| 1787 if (index->value() < JSDate::kFirstUncachedField) { | 1787 if (index->value() < JSDate::kFirstUncachedField) { |
| 1788 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); | 1788 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); |
| 1789 __ mov(scratch, Operand::StaticVariable(stamp)); | 1789 __ mov(scratch, Operand::StaticVariable(stamp)); |
| 1790 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset)); | 1790 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset)); |
| 1791 __ j(not_equal, &runtime, Label::kNear); | 1791 __ j(not_equal, &runtime, Label::kNear); |
| 1792 __ mov(result, FieldOperand(object, JSDate::kValueOffset + | 1792 __ mov(result, FieldOperand(object, JSDate::kValueOffset + |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1902 __ lea(ToRegister(instr->result()), address); | 1902 __ lea(ToRegister(instr->result()), address); |
| 1903 } | 1903 } |
| 1904 } else { | 1904 } else { |
| 1905 if (right->IsConstantOperand()) { | 1905 if (right->IsConstantOperand()) { |
| 1906 __ add(ToOperand(left), | 1906 __ add(ToOperand(left), |
| 1907 ToImmediate(right, instr->hydrogen()->representation())); | 1907 ToImmediate(right, instr->hydrogen()->representation())); |
| 1908 } else { | 1908 } else { |
| 1909 __ add(ToRegister(left), ToOperand(right)); | 1909 __ add(ToRegister(left), ToOperand(right)); |
| 1910 } | 1910 } |
| 1911 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | 1911 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
| 1912 DeoptimizeIf(overflow, instr); | 1912 DeoptimizeIf(overflow, instr, "overflow"); |
| 1913 } | 1913 } |
| 1914 } | 1914 } |
| 1915 } | 1915 } |
| 1916 | 1916 |
| 1917 | 1917 |
| 1918 void LCodeGen::DoMathMinMax(LMathMinMax* instr) { | 1918 void LCodeGen::DoMathMinMax(LMathMinMax* instr) { |
| 1919 LOperand* left = instr->left(); | 1919 LOperand* left = instr->left(); |
| 1920 LOperand* right = instr->right(); | 1920 LOperand* right = instr->right(); |
| 1921 DCHECK(left->Equals(instr->result())); | 1921 DCHECK(left->Equals(instr->result())); |
| 1922 HMathMinMax::Operation operation = instr->hydrogen()->operation(); | 1922 HMathMinMax::Operation operation = instr->hydrogen()->operation(); |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2126 } | 2126 } |
| 2127 | 2127 |
| 2128 if (expected.Contains(ToBooleanStub::SMI)) { | 2128 if (expected.Contains(ToBooleanStub::SMI)) { |
| 2129 // Smis: 0 -> false, all other -> true. | 2129 // Smis: 0 -> false, all other -> true. |
| 2130 __ test(reg, Operand(reg)); | 2130 __ test(reg, Operand(reg)); |
| 2131 __ j(equal, instr->FalseLabel(chunk_)); | 2131 __ j(equal, instr->FalseLabel(chunk_)); |
| 2132 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); | 2132 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); |
| 2133 } else if (expected.NeedsMap()) { | 2133 } else if (expected.NeedsMap()) { |
| 2134 // If we need a map later and have a Smi -> deopt. | 2134 // If we need a map later and have a Smi -> deopt. |
| 2135 __ test(reg, Immediate(kSmiTagMask)); | 2135 __ test(reg, Immediate(kSmiTagMask)); |
| 2136 DeoptimizeIf(zero, instr); | 2136 DeoptimizeIf(zero, instr, "Smi"); |
| 2137 } | 2137 } |
| 2138 | 2138 |
| 2139 Register map = no_reg; // Keep the compiler happy. | 2139 Register map = no_reg; // Keep the compiler happy. |
| 2140 if (expected.NeedsMap()) { | 2140 if (expected.NeedsMap()) { |
| 2141 map = ToRegister(instr->temp()); | 2141 map = ToRegister(instr->temp()); |
| 2142 DCHECK(!map.is(reg)); | 2142 DCHECK(!map.is(reg)); |
| 2143 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset)); | 2143 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset)); |
| 2144 | 2144 |
| 2145 if (expected.CanBeUndetectable()) { | 2145 if (expected.CanBeUndetectable()) { |
| 2146 // Undetectable -> false. | 2146 // Undetectable -> false. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2183 __ xorps(xmm_scratch, xmm_scratch); | 2183 __ xorps(xmm_scratch, xmm_scratch); |
| 2184 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset)); | 2184 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset)); |
| 2185 __ j(zero, instr->FalseLabel(chunk_)); | 2185 __ j(zero, instr->FalseLabel(chunk_)); |
| 2186 __ jmp(instr->TrueLabel(chunk_)); | 2186 __ jmp(instr->TrueLabel(chunk_)); |
| 2187 __ bind(¬_heap_number); | 2187 __ bind(¬_heap_number); |
| 2188 } | 2188 } |
| 2189 | 2189 |
| 2190 if (!expected.IsGeneric()) { | 2190 if (!expected.IsGeneric()) { |
| 2191 // We've seen something for the first time -> deopt. | 2191 // We've seen something for the first time -> deopt. |
| 2192 // This can only happen if we are not generic already. | 2192 // This can only happen if we are not generic already. |
| 2193 DeoptimizeIf(no_condition, instr); | 2193 DeoptimizeIf(no_condition, instr, "unexpected object"); |
| 2194 } | 2194 } |
| 2195 } | 2195 } |
| 2196 } | 2196 } |
| 2197 } | 2197 } |
| 2198 | 2198 |
| 2199 | 2199 |
| 2200 void LCodeGen::EmitGoto(int block) { | 2200 void LCodeGen::EmitGoto(int block) { |
| 2201 if (!IsNextEmittedBlock(block)) { | 2201 if (!IsNextEmittedBlock(block)) { |
| 2202 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block))); | 2202 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block))); |
| 2203 } | 2203 } |
| (...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2813 info()->AddNoFrameRange(no_frame_start, masm_->pc_offset()); | 2813 info()->AddNoFrameRange(no_frame_start, masm_->pc_offset()); |
| 2814 } | 2814 } |
| 2815 } | 2815 } |
| 2816 | 2816 |
| 2817 | 2817 |
| 2818 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { | 2818 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { |
| 2819 Register result = ToRegister(instr->result()); | 2819 Register result = ToRegister(instr->result()); |
| 2820 __ mov(result, Operand::ForCell(instr->hydrogen()->cell().handle())); | 2820 __ mov(result, Operand::ForCell(instr->hydrogen()->cell().handle())); |
| 2821 if (instr->hydrogen()->RequiresHoleCheck()) { | 2821 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2822 __ cmp(result, factory()->the_hole_value()); | 2822 __ cmp(result, factory()->the_hole_value()); |
| 2823 DeoptimizeIf(equal, instr); | 2823 DeoptimizeIf(equal, instr, "hole"); |
| 2824 } | 2824 } |
| 2825 } | 2825 } |
| 2826 | 2826 |
| 2827 | 2827 |
| 2828 template <class T> | 2828 template <class T> |
| 2829 void LCodeGen::EmitVectorLoadICRegisters(T* instr) { | 2829 void LCodeGen::EmitVectorLoadICRegisters(T* instr) { |
| 2830 DCHECK(FLAG_vector_ics); | 2830 DCHECK(FLAG_vector_ics); |
| 2831 Register vector = ToRegister(instr->temp_vector()); | 2831 Register vector = ToRegister(instr->temp_vector()); |
| 2832 DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister())); | 2832 DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister())); |
| 2833 __ mov(vector, instr->hydrogen()->feedback_vector()); | 2833 __ mov(vector, instr->hydrogen()->feedback_vector()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2857 void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { | 2857 void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { |
| 2858 Register value = ToRegister(instr->value()); | 2858 Register value = ToRegister(instr->value()); |
| 2859 Handle<PropertyCell> cell_handle = instr->hydrogen()->cell().handle(); | 2859 Handle<PropertyCell> cell_handle = instr->hydrogen()->cell().handle(); |
| 2860 | 2860 |
| 2861 // If the cell we are storing to contains the hole it could have | 2861 // If the cell we are storing to contains the hole it could have |
| 2862 // been deleted from the property dictionary. In that case, we need | 2862 // been deleted from the property dictionary. In that case, we need |
| 2863 // to update the property details in the property dictionary to mark | 2863 // to update the property details in the property dictionary to mark |
| 2864 // it as no longer deleted. We deoptimize in that case. | 2864 // it as no longer deleted. We deoptimize in that case. |
| 2865 if (instr->hydrogen()->RequiresHoleCheck()) { | 2865 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2866 __ cmp(Operand::ForCell(cell_handle), factory()->the_hole_value()); | 2866 __ cmp(Operand::ForCell(cell_handle), factory()->the_hole_value()); |
| 2867 DeoptimizeIf(equal, instr); | 2867 DeoptimizeIf(equal, instr, "hole"); |
| 2868 } | 2868 } |
| 2869 | 2869 |
| 2870 // Store the value. | 2870 // Store the value. |
| 2871 __ mov(Operand::ForCell(cell_handle), value); | 2871 __ mov(Operand::ForCell(cell_handle), value); |
| 2872 // Cells are always rescanned, so no write barrier here. | 2872 // Cells are always rescanned, so no write barrier here. |
| 2873 } | 2873 } |
| 2874 | 2874 |
| 2875 | 2875 |
| 2876 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { | 2876 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { |
| 2877 Register context = ToRegister(instr->context()); | 2877 Register context = ToRegister(instr->context()); |
| 2878 Register result = ToRegister(instr->result()); | 2878 Register result = ToRegister(instr->result()); |
| 2879 __ mov(result, ContextOperand(context, instr->slot_index())); | 2879 __ mov(result, ContextOperand(context, instr->slot_index())); |
| 2880 | 2880 |
| 2881 if (instr->hydrogen()->RequiresHoleCheck()) { | 2881 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2882 __ cmp(result, factory()->the_hole_value()); | 2882 __ cmp(result, factory()->the_hole_value()); |
| 2883 if (instr->hydrogen()->DeoptimizesOnHole()) { | 2883 if (instr->hydrogen()->DeoptimizesOnHole()) { |
| 2884 DeoptimizeIf(equal, instr); | 2884 DeoptimizeIf(equal, instr, "hole"); |
| 2885 } else { | 2885 } else { |
| 2886 Label is_not_hole; | 2886 Label is_not_hole; |
| 2887 __ j(not_equal, &is_not_hole, Label::kNear); | 2887 __ j(not_equal, &is_not_hole, Label::kNear); |
| 2888 __ mov(result, factory()->undefined_value()); | 2888 __ mov(result, factory()->undefined_value()); |
| 2889 __ bind(&is_not_hole); | 2889 __ bind(&is_not_hole); |
| 2890 } | 2890 } |
| 2891 } | 2891 } |
| 2892 } | 2892 } |
| 2893 | 2893 |
| 2894 | 2894 |
| 2895 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { | 2895 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { |
| 2896 Register context = ToRegister(instr->context()); | 2896 Register context = ToRegister(instr->context()); |
| 2897 Register value = ToRegister(instr->value()); | 2897 Register value = ToRegister(instr->value()); |
| 2898 | 2898 |
| 2899 Label skip_assignment; | 2899 Label skip_assignment; |
| 2900 | 2900 |
| 2901 Operand target = ContextOperand(context, instr->slot_index()); | 2901 Operand target = ContextOperand(context, instr->slot_index()); |
| 2902 if (instr->hydrogen()->RequiresHoleCheck()) { | 2902 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2903 __ cmp(target, factory()->the_hole_value()); | 2903 __ cmp(target, factory()->the_hole_value()); |
| 2904 if (instr->hydrogen()->DeoptimizesOnHole()) { | 2904 if (instr->hydrogen()->DeoptimizesOnHole()) { |
| 2905 DeoptimizeIf(equal, instr); | 2905 DeoptimizeIf(equal, instr, "hole"); |
| 2906 } else { | 2906 } else { |
| 2907 __ j(not_equal, &skip_assignment, Label::kNear); | 2907 __ j(not_equal, &skip_assignment, Label::kNear); |
| 2908 } | 2908 } |
| 2909 } | 2909 } |
| 2910 | 2910 |
| 2911 __ mov(target, value); | 2911 __ mov(target, value); |
| 2912 if (instr->hydrogen()->NeedsWriteBarrier()) { | 2912 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 2913 SmiCheck check_needed = | 2913 SmiCheck check_needed = |
| 2914 instr->hydrogen()->value()->type().IsHeapObject() | 2914 instr->hydrogen()->value()->type().IsHeapObject() |
| 2915 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 2915 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2994 Register function = ToRegister(instr->function()); | 2994 Register function = ToRegister(instr->function()); |
| 2995 Register temp = ToRegister(instr->temp()); | 2995 Register temp = ToRegister(instr->temp()); |
| 2996 Register result = ToRegister(instr->result()); | 2996 Register result = ToRegister(instr->result()); |
| 2997 | 2997 |
| 2998 // Get the prototype or initial map from the function. | 2998 // Get the prototype or initial map from the function. |
| 2999 __ mov(result, | 2999 __ mov(result, |
| 3000 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 3000 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
| 3001 | 3001 |
| 3002 // Check that the function has a prototype or an initial map. | 3002 // Check that the function has a prototype or an initial map. |
| 3003 __ cmp(Operand(result), Immediate(factory()->the_hole_value())); | 3003 __ cmp(Operand(result), Immediate(factory()->the_hole_value())); |
| 3004 DeoptimizeIf(equal, instr); | 3004 DeoptimizeIf(equal, instr, "hole"); |
| 3005 | 3005 |
| 3006 // If the function does not have an initial map, we're done. | 3006 // If the function does not have an initial map, we're done. |
| 3007 Label done; | 3007 Label done; |
| 3008 __ CmpObjectType(result, MAP_TYPE, temp); | 3008 __ CmpObjectType(result, MAP_TYPE, temp); |
| 3009 __ j(not_equal, &done, Label::kNear); | 3009 __ j(not_equal, &done, Label::kNear); |
| 3010 | 3010 |
| 3011 // Get the prototype from the initial map. | 3011 // Get the prototype from the initial map. |
| 3012 __ mov(result, FieldOperand(result, Map::kPrototypeOffset)); | 3012 __ mov(result, FieldOperand(result, Map::kPrototypeOffset)); |
| 3013 | 3013 |
| 3014 // All done. | 3014 // All done. |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3087 break; | 3087 break; |
| 3088 case EXTERNAL_INT32_ELEMENTS: | 3088 case EXTERNAL_INT32_ELEMENTS: |
| 3089 case INT32_ELEMENTS: | 3089 case INT32_ELEMENTS: |
| 3090 __ mov(result, operand); | 3090 __ mov(result, operand); |
| 3091 break; | 3091 break; |
| 3092 case EXTERNAL_UINT32_ELEMENTS: | 3092 case EXTERNAL_UINT32_ELEMENTS: |
| 3093 case UINT32_ELEMENTS: | 3093 case UINT32_ELEMENTS: |
| 3094 __ mov(result, operand); | 3094 __ mov(result, operand); |
| 3095 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { | 3095 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { |
| 3096 __ test(result, Operand(result)); | 3096 __ test(result, Operand(result)); |
| 3097 DeoptimizeIf(negative, instr); | 3097 DeoptimizeIf(negative, instr, "negative value"); |
| 3098 } | 3098 } |
| 3099 break; | 3099 break; |
| 3100 case EXTERNAL_FLOAT32_ELEMENTS: | 3100 case EXTERNAL_FLOAT32_ELEMENTS: |
| 3101 case EXTERNAL_FLOAT64_ELEMENTS: | 3101 case EXTERNAL_FLOAT64_ELEMENTS: |
| 3102 case FLOAT32_ELEMENTS: | 3102 case FLOAT32_ELEMENTS: |
| 3103 case FLOAT64_ELEMENTS: | 3103 case FLOAT64_ELEMENTS: |
| 3104 case FAST_SMI_ELEMENTS: | 3104 case FAST_SMI_ELEMENTS: |
| 3105 case FAST_ELEMENTS: | 3105 case FAST_ELEMENTS: |
| 3106 case FAST_DOUBLE_ELEMENTS: | 3106 case FAST_DOUBLE_ELEMENTS: |
| 3107 case FAST_HOLEY_SMI_ELEMENTS: | 3107 case FAST_HOLEY_SMI_ELEMENTS: |
| 3108 case FAST_HOLEY_ELEMENTS: | 3108 case FAST_HOLEY_ELEMENTS: |
| 3109 case FAST_HOLEY_DOUBLE_ELEMENTS: | 3109 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 3110 case DICTIONARY_ELEMENTS: | 3110 case DICTIONARY_ELEMENTS: |
| 3111 case SLOPPY_ARGUMENTS_ELEMENTS: | 3111 case SLOPPY_ARGUMENTS_ELEMENTS: |
| 3112 UNREACHABLE(); | 3112 UNREACHABLE(); |
| 3113 break; | 3113 break; |
| 3114 } | 3114 } |
| 3115 } | 3115 } |
| 3116 } | 3116 } |
| 3117 | 3117 |
| 3118 | 3118 |
| 3119 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { | 3119 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { |
| 3120 if (instr->hydrogen()->RequiresHoleCheck()) { | 3120 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 3121 Operand hole_check_operand = BuildFastArrayOperand( | 3121 Operand hole_check_operand = BuildFastArrayOperand( |
| 3122 instr->elements(), instr->key(), | 3122 instr->elements(), instr->key(), |
| 3123 instr->hydrogen()->key()->representation(), | 3123 instr->hydrogen()->key()->representation(), |
| 3124 FAST_DOUBLE_ELEMENTS, | 3124 FAST_DOUBLE_ELEMENTS, |
| 3125 instr->base_offset() + sizeof(kHoleNanLower32)); | 3125 instr->base_offset() + sizeof(kHoleNanLower32)); |
| 3126 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32)); | 3126 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32)); |
| 3127 DeoptimizeIf(equal, instr); | 3127 DeoptimizeIf(equal, instr, "hole"); |
| 3128 } | 3128 } |
| 3129 | 3129 |
| 3130 Operand double_load_operand = BuildFastArrayOperand( | 3130 Operand double_load_operand = BuildFastArrayOperand( |
| 3131 instr->elements(), | 3131 instr->elements(), |
| 3132 instr->key(), | 3132 instr->key(), |
| 3133 instr->hydrogen()->key()->representation(), | 3133 instr->hydrogen()->key()->representation(), |
| 3134 FAST_DOUBLE_ELEMENTS, | 3134 FAST_DOUBLE_ELEMENTS, |
| 3135 instr->base_offset()); | 3135 instr->base_offset()); |
| 3136 XMMRegister result = ToDoubleRegister(instr->result()); | 3136 XMMRegister result = ToDoubleRegister(instr->result()); |
| 3137 __ movsd(result, double_load_operand); | 3137 __ movsd(result, double_load_operand); |
| 3138 } | 3138 } |
| 3139 | 3139 |
| 3140 | 3140 |
| 3141 void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { | 3141 void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { |
| 3142 Register result = ToRegister(instr->result()); | 3142 Register result = ToRegister(instr->result()); |
| 3143 | 3143 |
| 3144 // Load the result. | 3144 // Load the result. |
| 3145 __ mov(result, | 3145 __ mov(result, |
| 3146 BuildFastArrayOperand(instr->elements(), instr->key(), | 3146 BuildFastArrayOperand(instr->elements(), instr->key(), |
| 3147 instr->hydrogen()->key()->representation(), | 3147 instr->hydrogen()->key()->representation(), |
| 3148 FAST_ELEMENTS, instr->base_offset())); | 3148 FAST_ELEMENTS, instr->base_offset())); |
| 3149 | 3149 |
| 3150 // Check for the hole value. | 3150 // Check for the hole value. |
| 3151 if (instr->hydrogen()->RequiresHoleCheck()) { | 3151 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 3152 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { | 3152 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { |
| 3153 __ test(result, Immediate(kSmiTagMask)); | 3153 __ test(result, Immediate(kSmiTagMask)); |
| 3154 DeoptimizeIf(not_equal, instr); | 3154 DeoptimizeIf(not_equal, instr, "not a Smi"); |
| 3155 } else { | 3155 } else { |
| 3156 __ cmp(result, factory()->the_hole_value()); | 3156 __ cmp(result, factory()->the_hole_value()); |
| 3157 DeoptimizeIf(equal, instr); | 3157 DeoptimizeIf(equal, instr, "hole"); |
| 3158 } | 3158 } |
| 3159 } | 3159 } |
| 3160 } | 3160 } |
| 3161 | 3161 |
| 3162 | 3162 |
| 3163 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { | 3163 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { |
| 3164 if (instr->is_typed_elements()) { | 3164 if (instr->is_typed_elements()) { |
| 3165 DoLoadKeyedExternalArray(instr); | 3165 DoLoadKeyedExternalArray(instr); |
| 3166 } else if (instr->hydrogen()->representation().IsDouble()) { | 3166 } else if (instr->hydrogen()->representation().IsDouble()) { |
| 3167 DoLoadKeyedFixedDoubleArray(instr); | 3167 DoLoadKeyedFixedDoubleArray(instr); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3294 } | 3294 } |
| 3295 | 3295 |
| 3296 // Normal function. Replace undefined or null with global receiver. | 3296 // Normal function. Replace undefined or null with global receiver. |
| 3297 __ cmp(receiver, factory()->null_value()); | 3297 __ cmp(receiver, factory()->null_value()); |
| 3298 __ j(equal, &global_object, Label::kNear); | 3298 __ j(equal, &global_object, Label::kNear); |
| 3299 __ cmp(receiver, factory()->undefined_value()); | 3299 __ cmp(receiver, factory()->undefined_value()); |
| 3300 __ j(equal, &global_object, Label::kNear); | 3300 __ j(equal, &global_object, Label::kNear); |
| 3301 | 3301 |
| 3302 // The receiver should be a JS object. | 3302 // The receiver should be a JS object. |
| 3303 __ test(receiver, Immediate(kSmiTagMask)); | 3303 __ test(receiver, Immediate(kSmiTagMask)); |
| 3304 DeoptimizeIf(equal, instr); | 3304 DeoptimizeIf(equal, instr, "Smi"); |
| 3305 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch); | 3305 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch); |
| 3306 DeoptimizeIf(below, instr); | 3306 DeoptimizeIf(below, instr, "not a JavaScript object"); |
| 3307 | 3307 |
| 3308 __ jmp(&receiver_ok, Label::kNear); | 3308 __ jmp(&receiver_ok, Label::kNear); |
| 3309 __ bind(&global_object); | 3309 __ bind(&global_object); |
| 3310 __ mov(receiver, FieldOperand(function, JSFunction::kContextOffset)); | 3310 __ mov(receiver, FieldOperand(function, JSFunction::kContextOffset)); |
| 3311 const int global_offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX); | 3311 const int global_offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX); |
| 3312 __ mov(receiver, Operand(receiver, global_offset)); | 3312 __ mov(receiver, Operand(receiver, global_offset)); |
| 3313 const int proxy_offset = GlobalObject::kGlobalProxyOffset; | 3313 const int proxy_offset = GlobalObject::kGlobalProxyOffset; |
| 3314 __ mov(receiver, FieldOperand(receiver, proxy_offset)); | 3314 __ mov(receiver, FieldOperand(receiver, proxy_offset)); |
| 3315 __ bind(&receiver_ok); | 3315 __ bind(&receiver_ok); |
| 3316 } | 3316 } |
| 3317 | 3317 |
| 3318 | 3318 |
| 3319 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { | 3319 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { |
| 3320 Register receiver = ToRegister(instr->receiver()); | 3320 Register receiver = ToRegister(instr->receiver()); |
| 3321 Register function = ToRegister(instr->function()); | 3321 Register function = ToRegister(instr->function()); |
| 3322 Register length = ToRegister(instr->length()); | 3322 Register length = ToRegister(instr->length()); |
| 3323 Register elements = ToRegister(instr->elements()); | 3323 Register elements = ToRegister(instr->elements()); |
| 3324 DCHECK(receiver.is(eax)); // Used for parameter count. | 3324 DCHECK(receiver.is(eax)); // Used for parameter count. |
| 3325 DCHECK(function.is(edi)); // Required by InvokeFunction. | 3325 DCHECK(function.is(edi)); // Required by InvokeFunction. |
| 3326 DCHECK(ToRegister(instr->result()).is(eax)); | 3326 DCHECK(ToRegister(instr->result()).is(eax)); |
| 3327 | 3327 |
| 3328 // Copy the arguments to this function possibly from the | 3328 // Copy the arguments to this function possibly from the |
| 3329 // adaptor frame below it. | 3329 // adaptor frame below it. |
| 3330 const uint32_t kArgumentsLimit = 1 * KB; | 3330 const uint32_t kArgumentsLimit = 1 * KB; |
| 3331 __ cmp(length, kArgumentsLimit); | 3331 __ cmp(length, kArgumentsLimit); |
| 3332 DeoptimizeIf(above, instr); | 3332 DeoptimizeIf(above, instr, "too many arguments"); |
| 3333 | 3333 |
| 3334 __ push(receiver); | 3334 __ push(receiver); |
| 3335 __ mov(receiver, length); | 3335 __ mov(receiver, length); |
| 3336 | 3336 |
| 3337 // Loop through the arguments pushing them onto the execution | 3337 // Loop through the arguments pushing them onto the execution |
| 3338 // stack. | 3338 // stack. |
| 3339 Label invoke, loop; | 3339 Label invoke, loop; |
| 3340 // length is a small non-negative integer, due to the test above. | 3340 // length is a small non-negative integer, due to the test above. |
| 3341 __ test(length, Operand(length)); | 3341 __ test(length, Operand(length)); |
| 3342 __ j(zero, &invoke, Label::kNear); | 3342 __ j(zero, &invoke, Label::kNear); |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3515 } | 3515 } |
| 3516 | 3516 |
| 3517 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); | 3517 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); |
| 3518 } | 3518 } |
| 3519 | 3519 |
| 3520 | 3520 |
| 3521 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) { | 3521 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) { |
| 3522 Register input_reg = ToRegister(instr->value()); | 3522 Register input_reg = ToRegister(instr->value()); |
| 3523 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 3523 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 3524 factory()->heap_number_map()); | 3524 factory()->heap_number_map()); |
| 3525 DeoptimizeIf(not_equal, instr); | 3525 DeoptimizeIf(not_equal, instr, "not a heap number"); |
| 3526 | 3526 |
| 3527 Label slow, allocated, done; | 3527 Label slow, allocated, done; |
| 3528 Register tmp = input_reg.is(eax) ? ecx : eax; | 3528 Register tmp = input_reg.is(eax) ? ecx : eax; |
| 3529 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx; | 3529 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx; |
| 3530 | 3530 |
| 3531 // Preserve the value of all registers. | 3531 // Preserve the value of all registers. |
| 3532 PushSafepointRegistersScope scope(this); | 3532 PushSafepointRegistersScope scope(this); |
| 3533 | 3533 |
| 3534 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset)); | 3534 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset)); |
| 3535 // Check the sign of the argument. If the argument is positive, just | 3535 // Check the sign of the argument. If the argument is positive, just |
| (...skipping 26 matching lines...) Expand all Loading... |
| 3562 __ bind(&done); | 3562 __ bind(&done); |
| 3563 } | 3563 } |
| 3564 | 3564 |
| 3565 | 3565 |
| 3566 void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) { | 3566 void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) { |
| 3567 Register input_reg = ToRegister(instr->value()); | 3567 Register input_reg = ToRegister(instr->value()); |
| 3568 __ test(input_reg, Operand(input_reg)); | 3568 __ test(input_reg, Operand(input_reg)); |
| 3569 Label is_positive; | 3569 Label is_positive; |
| 3570 __ j(not_sign, &is_positive, Label::kNear); | 3570 __ j(not_sign, &is_positive, Label::kNear); |
| 3571 __ neg(input_reg); // Sets flags. | 3571 __ neg(input_reg); // Sets flags. |
| 3572 DeoptimizeIf(negative, instr); | 3572 DeoptimizeIf(negative, instr, "overflow"); |
| 3573 __ bind(&is_positive); | 3573 __ bind(&is_positive); |
| 3574 } | 3574 } |
| 3575 | 3575 |
| 3576 | 3576 |
| 3577 void LCodeGen::DoMathAbs(LMathAbs* instr) { | 3577 void LCodeGen::DoMathAbs(LMathAbs* instr) { |
| 3578 // Class for deferred case. | 3578 // Class for deferred case. |
| 3579 class DeferredMathAbsTaggedHeapNumber FINAL : public LDeferredCode { | 3579 class DeferredMathAbsTaggedHeapNumber FINAL : public LDeferredCode { |
| 3580 public: | 3580 public: |
| 3581 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, | 3581 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, |
| 3582 LMathAbs* instr) | 3582 LMathAbs* instr) |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3620 if (CpuFeatures::IsSupported(SSE4_1)) { | 3620 if (CpuFeatures::IsSupported(SSE4_1)) { |
| 3621 CpuFeatureScope scope(masm(), SSE4_1); | 3621 CpuFeatureScope scope(masm(), SSE4_1); |
| 3622 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 3622 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 3623 // Deoptimize on negative zero. | 3623 // Deoptimize on negative zero. |
| 3624 Label non_zero; | 3624 Label non_zero; |
| 3625 __ xorps(xmm_scratch, xmm_scratch); // Zero the register. | 3625 __ xorps(xmm_scratch, xmm_scratch); // Zero the register. |
| 3626 __ ucomisd(input_reg, xmm_scratch); | 3626 __ ucomisd(input_reg, xmm_scratch); |
| 3627 __ j(not_equal, &non_zero, Label::kNear); | 3627 __ j(not_equal, &non_zero, Label::kNear); |
| 3628 __ movmskpd(output_reg, input_reg); | 3628 __ movmskpd(output_reg, input_reg); |
| 3629 __ test(output_reg, Immediate(1)); | 3629 __ test(output_reg, Immediate(1)); |
| 3630 DeoptimizeIf(not_zero, instr); | 3630 DeoptimizeIf(not_zero, instr, "minus zero"); |
| 3631 __ bind(&non_zero); | 3631 __ bind(&non_zero); |
| 3632 } | 3632 } |
| 3633 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown); | 3633 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown); |
| 3634 __ cvttsd2si(output_reg, Operand(xmm_scratch)); | 3634 __ cvttsd2si(output_reg, Operand(xmm_scratch)); |
| 3635 // Overflow is signalled with minint. | 3635 // Overflow is signalled with minint. |
| 3636 __ cmp(output_reg, 0x1); | 3636 __ cmp(output_reg, 0x1); |
| 3637 DeoptimizeIf(overflow, instr); | 3637 DeoptimizeIf(overflow, instr, "overflow"); |
| 3638 } else { | 3638 } else { |
| 3639 Label negative_sign, done; | 3639 Label negative_sign, done; |
| 3640 // Deoptimize on unordered. | 3640 // Deoptimize on unordered. |
| 3641 __ xorps(xmm_scratch, xmm_scratch); // Zero the register. | 3641 __ xorps(xmm_scratch, xmm_scratch); // Zero the register. |
| 3642 __ ucomisd(input_reg, xmm_scratch); | 3642 __ ucomisd(input_reg, xmm_scratch); |
| 3643 DeoptimizeIf(parity_even, instr); | 3643 DeoptimizeIf(parity_even, instr, "NaN"); |
| 3644 __ j(below, &negative_sign, Label::kNear); | 3644 __ j(below, &negative_sign, Label::kNear); |
| 3645 | 3645 |
| 3646 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 3646 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 3647 // Check for negative zero. | 3647 // Check for negative zero. |
| 3648 Label positive_sign; | 3648 Label positive_sign; |
| 3649 __ j(above, &positive_sign, Label::kNear); | 3649 __ j(above, &positive_sign, Label::kNear); |
| 3650 __ movmskpd(output_reg, input_reg); | 3650 __ movmskpd(output_reg, input_reg); |
| 3651 __ test(output_reg, Immediate(1)); | 3651 __ test(output_reg, Immediate(1)); |
| 3652 DeoptimizeIf(not_zero, instr); | 3652 DeoptimizeIf(not_zero, instr, "minus zero"); |
| 3653 __ Move(output_reg, Immediate(0)); | 3653 __ Move(output_reg, Immediate(0)); |
| 3654 __ jmp(&done, Label::kNear); | 3654 __ jmp(&done, Label::kNear); |
| 3655 __ bind(&positive_sign); | 3655 __ bind(&positive_sign); |
| 3656 } | 3656 } |
| 3657 | 3657 |
| 3658 // Use truncating instruction (OK because input is positive). | 3658 // Use truncating instruction (OK because input is positive). |
| 3659 __ cvttsd2si(output_reg, Operand(input_reg)); | 3659 __ cvttsd2si(output_reg, Operand(input_reg)); |
| 3660 // Overflow is signalled with minint. | 3660 // Overflow is signalled with minint. |
| 3661 __ cmp(output_reg, 0x1); | 3661 __ cmp(output_reg, 0x1); |
| 3662 DeoptimizeIf(overflow, instr); | 3662 DeoptimizeIf(overflow, instr, "overflow"); |
| 3663 __ jmp(&done, Label::kNear); | 3663 __ jmp(&done, Label::kNear); |
| 3664 | 3664 |
| 3665 // Non-zero negative reaches here. | 3665 // Non-zero negative reaches here. |
| 3666 __ bind(&negative_sign); | 3666 __ bind(&negative_sign); |
| 3667 // Truncate, then compare and compensate. | 3667 // Truncate, then compare and compensate. |
| 3668 __ cvttsd2si(output_reg, Operand(input_reg)); | 3668 __ cvttsd2si(output_reg, Operand(input_reg)); |
| 3669 __ Cvtsi2sd(xmm_scratch, output_reg); | 3669 __ Cvtsi2sd(xmm_scratch, output_reg); |
| 3670 __ ucomisd(input_reg, xmm_scratch); | 3670 __ ucomisd(input_reg, xmm_scratch); |
| 3671 __ j(equal, &done, Label::kNear); | 3671 __ j(equal, &done, Label::kNear); |
| 3672 __ sub(output_reg, Immediate(1)); | 3672 __ sub(output_reg, Immediate(1)); |
| 3673 DeoptimizeIf(overflow, instr); | 3673 DeoptimizeIf(overflow, instr, "overflow"); |
| 3674 | 3674 |
| 3675 __ bind(&done); | 3675 __ bind(&done); |
| 3676 } | 3676 } |
| 3677 } | 3677 } |
| 3678 | 3678 |
| 3679 | 3679 |
| 3680 void LCodeGen::DoMathRound(LMathRound* instr) { | 3680 void LCodeGen::DoMathRound(LMathRound* instr) { |
| 3681 Register output_reg = ToRegister(instr->result()); | 3681 Register output_reg = ToRegister(instr->result()); |
| 3682 XMMRegister input_reg = ToDoubleRegister(instr->value()); | 3682 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 3683 XMMRegister xmm_scratch = double_scratch0(); | 3683 XMMRegister xmm_scratch = double_scratch0(); |
| 3684 XMMRegister input_temp = ToDoubleRegister(instr->temp()); | 3684 XMMRegister input_temp = ToDoubleRegister(instr->temp()); |
| 3685 ExternalReference one_half = ExternalReference::address_of_one_half(); | 3685 ExternalReference one_half = ExternalReference::address_of_one_half(); |
| 3686 ExternalReference minus_one_half = | 3686 ExternalReference minus_one_half = |
| 3687 ExternalReference::address_of_minus_one_half(); | 3687 ExternalReference::address_of_minus_one_half(); |
| 3688 | 3688 |
| 3689 Label done, round_to_zero, below_one_half, do_not_compensate; | 3689 Label done, round_to_zero, below_one_half, do_not_compensate; |
| 3690 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear; | 3690 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear; |
| 3691 | 3691 |
| 3692 __ movsd(xmm_scratch, Operand::StaticVariable(one_half)); | 3692 __ movsd(xmm_scratch, Operand::StaticVariable(one_half)); |
| 3693 __ ucomisd(xmm_scratch, input_reg); | 3693 __ ucomisd(xmm_scratch, input_reg); |
| 3694 __ j(above, &below_one_half, Label::kNear); | 3694 __ j(above, &below_one_half, Label::kNear); |
| 3695 | 3695 |
| 3696 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x). | 3696 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x). |
| 3697 __ addsd(xmm_scratch, input_reg); | 3697 __ addsd(xmm_scratch, input_reg); |
| 3698 __ cvttsd2si(output_reg, Operand(xmm_scratch)); | 3698 __ cvttsd2si(output_reg, Operand(xmm_scratch)); |
| 3699 // Overflow is signalled with minint. | 3699 // Overflow is signalled with minint. |
| 3700 __ cmp(output_reg, 0x1); | 3700 __ cmp(output_reg, 0x1); |
| 3701 DeoptimizeIf(overflow, instr, "conversion overflow"); | 3701 DeoptimizeIf(overflow, instr, "overflow"); |
| 3702 __ jmp(&done, dist); | 3702 __ jmp(&done, dist); |
| 3703 | 3703 |
| 3704 __ bind(&below_one_half); | 3704 __ bind(&below_one_half); |
| 3705 __ movsd(xmm_scratch, Operand::StaticVariable(minus_one_half)); | 3705 __ movsd(xmm_scratch, Operand::StaticVariable(minus_one_half)); |
| 3706 __ ucomisd(xmm_scratch, input_reg); | 3706 __ ucomisd(xmm_scratch, input_reg); |
| 3707 __ j(below_equal, &round_to_zero, Label::kNear); | 3707 __ j(below_equal, &round_to_zero, Label::kNear); |
| 3708 | 3708 |
| 3709 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then | 3709 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then |
| 3710 // compare and compensate. | 3710 // compare and compensate. |
| 3711 __ movaps(input_temp, input_reg); // Do not alter input_reg. | 3711 __ movaps(input_temp, input_reg); // Do not alter input_reg. |
| 3712 __ subsd(input_temp, xmm_scratch); | 3712 __ subsd(input_temp, xmm_scratch); |
| 3713 __ cvttsd2si(output_reg, Operand(input_temp)); | 3713 __ cvttsd2si(output_reg, Operand(input_temp)); |
| 3714 // Catch minint due to overflow, and to prevent overflow when compensating. | 3714 // Catch minint due to overflow, and to prevent overflow when compensating. |
| 3715 __ cmp(output_reg, 0x1); | 3715 __ cmp(output_reg, 0x1); |
| 3716 DeoptimizeIf(overflow, instr, "conversion overflow"); | 3716 DeoptimizeIf(overflow, instr, "overflow"); |
| 3717 | 3717 |
| 3718 __ Cvtsi2sd(xmm_scratch, output_reg); | 3718 __ Cvtsi2sd(xmm_scratch, output_reg); |
| 3719 __ ucomisd(xmm_scratch, input_temp); | 3719 __ ucomisd(xmm_scratch, input_temp); |
| 3720 __ j(equal, &done, dist); | 3720 __ j(equal, &done, dist); |
| 3721 __ sub(output_reg, Immediate(1)); | 3721 __ sub(output_reg, Immediate(1)); |
| 3722 // No overflow because we already ruled out minint. | 3722 // No overflow because we already ruled out minint. |
| 3723 __ jmp(&done, dist); | 3723 __ jmp(&done, dist); |
| 3724 | 3724 |
| 3725 __ bind(&round_to_zero); | 3725 __ bind(&round_to_zero); |
| 3726 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if | 3726 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3798 DCHECK(ToDoubleRegister(instr->result()).is(xmm3)); | 3798 DCHECK(ToDoubleRegister(instr->result()).is(xmm3)); |
| 3799 | 3799 |
| 3800 if (exponent_type.IsSmi()) { | 3800 if (exponent_type.IsSmi()) { |
| 3801 MathPowStub stub(isolate(), MathPowStub::TAGGED); | 3801 MathPowStub stub(isolate(), MathPowStub::TAGGED); |
| 3802 __ CallStub(&stub); | 3802 __ CallStub(&stub); |
| 3803 } else if (exponent_type.IsTagged()) { | 3803 } else if (exponent_type.IsTagged()) { |
| 3804 Label no_deopt; | 3804 Label no_deopt; |
| 3805 __ JumpIfSmi(tagged_exponent, &no_deopt); | 3805 __ JumpIfSmi(tagged_exponent, &no_deopt); |
| 3806 DCHECK(!ecx.is(tagged_exponent)); | 3806 DCHECK(!ecx.is(tagged_exponent)); |
| 3807 __ CmpObjectType(tagged_exponent, HEAP_NUMBER_TYPE, ecx); | 3807 __ CmpObjectType(tagged_exponent, HEAP_NUMBER_TYPE, ecx); |
| 3808 DeoptimizeIf(not_equal, instr); | 3808 DeoptimizeIf(not_equal, instr, "not a heap number"); |
| 3809 __ bind(&no_deopt); | 3809 __ bind(&no_deopt); |
| 3810 MathPowStub stub(isolate(), MathPowStub::TAGGED); | 3810 MathPowStub stub(isolate(), MathPowStub::TAGGED); |
| 3811 __ CallStub(&stub); | 3811 __ CallStub(&stub); |
| 3812 } else if (exponent_type.IsInteger32()) { | 3812 } else if (exponent_type.IsInteger32()) { |
| 3813 MathPowStub stub(isolate(), MathPowStub::INTEGER); | 3813 MathPowStub stub(isolate(), MathPowStub::INTEGER); |
| 3814 __ CallStub(&stub); | 3814 __ CallStub(&stub); |
| 3815 } else { | 3815 } else { |
| 3816 DCHECK(exponent_type.IsDouble()); | 3816 DCHECK(exponent_type.IsDouble()); |
| 3817 MathPowStub stub(isolate(), MathPowStub::DOUBLE); | 3817 MathPowStub stub(isolate(), MathPowStub::DOUBLE); |
| 3818 __ CallStub(&stub); | 3818 __ CallStub(&stub); |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4110 instr->hydrogen()->index()->representation())); | 4110 instr->hydrogen()->index()->representation())); |
| 4111 } else { | 4111 } else { |
| 4112 __ cmp(ToRegister(instr->index()), ToOperand(instr->length())); | 4112 __ cmp(ToRegister(instr->index()), ToOperand(instr->length())); |
| 4113 } | 4113 } |
| 4114 if (FLAG_debug_code && instr->hydrogen()->skip_check()) { | 4114 if (FLAG_debug_code && instr->hydrogen()->skip_check()) { |
| 4115 Label done; | 4115 Label done; |
| 4116 __ j(NegateCondition(cc), &done, Label::kNear); | 4116 __ j(NegateCondition(cc), &done, Label::kNear); |
| 4117 __ int3(); | 4117 __ int3(); |
| 4118 __ bind(&done); | 4118 __ bind(&done); |
| 4119 } else { | 4119 } else { |
| 4120 DeoptimizeIf(cc, instr); | 4120 DeoptimizeIf(cc, instr, "out of bounds"); |
| 4121 } | 4121 } |
| 4122 } | 4122 } |
| 4123 | 4123 |
| 4124 | 4124 |
| 4125 void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { | 4125 void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { |
| 4126 ElementsKind elements_kind = instr->elements_kind(); | 4126 ElementsKind elements_kind = instr->elements_kind(); |
| 4127 LOperand* key = instr->key(); | 4127 LOperand* key = instr->key(); |
| 4128 if (!key->IsConstantOperand() && | 4128 if (!key->IsConstantOperand() && |
| 4129 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(), | 4129 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(), |
| 4130 elements_kind)) { | 4130 elements_kind)) { |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4278 CodeFactory::KeyedStoreIC(isolate(), instr->strict_mode()).code(); | 4278 CodeFactory::KeyedStoreIC(isolate(), instr->strict_mode()).code(); |
| 4279 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 4279 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 4280 } | 4280 } |
| 4281 | 4281 |
| 4282 | 4282 |
| 4283 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { | 4283 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { |
| 4284 Register object = ToRegister(instr->object()); | 4284 Register object = ToRegister(instr->object()); |
| 4285 Register temp = ToRegister(instr->temp()); | 4285 Register temp = ToRegister(instr->temp()); |
| 4286 Label no_memento_found; | 4286 Label no_memento_found; |
| 4287 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found); | 4287 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found); |
| 4288 DeoptimizeIf(equal, instr); | 4288 DeoptimizeIf(equal, instr, "memento found"); |
| 4289 __ bind(&no_memento_found); | 4289 __ bind(&no_memento_found); |
| 4290 } | 4290 } |
| 4291 | 4291 |
| 4292 | 4292 |
| 4293 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { | 4293 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { |
| 4294 Register object_reg = ToRegister(instr->object()); | 4294 Register object_reg = ToRegister(instr->object()); |
| 4295 | 4295 |
| 4296 Handle<Map> from_map = instr->original_map(); | 4296 Handle<Map> from_map = instr->original_map(); |
| 4297 Handle<Map> to_map = instr->transitioned_map(); | 4297 Handle<Map> to_map = instr->transitioned_map(); |
| 4298 ElementsKind from_kind = instr->from_kind(); | 4298 ElementsKind from_kind = instr->from_kind(); |
| (...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4623 __ StoreToSafepointRegisterSlot(reg, eax); | 4623 __ StoreToSafepointRegisterSlot(reg, eax); |
| 4624 } | 4624 } |
| 4625 | 4625 |
| 4626 | 4626 |
| 4627 void LCodeGen::DoSmiTag(LSmiTag* instr) { | 4627 void LCodeGen::DoSmiTag(LSmiTag* instr) { |
| 4628 HChange* hchange = instr->hydrogen(); | 4628 HChange* hchange = instr->hydrogen(); |
| 4629 Register input = ToRegister(instr->value()); | 4629 Register input = ToRegister(instr->value()); |
| 4630 if (hchange->CheckFlag(HValue::kCanOverflow) && | 4630 if (hchange->CheckFlag(HValue::kCanOverflow) && |
| 4631 hchange->value()->CheckFlag(HValue::kUint32)) { | 4631 hchange->value()->CheckFlag(HValue::kUint32)) { |
| 4632 __ test(input, Immediate(0xc0000000)); | 4632 __ test(input, Immediate(0xc0000000)); |
| 4633 DeoptimizeIf(not_zero, instr); | 4633 DeoptimizeIf(not_zero, instr, "overflow"); |
| 4634 } | 4634 } |
| 4635 __ SmiTag(input); | 4635 __ SmiTag(input); |
| 4636 if (hchange->CheckFlag(HValue::kCanOverflow) && | 4636 if (hchange->CheckFlag(HValue::kCanOverflow) && |
| 4637 !hchange->value()->CheckFlag(HValue::kUint32)) { | 4637 !hchange->value()->CheckFlag(HValue::kUint32)) { |
| 4638 DeoptimizeIf(overflow, instr); | 4638 DeoptimizeIf(overflow, instr, "overflow"); |
| 4639 } | 4639 } |
| 4640 } | 4640 } |
| 4641 | 4641 |
| 4642 | 4642 |
| 4643 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { | 4643 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { |
| 4644 LOperand* input = instr->value(); | 4644 LOperand* input = instr->value(); |
| 4645 Register result = ToRegister(input); | 4645 Register result = ToRegister(input); |
| 4646 DCHECK(input->IsRegister() && input->Equals(instr->result())); | 4646 DCHECK(input->IsRegister() && input->Equals(instr->result())); |
| 4647 if (instr->needs_check()) { | 4647 if (instr->needs_check()) { |
| 4648 __ test(result, Immediate(kSmiTagMask)); | 4648 __ test(result, Immediate(kSmiTagMask)); |
| 4649 DeoptimizeIf(not_zero, instr); | 4649 DeoptimizeIf(not_zero, instr, "not a Smi"); |
| 4650 } else { | 4650 } else { |
| 4651 __ AssertSmi(result); | 4651 __ AssertSmi(result); |
| 4652 } | 4652 } |
| 4653 __ SmiUntag(result); | 4653 __ SmiUntag(result); |
| 4654 } | 4654 } |
| 4655 | 4655 |
| 4656 | 4656 |
| 4657 void LCodeGen::EmitNumberUntagD(LNumberUntagD* instr, Register input_reg, | 4657 void LCodeGen::EmitNumberUntagD(LNumberUntagD* instr, Register input_reg, |
| 4658 Register temp_reg, XMMRegister result_reg, | 4658 Register temp_reg, XMMRegister result_reg, |
| 4659 NumberUntagDMode mode) { | 4659 NumberUntagDMode mode) { |
| 4660 bool can_convert_undefined_to_nan = | 4660 bool can_convert_undefined_to_nan = |
| 4661 instr->hydrogen()->can_convert_undefined_to_nan(); | 4661 instr->hydrogen()->can_convert_undefined_to_nan(); |
| 4662 bool deoptimize_on_minus_zero = instr->hydrogen()->deoptimize_on_minus_zero(); | 4662 bool deoptimize_on_minus_zero = instr->hydrogen()->deoptimize_on_minus_zero(); |
| 4663 | 4663 |
| 4664 Label convert, load_smi, done; | 4664 Label convert, load_smi, done; |
| 4665 | 4665 |
| 4666 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { | 4666 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { |
| 4667 // Smi check. | 4667 // Smi check. |
| 4668 __ JumpIfSmi(input_reg, &load_smi, Label::kNear); | 4668 __ JumpIfSmi(input_reg, &load_smi, Label::kNear); |
| 4669 | 4669 |
| 4670 // Heap number map check. | 4670 // Heap number map check. |
| 4671 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 4671 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 4672 factory()->heap_number_map()); | 4672 factory()->heap_number_map()); |
| 4673 if (can_convert_undefined_to_nan) { | 4673 if (can_convert_undefined_to_nan) { |
| 4674 __ j(not_equal, &convert, Label::kNear); | 4674 __ j(not_equal, &convert, Label::kNear); |
| 4675 } else { | 4675 } else { |
| 4676 DeoptimizeIf(not_equal, instr); | 4676 DeoptimizeIf(not_equal, instr, "not a heap number"); |
| 4677 } | 4677 } |
| 4678 | 4678 |
| 4679 // Heap number to XMM conversion. | 4679 // Heap number to XMM conversion. |
| 4680 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 4680 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| 4681 | 4681 |
| 4682 if (deoptimize_on_minus_zero) { | 4682 if (deoptimize_on_minus_zero) { |
| 4683 XMMRegister xmm_scratch = double_scratch0(); | 4683 XMMRegister xmm_scratch = double_scratch0(); |
| 4684 __ xorps(xmm_scratch, xmm_scratch); | 4684 __ xorps(xmm_scratch, xmm_scratch); |
| 4685 __ ucomisd(result_reg, xmm_scratch); | 4685 __ ucomisd(result_reg, xmm_scratch); |
| 4686 __ j(not_zero, &done, Label::kNear); | 4686 __ j(not_zero, &done, Label::kNear); |
| 4687 __ movmskpd(temp_reg, result_reg); | 4687 __ movmskpd(temp_reg, result_reg); |
| 4688 __ test_b(temp_reg, 1); | 4688 __ test_b(temp_reg, 1); |
| 4689 DeoptimizeIf(not_zero, instr); | 4689 DeoptimizeIf(not_zero, instr, "minus zero"); |
| 4690 } | 4690 } |
| 4691 __ jmp(&done, Label::kNear); | 4691 __ jmp(&done, Label::kNear); |
| 4692 | 4692 |
| 4693 if (can_convert_undefined_to_nan) { | 4693 if (can_convert_undefined_to_nan) { |
| 4694 __ bind(&convert); | 4694 __ bind(&convert); |
| 4695 | 4695 |
| 4696 // Convert undefined (and hole) to NaN. | 4696 // Convert undefined (and hole) to NaN. |
| 4697 __ cmp(input_reg, factory()->undefined_value()); | 4697 __ cmp(input_reg, factory()->undefined_value()); |
| 4698 DeoptimizeIf(not_equal, instr); | 4698 DeoptimizeIf(not_equal, instr, "not a heap number/undefined"); |
| 4699 | 4699 |
| 4700 ExternalReference nan = | 4700 ExternalReference nan = |
| 4701 ExternalReference::address_of_canonical_non_hole_nan(); | 4701 ExternalReference::address_of_canonical_non_hole_nan(); |
| 4702 __ movsd(result_reg, Operand::StaticVariable(nan)); | 4702 __ movsd(result_reg, Operand::StaticVariable(nan)); |
| 4703 __ jmp(&done, Label::kNear); | 4703 __ jmp(&done, Label::kNear); |
| 4704 } | 4704 } |
| 4705 } else { | 4705 } else { |
| 4706 DCHECK(mode == NUMBER_CANDIDATE_IS_SMI); | 4706 DCHECK(mode == NUMBER_CANDIDATE_IS_SMI); |
| 4707 } | 4707 } |
| 4708 | 4708 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4742 __ jmp(done); | 4742 __ jmp(done); |
| 4743 | 4743 |
| 4744 __ bind(&check_bools); | 4744 __ bind(&check_bools); |
| 4745 __ cmp(input_reg, factory()->true_value()); | 4745 __ cmp(input_reg, factory()->true_value()); |
| 4746 __ j(not_equal, &check_false, Label::kNear); | 4746 __ j(not_equal, &check_false, Label::kNear); |
| 4747 __ Move(input_reg, Immediate(1)); | 4747 __ Move(input_reg, Immediate(1)); |
| 4748 __ jmp(done); | 4748 __ jmp(done); |
| 4749 | 4749 |
| 4750 __ bind(&check_false); | 4750 __ bind(&check_false); |
| 4751 __ cmp(input_reg, factory()->false_value()); | 4751 __ cmp(input_reg, factory()->false_value()); |
| 4752 DeoptimizeIf(not_equal, instr, "cannot truncate"); | 4752 DeoptimizeIf(not_equal, instr, "not a heap number/undefined/true/false"); |
| 4753 __ Move(input_reg, Immediate(0)); | 4753 __ Move(input_reg, Immediate(0)); |
| 4754 } else { | 4754 } else { |
| 4755 XMMRegister scratch = ToDoubleRegister(instr->temp()); | 4755 XMMRegister scratch = ToDoubleRegister(instr->temp()); |
| 4756 DCHECK(!scratch.is(xmm0)); | 4756 DCHECK(!scratch.is(xmm0)); |
| 4757 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 4757 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 4758 isolate()->factory()->heap_number_map()); | 4758 isolate()->factory()->heap_number_map()); |
| 4759 DeoptimizeIf(not_equal, instr, "not a heap number"); | 4759 DeoptimizeIf(not_equal, instr, "not a heap number"); |
| 4760 __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 4760 __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| 4761 __ cvttsd2si(input_reg, Operand(xmm0)); | 4761 __ cvttsd2si(input_reg, Operand(xmm0)); |
| 4762 __ Cvtsi2sd(scratch, Operand(input_reg)); | 4762 __ Cvtsi2sd(scratch, Operand(input_reg)); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4833 LOperand* input = instr->value(); | 4833 LOperand* input = instr->value(); |
| 4834 DCHECK(input->IsDoubleRegister()); | 4834 DCHECK(input->IsDoubleRegister()); |
| 4835 LOperand* result = instr->result(); | 4835 LOperand* result = instr->result(); |
| 4836 DCHECK(result->IsRegister()); | 4836 DCHECK(result->IsRegister()); |
| 4837 Register result_reg = ToRegister(result); | 4837 Register result_reg = ToRegister(result); |
| 4838 | 4838 |
| 4839 if (instr->truncating()) { | 4839 if (instr->truncating()) { |
| 4840 XMMRegister input_reg = ToDoubleRegister(input); | 4840 XMMRegister input_reg = ToDoubleRegister(input); |
| 4841 __ TruncateDoubleToI(result_reg, input_reg); | 4841 __ TruncateDoubleToI(result_reg, input_reg); |
| 4842 } else { | 4842 } else { |
| 4843 Label bailout, done; | 4843 Label lost_precision, is_nan, minus_zero, done; |
| 4844 XMMRegister input_reg = ToDoubleRegister(input); | 4844 XMMRegister input_reg = ToDoubleRegister(input); |
| 4845 XMMRegister xmm_scratch = double_scratch0(); | 4845 XMMRegister xmm_scratch = double_scratch0(); |
| 4846 __ DoubleToI(result_reg, input_reg, xmm_scratch, | 4846 __ DoubleToI(result_reg, input_reg, xmm_scratch, |
| 4847 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear); | 4847 instr->hydrogen()->GetMinusZeroMode(), &lost_precision, |
| 4848 &is_nan, &minus_zero, |
| 4849 DeoptEveryNTimes() ? Label::kFar : Label::kNear); |
| 4848 __ jmp(&done, Label::kNear); | 4850 __ jmp(&done, Label::kNear); |
| 4849 __ bind(&bailout); | 4851 __ bind(&lost_precision); |
| 4850 DeoptimizeIf(no_condition, instr); | 4852 DeoptimizeIf(no_condition, instr, "lost precision"); |
| 4853 __ bind(&is_nan); |
| 4854 DeoptimizeIf(no_condition, instr, "NaN"); |
| 4855 __ bind(&minus_zero); |
| 4856 DeoptimizeIf(no_condition, instr, "minus zero"); |
| 4851 __ bind(&done); | 4857 __ bind(&done); |
| 4852 } | 4858 } |
| 4853 } | 4859 } |
| 4854 | 4860 |
| 4855 | 4861 |
| 4856 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { | 4862 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { |
| 4857 LOperand* input = instr->value(); | 4863 LOperand* input = instr->value(); |
| 4858 DCHECK(input->IsDoubleRegister()); | 4864 DCHECK(input->IsDoubleRegister()); |
| 4859 LOperand* result = instr->result(); | 4865 LOperand* result = instr->result(); |
| 4860 DCHECK(result->IsRegister()); | 4866 DCHECK(result->IsRegister()); |
| 4861 Register result_reg = ToRegister(result); | 4867 Register result_reg = ToRegister(result); |
| 4862 | 4868 |
| 4863 Label bailout, done; | 4869 Label lost_precision, is_nan, minus_zero, done; |
| 4864 XMMRegister input_reg = ToDoubleRegister(input); | 4870 XMMRegister input_reg = ToDoubleRegister(input); |
| 4865 XMMRegister xmm_scratch = double_scratch0(); | 4871 XMMRegister xmm_scratch = double_scratch0(); |
| 4866 __ DoubleToI(result_reg, input_reg, xmm_scratch, | 4872 __ DoubleToI(result_reg, input_reg, xmm_scratch, |
| 4867 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear); | 4873 instr->hydrogen()->GetMinusZeroMode(), &lost_precision, &is_nan, |
| 4874 &minus_zero, DeoptEveryNTimes() ? Label::kFar : Label::kNear); |
| 4868 __ jmp(&done, Label::kNear); | 4875 __ jmp(&done, Label::kNear); |
| 4869 __ bind(&bailout); | 4876 __ bind(&lost_precision); |
| 4870 DeoptimizeIf(no_condition, instr); | 4877 DeoptimizeIf(no_condition, instr, "lost precision"); |
| 4878 __ bind(&is_nan); |
| 4879 DeoptimizeIf(no_condition, instr, "NaN"); |
| 4880 __ bind(&minus_zero); |
| 4881 DeoptimizeIf(no_condition, instr, "minus zero"); |
| 4871 __ bind(&done); | 4882 __ bind(&done); |
| 4872 | |
| 4873 __ SmiTag(result_reg); | 4883 __ SmiTag(result_reg); |
| 4874 DeoptimizeIf(overflow, instr); | 4884 DeoptimizeIf(overflow, instr, "overflow"); |
| 4875 } | 4885 } |
| 4876 | 4886 |
| 4877 | 4887 |
| 4878 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { | 4888 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { |
| 4879 LOperand* input = instr->value(); | 4889 LOperand* input = instr->value(); |
| 4880 __ test(ToOperand(input), Immediate(kSmiTagMask)); | 4890 __ test(ToOperand(input), Immediate(kSmiTagMask)); |
| 4881 DeoptimizeIf(not_zero, instr); | 4891 DeoptimizeIf(not_zero, instr, "not a Smi"); |
| 4882 } | 4892 } |
| 4883 | 4893 |
| 4884 | 4894 |
| 4885 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { | 4895 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { |
| 4886 if (!instr->hydrogen()->value()->type().IsHeapObject()) { | 4896 if (!instr->hydrogen()->value()->type().IsHeapObject()) { |
| 4887 LOperand* input = instr->value(); | 4897 LOperand* input = instr->value(); |
| 4888 __ test(ToOperand(input), Immediate(kSmiTagMask)); | 4898 __ test(ToOperand(input), Immediate(kSmiTagMask)); |
| 4889 DeoptimizeIf(zero, instr); | 4899 DeoptimizeIf(zero, instr, "Smi"); |
| 4890 } | 4900 } |
| 4891 } | 4901 } |
| 4892 | 4902 |
| 4893 | 4903 |
| 4894 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { | 4904 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { |
| 4895 Register input = ToRegister(instr->value()); | 4905 Register input = ToRegister(instr->value()); |
| 4896 Register temp = ToRegister(instr->temp()); | 4906 Register temp = ToRegister(instr->temp()); |
| 4897 | 4907 |
| 4898 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); | 4908 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); |
| 4899 | 4909 |
| 4900 if (instr->hydrogen()->is_interval_check()) { | 4910 if (instr->hydrogen()->is_interval_check()) { |
| 4901 InstanceType first; | 4911 InstanceType first; |
| 4902 InstanceType last; | 4912 InstanceType last; |
| 4903 instr->hydrogen()->GetCheckInterval(&first, &last); | 4913 instr->hydrogen()->GetCheckInterval(&first, &last); |
| 4904 | 4914 |
| 4905 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset), | 4915 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset), |
| 4906 static_cast<int8_t>(first)); | 4916 static_cast<int8_t>(first)); |
| 4907 | 4917 |
| 4908 // If there is only one type in the interval check for equality. | 4918 // If there is only one type in the interval check for equality. |
| 4909 if (first == last) { | 4919 if (first == last) { |
| 4910 DeoptimizeIf(not_equal, instr); | 4920 DeoptimizeIf(not_equal, instr, "wrong instance type"); |
| 4911 } else { | 4921 } else { |
| 4912 DeoptimizeIf(below, instr); | 4922 DeoptimizeIf(below, instr, "wrong instance type"); |
| 4913 // Omit check for the last type. | 4923 // Omit check for the last type. |
| 4914 if (last != LAST_TYPE) { | 4924 if (last != LAST_TYPE) { |
| 4915 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset), | 4925 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset), |
| 4916 static_cast<int8_t>(last)); | 4926 static_cast<int8_t>(last)); |
| 4917 DeoptimizeIf(above, instr); | 4927 DeoptimizeIf(above, instr, "wrong instance type"); |
| 4918 } | 4928 } |
| 4919 } | 4929 } |
| 4920 } else { | 4930 } else { |
| 4921 uint8_t mask; | 4931 uint8_t mask; |
| 4922 uint8_t tag; | 4932 uint8_t tag; |
| 4923 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag); | 4933 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag); |
| 4924 | 4934 |
| 4925 if (base::bits::IsPowerOfTwo32(mask)) { | 4935 if (base::bits::IsPowerOfTwo32(mask)) { |
| 4926 DCHECK(tag == 0 || base::bits::IsPowerOfTwo32(tag)); | 4936 DCHECK(tag == 0 || base::bits::IsPowerOfTwo32(tag)); |
| 4927 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask); | 4937 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask); |
| 4928 DeoptimizeIf(tag == 0 ? not_zero : zero, instr); | 4938 DeoptimizeIf(tag == 0 ? not_zero : zero, instr, "wrong instance type"); |
| 4929 } else { | 4939 } else { |
| 4930 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); | 4940 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); |
| 4931 __ and_(temp, mask); | 4941 __ and_(temp, mask); |
| 4932 __ cmp(temp, tag); | 4942 __ cmp(temp, tag); |
| 4933 DeoptimizeIf(not_equal, instr); | 4943 DeoptimizeIf(not_equal, instr, "wrong instance type"); |
| 4934 } | 4944 } |
| 4935 } | 4945 } |
| 4936 } | 4946 } |
| 4937 | 4947 |
| 4938 | 4948 |
| 4939 void LCodeGen::DoCheckValue(LCheckValue* instr) { | 4949 void LCodeGen::DoCheckValue(LCheckValue* instr) { |
| 4940 Handle<HeapObject> object = instr->hydrogen()->object().handle(); | 4950 Handle<HeapObject> object = instr->hydrogen()->object().handle(); |
| 4941 if (instr->hydrogen()->object_in_new_space()) { | 4951 if (instr->hydrogen()->object_in_new_space()) { |
| 4942 Register reg = ToRegister(instr->value()); | 4952 Register reg = ToRegister(instr->value()); |
| 4943 Handle<Cell> cell = isolate()->factory()->NewCell(object); | 4953 Handle<Cell> cell = isolate()->factory()->NewCell(object); |
| 4944 __ cmp(reg, Operand::ForCell(cell)); | 4954 __ cmp(reg, Operand::ForCell(cell)); |
| 4945 } else { | 4955 } else { |
| 4946 Operand operand = ToOperand(instr->value()); | 4956 Operand operand = ToOperand(instr->value()); |
| 4947 __ cmp(operand, object); | 4957 __ cmp(operand, object); |
| 4948 } | 4958 } |
| 4949 DeoptimizeIf(not_equal, instr); | 4959 DeoptimizeIf(not_equal, instr, "value mismatch"); |
| 4950 } | 4960 } |
| 4951 | 4961 |
| 4952 | 4962 |
| 4953 void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { | 4963 void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { |
| 4954 { | 4964 { |
| 4955 PushSafepointRegistersScope scope(this); | 4965 PushSafepointRegistersScope scope(this); |
| 4956 __ push(object); | 4966 __ push(object); |
| 4957 __ xor_(esi, esi); | 4967 __ xor_(esi, esi); |
| 4958 __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance); | 4968 __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance); |
| 4959 RecordSafepointWithRegisters( | 4969 RecordSafepointWithRegisters( |
| 4960 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt); | 4970 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt); |
| 4961 | 4971 |
| 4962 __ test(eax, Immediate(kSmiTagMask)); | 4972 __ test(eax, Immediate(kSmiTagMask)); |
| 4963 } | 4973 } |
| 4964 DeoptimizeIf(zero, instr); | 4974 DeoptimizeIf(zero, instr, "instance migration failed"); |
| 4965 } | 4975 } |
| 4966 | 4976 |
| 4967 | 4977 |
| 4968 void LCodeGen::DoCheckMaps(LCheckMaps* instr) { | 4978 void LCodeGen::DoCheckMaps(LCheckMaps* instr) { |
| 4969 class DeferredCheckMaps FINAL : public LDeferredCode { | 4979 class DeferredCheckMaps FINAL : public LDeferredCode { |
| 4970 public: | 4980 public: |
| 4971 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) | 4981 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) |
| 4972 : LDeferredCode(codegen), instr_(instr), object_(object) { | 4982 : LDeferredCode(codegen), instr_(instr), object_(object) { |
| 4973 SetExit(check_maps()); | 4983 SetExit(check_maps()); |
| 4974 } | 4984 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5007 Handle<Map> map = maps->at(i).handle(); | 5017 Handle<Map> map = maps->at(i).handle(); |
| 5008 __ CompareMap(reg, map); | 5018 __ CompareMap(reg, map); |
| 5009 __ j(equal, &success, Label::kNear); | 5019 __ j(equal, &success, Label::kNear); |
| 5010 } | 5020 } |
| 5011 | 5021 |
| 5012 Handle<Map> map = maps->at(maps->size() - 1).handle(); | 5022 Handle<Map> map = maps->at(maps->size() - 1).handle(); |
| 5013 __ CompareMap(reg, map); | 5023 __ CompareMap(reg, map); |
| 5014 if (instr->hydrogen()->HasMigrationTarget()) { | 5024 if (instr->hydrogen()->HasMigrationTarget()) { |
| 5015 __ j(not_equal, deferred->entry()); | 5025 __ j(not_equal, deferred->entry()); |
| 5016 } else { | 5026 } else { |
| 5017 DeoptimizeIf(not_equal, instr); | 5027 DeoptimizeIf(not_equal, instr, "wrong map"); |
| 5018 } | 5028 } |
| 5019 | 5029 |
| 5020 __ bind(&success); | 5030 __ bind(&success); |
| 5021 } | 5031 } |
| 5022 | 5032 |
| 5023 | 5033 |
| 5024 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { | 5034 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { |
| 5025 XMMRegister value_reg = ToDoubleRegister(instr->unclamped()); | 5035 XMMRegister value_reg = ToDoubleRegister(instr->unclamped()); |
| 5026 XMMRegister xmm_scratch = double_scratch0(); | 5036 XMMRegister xmm_scratch = double_scratch0(); |
| 5027 Register result_reg = ToRegister(instr->result()); | 5037 Register result_reg = ToRegister(instr->result()); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 5046 __ JumpIfSmi(input_reg, &is_smi); | 5056 __ JumpIfSmi(input_reg, &is_smi); |
| 5047 | 5057 |
| 5048 // Check for heap number | 5058 // Check for heap number |
| 5049 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 5059 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 5050 factory()->heap_number_map()); | 5060 factory()->heap_number_map()); |
| 5051 __ j(equal, &heap_number, Label::kNear); | 5061 __ j(equal, &heap_number, Label::kNear); |
| 5052 | 5062 |
| 5053 // Check for undefined. Undefined is converted to zero for clamping | 5063 // Check for undefined. Undefined is converted to zero for clamping |
| 5054 // conversions. | 5064 // conversions. |
| 5055 __ cmp(input_reg, factory()->undefined_value()); | 5065 __ cmp(input_reg, factory()->undefined_value()); |
| 5056 DeoptimizeIf(not_equal, instr); | 5066 DeoptimizeIf(not_equal, instr, "not a heap number/undefined"); |
| 5057 __ mov(input_reg, 0); | 5067 __ mov(input_reg, 0); |
| 5058 __ jmp(&done, Label::kNear); | 5068 __ jmp(&done, Label::kNear); |
| 5059 | 5069 |
| 5060 // Heap number | 5070 // Heap number |
| 5061 __ bind(&heap_number); | 5071 __ bind(&heap_number); |
| 5062 __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 5072 __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| 5063 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg); | 5073 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg); |
| 5064 __ jmp(&done, Label::kNear); | 5074 __ jmp(&done, Label::kNear); |
| 5065 | 5075 |
| 5066 // smi | 5076 // smi |
| (...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5536 DCHECK(!environment->HasBeenRegistered()); | 5546 DCHECK(!environment->HasBeenRegistered()); |
| 5537 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); | 5547 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); |
| 5538 | 5548 |
| 5539 GenerateOsrPrologue(); | 5549 GenerateOsrPrologue(); |
| 5540 } | 5550 } |
| 5541 | 5551 |
| 5542 | 5552 |
| 5543 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { | 5553 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { |
| 5544 DCHECK(ToRegister(instr->context()).is(esi)); | 5554 DCHECK(ToRegister(instr->context()).is(esi)); |
| 5545 __ cmp(eax, isolate()->factory()->undefined_value()); | 5555 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 5546 DeoptimizeIf(equal, instr); | 5556 DeoptimizeIf(equal, instr, "undefined"); |
| 5547 | 5557 |
| 5548 __ cmp(eax, isolate()->factory()->null_value()); | 5558 __ cmp(eax, isolate()->factory()->null_value()); |
| 5549 DeoptimizeIf(equal, instr); | 5559 DeoptimizeIf(equal, instr, "null"); |
| 5550 | 5560 |
| 5551 __ test(eax, Immediate(kSmiTagMask)); | 5561 __ test(eax, Immediate(kSmiTagMask)); |
| 5552 DeoptimizeIf(zero, instr); | 5562 DeoptimizeIf(zero, instr, "Smi"); |
| 5553 | 5563 |
| 5554 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 5564 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 5555 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx); | 5565 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx); |
| 5556 DeoptimizeIf(below_equal, instr); | 5566 DeoptimizeIf(below_equal, instr, "wrong instance type"); |
| 5557 | 5567 |
| 5558 Label use_cache, call_runtime; | 5568 Label use_cache, call_runtime; |
| 5559 __ CheckEnumCache(&call_runtime); | 5569 __ CheckEnumCache(&call_runtime); |
| 5560 | 5570 |
| 5561 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 5571 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 5562 __ jmp(&use_cache, Label::kNear); | 5572 __ jmp(&use_cache, Label::kNear); |
| 5563 | 5573 |
| 5564 // Get the set of properties to enumerate. | 5574 // Get the set of properties to enumerate. |
| 5565 __ bind(&call_runtime); | 5575 __ bind(&call_runtime); |
| 5566 __ push(eax); | 5576 __ push(eax); |
| 5567 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr); | 5577 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr); |
| 5568 | 5578 |
| 5569 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 5579 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 5570 isolate()->factory()->meta_map()); | 5580 isolate()->factory()->meta_map()); |
| 5571 DeoptimizeIf(not_equal, instr); | 5581 DeoptimizeIf(not_equal, instr, "wrong map"); |
| 5572 __ bind(&use_cache); | 5582 __ bind(&use_cache); |
| 5573 } | 5583 } |
| 5574 | 5584 |
| 5575 | 5585 |
| 5576 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { | 5586 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { |
| 5577 Register map = ToRegister(instr->map()); | 5587 Register map = ToRegister(instr->map()); |
| 5578 Register result = ToRegister(instr->result()); | 5588 Register result = ToRegister(instr->result()); |
| 5579 Label load_cache, done; | 5589 Label load_cache, done; |
| 5580 __ EnumLength(result, map); | 5590 __ EnumLength(result, map); |
| 5581 __ cmp(result, Immediate(Smi::FromInt(0))); | 5591 __ cmp(result, Immediate(Smi::FromInt(0))); |
| 5582 __ j(not_equal, &load_cache, Label::kNear); | 5592 __ j(not_equal, &load_cache, Label::kNear); |
| 5583 __ mov(result, isolate()->factory()->empty_fixed_array()); | 5593 __ mov(result, isolate()->factory()->empty_fixed_array()); |
| 5584 __ jmp(&done, Label::kNear); | 5594 __ jmp(&done, Label::kNear); |
| 5585 | 5595 |
| 5586 __ bind(&load_cache); | 5596 __ bind(&load_cache); |
| 5587 __ LoadInstanceDescriptors(map, result); | 5597 __ LoadInstanceDescriptors(map, result); |
| 5588 __ mov(result, | 5598 __ mov(result, |
| 5589 FieldOperand(result, DescriptorArray::kEnumCacheOffset)); | 5599 FieldOperand(result, DescriptorArray::kEnumCacheOffset)); |
| 5590 __ mov(result, | 5600 __ mov(result, |
| 5591 FieldOperand(result, FixedArray::SizeFor(instr->idx()))); | 5601 FieldOperand(result, FixedArray::SizeFor(instr->idx()))); |
| 5592 __ bind(&done); | 5602 __ bind(&done); |
| 5593 __ test(result, result); | 5603 __ test(result, result); |
| 5594 DeoptimizeIf(equal, instr); | 5604 DeoptimizeIf(equal, instr, "no cache"); |
| 5595 } | 5605 } |
| 5596 | 5606 |
| 5597 | 5607 |
| 5598 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { | 5608 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { |
| 5599 Register object = ToRegister(instr->value()); | 5609 Register object = ToRegister(instr->value()); |
| 5600 __ cmp(ToRegister(instr->map()), | 5610 __ cmp(ToRegister(instr->map()), |
| 5601 FieldOperand(object, HeapObject::kMapOffset)); | 5611 FieldOperand(object, HeapObject::kMapOffset)); |
| 5602 DeoptimizeIf(not_equal, instr); | 5612 DeoptimizeIf(not_equal, instr, "wrong map"); |
| 5603 } | 5613 } |
| 5604 | 5614 |
| 5605 | 5615 |
| 5606 void LCodeGen::DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr, | 5616 void LCodeGen::DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr, |
| 5607 Register object, | 5617 Register object, |
| 5608 Register index) { | 5618 Register index) { |
| 5609 PushSafepointRegistersScope scope(this); | 5619 PushSafepointRegistersScope scope(this); |
| 5610 __ push(object); | 5620 __ push(object); |
| 5611 __ push(index); | 5621 __ push(index); |
| 5612 __ xor_(esi, esi); | 5622 __ xor_(esi, esi); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5686 CallRuntime(Runtime::kPushBlockContext, 2, instr); | 5696 CallRuntime(Runtime::kPushBlockContext, 2, instr); |
| 5687 RecordSafepoint(Safepoint::kNoLazyDeopt); | 5697 RecordSafepoint(Safepoint::kNoLazyDeopt); |
| 5688 } | 5698 } |
| 5689 | 5699 |
| 5690 | 5700 |
| 5691 #undef __ | 5701 #undef __ |
| 5692 | 5702 |
| 5693 } } // namespace v8::internal | 5703 } } // namespace v8::internal |
| 5694 | 5704 |
| 5695 #endif // V8_TARGET_ARCH_IA32 | 5705 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |