| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 1208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1219 RUNTIME_ASSERT(index <= subject->length()); | 1219 RUNTIME_ASSERT(index <= subject->length()); |
| 1220 Counters::regexp_entry_runtime.Increment(); | 1220 Counters::regexp_entry_runtime.Increment(); |
| 1221 Handle<Object> result = RegExpImpl::Exec(regexp, | 1221 Handle<Object> result = RegExpImpl::Exec(regexp, |
| 1222 subject, | 1222 subject, |
| 1223 index, | 1223 index, |
| 1224 last_match_info); | 1224 last_match_info); |
| 1225 if (result.is_null()) return Failure::Exception(); | 1225 if (result.is_null()) return Failure::Exception(); |
| 1226 return *result; | 1226 return *result; |
| 1227 } | 1227 } |
| 1228 | 1228 |
| 1229 static Object* Runtime_RegExpExecMultiple(Arguments args) { |
| 1230 HandleScope scope; |
| 1231 ASSERT(args.length() == 4); |
| 1232 |
| 1233 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); |
| 1234 CONVERT_ARG_CHECKED(String, subject, 1); |
| 1235 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2); |
| 1236 CONVERT_ARG_CHECKED(JSArray, result_array, 3); |
| 1237 RUNTIME_ASSERT(last_match_info->HasFastElements()); |
| 1238 RUNTIME_ASSERT(result_array->HasFastElements()); |
| 1239 RUNTIME_ASSERT(regexp->GetFlags().is_global()); |
| 1240 |
| 1241 ZoneScope zone(DELETE_ON_EXIT); |
| 1242 // TODO(lrn): Be much smarter about calling the regexp exec |
| 1243 // function in a loop! And split execution into Atom and Irregexp |
| 1244 // parts (atoms never have captures and can call StringMatch directly). |
| 1245 ZoneList<Smi*> captures(256); |
| 1246 // Number of captures per regexp match (excluding the match itself). |
| 1247 |
| 1248 int capture_count = |
| 1249 RegExpImpl::RegExpNumberOfCaptures(FixedArray::cast(regexp->data())); |
| 1250 int subject_length = subject->length(); |
| 1251 |
| 1252 // Execute regexp once. If absolutely no match, we exit fast. |
| 1253 // Otherwise prepare to repeat execution. |
| 1254 Handle<Object> result = |
| 1255 RegExpImpl::Exec(regexp, subject, 0, last_match_info); |
| 1256 if (result.is_null()) { |
| 1257 return Failure::Exception(); |
| 1258 } |
| 1259 if (result->IsNull()) { |
| 1260 // No match at all, return null. |
| 1261 return Smi::FromInt(0); |
| 1262 } |
| 1263 |
| 1264 ASSERT_EQ(*last_match_info, *result); |
| 1265 ASSERT(last_match_info->HasFastElements()); |
| 1266 |
| 1267 // Include the match itself as a capture. |
| 1268 int capture_reg_count = (capture_count + 1) * 2; |
| 1269 |
| 1270 ASSERT_EQ(capture_reg_count, |
| 1271 Smi::cast(FixedArray::cast(last_match_info->elements())-> |
| 1272 get(RegExpImpl::kLastCaptureCount))->value()); |
| 1273 |
| 1274 int index; |
| 1275 int matches = 0; |
| 1276 do { |
| 1277 { |
| 1278 AssertNoAllocation no_gc; |
| 1279 ASSERT(last_match_info->HasFastElements()); |
| 1280 |
| 1281 FixedArray* match_array = FixedArray::cast(last_match_info->elements()); |
| 1282 Smi* match_start = |
| 1283 Smi::cast(match_array->get(RegExpImpl::kFirstCapture)); |
| 1284 Smi* match_end = |
| 1285 Smi::cast(match_array->get(RegExpImpl::kFirstCapture + 1)); |
| 1286 captures.Add(match_start); |
| 1287 captures.Add(match_end); |
| 1288 // TODO(lrn): Expand, if necessary, captures list in one go and |
| 1289 // use memcpy to copy captures. |
| 1290 for (int i = 2; i < capture_reg_count; i++) { |
| 1291 captures.Add( |
| 1292 Smi::cast(match_array->get(RegExpImpl::kFirstCapture + i))); |
| 1293 } |
| 1294 matches++; |
| 1295 index = match_end->value(); |
| 1296 if (match_start == match_end) { |
| 1297 index++; |
| 1298 if (index > subject_length) { |
| 1299 break; |
| 1300 } |
| 1301 } |
| 1302 } |
| 1303 result = RegExpImpl::Exec(regexp, subject, index, last_match_info); |
| 1304 if (result.is_null()) { |
| 1305 return Failure::Exception(); |
| 1306 } |
| 1307 } while (!result->IsNull()); |
| 1308 |
| 1309 // Done collecting match indices. Now create a result array on the format: |
| 1310 // - Smi number of captures (not including match) per match |
| 1311 // - for each match: |
| 1312 // - smi index of match |
| 1313 // - match substring |
| 1314 // - for each capture |
| 1315 // - captured substring, or undefined if capture is not participating. |
| 1316 int array_length = 1 + (2 + capture_count) * matches; |
| 1317 result_array->Resize(array_length); |
| 1318 result_array->set_length(Smi::FromInt(array_length)); |
| 1319 Handle<FixedArray> elements(FixedArray::cast(result_array->elements())); |
| 1320 |
| 1321 elements->set(0, Smi::FromInt(capture_count)); |
| 1322 int capture_index = 0; |
| 1323 int result_index = 1; |
| 1324 for (int i = 0; i < matches; i++) { |
| 1325 Smi* from = captures.at(capture_index); |
| 1326 Smi* to = captures.at(capture_index + 1); |
| 1327 elements->set(result_index, from); |
| 1328 elements->set(result_index + 1, *Factory::NewSubString(subject, |
| 1329 from->value(), |
| 1330 to->value())); |
| 1331 result_index += 2; |
| 1332 capture_index += 2; |
| 1333 for (int j = 0; j < capture_count; j++) { |
| 1334 int from = captures.at(capture_index)->value(); |
| 1335 if (from >= 0) { |
| 1336 int to = captures.at(capture_index + 1)->value(); |
| 1337 ASSERT(to >= 0); |
| 1338 elements->set(result_index, |
| 1339 *Factory::NewSubString(subject, from, to)); |
| 1340 } else { |
| 1341 ASSERT(captures.at(capture_index + 1)->value() < 0); |
| 1342 elements->set(result_index, Heap::undefined_value()); |
| 1343 } |
| 1344 capture_index += 2; |
| 1345 result_index++; |
| 1346 } |
| 1347 } |
| 1348 |
| 1349 return Smi::FromInt(matches); |
| 1350 } |
| 1351 |
| 1229 | 1352 |
| 1230 static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) { | 1353 static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) { |
| 1231 HandleScope scope; | 1354 HandleScope scope; |
| 1232 ASSERT(args.length() == 1); | 1355 ASSERT(args.length() == 1); |
| 1233 CONVERT_ARG_CHECKED(JSArray, prototype, 0); | 1356 CONVERT_ARG_CHECKED(JSArray, prototype, 0); |
| 1234 // This is necessary to enable fast checks for absence of elements | 1357 // This is necessary to enable fast checks for absence of elements |
| 1235 // on Array.prototype and below. | 1358 // on Array.prototype and below. |
| 1236 prototype->set_elements(Heap::empty_fixed_array()); | 1359 prototype->set_elements(Heap::empty_fixed_array()); |
| 1237 return Smi::FromInt(0); | 1360 return Smi::FromInt(0); |
| 1238 } | 1361 } |
| (...skipping 3827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5066 prefix_length = y->length(); | 5189 prefix_length = y->length(); |
| 5067 equal_prefix_result = Smi::FromInt(GREATER); | 5190 equal_prefix_result = Smi::FromInt(GREATER); |
| 5068 } else if (y->length() > prefix_length) { | 5191 } else if (y->length() > prefix_length) { |
| 5069 equal_prefix_result = Smi::FromInt(LESS); | 5192 equal_prefix_result = Smi::FromInt(LESS); |
| 5070 } | 5193 } |
| 5071 int r; | 5194 int r; |
| 5072 if (x->IsAsciiRepresentation()) { | 5195 if (x->IsAsciiRepresentation()) { |
| 5073 Vector<const char> x_chars = x->ToAsciiVector(); | 5196 Vector<const char> x_chars = x->ToAsciiVector(); |
| 5074 if (y->IsAsciiRepresentation()) { | 5197 if (y->IsAsciiRepresentation()) { |
| 5075 Vector<const char> y_chars = y->ToAsciiVector(); | 5198 Vector<const char> y_chars = y->ToAsciiVector(); |
| 5076 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | 5199 r = memcmp(x_chars.start(), y_chars.start(), prefix_length); |
| 5077 } else { | 5200 } else { |
| 5078 Vector<const uc16> y_chars = y->ToUC16Vector(); | 5201 Vector<const uc16> y_chars = y->ToUC16Vector(); |
| 5079 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | 5202 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
| 5080 } | 5203 } |
| 5081 } else { | 5204 } else { |
| 5082 Vector<const uc16> x_chars = x->ToUC16Vector(); | 5205 Vector<const uc16> x_chars = x->ToUC16Vector(); |
| 5083 if (y->IsAsciiRepresentation()) { | 5206 if (y->IsAsciiRepresentation()) { |
| 5084 Vector<const char> y_chars = y->ToAsciiVector(); | 5207 Vector<const char> y_chars = y->ToAsciiVector(); |
| 5085 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | 5208 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
| 5086 } else { | 5209 } else { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 5114 if (x->length() == 0) return Smi::FromInt(EQUAL); | 5237 if (x->length() == 0) return Smi::FromInt(EQUAL); |
| 5115 return Smi::FromInt(GREATER); | 5238 return Smi::FromInt(GREATER); |
| 5116 } else if (x->length() == 0) { | 5239 } else if (x->length() == 0) { |
| 5117 return Smi::FromInt(LESS); | 5240 return Smi::FromInt(LESS); |
| 5118 } | 5241 } |
| 5119 | 5242 |
| 5120 int d = x->Get(0) - y->Get(0); | 5243 int d = x->Get(0) - y->Get(0); |
| 5121 if (d < 0) return Smi::FromInt(LESS); | 5244 if (d < 0) return Smi::FromInt(LESS); |
| 5122 else if (d > 0) return Smi::FromInt(GREATER); | 5245 else if (d > 0) return Smi::FromInt(GREATER); |
| 5123 | 5246 |
| 5124 Object* obj = Heap::PrepareForCompare(x); | 5247 x->TryFlatten(); |
| 5125 if (obj->IsFailure()) return obj; | 5248 y->TryFlatten(); |
| 5126 obj = Heap::PrepareForCompare(y); | |
| 5127 if (obj->IsFailure()) return obj; | |
| 5128 | 5249 |
| 5129 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) | 5250 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) |
| 5130 : StringInputBufferCompare(x, y); | 5251 : StringInputBufferCompare(x, y); |
| 5131 } | 5252 } |
| 5132 | 5253 |
| 5133 | 5254 |
| 5134 static Object* Runtime_Math_acos(Arguments args) { | 5255 static Object* Runtime_Math_acos(Arguments args) { |
| 5135 NoHandleAllocation ha; | 5256 NoHandleAllocation ha; |
| 5136 ASSERT(args.length() == 1); | 5257 ASSERT(args.length() == 1); |
| 5137 Counters::math_acos.Increment(); | 5258 Counters::math_acos.Increment(); |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5318 } else { | 5439 } else { |
| 5319 return Heap::AllocateHeapNumber(pow(x, y)); | 5440 return Heap::AllocateHeapNumber(pow(x, y)); |
| 5320 } | 5441 } |
| 5321 } | 5442 } |
| 5322 | 5443 |
| 5323 | 5444 |
| 5324 static Object* Runtime_Math_round(Arguments args) { | 5445 static Object* Runtime_Math_round(Arguments args) { |
| 5325 NoHandleAllocation ha; | 5446 NoHandleAllocation ha; |
| 5326 ASSERT(args.length() == 1); | 5447 ASSERT(args.length() == 1); |
| 5327 Counters::math_round.Increment(); | 5448 Counters::math_round.Increment(); |
| 5449 |
| 5328 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5450 CONVERT_DOUBLE_CHECKED(x, args[0]); |
| 5329 | |
| 5330 if (x > 0 && x < Smi::kMaxValue) { | |
| 5331 return Smi::FromInt(static_cast<int>(x + 0.5)); | |
| 5332 } | |
| 5333 | |
| 5334 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value(); | 5451 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value(); |
| 5335 | 5452 double integer = ceil(x); |
| 5336 // if the magnitude is big enough, there's no place for fraction part. If we | 5453 if (integer - x > 0.5) { integer -= 1.0; } |
| 5337 // try to add 0.5 to this number, 1.0 will be added instead. | 5454 return Heap::NumberFromDouble(integer); |
| 5338 if (x >= 9007199254740991.0 || x <= -9007199254740991.0) { | |
| 5339 return args[0]; | |
| 5340 } | |
| 5341 | |
| 5342 return Heap::NumberFromDouble(floor(x + 0.5)); | |
| 5343 } | 5455 } |
| 5344 | 5456 |
| 5345 | 5457 |
| 5346 static Object* Runtime_Math_sin(Arguments args) { | 5458 static Object* Runtime_Math_sin(Arguments args) { |
| 5347 NoHandleAllocation ha; | 5459 NoHandleAllocation ha; |
| 5348 ASSERT(args.length() == 1); | 5460 ASSERT(args.length() == 1); |
| 5349 Counters::math_sin.Increment(); | 5461 Counters::math_sin.Increment(); |
| 5350 | 5462 |
| 5351 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5463 CONVERT_DOUBLE_CHECKED(x, args[0]); |
| 5352 return TranscendentalCache::Get(TranscendentalCache::SIN, x); | 5464 return TranscendentalCache::Get(TranscendentalCache::SIN, x); |
| (...skipping 4029 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9382 } else { | 9494 } else { |
| 9383 // Handle last resort GC and make sure to allow future allocations | 9495 // Handle last resort GC and make sure to allow future allocations |
| 9384 // to grow the heap without causing GCs (if possible). | 9496 // to grow the heap without causing GCs (if possible). |
| 9385 Counters::gc_last_resort_from_js.Increment(); | 9497 Counters::gc_last_resort_from_js.Increment(); |
| 9386 Heap::CollectAllGarbage(false); | 9498 Heap::CollectAllGarbage(false); |
| 9387 } | 9499 } |
| 9388 } | 9500 } |
| 9389 | 9501 |
| 9390 | 9502 |
| 9391 } } // namespace v8::internal | 9503 } } // namespace v8::internal |
| OLD | NEW |