Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Side by Side Diff: src/runtime/runtime.cc

Issue 604703004: Move string-related runtime functions into separate files. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/runtime/runtime.h ('k') | src/runtime/runtime-json.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/runtime/runtime.h ('k') | src/runtime/runtime-json.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698