Chromium Code Reviews| 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 14 matching lines...) Expand all Loading... | |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include <stdlib.h> | 28 #include <stdlib.h> |
| 29 | 29 |
| 30 #include "v8.h" | 30 #include "v8.h" |
| 31 | 31 |
| 32 #include "accessors.h" | 32 #include "accessors.h" |
| 33 #include "api.h" | 33 #include "api.h" |
| 34 #include "arguments.h" | 34 #include "arguments.h" |
| 35 #include "codegen.h" | |
| 35 #include "compiler.h" | 36 #include "compiler.h" |
| 36 #include "cpu.h" | 37 #include "cpu.h" |
| 37 #include "dateparser-inl.h" | 38 #include "dateparser-inl.h" |
| 38 #include "debug.h" | 39 #include "debug.h" |
| 39 #include "execution.h" | 40 #include "execution.h" |
| 40 #include "jsregexp.h" | 41 #include "jsregexp.h" |
| 41 #include "liveedit.h" | 42 #include "liveedit.h" |
| 42 #include "parser.h" | 43 #include "parser.h" |
| 43 #include "platform.h" | 44 #include "platform.h" |
| 44 #include "runtime.h" | 45 #include "runtime.h" |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 240 } | 241 } |
| 241 | 242 |
| 242 | 243 |
| 243 static Handle<Object> CreateLiteralBoilerplate( | 244 static Handle<Object> CreateLiteralBoilerplate( |
| 244 Handle<FixedArray> literals, | 245 Handle<FixedArray> literals, |
| 245 Handle<FixedArray> constant_properties); | 246 Handle<FixedArray> constant_properties); |
| 246 | 247 |
| 247 | 248 |
| 248 static Handle<Object> CreateObjectLiteralBoilerplate( | 249 static Handle<Object> CreateObjectLiteralBoilerplate( |
| 249 Handle<FixedArray> literals, | 250 Handle<FixedArray> literals, |
| 250 Handle<FixedArray> constant_properties) { | 251 Handle<FixedArray> constant_properties, |
| 252 bool should_have_fast_elements) { | |
| 251 // Get the global context from the literals array. This is the | 253 // Get the global context from the literals array. This is the |
| 252 // context in which the function was created and we use the object | 254 // context in which the function was created and we use the object |
| 253 // function from this context to create the object literal. We do | 255 // function from this context to create the object literal. We do |
| 254 // not use the object function from the current global context | 256 // not use the object function from the current global context |
| 255 // because this might be the object function from another context | 257 // because this might be the object function from another context |
| 256 // which we should not have access to. | 258 // which we should not have access to. |
| 257 Handle<Context> context = | 259 Handle<Context> context = |
| 258 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals)); | 260 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals)); |
| 259 | 261 |
| 260 bool is_result_from_cache; | 262 bool is_result_from_cache; |
| 261 Handle<Map> map = ComputeObjectLiteralMap(context, | 263 Handle<Map> map = ComputeObjectLiteralMap(context, |
| 262 constant_properties, | 264 constant_properties, |
| 263 &is_result_from_cache); | 265 &is_result_from_cache); |
| 264 | 266 |
| 265 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map); | 267 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map); |
| 268 | |
| 269 // Normalize the elements of the boilerplate to save space if needed. | |
| 270 if (!should_have_fast_elements) NormalizeElements(boilerplate); | |
| 271 | |
| 266 { // Add the constant properties to the boilerplate. | 272 { // Add the constant properties to the boilerplate. |
| 267 int length = constant_properties->length(); | 273 int length = constant_properties->length(); |
| 268 OptimizedObjectForAddingMultipleProperties opt(boilerplate, | 274 OptimizedObjectForAddingMultipleProperties opt(boilerplate, |
| 269 length / 2, | 275 length / 2, |
| 270 !is_result_from_cache); | 276 !is_result_from_cache); |
| 271 for (int index = 0; index < length; index +=2) { | 277 for (int index = 0; index < length; index +=2) { |
| 272 Handle<Object> key(constant_properties->get(index+0)); | 278 Handle<Object> key(constant_properties->get(index+0)); |
| 273 Handle<Object> value(constant_properties->get(index+1)); | 279 Handle<Object> value(constant_properties->get(index+1)); |
| 274 if (value->IsFixedArray()) { | 280 if (value->IsFixedArray()) { |
| 275 // The value contains the constant_properties of a | 281 // The value contains the constant_properties of a |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 337 Handle<JSArray>::cast(object)->SetContent(*content); | 343 Handle<JSArray>::cast(object)->SetContent(*content); |
| 338 return object; | 344 return object; |
| 339 } | 345 } |
| 340 | 346 |
| 341 | 347 |
| 342 static Handle<Object> CreateLiteralBoilerplate( | 348 static Handle<Object> CreateLiteralBoilerplate( |
| 343 Handle<FixedArray> literals, | 349 Handle<FixedArray> literals, |
| 344 Handle<FixedArray> array) { | 350 Handle<FixedArray> array) { |
| 345 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); | 351 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); |
| 346 switch (CompileTimeValue::GetType(array)) { | 352 switch (CompileTimeValue::GetType(array)) { |
| 347 case CompileTimeValue::OBJECT_LITERAL: | 353 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: |
| 348 return CreateObjectLiteralBoilerplate(literals, elements); | 354 return CreateObjectLiteralBoilerplate(literals, elements, true); |
| 355 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: | |
| 356 return CreateObjectLiteralBoilerplate(literals, elements, false); | |
| 349 case CompileTimeValue::ARRAY_LITERAL: | 357 case CompileTimeValue::ARRAY_LITERAL: |
| 350 return CreateArrayLiteralBoilerplate(literals, elements); | 358 return CreateArrayLiteralBoilerplate(literals, elements); |
| 351 default: | 359 default: |
| 352 UNREACHABLE(); | 360 UNREACHABLE(); |
| 353 return Handle<Object>::null(); | 361 return Handle<Object>::null(); |
| 354 } | 362 } |
| 355 } | 363 } |
| 356 | 364 |
| 357 | 365 |
| 358 static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) { | |
| 359 HandleScope scope; | |
| 360 ASSERT(args.length() == 3); | |
| 361 // Copy the arguments. | |
| 362 CONVERT_ARG_CHECKED(FixedArray, literals, 0); | |
| 363 CONVERT_SMI_CHECKED(literals_index, args[1]); | |
| 364 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); | |
| 365 | |
| 366 Handle<Object> result = | |
| 367 CreateObjectLiteralBoilerplate(literals, constant_properties); | |
| 368 | |
| 369 if (result.is_null()) return Failure::Exception(); | |
| 370 | |
| 371 // Update the functions literal and return the boilerplate. | |
| 372 literals->set(literals_index, *result); | |
| 373 | |
| 374 return *result; | |
| 375 } | |
| 376 | |
| 377 | |
| 378 static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) { | 366 static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) { |
| 379 // Takes a FixedArray of elements containing the literal elements of | 367 // Takes a FixedArray of elements containing the literal elements of |
| 380 // the array literal and produces JSArray with those elements. | 368 // the array literal and produces JSArray with those elements. |
| 381 // Additionally takes the literals array of the surrounding function | 369 // Additionally takes the literals array of the surrounding function |
| 382 // which contains the context from which to get the Array function | 370 // which contains the context from which to get the Array function |
| 383 // to use for creating the array literal. | 371 // to use for creating the array literal. |
| 384 HandleScope scope; | 372 HandleScope scope; |
| 385 ASSERT(args.length() == 3); | 373 ASSERT(args.length() == 3); |
| 386 CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 374 CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
| 387 CONVERT_SMI_CHECKED(literals_index, args[1]); | 375 CONVERT_SMI_CHECKED(literals_index, args[1]); |
| 388 CONVERT_ARG_CHECKED(FixedArray, elements, 2); | 376 CONVERT_ARG_CHECKED(FixedArray, elements, 2); |
| 389 | 377 |
| 390 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements); | 378 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements); |
| 391 if (object.is_null()) return Failure::Exception(); | 379 if (object.is_null()) return Failure::Exception(); |
| 392 | 380 |
| 393 // Update the functions literal and return the boilerplate. | 381 // Update the functions literal and return the boilerplate. |
| 394 literals->set(literals_index, *object); | 382 literals->set(literals_index, *object); |
| 395 return *object; | 383 return *object; |
| 396 } | 384 } |
| 397 | 385 |
| 398 | 386 |
| 399 static Object* Runtime_CreateObjectLiteral(Arguments args) { | 387 static Object* Runtime_CreateObjectLiteral(Arguments args) { |
| 400 HandleScope scope; | 388 HandleScope scope; |
| 401 ASSERT(args.length() == 3); | 389 ASSERT(args.length() == 4); |
| 402 CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 390 CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
| 403 CONVERT_SMI_CHECKED(literals_index, args[1]); | 391 CONVERT_SMI_CHECKED(literals_index, args[1]); |
| 404 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); | 392 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); |
| 393 CONVERT_SMI_CHECKED(fast_elements, args[3]); | |
| 394 bool should_have_fast_elements = fast_elements == 1; | |
| 405 | 395 |
| 406 // Check if boilerplate exists. If not, create it first. | 396 // Check if boilerplate exists. If not, create it first. |
| 407 Handle<Object> boilerplate(literals->get(literals_index)); | 397 Handle<Object> boilerplate(literals->get(literals_index)); |
| 408 if (*boilerplate == Heap::undefined_value()) { | 398 if (*boilerplate == Heap::undefined_value()) { |
| 409 boilerplate = CreateObjectLiteralBoilerplate(literals, constant_properties); | 399 boilerplate = CreateObjectLiteralBoilerplate(literals, |
| 400 constant_properties, | |
| 401 should_have_fast_elements); | |
| 410 if (boilerplate.is_null()) return Failure::Exception(); | 402 if (boilerplate.is_null()) return Failure::Exception(); |
| 411 // Update the functions literal and return the boilerplate. | 403 // Update the functions literal and return the boilerplate. |
| 412 literals->set(literals_index, *boilerplate); | 404 literals->set(literals_index, *boilerplate); |
| 413 } | 405 } |
| 414 return DeepCopyBoilerplate(JSObject::cast(*boilerplate)); | 406 return DeepCopyBoilerplate(JSObject::cast(*boilerplate)); |
| 415 } | 407 } |
| 416 | 408 |
| 417 | 409 |
| 418 static Object* Runtime_CreateObjectLiteralShallow(Arguments args) { | 410 static Object* Runtime_CreateObjectLiteralShallow(Arguments args) { |
| 419 HandleScope scope; | 411 HandleScope scope; |
| 420 ASSERT(args.length() == 3); | 412 ASSERT(args.length() == 4); |
| 421 CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 413 CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
| 422 CONVERT_SMI_CHECKED(literals_index, args[1]); | 414 CONVERT_SMI_CHECKED(literals_index, args[1]); |
| 423 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); | 415 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); |
| 416 CONVERT_SMI_CHECKED(fast_elements, args[3]); | |
| 417 bool should_have_fast_elements = fast_elements == 1; | |
| 424 | 418 |
| 425 // Check if boilerplate exists. If not, create it first. | 419 // Check if boilerplate exists. If not, create it first. |
| 426 Handle<Object> boilerplate(literals->get(literals_index)); | 420 Handle<Object> boilerplate(literals->get(literals_index)); |
| 427 if (*boilerplate == Heap::undefined_value()) { | 421 if (*boilerplate == Heap::undefined_value()) { |
| 428 boilerplate = CreateObjectLiteralBoilerplate(literals, constant_properties); | 422 boilerplate = CreateObjectLiteralBoilerplate(literals, |
| 423 constant_properties, | |
| 424 should_have_fast_elements); | |
| 429 if (boilerplate.is_null()) return Failure::Exception(); | 425 if (boilerplate.is_null()) return Failure::Exception(); |
| 430 // Update the functions literal and return the boilerplate. | 426 // Update the functions literal and return the boilerplate. |
| 431 literals->set(literals_index, *boilerplate); | 427 literals->set(literals_index, *boilerplate); |
| 432 } | 428 } |
| 433 return Heap::CopyJSObject(JSObject::cast(*boilerplate)); | 429 return Heap::CopyJSObject(JSObject::cast(*boilerplate)); |
| 434 } | 430 } |
| 435 | 431 |
| 436 | 432 |
| 437 static Object* Runtime_CreateArrayLiteral(Arguments args) { | 433 static Object* Runtime_CreateArrayLiteral(Arguments args) { |
| 438 HandleScope scope; | 434 HandleScope scope; |
| (...skipping 796 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1235 HandleScope scope; | 1231 HandleScope scope; |
| 1236 ASSERT(args.length() == 1); | 1232 ASSERT(args.length() == 1); |
| 1237 CONVERT_ARG_CHECKED(JSArray, prototype, 0); | 1233 CONVERT_ARG_CHECKED(JSArray, prototype, 0); |
| 1238 // This is necessary to enable fast checks for absence of elements | 1234 // This is necessary to enable fast checks for absence of elements |
| 1239 // on Array.prototype and below. | 1235 // on Array.prototype and below. |
| 1240 prototype->set_elements(Heap::empty_fixed_array()); | 1236 prototype->set_elements(Heap::empty_fixed_array()); |
| 1241 return Smi::FromInt(0); | 1237 return Smi::FromInt(0); |
| 1242 } | 1238 } |
| 1243 | 1239 |
| 1244 | 1240 |
| 1241 static void SetCustomCallGenerator(Handle<JSFunction> function, | |
| 1242 CustomCallGenerator generator) { | |
| 1243 if (function->shared()->function_data()->IsUndefined()) { | |
| 1244 function->shared()->set_function_data(*FromCData(generator)); | |
| 1245 } | |
| 1246 } | |
| 1247 | |
| 1248 | |
| 1249 static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder, | |
| 1250 const char* name, | |
| 1251 Builtins::Name builtin_name, | |
| 1252 CustomCallGenerator generator = NULL) { | |
|
Erik Corry
2010/03/23 10:12:44
This should be an external reference (note for lat
| |
| 1253 Handle<String> key = Factory::LookupAsciiSymbol(name); | |
| 1254 Handle<Code> code(Builtins::builtin(builtin_name)); | |
| 1255 Handle<JSFunction> optimized = Factory::NewFunction(key, | |
| 1256 JS_OBJECT_TYPE, | |
| 1257 JSObject::kHeaderSize, | |
| 1258 code, | |
| 1259 false); | |
| 1260 optimized->shared()->DontAdaptArguments(); | |
| 1261 if (generator != NULL) { | |
| 1262 SetCustomCallGenerator(optimized, generator); | |
| 1263 } | |
| 1264 SetProperty(holder, key, optimized, NONE); | |
| 1265 return optimized; | |
| 1266 } | |
| 1267 | |
| 1268 | |
| 1269 static Object* CompileArrayPushCall(CallStubCompiler* compiler, | |
| 1270 Object* object, | |
| 1271 JSObject* holder, | |
| 1272 JSFunction* function, | |
| 1273 String* name, | |
| 1274 StubCompiler::CheckType check) { | |
| 1275 return compiler->CompileArrayPushCall(object, holder, function, name, check); | |
| 1276 } | |
| 1277 | |
| 1278 | |
| 1279 static Object* CompileArrayPopCall(CallStubCompiler* compiler, | |
| 1280 Object* object, | |
| 1281 JSObject* holder, | |
| 1282 JSFunction* function, | |
| 1283 String* name, | |
| 1284 StubCompiler::CheckType check) { | |
| 1285 return compiler->CompileArrayPopCall(object, holder, function, name, check); | |
| 1286 } | |
| 1287 | |
| 1288 | |
| 1289 static Object* Runtime_SpecialArrayFunctions(Arguments args) { | |
| 1290 HandleScope scope; | |
| 1291 ASSERT(args.length() == 1); | |
| 1292 CONVERT_ARG_CHECKED(JSObject, holder, 0); | |
| 1293 | |
| 1294 InstallBuiltin(holder, "pop", Builtins::ArrayPop, CompileArrayPopCall); | |
| 1295 InstallBuiltin(holder, "push", Builtins::ArrayPush, CompileArrayPushCall); | |
| 1296 InstallBuiltin(holder, "shift", Builtins::ArrayShift); | |
| 1297 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift); | |
| 1298 InstallBuiltin(holder, "slice", Builtins::ArraySlice); | |
| 1299 InstallBuiltin(holder, "splice", Builtins::ArraySplice); | |
| 1300 InstallBuiltin(holder, "concat", Builtins::ArrayConcat); | |
| 1301 | |
| 1302 return *holder; | |
| 1303 } | |
| 1304 | |
| 1305 | |
| 1245 static Object* Runtime_MaterializeRegExpLiteral(Arguments args) { | 1306 static Object* Runtime_MaterializeRegExpLiteral(Arguments args) { |
| 1246 HandleScope scope; | 1307 HandleScope scope; |
| 1247 ASSERT(args.length() == 4); | 1308 ASSERT(args.length() == 4); |
| 1248 CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 1309 CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
| 1249 int index = Smi::cast(args[1])->value(); | 1310 int index = Smi::cast(args[1])->value(); |
| 1250 Handle<String> pattern = args.at<String>(2); | 1311 Handle<String> pattern = args.at<String>(2); |
| 1251 Handle<String> flags = args.at<String>(3); | 1312 Handle<String> flags = args.at<String>(3); |
| 1252 | 1313 |
| 1253 // Get the RegExp function from the context in the literals array. | 1314 // Get the RegExp function from the context in the literals array. |
| 1254 // This is the RegExp function from the context in which the | 1315 // This is the RegExp function from the context in which the |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1369 if (obj->IsFailure()) return obj; | 1430 if (obj->IsFailure()) return obj; |
| 1370 return args[0]; // return TOS | 1431 return args[0]; // return TOS |
| 1371 } | 1432 } |
| 1372 | 1433 |
| 1373 | 1434 |
| 1374 static Object* Runtime_FunctionIsAPIFunction(Arguments args) { | 1435 static Object* Runtime_FunctionIsAPIFunction(Arguments args) { |
| 1375 NoHandleAllocation ha; | 1436 NoHandleAllocation ha; |
| 1376 ASSERT(args.length() == 1); | 1437 ASSERT(args.length() == 1); |
| 1377 | 1438 |
| 1378 CONVERT_CHECKED(JSFunction, f, args[0]); | 1439 CONVERT_CHECKED(JSFunction, f, args[0]); |
| 1379 // The function_data field of the shared function info is used exclusively by | 1440 return f->shared()->IsApiFunction() ? Heap::true_value() |
| 1380 // the API. | 1441 : Heap::false_value(); |
| 1381 return !f->shared()->function_data()->IsUndefined() ? Heap::true_value() | |
| 1382 : Heap::false_value(); | |
| 1383 } | 1442 } |
| 1384 | 1443 |
| 1385 static Object* Runtime_FunctionIsBuiltin(Arguments args) { | 1444 static Object* Runtime_FunctionIsBuiltin(Arguments args) { |
| 1386 NoHandleAllocation ha; | 1445 NoHandleAllocation ha; |
| 1387 ASSERT(args.length() == 1); | 1446 ASSERT(args.length() == 1); |
| 1388 | 1447 |
| 1389 CONVERT_CHECKED(JSFunction, f, args[0]); | 1448 CONVERT_CHECKED(JSFunction, f, args[0]); |
| 1390 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value(); | 1449 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value(); |
| 1391 } | 1450 } |
| 1392 | 1451 |
| (...skipping 688 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2081 int good_suffix_shift_[kBMMaxShift + 1]; | 2140 int good_suffix_shift_[kBMMaxShift + 1]; |
| 2082 int* biased_suffixes_; | 2141 int* biased_suffixes_; |
| 2083 int* biased_good_suffix_shift_; | 2142 int* biased_good_suffix_shift_; |
| 2084 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers); | 2143 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers); |
| 2085 }; | 2144 }; |
| 2086 | 2145 |
| 2087 // buffers reused by BoyerMoore | 2146 // buffers reused by BoyerMoore |
| 2088 static int bad_char_occurrence[kBMAlphabetSize]; | 2147 static int bad_char_occurrence[kBMAlphabetSize]; |
| 2089 static BMGoodSuffixBuffers bmgs_buffers; | 2148 static BMGoodSuffixBuffers bmgs_buffers; |
| 2090 | 2149 |
| 2150 // State of the string match tables. | |
| 2151 // SIMPLE: No usable content in the buffers. | |
| 2152 // BOYER_MOORE_HORSPOOL: The bad_char_occurences table has been populated. | |
| 2153 // BOYER_MOORE: The bmgs_buffers tables have also been populated. | |
| 2154 // Whenever starting with a new needle, one should call InitializeStringSearch | |
| 2155 // to determine which search strategy to use, and in the case of a long-needle | |
| 2156 // strategy, the call also initializes the algorithm to SIMPLE. | |
| 2157 enum StringSearchAlgorithm { SIMPLE_SEARCH, BOYER_MOORE_HORSPOOL, BOYER_MOORE }; | |
| 2158 static StringSearchAlgorithm algorithm; | |
| 2159 | |
| 2160 | |
| 2091 // Compute the bad-char table for Boyer-Moore in the static buffer. | 2161 // Compute the bad-char table for Boyer-Moore in the static buffer. |
| 2092 template <typename pchar> | 2162 template <typename pchar> |
| 2093 static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern, | 2163 static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern) { |
| 2094 int start) { | 2164 // Only preprocess at most kBMMaxShift last characters of pattern. |
| 2165 int start = pattern.length() < kBMMaxShift ? 0 | |
| 2166 : pattern.length() - kBMMaxShift; | |
| 2095 // Run forwards to populate bad_char_table, so that *last* instance | 2167 // Run forwards to populate bad_char_table, so that *last* instance |
| 2096 // of character equivalence class is the one registered. | 2168 // of character equivalence class is the one registered. |
| 2097 // Notice: Doesn't include the last character. | 2169 // Notice: Doesn't include the last character. |
| 2098 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1 | 2170 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1 |
| 2099 : kBMAlphabetSize; | 2171 : kBMAlphabetSize; |
| 2100 if (start == 0) { // All patterns less than kBMMaxShift in length. | 2172 if (start == 0) { // All patterns less than kBMMaxShift in length. |
| 2101 memset(bad_char_occurrence, -1, table_size * sizeof(*bad_char_occurrence)); | 2173 memset(bad_char_occurrence, -1, table_size * sizeof(*bad_char_occurrence)); |
| 2102 } else { | 2174 } else { |
| 2103 for (int i = 0; i < table_size; i++) { | 2175 for (int i = 0; i < table_size; i++) { |
| 2104 bad_char_occurrence[i] = start - 1; | 2176 bad_char_occurrence[i] = start - 1; |
| 2105 } | 2177 } |
| 2106 } | 2178 } |
| 2107 for (int i = start; i < pattern.length() - 1; i++) { | 2179 for (int i = start; i < pattern.length() - 1; i++) { |
| 2108 pchar c = pattern[i]; | 2180 pchar c = pattern[i]; |
| 2109 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize; | 2181 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize; |
| 2110 bad_char_occurrence[bucket] = i; | 2182 bad_char_occurrence[bucket] = i; |
| 2111 } | 2183 } |
| 2112 } | 2184 } |
| 2113 | 2185 |
| 2186 | |
| 2114 template <typename pchar> | 2187 template <typename pchar> |
| 2115 static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern, | 2188 static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern) { |
| 2116 int start) { | |
| 2117 int m = pattern.length(); | 2189 int m = pattern.length(); |
| 2190 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; | |
| 2118 int len = m - start; | 2191 int len = m - start; |
| 2119 // Compute Good Suffix tables. | 2192 // Compute Good Suffix tables. |
| 2120 bmgs_buffers.init(m); | 2193 bmgs_buffers.init(m); |
| 2121 | 2194 |
| 2122 bmgs_buffers.shift(m-1) = 1; | 2195 bmgs_buffers.shift(m-1) = 1; |
| 2123 bmgs_buffers.suffix(m) = m + 1; | 2196 bmgs_buffers.suffix(m) = m + 1; |
| 2124 pchar last_char = pattern[m - 1]; | 2197 pchar last_char = pattern[m - 1]; |
| 2125 int suffix = m + 1; | 2198 int suffix = m + 1; |
| 2126 for (int i = m; i > start;) { | 2199 for (int i = m; i > start;) { |
| 2127 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) { | 2200 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) { |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 2154 if (bmgs_buffers.shift(i) == len) { | 2227 if (bmgs_buffers.shift(i) == len) { |
| 2155 bmgs_buffers.shift(i) = suffix - start; | 2228 bmgs_buffers.shift(i) = suffix - start; |
| 2156 } | 2229 } |
| 2157 if (i == suffix) { | 2230 if (i == suffix) { |
| 2158 suffix = bmgs_buffers.suffix(suffix); | 2231 suffix = bmgs_buffers.suffix(suffix); |
| 2159 } | 2232 } |
| 2160 } | 2233 } |
| 2161 } | 2234 } |
| 2162 } | 2235 } |
| 2163 | 2236 |
| 2237 | |
| 2164 template <typename schar, typename pchar> | 2238 template <typename schar, typename pchar> |
| 2165 static inline int CharOccurrence(int char_code) { | 2239 static inline int CharOccurrence(int char_code) { |
| 2166 if (sizeof(schar) == 1) { | 2240 if (sizeof(schar) == 1) { |
| 2167 return bad_char_occurrence[char_code]; | 2241 return bad_char_occurrence[char_code]; |
| 2168 } | 2242 } |
| 2169 if (sizeof(pchar) == 1) { | 2243 if (sizeof(pchar) == 1) { |
| 2170 if (char_code > String::kMaxAsciiCharCode) { | 2244 if (char_code > String::kMaxAsciiCharCode) { |
| 2171 return -1; | 2245 return -1; |
| 2172 } | 2246 } |
| 2173 return bad_char_occurrence[char_code]; | 2247 return bad_char_occurrence[char_code]; |
| 2174 } | 2248 } |
| 2175 return bad_char_occurrence[char_code % kBMAlphabetSize]; | 2249 return bad_char_occurrence[char_code % kBMAlphabetSize]; |
| 2176 } | 2250 } |
| 2177 | 2251 |
| 2252 | |
| 2178 // Restricted simplified Boyer-Moore string matching. | 2253 // Restricted simplified Boyer-Moore string matching. |
| 2179 // Uses only the bad-shift table of Boyer-Moore and only uses it | 2254 // Uses only the bad-shift table of Boyer-Moore and only uses it |
| 2180 // for the character compared to the last character of the needle. | 2255 // for the character compared to the last character of the needle. |
| 2181 template <typename schar, typename pchar> | 2256 template <typename schar, typename pchar> |
| 2182 static int BoyerMooreHorspool(Vector<const schar> subject, | 2257 static int BoyerMooreHorspool(Vector<const schar> subject, |
| 2183 Vector<const pchar> pattern, | 2258 Vector<const pchar> pattern, |
| 2184 int start_index, | 2259 int start_index, |
| 2185 bool* complete) { | 2260 bool* complete) { |
| 2261 ASSERT(algorithm <= BOYER_MOORE_HORSPOOL); | |
| 2186 int n = subject.length(); | 2262 int n = subject.length(); |
| 2187 int m = pattern.length(); | 2263 int m = pattern.length(); |
| 2188 // Only preprocess at most kBMMaxShift last characters of pattern. | |
| 2189 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; | |
| 2190 | 2264 |
| 2191 BoyerMoorePopulateBadCharTable(pattern, start); | 2265 int badness = -m; |
| 2192 | 2266 |
| 2193 int badness = -m; // How bad we are doing without a good-suffix table. | 2267 // How bad we are doing without a good-suffix table. |
| 2194 int idx; // No matches found prior to this index. | 2268 int idx; // No matches found prior to this index. |
| 2195 pchar last_char = pattern[m - 1]; | 2269 pchar last_char = pattern[m - 1]; |
| 2196 int last_char_shift = m - 1 - CharOccurrence<schar, pchar>(last_char); | 2270 int last_char_shift = m - 1 - CharOccurrence<schar, pchar>(last_char); |
| 2197 // Perform search | 2271 // Perform search |
| 2198 for (idx = start_index; idx <= n - m;) { | 2272 for (idx = start_index; idx <= n - m;) { |
| 2199 int j = m - 1; | 2273 int j = m - 1; |
| 2200 int c; | 2274 int c; |
| 2201 while (last_char != (c = subject[idx + j])) { | 2275 while (last_char != (c = subject[idx + j])) { |
| 2202 int bc_occ = CharOccurrence<schar, pchar>(c); | 2276 int bc_occ = CharOccurrence<schar, pchar>(c); |
| 2203 int shift = j - bc_occ; | 2277 int shift = j - bc_occ; |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 2228 } | 2302 } |
| 2229 *complete = true; | 2303 *complete = true; |
| 2230 return -1; | 2304 return -1; |
| 2231 } | 2305 } |
| 2232 | 2306 |
| 2233 | 2307 |
| 2234 template <typename schar, typename pchar> | 2308 template <typename schar, typename pchar> |
| 2235 static int BoyerMooreIndexOf(Vector<const schar> subject, | 2309 static int BoyerMooreIndexOf(Vector<const schar> subject, |
| 2236 Vector<const pchar> pattern, | 2310 Vector<const pchar> pattern, |
| 2237 int idx) { | 2311 int idx) { |
| 2312 ASSERT(algorithm <= BOYER_MOORE); | |
| 2238 int n = subject.length(); | 2313 int n = subject.length(); |
| 2239 int m = pattern.length(); | 2314 int m = pattern.length(); |
| 2240 // Only preprocess at most kBMMaxShift last characters of pattern. | 2315 // Only preprocess at most kBMMaxShift last characters of pattern. |
| 2241 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; | 2316 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; |
| 2242 | 2317 |
| 2243 // Build the Good Suffix table and continue searching. | |
| 2244 BoyerMoorePopulateGoodSuffixTable(pattern, start); | |
| 2245 pchar last_char = pattern[m - 1]; | 2318 pchar last_char = pattern[m - 1]; |
| 2246 // Continue search from i. | 2319 // Continue search from i. |
| 2247 while (idx <= n - m) { | 2320 while (idx <= n - m) { |
| 2248 int j = m - 1; | 2321 int j = m - 1; |
| 2249 schar c; | 2322 schar c; |
| 2250 while (last_char != (c = subject[idx + j])) { | 2323 while (last_char != (c = subject[idx + j])) { |
| 2251 int shift = j - CharOccurrence<schar, pchar>(c); | 2324 int shift = j - CharOccurrence<schar, pchar>(c); |
| 2252 idx += shift; | 2325 idx += shift; |
| 2253 if (idx > n - m) { | 2326 if (idx > n - m) { |
| 2254 return -1; | 2327 return -1; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 2270 } | 2343 } |
| 2271 idx += shift; | 2344 idx += shift; |
| 2272 } | 2345 } |
| 2273 } | 2346 } |
| 2274 | 2347 |
| 2275 return -1; | 2348 return -1; |
| 2276 } | 2349 } |
| 2277 | 2350 |
| 2278 | 2351 |
| 2279 template <typename schar> | 2352 template <typename schar> |
| 2280 static int SingleCharIndexOf(Vector<const schar> string, | 2353 static inline int SingleCharIndexOf(Vector<const schar> string, |
| 2281 schar pattern_char, | 2354 schar pattern_char, |
| 2282 int start_index) { | 2355 int start_index) { |
| 2356 if (sizeof(schar) == 1) { | |
| 2357 const schar* pos = reinterpret_cast<const schar*>( | |
| 2358 memchr(string.start() + start_index, | |
| 2359 pattern_char, | |
| 2360 string.length() - start_index)); | |
| 2361 if (pos == NULL) return -1; | |
| 2362 return pos - string.start(); | |
| 2363 } | |
| 2283 for (int i = start_index, n = string.length(); i < n; i++) { | 2364 for (int i = start_index, n = string.length(); i < n; i++) { |
| 2284 if (pattern_char == string[i]) { | 2365 if (pattern_char == string[i]) { |
| 2285 return i; | 2366 return i; |
| 2286 } | 2367 } |
| 2287 } | 2368 } |
| 2288 return -1; | 2369 return -1; |
| 2289 } | 2370 } |
| 2290 | 2371 |
| 2291 | 2372 |
| 2292 template <typename schar> | 2373 template <typename schar> |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 2310 // does not occur at a position prior to the returned index. | 2391 // does not occur at a position prior to the returned index. |
| 2311 template <typename pchar, typename schar> | 2392 template <typename pchar, typename schar> |
| 2312 static int SimpleIndexOf(Vector<const schar> subject, | 2393 static int SimpleIndexOf(Vector<const schar> subject, |
| 2313 Vector<const pchar> pattern, | 2394 Vector<const pchar> pattern, |
| 2314 int idx, | 2395 int idx, |
| 2315 bool* complete) { | 2396 bool* complete) { |
| 2316 // Badness is a count of how much work we have done. When we have | 2397 // Badness is a count of how much work we have done. When we have |
| 2317 // done enough work we decide it's probably worth switching to a better | 2398 // done enough work we decide it's probably worth switching to a better |
| 2318 // algorithm. | 2399 // algorithm. |
| 2319 int badness = -10 - (pattern.length() << 2); | 2400 int badness = -10 - (pattern.length() << 2); |
| 2401 | |
| 2320 // We know our pattern is at least 2 characters, we cache the first so | 2402 // We know our pattern is at least 2 characters, we cache the first so |
| 2321 // the common case of the first character not matching is faster. | 2403 // the common case of the first character not matching is faster. |
| 2322 pchar pattern_first_char = pattern[0]; | 2404 pchar pattern_first_char = pattern[0]; |
| 2323 | |
| 2324 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) { | 2405 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) { |
| 2325 badness++; | 2406 badness++; |
| 2326 if (badness > 0) { | 2407 if (badness > 0) { |
| 2327 *complete = false; | 2408 *complete = false; |
| 2328 return i; | 2409 return i; |
| 2329 } | 2410 } |
| 2330 if (subject[i] != pattern_first_char) continue; | 2411 if (sizeof(schar) == 1 && sizeof(pchar) == 1) { |
| 2412 const schar* pos = reinterpret_cast<const schar*>( | |
| 2413 memchr(subject.start() + i, | |
| 2414 pattern_first_char, | |
| 2415 n - i + 1)); | |
| 2416 if (pos == NULL) { | |
| 2417 *complete = true; | |
| 2418 return -1; | |
| 2419 } | |
| 2420 i = pos - subject.start(); | |
| 2421 } else { | |
| 2422 if (subject[i] != pattern_first_char) continue; | |
| 2423 } | |
| 2331 int j = 1; | 2424 int j = 1; |
| 2332 do { | 2425 do { |
| 2333 if (pattern[j] != subject[i+j]) { | 2426 if (pattern[j] != subject[i+j]) { |
| 2334 break; | 2427 break; |
| 2335 } | 2428 } |
| 2336 j++; | 2429 j++; |
| 2337 } while (j < pattern.length()); | 2430 } while (j < pattern.length()); |
| 2338 if (j == pattern.length()) { | 2431 if (j == pattern.length()) { |
| 2339 *complete = true; | 2432 *complete = true; |
| 2340 return i; | 2433 return i; |
| 2341 } | 2434 } |
| 2342 badness += j; | 2435 badness += j; |
| 2343 } | 2436 } |
| 2344 *complete = true; | 2437 *complete = true; |
| 2345 return -1; | 2438 return -1; |
| 2346 } | 2439 } |
| 2347 | 2440 |
| 2348 // Simple indexOf that never bails out. For short patterns only. | 2441 // Simple indexOf that never bails out. For short patterns only. |
| 2349 template <typename pchar, typename schar> | 2442 template <typename pchar, typename schar> |
| 2350 static int SimpleIndexOf(Vector<const schar> subject, | 2443 static int SimpleIndexOf(Vector<const schar> subject, |
| 2351 Vector<const pchar> pattern, | 2444 Vector<const pchar> pattern, |
| 2352 int idx) { | 2445 int idx) { |
| 2353 pchar pattern_first_char = pattern[0]; | 2446 pchar pattern_first_char = pattern[0]; |
| 2354 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) { | 2447 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) { |
| 2355 if (subject[i] != pattern_first_char) continue; | 2448 if (sizeof(schar) == 1 && sizeof(pchar) == 1) { |
| 2449 const schar* pos = reinterpret_cast<const schar*>( | |
| 2450 memchr(subject.start() + i, | |
| 2451 pattern_first_char, | |
| 2452 n - i + 1)); | |
| 2453 if (pos == NULL) return -1; | |
| 2454 i = pos - subject.start(); | |
| 2455 } else { | |
| 2456 if (subject[i] != pattern_first_char) continue; | |
| 2457 } | |
| 2356 int j = 1; | 2458 int j = 1; |
| 2357 do { | 2459 do { |
| 2358 if (pattern[j] != subject[i+j]) { | 2460 if (pattern[j] != subject[i+j]) { |
| 2359 break; | 2461 break; |
| 2360 } | 2462 } |
| 2361 j++; | 2463 j++; |
| 2362 } while (j < pattern.length()); | 2464 } while (j < pattern.length()); |
| 2363 if (j == pattern.length()) { | 2465 if (j == pattern.length()) { |
| 2364 return i; | 2466 return i; |
| 2365 } | 2467 } |
| 2366 } | 2468 } |
| 2367 return -1; | 2469 return -1; |
| 2368 } | 2470 } |
| 2369 | 2471 |
| 2370 | 2472 |
| 2371 // Dispatch to different algorithms. | 2473 // Strategy for searching for a string in another string. |
| 2372 template <typename schar, typename pchar> | 2474 enum StringSearchStrategy { SEARCH_FAIL, SEARCH_SHORT, SEARCH_LONG }; |
| 2373 static int StringMatchStrategy(Vector<const schar> sub, | 2475 |
| 2374 Vector<const pchar> pat, | 2476 |
| 2375 int start_index) { | 2477 template <typename pchar> |
| 2478 static inline StringSearchStrategy InitializeStringSearch( | |
| 2479 Vector<const pchar> pat, bool ascii_subject) { | |
| 2376 ASSERT(pat.length() > 1); | 2480 ASSERT(pat.length() > 1); |
| 2377 | |
| 2378 // We have an ASCII haystack and a non-ASCII needle. Check if there | 2481 // We have an ASCII haystack and a non-ASCII needle. Check if there |
| 2379 // really is a non-ASCII character in the needle and bail out if there | 2482 // really is a non-ASCII character in the needle and bail out if there |
| 2380 // is. | 2483 // is. |
| 2381 if (sizeof(schar) == 1 && sizeof(pchar) > 1) { | 2484 if (ascii_subject && sizeof(pchar) > 1) { |
| 2382 for (int i = 0; i < pat.length(); i++) { | 2485 for (int i = 0; i < pat.length(); i++) { |
| 2383 uc16 c = pat[i]; | 2486 uc16 c = pat[i]; |
| 2384 if (c > String::kMaxAsciiCharCode) { | 2487 if (c > String::kMaxAsciiCharCode) { |
| 2385 return -1; | 2488 return SEARCH_FAIL; |
| 2386 } | 2489 } |
| 2387 } | 2490 } |
| 2388 } | 2491 } |
| 2389 if (pat.length() < kBMMinPatternLength) { | 2492 if (pat.length() < kBMMinPatternLength) { |
| 2390 // We don't believe fancy searching can ever be more efficient. | 2493 return SEARCH_SHORT; |
| 2391 // The max shift of Boyer-Moore on a pattern of this length does | |
| 2392 // not compensate for the overhead. | |
| 2393 return SimpleIndexOf(sub, pat, start_index); | |
| 2394 } | 2494 } |
| 2495 algorithm = SIMPLE_SEARCH; | |
| 2496 return SEARCH_LONG; | |
| 2497 } | |
| 2498 | |
| 2499 | |
| 2500 // Dispatch long needle searches to different algorithms. | |
| 2501 template <typename schar, typename pchar> | |
| 2502 static int ComplexIndexOf(Vector<const schar> sub, | |
| 2503 Vector<const pchar> pat, | |
| 2504 int start_index) { | |
| 2505 ASSERT(pat.length() >= kBMMinPatternLength); | |
| 2395 // Try algorithms in order of increasing setup cost and expected performance. | 2506 // Try algorithms in order of increasing setup cost and expected performance. |
| 2396 bool complete; | 2507 bool complete; |
| 2397 int idx = SimpleIndexOf(sub, pat, start_index, &complete); | 2508 int idx = start_index; |
| 2398 if (complete) return idx; | 2509 switch (algorithm) { |
| 2399 idx = BoyerMooreHorspool(sub, pat, idx, &complete); | 2510 case SIMPLE_SEARCH: |
| 2400 if (complete) return idx; | 2511 idx = SimpleIndexOf(sub, pat, idx, &complete); |
| 2401 return BoyerMooreIndexOf(sub, pat, idx); | 2512 if (complete) return idx; |
| 2513 BoyerMoorePopulateBadCharTable(pat); | |
| 2514 algorithm = BOYER_MOORE_HORSPOOL; | |
| 2515 // FALLTHROUGH. | |
| 2516 case BOYER_MOORE_HORSPOOL: | |
| 2517 idx = BoyerMooreHorspool(sub, pat, idx, &complete); | |
| 2518 if (complete) return idx; | |
| 2519 // Build the Good Suffix table and continue searching. | |
| 2520 BoyerMoorePopulateGoodSuffixTable(pat); | |
| 2521 algorithm = BOYER_MOORE; | |
| 2522 // FALLTHROUGH. | |
| 2523 case BOYER_MOORE: | |
| 2524 return BoyerMooreIndexOf(sub, pat, idx); | |
| 2525 } | |
| 2526 UNREACHABLE(); | |
| 2527 return -1; | |
| 2402 } | 2528 } |
| 2403 | 2529 |
| 2530 | |
| 2531 // Dispatch to different search strategies for a single search. | |
| 2532 // If searching multiple times on the same needle, the search | |
| 2533 // strategy should only be computed once and then dispatch to different | |
| 2534 // loops. | |
| 2535 template <typename schar, typename pchar> | |
| 2536 static int StringSearch(Vector<const schar> sub, | |
| 2537 Vector<const pchar> pat, | |
| 2538 int start_index) { | |
| 2539 bool ascii_subject = (sizeof(schar) == 1); | |
| 2540 StringSearchStrategy strategy = InitializeStringSearch(pat, ascii_subject); | |
| 2541 switch (strategy) { | |
| 2542 case SEARCH_FAIL: return -1; | |
| 2543 case SEARCH_SHORT: return SimpleIndexOf(sub, pat, start_index); | |
| 2544 case SEARCH_LONG: return ComplexIndexOf(sub, pat, start_index); | |
| 2545 } | |
| 2546 UNREACHABLE(); | |
| 2547 return -1; | |
| 2548 } | |
| 2549 | |
| 2550 | |
| 2404 // Perform string match of pattern on subject, starting at start index. | 2551 // Perform string match of pattern on subject, starting at start index. |
| 2405 // Caller must ensure that 0 <= start_index <= sub->length(), | 2552 // Caller must ensure that 0 <= start_index <= sub->length(), |
| 2406 // and should check that pat->length() + start_index <= sub->length() | 2553 // and should check that pat->length() + start_index <= sub->length() |
| 2407 int Runtime::StringMatch(Handle<String> sub, | 2554 int Runtime::StringMatch(Handle<String> sub, |
| 2408 Handle<String> pat, | 2555 Handle<String> pat, |
| 2409 int start_index) { | 2556 int start_index) { |
| 2410 ASSERT(0 <= start_index); | 2557 ASSERT(0 <= start_index); |
| 2411 ASSERT(start_index <= sub->length()); | 2558 ASSERT(start_index <= sub->length()); |
| 2412 | 2559 |
| 2413 int pattern_length = pat->length(); | 2560 int pattern_length = pat->length(); |
| 2414 if (pattern_length == 0) return start_index; | 2561 if (pattern_length == 0) return start_index; |
| 2415 | 2562 |
| 2416 int subject_length = sub->length(); | 2563 int subject_length = sub->length(); |
| 2417 if (start_index + pattern_length > subject_length) return -1; | 2564 if (start_index + pattern_length > subject_length) return -1; |
| 2418 | 2565 |
| 2419 if (!sub->IsFlat()) { | 2566 if (!sub->IsFlat()) { |
| 2420 FlattenString(sub); | 2567 FlattenString(sub); |
| 2421 } | 2568 } |
| 2569 | |
| 2422 // Searching for one specific character is common. For one | 2570 // Searching for one specific character is common. For one |
| 2423 // character patterns linear search is necessary, so any smart | 2571 // character patterns linear search is necessary, so any smart |
| 2424 // algorithm is unnecessary overhead. | 2572 // algorithm is unnecessary overhead. |
| 2425 if (pattern_length == 1) { | 2573 if (pattern_length == 1) { |
| 2426 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid | 2574 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid |
| 2427 if (sub->IsAsciiRepresentation()) { | 2575 if (sub->IsAsciiRepresentation()) { |
| 2428 uc16 pchar = pat->Get(0); | 2576 uc16 pchar = pat->Get(0); |
| 2429 if (pchar > String::kMaxAsciiCharCode) { | 2577 if (pchar > String::kMaxAsciiCharCode) { |
| 2430 return -1; | 2578 return -1; |
| 2431 } | 2579 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 2445 | 2593 |
| 2446 if (!pat->IsFlat()) { | 2594 if (!pat->IsFlat()) { |
| 2447 FlattenString(pat); | 2595 FlattenString(pat); |
| 2448 } | 2596 } |
| 2449 | 2597 |
| 2450 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid | 2598 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid |
| 2451 // dispatch on type of strings | 2599 // dispatch on type of strings |
| 2452 if (pat->IsAsciiRepresentation()) { | 2600 if (pat->IsAsciiRepresentation()) { |
| 2453 Vector<const char> pat_vector = pat->ToAsciiVector(); | 2601 Vector<const char> pat_vector = pat->ToAsciiVector(); |
| 2454 if (sub->IsAsciiRepresentation()) { | 2602 if (sub->IsAsciiRepresentation()) { |
| 2455 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); | 2603 return StringSearch(sub->ToAsciiVector(), pat_vector, start_index); |
| 2456 } | 2604 } |
| 2457 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); | 2605 return StringSearch(sub->ToUC16Vector(), pat_vector, start_index); |
| 2458 } | 2606 } |
| 2459 Vector<const uc16> pat_vector = pat->ToUC16Vector(); | 2607 Vector<const uc16> pat_vector = pat->ToUC16Vector(); |
| 2460 if (sub->IsAsciiRepresentation()) { | 2608 if (sub->IsAsciiRepresentation()) { |
| 2461 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); | 2609 return StringSearch(sub->ToAsciiVector(), pat_vector, start_index); |
| 2462 } | 2610 } |
| 2463 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); | 2611 return StringSearch(sub->ToUC16Vector(), pat_vector, start_index); |
| 2464 } | 2612 } |
| 2465 | 2613 |
| 2466 | 2614 |
| 2467 static Object* Runtime_StringIndexOf(Arguments args) { | 2615 static Object* Runtime_StringIndexOf(Arguments args) { |
| 2468 HandleScope scope; // create a new handle scope | 2616 HandleScope scope; // create a new handle scope |
| 2469 ASSERT(args.length() == 3); | 2617 ASSERT(args.length() == 3); |
| 2470 | 2618 |
| 2471 CONVERT_ARG_CHECKED(String, sub, 0); | 2619 CONVERT_ARG_CHECKED(String, sub, 0); |
| 2472 CONVERT_ARG_CHECKED(String, pat, 1); | 2620 CONVERT_ARG_CHECKED(String, pat, 1); |
| 2473 | 2621 |
| (...skipping 1734 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4208 int right = length; | 4356 int right = length; |
| 4209 if (trimRight) { | 4357 if (trimRight) { |
| 4210 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { | 4358 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { |
| 4211 right--; | 4359 right--; |
| 4212 } | 4360 } |
| 4213 } | 4361 } |
| 4214 return s->SubString(left, right); | 4362 return s->SubString(left, right); |
| 4215 } | 4363 } |
| 4216 | 4364 |
| 4217 | 4365 |
| 4366 template <typename schar, typename pchar> | |
| 4367 void FindStringIndices(Vector<const schar> subject, | |
| 4368 Vector<const pchar> pattern, | |
| 4369 ZoneList<int>* indices, | |
| 4370 unsigned int limit) { | |
| 4371 ASSERT(limit > 0); | |
| 4372 // Collect indices of pattern in subject, and the end-of-string index. | |
| 4373 // Stop after finding at most limit values. | |
| 4374 StringSearchStrategy strategy = | |
| 4375 InitializeStringSearch(pattern, sizeof(schar) == 1); | |
| 4376 switch (strategy) { | |
| 4377 case SEARCH_FAIL: return; | |
| 4378 case SEARCH_SHORT: { | |
| 4379 int pattern_length = pattern.length(); | |
| 4380 int index = 0; | |
| 4381 while (limit > 0) { | |
| 4382 index = SimpleIndexOf(subject, pattern, index); | |
| 4383 if (index < 0) return; | |
| 4384 indices->Add(index); | |
| 4385 index += pattern_length; | |
| 4386 limit--; | |
| 4387 } | |
| 4388 return; | |
| 4389 } | |
| 4390 case SEARCH_LONG: { | |
| 4391 int pattern_length = pattern.length(); | |
| 4392 int index = 0; | |
| 4393 while (limit > 0) { | |
| 4394 index = ComplexIndexOf(subject, pattern, index); | |
| 4395 if (index < 0) return; | |
| 4396 indices->Add(index); | |
| 4397 index += pattern_length; | |
| 4398 limit--; | |
| 4399 } | |
| 4400 return; | |
| 4401 } | |
| 4402 default: | |
| 4403 UNREACHABLE(); | |
| 4404 return; | |
| 4405 } | |
| 4406 } | |
| 4407 | |
| 4408 template <typename schar> | |
| 4409 inline void FindCharIndices(Vector<const schar> subject, | |
| 4410 const schar pattern_char, | |
| 4411 ZoneList<int>* indices, | |
| 4412 unsigned int limit) { | |
| 4413 // Collect indices of pattern_char in subject, and the end-of-string index. | |
| 4414 // Stop after finding at most limit values. | |
| 4415 int index = 0; | |
| 4416 while (limit > 0) { | |
| 4417 index = SingleCharIndexOf(subject, pattern_char, index); | |
| 4418 if (index < 0) return; | |
| 4419 indices->Add(index); | |
| 4420 index++; | |
| 4421 limit--; | |
| 4422 } | |
| 4423 } | |
| 4424 | |
| 4425 | |
| 4426 static Object* Runtime_StringSplit(Arguments args) { | |
| 4427 ASSERT(args.length() == 3); | |
| 4428 HandleScope handle_scope; | |
| 4429 CONVERT_ARG_CHECKED(String, subject, 0); | |
| 4430 CONVERT_ARG_CHECKED(String, pattern, 1); | |
| 4431 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]); | |
| 4432 | |
| 4433 int subject_length = subject->length(); | |
| 4434 int pattern_length = pattern->length(); | |
| 4435 RUNTIME_ASSERT(pattern_length > 0); | |
| 4436 | |
| 4437 // The limit can be very large (0xffffffffu), but since the pattern | |
| 4438 // isn't empty, we can never create more parts than ~half the length | |
| 4439 // of the subject. | |
| 4440 | |
| 4441 if (!subject->IsFlat()) FlattenString(subject); | |
| 4442 | |
| 4443 static const int kMaxInitialListCapacity = 16; | |
| 4444 | |
| 4445 ZoneScope scope(DELETE_ON_EXIT); | |
| 4446 | |
| 4447 // Find (up to limit) indices of separator and end-of-string in subject | |
| 4448 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit); | |
| 4449 ZoneList<int> indices(initial_capacity); | |
| 4450 if (pattern_length == 1) { | |
| 4451 // Special case, go directly to fast single-character split. | |
| 4452 AssertNoAllocation nogc; | |
| 4453 uc16 pattern_char = pattern->Get(0); | |
| 4454 if (subject->IsTwoByteRepresentation()) { | |
| 4455 FindCharIndices(subject->ToUC16Vector(), pattern_char, | |
| 4456 &indices, | |
| 4457 limit); | |
| 4458 } else if (pattern_char <= String::kMaxAsciiCharCode) { | |
| 4459 FindCharIndices(subject->ToAsciiVector(), | |
| 4460 static_cast<char>(pattern_char), | |
| 4461 &indices, | |
| 4462 limit); | |
| 4463 } | |
| 4464 } else { | |
| 4465 if (!pattern->IsFlat()) FlattenString(pattern); | |
| 4466 AssertNoAllocation nogc; | |
| 4467 if (subject->IsAsciiRepresentation()) { | |
| 4468 Vector<const char> subject_vector = subject->ToAsciiVector(); | |
| 4469 if (pattern->IsAsciiRepresentation()) { | |
| 4470 FindStringIndices(subject_vector, | |
| 4471 pattern->ToAsciiVector(), | |
| 4472 &indices, | |
| 4473 limit); | |
| 4474 } else { | |
| 4475 FindStringIndices(subject_vector, | |
| 4476 pattern->ToUC16Vector(), | |
| 4477 &indices, | |
| 4478 limit); | |
| 4479 } | |
| 4480 } else { | |
| 4481 Vector<const uc16> subject_vector = subject->ToUC16Vector(); | |
| 4482 if (pattern->IsAsciiRepresentation()) { | |
| 4483 FindStringIndices(subject_vector, | |
| 4484 pattern->ToAsciiVector(), | |
| 4485 &indices, | |
| 4486 limit); | |
| 4487 } else { | |
| 4488 FindStringIndices(subject_vector, | |
| 4489 pattern->ToUC16Vector(), | |
| 4490 &indices, | |
| 4491 limit); | |
| 4492 } | |
| 4493 } | |
| 4494 } | |
| 4495 if (static_cast<uint32_t>(indices.length()) < limit) { | |
| 4496 indices.Add(subject_length); | |
| 4497 } | |
| 4498 // The list indices now contains the end of each part to create. | |
| 4499 | |
| 4500 | |
| 4501 // Create JSArray of substrings separated by separator. | |
| 4502 int part_count = indices.length(); | |
| 4503 | |
| 4504 Handle<JSArray> result = Factory::NewJSArray(part_count); | |
| 4505 result->set_length(Smi::FromInt(part_count)); | |
| 4506 | |
| 4507 ASSERT(result->HasFastElements()); | |
| 4508 | |
| 4509 if (part_count == 1 && indices.at(0) == subject_length) { | |
| 4510 FixedArray::cast(result->elements())->set(0, *subject); | |
| 4511 return *result; | |
| 4512 } | |
| 4513 | |
| 4514 Handle<FixedArray> elements(FixedArray::cast(result->elements())); | |
| 4515 int part_start = 0; | |
| 4516 for (int i = 0; i < part_count; i++) { | |
| 4517 HandleScope local_loop_handle; | |
| 4518 int part_end = indices.at(i); | |
| 4519 Handle<String> substring = | |
| 4520 Factory::NewSubString(subject, part_start, part_end); | |
| 4521 elements->set(i, *substring); | |
| 4522 part_start = part_end + pattern_length; | |
| 4523 } | |
| 4524 | |
| 4525 return *result; | |
| 4526 } | |
| 4527 | |
| 4528 | |
| 4218 // Copies ascii characters to the given fixed array looking up | 4529 // Copies ascii characters to the given fixed array looking up |
| 4219 // one-char strings in the cache. Gives up on the first char that is | 4530 // one-char strings in the cache. Gives up on the first char that is |
| 4220 // not in the cache and fills the remainder with smi zeros. Returns | 4531 // not in the cache and fills the remainder with smi zeros. Returns |
| 4221 // the length of the successfully copied prefix. | 4532 // the length of the successfully copied prefix. |
| 4222 static int CopyCachedAsciiCharsToArray(const char* chars, | 4533 static int CopyCachedAsciiCharsToArray(const char* chars, |
| 4223 FixedArray* elements, | 4534 FixedArray* elements, |
| 4224 int length) { | 4535 int length) { |
| 4225 AssertNoAllocation nogc; | 4536 AssertNoAllocation nogc; |
| 4226 FixedArray* ascii_cache = Heap::single_character_string_cache(); | 4537 FixedArray* ascii_cache = Heap::single_character_string_cache(); |
| 4227 Object* undefined = Heap::undefined_value(); | 4538 Object* undefined = Heap::undefined_value(); |
| (...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4784 prefix_length = y->length(); | 5095 prefix_length = y->length(); |
| 4785 equal_prefix_result = Smi::FromInt(GREATER); | 5096 equal_prefix_result = Smi::FromInt(GREATER); |
| 4786 } else if (y->length() > prefix_length) { | 5097 } else if (y->length() > prefix_length) { |
| 4787 equal_prefix_result = Smi::FromInt(LESS); | 5098 equal_prefix_result = Smi::FromInt(LESS); |
| 4788 } | 5099 } |
| 4789 int r; | 5100 int r; |
| 4790 if (x->IsAsciiRepresentation()) { | 5101 if (x->IsAsciiRepresentation()) { |
| 4791 Vector<const char> x_chars = x->ToAsciiVector(); | 5102 Vector<const char> x_chars = x->ToAsciiVector(); |
| 4792 if (y->IsAsciiRepresentation()) { | 5103 if (y->IsAsciiRepresentation()) { |
| 4793 Vector<const char> y_chars = y->ToAsciiVector(); | 5104 Vector<const char> y_chars = y->ToAsciiVector(); |
| 4794 r = memcmp(x_chars.start(), y_chars.start(), prefix_length); | 5105 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
| 4795 } else { | 5106 } else { |
| 4796 Vector<const uc16> y_chars = y->ToUC16Vector(); | 5107 Vector<const uc16> y_chars = y->ToUC16Vector(); |
| 4797 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | 5108 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
| 4798 } | 5109 } |
| 4799 } else { | 5110 } else { |
| 4800 Vector<const uc16> x_chars = x->ToUC16Vector(); | 5111 Vector<const uc16> x_chars = x->ToUC16Vector(); |
| 4801 if (y->IsAsciiRepresentation()) { | 5112 if (y->IsAsciiRepresentation()) { |
| 4802 Vector<const char> y_chars = y->ToAsciiVector(); | 5113 Vector<const char> y_chars = y->ToAsciiVector(); |
| 4803 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | 5114 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |
| 4804 } else { | 5115 } else { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 4832 if (x->length() == 0) return Smi::FromInt(EQUAL); | 5143 if (x->length() == 0) return Smi::FromInt(EQUAL); |
| 4833 return Smi::FromInt(GREATER); | 5144 return Smi::FromInt(GREATER); |
| 4834 } else if (x->length() == 0) { | 5145 } else if (x->length() == 0) { |
| 4835 return Smi::FromInt(LESS); | 5146 return Smi::FromInt(LESS); |
| 4836 } | 5147 } |
| 4837 | 5148 |
| 4838 int d = x->Get(0) - y->Get(0); | 5149 int d = x->Get(0) - y->Get(0); |
| 4839 if (d < 0) return Smi::FromInt(LESS); | 5150 if (d < 0) return Smi::FromInt(LESS); |
| 4840 else if (d > 0) return Smi::FromInt(GREATER); | 5151 else if (d > 0) return Smi::FromInt(GREATER); |
| 4841 | 5152 |
| 4842 x->TryFlatten(); | 5153 Object* obj = Heap::PrepareForCompare(x); |
| 4843 y->TryFlatten(); | 5154 if (obj->IsFailure()) return obj; |
| 5155 obj = Heap::PrepareForCompare(y); | |
| 5156 if (obj->IsFailure()) return obj; | |
| 4844 | 5157 |
| 4845 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) | 5158 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) |
| 4846 : StringInputBufferCompare(x, y); | 5159 : StringInputBufferCompare(x, y); |
| 4847 } | 5160 } |
| 4848 | 5161 |
| 4849 | 5162 |
| 4850 static Object* Runtime_Math_abs(Arguments args) { | |
| 4851 NoHandleAllocation ha; | |
| 4852 ASSERT(args.length() == 1); | |
| 4853 Counters::math_abs.Increment(); | |
| 4854 | |
| 4855 CONVERT_DOUBLE_CHECKED(x, args[0]); | |
| 4856 return Heap::AllocateHeapNumber(fabs(x)); | |
| 4857 } | |
| 4858 | |
| 4859 | |
| 4860 static Object* Runtime_Math_acos(Arguments args) { | 5163 static Object* Runtime_Math_acos(Arguments args) { |
| 4861 NoHandleAllocation ha; | 5164 NoHandleAllocation ha; |
| 4862 ASSERT(args.length() == 1); | 5165 ASSERT(args.length() == 1); |
| 4863 Counters::math_acos.Increment(); | 5166 Counters::math_acos.Increment(); |
| 4864 | 5167 |
| 4865 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5168 CONVERT_DOUBLE_CHECKED(x, args[0]); |
| 4866 return TranscendentalCache::Get(TranscendentalCache::ACOS, x); | 5169 return TranscendentalCache::Get(TranscendentalCache::ACOS, x); |
| 4867 } | 5170 } |
| 4868 | 5171 |
| 4869 | 5172 |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5040 if (y == 0) { | 5343 if (y == 0) { |
| 5041 return Smi::FromInt(1); | 5344 return Smi::FromInt(1); |
| 5042 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { | 5345 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { |
| 5043 return Heap::nan_value(); | 5346 return Heap::nan_value(); |
| 5044 } else { | 5347 } else { |
| 5045 return Heap::AllocateHeapNumber(pow(x, y)); | 5348 return Heap::AllocateHeapNumber(pow(x, y)); |
| 5046 } | 5349 } |
| 5047 } | 5350 } |
| 5048 | 5351 |
| 5049 | 5352 |
| 5050 static Object* Runtime_Math_round(Arguments args) { | 5353 static Object* Runtime_RoundNumber(Arguments args) { |
| 5051 NoHandleAllocation ha; | 5354 NoHandleAllocation ha; |
| 5052 ASSERT(args.length() == 1); | 5355 ASSERT(args.length() == 1); |
| 5053 Counters::math_round.Increment(); | 5356 Counters::math_round.Increment(); |
| 5054 | 5357 |
| 5055 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5358 if (!args[0]->IsHeapNumber()) { |
| 5056 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value(); | 5359 // Must be smi. Return the argument unchanged for all the other types |
| 5057 double integer = ceil(x); | 5360 // to make fuzz-natives test happy. |
| 5058 if (integer - x > 0.5) { integer -= 1.0; } | 5361 return args[0]; |
| 5059 return Heap::NumberFromDouble(integer); | 5362 } |
| 5363 | |
| 5364 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]); | |
| 5365 | |
| 5366 double value = number->value(); | |
| 5367 int exponent = number->get_exponent(); | |
| 5368 int sign = number->get_sign(); | |
| 5369 | |
| 5370 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and | |
| 5371 // should be rounded to 2^30, which is not smi. | |
| 5372 if (!sign && exponent <= kSmiValueSize - 3) { | |
| 5373 return Smi::FromInt(static_cast<int>(value + 0.5)); | |
| 5374 } | |
| 5375 | |
| 5376 // If the magnitude is big enough, there's no place for fraction part. If we | |
| 5377 // try to add 0.5 to this number, 1.0 will be added instead. | |
| 5378 if (exponent >= 52) { | |
| 5379 return number; | |
| 5380 } | |
| 5381 | |
| 5382 if (sign && value >= -0.5) return Heap::minus_zero_value(); | |
| 5383 | |
| 5384 return Heap::NumberFromDouble(floor(value + 0.5)); | |
| 5060 } | 5385 } |
| 5061 | 5386 |
| 5062 | 5387 |
| 5063 static Object* Runtime_Math_sin(Arguments args) { | 5388 static Object* Runtime_Math_sin(Arguments args) { |
| 5064 NoHandleAllocation ha; | 5389 NoHandleAllocation ha; |
| 5065 ASSERT(args.length() == 1); | 5390 ASSERT(args.length() == 1); |
| 5066 Counters::math_sin.Increment(); | 5391 Counters::math_sin.Increment(); |
| 5067 | 5392 |
| 5068 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5393 CONVERT_DOUBLE_CHECKED(x, args[0]); |
| 5069 return TranscendentalCache::Get(TranscendentalCache::SIN, x); | 5394 return TranscendentalCache::Get(TranscendentalCache::SIN, x); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 5083 static Object* Runtime_Math_tan(Arguments args) { | 5408 static Object* Runtime_Math_tan(Arguments args) { |
| 5084 NoHandleAllocation ha; | 5409 NoHandleAllocation ha; |
| 5085 ASSERT(args.length() == 1); | 5410 ASSERT(args.length() == 1); |
| 5086 Counters::math_tan.Increment(); | 5411 Counters::math_tan.Increment(); |
| 5087 | 5412 |
| 5088 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5413 CONVERT_DOUBLE_CHECKED(x, args[0]); |
| 5089 return TranscendentalCache::Get(TranscendentalCache::TAN, x); | 5414 return TranscendentalCache::Get(TranscendentalCache::TAN, x); |
| 5090 } | 5415 } |
| 5091 | 5416 |
| 5092 | 5417 |
| 5093 static Object* Runtime_DateMakeDay(Arguments args) { | 5418 static int MakeDay(int year, int month, int day) { |
| 5094 NoHandleAllocation ha; | |
| 5095 ASSERT(args.length() == 3); | |
| 5096 | |
| 5097 CONVERT_SMI_CHECKED(year, args[0]); | |
| 5098 CONVERT_SMI_CHECKED(month, args[1]); | |
| 5099 CONVERT_SMI_CHECKED(date, args[2]); | |
| 5100 | |
| 5101 static const int day_from_month[] = {0, 31, 59, 90, 120, 151, | 5419 static const int day_from_month[] = {0, 31, 59, 90, 120, 151, |
| 5102 181, 212, 243, 273, 304, 334}; | 5420 181, 212, 243, 273, 304, 334}; |
| 5103 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152, | 5421 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152, |
| 5104 182, 213, 244, 274, 305, 335}; | 5422 182, 213, 244, 274, 305, 335}; |
| 5105 | 5423 |
| 5106 year += month / 12; | 5424 year += month / 12; |
| 5107 month %= 12; | 5425 month %= 12; |
| 5108 if (month < 0) { | 5426 if (month < 0) { |
| 5109 year--; | 5427 year--; |
| 5110 month += 12; | 5428 month += 12; |
| 5111 } | 5429 } |
| 5112 | 5430 |
| 5113 ASSERT(month >= 0); | 5431 ASSERT(month >= 0); |
| 5114 ASSERT(month < 12); | 5432 ASSERT(month < 12); |
| 5115 | 5433 |
| 5116 // year_delta is an arbitrary number such that: | 5434 // year_delta is an arbitrary number such that: |
| 5117 // a) year_delta = -1 (mod 400) | 5435 // a) year_delta = -1 (mod 400) |
| 5118 // b) year + year_delta > 0 for years in the range defined by | 5436 // b) year + year_delta > 0 for years in the range defined by |
| 5119 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of | 5437 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of |
| 5120 // Jan 1 1970. This is required so that we don't run into integer | 5438 // Jan 1 1970. This is required so that we don't run into integer |
| 5121 // division of negative numbers. | 5439 // division of negative numbers. |
| 5122 // c) there shouldn't be overflow for 32-bit integers in the following | 5440 // c) there shouldn't be an overflow for 32-bit integers in the following |
| 5123 // operations. | 5441 // operations. |
| 5124 static const int year_delta = 399999; | 5442 static const int year_delta = 399999; |
| 5125 static const int base_day = 365 * (1970 + year_delta) + | 5443 static const int base_day = 365 * (1970 + year_delta) + |
| 5126 (1970 + year_delta) / 4 - | 5444 (1970 + year_delta) / 4 - |
| 5127 (1970 + year_delta) / 100 + | 5445 (1970 + year_delta) / 100 + |
| 5128 (1970 + year_delta) / 400; | 5446 (1970 + year_delta) / 400; |
| 5129 | 5447 |
| 5130 int year1 = year + year_delta; | 5448 int year1 = year + year_delta; |
| 5131 int day_from_year = 365 * year1 + | 5449 int day_from_year = 365 * year1 + |
| 5132 year1 / 4 - | 5450 year1 / 4 - |
| 5133 year1 / 100 + | 5451 year1 / 100 + |
| 5134 year1 / 400 - | 5452 year1 / 400 - |
| 5135 base_day; | 5453 base_day; |
| 5136 | 5454 |
| 5137 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) { | 5455 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) { |
| 5138 return Smi::FromInt(day_from_year + day_from_month[month] + date - 1); | 5456 return day_from_year + day_from_month[month] + day - 1; |
| 5139 } | 5457 } |
| 5140 | 5458 |
| 5141 return Smi::FromInt(day_from_year + day_from_month_leap[month] + date - 1); | 5459 return day_from_year + day_from_month_leap[month] + day - 1; |
| 5460 } | |
| 5461 | |
| 5462 | |
| 5463 static Object* Runtime_DateMakeDay(Arguments args) { | |
| 5464 NoHandleAllocation ha; | |
| 5465 ASSERT(args.length() == 3); | |
| 5466 | |
| 5467 CONVERT_SMI_CHECKED(year, args[0]); | |
| 5468 CONVERT_SMI_CHECKED(month, args[1]); | |
| 5469 CONVERT_SMI_CHECKED(date, args[2]); | |
| 5470 | |
| 5471 return Smi::FromInt(MakeDay(year, month, date)); | |
| 5472 } | |
| 5473 | |
| 5474 | |
| 5475 static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1}; | |
| 5476 static const int kDaysIn4Years = 4 * 365 + 1; | |
| 5477 static const int kDaysIn100Years = 25 * kDaysIn4Years - 1; | |
| 5478 static const int kDaysIn400Years = 4 * kDaysIn100Years + 1; | |
| 5479 static const int kDays1970to2000 = 30 * 365 + 7; | |
| 5480 static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years - | |
| 5481 kDays1970to2000; | |
| 5482 static const int kYearsOffset = 400000; | |
| 5483 | |
| 5484 static const char kDayInYear[] = { | |
| 5485 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5486 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5487 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5488 22, 23, 24, 25, 26, 27, 28, | |
| 5489 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5490 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5491 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5492 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5493 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5494 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5495 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5496 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5497 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5498 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5499 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5500 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5501 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5502 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5503 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5504 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5505 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5506 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5507 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5508 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5509 | |
| 5510 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5511 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5512 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5513 22, 23, 24, 25, 26, 27, 28, | |
| 5514 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5515 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5516 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5517 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5518 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5519 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5520 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5521 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5522 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5523 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5524 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5525 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5526 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5527 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5528 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5529 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5530 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5531 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5532 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5533 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5534 | |
| 5535 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5536 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5537 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5538 22, 23, 24, 25, 26, 27, 28, 29, | |
| 5539 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5540 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5541 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5542 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5543 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5544 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5545 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5546 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5547 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5548 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5549 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5550 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5551 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5552 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5553 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5554 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5555 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5556 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5557 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5558 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5559 | |
| 5560 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5561 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5562 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5563 22, 23, 24, 25, 26, 27, 28, | |
| 5564 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5565 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5566 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5567 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5568 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5569 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5570 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5571 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5572 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5573 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5574 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5575 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5576 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5577 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5578 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5579 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
| 5580 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5581 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
| 5582 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
| 5583 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; | |
| 5584 | |
| 5585 static const char kMonthInYear[] = { | |
| 5586 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 5587 0, 0, 0, 0, 0, 0, | |
| 5588 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 5589 1, 1, 1, | |
| 5590 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
| 5591 2, 2, 2, 2, 2, 2, | |
| 5592 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | |
| 5593 3, 3, 3, 3, 3, | |
| 5594 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, | |
| 5595 4, 4, 4, 4, 4, 4, | |
| 5596 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | |
| 5597 5, 5, 5, 5, 5, | |
| 5598 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | |
| 5599 6, 6, 6, 6, 6, 6, | |
| 5600 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | |
| 5601 7, 7, 7, 7, 7, 7, | |
| 5602 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
| 5603 8, 8, 8, 8, 8, | |
| 5604 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, | |
| 5605 9, 9, 9, 9, 9, 9, | |
| 5606 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | |
| 5607 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | |
| 5608 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | |
| 5609 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | |
| 5610 | |
| 5611 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 5612 0, 0, 0, 0, 0, 0, | |
| 5613 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 5614 1, 1, 1, | |
| 5615 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
| 5616 2, 2, 2, 2, 2, 2, | |
| 5617 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | |
| 5618 3, 3, 3, 3, 3, | |
| 5619 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, | |
| 5620 4, 4, 4, 4, 4, 4, | |
| 5621 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | |
| 5622 5, 5, 5, 5, 5, | |
| 5623 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | |
| 5624 6, 6, 6, 6, 6, 6, | |
| 5625 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | |
| 5626 7, 7, 7, 7, 7, 7, | |
| 5627 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
| 5628 8, 8, 8, 8, 8, | |
| 5629 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, | |
| 5630 9, 9, 9, 9, 9, 9, | |
| 5631 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | |
| 5632 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | |
| 5633 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | |
| 5634 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | |
| 5635 | |
| 5636 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 5637 0, 0, 0, 0, 0, 0, | |
| 5638 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 5639 1, 1, 1, 1, | |
| 5640 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
| 5641 2, 2, 2, 2, 2, 2, | |
| 5642 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | |
| 5643 3, 3, 3, 3, 3, | |
| 5644 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, | |
| 5645 4, 4, 4, 4, 4, 4, | |
| 5646 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | |
| 5647 5, 5, 5, 5, 5, | |
| 5648 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | |
| 5649 6, 6, 6, 6, 6, 6, | |
| 5650 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | |
| 5651 7, 7, 7, 7, 7, 7, | |
| 5652 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
| 5653 8, 8, 8, 8, 8, | |
| 5654 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, | |
| 5655 9, 9, 9, 9, 9, 9, | |
| 5656 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | |
| 5657 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | |
| 5658 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | |
| 5659 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | |
| 5660 | |
| 5661 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 5662 0, 0, 0, 0, 0, 0, | |
| 5663 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 5664 1, 1, 1, | |
| 5665 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
| 5666 2, 2, 2, 2, 2, 2, | |
| 5667 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | |
| 5668 3, 3, 3, 3, 3, | |
| 5669 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, | |
| 5670 4, 4, 4, 4, 4, 4, | |
| 5671 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | |
| 5672 5, 5, 5, 5, 5, | |
| 5673 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | |
| 5674 6, 6, 6, 6, 6, 6, | |
| 5675 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | |
| 5676 7, 7, 7, 7, 7, 7, | |
| 5677 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
| 5678 8, 8, 8, 8, 8, | |
| 5679 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, | |
| 5680 9, 9, 9, 9, 9, 9, | |
| 5681 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | |
| 5682 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | |
| 5683 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, | |
| 5684 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11}; | |
| 5685 | |
| 5686 | |
| 5687 // This function works for dates from 1970 to 2099. | |
| 5688 static inline void DateYMDFromTimeAfter1970(int date, | |
| 5689 int& year, int& month, int& day) { | |
| 5690 #ifdef DEBUG | |
| 5691 int save_date = date; // Need this for ASSERTÂ in the end. | |
| 5692 #endif | |
| 5693 | |
| 5694 year = 1970 + (4 * date + 2) / kDaysIn4Years; | |
| 5695 date %= kDaysIn4Years; | |
| 5696 | |
| 5697 month = kMonthInYear[date]; | |
| 5698 day = kDayInYear[date]; | |
| 5699 | |
| 5700 ASSERT(MakeDay(year, month, day) == save_date); | |
| 5701 } | |
| 5702 | |
| 5703 | |
| 5704 static inline void DateYMDFromTimeSlow(int date, | |
| 5705 int& year, int& month, int& day) { | |
| 5706 #ifdef DEBUG | |
| 5707 int save_date = date; // Need this for ASSERTÂ in the end. | |
| 5708 #endif | |
| 5709 | |
| 5710 date += kDaysOffset; | |
| 5711 year = 400 * (date / kDaysIn400Years) - kYearsOffset; | |
| 5712 date %= kDaysIn400Years; | |
| 5713 | |
| 5714 ASSERT(MakeDay(year, 0, 1) + date == save_date); | |
| 5715 | |
| 5716 date--; | |
| 5717 int yd1 = date / kDaysIn100Years; | |
| 5718 date %= kDaysIn100Years; | |
| 5719 year += 100 * yd1; | |
| 5720 | |
| 5721 date++; | |
| 5722 int yd2 = date / kDaysIn4Years; | |
| 5723 date %= kDaysIn4Years; | |
| 5724 year += 4 * yd2; | |
| 5725 | |
| 5726 date--; | |
| 5727 int yd3 = date / 365; | |
| 5728 date %= 365; | |
| 5729 year += yd3; | |
| 5730 | |
| 5731 bool is_leap = (!yd1 || yd2) && !yd3; | |
| 5732 | |
| 5733 ASSERT(date >= -1); | |
| 5734 ASSERT(is_leap || (date >= 0)); | |
| 5735 ASSERT((date < 365) || (is_leap && (date < 366))); | |
| 5736 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0)))); | |
| 5737 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date)); | |
| 5738 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date)); | |
| 5739 | |
| 5740 if (is_leap) { | |
| 5741 day = kDayInYear[2*365 + 1 + date]; | |
| 5742 month = kMonthInYear[2*365 + 1 + date]; | |
| 5743 } else { | |
| 5744 day = kDayInYear[date]; | |
| 5745 month = kMonthInYear[date]; | |
| 5746 } | |
| 5747 | |
| 5748 ASSERT(MakeDay(year, month, day) == save_date); | |
| 5749 } | |
| 5750 | |
| 5751 | |
| 5752 static inline void DateYMDFromTime(int date, | |
| 5753 int& year, int& month, int& day) { | |
| 5754 if (date >= 0 && date < 32 * kDaysIn4Years) { | |
| 5755 DateYMDFromTimeAfter1970(date, year, month, day); | |
| 5756 } else { | |
| 5757 DateYMDFromTimeSlow(date, year, month, day); | |
| 5758 } | |
| 5759 } | |
| 5760 | |
| 5761 | |
| 5762 static Object* Runtime_DateYMDFromTime(Arguments args) { | |
| 5763 NoHandleAllocation ha; | |
| 5764 ASSERT(args.length() == 2); | |
| 5765 | |
| 5766 CONVERT_DOUBLE_CHECKED(t, args[0]); | |
| 5767 CONVERT_CHECKED(JSArray, res_array, args[1]); | |
| 5768 | |
| 5769 int year, month, day; | |
| 5770 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day); | |
| 5771 | |
| 5772 res_array->SetElement(0, Smi::FromInt(year)); | |
| 5773 res_array->SetElement(1, Smi::FromInt(month)); | |
| 5774 res_array->SetElement(2, Smi::FromInt(day)); | |
| 5775 | |
| 5776 return Heap::undefined_value(); | |
| 5142 } | 5777 } |
| 5143 | 5778 |
| 5144 | 5779 |
| 5145 static Object* Runtime_NewArgumentsFast(Arguments args) { | 5780 static Object* Runtime_NewArgumentsFast(Arguments args) { |
| 5146 NoHandleAllocation ha; | 5781 NoHandleAllocation ha; |
| 5147 ASSERT(args.length() == 3); | 5782 ASSERT(args.length() == 3); |
| 5148 | 5783 |
| 5149 JSFunction* callee = JSFunction::cast(args[0]); | 5784 JSFunction* callee = JSFunction::cast(args[0]); |
| 5150 Object** parameters = reinterpret_cast<Object**>(args[1]); | 5785 Object** parameters = reinterpret_cast<Object**>(args[1]); |
| 5151 const int length = Smi::cast(args[2])->value(); | 5786 const int length = Smi::cast(args[2])->value(); |
| (...skipping 3322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8474 SharedFunctionInfo::cast(wrapper->value())); | 9109 SharedFunctionInfo::cast(wrapper->value())); |
| 8475 LiveEdit::FunctionPatchabilityStatus check_res = | 9110 LiveEdit::FunctionPatchabilityStatus check_res = |
| 8476 FindFunctionCodeOnStacks(shared); | 9111 FindFunctionCodeOnStacks(shared); |
| 8477 SetElement(result, i, Handle<Smi>(Smi::FromInt(check_res))); | 9112 SetElement(result, i, Handle<Smi>(Smi::FromInt(check_res))); |
| 8478 } | 9113 } |
| 8479 | 9114 |
| 8480 return *result; | 9115 return *result; |
| 8481 } | 9116 } |
| 8482 | 9117 |
| 8483 | 9118 |
| 9119 // A testing entry. Returns statement position which is the closest to | |
| 9120 // source_position. | |
| 9121 static Object* Runtime_GetFunctionCodePositionFromSource(Arguments args) { | |
| 9122 ASSERT(args.length() == 2); | |
| 9123 HandleScope scope; | |
| 9124 CONVERT_ARG_CHECKED(JSFunction, function, 0); | |
| 9125 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); | |
| 9126 | |
| 9127 Handle<Code> code(function->code()); | |
| 9128 | |
| 9129 RelocIterator it(*code, 1 << RelocInfo::STATEMENT_POSITION); | |
| 9130 int closest_pc = 0; | |
| 9131 int distance = kMaxInt; | |
| 9132 while (!it.done()) { | |
| 9133 int statement_position = static_cast<int>(it.rinfo()->data()); | |
| 9134 // Check if this break point is closer that what was previously found. | |
| 9135 if (source_position <= statement_position && | |
| 9136 statement_position - source_position < distance) { | |
| 9137 closest_pc = it.rinfo()->pc() - code->instruction_start(); | |
| 9138 distance = statement_position - source_position; | |
| 9139 // Check whether we can't get any closer. | |
| 9140 if (distance == 0) break; | |
| 9141 } | |
| 9142 it.next(); | |
| 9143 } | |
| 9144 | |
| 9145 return Smi::FromInt(closest_pc); | |
| 9146 } | |
| 9147 | |
| 9148 | |
| 8484 #endif // ENABLE_DEBUGGER_SUPPORT | 9149 #endif // ENABLE_DEBUGGER_SUPPORT |
| 8485 | 9150 |
| 8486 #ifdef ENABLE_LOGGING_AND_PROFILING | 9151 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 8487 | 9152 |
| 8488 static Object* Runtime_ProfilerResume(Arguments args) { | 9153 static Object* Runtime_ProfilerResume(Arguments args) { |
| 8489 NoHandleAllocation ha; | 9154 NoHandleAllocation ha; |
| 8490 ASSERT(args.length() == 2); | 9155 ASSERT(args.length() == 2); |
| 8491 | 9156 |
| 8492 CONVERT_CHECKED(Smi, smi_modules, args[0]); | 9157 CONVERT_CHECKED(Smi, smi_modules, args[0]); |
| 8493 CONVERT_CHECKED(Smi, smi_tag, args[1]); | 9158 CONVERT_CHECKED(Smi, smi_tag, args[1]); |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8668 | 9333 |
| 8669 | 9334 |
| 8670 #ifdef DEBUG | 9335 #ifdef DEBUG |
| 8671 // ListNatives is ONLY used by the fuzz-natives.js in debug mode | 9336 // ListNatives is ONLY used by the fuzz-natives.js in debug mode |
| 8672 // Exclude the code in release mode. | 9337 // Exclude the code in release mode. |
| 8673 static Object* Runtime_ListNatives(Arguments args) { | 9338 static Object* Runtime_ListNatives(Arguments args) { |
| 8674 ASSERT(args.length() == 0); | 9339 ASSERT(args.length() == 0); |
| 8675 HandleScope scope; | 9340 HandleScope scope; |
| 8676 Handle<JSArray> result = Factory::NewJSArray(0); | 9341 Handle<JSArray> result = Factory::NewJSArray(0); |
| 8677 int index = 0; | 9342 int index = 0; |
| 9343 bool inline_runtime_functions = false; | |
| 8678 #define ADD_ENTRY(Name, argc, ressize) \ | 9344 #define ADD_ENTRY(Name, argc, ressize) \ |
| 8679 { \ | 9345 { \ |
| 8680 HandleScope inner; \ | 9346 HandleScope inner; \ |
| 8681 Handle<String> name = \ | 9347 Handle<String> name; \ |
| 8682 Factory::NewStringFromAscii( \ | 9348 /* Inline runtime functions have an underscore in front of the name. */ \ |
| 8683 Vector<const char>(#Name, StrLength(#Name))); \ | 9349 if (inline_runtime_functions) { \ |
| 9350 name = Factory::NewStringFromAscii( \ | |
| 9351 Vector<const char>("_" #Name, StrLength("_" #Name))); \ | |
| 9352 } else { \ | |
| 9353 name = Factory::NewStringFromAscii( \ | |
| 9354 Vector<const char>(#Name, StrLength(#Name))); \ | |
| 9355 } \ | |
| 8684 Handle<JSArray> pair = Factory::NewJSArray(0); \ | 9356 Handle<JSArray> pair = Factory::NewJSArray(0); \ |
| 8685 SetElement(pair, 0, name); \ | 9357 SetElement(pair, 0, name); \ |
| 8686 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \ | 9358 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \ |
| 8687 SetElement(result, index++, pair); \ | 9359 SetElement(result, index++, pair); \ |
| 8688 } | 9360 } |
| 9361 inline_runtime_functions = false; | |
| 8689 RUNTIME_FUNCTION_LIST(ADD_ENTRY) | 9362 RUNTIME_FUNCTION_LIST(ADD_ENTRY) |
| 9363 inline_runtime_functions = true; | |
| 9364 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY) | |
| 8690 #undef ADD_ENTRY | 9365 #undef ADD_ENTRY |
| 8691 return *result; | 9366 return *result; |
| 8692 } | 9367 } |
| 8693 #endif | 9368 #endif |
| 8694 | 9369 |
| 8695 | 9370 |
| 8696 static Object* Runtime_Log(Arguments args) { | 9371 static Object* Runtime_Log(Arguments args) { |
| 8697 ASSERT(args.length() == 2); | 9372 ASSERT(args.length() == 2); |
| 8698 CONVERT_CHECKED(String, format, args[0]); | 9373 CONVERT_CHECKED(String, format, args[0]); |
| 8699 CONVERT_CHECKED(JSArray, elms, args[1]); | 9374 CONVERT_CHECKED(JSArray, elms, args[1]); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8749 } else { | 9424 } else { |
| 8750 // Handle last resort GC and make sure to allow future allocations | 9425 // Handle last resort GC and make sure to allow future allocations |
| 8751 // to grow the heap without causing GCs (if possible). | 9426 // to grow the heap without causing GCs (if possible). |
| 8752 Counters::gc_last_resort_from_js.Increment(); | 9427 Counters::gc_last_resort_from_js.Increment(); |
| 8753 Heap::CollectAllGarbage(false); | 9428 Heap::CollectAllGarbage(false); |
| 8754 } | 9429 } |
| 8755 } | 9430 } |
| 8756 | 9431 |
| 8757 | 9432 |
| 8758 } } // namespace v8::internal | 9433 } } // namespace v8::internal |
| OLD | NEW |