| OLD | NEW | 
|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include <stdlib.h> | 5 #include <stdlib.h> | 
| 6 #include <limits> | 6 #include <limits> | 
| 7 | 7 | 
| 8 #include "src/v8.h" | 8 #include "src/v8.h" | 
| 9 | 9 | 
| 10 #include "src/accessors.h" | 10 #include "src/accessors.h" | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 21 #include "src/conversions.h" | 21 #include "src/conversions.h" | 
| 22 #include "src/cpu-profiler.h" | 22 #include "src/cpu-profiler.h" | 
| 23 #include "src/date.h" | 23 #include "src/date.h" | 
| 24 #include "src/dateparser-inl.h" | 24 #include "src/dateparser-inl.h" | 
| 25 #include "src/debug.h" | 25 #include "src/debug.h" | 
| 26 #include "src/deoptimizer.h" | 26 #include "src/deoptimizer.h" | 
| 27 #include "src/execution.h" | 27 #include "src/execution.h" | 
| 28 #include "src/full-codegen.h" | 28 #include "src/full-codegen.h" | 
| 29 #include "src/global-handles.h" | 29 #include "src/global-handles.h" | 
| 30 #include "src/isolate-inl.h" | 30 #include "src/isolate-inl.h" | 
| 31 #include "src/json-parser.h" |  | 
| 32 #include "src/json-stringifier.h" |  | 
| 33 #include "src/jsregexp-inl.h" |  | 
| 34 #include "src/jsregexp.h" |  | 
| 35 #include "src/liveedit.h" | 31 #include "src/liveedit.h" | 
| 36 #include "src/misc-intrinsics.h" | 32 #include "src/misc-intrinsics.h" | 
| 37 #include "src/parser.h" | 33 #include "src/parser.h" | 
| 38 #include "src/prototype.h" | 34 #include "src/prototype.h" | 
| 39 #include "src/runtime/runtime.h" | 35 #include "src/runtime/runtime.h" | 
| 40 #include "src/runtime/runtime-utils.h" | 36 #include "src/runtime/runtime-utils.h" | 
| 41 #include "src/runtime-profiler.h" | 37 #include "src/runtime-profiler.h" | 
| 42 #include "src/scopeinfo.h" | 38 #include "src/scopeinfo.h" | 
| 43 #include "src/smart-pointers.h" | 39 #include "src/smart-pointers.h" | 
| 44 #include "src/string-search.h" |  | 
| 45 #include "src/uri.h" |  | 
| 46 #include "src/utils.h" | 40 #include "src/utils.h" | 
| 47 #include "src/v8threads.h" | 41 #include "src/v8threads.h" | 
| 48 #include "src/vm-state-inl.h" | 42 #include "src/vm-state-inl.h" | 
| 49 #include "third_party/fdlibm/fdlibm.h" | 43 #include "third_party/fdlibm/fdlibm.h" | 
| 50 | 44 | 
| 51 | 45 | 
| 52 #ifndef _STLP_VENDOR_CSTD | 46 #ifndef _STLP_VENDOR_CSTD | 
| 53 // STLPort doesn't import fpclassify and isless into the std namespace. | 47 // STLPort doesn't import fpclassify and isless into the std namespace. | 
| 54 using std::fpclassify; | 48 using std::fpclassify; | 
| 55 using std::isless; | 49 using std::isless; | 
| (...skipping 1926 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1982   if (obj->IsJSGlobalProxy()) { | 1976   if (obj->IsJSGlobalProxy()) { | 
| 1983     PrototypeIterator iter(isolate, obj); | 1977     PrototypeIterator iter(isolate, obj); | 
| 1984     if (iter.IsAtEnd()) return isolate->heap()->false_value(); | 1978     if (iter.IsAtEnd()) return isolate->heap()->false_value(); | 
| 1985     DCHECK(iter.GetCurrent()->IsJSGlobalObject()); | 1979     DCHECK(iter.GetCurrent()->IsJSGlobalObject()); | 
| 1986     obj = JSObject::cast(iter.GetCurrent()); | 1980     obj = JSObject::cast(iter.GetCurrent()); | 
| 1987   } | 1981   } | 
| 1988   return isolate->heap()->ToBoolean(obj->map()->is_extensible()); | 1982   return isolate->heap()->ToBoolean(obj->map()->is_extensible()); | 
| 1989 } | 1983 } | 
| 1990 | 1984 | 
| 1991 | 1985 | 
| 1992 RUNTIME_FUNCTION(Runtime_RegExpCompile) { |  | 
| 1993   HandleScope scope(isolate); |  | 
| 1994   DCHECK(args.length() == 3); |  | 
| 1995   CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0); |  | 
| 1996   CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); |  | 
| 1997   CONVERT_ARG_HANDLE_CHECKED(String, flags, 2); |  | 
| 1998   Handle<Object> result; |  | 
| 1999   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |  | 
| 2000                                      RegExpImpl::Compile(re, pattern, flags)); |  | 
| 2001   return *result; |  | 
| 2002 } |  | 
| 2003 |  | 
| 2004 |  | 
| 2005 RUNTIME_FUNCTION(Runtime_CreateApiFunction) { | 1986 RUNTIME_FUNCTION(Runtime_CreateApiFunction) { | 
| 2006   HandleScope scope(isolate); | 1987   HandleScope scope(isolate); | 
| 2007   DCHECK(args.length() == 2); | 1988   DCHECK(args.length() == 2); | 
| 2008   CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0); | 1989   CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0); | 
| 2009   CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); | 1990   CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); | 
| 2010   return *isolate->factory()->CreateApiFunction(data, prototype); | 1991   return *isolate->factory()->CreateApiFunction(data, prototype); | 
| 2011 } | 1992 } | 
| 2012 | 1993 | 
| 2013 | 1994 | 
| 2014 RUNTIME_FUNCTION(Runtime_IsTemplate) { | 1995 RUNTIME_FUNCTION(Runtime_IsTemplate) { | 
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 2393   CONVERT_SMI_ARG_CHECKED(properties, 1); | 2374   CONVERT_SMI_ARG_CHECKED(properties, 1); | 
| 2394   // Conservative upper limit to prevent fuzz tests from going OOM. | 2375   // Conservative upper limit to prevent fuzz tests from going OOM. | 
| 2395   RUNTIME_ASSERT(properties <= 100000); | 2376   RUNTIME_ASSERT(properties <= 100000); | 
| 2396   if (object->HasFastProperties() && !object->IsJSGlobalProxy()) { | 2377   if (object->HasFastProperties() && !object->IsJSGlobalProxy()) { | 
| 2397     JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties); | 2378     JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties); | 
| 2398   } | 2379   } | 
| 2399   return *object; | 2380   return *object; | 
| 2400 } | 2381 } | 
| 2401 | 2382 | 
| 2402 | 2383 | 
| 2403 RUNTIME_FUNCTION(Runtime_RegExpExecRT) { |  | 
| 2404   HandleScope scope(isolate); |  | 
| 2405   DCHECK(args.length() == 4); |  | 
| 2406   CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); |  | 
| 2407   CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); |  | 
| 2408   CONVERT_INT32_ARG_CHECKED(index, 2); |  | 
| 2409   CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); |  | 
| 2410   // Due to the way the JS calls are constructed this must be less than the |  | 
| 2411   // length of a string, i.e. it is always a Smi.  We check anyway for security. |  | 
| 2412   RUNTIME_ASSERT(index >= 0); |  | 
| 2413   RUNTIME_ASSERT(index <= subject->length()); |  | 
| 2414   isolate->counters()->regexp_entry_runtime()->Increment(); |  | 
| 2415   Handle<Object> result; |  | 
| 2416   ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 2417       isolate, result, |  | 
| 2418       RegExpImpl::Exec(regexp, subject, index, last_match_info)); |  | 
| 2419   return *result; |  | 
| 2420 } |  | 
| 2421 |  | 
| 2422 |  | 
| 2423 RUNTIME_FUNCTION(Runtime_RegExpConstructResult) { |  | 
| 2424   HandleScope handle_scope(isolate); |  | 
| 2425   DCHECK(args.length() == 3); |  | 
| 2426   CONVERT_SMI_ARG_CHECKED(size, 0); |  | 
| 2427   RUNTIME_ASSERT(size >= 0 && size <= FixedArray::kMaxLength); |  | 
| 2428   CONVERT_ARG_HANDLE_CHECKED(Object, index, 1); |  | 
| 2429   CONVERT_ARG_HANDLE_CHECKED(Object, input, 2); |  | 
| 2430   Handle<FixedArray> elements = isolate->factory()->NewFixedArray(size); |  | 
| 2431   Handle<Map> regexp_map(isolate->native_context()->regexp_result_map()); |  | 
| 2432   Handle<JSObject> object = |  | 
| 2433       isolate->factory()->NewJSObjectFromMap(regexp_map, NOT_TENURED, false); |  | 
| 2434   Handle<JSArray> array = Handle<JSArray>::cast(object); |  | 
| 2435   array->set_elements(*elements); |  | 
| 2436   array->set_length(Smi::FromInt(size)); |  | 
| 2437   // Write in-object properties after the length of the array. |  | 
| 2438   array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, *index); |  | 
| 2439   array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, *input); |  | 
| 2440   return *array; |  | 
| 2441 } |  | 
| 2442 |  | 
| 2443 |  | 
| 2444 RUNTIME_FUNCTION(Runtime_RegExpInitializeObject) { |  | 
| 2445   HandleScope scope(isolate); |  | 
| 2446   DCHECK(args.length() == 6); |  | 
| 2447   CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); |  | 
| 2448   CONVERT_ARG_HANDLE_CHECKED(String, source, 1); |  | 
| 2449   // If source is the empty string we set it to "(?:)" instead as |  | 
| 2450   // suggested by ECMA-262, 5th, section 15.10.4.1. |  | 
| 2451   if (source->length() == 0) source = isolate->factory()->query_colon_string(); |  | 
| 2452 |  | 
| 2453   CONVERT_ARG_HANDLE_CHECKED(Object, global, 2); |  | 
| 2454   if (!global->IsTrue()) global = isolate->factory()->false_value(); |  | 
| 2455 |  | 
| 2456   CONVERT_ARG_HANDLE_CHECKED(Object, ignoreCase, 3); |  | 
| 2457   if (!ignoreCase->IsTrue()) ignoreCase = isolate->factory()->false_value(); |  | 
| 2458 |  | 
| 2459   CONVERT_ARG_HANDLE_CHECKED(Object, multiline, 4); |  | 
| 2460   if (!multiline->IsTrue()) multiline = isolate->factory()->false_value(); |  | 
| 2461 |  | 
| 2462   CONVERT_ARG_HANDLE_CHECKED(Object, sticky, 5); |  | 
| 2463   if (!sticky->IsTrue()) sticky = isolate->factory()->false_value(); |  | 
| 2464 |  | 
| 2465   Map* map = regexp->map(); |  | 
| 2466   Object* constructor = map->constructor(); |  | 
| 2467   if (!FLAG_harmony_regexps && constructor->IsJSFunction() && |  | 
| 2468       JSFunction::cast(constructor)->initial_map() == map) { |  | 
| 2469     // If we still have the original map, set in-object properties directly. |  | 
| 2470     regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *source); |  | 
| 2471     // Both true and false are immovable immortal objects so no need for write |  | 
| 2472     // barrier. |  | 
| 2473     regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, *global, |  | 
| 2474                                   SKIP_WRITE_BARRIER); |  | 
| 2475     regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, *ignoreCase, |  | 
| 2476                                   SKIP_WRITE_BARRIER); |  | 
| 2477     regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, *multiline, |  | 
| 2478                                   SKIP_WRITE_BARRIER); |  | 
| 2479     regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, |  | 
| 2480                                   Smi::FromInt(0), SKIP_WRITE_BARRIER); |  | 
| 2481     return *regexp; |  | 
| 2482   } |  | 
| 2483 |  | 
| 2484   // Map has changed, so use generic, but slower, method.  We also end here if |  | 
| 2485   // the --harmony-regexp flag is set, because the initial map does not have |  | 
| 2486   // space for the 'sticky' flag, since it is from the snapshot, but must work |  | 
| 2487   // both with and without --harmony-regexp.  When sticky comes out from under |  | 
| 2488   // the flag, we will be able to use the fast initial map. |  | 
| 2489   PropertyAttributes final = |  | 
| 2490       static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE); |  | 
| 2491   PropertyAttributes writable = |  | 
| 2492       static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); |  | 
| 2493   Handle<Object> zero(Smi::FromInt(0), isolate); |  | 
| 2494   Factory* factory = isolate->factory(); |  | 
| 2495   JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->source_string(), |  | 
| 2496                                            source, final).Check(); |  | 
| 2497   JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->global_string(), |  | 
| 2498                                            global, final).Check(); |  | 
| 2499   JSObject::SetOwnPropertyIgnoreAttributes( |  | 
| 2500       regexp, factory->ignore_case_string(), ignoreCase, final).Check(); |  | 
| 2501   JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->multiline_string(), |  | 
| 2502                                            multiline, final).Check(); |  | 
| 2503   if (FLAG_harmony_regexps) { |  | 
| 2504     JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->sticky_string(), |  | 
| 2505                                              sticky, final).Check(); |  | 
| 2506   } |  | 
| 2507   JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->last_index_string(), |  | 
| 2508                                            zero, writable).Check(); |  | 
| 2509   return *regexp; |  | 
| 2510 } |  | 
| 2511 |  | 
| 2512 |  | 
| 2513 RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) { | 2384 RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) { | 
| 2514   HandleScope scope(isolate); | 2385   HandleScope scope(isolate); | 
| 2515   DCHECK(args.length() == 1); | 2386   DCHECK(args.length() == 1); | 
| 2516   CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0); | 2387   CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0); | 
| 2517   Object* length = prototype->length(); | 2388   Object* length = prototype->length(); | 
| 2518   RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0); | 2389   RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0); | 
| 2519   RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements()); | 2390   RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements()); | 
| 2520   // This is necessary to enable fast checks for absence of elements | 2391   // This is necessary to enable fast checks for absence of elements | 
| 2521   // on Array.prototype and below. | 2392   // on Array.prototype and below. | 
| 2522   prototype->set_elements(isolate->heap()->empty_fixed_array()); | 2393   prototype->set_elements(isolate->heap()->empty_fixed_array()); | 
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 2590   if (shared->native() || shared->strict_mode() == STRICT) { | 2461   if (shared->native() || shared->strict_mode() == STRICT) { | 
| 2591     return isolate->heap()->undefined_value(); | 2462     return isolate->heap()->undefined_value(); | 
| 2592   } | 2463   } | 
| 2593   // Returns undefined for strict or native functions, or | 2464   // Returns undefined for strict or native functions, or | 
| 2594   // the associated global receiver for "normal" functions. | 2465   // the associated global receiver for "normal" functions. | 
| 2595 | 2466 | 
| 2596   return function->global_proxy(); | 2467   return function->global_proxy(); | 
| 2597 } | 2468 } | 
| 2598 | 2469 | 
| 2599 | 2470 | 
| 2600 RUNTIME_FUNCTION(Runtime_MaterializeRegExpLiteral) { |  | 
| 2601   HandleScope scope(isolate); |  | 
| 2602   DCHECK(args.length() == 4); |  | 
| 2603   CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); |  | 
| 2604   CONVERT_SMI_ARG_CHECKED(index, 1); |  | 
| 2605   CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2); |  | 
| 2606   CONVERT_ARG_HANDLE_CHECKED(String, flags, 3); |  | 
| 2607 |  | 
| 2608   // Get the RegExp function from the context in the literals array. |  | 
| 2609   // This is the RegExp function from the context in which the |  | 
| 2610   // function was created.  We do not use the RegExp function from the |  | 
| 2611   // current native context because this might be the RegExp function |  | 
| 2612   // from another context which we should not have access to. |  | 
| 2613   Handle<JSFunction> constructor = Handle<JSFunction>( |  | 
| 2614       JSFunction::NativeContextFromLiterals(*literals)->regexp_function()); |  | 
| 2615   // Compute the regular expression literal. |  | 
| 2616   Handle<Object> regexp; |  | 
| 2617   ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 2618       isolate, regexp, |  | 
| 2619       RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags)); |  | 
| 2620   literals->set(index, *regexp); |  | 
| 2621   return *regexp; |  | 
| 2622 } |  | 
| 2623 |  | 
| 2624 |  | 
| 2625 RUNTIME_FUNCTION(Runtime_FunctionGetName) { | 2471 RUNTIME_FUNCTION(Runtime_FunctionGetName) { | 
| 2626   SealHandleScope shs(isolate); | 2472   SealHandleScope shs(isolate); | 
| 2627   DCHECK(args.length() == 1); | 2473   DCHECK(args.length() == 1); | 
| 2628 | 2474 | 
| 2629   CONVERT_ARG_CHECKED(JSFunction, f, 0); | 2475   CONVERT_ARG_CHECKED(JSFunction, f, 0); | 
| 2630   return f->shared()->name(); | 2476   return f->shared()->name(); | 
| 2631 } | 2477 } | 
| 2632 | 2478 | 
| 2633 | 2479 | 
| 2634 RUNTIME_FUNCTION(Runtime_FunctionSetName) { | 2480 RUNTIME_FUNCTION(Runtime_FunctionSetName) { | 
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 3006   // %ObjectFreeze is a fast path and these cases are handled elsewhere. | 2852   // %ObjectFreeze is a fast path and these cases are handled elsewhere. | 
| 3007   RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() && | 2853   RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() && | 
| 3008                  !object->map()->is_observed() && !object->IsJSProxy()); | 2854                  !object->map()->is_observed() && !object->IsJSProxy()); | 
| 3009 | 2855 | 
| 3010   Handle<Object> result; | 2856   Handle<Object> result; | 
| 3011   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object)); | 2857   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object)); | 
| 3012   return *result; | 2858   return *result; | 
| 3013 } | 2859 } | 
| 3014 | 2860 | 
| 3015 | 2861 | 
| 3016 RUNTIME_FUNCTION(Runtime_StringCharCodeAtRT) { |  | 
| 3017   HandleScope handle_scope(isolate); |  | 
| 3018   DCHECK(args.length() == 2); |  | 
| 3019 |  | 
| 3020   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); |  | 
| 3021   CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]); |  | 
| 3022 |  | 
| 3023   // Flatten the string.  If someone wants to get a char at an index |  | 
| 3024   // in a cons string, it is likely that more indices will be |  | 
| 3025   // accessed. |  | 
| 3026   subject = String::Flatten(subject); |  | 
| 3027 |  | 
| 3028   if (i >= static_cast<uint32_t>(subject->length())) { |  | 
| 3029     return isolate->heap()->nan_value(); |  | 
| 3030   } |  | 
| 3031 |  | 
| 3032   return Smi::FromInt(subject->Get(i)); |  | 
| 3033 } |  | 
| 3034 |  | 
| 3035 |  | 
| 3036 RUNTIME_FUNCTION(Runtime_CharFromCode) { |  | 
| 3037   HandleScope handlescope(isolate); |  | 
| 3038   DCHECK(args.length() == 1); |  | 
| 3039   if (args[0]->IsNumber()) { |  | 
| 3040     CONVERT_NUMBER_CHECKED(uint32_t, code, Uint32, args[0]); |  | 
| 3041     code &= 0xffff; |  | 
| 3042     return *isolate->factory()->LookupSingleCharacterStringFromCode(code); |  | 
| 3043   } |  | 
| 3044   return isolate->heap()->empty_string(); |  | 
| 3045 } |  | 
| 3046 |  | 
| 3047 |  | 
| 3048 class FixedArrayBuilder { |  | 
| 3049  public: |  | 
| 3050   explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity) |  | 
| 3051       : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)), |  | 
| 3052         length_(0), |  | 
| 3053         has_non_smi_elements_(false) { |  | 
| 3054     // Require a non-zero initial size. Ensures that doubling the size to |  | 
| 3055     // extend the array will work. |  | 
| 3056     DCHECK(initial_capacity > 0); |  | 
| 3057   } |  | 
| 3058 |  | 
| 3059   explicit FixedArrayBuilder(Handle<FixedArray> backing_store) |  | 
| 3060       : array_(backing_store), length_(0), has_non_smi_elements_(false) { |  | 
| 3061     // Require a non-zero initial size. Ensures that doubling the size to |  | 
| 3062     // extend the array will work. |  | 
| 3063     DCHECK(backing_store->length() > 0); |  | 
| 3064   } |  | 
| 3065 |  | 
| 3066   bool HasCapacity(int elements) { |  | 
| 3067     int length = array_->length(); |  | 
| 3068     int required_length = length_ + elements; |  | 
| 3069     return (length >= required_length); |  | 
| 3070   } |  | 
| 3071 |  | 
| 3072   void EnsureCapacity(int elements) { |  | 
| 3073     int length = array_->length(); |  | 
| 3074     int required_length = length_ + elements; |  | 
| 3075     if (length < required_length) { |  | 
| 3076       int new_length = length; |  | 
| 3077       do { |  | 
| 3078         new_length *= 2; |  | 
| 3079       } while (new_length < required_length); |  | 
| 3080       Handle<FixedArray> extended_array = |  | 
| 3081           array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length); |  | 
| 3082       array_->CopyTo(0, *extended_array, 0, length_); |  | 
| 3083       array_ = extended_array; |  | 
| 3084     } |  | 
| 3085   } |  | 
| 3086 |  | 
| 3087   void Add(Object* value) { |  | 
| 3088     DCHECK(!value->IsSmi()); |  | 
| 3089     DCHECK(length_ < capacity()); |  | 
| 3090     array_->set(length_, value); |  | 
| 3091     length_++; |  | 
| 3092     has_non_smi_elements_ = true; |  | 
| 3093   } |  | 
| 3094 |  | 
| 3095   void Add(Smi* value) { |  | 
| 3096     DCHECK(value->IsSmi()); |  | 
| 3097     DCHECK(length_ < capacity()); |  | 
| 3098     array_->set(length_, value); |  | 
| 3099     length_++; |  | 
| 3100   } |  | 
| 3101 |  | 
| 3102   Handle<FixedArray> array() { return array_; } |  | 
| 3103 |  | 
| 3104   int length() { return length_; } |  | 
| 3105 |  | 
| 3106   int capacity() { return array_->length(); } |  | 
| 3107 |  | 
| 3108   Handle<JSArray> ToJSArray(Handle<JSArray> target_array) { |  | 
| 3109     JSArray::SetContent(target_array, array_); |  | 
| 3110     target_array->set_length(Smi::FromInt(length_)); |  | 
| 3111     return target_array; |  | 
| 3112   } |  | 
| 3113 |  | 
| 3114 |  | 
| 3115  private: |  | 
| 3116   Handle<FixedArray> array_; |  | 
| 3117   int length_; |  | 
| 3118   bool has_non_smi_elements_; |  | 
| 3119 }; |  | 
| 3120 |  | 
| 3121 |  | 
| 3122 // Forward declarations. |  | 
| 3123 const int kStringBuilderConcatHelperLengthBits = 11; |  | 
| 3124 const int kStringBuilderConcatHelperPositionBits = 19; |  | 
| 3125 |  | 
| 3126 template <typename schar> |  | 
| 3127 static inline void StringBuilderConcatHelper(String*, schar*, FixedArray*, int); |  | 
| 3128 |  | 
| 3129 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits> |  | 
| 3130     StringBuilderSubstringLength; |  | 
| 3131 typedef BitField<int, kStringBuilderConcatHelperLengthBits, |  | 
| 3132                  kStringBuilderConcatHelperPositionBits> |  | 
| 3133     StringBuilderSubstringPosition; |  | 
| 3134 |  | 
| 3135 |  | 
| 3136 class ReplacementStringBuilder { |  | 
| 3137  public: |  | 
| 3138   ReplacementStringBuilder(Heap* heap, Handle<String> subject, |  | 
| 3139                            int estimated_part_count) |  | 
| 3140       : heap_(heap), |  | 
| 3141         array_builder_(heap->isolate(), estimated_part_count), |  | 
| 3142         subject_(subject), |  | 
| 3143         character_count_(0), |  | 
| 3144         is_one_byte_(subject->IsOneByteRepresentation()) { |  | 
| 3145     // Require a non-zero initial size. Ensures that doubling the size to |  | 
| 3146     // extend the array will work. |  | 
| 3147     DCHECK(estimated_part_count > 0); |  | 
| 3148   } |  | 
| 3149 |  | 
| 3150   static inline void AddSubjectSlice(FixedArrayBuilder* builder, int from, |  | 
| 3151                                      int to) { |  | 
| 3152     DCHECK(from >= 0); |  | 
| 3153     int length = to - from; |  | 
| 3154     DCHECK(length > 0); |  | 
| 3155     if (StringBuilderSubstringLength::is_valid(length) && |  | 
| 3156         StringBuilderSubstringPosition::is_valid(from)) { |  | 
| 3157       int encoded_slice = StringBuilderSubstringLength::encode(length) | |  | 
| 3158                           StringBuilderSubstringPosition::encode(from); |  | 
| 3159       builder->Add(Smi::FromInt(encoded_slice)); |  | 
| 3160     } else { |  | 
| 3161       // Otherwise encode as two smis. |  | 
| 3162       builder->Add(Smi::FromInt(-length)); |  | 
| 3163       builder->Add(Smi::FromInt(from)); |  | 
| 3164     } |  | 
| 3165   } |  | 
| 3166 |  | 
| 3167 |  | 
| 3168   void EnsureCapacity(int elements) { array_builder_.EnsureCapacity(elements); } |  | 
| 3169 |  | 
| 3170 |  | 
| 3171   void AddSubjectSlice(int from, int to) { |  | 
| 3172     AddSubjectSlice(&array_builder_, from, to); |  | 
| 3173     IncrementCharacterCount(to - from); |  | 
| 3174   } |  | 
| 3175 |  | 
| 3176 |  | 
| 3177   void AddString(Handle<String> string) { |  | 
| 3178     int length = string->length(); |  | 
| 3179     DCHECK(length > 0); |  | 
| 3180     AddElement(*string); |  | 
| 3181     if (!string->IsOneByteRepresentation()) { |  | 
| 3182       is_one_byte_ = false; |  | 
| 3183     } |  | 
| 3184     IncrementCharacterCount(length); |  | 
| 3185   } |  | 
| 3186 |  | 
| 3187 |  | 
| 3188   MaybeHandle<String> ToString() { |  | 
| 3189     Isolate* isolate = heap_->isolate(); |  | 
| 3190     if (array_builder_.length() == 0) { |  | 
| 3191       return isolate->factory()->empty_string(); |  | 
| 3192     } |  | 
| 3193 |  | 
| 3194     Handle<String> joined_string; |  | 
| 3195     if (is_one_byte_) { |  | 
| 3196       Handle<SeqOneByteString> seq; |  | 
| 3197       ASSIGN_RETURN_ON_EXCEPTION( |  | 
| 3198           isolate, seq, |  | 
| 3199           isolate->factory()->NewRawOneByteString(character_count_), String); |  | 
| 3200 |  | 
| 3201       DisallowHeapAllocation no_gc; |  | 
| 3202       uint8_t* char_buffer = seq->GetChars(); |  | 
| 3203       StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(), |  | 
| 3204                                 array_builder_.length()); |  | 
| 3205       joined_string = Handle<String>::cast(seq); |  | 
| 3206     } else { |  | 
| 3207       // Two-byte. |  | 
| 3208       Handle<SeqTwoByteString> seq; |  | 
| 3209       ASSIGN_RETURN_ON_EXCEPTION( |  | 
| 3210           isolate, seq, |  | 
| 3211           isolate->factory()->NewRawTwoByteString(character_count_), String); |  | 
| 3212 |  | 
| 3213       DisallowHeapAllocation no_gc; |  | 
| 3214       uc16* char_buffer = seq->GetChars(); |  | 
| 3215       StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(), |  | 
| 3216                                 array_builder_.length()); |  | 
| 3217       joined_string = Handle<String>::cast(seq); |  | 
| 3218     } |  | 
| 3219     return joined_string; |  | 
| 3220   } |  | 
| 3221 |  | 
| 3222 |  | 
| 3223   void IncrementCharacterCount(int by) { |  | 
| 3224     if (character_count_ > String::kMaxLength - by) { |  | 
| 3225       STATIC_ASSERT(String::kMaxLength < kMaxInt); |  | 
| 3226       character_count_ = kMaxInt; |  | 
| 3227     } else { |  | 
| 3228       character_count_ += by; |  | 
| 3229     } |  | 
| 3230   } |  | 
| 3231 |  | 
| 3232  private: |  | 
| 3233   void AddElement(Object* element) { |  | 
| 3234     DCHECK(element->IsSmi() || element->IsString()); |  | 
| 3235     DCHECK(array_builder_.capacity() > array_builder_.length()); |  | 
| 3236     array_builder_.Add(element); |  | 
| 3237   } |  | 
| 3238 |  | 
| 3239   Heap* heap_; |  | 
| 3240   FixedArrayBuilder array_builder_; |  | 
| 3241   Handle<String> subject_; |  | 
| 3242   int character_count_; |  | 
| 3243   bool is_one_byte_; |  | 
| 3244 }; |  | 
| 3245 |  | 
| 3246 |  | 
| 3247 class CompiledReplacement { |  | 
| 3248  public: |  | 
| 3249   explicit CompiledReplacement(Zone* zone) |  | 
| 3250       : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {} |  | 
| 3251 |  | 
| 3252   // Return whether the replacement is simple. |  | 
| 3253   bool Compile(Handle<String> replacement, int capture_count, |  | 
| 3254                int subject_length); |  | 
| 3255 |  | 
| 3256   // Use Apply only if Compile returned false. |  | 
| 3257   void Apply(ReplacementStringBuilder* builder, int match_from, int match_to, |  | 
| 3258              int32_t* match); |  | 
| 3259 |  | 
| 3260   // Number of distinct parts of the replacement pattern. |  | 
| 3261   int parts() { return parts_.length(); } |  | 
| 3262 |  | 
| 3263   Zone* zone() const { return zone_; } |  | 
| 3264 |  | 
| 3265  private: |  | 
| 3266   enum PartType { |  | 
| 3267     SUBJECT_PREFIX = 1, |  | 
| 3268     SUBJECT_SUFFIX, |  | 
| 3269     SUBJECT_CAPTURE, |  | 
| 3270     REPLACEMENT_SUBSTRING, |  | 
| 3271     REPLACEMENT_STRING, |  | 
| 3272     NUMBER_OF_PART_TYPES |  | 
| 3273   }; |  | 
| 3274 |  | 
| 3275   struct ReplacementPart { |  | 
| 3276     static inline ReplacementPart SubjectMatch() { |  | 
| 3277       return ReplacementPart(SUBJECT_CAPTURE, 0); |  | 
| 3278     } |  | 
| 3279     static inline ReplacementPart SubjectCapture(int capture_index) { |  | 
| 3280       return ReplacementPart(SUBJECT_CAPTURE, capture_index); |  | 
| 3281     } |  | 
| 3282     static inline ReplacementPart SubjectPrefix() { |  | 
| 3283       return ReplacementPart(SUBJECT_PREFIX, 0); |  | 
| 3284     } |  | 
| 3285     static inline ReplacementPart SubjectSuffix(int subject_length) { |  | 
| 3286       return ReplacementPart(SUBJECT_SUFFIX, subject_length); |  | 
| 3287     } |  | 
| 3288     static inline ReplacementPart ReplacementString() { |  | 
| 3289       return ReplacementPart(REPLACEMENT_STRING, 0); |  | 
| 3290     } |  | 
| 3291     static inline ReplacementPart ReplacementSubString(int from, int to) { |  | 
| 3292       DCHECK(from >= 0); |  | 
| 3293       DCHECK(to > from); |  | 
| 3294       return ReplacementPart(-from, to); |  | 
| 3295     } |  | 
| 3296 |  | 
| 3297     // If tag <= 0 then it is the negation of a start index of a substring of |  | 
| 3298     // the replacement pattern, otherwise it's a value from PartType. |  | 
| 3299     ReplacementPart(int tag, int data) : tag(tag), data(data) { |  | 
| 3300       // Must be non-positive or a PartType value. |  | 
| 3301       DCHECK(tag < NUMBER_OF_PART_TYPES); |  | 
| 3302     } |  | 
| 3303     // Either a value of PartType or a non-positive number that is |  | 
| 3304     // the negation of an index into the replacement string. |  | 
| 3305     int tag; |  | 
| 3306     // The data value's interpretation depends on the value of tag: |  | 
| 3307     // tag == SUBJECT_PREFIX || |  | 
| 3308     // tag == SUBJECT_SUFFIX:  data is unused. |  | 
| 3309     // tag == SUBJECT_CAPTURE: data is the number of the capture. |  | 
| 3310     // tag == REPLACEMENT_SUBSTRING || |  | 
| 3311     // tag == REPLACEMENT_STRING:    data is index into array of substrings |  | 
| 3312     //                               of the replacement string. |  | 
| 3313     // tag <= 0: Temporary representation of the substring of the replacement |  | 
| 3314     //           string ranging over -tag .. data. |  | 
| 3315     //           Is replaced by REPLACEMENT_{SUB,}STRING when we create the |  | 
| 3316     //           substring objects. |  | 
| 3317     int data; |  | 
| 3318   }; |  | 
| 3319 |  | 
| 3320   template <typename Char> |  | 
| 3321   bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts, |  | 
| 3322                                Vector<Char> characters, int capture_count, |  | 
| 3323                                int subject_length, Zone* zone) { |  | 
| 3324     int length = characters.length(); |  | 
| 3325     int last = 0; |  | 
| 3326     for (int i = 0; i < length; i++) { |  | 
| 3327       Char c = characters[i]; |  | 
| 3328       if (c == '$') { |  | 
| 3329         int next_index = i + 1; |  | 
| 3330         if (next_index == length) {  // No next character! |  | 
| 3331           break; |  | 
| 3332         } |  | 
| 3333         Char c2 = characters[next_index]; |  | 
| 3334         switch (c2) { |  | 
| 3335           case '$': |  | 
| 3336             if (i > last) { |  | 
| 3337               // There is a substring before. Include the first "$". |  | 
| 3338               parts->Add( |  | 
| 3339                   ReplacementPart::ReplacementSubString(last, next_index), |  | 
| 3340                   zone); |  | 
| 3341               last = next_index + 1;  // Continue after the second "$". |  | 
| 3342             } else { |  | 
| 3343               // Let the next substring start with the second "$". |  | 
| 3344               last = next_index; |  | 
| 3345             } |  | 
| 3346             i = next_index; |  | 
| 3347             break; |  | 
| 3348           case '`': |  | 
| 3349             if (i > last) { |  | 
| 3350               parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); |  | 
| 3351             } |  | 
| 3352             parts->Add(ReplacementPart::SubjectPrefix(), zone); |  | 
| 3353             i = next_index; |  | 
| 3354             last = i + 1; |  | 
| 3355             break; |  | 
| 3356           case '\'': |  | 
| 3357             if (i > last) { |  | 
| 3358               parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); |  | 
| 3359             } |  | 
| 3360             parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone); |  | 
| 3361             i = next_index; |  | 
| 3362             last = i + 1; |  | 
| 3363             break; |  | 
| 3364           case '&': |  | 
| 3365             if (i > last) { |  | 
| 3366               parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); |  | 
| 3367             } |  | 
| 3368             parts->Add(ReplacementPart::SubjectMatch(), zone); |  | 
| 3369             i = next_index; |  | 
| 3370             last = i + 1; |  | 
| 3371             break; |  | 
| 3372           case '0': |  | 
| 3373           case '1': |  | 
| 3374           case '2': |  | 
| 3375           case '3': |  | 
| 3376           case '4': |  | 
| 3377           case '5': |  | 
| 3378           case '6': |  | 
| 3379           case '7': |  | 
| 3380           case '8': |  | 
| 3381           case '9': { |  | 
| 3382             int capture_ref = c2 - '0'; |  | 
| 3383             if (capture_ref > capture_count) { |  | 
| 3384               i = next_index; |  | 
| 3385               continue; |  | 
| 3386             } |  | 
| 3387             int second_digit_index = next_index + 1; |  | 
| 3388             if (second_digit_index < length) { |  | 
| 3389               // Peek ahead to see if we have two digits. |  | 
| 3390               Char c3 = characters[second_digit_index]; |  | 
| 3391               if ('0' <= c3 && c3 <= '9') {  // Double digits. |  | 
| 3392                 int double_digit_ref = capture_ref * 10 + c3 - '0'; |  | 
| 3393                 if (double_digit_ref <= capture_count) { |  | 
| 3394                   next_index = second_digit_index; |  | 
| 3395                   capture_ref = double_digit_ref; |  | 
| 3396                 } |  | 
| 3397               } |  | 
| 3398             } |  | 
| 3399             if (capture_ref > 0) { |  | 
| 3400               if (i > last) { |  | 
| 3401                 parts->Add(ReplacementPart::ReplacementSubString(last, i), |  | 
| 3402                            zone); |  | 
| 3403               } |  | 
| 3404               DCHECK(capture_ref <= capture_count); |  | 
| 3405               parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone); |  | 
| 3406               last = next_index + 1; |  | 
| 3407             } |  | 
| 3408             i = next_index; |  | 
| 3409             break; |  | 
| 3410           } |  | 
| 3411           default: |  | 
| 3412             i = next_index; |  | 
| 3413             break; |  | 
| 3414         } |  | 
| 3415       } |  | 
| 3416     } |  | 
| 3417     if (length > last) { |  | 
| 3418       if (last == 0) { |  | 
| 3419         // Replacement is simple.  Do not use Apply to do the replacement. |  | 
| 3420         return true; |  | 
| 3421       } else { |  | 
| 3422         parts->Add(ReplacementPart::ReplacementSubString(last, length), zone); |  | 
| 3423       } |  | 
| 3424     } |  | 
| 3425     return false; |  | 
| 3426   } |  | 
| 3427 |  | 
| 3428   ZoneList<ReplacementPart> parts_; |  | 
| 3429   ZoneList<Handle<String> > replacement_substrings_; |  | 
| 3430   Zone* zone_; |  | 
| 3431 }; |  | 
| 3432 |  | 
| 3433 |  | 
| 3434 bool CompiledReplacement::Compile(Handle<String> replacement, int capture_count, |  | 
| 3435                                   int subject_length) { |  | 
| 3436   { |  | 
| 3437     DisallowHeapAllocation no_gc; |  | 
| 3438     String::FlatContent content = replacement->GetFlatContent(); |  | 
| 3439     DCHECK(content.IsFlat()); |  | 
| 3440     bool simple = false; |  | 
| 3441     if (content.IsOneByte()) { |  | 
| 3442       simple = ParseReplacementPattern(&parts_, content.ToOneByteVector(), |  | 
| 3443                                        capture_count, subject_length, zone()); |  | 
| 3444     } else { |  | 
| 3445       DCHECK(content.IsTwoByte()); |  | 
| 3446       simple = ParseReplacementPattern(&parts_, content.ToUC16Vector(), |  | 
| 3447                                        capture_count, subject_length, zone()); |  | 
| 3448     } |  | 
| 3449     if (simple) return true; |  | 
| 3450   } |  | 
| 3451 |  | 
| 3452   Isolate* isolate = replacement->GetIsolate(); |  | 
| 3453   // Find substrings of replacement string and create them as String objects. |  | 
| 3454   int substring_index = 0; |  | 
| 3455   for (int i = 0, n = parts_.length(); i < n; i++) { |  | 
| 3456     int tag = parts_[i].tag; |  | 
| 3457     if (tag <= 0) {  // A replacement string slice. |  | 
| 3458       int from = -tag; |  | 
| 3459       int to = parts_[i].data; |  | 
| 3460       replacement_substrings_.Add( |  | 
| 3461           isolate->factory()->NewSubString(replacement, from, to), zone()); |  | 
| 3462       parts_[i].tag = REPLACEMENT_SUBSTRING; |  | 
| 3463       parts_[i].data = substring_index; |  | 
| 3464       substring_index++; |  | 
| 3465     } else if (tag == REPLACEMENT_STRING) { |  | 
| 3466       replacement_substrings_.Add(replacement, zone()); |  | 
| 3467       parts_[i].data = substring_index; |  | 
| 3468       substring_index++; |  | 
| 3469     } |  | 
| 3470   } |  | 
| 3471   return false; |  | 
| 3472 } |  | 
| 3473 |  | 
| 3474 |  | 
| 3475 void CompiledReplacement::Apply(ReplacementStringBuilder* builder, |  | 
| 3476                                 int match_from, int match_to, int32_t* match) { |  | 
| 3477   DCHECK_LT(0, parts_.length()); |  | 
| 3478   for (int i = 0, n = parts_.length(); i < n; i++) { |  | 
| 3479     ReplacementPart part = parts_[i]; |  | 
| 3480     switch (part.tag) { |  | 
| 3481       case SUBJECT_PREFIX: |  | 
| 3482         if (match_from > 0) builder->AddSubjectSlice(0, match_from); |  | 
| 3483         break; |  | 
| 3484       case SUBJECT_SUFFIX: { |  | 
| 3485         int subject_length = part.data; |  | 
| 3486         if (match_to < subject_length) { |  | 
| 3487           builder->AddSubjectSlice(match_to, subject_length); |  | 
| 3488         } |  | 
| 3489         break; |  | 
| 3490       } |  | 
| 3491       case SUBJECT_CAPTURE: { |  | 
| 3492         int capture = part.data; |  | 
| 3493         int from = match[capture * 2]; |  | 
| 3494         int to = match[capture * 2 + 1]; |  | 
| 3495         if (from >= 0 && to > from) { |  | 
| 3496           builder->AddSubjectSlice(from, to); |  | 
| 3497         } |  | 
| 3498         break; |  | 
| 3499       } |  | 
| 3500       case REPLACEMENT_SUBSTRING: |  | 
| 3501       case REPLACEMENT_STRING: |  | 
| 3502         builder->AddString(replacement_substrings_[part.data]); |  | 
| 3503         break; |  | 
| 3504       default: |  | 
| 3505         UNREACHABLE(); |  | 
| 3506     } |  | 
| 3507   } |  | 
| 3508 } |  | 
| 3509 |  | 
| 3510 |  | 
| 3511 void FindOneByteStringIndices(Vector<const uint8_t> subject, char pattern, |  | 
| 3512                               ZoneList<int>* indices, unsigned int limit, |  | 
| 3513                               Zone* zone) { |  | 
| 3514   DCHECK(limit > 0); |  | 
| 3515   // Collect indices of pattern in subject using memchr. |  | 
| 3516   // Stop after finding at most limit values. |  | 
| 3517   const uint8_t* subject_start = subject.start(); |  | 
| 3518   const uint8_t* subject_end = subject_start + subject.length(); |  | 
| 3519   const uint8_t* pos = subject_start; |  | 
| 3520   while (limit > 0) { |  | 
| 3521     pos = reinterpret_cast<const uint8_t*>( |  | 
| 3522         memchr(pos, pattern, subject_end - pos)); |  | 
| 3523     if (pos == NULL) return; |  | 
| 3524     indices->Add(static_cast<int>(pos - subject_start), zone); |  | 
| 3525     pos++; |  | 
| 3526     limit--; |  | 
| 3527   } |  | 
| 3528 } |  | 
| 3529 |  | 
| 3530 |  | 
| 3531 void FindTwoByteStringIndices(const Vector<const uc16> subject, uc16 pattern, |  | 
| 3532                               ZoneList<int>* indices, unsigned int limit, |  | 
| 3533                               Zone* zone) { |  | 
| 3534   DCHECK(limit > 0); |  | 
| 3535   const uc16* subject_start = subject.start(); |  | 
| 3536   const uc16* subject_end = subject_start + subject.length(); |  | 
| 3537   for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) { |  | 
| 3538     if (*pos == pattern) { |  | 
| 3539       indices->Add(static_cast<int>(pos - subject_start), zone); |  | 
| 3540       limit--; |  | 
| 3541     } |  | 
| 3542   } |  | 
| 3543 } |  | 
| 3544 |  | 
| 3545 |  | 
| 3546 template <typename SubjectChar, typename PatternChar> |  | 
| 3547 void FindStringIndices(Isolate* isolate, Vector<const SubjectChar> subject, |  | 
| 3548                        Vector<const PatternChar> pattern, |  | 
| 3549                        ZoneList<int>* indices, unsigned int limit, Zone* zone) { |  | 
| 3550   DCHECK(limit > 0); |  | 
| 3551   // Collect indices of pattern in subject. |  | 
| 3552   // Stop after finding at most limit values. |  | 
| 3553   int pattern_length = pattern.length(); |  | 
| 3554   int index = 0; |  | 
| 3555   StringSearch<PatternChar, SubjectChar> search(isolate, pattern); |  | 
| 3556   while (limit > 0) { |  | 
| 3557     index = search.Search(subject, index); |  | 
| 3558     if (index < 0) return; |  | 
| 3559     indices->Add(index, zone); |  | 
| 3560     index += pattern_length; |  | 
| 3561     limit--; |  | 
| 3562   } |  | 
| 3563 } |  | 
| 3564 |  | 
| 3565 |  | 
| 3566 void FindStringIndicesDispatch(Isolate* isolate, String* subject, |  | 
| 3567                                String* pattern, ZoneList<int>* indices, |  | 
| 3568                                unsigned int limit, Zone* zone) { |  | 
| 3569   { |  | 
| 3570     DisallowHeapAllocation no_gc; |  | 
| 3571     String::FlatContent subject_content = subject->GetFlatContent(); |  | 
| 3572     String::FlatContent pattern_content = pattern->GetFlatContent(); |  | 
| 3573     DCHECK(subject_content.IsFlat()); |  | 
| 3574     DCHECK(pattern_content.IsFlat()); |  | 
| 3575     if (subject_content.IsOneByte()) { |  | 
| 3576       Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector(); |  | 
| 3577       if (pattern_content.IsOneByte()) { |  | 
| 3578         Vector<const uint8_t> pattern_vector = |  | 
| 3579             pattern_content.ToOneByteVector(); |  | 
| 3580         if (pattern_vector.length() == 1) { |  | 
| 3581           FindOneByteStringIndices(subject_vector, pattern_vector[0], indices, |  | 
| 3582                                    limit, zone); |  | 
| 3583         } else { |  | 
| 3584           FindStringIndices(isolate, subject_vector, pattern_vector, indices, |  | 
| 3585                             limit, zone); |  | 
| 3586         } |  | 
| 3587       } else { |  | 
| 3588         FindStringIndices(isolate, subject_vector, |  | 
| 3589                           pattern_content.ToUC16Vector(), indices, limit, zone); |  | 
| 3590       } |  | 
| 3591     } else { |  | 
| 3592       Vector<const uc16> subject_vector = subject_content.ToUC16Vector(); |  | 
| 3593       if (pattern_content.IsOneByte()) { |  | 
| 3594         Vector<const uint8_t> pattern_vector = |  | 
| 3595             pattern_content.ToOneByteVector(); |  | 
| 3596         if (pattern_vector.length() == 1) { |  | 
| 3597           FindTwoByteStringIndices(subject_vector, pattern_vector[0], indices, |  | 
| 3598                                    limit, zone); |  | 
| 3599         } else { |  | 
| 3600           FindStringIndices(isolate, subject_vector, pattern_vector, indices, |  | 
| 3601                             limit, zone); |  | 
| 3602         } |  | 
| 3603       } else { |  | 
| 3604         Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector(); |  | 
| 3605         if (pattern_vector.length() == 1) { |  | 
| 3606           FindTwoByteStringIndices(subject_vector, pattern_vector[0], indices, |  | 
| 3607                                    limit, zone); |  | 
| 3608         } else { |  | 
| 3609           FindStringIndices(isolate, subject_vector, pattern_vector, indices, |  | 
| 3610                             limit, zone); |  | 
| 3611         } |  | 
| 3612       } |  | 
| 3613     } |  | 
| 3614   } |  | 
| 3615 } |  | 
| 3616 |  | 
| 3617 |  | 
| 3618 template <typename ResultSeqString> |  | 
| 3619 MUST_USE_RESULT static Object* StringReplaceGlobalAtomRegExpWithString( |  | 
| 3620     Isolate* isolate, Handle<String> subject, Handle<JSRegExp> pattern_regexp, |  | 
| 3621     Handle<String> replacement, Handle<JSArray> last_match_info) { |  | 
| 3622   DCHECK(subject->IsFlat()); |  | 
| 3623   DCHECK(replacement->IsFlat()); |  | 
| 3624 |  | 
| 3625   ZoneScope zone_scope(isolate->runtime_zone()); |  | 
| 3626   ZoneList<int> indices(8, zone_scope.zone()); |  | 
| 3627   DCHECK_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag()); |  | 
| 3628   String* pattern = |  | 
| 3629       String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex)); |  | 
| 3630   int subject_len = subject->length(); |  | 
| 3631   int pattern_len = pattern->length(); |  | 
| 3632   int replacement_len = replacement->length(); |  | 
| 3633 |  | 
| 3634   FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff, |  | 
| 3635                             zone_scope.zone()); |  | 
| 3636 |  | 
| 3637   int matches = indices.length(); |  | 
| 3638   if (matches == 0) return *subject; |  | 
| 3639 |  | 
| 3640   // Detect integer overflow. |  | 
| 3641   int64_t result_len_64 = (static_cast<int64_t>(replacement_len) - |  | 
| 3642                            static_cast<int64_t>(pattern_len)) * |  | 
| 3643                               static_cast<int64_t>(matches) + |  | 
| 3644                           static_cast<int64_t>(subject_len); |  | 
| 3645   int result_len; |  | 
| 3646   if (result_len_64 > static_cast<int64_t>(String::kMaxLength)) { |  | 
| 3647     STATIC_ASSERT(String::kMaxLength < kMaxInt); |  | 
| 3648     result_len = kMaxInt;  // Provoke exception. |  | 
| 3649   } else { |  | 
| 3650     result_len = static_cast<int>(result_len_64); |  | 
| 3651   } |  | 
| 3652 |  | 
| 3653   int subject_pos = 0; |  | 
| 3654   int result_pos = 0; |  | 
| 3655 |  | 
| 3656   MaybeHandle<SeqString> maybe_res; |  | 
| 3657   if (ResultSeqString::kHasOneByteEncoding) { |  | 
| 3658     maybe_res = isolate->factory()->NewRawOneByteString(result_len); |  | 
| 3659   } else { |  | 
| 3660     maybe_res = isolate->factory()->NewRawTwoByteString(result_len); |  | 
| 3661   } |  | 
| 3662   Handle<SeqString> untyped_res; |  | 
| 3663   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, untyped_res, maybe_res); |  | 
| 3664   Handle<ResultSeqString> result = Handle<ResultSeqString>::cast(untyped_res); |  | 
| 3665 |  | 
| 3666   for (int i = 0; i < matches; i++) { |  | 
| 3667     // Copy non-matched subject content. |  | 
| 3668     if (subject_pos < indices.at(i)) { |  | 
| 3669       String::WriteToFlat(*subject, result->GetChars() + result_pos, |  | 
| 3670                           subject_pos, indices.at(i)); |  | 
| 3671       result_pos += indices.at(i) - subject_pos; |  | 
| 3672     } |  | 
| 3673 |  | 
| 3674     // Replace match. |  | 
| 3675     if (replacement_len > 0) { |  | 
| 3676       String::WriteToFlat(*replacement, result->GetChars() + result_pos, 0, |  | 
| 3677                           replacement_len); |  | 
| 3678       result_pos += replacement_len; |  | 
| 3679     } |  | 
| 3680 |  | 
| 3681     subject_pos = indices.at(i) + pattern_len; |  | 
| 3682   } |  | 
| 3683   // Add remaining subject content at the end. |  | 
| 3684   if (subject_pos < subject_len) { |  | 
| 3685     String::WriteToFlat(*subject, result->GetChars() + result_pos, subject_pos, |  | 
| 3686                         subject_len); |  | 
| 3687   } |  | 
| 3688 |  | 
| 3689   int32_t match_indices[] = {indices.at(matches - 1), |  | 
| 3690                              indices.at(matches - 1) + pattern_len}; |  | 
| 3691   RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices); |  | 
| 3692 |  | 
| 3693   return *result; |  | 
| 3694 } |  | 
| 3695 |  | 
| 3696 |  | 
| 3697 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString( |  | 
| 3698     Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, |  | 
| 3699     Handle<String> replacement, Handle<JSArray> last_match_info) { |  | 
| 3700   DCHECK(subject->IsFlat()); |  | 
| 3701   DCHECK(replacement->IsFlat()); |  | 
| 3702 |  | 
| 3703   int capture_count = regexp->CaptureCount(); |  | 
| 3704   int subject_length = subject->length(); |  | 
| 3705 |  | 
| 3706   // CompiledReplacement uses zone allocation. |  | 
| 3707   ZoneScope zone_scope(isolate->runtime_zone()); |  | 
| 3708   CompiledReplacement compiled_replacement(zone_scope.zone()); |  | 
| 3709   bool simple_replace = |  | 
| 3710       compiled_replacement.Compile(replacement, capture_count, subject_length); |  | 
| 3711 |  | 
| 3712   // Shortcut for simple non-regexp global replacements |  | 
| 3713   if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) { |  | 
| 3714     if (subject->HasOnlyOneByteChars() && replacement->HasOnlyOneByteChars()) { |  | 
| 3715       return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( |  | 
| 3716           isolate, subject, regexp, replacement, last_match_info); |  | 
| 3717     } else { |  | 
| 3718       return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( |  | 
| 3719           isolate, subject, regexp, replacement, last_match_info); |  | 
| 3720     } |  | 
| 3721   } |  | 
| 3722 |  | 
| 3723   RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); |  | 
| 3724   if (global_cache.HasException()) return isolate->heap()->exception(); |  | 
| 3725 |  | 
| 3726   int32_t* current_match = global_cache.FetchNext(); |  | 
| 3727   if (current_match == NULL) { |  | 
| 3728     if (global_cache.HasException()) return isolate->heap()->exception(); |  | 
| 3729     return *subject; |  | 
| 3730   } |  | 
| 3731 |  | 
| 3732   // Guessing the number of parts that the final result string is built |  | 
| 3733   // from. Global regexps can match any number of times, so we guess |  | 
| 3734   // conservatively. |  | 
| 3735   int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1; |  | 
| 3736   ReplacementStringBuilder builder(isolate->heap(), subject, expected_parts); |  | 
| 3737 |  | 
| 3738   // Number of parts added by compiled replacement plus preceeding |  | 
| 3739   // string and possibly suffix after last match.  It is possible for |  | 
| 3740   // all components to use two elements when encoded as two smis. |  | 
| 3741   const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2); |  | 
| 3742 |  | 
| 3743   int prev = 0; |  | 
| 3744 |  | 
| 3745   do { |  | 
| 3746     builder.EnsureCapacity(parts_added_per_loop); |  | 
| 3747 |  | 
| 3748     int start = current_match[0]; |  | 
| 3749     int end = current_match[1]; |  | 
| 3750 |  | 
| 3751     if (prev < start) { |  | 
| 3752       builder.AddSubjectSlice(prev, start); |  | 
| 3753     } |  | 
| 3754 |  | 
| 3755     if (simple_replace) { |  | 
| 3756       builder.AddString(replacement); |  | 
| 3757     } else { |  | 
| 3758       compiled_replacement.Apply(&builder, start, end, current_match); |  | 
| 3759     } |  | 
| 3760     prev = end; |  | 
| 3761 |  | 
| 3762     current_match = global_cache.FetchNext(); |  | 
| 3763   } while (current_match != NULL); |  | 
| 3764 |  | 
| 3765   if (global_cache.HasException()) return isolate->heap()->exception(); |  | 
| 3766 |  | 
| 3767   if (prev < subject_length) { |  | 
| 3768     builder.EnsureCapacity(2); |  | 
| 3769     builder.AddSubjectSlice(prev, subject_length); |  | 
| 3770   } |  | 
| 3771 |  | 
| 3772   RegExpImpl::SetLastMatchInfo(last_match_info, subject, capture_count, |  | 
| 3773                                global_cache.LastSuccessfulMatch()); |  | 
| 3774 |  | 
| 3775   Handle<String> result; |  | 
| 3776   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, builder.ToString()); |  | 
| 3777   return *result; |  | 
| 3778 } |  | 
| 3779 |  | 
| 3780 |  | 
| 3781 template <typename ResultSeqString> |  | 
| 3782 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString( |  | 
| 3783     Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, |  | 
| 3784     Handle<JSArray> last_match_info) { |  | 
| 3785   DCHECK(subject->IsFlat()); |  | 
| 3786 |  | 
| 3787   // Shortcut for simple non-regexp global replacements |  | 
| 3788   if (regexp->TypeTag() == JSRegExp::ATOM) { |  | 
| 3789     Handle<String> empty_string = isolate->factory()->empty_string(); |  | 
| 3790     if (subject->IsOneByteRepresentation()) { |  | 
| 3791       return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( |  | 
| 3792           isolate, subject, regexp, empty_string, last_match_info); |  | 
| 3793     } else { |  | 
| 3794       return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( |  | 
| 3795           isolate, subject, regexp, empty_string, last_match_info); |  | 
| 3796     } |  | 
| 3797   } |  | 
| 3798 |  | 
| 3799   RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); |  | 
| 3800   if (global_cache.HasException()) return isolate->heap()->exception(); |  | 
| 3801 |  | 
| 3802   int32_t* current_match = global_cache.FetchNext(); |  | 
| 3803   if (current_match == NULL) { |  | 
| 3804     if (global_cache.HasException()) return isolate->heap()->exception(); |  | 
| 3805     return *subject; |  | 
| 3806   } |  | 
| 3807 |  | 
| 3808   int start = current_match[0]; |  | 
| 3809   int end = current_match[1]; |  | 
| 3810   int capture_count = regexp->CaptureCount(); |  | 
| 3811   int subject_length = subject->length(); |  | 
| 3812 |  | 
| 3813   int new_length = subject_length - (end - start); |  | 
| 3814   if (new_length == 0) return isolate->heap()->empty_string(); |  | 
| 3815 |  | 
| 3816   Handle<ResultSeqString> answer; |  | 
| 3817   if (ResultSeqString::kHasOneByteEncoding) { |  | 
| 3818     answer = Handle<ResultSeqString>::cast( |  | 
| 3819         isolate->factory()->NewRawOneByteString(new_length).ToHandleChecked()); |  | 
| 3820   } else { |  | 
| 3821     answer = Handle<ResultSeqString>::cast( |  | 
| 3822         isolate->factory()->NewRawTwoByteString(new_length).ToHandleChecked()); |  | 
| 3823   } |  | 
| 3824 |  | 
| 3825   int prev = 0; |  | 
| 3826   int position = 0; |  | 
| 3827 |  | 
| 3828   do { |  | 
| 3829     start = current_match[0]; |  | 
| 3830     end = current_match[1]; |  | 
| 3831     if (prev < start) { |  | 
| 3832       // Add substring subject[prev;start] to answer string. |  | 
| 3833       String::WriteToFlat(*subject, answer->GetChars() + position, prev, start); |  | 
| 3834       position += start - prev; |  | 
| 3835     } |  | 
| 3836     prev = end; |  | 
| 3837 |  | 
| 3838     current_match = global_cache.FetchNext(); |  | 
| 3839   } while (current_match != NULL); |  | 
| 3840 |  | 
| 3841   if (global_cache.HasException()) return isolate->heap()->exception(); |  | 
| 3842 |  | 
| 3843   RegExpImpl::SetLastMatchInfo(last_match_info, subject, capture_count, |  | 
| 3844                                global_cache.LastSuccessfulMatch()); |  | 
| 3845 |  | 
| 3846   if (prev < subject_length) { |  | 
| 3847     // Add substring subject[prev;length] to answer string. |  | 
| 3848     String::WriteToFlat(*subject, answer->GetChars() + position, prev, |  | 
| 3849                         subject_length); |  | 
| 3850     position += subject_length - prev; |  | 
| 3851   } |  | 
| 3852 |  | 
| 3853   if (position == 0) return isolate->heap()->empty_string(); |  | 
| 3854 |  | 
| 3855   // Shorten string and fill |  | 
| 3856   int string_size = ResultSeqString::SizeFor(position); |  | 
| 3857   int allocated_string_size = ResultSeqString::SizeFor(new_length); |  | 
| 3858   int delta = allocated_string_size - string_size; |  | 
| 3859 |  | 
| 3860   answer->set_length(position); |  | 
| 3861   if (delta == 0) return *answer; |  | 
| 3862 |  | 
| 3863   Address end_of_string = answer->address() + string_size; |  | 
| 3864   Heap* heap = isolate->heap(); |  | 
| 3865 |  | 
| 3866   // The trimming is performed on a newly allocated object, which is on a |  | 
| 3867   // fresly allocated page or on an already swept page. Hence, the sweeper |  | 
| 3868   // thread can not get confused with the filler creation. No synchronization |  | 
| 3869   // needed. |  | 
| 3870   heap->CreateFillerObjectAt(end_of_string, delta); |  | 
| 3871   heap->AdjustLiveBytes(answer->address(), -delta, Heap::FROM_MUTATOR); |  | 
| 3872   return *answer; |  | 
| 3873 } |  | 
| 3874 |  | 
| 3875 |  | 
| 3876 RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) { |  | 
| 3877   HandleScope scope(isolate); |  | 
| 3878   DCHECK(args.length() == 4); |  | 
| 3879 |  | 
| 3880   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); |  | 
| 3881   CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); |  | 
| 3882   CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); |  | 
| 3883   CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); |  | 
| 3884 |  | 
| 3885   RUNTIME_ASSERT(regexp->GetFlags().is_global()); |  | 
| 3886   RUNTIME_ASSERT(last_match_info->HasFastObjectElements()); |  | 
| 3887 |  | 
| 3888   subject = String::Flatten(subject); |  | 
| 3889 |  | 
| 3890   if (replacement->length() == 0) { |  | 
| 3891     if (subject->HasOnlyOneByteChars()) { |  | 
| 3892       return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>( |  | 
| 3893           isolate, subject, regexp, last_match_info); |  | 
| 3894     } else { |  | 
| 3895       return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>( |  | 
| 3896           isolate, subject, regexp, last_match_info); |  | 
| 3897     } |  | 
| 3898   } |  | 
| 3899 |  | 
| 3900   replacement = String::Flatten(replacement); |  | 
| 3901 |  | 
| 3902   return StringReplaceGlobalRegExpWithString(isolate, subject, regexp, |  | 
| 3903                                              replacement, last_match_info); |  | 
| 3904 } |  | 
| 3905 |  | 
| 3906 |  | 
| 3907 // This may return an empty MaybeHandle if an exception is thrown or |  | 
| 3908 // we abort due to reaching the recursion limit. |  | 
| 3909 MaybeHandle<String> StringReplaceOneCharWithString( |  | 
| 3910     Isolate* isolate, Handle<String> subject, Handle<String> search, |  | 
| 3911     Handle<String> replace, bool* found, int recursion_limit) { |  | 
| 3912   StackLimitCheck stackLimitCheck(isolate); |  | 
| 3913   if (stackLimitCheck.HasOverflowed() || (recursion_limit == 0)) { |  | 
| 3914     return MaybeHandle<String>(); |  | 
| 3915   } |  | 
| 3916   recursion_limit--; |  | 
| 3917   if (subject->IsConsString()) { |  | 
| 3918     ConsString* cons = ConsString::cast(*subject); |  | 
| 3919     Handle<String> first = Handle<String>(cons->first()); |  | 
| 3920     Handle<String> second = Handle<String>(cons->second()); |  | 
| 3921     Handle<String> new_first; |  | 
| 3922     if (!StringReplaceOneCharWithString(isolate, first, search, replace, found, |  | 
| 3923                                         recursion_limit).ToHandle(&new_first)) { |  | 
| 3924       return MaybeHandle<String>(); |  | 
| 3925     } |  | 
| 3926     if (*found) return isolate->factory()->NewConsString(new_first, second); |  | 
| 3927 |  | 
| 3928     Handle<String> new_second; |  | 
| 3929     if (!StringReplaceOneCharWithString(isolate, second, search, replace, found, |  | 
| 3930                                         recursion_limit) |  | 
| 3931              .ToHandle(&new_second)) { |  | 
| 3932       return MaybeHandle<String>(); |  | 
| 3933     } |  | 
| 3934     if (*found) return isolate->factory()->NewConsString(first, new_second); |  | 
| 3935 |  | 
| 3936     return subject; |  | 
| 3937   } else { |  | 
| 3938     int index = Runtime::StringMatch(isolate, subject, search, 0); |  | 
| 3939     if (index == -1) return subject; |  | 
| 3940     *found = true; |  | 
| 3941     Handle<String> first = isolate->factory()->NewSubString(subject, 0, index); |  | 
| 3942     Handle<String> cons1; |  | 
| 3943     ASSIGN_RETURN_ON_EXCEPTION( |  | 
| 3944         isolate, cons1, isolate->factory()->NewConsString(first, replace), |  | 
| 3945         String); |  | 
| 3946     Handle<String> second = |  | 
| 3947         isolate->factory()->NewSubString(subject, index + 1, subject->length()); |  | 
| 3948     return isolate->factory()->NewConsString(cons1, second); |  | 
| 3949   } |  | 
| 3950 } |  | 
| 3951 |  | 
| 3952 |  | 
| 3953 RUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) { |  | 
| 3954   HandleScope scope(isolate); |  | 
| 3955   DCHECK(args.length() == 3); |  | 
| 3956   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); |  | 
| 3957   CONVERT_ARG_HANDLE_CHECKED(String, search, 1); |  | 
| 3958   CONVERT_ARG_HANDLE_CHECKED(String, replace, 2); |  | 
| 3959 |  | 
| 3960   // If the cons string tree is too deep, we simply abort the recursion and |  | 
| 3961   // retry with a flattened subject string. |  | 
| 3962   const int kRecursionLimit = 0x1000; |  | 
| 3963   bool found = false; |  | 
| 3964   Handle<String> result; |  | 
| 3965   if (StringReplaceOneCharWithString(isolate, subject, search, replace, &found, |  | 
| 3966                                      kRecursionLimit).ToHandle(&result)) { |  | 
| 3967     return *result; |  | 
| 3968   } |  | 
| 3969   if (isolate->has_pending_exception()) return isolate->heap()->exception(); |  | 
| 3970 |  | 
| 3971   subject = String::Flatten(subject); |  | 
| 3972   ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 3973       isolate, result, |  | 
| 3974       StringReplaceOneCharWithString(isolate, subject, search, replace, &found, |  | 
| 3975                                      kRecursionLimit)); |  | 
| 3976   return *result; |  | 
| 3977 } |  | 
| 3978 |  | 
| 3979 |  | 
| 3980 // Perform string match of pattern on subject, starting at start index. |  | 
| 3981 // Caller must ensure that 0 <= start_index <= sub->length(), |  | 
| 3982 // and should check that pat->length() + start_index <= sub->length(). |  | 
| 3983 int Runtime::StringMatch(Isolate* isolate, Handle<String> sub, |  | 
| 3984                          Handle<String> pat, int start_index) { |  | 
| 3985   DCHECK(0 <= start_index); |  | 
| 3986   DCHECK(start_index <= sub->length()); |  | 
| 3987 |  | 
| 3988   int pattern_length = pat->length(); |  | 
| 3989   if (pattern_length == 0) return start_index; |  | 
| 3990 |  | 
| 3991   int subject_length = sub->length(); |  | 
| 3992   if (start_index + pattern_length > subject_length) return -1; |  | 
| 3993 |  | 
| 3994   sub = String::Flatten(sub); |  | 
| 3995   pat = String::Flatten(pat); |  | 
| 3996 |  | 
| 3997   DisallowHeapAllocation no_gc;  // ensure vectors stay valid |  | 
| 3998   // Extract flattened substrings of cons strings before getting encoding. |  | 
| 3999   String::FlatContent seq_sub = sub->GetFlatContent(); |  | 
| 4000   String::FlatContent seq_pat = pat->GetFlatContent(); |  | 
| 4001 |  | 
| 4002   // dispatch on type of strings |  | 
| 4003   if (seq_pat.IsOneByte()) { |  | 
| 4004     Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector(); |  | 
| 4005     if (seq_sub.IsOneByte()) { |  | 
| 4006       return SearchString(isolate, seq_sub.ToOneByteVector(), pat_vector, |  | 
| 4007                           start_index); |  | 
| 4008     } |  | 
| 4009     return SearchString(isolate, seq_sub.ToUC16Vector(), pat_vector, |  | 
| 4010                         start_index); |  | 
| 4011   } |  | 
| 4012   Vector<const uc16> pat_vector = seq_pat.ToUC16Vector(); |  | 
| 4013   if (seq_sub.IsOneByte()) { |  | 
| 4014     return SearchString(isolate, seq_sub.ToOneByteVector(), pat_vector, |  | 
| 4015                         start_index); |  | 
| 4016   } |  | 
| 4017   return SearchString(isolate, seq_sub.ToUC16Vector(), pat_vector, start_index); |  | 
| 4018 } |  | 
| 4019 |  | 
| 4020 |  | 
| 4021 RUNTIME_FUNCTION(Runtime_StringIndexOf) { |  | 
| 4022   HandleScope scope(isolate); |  | 
| 4023   DCHECK(args.length() == 3); |  | 
| 4024 |  | 
| 4025   CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); |  | 
| 4026   CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); |  | 
| 4027   CONVERT_ARG_HANDLE_CHECKED(Object, index, 2); |  | 
| 4028 |  | 
| 4029   uint32_t start_index; |  | 
| 4030   if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); |  | 
| 4031 |  | 
| 4032   RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length())); |  | 
| 4033   int position = Runtime::StringMatch(isolate, sub, pat, start_index); |  | 
| 4034   return Smi::FromInt(position); |  | 
| 4035 } |  | 
| 4036 |  | 
| 4037 |  | 
| 4038 template <typename schar, typename pchar> |  | 
| 4039 static int StringMatchBackwards(Vector<const schar> subject, |  | 
| 4040                                 Vector<const pchar> pattern, int idx) { |  | 
| 4041   int pattern_length = pattern.length(); |  | 
| 4042   DCHECK(pattern_length >= 1); |  | 
| 4043   DCHECK(idx + pattern_length <= subject.length()); |  | 
| 4044 |  | 
| 4045   if (sizeof(schar) == 1 && sizeof(pchar) > 1) { |  | 
| 4046     for (int i = 0; i < pattern_length; i++) { |  | 
| 4047       uc16 c = pattern[i]; |  | 
| 4048       if (c > String::kMaxOneByteCharCode) { |  | 
| 4049         return -1; |  | 
| 4050       } |  | 
| 4051     } |  | 
| 4052   } |  | 
| 4053 |  | 
| 4054   pchar pattern_first_char = pattern[0]; |  | 
| 4055   for (int i = idx; i >= 0; i--) { |  | 
| 4056     if (subject[i] != pattern_first_char) continue; |  | 
| 4057     int j = 1; |  | 
| 4058     while (j < pattern_length) { |  | 
| 4059       if (pattern[j] != subject[i + j]) { |  | 
| 4060         break; |  | 
| 4061       } |  | 
| 4062       j++; |  | 
| 4063     } |  | 
| 4064     if (j == pattern_length) { |  | 
| 4065       return i; |  | 
| 4066     } |  | 
| 4067   } |  | 
| 4068   return -1; |  | 
| 4069 } |  | 
| 4070 |  | 
| 4071 |  | 
| 4072 RUNTIME_FUNCTION(Runtime_StringLastIndexOf) { |  | 
| 4073   HandleScope scope(isolate); |  | 
| 4074   DCHECK(args.length() == 3); |  | 
| 4075 |  | 
| 4076   CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); |  | 
| 4077   CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); |  | 
| 4078   CONVERT_ARG_HANDLE_CHECKED(Object, index, 2); |  | 
| 4079 |  | 
| 4080   uint32_t start_index; |  | 
| 4081   if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); |  | 
| 4082 |  | 
| 4083   uint32_t pat_length = pat->length(); |  | 
| 4084   uint32_t sub_length = sub->length(); |  | 
| 4085 |  | 
| 4086   if (start_index + pat_length > sub_length) { |  | 
| 4087     start_index = sub_length - pat_length; |  | 
| 4088   } |  | 
| 4089 |  | 
| 4090   if (pat_length == 0) { |  | 
| 4091     return Smi::FromInt(start_index); |  | 
| 4092   } |  | 
| 4093 |  | 
| 4094   sub = String::Flatten(sub); |  | 
| 4095   pat = String::Flatten(pat); |  | 
| 4096 |  | 
| 4097   int position = -1; |  | 
| 4098   DisallowHeapAllocation no_gc;  // ensure vectors stay valid |  | 
| 4099 |  | 
| 4100   String::FlatContent sub_content = sub->GetFlatContent(); |  | 
| 4101   String::FlatContent pat_content = pat->GetFlatContent(); |  | 
| 4102 |  | 
| 4103   if (pat_content.IsOneByte()) { |  | 
| 4104     Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector(); |  | 
| 4105     if (sub_content.IsOneByte()) { |  | 
| 4106       position = StringMatchBackwards(sub_content.ToOneByteVector(), pat_vector, |  | 
| 4107                                       start_index); |  | 
| 4108     } else { |  | 
| 4109       position = StringMatchBackwards(sub_content.ToUC16Vector(), pat_vector, |  | 
| 4110                                       start_index); |  | 
| 4111     } |  | 
| 4112   } else { |  | 
| 4113     Vector<const uc16> pat_vector = pat_content.ToUC16Vector(); |  | 
| 4114     if (sub_content.IsOneByte()) { |  | 
| 4115       position = StringMatchBackwards(sub_content.ToOneByteVector(), pat_vector, |  | 
| 4116                                       start_index); |  | 
| 4117     } else { |  | 
| 4118       position = StringMatchBackwards(sub_content.ToUC16Vector(), pat_vector, |  | 
| 4119                                       start_index); |  | 
| 4120     } |  | 
| 4121   } |  | 
| 4122 |  | 
| 4123   return Smi::FromInt(position); |  | 
| 4124 } |  | 
| 4125 |  | 
| 4126 |  | 
| 4127 RUNTIME_FUNCTION(Runtime_StringLocaleCompare) { |  | 
| 4128   HandleScope handle_scope(isolate); |  | 
| 4129   DCHECK(args.length() == 2); |  | 
| 4130 |  | 
| 4131   CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); |  | 
| 4132   CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); |  | 
| 4133 |  | 
| 4134   if (str1.is_identical_to(str2)) return Smi::FromInt(0);  // Equal. |  | 
| 4135   int str1_length = str1->length(); |  | 
| 4136   int str2_length = str2->length(); |  | 
| 4137 |  | 
| 4138   // Decide trivial cases without flattening. |  | 
| 4139   if (str1_length == 0) { |  | 
| 4140     if (str2_length == 0) return Smi::FromInt(0);  // Equal. |  | 
| 4141     return Smi::FromInt(-str2_length); |  | 
| 4142   } else { |  | 
| 4143     if (str2_length == 0) return Smi::FromInt(str1_length); |  | 
| 4144   } |  | 
| 4145 |  | 
| 4146   int end = str1_length < str2_length ? str1_length : str2_length; |  | 
| 4147 |  | 
| 4148   // No need to flatten if we are going to find the answer on the first |  | 
| 4149   // character.  At this point we know there is at least one character |  | 
| 4150   // in each string, due to the trivial case handling above. |  | 
| 4151   int d = str1->Get(0) - str2->Get(0); |  | 
| 4152   if (d != 0) return Smi::FromInt(d); |  | 
| 4153 |  | 
| 4154   str1 = String::Flatten(str1); |  | 
| 4155   str2 = String::Flatten(str2); |  | 
| 4156 |  | 
| 4157   DisallowHeapAllocation no_gc; |  | 
| 4158   String::FlatContent flat1 = str1->GetFlatContent(); |  | 
| 4159   String::FlatContent flat2 = str2->GetFlatContent(); |  | 
| 4160 |  | 
| 4161   for (int i = 0; i < end; i++) { |  | 
| 4162     if (flat1.Get(i) != flat2.Get(i)) { |  | 
| 4163       return Smi::FromInt(flat1.Get(i) - flat2.Get(i)); |  | 
| 4164     } |  | 
| 4165   } |  | 
| 4166 |  | 
| 4167   return Smi::FromInt(str1_length - str2_length); |  | 
| 4168 } |  | 
| 4169 |  | 
| 4170 |  | 
| 4171 RUNTIME_FUNCTION(Runtime_SubString) { |  | 
| 4172   HandleScope scope(isolate); |  | 
| 4173   DCHECK(args.length() == 3); |  | 
| 4174 |  | 
| 4175   CONVERT_ARG_HANDLE_CHECKED(String, string, 0); |  | 
| 4176   int start, end; |  | 
| 4177   // We have a fast integer-only case here to avoid a conversion to double in |  | 
| 4178   // the common case where from and to are Smis. |  | 
| 4179   if (args[1]->IsSmi() && args[2]->IsSmi()) { |  | 
| 4180     CONVERT_SMI_ARG_CHECKED(from_number, 1); |  | 
| 4181     CONVERT_SMI_ARG_CHECKED(to_number, 2); |  | 
| 4182     start = from_number; |  | 
| 4183     end = to_number; |  | 
| 4184   } else { |  | 
| 4185     CONVERT_DOUBLE_ARG_CHECKED(from_number, 1); |  | 
| 4186     CONVERT_DOUBLE_ARG_CHECKED(to_number, 2); |  | 
| 4187     start = FastD2IChecked(from_number); |  | 
| 4188     end = FastD2IChecked(to_number); |  | 
| 4189   } |  | 
| 4190   RUNTIME_ASSERT(end >= start); |  | 
| 4191   RUNTIME_ASSERT(start >= 0); |  | 
| 4192   RUNTIME_ASSERT(end <= string->length()); |  | 
| 4193   isolate->counters()->sub_string_runtime()->Increment(); |  | 
| 4194 |  | 
| 4195   return *isolate->factory()->NewSubString(string, start, end); |  | 
| 4196 } |  | 
| 4197 |  | 
| 4198 |  | 
| 4199 RUNTIME_FUNCTION(Runtime_InternalizeString) { |  | 
| 4200   HandleScope handles(isolate); |  | 
| 4201   RUNTIME_ASSERT(args.length() == 1); |  | 
| 4202   CONVERT_ARG_HANDLE_CHECKED(String, string, 0); |  | 
| 4203   return *isolate->factory()->InternalizeString(string); |  | 
| 4204 } |  | 
| 4205 |  | 
| 4206 |  | 
| 4207 RUNTIME_FUNCTION(Runtime_StringMatch) { |  | 
| 4208   HandleScope handles(isolate); |  | 
| 4209   DCHECK(args.length() == 3); |  | 
| 4210 |  | 
| 4211   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); |  | 
| 4212   CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); |  | 
| 4213   CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2); |  | 
| 4214 |  | 
| 4215   RUNTIME_ASSERT(regexp_info->HasFastObjectElements()); |  | 
| 4216 |  | 
| 4217   RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); |  | 
| 4218   if (global_cache.HasException()) return isolate->heap()->exception(); |  | 
| 4219 |  | 
| 4220   int capture_count = regexp->CaptureCount(); |  | 
| 4221 |  | 
| 4222   ZoneScope zone_scope(isolate->runtime_zone()); |  | 
| 4223   ZoneList<int> offsets(8, zone_scope.zone()); |  | 
| 4224 |  | 
| 4225   while (true) { |  | 
| 4226     int32_t* match = global_cache.FetchNext(); |  | 
| 4227     if (match == NULL) break; |  | 
| 4228     offsets.Add(match[0], zone_scope.zone());  // start |  | 
| 4229     offsets.Add(match[1], zone_scope.zone());  // end |  | 
| 4230   } |  | 
| 4231 |  | 
| 4232   if (global_cache.HasException()) return isolate->heap()->exception(); |  | 
| 4233 |  | 
| 4234   if (offsets.length() == 0) { |  | 
| 4235     // Not a single match. |  | 
| 4236     return isolate->heap()->null_value(); |  | 
| 4237   } |  | 
| 4238 |  | 
| 4239   RegExpImpl::SetLastMatchInfo(regexp_info, subject, capture_count, |  | 
| 4240                                global_cache.LastSuccessfulMatch()); |  | 
| 4241 |  | 
| 4242   int matches = offsets.length() / 2; |  | 
| 4243   Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches); |  | 
| 4244   Handle<String> substring = |  | 
| 4245       isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1)); |  | 
| 4246   elements->set(0, *substring); |  | 
| 4247   for (int i = 1; i < matches; i++) { |  | 
| 4248     HandleScope temp_scope(isolate); |  | 
| 4249     int from = offsets.at(i * 2); |  | 
| 4250     int to = offsets.at(i * 2 + 1); |  | 
| 4251     Handle<String> substring = |  | 
| 4252         isolate->factory()->NewProperSubString(subject, from, to); |  | 
| 4253     elements->set(i, *substring); |  | 
| 4254   } |  | 
| 4255   Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements); |  | 
| 4256   result->set_length(Smi::FromInt(matches)); |  | 
| 4257   return *result; |  | 
| 4258 } |  | 
| 4259 |  | 
| 4260 |  | 
| 4261 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain |  | 
| 4262 // separate last match info.  See comment on that function. |  | 
| 4263 template <bool has_capture> |  | 
| 4264 static Object* SearchRegExpMultiple(Isolate* isolate, Handle<String> subject, |  | 
| 4265                                     Handle<JSRegExp> regexp, |  | 
| 4266                                     Handle<JSArray> last_match_array, |  | 
| 4267                                     Handle<JSArray> result_array) { |  | 
| 4268   DCHECK(subject->IsFlat()); |  | 
| 4269   DCHECK_NE(has_capture, regexp->CaptureCount() == 0); |  | 
| 4270 |  | 
| 4271   int capture_count = regexp->CaptureCount(); |  | 
| 4272   int subject_length = subject->length(); |  | 
| 4273 |  | 
| 4274   static const int kMinLengthToCache = 0x1000; |  | 
| 4275 |  | 
| 4276   if (subject_length > kMinLengthToCache) { |  | 
| 4277     Handle<Object> cached_answer( |  | 
| 4278         RegExpResultsCache::Lookup(isolate->heap(), *subject, regexp->data(), |  | 
| 4279                                    RegExpResultsCache::REGEXP_MULTIPLE_INDICES), |  | 
| 4280         isolate); |  | 
| 4281     if (*cached_answer != Smi::FromInt(0)) { |  | 
| 4282       Handle<FixedArray> cached_fixed_array = |  | 
| 4283           Handle<FixedArray>(FixedArray::cast(*cached_answer)); |  | 
| 4284       // The cache FixedArray is a COW-array and can therefore be reused. |  | 
| 4285       JSArray::SetContent(result_array, cached_fixed_array); |  | 
| 4286       // The actual length of the result array is stored in the last element of |  | 
| 4287       // the backing store (the backing FixedArray may have a larger capacity). |  | 
| 4288       Object* cached_fixed_array_last_element = |  | 
| 4289           cached_fixed_array->get(cached_fixed_array->length() - 1); |  | 
| 4290       Smi* js_array_length = Smi::cast(cached_fixed_array_last_element); |  | 
| 4291       result_array->set_length(js_array_length); |  | 
| 4292       RegExpImpl::SetLastMatchInfo(last_match_array, subject, capture_count, |  | 
| 4293                                    NULL); |  | 
| 4294       return *result_array; |  | 
| 4295     } |  | 
| 4296   } |  | 
| 4297 |  | 
| 4298   RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); |  | 
| 4299   if (global_cache.HasException()) return isolate->heap()->exception(); |  | 
| 4300 |  | 
| 4301   // Ensured in Runtime_RegExpExecMultiple. |  | 
| 4302   DCHECK(result_array->HasFastObjectElements()); |  | 
| 4303   Handle<FixedArray> result_elements( |  | 
| 4304       FixedArray::cast(result_array->elements())); |  | 
| 4305   if (result_elements->length() < 16) { |  | 
| 4306     result_elements = isolate->factory()->NewFixedArrayWithHoles(16); |  | 
| 4307   } |  | 
| 4308 |  | 
| 4309   FixedArrayBuilder builder(result_elements); |  | 
| 4310 |  | 
| 4311   // Position to search from. |  | 
| 4312   int match_start = -1; |  | 
| 4313   int match_end = 0; |  | 
| 4314   bool first = true; |  | 
| 4315 |  | 
| 4316   // Two smis before and after the match, for very long strings. |  | 
| 4317   static const int kMaxBuilderEntriesPerRegExpMatch = 5; |  | 
| 4318 |  | 
| 4319   while (true) { |  | 
| 4320     int32_t* current_match = global_cache.FetchNext(); |  | 
| 4321     if (current_match == NULL) break; |  | 
| 4322     match_start = current_match[0]; |  | 
| 4323     builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); |  | 
| 4324     if (match_end < match_start) { |  | 
| 4325       ReplacementStringBuilder::AddSubjectSlice(&builder, match_end, |  | 
| 4326                                                 match_start); |  | 
| 4327     } |  | 
| 4328     match_end = current_match[1]; |  | 
| 4329     { |  | 
| 4330       // Avoid accumulating new handles inside loop. |  | 
| 4331       HandleScope temp_scope(isolate); |  | 
| 4332       Handle<String> match; |  | 
| 4333       if (!first) { |  | 
| 4334         match = isolate->factory()->NewProperSubString(subject, match_start, |  | 
| 4335                                                        match_end); |  | 
| 4336       } else { |  | 
| 4337         match = |  | 
| 4338             isolate->factory()->NewSubString(subject, match_start, match_end); |  | 
| 4339         first = false; |  | 
| 4340       } |  | 
| 4341 |  | 
| 4342       if (has_capture) { |  | 
| 4343         // Arguments array to replace function is match, captures, index and |  | 
| 4344         // subject, i.e., 3 + capture count in total. |  | 
| 4345         Handle<FixedArray> elements = |  | 
| 4346             isolate->factory()->NewFixedArray(3 + capture_count); |  | 
| 4347 |  | 
| 4348         elements->set(0, *match); |  | 
| 4349         for (int i = 1; i <= capture_count; i++) { |  | 
| 4350           int start = current_match[i * 2]; |  | 
| 4351           if (start >= 0) { |  | 
| 4352             int end = current_match[i * 2 + 1]; |  | 
| 4353             DCHECK(start <= end); |  | 
| 4354             Handle<String> substring = |  | 
| 4355                 isolate->factory()->NewSubString(subject, start, end); |  | 
| 4356             elements->set(i, *substring); |  | 
| 4357           } else { |  | 
| 4358             DCHECK(current_match[i * 2 + 1] < 0); |  | 
| 4359             elements->set(i, isolate->heap()->undefined_value()); |  | 
| 4360           } |  | 
| 4361         } |  | 
| 4362         elements->set(capture_count + 1, Smi::FromInt(match_start)); |  | 
| 4363         elements->set(capture_count + 2, *subject); |  | 
| 4364         builder.Add(*isolate->factory()->NewJSArrayWithElements(elements)); |  | 
| 4365       } else { |  | 
| 4366         builder.Add(*match); |  | 
| 4367       } |  | 
| 4368     } |  | 
| 4369   } |  | 
| 4370 |  | 
| 4371   if (global_cache.HasException()) return isolate->heap()->exception(); |  | 
| 4372 |  | 
| 4373   if (match_start >= 0) { |  | 
| 4374     // Finished matching, with at least one match. |  | 
| 4375     if (match_end < subject_length) { |  | 
| 4376       ReplacementStringBuilder::AddSubjectSlice(&builder, match_end, |  | 
| 4377                                                 subject_length); |  | 
| 4378     } |  | 
| 4379 |  | 
| 4380     RegExpImpl::SetLastMatchInfo(last_match_array, subject, capture_count, |  | 
| 4381                                  NULL); |  | 
| 4382 |  | 
| 4383     if (subject_length > kMinLengthToCache) { |  | 
| 4384       // Store the length of the result array into the last element of the |  | 
| 4385       // backing FixedArray. |  | 
| 4386       builder.EnsureCapacity(1); |  | 
| 4387       Handle<FixedArray> fixed_array = builder.array(); |  | 
| 4388       fixed_array->set(fixed_array->length() - 1, |  | 
| 4389                        Smi::FromInt(builder.length())); |  | 
| 4390       // Cache the result and turn the FixedArray into a COW array. |  | 
| 4391       RegExpResultsCache::Enter(isolate, subject, |  | 
| 4392                                 handle(regexp->data(), isolate), fixed_array, |  | 
| 4393                                 RegExpResultsCache::REGEXP_MULTIPLE_INDICES); |  | 
| 4394     } |  | 
| 4395     return *builder.ToJSArray(result_array); |  | 
| 4396   } else { |  | 
| 4397     return isolate->heap()->null_value();  // No matches at all. |  | 
| 4398   } |  | 
| 4399 } |  | 
| 4400 |  | 
| 4401 |  | 
| 4402 // This is only called for StringReplaceGlobalRegExpWithFunction.  This sets |  | 
| 4403 // lastMatchInfoOverride to maintain the last match info, so we don't need to |  | 
| 4404 // set any other last match array info. |  | 
| 4405 RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) { |  | 
| 4406   HandleScope handles(isolate); |  | 
| 4407   DCHECK(args.length() == 4); |  | 
| 4408 |  | 
| 4409   CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); |  | 
| 4410   CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); |  | 
| 4411   CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2); |  | 
| 4412   CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3); |  | 
| 4413   RUNTIME_ASSERT(last_match_info->HasFastObjectElements()); |  | 
| 4414   RUNTIME_ASSERT(result_array->HasFastObjectElements()); |  | 
| 4415 |  | 
| 4416   subject = String::Flatten(subject); |  | 
| 4417   RUNTIME_ASSERT(regexp->GetFlags().is_global()); |  | 
| 4418 |  | 
| 4419   if (regexp->CaptureCount() == 0) { |  | 
| 4420     return SearchRegExpMultiple<false>(isolate, subject, regexp, |  | 
| 4421                                        last_match_info, result_array); |  | 
| 4422   } else { |  | 
| 4423     return SearchRegExpMultiple<true>(isolate, subject, regexp, last_match_info, |  | 
| 4424                                       result_array); |  | 
| 4425   } |  | 
| 4426 } |  | 
| 4427 |  | 
| 4428 |  | 
| 4429 RUNTIME_FUNCTION(Runtime_NumberToRadixString) { | 2862 RUNTIME_FUNCTION(Runtime_NumberToRadixString) { | 
| 4430   HandleScope scope(isolate); | 2863   HandleScope scope(isolate); | 
| 4431   DCHECK(args.length() == 2); | 2864   DCHECK(args.length() == 2); | 
| 4432   CONVERT_SMI_ARG_CHECKED(radix, 1); | 2865   CONVERT_SMI_ARG_CHECKED(radix, 1); | 
| 4433   RUNTIME_ASSERT(2 <= radix && radix <= 36); | 2866   RUNTIME_ASSERT(2 <= radix && radix <= 36); | 
| 4434 | 2867 | 
| 4435   // Fast case where the result is a one character string. | 2868   // Fast case where the result is a one character string. | 
| 4436   if (args[0]->IsSmi()) { | 2869   if (args[0]->IsSmi()) { | 
| 4437     int value = args.smi_at(0); | 2870     int value = args.smi_at(0); | 
| 4438     if (value >= 0 && value < radix) { | 2871     if (value >= 0 && value < radix) { | 
| (...skipping 1580 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 6019     // The current spec draft has not updated "ToNumber Applied to the String | 4452     // The current spec draft has not updated "ToNumber Applied to the String | 
| 6020     // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584 | 4453     // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584 | 
| 6021     flags |= ALLOW_OCTAL | ALLOW_BINARY; | 4454     flags |= ALLOW_OCTAL | ALLOW_BINARY; | 
| 6022   } | 4455   } | 
| 6023 | 4456 | 
| 6024   return *isolate->factory()->NewNumber( | 4457   return *isolate->factory()->NewNumber( | 
| 6025       StringToDouble(isolate->unicode_cache(), *subject, flags)); | 4458       StringToDouble(isolate->unicode_cache(), *subject, flags)); | 
| 6026 } | 4459 } | 
| 6027 | 4460 | 
| 6028 | 4461 | 
| 6029 RUNTIME_FUNCTION(Runtime_NewString) { |  | 
| 6030   HandleScope scope(isolate); |  | 
| 6031   DCHECK(args.length() == 2); |  | 
| 6032   CONVERT_INT32_ARG_CHECKED(length, 0); |  | 
| 6033   CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1); |  | 
| 6034   if (length == 0) return isolate->heap()->empty_string(); |  | 
| 6035   Handle<String> result; |  | 
| 6036   if (is_one_byte) { |  | 
| 6037     ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 6038         isolate, result, isolate->factory()->NewRawOneByteString(length)); |  | 
| 6039   } else { |  | 
| 6040     ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 6041         isolate, result, isolate->factory()->NewRawTwoByteString(length)); |  | 
| 6042   } |  | 
| 6043   return *result; |  | 
| 6044 } |  | 
| 6045 |  | 
| 6046 |  | 
| 6047 RUNTIME_FUNCTION(Runtime_TruncateString) { |  | 
| 6048   HandleScope scope(isolate); |  | 
| 6049   DCHECK(args.length() == 2); |  | 
| 6050   CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0); |  | 
| 6051   CONVERT_INT32_ARG_CHECKED(new_length, 1); |  | 
| 6052   RUNTIME_ASSERT(new_length >= 0); |  | 
| 6053   return *SeqString::Truncate(string, new_length); |  | 
| 6054 } |  | 
| 6055 |  | 
| 6056 |  | 
| 6057 RUNTIME_FUNCTION(Runtime_URIEscape) { |  | 
| 6058   HandleScope scope(isolate); |  | 
| 6059   DCHECK(args.length() == 1); |  | 
| 6060   CONVERT_ARG_HANDLE_CHECKED(String, source, 0); |  | 
| 6061   Handle<String> string = String::Flatten(source); |  | 
| 6062   DCHECK(string->IsFlat()); |  | 
| 6063   Handle<String> result; |  | 
| 6064   ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 6065       isolate, result, string->IsOneByteRepresentationUnderneath() |  | 
| 6066                            ? URIEscape::Escape<uint8_t>(isolate, source) |  | 
| 6067                            : URIEscape::Escape<uc16>(isolate, source)); |  | 
| 6068   return *result; |  | 
| 6069 } |  | 
| 6070 |  | 
| 6071 |  | 
| 6072 RUNTIME_FUNCTION(Runtime_URIUnescape) { |  | 
| 6073   HandleScope scope(isolate); |  | 
| 6074   DCHECK(args.length() == 1); |  | 
| 6075   CONVERT_ARG_HANDLE_CHECKED(String, source, 0); |  | 
| 6076   Handle<String> string = String::Flatten(source); |  | 
| 6077   DCHECK(string->IsFlat()); |  | 
| 6078   Handle<String> result; |  | 
| 6079   ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 6080       isolate, result, string->IsOneByteRepresentationUnderneath() |  | 
| 6081                            ? URIUnescape::Unescape<uint8_t>(isolate, source) |  | 
| 6082                            : URIUnescape::Unescape<uc16>(isolate, source)); |  | 
| 6083   return *result; |  | 
| 6084 } |  | 
| 6085 |  | 
| 6086 |  | 
| 6087 RUNTIME_FUNCTION(Runtime_QuoteJSONString) { |  | 
| 6088   HandleScope scope(isolate); |  | 
| 6089   CONVERT_ARG_HANDLE_CHECKED(String, string, 0); |  | 
| 6090   DCHECK(args.length() == 1); |  | 
| 6091   Handle<Object> result; |  | 
| 6092   ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 6093       isolate, result, BasicJsonStringifier::StringifyString(isolate, string)); |  | 
| 6094   return *result; |  | 
| 6095 } |  | 
| 6096 |  | 
| 6097 |  | 
| 6098 RUNTIME_FUNCTION(Runtime_BasicJSONStringify) { |  | 
| 6099   HandleScope scope(isolate); |  | 
| 6100   DCHECK(args.length() == 1); |  | 
| 6101   CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |  | 
| 6102   BasicJsonStringifier stringifier(isolate); |  | 
| 6103   Handle<Object> result; |  | 
| 6104   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |  | 
| 6105                                      stringifier.Stringify(object)); |  | 
| 6106   return *result; |  | 
| 6107 } |  | 
| 6108 |  | 
| 6109 |  | 
| 6110 RUNTIME_FUNCTION(Runtime_StringParseInt) { | 4462 RUNTIME_FUNCTION(Runtime_StringParseInt) { | 
| 6111   HandleScope handle_scope(isolate); | 4463   HandleScope handle_scope(isolate); | 
| 6112   DCHECK(args.length() == 2); | 4464   DCHECK(args.length() == 2); | 
| 6113   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | 4465   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | 
| 6114   CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]); | 4466   CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]); | 
| 6115   RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); | 4467   RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); | 
| 6116 | 4468 | 
| 6117   subject = String::Flatten(subject); | 4469   subject = String::Flatten(subject); | 
| 6118   double value; | 4470   double value; | 
| 6119 | 4471 | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
| 6140   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | 4492   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | 
| 6141 | 4493 | 
| 6142   subject = String::Flatten(subject); | 4494   subject = String::Flatten(subject); | 
| 6143   double value = StringToDouble(isolate->unicode_cache(), *subject, | 4495   double value = StringToDouble(isolate->unicode_cache(), *subject, | 
| 6144                                 ALLOW_TRAILING_JUNK, base::OS::nan_value()); | 4496                                 ALLOW_TRAILING_JUNK, base::OS::nan_value()); | 
| 6145 | 4497 | 
| 6146   return *isolate->factory()->NewNumber(value); | 4498   return *isolate->factory()->NewNumber(value); | 
| 6147 } | 4499 } | 
| 6148 | 4500 | 
| 6149 | 4501 | 
| 6150 static inline bool ToUpperOverflows(uc32 character) { |  | 
| 6151   // y with umlauts and the micro sign are the only characters that stop |  | 
| 6152   // fitting into one-byte when converting to uppercase. |  | 
| 6153   static const uc32 yuml_code = 0xff; |  | 
| 6154   static const uc32 micro_code = 0xb5; |  | 
| 6155   return (character == yuml_code || character == micro_code); |  | 
| 6156 } |  | 
| 6157 |  | 
| 6158 |  | 
| 6159 template <class Converter> |  | 
| 6160 MUST_USE_RESULT static Object* ConvertCaseHelper( |  | 
| 6161     Isolate* isolate, String* string, SeqString* result, int result_length, |  | 
| 6162     unibrow::Mapping<Converter, 128>* mapping) { |  | 
| 6163   DisallowHeapAllocation no_gc; |  | 
| 6164   // We try this twice, once with the assumption that the result is no longer |  | 
| 6165   // than the input and, if that assumption breaks, again with the exact |  | 
| 6166   // length.  This may not be pretty, but it is nicer than what was here before |  | 
| 6167   // and I hereby claim my vaffel-is. |  | 
| 6168   // |  | 
| 6169   // NOTE: This assumes that the upper/lower case of an ASCII |  | 
| 6170   // character is also ASCII.  This is currently the case, but it |  | 
| 6171   // might break in the future if we implement more context and locale |  | 
| 6172   // dependent upper/lower conversions. |  | 
| 6173   bool has_changed_character = false; |  | 
| 6174 |  | 
| 6175   // Convert all characters to upper case, assuming that they will fit |  | 
| 6176   // in the buffer |  | 
| 6177   Access<ConsStringIteratorOp> op(isolate->runtime_state()->string_iterator()); |  | 
| 6178   StringCharacterStream stream(string, op.value()); |  | 
| 6179   unibrow::uchar chars[Converter::kMaxWidth]; |  | 
| 6180   // We can assume that the string is not empty |  | 
| 6181   uc32 current = stream.GetNext(); |  | 
| 6182   bool ignore_overflow = Converter::kIsToLower || result->IsSeqTwoByteString(); |  | 
| 6183   for (int i = 0; i < result_length;) { |  | 
| 6184     bool has_next = stream.HasMore(); |  | 
| 6185     uc32 next = has_next ? stream.GetNext() : 0; |  | 
| 6186     int char_length = mapping->get(current, next, chars); |  | 
| 6187     if (char_length == 0) { |  | 
| 6188       // The case conversion of this character is the character itself. |  | 
| 6189       result->Set(i, current); |  | 
| 6190       i++; |  | 
| 6191     } else if (char_length == 1 && |  | 
| 6192                (ignore_overflow || !ToUpperOverflows(current))) { |  | 
| 6193       // Common case: converting the letter resulted in one character. |  | 
| 6194       DCHECK(static_cast<uc32>(chars[0]) != current); |  | 
| 6195       result->Set(i, chars[0]); |  | 
| 6196       has_changed_character = true; |  | 
| 6197       i++; |  | 
| 6198     } else if (result_length == string->length()) { |  | 
| 6199       bool overflows = ToUpperOverflows(current); |  | 
| 6200       // We've assumed that the result would be as long as the |  | 
| 6201       // input but here is a character that converts to several |  | 
| 6202       // characters.  No matter, we calculate the exact length |  | 
| 6203       // of the result and try the whole thing again. |  | 
| 6204       // |  | 
| 6205       // Note that this leaves room for optimization.  We could just |  | 
| 6206       // memcpy what we already have to the result string.  Also, |  | 
| 6207       // the result string is the last object allocated we could |  | 
| 6208       // "realloc" it and probably, in the vast majority of cases, |  | 
| 6209       // extend the existing string to be able to hold the full |  | 
| 6210       // result. |  | 
| 6211       int next_length = 0; |  | 
| 6212       if (has_next) { |  | 
| 6213         next_length = mapping->get(next, 0, chars); |  | 
| 6214         if (next_length == 0) next_length = 1; |  | 
| 6215       } |  | 
| 6216       int current_length = i + char_length + next_length; |  | 
| 6217       while (stream.HasMore()) { |  | 
| 6218         current = stream.GetNext(); |  | 
| 6219         overflows |= ToUpperOverflows(current); |  | 
| 6220         // NOTE: we use 0 as the next character here because, while |  | 
| 6221         // the next character may affect what a character converts to, |  | 
| 6222         // it does not in any case affect the length of what it convert |  | 
| 6223         // to. |  | 
| 6224         int char_length = mapping->get(current, 0, chars); |  | 
| 6225         if (char_length == 0) char_length = 1; |  | 
| 6226         current_length += char_length; |  | 
| 6227         if (current_length > String::kMaxLength) { |  | 
| 6228           AllowHeapAllocation allocate_error_and_return; |  | 
| 6229           THROW_NEW_ERROR_RETURN_FAILURE(isolate, |  | 
| 6230                                          NewInvalidStringLengthError()); |  | 
| 6231         } |  | 
| 6232       } |  | 
| 6233       // Try again with the real length.  Return signed if we need |  | 
| 6234       // to allocate a two-byte string for to uppercase. |  | 
| 6235       return (overflows && !ignore_overflow) ? Smi::FromInt(-current_length) |  | 
| 6236                                              : Smi::FromInt(current_length); |  | 
| 6237     } else { |  | 
| 6238       for (int j = 0; j < char_length; j++) { |  | 
| 6239         result->Set(i, chars[j]); |  | 
| 6240         i++; |  | 
| 6241       } |  | 
| 6242       has_changed_character = true; |  | 
| 6243     } |  | 
| 6244     current = next; |  | 
| 6245   } |  | 
| 6246   if (has_changed_character) { |  | 
| 6247     return result; |  | 
| 6248   } else { |  | 
| 6249     // If we didn't actually change anything in doing the conversion |  | 
| 6250     // we simple return the result and let the converted string |  | 
| 6251     // become garbage; there is no reason to keep two identical strings |  | 
| 6252     // alive. |  | 
| 6253     return string; |  | 
| 6254   } |  | 
| 6255 } |  | 
| 6256 |  | 
| 6257 |  | 
| 6258 namespace { |  | 
| 6259 |  | 
| 6260 static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF; |  | 
| 6261 static const uintptr_t kAsciiMask = kOneInEveryByte << 7; |  | 
| 6262 |  | 
| 6263 // Given a word and two range boundaries returns a word with high bit |  | 
| 6264 // set in every byte iff the corresponding input byte was strictly in |  | 
| 6265 // the range (m, n). All the other bits in the result are cleared. |  | 
| 6266 // This function is only useful when it can be inlined and the |  | 
| 6267 // boundaries are statically known. |  | 
| 6268 // Requires: all bytes in the input word and the boundaries must be |  | 
| 6269 // ASCII (less than 0x7F). |  | 
| 6270 static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) { |  | 
| 6271   // Use strict inequalities since in edge cases the function could be |  | 
| 6272   // further simplified. |  | 
| 6273   DCHECK(0 < m && m < n); |  | 
| 6274   // Has high bit set in every w byte less than n. |  | 
| 6275   uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w; |  | 
| 6276   // Has high bit set in every w byte greater than m. |  | 
| 6277   uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m); |  | 
| 6278   return (tmp1 & tmp2 & (kOneInEveryByte * 0x80)); |  | 
| 6279 } |  | 
| 6280 |  | 
| 6281 |  | 
| 6282 #ifdef DEBUG |  | 
| 6283 static bool CheckFastAsciiConvert(char* dst, const char* src, int length, |  | 
| 6284                                   bool changed, bool is_to_lower) { |  | 
| 6285   bool expected_changed = false; |  | 
| 6286   for (int i = 0; i < length; i++) { |  | 
| 6287     if (dst[i] == src[i]) continue; |  | 
| 6288     expected_changed = true; |  | 
| 6289     if (is_to_lower) { |  | 
| 6290       DCHECK('A' <= src[i] && src[i] <= 'Z'); |  | 
| 6291       DCHECK(dst[i] == src[i] + ('a' - 'A')); |  | 
| 6292     } else { |  | 
| 6293       DCHECK('a' <= src[i] && src[i] <= 'z'); |  | 
| 6294       DCHECK(dst[i] == src[i] - ('a' - 'A')); |  | 
| 6295     } |  | 
| 6296   } |  | 
| 6297   return (expected_changed == changed); |  | 
| 6298 } |  | 
| 6299 #endif |  | 
| 6300 |  | 
| 6301 |  | 
| 6302 template <class Converter> |  | 
| 6303 static bool FastAsciiConvert(char* dst, const char* src, int length, |  | 
| 6304                              bool* changed_out) { |  | 
| 6305 #ifdef DEBUG |  | 
| 6306   char* saved_dst = dst; |  | 
| 6307   const char* saved_src = src; |  | 
| 6308 #endif |  | 
| 6309   DisallowHeapAllocation no_gc; |  | 
| 6310   // We rely on the distance between upper and lower case letters |  | 
| 6311   // being a known power of 2. |  | 
| 6312   DCHECK('a' - 'A' == (1 << 5)); |  | 
| 6313   // Boundaries for the range of input characters than require conversion. |  | 
| 6314   static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1; |  | 
| 6315   static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1; |  | 
| 6316   bool changed = false; |  | 
| 6317   uintptr_t or_acc = 0; |  | 
| 6318   const char* const limit = src + length; |  | 
| 6319 |  | 
| 6320   // dst is newly allocated and always aligned. |  | 
| 6321   DCHECK(IsAligned(reinterpret_cast<intptr_t>(dst), sizeof(uintptr_t))); |  | 
| 6322   // Only attempt processing one word at a time if src is also aligned. |  | 
| 6323   if (IsAligned(reinterpret_cast<intptr_t>(src), sizeof(uintptr_t))) { |  | 
| 6324     // Process the prefix of the input that requires no conversion one aligned |  | 
| 6325     // (machine) word at a time. |  | 
| 6326     while (src <= limit - sizeof(uintptr_t)) { |  | 
| 6327       const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src); |  | 
| 6328       or_acc |= w; |  | 
| 6329       if (AsciiRangeMask(w, lo, hi) != 0) { |  | 
| 6330         changed = true; |  | 
| 6331         break; |  | 
| 6332       } |  | 
| 6333       *reinterpret_cast<uintptr_t*>(dst) = w; |  | 
| 6334       src += sizeof(uintptr_t); |  | 
| 6335       dst += sizeof(uintptr_t); |  | 
| 6336     } |  | 
| 6337     // Process the remainder of the input performing conversion when |  | 
| 6338     // required one word at a time. |  | 
| 6339     while (src <= limit - sizeof(uintptr_t)) { |  | 
| 6340       const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src); |  | 
| 6341       or_acc |= w; |  | 
| 6342       uintptr_t m = AsciiRangeMask(w, lo, hi); |  | 
| 6343       // The mask has high (7th) bit set in every byte that needs |  | 
| 6344       // conversion and we know that the distance between cases is |  | 
| 6345       // 1 << 5. |  | 
| 6346       *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2); |  | 
| 6347       src += sizeof(uintptr_t); |  | 
| 6348       dst += sizeof(uintptr_t); |  | 
| 6349     } |  | 
| 6350   } |  | 
| 6351   // Process the last few bytes of the input (or the whole input if |  | 
| 6352   // unaligned access is not supported). |  | 
| 6353   while (src < limit) { |  | 
| 6354     char c = *src; |  | 
| 6355     or_acc |= c; |  | 
| 6356     if (lo < c && c < hi) { |  | 
| 6357       c ^= (1 << 5); |  | 
| 6358       changed = true; |  | 
| 6359     } |  | 
| 6360     *dst = c; |  | 
| 6361     ++src; |  | 
| 6362     ++dst; |  | 
| 6363   } |  | 
| 6364 |  | 
| 6365   if ((or_acc & kAsciiMask) != 0) return false; |  | 
| 6366 |  | 
| 6367   DCHECK(CheckFastAsciiConvert(saved_dst, saved_src, length, changed, |  | 
| 6368                                Converter::kIsToLower)); |  | 
| 6369 |  | 
| 6370   *changed_out = changed; |  | 
| 6371   return true; |  | 
| 6372 } |  | 
| 6373 |  | 
| 6374 }  // namespace |  | 
| 6375 |  | 
| 6376 |  | 
| 6377 template <class Converter> |  | 
| 6378 MUST_USE_RESULT static Object* ConvertCase( |  | 
| 6379     Handle<String> s, Isolate* isolate, |  | 
| 6380     unibrow::Mapping<Converter, 128>* mapping) { |  | 
| 6381   s = String::Flatten(s); |  | 
| 6382   int length = s->length(); |  | 
| 6383   // Assume that the string is not empty; we need this assumption later |  | 
| 6384   if (length == 0) return *s; |  | 
| 6385 |  | 
| 6386   // Simpler handling of ASCII strings. |  | 
| 6387   // |  | 
| 6388   // NOTE: This assumes that the upper/lower case of an ASCII |  | 
| 6389   // character is also ASCII.  This is currently the case, but it |  | 
| 6390   // might break in the future if we implement more context and locale |  | 
| 6391   // dependent upper/lower conversions. |  | 
| 6392   if (s->IsOneByteRepresentationUnderneath()) { |  | 
| 6393     // Same length as input. |  | 
| 6394     Handle<SeqOneByteString> result = |  | 
| 6395         isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); |  | 
| 6396     DisallowHeapAllocation no_gc; |  | 
| 6397     String::FlatContent flat_content = s->GetFlatContent(); |  | 
| 6398     DCHECK(flat_content.IsFlat()); |  | 
| 6399     bool has_changed_character = false; |  | 
| 6400     bool is_ascii = FastAsciiConvert<Converter>( |  | 
| 6401         reinterpret_cast<char*>(result->GetChars()), |  | 
| 6402         reinterpret_cast<const char*>(flat_content.ToOneByteVector().start()), |  | 
| 6403         length, &has_changed_character); |  | 
| 6404     // If not ASCII, we discard the result and take the 2 byte path. |  | 
| 6405     if (is_ascii) return has_changed_character ? *result : *s; |  | 
| 6406   } |  | 
| 6407 |  | 
| 6408   Handle<SeqString> result;  // Same length as input. |  | 
| 6409   if (s->IsOneByteRepresentation()) { |  | 
| 6410     result = isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); |  | 
| 6411   } else { |  | 
| 6412     result = isolate->factory()->NewRawTwoByteString(length).ToHandleChecked(); |  | 
| 6413   } |  | 
| 6414 |  | 
| 6415   Object* answer = ConvertCaseHelper(isolate, *s, *result, length, mapping); |  | 
| 6416   if (answer->IsException() || answer->IsString()) return answer; |  | 
| 6417 |  | 
| 6418   DCHECK(answer->IsSmi()); |  | 
| 6419   length = Smi::cast(answer)->value(); |  | 
| 6420   if (s->IsOneByteRepresentation() && length > 0) { |  | 
| 6421     ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 6422         isolate, result, isolate->factory()->NewRawOneByteString(length)); |  | 
| 6423   } else { |  | 
| 6424     if (length < 0) length = -length; |  | 
| 6425     ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 6426         isolate, result, isolate->factory()->NewRawTwoByteString(length)); |  | 
| 6427   } |  | 
| 6428   return ConvertCaseHelper(isolate, *s, *result, length, mapping); |  | 
| 6429 } |  | 
| 6430 |  | 
| 6431 |  | 
| 6432 RUNTIME_FUNCTION(Runtime_StringToLowerCase) { |  | 
| 6433   HandleScope scope(isolate); |  | 
| 6434   DCHECK(args.length() == 1); |  | 
| 6435   CONVERT_ARG_HANDLE_CHECKED(String, s, 0); |  | 
| 6436   return ConvertCase(s, isolate, isolate->runtime_state()->to_lower_mapping()); |  | 
| 6437 } |  | 
| 6438 |  | 
| 6439 |  | 
| 6440 RUNTIME_FUNCTION(Runtime_StringToUpperCase) { |  | 
| 6441   HandleScope scope(isolate); |  | 
| 6442   DCHECK(args.length() == 1); |  | 
| 6443   CONVERT_ARG_HANDLE_CHECKED(String, s, 0); |  | 
| 6444   return ConvertCase(s, isolate, isolate->runtime_state()->to_upper_mapping()); |  | 
| 6445 } |  | 
| 6446 |  | 
| 6447 |  | 
| 6448 RUNTIME_FUNCTION(Runtime_StringTrim) { |  | 
| 6449   HandleScope scope(isolate); |  | 
| 6450   DCHECK(args.length() == 3); |  | 
| 6451 |  | 
| 6452   CONVERT_ARG_HANDLE_CHECKED(String, string, 0); |  | 
| 6453   CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1); |  | 
| 6454   CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2); |  | 
| 6455 |  | 
| 6456   string = String::Flatten(string); |  | 
| 6457   int length = string->length(); |  | 
| 6458 |  | 
| 6459   int left = 0; |  | 
| 6460   UnicodeCache* unicode_cache = isolate->unicode_cache(); |  | 
| 6461   if (trimLeft) { |  | 
| 6462     while (left < length && |  | 
| 6463            unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) { |  | 
| 6464       left++; |  | 
| 6465     } |  | 
| 6466   } |  | 
| 6467 |  | 
| 6468   int right = length; |  | 
| 6469   if (trimRight) { |  | 
| 6470     while ( |  | 
| 6471         right > left && |  | 
| 6472         unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { |  | 
| 6473       right--; |  | 
| 6474     } |  | 
| 6475   } |  | 
| 6476 |  | 
| 6477   return *isolate->factory()->NewSubString(string, left, right); |  | 
| 6478 } |  | 
| 6479 |  | 
| 6480 |  | 
| 6481 RUNTIME_FUNCTION(Runtime_StringSplit) { |  | 
| 6482   HandleScope handle_scope(isolate); |  | 
| 6483   DCHECK(args.length() == 3); |  | 
| 6484   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); |  | 
| 6485   CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); |  | 
| 6486   CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]); |  | 
| 6487   RUNTIME_ASSERT(limit > 0); |  | 
| 6488 |  | 
| 6489   int subject_length = subject->length(); |  | 
| 6490   int pattern_length = pattern->length(); |  | 
| 6491   RUNTIME_ASSERT(pattern_length > 0); |  | 
| 6492 |  | 
| 6493   if (limit == 0xffffffffu) { |  | 
| 6494     Handle<Object> cached_answer( |  | 
| 6495         RegExpResultsCache::Lookup(isolate->heap(), *subject, *pattern, |  | 
| 6496                                    RegExpResultsCache::STRING_SPLIT_SUBSTRINGS), |  | 
| 6497         isolate); |  | 
| 6498     if (*cached_answer != Smi::FromInt(0)) { |  | 
| 6499       // The cache FixedArray is a COW-array and can therefore be reused. |  | 
| 6500       Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements( |  | 
| 6501           Handle<FixedArray>::cast(cached_answer)); |  | 
| 6502       return *result; |  | 
| 6503     } |  | 
| 6504   } |  | 
| 6505 |  | 
| 6506   // The limit can be very large (0xffffffffu), but since the pattern |  | 
| 6507   // isn't empty, we can never create more parts than ~half the length |  | 
| 6508   // of the subject. |  | 
| 6509 |  | 
| 6510   subject = String::Flatten(subject); |  | 
| 6511   pattern = String::Flatten(pattern); |  | 
| 6512 |  | 
| 6513   static const int kMaxInitialListCapacity = 16; |  | 
| 6514 |  | 
| 6515   ZoneScope zone_scope(isolate->runtime_zone()); |  | 
| 6516 |  | 
| 6517   // Find (up to limit) indices of separator and end-of-string in subject |  | 
| 6518   int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit); |  | 
| 6519   ZoneList<int> indices(initial_capacity, zone_scope.zone()); |  | 
| 6520 |  | 
| 6521   FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit, |  | 
| 6522                             zone_scope.zone()); |  | 
| 6523 |  | 
| 6524   if (static_cast<uint32_t>(indices.length()) < limit) { |  | 
| 6525     indices.Add(subject_length, zone_scope.zone()); |  | 
| 6526   } |  | 
| 6527 |  | 
| 6528   // The list indices now contains the end of each part to create. |  | 
| 6529 |  | 
| 6530   // Create JSArray of substrings separated by separator. |  | 
| 6531   int part_count = indices.length(); |  | 
| 6532 |  | 
| 6533   Handle<JSArray> result = isolate->factory()->NewJSArray(part_count); |  | 
| 6534   JSObject::EnsureCanContainHeapObjectElements(result); |  | 
| 6535   result->set_length(Smi::FromInt(part_count)); |  | 
| 6536 |  | 
| 6537   DCHECK(result->HasFastObjectElements()); |  | 
| 6538 |  | 
| 6539   if (part_count == 1 && indices.at(0) == subject_length) { |  | 
| 6540     FixedArray::cast(result->elements())->set(0, *subject); |  | 
| 6541     return *result; |  | 
| 6542   } |  | 
| 6543 |  | 
| 6544   Handle<FixedArray> elements(FixedArray::cast(result->elements())); |  | 
| 6545   int part_start = 0; |  | 
| 6546   for (int i = 0; i < part_count; i++) { |  | 
| 6547     HandleScope local_loop_handle(isolate); |  | 
| 6548     int part_end = indices.at(i); |  | 
| 6549     Handle<String> substring = |  | 
| 6550         isolate->factory()->NewProperSubString(subject, part_start, part_end); |  | 
| 6551     elements->set(i, *substring); |  | 
| 6552     part_start = part_end + pattern_length; |  | 
| 6553   } |  | 
| 6554 |  | 
| 6555   if (limit == 0xffffffffu) { |  | 
| 6556     if (result->HasFastObjectElements()) { |  | 
| 6557       RegExpResultsCache::Enter(isolate, subject, pattern, elements, |  | 
| 6558                                 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS); |  | 
| 6559     } |  | 
| 6560   } |  | 
| 6561 |  | 
| 6562   return *result; |  | 
| 6563 } |  | 
| 6564 |  | 
| 6565 |  | 
| 6566 // Copies Latin1 characters to the given fixed array looking up |  | 
| 6567 // one-char strings in the cache. Gives up on the first char that is |  | 
| 6568 // not in the cache and fills the remainder with smi zeros. Returns |  | 
| 6569 // the length of the successfully copied prefix. |  | 
| 6570 static int CopyCachedOneByteCharsToArray(Heap* heap, const uint8_t* chars, |  | 
| 6571                                          FixedArray* elements, int length) { |  | 
| 6572   DisallowHeapAllocation no_gc; |  | 
| 6573   FixedArray* one_byte_cache = heap->single_character_string_cache(); |  | 
| 6574   Object* undefined = heap->undefined_value(); |  | 
| 6575   int i; |  | 
| 6576   WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc); |  | 
| 6577   for (i = 0; i < length; ++i) { |  | 
| 6578     Object* value = one_byte_cache->get(chars[i]); |  | 
| 6579     if (value == undefined) break; |  | 
| 6580     elements->set(i, value, mode); |  | 
| 6581   } |  | 
| 6582   if (i < length) { |  | 
| 6583     DCHECK(Smi::FromInt(0) == 0); |  | 
| 6584     memset(elements->data_start() + i, 0, kPointerSize * (length - i)); |  | 
| 6585   } |  | 
| 6586 #ifdef DEBUG |  | 
| 6587   for (int j = 0; j < length; ++j) { |  | 
| 6588     Object* element = elements->get(j); |  | 
| 6589     DCHECK(element == Smi::FromInt(0) || |  | 
| 6590            (element->IsString() && String::cast(element)->LooksValid())); |  | 
| 6591   } |  | 
| 6592 #endif |  | 
| 6593   return i; |  | 
| 6594 } |  | 
| 6595 |  | 
| 6596 |  | 
| 6597 // Converts a String to JSArray. |  | 
| 6598 // For example, "foo" => ["f", "o", "o"]. |  | 
| 6599 RUNTIME_FUNCTION(Runtime_StringToArray) { |  | 
| 6600   HandleScope scope(isolate); |  | 
| 6601   DCHECK(args.length() == 2); |  | 
| 6602   CONVERT_ARG_HANDLE_CHECKED(String, s, 0); |  | 
| 6603   CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); |  | 
| 6604 |  | 
| 6605   s = String::Flatten(s); |  | 
| 6606   const int length = static_cast<int>(Min<uint32_t>(s->length(), limit)); |  | 
| 6607 |  | 
| 6608   Handle<FixedArray> elements; |  | 
| 6609   int position = 0; |  | 
| 6610   if (s->IsFlat() && s->IsOneByteRepresentation()) { |  | 
| 6611     // Try using cached chars where possible. |  | 
| 6612     elements = isolate->factory()->NewUninitializedFixedArray(length); |  | 
| 6613 |  | 
| 6614     DisallowHeapAllocation no_gc; |  | 
| 6615     String::FlatContent content = s->GetFlatContent(); |  | 
| 6616     if (content.IsOneByte()) { |  | 
| 6617       Vector<const uint8_t> chars = content.ToOneByteVector(); |  | 
| 6618       // Note, this will initialize all elements (not only the prefix) |  | 
| 6619       // to prevent GC from seeing partially initialized array. |  | 
| 6620       position = CopyCachedOneByteCharsToArray(isolate->heap(), chars.start(), |  | 
| 6621                                                *elements, length); |  | 
| 6622     } else { |  | 
| 6623       MemsetPointer(elements->data_start(), isolate->heap()->undefined_value(), |  | 
| 6624                     length); |  | 
| 6625     } |  | 
| 6626   } else { |  | 
| 6627     elements = isolate->factory()->NewFixedArray(length); |  | 
| 6628   } |  | 
| 6629   for (int i = position; i < length; ++i) { |  | 
| 6630     Handle<Object> str = |  | 
| 6631         isolate->factory()->LookupSingleCharacterStringFromCode(s->Get(i)); |  | 
| 6632     elements->set(i, *str); |  | 
| 6633   } |  | 
| 6634 |  | 
| 6635 #ifdef DEBUG |  | 
| 6636   for (int i = 0; i < length; ++i) { |  | 
| 6637     DCHECK(String::cast(elements->get(i))->length() == 1); |  | 
| 6638   } |  | 
| 6639 #endif |  | 
| 6640 |  | 
| 6641   return *isolate->factory()->NewJSArrayWithElements(elements); |  | 
| 6642 } |  | 
| 6643 |  | 
| 6644 |  | 
| 6645 RUNTIME_FUNCTION(Runtime_NewStringWrapper) { | 4502 RUNTIME_FUNCTION(Runtime_NewStringWrapper) { | 
| 6646   HandleScope scope(isolate); | 4503   HandleScope scope(isolate); | 
| 6647   DCHECK(args.length() == 1); | 4504   DCHECK(args.length() == 1); | 
| 6648   CONVERT_ARG_HANDLE_CHECKED(String, value, 0); | 4505   CONVERT_ARG_HANDLE_CHECKED(String, value, 0); | 
| 6649   return *Object::ToObject(isolate, value).ToHandleChecked(); | 4506   return *Object::ToObject(isolate, value).ToHandleChecked(); | 
| 6650 } | 4507 } | 
| 6651 | 4508 | 
| 6652 | 4509 | 
| 6653 bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) { |  | 
| 6654   unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; |  | 
| 6655   int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars); |  | 
| 6656   return char_length == 0; |  | 
| 6657 } |  | 
| 6658 |  | 
| 6659 |  | 
| 6660 RUNTIME_FUNCTION(Runtime_NumberToStringRT) { | 4510 RUNTIME_FUNCTION(Runtime_NumberToStringRT) { | 
| 6661   HandleScope scope(isolate); | 4511   HandleScope scope(isolate); | 
| 6662   DCHECK(args.length() == 1); | 4512   DCHECK(args.length() == 1); | 
| 6663   CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0); | 4513   CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0); | 
| 6664 | 4514 | 
| 6665   return *isolate->factory()->NumberToString(number); | 4515   return *isolate->factory()->NumberToString(number); | 
| 6666 } | 4516 } | 
| 6667 | 4517 | 
| 6668 | 4518 | 
| 6669 RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) { | 4519 RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) { | 
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 6807 | 4657 | 
| 6808   // We rely on implementation-defined behavior below, but at least not on | 4658   // We rely on implementation-defined behavior below, but at least not on | 
| 6809   // undefined behavior. | 4659   // undefined behavior. | 
| 6810   CONVERT_NUMBER_CHECKED(uint32_t, x, Int32, args[0]); | 4660   CONVERT_NUMBER_CHECKED(uint32_t, x, Int32, args[0]); | 
| 6811   CONVERT_NUMBER_CHECKED(uint32_t, y, Int32, args[1]); | 4661   CONVERT_NUMBER_CHECKED(uint32_t, y, Int32, args[1]); | 
| 6812   int32_t product = static_cast<int32_t>(x * y); | 4662   int32_t product = static_cast<int32_t>(x * y); | 
| 6813   return *isolate->factory()->NewNumberFromInt(product); | 4663   return *isolate->factory()->NewNumberFromInt(product); | 
| 6814 } | 4664 } | 
| 6815 | 4665 | 
| 6816 | 4666 | 
| 6817 RUNTIME_FUNCTION(Runtime_StringAdd) { |  | 
| 6818   HandleScope scope(isolate); |  | 
| 6819   DCHECK(args.length() == 2); |  | 
| 6820   CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); |  | 
| 6821   CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); |  | 
| 6822   isolate->counters()->string_add_runtime()->Increment(); |  | 
| 6823   Handle<String> result; |  | 
| 6824   ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 6825       isolate, result, isolate->factory()->NewConsString(str1, str2)); |  | 
| 6826   return *result; |  | 
| 6827 } |  | 
| 6828 |  | 
| 6829 |  | 
| 6830 template <typename sinkchar> |  | 
| 6831 static inline void StringBuilderConcatHelper(String* special, sinkchar* sink, |  | 
| 6832                                              FixedArray* fixed_array, |  | 
| 6833                                              int array_length) { |  | 
| 6834   DisallowHeapAllocation no_gc; |  | 
| 6835   int position = 0; |  | 
| 6836   for (int i = 0; i < array_length; i++) { |  | 
| 6837     Object* element = fixed_array->get(i); |  | 
| 6838     if (element->IsSmi()) { |  | 
| 6839       // Smi encoding of position and length. |  | 
| 6840       int encoded_slice = Smi::cast(element)->value(); |  | 
| 6841       int pos; |  | 
| 6842       int len; |  | 
| 6843       if (encoded_slice > 0) { |  | 
| 6844         // Position and length encoded in one smi. |  | 
| 6845         pos = StringBuilderSubstringPosition::decode(encoded_slice); |  | 
| 6846         len = StringBuilderSubstringLength::decode(encoded_slice); |  | 
| 6847       } else { |  | 
| 6848         // Position and length encoded in two smis. |  | 
| 6849         Object* obj = fixed_array->get(++i); |  | 
| 6850         DCHECK(obj->IsSmi()); |  | 
| 6851         pos = Smi::cast(obj)->value(); |  | 
| 6852         len = -encoded_slice; |  | 
| 6853       } |  | 
| 6854       String::WriteToFlat(special, sink + position, pos, pos + len); |  | 
| 6855       position += len; |  | 
| 6856     } else { |  | 
| 6857       String* string = String::cast(element); |  | 
| 6858       int element_length = string->length(); |  | 
| 6859       String::WriteToFlat(string, sink + position, 0, element_length); |  | 
| 6860       position += element_length; |  | 
| 6861     } |  | 
| 6862   } |  | 
| 6863 } |  | 
| 6864 |  | 
| 6865 |  | 
| 6866 // Returns the result length of the concatenation. |  | 
| 6867 // On illegal argument, -1 is returned. |  | 
| 6868 static inline int StringBuilderConcatLength(int special_length, |  | 
| 6869                                             FixedArray* fixed_array, |  | 
| 6870                                             int array_length, bool* one_byte) { |  | 
| 6871   DisallowHeapAllocation no_gc; |  | 
| 6872   int position = 0; |  | 
| 6873   for (int i = 0; i < array_length; i++) { |  | 
| 6874     int increment = 0; |  | 
| 6875     Object* elt = fixed_array->get(i); |  | 
| 6876     if (elt->IsSmi()) { |  | 
| 6877       // Smi encoding of position and length. |  | 
| 6878       int smi_value = Smi::cast(elt)->value(); |  | 
| 6879       int pos; |  | 
| 6880       int len; |  | 
| 6881       if (smi_value > 0) { |  | 
| 6882         // Position and length encoded in one smi. |  | 
| 6883         pos = StringBuilderSubstringPosition::decode(smi_value); |  | 
| 6884         len = StringBuilderSubstringLength::decode(smi_value); |  | 
| 6885       } else { |  | 
| 6886         // Position and length encoded in two smis. |  | 
| 6887         len = -smi_value; |  | 
| 6888         // Get the position and check that it is a positive smi. |  | 
| 6889         i++; |  | 
| 6890         if (i >= array_length) return -1; |  | 
| 6891         Object* next_smi = fixed_array->get(i); |  | 
| 6892         if (!next_smi->IsSmi()) return -1; |  | 
| 6893         pos = Smi::cast(next_smi)->value(); |  | 
| 6894         if (pos < 0) return -1; |  | 
| 6895       } |  | 
| 6896       DCHECK(pos >= 0); |  | 
| 6897       DCHECK(len >= 0); |  | 
| 6898       if (pos > special_length || len > special_length - pos) return -1; |  | 
| 6899       increment = len; |  | 
| 6900     } else if (elt->IsString()) { |  | 
| 6901       String* element = String::cast(elt); |  | 
| 6902       int element_length = element->length(); |  | 
| 6903       increment = element_length; |  | 
| 6904       if (*one_byte && !element->HasOnlyOneByteChars()) { |  | 
| 6905         *one_byte = false; |  | 
| 6906       } |  | 
| 6907     } else { |  | 
| 6908       return -1; |  | 
| 6909     } |  | 
| 6910     if (increment > String::kMaxLength - position) { |  | 
| 6911       return kMaxInt;  // Provoke throw on allocation. |  | 
| 6912     } |  | 
| 6913     position += increment; |  | 
| 6914   } |  | 
| 6915   return position; |  | 
| 6916 } |  | 
| 6917 |  | 
| 6918 |  | 
| 6919 RUNTIME_FUNCTION(Runtime_StringBuilderConcat) { |  | 
| 6920   HandleScope scope(isolate); |  | 
| 6921   DCHECK(args.length() == 3); |  | 
| 6922   CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); |  | 
| 6923   int32_t array_length; |  | 
| 6924   if (!args[1]->ToInt32(&array_length)) { |  | 
| 6925     THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError()); |  | 
| 6926   } |  | 
| 6927   CONVERT_ARG_HANDLE_CHECKED(String, special, 2); |  | 
| 6928 |  | 
| 6929   size_t actual_array_length = 0; |  | 
| 6930   RUNTIME_ASSERT( |  | 
| 6931       TryNumberToSize(isolate, array->length(), &actual_array_length)); |  | 
| 6932   RUNTIME_ASSERT(array_length >= 0); |  | 
| 6933   RUNTIME_ASSERT(static_cast<size_t>(array_length) <= actual_array_length); |  | 
| 6934 |  | 
| 6935   // This assumption is used by the slice encoding in one or two smis. |  | 
| 6936   DCHECK(Smi::kMaxValue >= String::kMaxLength); |  | 
| 6937 |  | 
| 6938   RUNTIME_ASSERT(array->HasFastElements()); |  | 
| 6939   JSObject::EnsureCanContainHeapObjectElements(array); |  | 
| 6940 |  | 
| 6941   int special_length = special->length(); |  | 
| 6942   if (!array->HasFastObjectElements()) { |  | 
| 6943     return isolate->Throw(isolate->heap()->illegal_argument_string()); |  | 
| 6944   } |  | 
| 6945 |  | 
| 6946   int length; |  | 
| 6947   bool one_byte = special->HasOnlyOneByteChars(); |  | 
| 6948 |  | 
| 6949   { |  | 
| 6950     DisallowHeapAllocation no_gc; |  | 
| 6951     FixedArray* fixed_array = FixedArray::cast(array->elements()); |  | 
| 6952     if (fixed_array->length() < array_length) { |  | 
| 6953       array_length = fixed_array->length(); |  | 
| 6954     } |  | 
| 6955 |  | 
| 6956     if (array_length == 0) { |  | 
| 6957       return isolate->heap()->empty_string(); |  | 
| 6958     } else if (array_length == 1) { |  | 
| 6959       Object* first = fixed_array->get(0); |  | 
| 6960       if (first->IsString()) return first; |  | 
| 6961     } |  | 
| 6962     length = StringBuilderConcatLength(special_length, fixed_array, |  | 
| 6963                                        array_length, &one_byte); |  | 
| 6964   } |  | 
| 6965 |  | 
| 6966   if (length == -1) { |  | 
| 6967     return isolate->Throw(isolate->heap()->illegal_argument_string()); |  | 
| 6968   } |  | 
| 6969 |  | 
| 6970   if (one_byte) { |  | 
| 6971     Handle<SeqOneByteString> answer; |  | 
| 6972     ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 6973         isolate, answer, isolate->factory()->NewRawOneByteString(length)); |  | 
| 6974     StringBuilderConcatHelper(*special, answer->GetChars(), |  | 
| 6975                               FixedArray::cast(array->elements()), |  | 
| 6976                               array_length); |  | 
| 6977     return *answer; |  | 
| 6978   } else { |  | 
| 6979     Handle<SeqTwoByteString> answer; |  | 
| 6980     ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 6981         isolate, answer, isolate->factory()->NewRawTwoByteString(length)); |  | 
| 6982     StringBuilderConcatHelper(*special, answer->GetChars(), |  | 
| 6983                               FixedArray::cast(array->elements()), |  | 
| 6984                               array_length); |  | 
| 6985     return *answer; |  | 
| 6986   } |  | 
| 6987 } |  | 
| 6988 |  | 
| 6989 |  | 
| 6990 RUNTIME_FUNCTION(Runtime_StringBuilderJoin) { |  | 
| 6991   HandleScope scope(isolate); |  | 
| 6992   DCHECK(args.length() == 3); |  | 
| 6993   CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); |  | 
| 6994   int32_t array_length; |  | 
| 6995   if (!args[1]->ToInt32(&array_length)) { |  | 
| 6996     THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError()); |  | 
| 6997   } |  | 
| 6998   CONVERT_ARG_HANDLE_CHECKED(String, separator, 2); |  | 
| 6999   RUNTIME_ASSERT(array->HasFastObjectElements()); |  | 
| 7000   RUNTIME_ASSERT(array_length >= 0); |  | 
| 7001 |  | 
| 7002   Handle<FixedArray> fixed_array(FixedArray::cast(array->elements())); |  | 
| 7003   if (fixed_array->length() < array_length) { |  | 
| 7004     array_length = fixed_array->length(); |  | 
| 7005   } |  | 
| 7006 |  | 
| 7007   if (array_length == 0) { |  | 
| 7008     return isolate->heap()->empty_string(); |  | 
| 7009   } else if (array_length == 1) { |  | 
| 7010     Object* first = fixed_array->get(0); |  | 
| 7011     RUNTIME_ASSERT(first->IsString()); |  | 
| 7012     return first; |  | 
| 7013   } |  | 
| 7014 |  | 
| 7015   int separator_length = separator->length(); |  | 
| 7016   RUNTIME_ASSERT(separator_length > 0); |  | 
| 7017   int max_nof_separators = |  | 
| 7018       (String::kMaxLength + separator_length - 1) / separator_length; |  | 
| 7019   if (max_nof_separators < (array_length - 1)) { |  | 
| 7020     THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError()); |  | 
| 7021   } |  | 
| 7022   int length = (array_length - 1) * separator_length; |  | 
| 7023   for (int i = 0; i < array_length; i++) { |  | 
| 7024     Object* element_obj = fixed_array->get(i); |  | 
| 7025     RUNTIME_ASSERT(element_obj->IsString()); |  | 
| 7026     String* element = String::cast(element_obj); |  | 
| 7027     int increment = element->length(); |  | 
| 7028     if (increment > String::kMaxLength - length) { |  | 
| 7029       STATIC_ASSERT(String::kMaxLength < kMaxInt); |  | 
| 7030       length = kMaxInt;  // Provoke exception; |  | 
| 7031       break; |  | 
| 7032     } |  | 
| 7033     length += increment; |  | 
| 7034   } |  | 
| 7035 |  | 
| 7036   Handle<SeqTwoByteString> answer; |  | 
| 7037   ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |  | 
| 7038       isolate, answer, isolate->factory()->NewRawTwoByteString(length)); |  | 
| 7039 |  | 
| 7040   DisallowHeapAllocation no_gc; |  | 
| 7041 |  | 
| 7042   uc16* sink = answer->GetChars(); |  | 
| 7043 #ifdef DEBUG |  | 
| 7044   uc16* end = sink + length; |  | 
| 7045 #endif |  | 
| 7046 |  | 
| 7047   RUNTIME_ASSERT(fixed_array->get(0)->IsString()); |  | 
| 7048   String* first = String::cast(fixed_array->get(0)); |  | 
| 7049   String* separator_raw = *separator; |  | 
| 7050   int first_length = first->length(); |  | 
| 7051   String::WriteToFlat(first, sink, 0, first_length); |  | 
| 7052   sink += first_length; |  | 
| 7053 |  | 
| 7054   for (int i = 1; i < array_length; i++) { |  | 
| 7055     DCHECK(sink + separator_length <= end); |  | 
| 7056     String::WriteToFlat(separator_raw, sink, 0, separator_length); |  | 
| 7057     sink += separator_length; |  | 
| 7058 |  | 
| 7059     RUNTIME_ASSERT(fixed_array->get(i)->IsString()); |  | 
| 7060     String* element = String::cast(fixed_array->get(i)); |  | 
| 7061     int element_length = element->length(); |  | 
| 7062     DCHECK(sink + element_length <= end); |  | 
| 7063     String::WriteToFlat(element, sink, 0, element_length); |  | 
| 7064     sink += element_length; |  | 
| 7065   } |  | 
| 7066   DCHECK(sink == end); |  | 
| 7067 |  | 
| 7068   // Use %_FastOneByteArrayJoin instead. |  | 
| 7069   DCHECK(!answer->IsOneByteRepresentation()); |  | 
| 7070   return *answer; |  | 
| 7071 } |  | 
| 7072 |  | 
| 7073 template <typename Char> |  | 
| 7074 static void JoinSparseArrayWithSeparator(FixedArray* elements, |  | 
| 7075                                          int elements_length, |  | 
| 7076                                          uint32_t array_length, |  | 
| 7077                                          String* separator, |  | 
| 7078                                          Vector<Char> buffer) { |  | 
| 7079   DisallowHeapAllocation no_gc; |  | 
| 7080   int previous_separator_position = 0; |  | 
| 7081   int separator_length = separator->length(); |  | 
| 7082   int cursor = 0; |  | 
| 7083   for (int i = 0; i < elements_length; i += 2) { |  | 
| 7084     int position = NumberToInt32(elements->get(i)); |  | 
| 7085     String* string = String::cast(elements->get(i + 1)); |  | 
| 7086     int string_length = string->length(); |  | 
| 7087     if (string->length() > 0) { |  | 
| 7088       while (previous_separator_position < position) { |  | 
| 7089         String::WriteToFlat<Char>(separator, &buffer[cursor], 0, |  | 
| 7090                                   separator_length); |  | 
| 7091         cursor += separator_length; |  | 
| 7092         previous_separator_position++; |  | 
| 7093       } |  | 
| 7094       String::WriteToFlat<Char>(string, &buffer[cursor], 0, string_length); |  | 
| 7095       cursor += string->length(); |  | 
| 7096     } |  | 
| 7097   } |  | 
| 7098   if (separator_length > 0) { |  | 
| 7099     // Array length must be representable as a signed 32-bit number, |  | 
| 7100     // otherwise the total string length would have been too large. |  | 
| 7101     DCHECK(array_length <= 0x7fffffff);  // Is int32_t. |  | 
| 7102     int last_array_index = static_cast<int>(array_length - 1); |  | 
| 7103     while (previous_separator_position < last_array_index) { |  | 
| 7104       String::WriteToFlat<Char>(separator, &buffer[cursor], 0, |  | 
| 7105                                 separator_length); |  | 
| 7106       cursor += separator_length; |  | 
| 7107       previous_separator_position++; |  | 
| 7108     } |  | 
| 7109   } |  | 
| 7110   DCHECK(cursor <= buffer.length()); |  | 
| 7111 } |  | 
| 7112 |  | 
| 7113 |  | 
| 7114 RUNTIME_FUNCTION(Runtime_SparseJoinWithSeparator) { |  | 
| 7115   HandleScope scope(isolate); |  | 
| 7116   DCHECK(args.length() == 3); |  | 
| 7117   CONVERT_ARG_HANDLE_CHECKED(JSArray, elements_array, 0); |  | 
| 7118   CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]); |  | 
| 7119   CONVERT_ARG_HANDLE_CHECKED(String, separator, 2); |  | 
| 7120   // elements_array is fast-mode JSarray of alternating positions |  | 
| 7121   // (increasing order) and strings. |  | 
| 7122   RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements()); |  | 
| 7123   // array_length is length of original array (used to add separators); |  | 
| 7124   // separator is string to put between elements. Assumed to be non-empty. |  | 
| 7125   RUNTIME_ASSERT(array_length > 0); |  | 
| 7126 |  | 
| 7127   // Find total length of join result. |  | 
| 7128   int string_length = 0; |  | 
| 7129   bool is_one_byte = separator->IsOneByteRepresentation(); |  | 
| 7130   bool overflow = false; |  | 
| 7131   CONVERT_NUMBER_CHECKED(int, elements_length, Int32, elements_array->length()); |  | 
| 7132   RUNTIME_ASSERT(elements_length <= elements_array->elements()->length()); |  | 
| 7133   RUNTIME_ASSERT((elements_length & 1) == 0);  // Even length. |  | 
| 7134   FixedArray* elements = FixedArray::cast(elements_array->elements()); |  | 
| 7135   for (int i = 0; i < elements_length; i += 2) { |  | 
| 7136     RUNTIME_ASSERT(elements->get(i)->IsNumber()); |  | 
| 7137     CONVERT_NUMBER_CHECKED(uint32_t, position, Uint32, elements->get(i)); |  | 
| 7138     RUNTIME_ASSERT(position < array_length); |  | 
| 7139     RUNTIME_ASSERT(elements->get(i + 1)->IsString()); |  | 
| 7140   } |  | 
| 7141 |  | 
| 7142   { |  | 
| 7143     DisallowHeapAllocation no_gc; |  | 
| 7144     for (int i = 0; i < elements_length; i += 2) { |  | 
| 7145       String* string = String::cast(elements->get(i + 1)); |  | 
| 7146       int length = string->length(); |  | 
| 7147       if (is_one_byte && !string->IsOneByteRepresentation()) { |  | 
| 7148         is_one_byte = false; |  | 
| 7149       } |  | 
| 7150       if (length > String::kMaxLength || |  | 
| 7151           String::kMaxLength - length < string_length) { |  | 
| 7152         overflow = true; |  | 
| 7153         break; |  | 
| 7154       } |  | 
| 7155       string_length += length; |  | 
| 7156     } |  | 
| 7157   } |  | 
| 7158 |  | 
| 7159   int separator_length = separator->length(); |  | 
| 7160   if (!overflow && separator_length > 0) { |  | 
| 7161     if (array_length <= 0x7fffffffu) { |  | 
| 7162       int separator_count = static_cast<int>(array_length) - 1; |  | 
| 7163       int remaining_length = String::kMaxLength - string_length; |  | 
| 7164       if ((remaining_length / separator_length) >= separator_count) { |  | 
| 7165         string_length += separator_length * (array_length - 1); |  | 
| 7166       } else { |  | 
| 7167         // Not room for the separators within the maximal string length. |  | 
| 7168         overflow = true; |  | 
| 7169       } |  | 
| 7170     } else { |  | 
| 7171       // Nonempty separator and at least 2^31-1 separators necessary |  | 
| 7172       // means that the string is too large to create. |  | 
| 7173       STATIC_ASSERT(String::kMaxLength < 0x7fffffff); |  | 
| 7174       overflow = true; |  | 
| 7175     } |  | 
| 7176   } |  | 
| 7177   if (overflow) { |  | 
| 7178     // Throw an exception if the resulting string is too large. See |  | 
| 7179     // https://code.google.com/p/chromium/issues/detail?id=336820 |  | 
| 7180     // for details. |  | 
| 7181     THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError()); |  | 
| 7182   } |  | 
| 7183 |  | 
| 7184   if (is_one_byte) { |  | 
| 7185     Handle<SeqOneByteString> result = isolate->factory() |  | 
| 7186                                           ->NewRawOneByteString(string_length) |  | 
| 7187                                           .ToHandleChecked(); |  | 
| 7188     JoinSparseArrayWithSeparator<uint8_t>( |  | 
| 7189         FixedArray::cast(elements_array->elements()), elements_length, |  | 
| 7190         array_length, *separator, |  | 
| 7191         Vector<uint8_t>(result->GetChars(), string_length)); |  | 
| 7192     return *result; |  | 
| 7193   } else { |  | 
| 7194     Handle<SeqTwoByteString> result = isolate->factory() |  | 
| 7195                                           ->NewRawTwoByteString(string_length) |  | 
| 7196                                           .ToHandleChecked(); |  | 
| 7197     JoinSparseArrayWithSeparator<uc16>( |  | 
| 7198         FixedArray::cast(elements_array->elements()), elements_length, |  | 
| 7199         array_length, *separator, |  | 
| 7200         Vector<uc16>(result->GetChars(), string_length)); |  | 
| 7201     return *result; |  | 
| 7202   } |  | 
| 7203 } |  | 
| 7204 |  | 
| 7205 |  | 
| 7206 RUNTIME_FUNCTION(Runtime_NumberOr) { | 4667 RUNTIME_FUNCTION(Runtime_NumberOr) { | 
| 7207   HandleScope scope(isolate); | 4668   HandleScope scope(isolate); | 
| 7208   DCHECK(args.length() == 2); | 4669   DCHECK(args.length() == 2); | 
| 7209 | 4670 | 
| 7210   CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | 4671   CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | 
| 7211   CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | 4672   CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | 
| 7212   return *isolate->factory()->NewNumberFromInt(x | y); | 4673   return *isolate->factory()->NewNumberFromInt(x | y); | 
| 7213 } | 4674 } | 
| 7214 | 4675 | 
| 7215 | 4676 | 
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 7276   Object* result; | 4737   Object* result; | 
| 7277   if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) { | 4738   if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) { | 
| 7278     result = Smi::FromInt(EQUAL); | 4739     result = Smi::FromInt(EQUAL); | 
| 7279   } else { | 4740   } else { | 
| 7280     result = Smi::FromInt(NOT_EQUAL); | 4741     result = Smi::FromInt(NOT_EQUAL); | 
| 7281   } | 4742   } | 
| 7282   return result; | 4743   return result; | 
| 7283 } | 4744 } | 
| 7284 | 4745 | 
| 7285 | 4746 | 
| 7286 RUNTIME_FUNCTION(Runtime_StringEquals) { |  | 
| 7287   HandleScope handle_scope(isolate); |  | 
| 7288   DCHECK(args.length() == 2); |  | 
| 7289 |  | 
| 7290   CONVERT_ARG_HANDLE_CHECKED(String, x, 0); |  | 
| 7291   CONVERT_ARG_HANDLE_CHECKED(String, y, 1); |  | 
| 7292 |  | 
| 7293   bool not_equal = !String::Equals(x, y); |  | 
| 7294   // This is slightly convoluted because the value that signifies |  | 
| 7295   // equality is 0 and inequality is 1 so we have to negate the result |  | 
| 7296   // from String::Equals. |  | 
| 7297   DCHECK(not_equal == 0 || not_equal == 1); |  | 
| 7298   STATIC_ASSERT(EQUAL == 0); |  | 
| 7299   STATIC_ASSERT(NOT_EQUAL == 1); |  | 
| 7300   return Smi::FromInt(not_equal); |  | 
| 7301 } |  | 
| 7302 |  | 
| 7303 |  | 
| 7304 RUNTIME_FUNCTION(Runtime_NumberCompare) { | 4747 RUNTIME_FUNCTION(Runtime_NumberCompare) { | 
| 7305   SealHandleScope shs(isolate); | 4748   SealHandleScope shs(isolate); | 
| 7306   DCHECK(args.length() == 3); | 4749   DCHECK(args.length() == 3); | 
| 7307 | 4750 | 
| 7308   CONVERT_DOUBLE_ARG_CHECKED(x, 0); | 4751   CONVERT_DOUBLE_ARG_CHECKED(x, 0); | 
| 7309   CONVERT_DOUBLE_ARG_CHECKED(y, 1); | 4752   CONVERT_DOUBLE_ARG_CHECKED(y, 1); | 
| 7310   CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2) | 4753   CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2) | 
| 7311   if (std::isnan(x) || std::isnan(y)) return *uncomparable_result; | 4754   if (std::isnan(x) || std::isnan(y)) return *uncomparable_result; | 
| 7312   if (x == y) return Smi::FromInt(EQUAL); | 4755   if (x == y) return Smi::FromInt(EQUAL); | 
| 7313   if (isless(x, y)) return Smi::FromInt(LESS); | 4756   if (isless(x, y)) return Smi::FromInt(LESS); | 
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 7384     x_scaled /= 10; | 4827     x_scaled /= 10; | 
| 7385     tie = GREATER; | 4828     tie = GREATER; | 
| 7386   } | 4829   } | 
| 7387 | 4830 | 
| 7388   if (x_scaled < y_scaled) return Smi::FromInt(LESS); | 4831   if (x_scaled < y_scaled) return Smi::FromInt(LESS); | 
| 7389   if (x_scaled > y_scaled) return Smi::FromInt(GREATER); | 4832   if (x_scaled > y_scaled) return Smi::FromInt(GREATER); | 
| 7390   return Smi::FromInt(tie); | 4833   return Smi::FromInt(tie); | 
| 7391 } | 4834 } | 
| 7392 | 4835 | 
| 7393 | 4836 | 
| 7394 RUNTIME_FUNCTION(Runtime_StringCompare) { |  | 
| 7395   HandleScope handle_scope(isolate); |  | 
| 7396   DCHECK(args.length() == 2); |  | 
| 7397 | 4837 | 
| 7398   CONVERT_ARG_HANDLE_CHECKED(String, x, 0); |  | 
| 7399   CONVERT_ARG_HANDLE_CHECKED(String, y, 1); |  | 
| 7400 |  | 
| 7401   isolate->counters()->string_compare_runtime()->Increment(); |  | 
| 7402 |  | 
| 7403   // A few fast case tests before we flatten. |  | 
| 7404   if (x.is_identical_to(y)) return Smi::FromInt(EQUAL); |  | 
| 7405   if (y->length() == 0) { |  | 
| 7406     if (x->length() == 0) return Smi::FromInt(EQUAL); |  | 
| 7407     return Smi::FromInt(GREATER); |  | 
| 7408   } else if (x->length() == 0) { |  | 
| 7409     return Smi::FromInt(LESS); |  | 
| 7410   } |  | 
| 7411 |  | 
| 7412   int d = x->Get(0) - y->Get(0); |  | 
| 7413   if (d < 0) |  | 
| 7414     return Smi::FromInt(LESS); |  | 
| 7415   else if (d > 0) |  | 
| 7416     return Smi::FromInt(GREATER); |  | 
| 7417 |  | 
| 7418   // Slow case. |  | 
| 7419   x = String::Flatten(x); |  | 
| 7420   y = String::Flatten(y); |  | 
| 7421 |  | 
| 7422   DisallowHeapAllocation no_gc; |  | 
| 7423   Object* equal_prefix_result = Smi::FromInt(EQUAL); |  | 
| 7424   int prefix_length = x->length(); |  | 
| 7425   if (y->length() < prefix_length) { |  | 
| 7426     prefix_length = y->length(); |  | 
| 7427     equal_prefix_result = Smi::FromInt(GREATER); |  | 
| 7428   } else if (y->length() > prefix_length) { |  | 
| 7429     equal_prefix_result = Smi::FromInt(LESS); |  | 
| 7430   } |  | 
| 7431   int r; |  | 
| 7432   String::FlatContent x_content = x->GetFlatContent(); |  | 
| 7433   String::FlatContent y_content = y->GetFlatContent(); |  | 
| 7434   if (x_content.IsOneByte()) { |  | 
| 7435     Vector<const uint8_t> x_chars = x_content.ToOneByteVector(); |  | 
| 7436     if (y_content.IsOneByte()) { |  | 
| 7437       Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); |  | 
| 7438       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |  | 
| 7439     } else { |  | 
| 7440       Vector<const uc16> y_chars = y_content.ToUC16Vector(); |  | 
| 7441       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |  | 
| 7442     } |  | 
| 7443   } else { |  | 
| 7444     Vector<const uc16> x_chars = x_content.ToUC16Vector(); |  | 
| 7445     if (y_content.IsOneByte()) { |  | 
| 7446       Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); |  | 
| 7447       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |  | 
| 7448     } else { |  | 
| 7449       Vector<const uc16> y_chars = y_content.ToUC16Vector(); |  | 
| 7450       r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); |  | 
| 7451     } |  | 
| 7452   } |  | 
| 7453   Object* result; |  | 
| 7454   if (r == 0) { |  | 
| 7455     result = equal_prefix_result; |  | 
| 7456   } else { |  | 
| 7457     result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); |  | 
| 7458   } |  | 
| 7459   return result; |  | 
| 7460 } |  | 
| 7461 | 4838 | 
| 7462 | 4839 | 
| 7463 #define RUNTIME_UNARY_MATH(Name, name)                       \ | 4840 #define RUNTIME_UNARY_MATH(Name, name)                       \ | 
| 7464   RUNTIME_FUNCTION(Runtime_Math##Name) {                     \ | 4841   RUNTIME_FUNCTION(Runtime_Math##Name) {                     \ | 
| 7465     HandleScope scope(isolate);                              \ | 4842     HandleScope scope(isolate);                              \ | 
| 7466     DCHECK(args.length() == 1);                              \ | 4843     DCHECK(args.length() == 1);                              \ | 
| 7467     isolate->counters()->math_##name()->Increment();         \ | 4844     isolate->counters()->math_##name()->Increment();         \ | 
| 7468     CONVERT_DOUBLE_ARG_CHECKED(x, 0);                        \ | 4845     CONVERT_DOUBLE_ARG_CHECKED(x, 0);                        \ | 
| 7469     return *isolate->factory()->NewHeapNumber(std::name(x)); \ | 4846     return *isolate->factory()->NewHeapNumber(std::name(x)); \ | 
| 7470   } | 4847   } | 
| (...skipping 1983 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 9454 RUNTIME_FUNCTION(Runtime_IsAttachedGlobal) { | 6831 RUNTIME_FUNCTION(Runtime_IsAttachedGlobal) { | 
| 9455   SealHandleScope shs(isolate); | 6832   SealHandleScope shs(isolate); | 
| 9456   DCHECK(args.length() == 1); | 6833   DCHECK(args.length() == 1); | 
| 9457   CONVERT_ARG_CHECKED(Object, global, 0); | 6834   CONVERT_ARG_CHECKED(Object, global, 0); | 
| 9458   if (!global->IsJSGlobalObject()) return isolate->heap()->false_value(); | 6835   if (!global->IsJSGlobalObject()) return isolate->heap()->false_value(); | 
| 9459   return isolate->heap()->ToBoolean( | 6836   return isolate->heap()->ToBoolean( | 
| 9460       !JSGlobalObject::cast(global)->IsDetached()); | 6837       !JSGlobalObject::cast(global)->IsDetached()); | 
| 9461 } | 6838 } | 
| 9462 | 6839 | 
| 9463 | 6840 | 
| 9464 RUNTIME_FUNCTION(Runtime_ParseJson) { |  | 
| 9465   HandleScope scope(isolate); |  | 
| 9466   DCHECK(args.length() == 1); |  | 
| 9467   CONVERT_ARG_HANDLE_CHECKED(String, source, 0); |  | 
| 9468 |  | 
| 9469   source = String::Flatten(source); |  | 
| 9470   // Optimized fast case where we only have Latin1 characters. |  | 
| 9471   Handle<Object> result; |  | 
| 9472   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |  | 
| 9473                                      source->IsSeqOneByteString() |  | 
| 9474                                          ? JsonParser<true>::Parse(source) |  | 
| 9475                                          : JsonParser<false>::Parse(source)); |  | 
| 9476   return *result; |  | 
| 9477 } |  | 
| 9478 |  | 
| 9479 |  | 
| 9480 bool CodeGenerationFromStringsAllowed(Isolate* isolate, | 6841 bool CodeGenerationFromStringsAllowed(Isolate* isolate, | 
| 9481                                       Handle<Context> context) { | 6842                                       Handle<Context> context) { | 
| 9482   DCHECK(context->allow_code_gen_from_strings()->IsFalse()); | 6843   DCHECK(context->allow_code_gen_from_strings()->IsFalse()); | 
| 9483   // Check with callback if set. | 6844   // Check with callback if set. | 
| 9484   AllowCodeGenerationFromStringsCallback callback = | 6845   AllowCodeGenerationFromStringsCallback callback = | 
| 9485       isolate->allow_code_gen_callback(); | 6846       isolate->allow_code_gen_callback(); | 
| 9486   if (callback == NULL) { | 6847   if (callback == NULL) { | 
| 9487     // No callback set and code generation disallowed. | 6848     // No callback set and code generation disallowed. | 
| 9488     return false; | 6849     return false; | 
| 9489   } else { | 6850   } else { | 
| (...skipping 4760 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 14250     THROW_NEW_ERROR_RETURN_FAILURE( | 11611     THROW_NEW_ERROR_RETURN_FAILURE( | 
| 14251         isolate, | 11612         isolate, | 
| 14252         NewTypeError("not_date_object", HandleVector<Object>(NULL, 0))); | 11613         NewTypeError("not_date_object", HandleVector<Object>(NULL, 0))); | 
| 14253   } | 11614   } | 
| 14254   JSDate* date = JSDate::cast(obj); | 11615   JSDate* date = JSDate::cast(obj); | 
| 14255   if (index == 0) return date->value(); | 11616   if (index == 0) return date->value(); | 
| 14256   return JSDate::GetField(date, Smi::FromInt(index)); | 11617   return JSDate::GetField(date, Smi::FromInt(index)); | 
| 14257 } | 11618 } | 
| 14258 | 11619 | 
| 14259 | 11620 | 
| 14260 RUNTIME_FUNCTION(RuntimeReference_StringCharFromCode) { |  | 
| 14261   SealHandleScope shs(isolate); |  | 
| 14262   return __RT_impl_Runtime_CharFromCode(args, isolate); |  | 
| 14263 } |  | 
| 14264 |  | 
| 14265 |  | 
| 14266 RUNTIME_FUNCTION(RuntimeReference_StringCharAt) { |  | 
| 14267   SealHandleScope shs(isolate); |  | 
| 14268   DCHECK(args.length() == 2); |  | 
| 14269   if (!args[0]->IsString()) return Smi::FromInt(0); |  | 
| 14270   if (!args[1]->IsNumber()) return Smi::FromInt(0); |  | 
| 14271   if (std::isinf(args.number_at(1))) return isolate->heap()->empty_string(); |  | 
| 14272   Object* code = __RT_impl_Runtime_StringCharCodeAtRT(args, isolate); |  | 
| 14273   if (code->IsNaN()) return isolate->heap()->empty_string(); |  | 
| 14274   return __RT_impl_Runtime_CharFromCode(Arguments(1, &code), isolate); |  | 
| 14275 } |  | 
| 14276 |  | 
| 14277 |  | 
| 14278 RUNTIME_FUNCTION(RuntimeReference_OneByteSeqStringSetChar) { |  | 
| 14279   SealHandleScope shs(isolate); |  | 
| 14280   DCHECK(args.length() == 3); |  | 
| 14281   CONVERT_INT32_ARG_CHECKED(index, 0); |  | 
| 14282   CONVERT_INT32_ARG_CHECKED(value, 1); |  | 
| 14283   CONVERT_ARG_CHECKED(SeqOneByteString, string, 2); |  | 
| 14284   string->SeqOneByteStringSet(index, value); |  | 
| 14285   return string; |  | 
| 14286 } |  | 
| 14287 |  | 
| 14288 |  | 
| 14289 RUNTIME_FUNCTION(RuntimeReference_TwoByteSeqStringSetChar) { |  | 
| 14290   SealHandleScope shs(isolate); |  | 
| 14291   DCHECK(args.length() == 3); |  | 
| 14292   CONVERT_INT32_ARG_CHECKED(index, 0); |  | 
| 14293   CONVERT_INT32_ARG_CHECKED(value, 1); |  | 
| 14294   CONVERT_ARG_CHECKED(SeqTwoByteString, string, 2); |  | 
| 14295   string->SeqTwoByteStringSet(index, value); |  | 
| 14296   return string; |  | 
| 14297 } |  | 
| 14298 |  | 
| 14299 |  | 
| 14300 RUNTIME_FUNCTION(RuntimeReference_ObjectEquals) { | 11621 RUNTIME_FUNCTION(RuntimeReference_ObjectEquals) { | 
| 14301   SealHandleScope shs(isolate); | 11622   SealHandleScope shs(isolate); | 
| 14302   DCHECK(args.length() == 2); | 11623   DCHECK(args.length() == 2); | 
| 14303   CONVERT_ARG_CHECKED(Object, obj1, 0); | 11624   CONVERT_ARG_CHECKED(Object, obj1, 0); | 
| 14304   CONVERT_ARG_CHECKED(Object, obj2, 1); | 11625   CONVERT_ARG_CHECKED(Object, obj2, 1); | 
| 14305   return isolate->heap()->ToBoolean(obj1 == obj2); | 11626   return isolate->heap()->ToBoolean(obj1 == obj2); | 
| 14306 } | 11627 } | 
| 14307 | 11628 | 
| 14308 | 11629 | 
| 14309 RUNTIME_FUNCTION(RuntimeReference_IsObject) { | 11630 RUNTIME_FUNCTION(RuntimeReference_IsObject) { | 
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 14396 | 11717 | 
| 14397 RUNTIME_FUNCTION(RuntimeReference_ClassOf) { | 11718 RUNTIME_FUNCTION(RuntimeReference_ClassOf) { | 
| 14398   SealHandleScope shs(isolate); | 11719   SealHandleScope shs(isolate); | 
| 14399   DCHECK(args.length() == 1); | 11720   DCHECK(args.length() == 1); | 
| 14400   CONVERT_ARG_CHECKED(Object, obj, 0); | 11721   CONVERT_ARG_CHECKED(Object, obj, 0); | 
| 14401   if (!obj->IsJSReceiver()) return isolate->heap()->null_value(); | 11722   if (!obj->IsJSReceiver()) return isolate->heap()->null_value(); | 
| 14402   return JSReceiver::cast(obj)->class_name(); | 11723   return JSReceiver::cast(obj)->class_name(); | 
| 14403 } | 11724 } | 
| 14404 | 11725 | 
| 14405 | 11726 | 
| 14406 RUNTIME_FUNCTION(RuntimeReference_StringCharCodeAt) { |  | 
| 14407   SealHandleScope shs(isolate); |  | 
| 14408   DCHECK(args.length() == 2); |  | 
| 14409   if (!args[0]->IsString()) return isolate->heap()->undefined_value(); |  | 
| 14410   if (!args[1]->IsNumber()) return isolate->heap()->undefined_value(); |  | 
| 14411   if (std::isinf(args.number_at(1))) return isolate->heap()->nan_value(); |  | 
| 14412   return __RT_impl_Runtime_StringCharCodeAtRT(args, isolate); |  | 
| 14413 } |  | 
| 14414 |  | 
| 14415 |  | 
| 14416 RUNTIME_FUNCTION(RuntimeReference_StringAdd) { |  | 
| 14417   SealHandleScope shs(isolate); |  | 
| 14418   return __RT_impl_Runtime_StringAdd(args, isolate); |  | 
| 14419 } |  | 
| 14420 |  | 
| 14421 |  | 
| 14422 RUNTIME_FUNCTION(RuntimeReference_SubString) { |  | 
| 14423   SealHandleScope shs(isolate); |  | 
| 14424   return __RT_impl_Runtime_SubString(args, isolate); |  | 
| 14425 } |  | 
| 14426 |  | 
| 14427 |  | 
| 14428 RUNTIME_FUNCTION(RuntimeReference_StringCompare) { |  | 
| 14429   SealHandleScope shs(isolate); |  | 
| 14430   return __RT_impl_Runtime_StringCompare(args, isolate); |  | 
| 14431 } |  | 
| 14432 |  | 
| 14433 |  | 
| 14434 RUNTIME_FUNCTION(RuntimeReference_RegExpExec) { |  | 
| 14435   SealHandleScope shs(isolate); |  | 
| 14436   return __RT_impl_Runtime_RegExpExecRT(args, isolate); |  | 
| 14437 } |  | 
| 14438 |  | 
| 14439 |  | 
| 14440 RUNTIME_FUNCTION(RuntimeReference_RegExpConstructResult) { |  | 
| 14441   SealHandleScope shs(isolate); |  | 
| 14442   return __RT_impl_Runtime_RegExpConstructResult(args, isolate); |  | 
| 14443 } |  | 
| 14444 |  | 
| 14445 |  | 
| 14446 RUNTIME_FUNCTION(RuntimeReference_GetFromCache) { | 11727 RUNTIME_FUNCTION(RuntimeReference_GetFromCache) { | 
| 14447   HandleScope scope(isolate); | 11728   HandleScope scope(isolate); | 
| 14448   DCHECK(args.length() == 2); | 11729   DCHECK(args.length() == 2); | 
| 14449   CONVERT_SMI_ARG_CHECKED(id, 0); | 11730   CONVERT_SMI_ARG_CHECKED(id, 0); | 
| 14450   args[0] = isolate->native_context()->jsfunction_result_caches()->get(id); | 11731   args[0] = isolate->native_context()->jsfunction_result_caches()->get(id); | 
| 14451   return __RT_impl_Runtime_GetFromCache(args, isolate); | 11732   return __RT_impl_Runtime_GetFromCache(args, isolate); | 
| 14452 } | 11733 } | 
| 14453 | 11734 | 
| 14454 | 11735 | 
| 14455 RUNTIME_FUNCTION(RuntimeReference_NumberToString) { | 11736 RUNTIME_FUNCTION(RuntimeReference_NumberToString) { | 
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 14537   } | 11818   } | 
| 14538   return NULL; | 11819   return NULL; | 
| 14539 } | 11820 } | 
| 14540 | 11821 | 
| 14541 | 11822 | 
| 14542 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { | 11823 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { | 
| 14543   return &(kIntrinsicFunctions[static_cast<int>(id)]); | 11824   return &(kIntrinsicFunctions[static_cast<int>(id)]); | 
| 14544 } | 11825 } | 
| 14545 } | 11826 } | 
| 14546 }  // namespace v8::internal | 11827 }  // namespace v8::internal | 
| OLD | NEW | 
|---|