Move string-related runtime functions into separate files.
R=bmeurer@chromium.org Review URL: https://codereview.chromium.org/604703004 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24261 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
4e116f383b
commit
3ef16353ba
5
BUILD.gn
5
BUILD.gn
@ -821,9 +821,14 @@ source_set("v8_base") {
|
||||
"src/runtime-profiler.cc",
|
||||
"src/runtime-profiler.h",
|
||||
"src/runtime/runtime-i18n.cc",
|
||||
"src/runtime/runtime-json.cc",
|
||||
"src/runtime/runtime-regexp.cc",
|
||||
"src/runtime/runtime-strings.cc",
|
||||
"src/runtime/runtime-uri.cc",
|
||||
"src/runtime/runtime-utils.h",
|
||||
"src/runtime/runtime.cc",
|
||||
"src/runtime/runtime.h",
|
||||
"src/runtime/string-builder.h",
|
||||
"src/safepoint-table.cc",
|
||||
"src/safepoint-table.h",
|
||||
"src/sampler.cc",
|
||||
|
54
src/runtime/runtime-json.cc
Normal file
54
src/runtime/runtime-json.cc
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/arguments.h"
|
||||
#include "src/json-parser.h"
|
||||
#include "src/json-stringifier.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
#include "src/runtime/runtime-utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_QuoteJSONString) {
|
||||
HandleScope scope(isolate);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
|
||||
DCHECK(args.length() == 1);
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result, BasicJsonStringifier::StringifyString(isolate, string));
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_BasicJSONStringify) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
||||
BasicJsonStringifier stringifier(isolate);
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
|
||||
stringifier.Stringify(object));
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ParseJson) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
|
||||
|
||||
source = String::Flatten(source);
|
||||
// Optimized fast case where we only have Latin1 characters.
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
|
||||
source->IsSeqOneByteString()
|
||||
? JsonParser<true>::Parse(source)
|
||||
: JsonParser<false>::Parse(source));
|
||||
return *result;
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal
|
1131
src/runtime/runtime-regexp.cc
Normal file
1131
src/runtime/runtime-regexp.cc
Normal file
File diff suppressed because it is too large
Load Diff
1252
src/runtime/runtime-strings.cc
Normal file
1252
src/runtime/runtime-strings.cc
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,20 +1,20 @@
|
||||
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_URI_H_
|
||||
#define V8_URI_H_
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/arguments.h"
|
||||
#include "src/conversions.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
#include "src/runtime/runtime-utils.h"
|
||||
#include "src/string-search.h"
|
||||
#include "src/utils.h"
|
||||
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
template <typename Char>
|
||||
static INLINE(Vector<const Char> GetCharVector(Handle<String> string));
|
||||
|
||||
@ -37,42 +37,41 @@ Vector<const uc16> GetCharVector(Handle<String> string) {
|
||||
|
||||
class URIUnescape : public AllStatic {
|
||||
public:
|
||||
template<typename Char>
|
||||
template <typename Char>
|
||||
MUST_USE_RESULT static MaybeHandle<String> Unescape(Isolate* isolate,
|
||||
Handle<String> source);
|
||||
|
||||
private:
|
||||
static const signed char kHexValue['g'];
|
||||
|
||||
template<typename Char>
|
||||
MUST_USE_RESULT static MaybeHandle<String> UnescapeSlow(
|
||||
Isolate* isolate, Handle<String> string, int start_index);
|
||||
template <typename Char>
|
||||
MUST_USE_RESULT static MaybeHandle<String> UnescapeSlow(Isolate* isolate,
|
||||
Handle<String> string,
|
||||
int start_index);
|
||||
|
||||
static INLINE(int TwoDigitHex(uint16_t character1, uint16_t character2));
|
||||
|
||||
template <typename Char>
|
||||
static INLINE(int UnescapeChar(Vector<const Char> vector,
|
||||
int i,
|
||||
int length,
|
||||
static INLINE(int UnescapeChar(Vector<const Char> vector, int i, int length,
|
||||
int* step));
|
||||
};
|
||||
|
||||
|
||||
const signed char URIUnescape::kHexValue[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15 };
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -0, 1, 2, 3, 4, 5,
|
||||
6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15};
|
||||
|
||||
|
||||
template<typename Char>
|
||||
template <typename Char>
|
||||
MaybeHandle<String> URIUnescape::Unescape(Isolate* isolate,
|
||||
Handle<String> source) {
|
||||
int index;
|
||||
{ DisallowHeapAllocation no_allocation;
|
||||
{
|
||||
DisallowHeapAllocation no_allocation;
|
||||
StringSearch<uint8_t, Char> search(isolate, STATIC_CHAR_VECTOR("%"));
|
||||
index = search.Search(GetCharVector<Char>(source), 0);
|
||||
if (index < 0) return source;
|
||||
@ -82,18 +81,20 @@ MaybeHandle<String> URIUnescape::Unescape(Isolate* isolate,
|
||||
|
||||
|
||||
template <typename Char>
|
||||
MaybeHandle<String> URIUnescape::UnescapeSlow(
|
||||
Isolate* isolate, Handle<String> string, int start_index) {
|
||||
MaybeHandle<String> URIUnescape::UnescapeSlow(Isolate* isolate,
|
||||
Handle<String> string,
|
||||
int start_index) {
|
||||
bool one_byte = true;
|
||||
int length = string->length();
|
||||
|
||||
int unescaped_length = 0;
|
||||
{ DisallowHeapAllocation no_allocation;
|
||||
{
|
||||
DisallowHeapAllocation no_allocation;
|
||||
Vector<const Char> vector = GetCharVector<Char>(string);
|
||||
for (int i = start_index; i < length; unescaped_length++) {
|
||||
int step;
|
||||
if (UnescapeChar(vector, i, length, &step) >
|
||||
String::kMaxOneByteCharCode) {
|
||||
String::kMaxOneByteCharCode) {
|
||||
one_byte = false;
|
||||
}
|
||||
i += step;
|
||||
@ -108,8 +109,9 @@ MaybeHandle<String> URIUnescape::UnescapeSlow(
|
||||
Handle<String> second_part;
|
||||
DCHECK(unescaped_length <= String::kMaxLength);
|
||||
if (one_byte) {
|
||||
Handle<SeqOneByteString> dest = isolate->factory()->NewRawOneByteString(
|
||||
unescaped_length).ToHandleChecked();
|
||||
Handle<SeqOneByteString> dest = isolate->factory()
|
||||
->NewRawOneByteString(unescaped_length)
|
||||
.ToHandleChecked();
|
||||
DisallowHeapAllocation no_allocation;
|
||||
Vector<const Char> vector = GetCharVector<Char>(string);
|
||||
for (int i = start_index; i < length; dest_position++) {
|
||||
@ -120,8 +122,9 @@ MaybeHandle<String> URIUnescape::UnescapeSlow(
|
||||
}
|
||||
second_part = dest;
|
||||
} else {
|
||||
Handle<SeqTwoByteString> dest = isolate->factory()->NewRawTwoByteString(
|
||||
unescaped_length).ToHandleChecked();
|
||||
Handle<SeqTwoByteString> dest = isolate->factory()
|
||||
->NewRawTwoByteString(unescaped_length)
|
||||
.ToHandleChecked();
|
||||
DisallowHeapAllocation no_allocation;
|
||||
Vector<const Char> vector = GetCharVector<Char>(string);
|
||||
for (int i = start_index; i < length; dest_position++) {
|
||||
@ -148,26 +151,18 @@ int URIUnescape::TwoDigitHex(uint16_t character1, uint16_t character2) {
|
||||
|
||||
|
||||
template <typename Char>
|
||||
int URIUnescape::UnescapeChar(Vector<const Char> vector,
|
||||
int i,
|
||||
int length,
|
||||
int URIUnescape::UnescapeChar(Vector<const Char> vector, int i, int length,
|
||||
int* step) {
|
||||
uint16_t character = vector[i];
|
||||
int32_t hi = 0;
|
||||
int32_t lo = 0;
|
||||
if (character == '%' &&
|
||||
i <= length - 6 &&
|
||||
vector[i + 1] == 'u' &&
|
||||
(hi = TwoDigitHex(vector[i + 2],
|
||||
vector[i + 3])) != -1 &&
|
||||
(lo = TwoDigitHex(vector[i + 4],
|
||||
vector[i + 5])) != -1) {
|
||||
if (character == '%' && i <= length - 6 && vector[i + 1] == 'u' &&
|
||||
(hi = TwoDigitHex(vector[i + 2], vector[i + 3])) != -1 &&
|
||||
(lo = TwoDigitHex(vector[i + 4], vector[i + 5])) != -1) {
|
||||
*step = 6;
|
||||
return (hi << 8) + lo;
|
||||
} else if (character == '%' &&
|
||||
i <= length - 3 &&
|
||||
(lo = TwoDigitHex(vector[i + 1],
|
||||
vector[i + 2])) != -1) {
|
||||
} else if (character == '%' && i <= length - 3 &&
|
||||
(lo = TwoDigitHex(vector[i + 1], vector[i + 2])) != -1) {
|
||||
*step = 3;
|
||||
return lo;
|
||||
} else {
|
||||
@ -179,7 +174,7 @@ int URIUnescape::UnescapeChar(Vector<const Char> vector,
|
||||
|
||||
class URIEscape : public AllStatic {
|
||||
public:
|
||||
template<typename Char>
|
||||
template <typename Char>
|
||||
MUST_USE_RESULT static MaybeHandle<String> Escape(Isolate* isolate,
|
||||
Handle<String> string);
|
||||
|
||||
@ -206,31 +201,27 @@ const char URIEscape::kHexChars[] = "0123456789ABCDEF";
|
||||
// }
|
||||
|
||||
const char URIEscape::kNotEscaped[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
|
||||
template<typename Char>
|
||||
template <typename Char>
|
||||
MaybeHandle<String> URIEscape::Escape(Isolate* isolate, Handle<String> string) {
|
||||
DCHECK(string->IsFlat());
|
||||
int escaped_length = 0;
|
||||
int length = string->length();
|
||||
|
||||
{ DisallowHeapAllocation no_allocation;
|
||||
{
|
||||
DisallowHeapAllocation no_allocation;
|
||||
Vector<const Char> vector = GetCharVector<Char>(string);
|
||||
for (int i = 0; i < length; i++) {
|
||||
uint16_t c = vector[i];
|
||||
@ -243,7 +234,7 @@ MaybeHandle<String> URIEscape::Escape(Isolate* isolate, Handle<String> string) {
|
||||
}
|
||||
|
||||
// We don't allow strings that are longer than a maximal length.
|
||||
DCHECK(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
|
||||
DCHECK(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
|
||||
if (escaped_length > String::kMaxLength) break; // Provoke exception.
|
||||
}
|
||||
}
|
||||
@ -253,30 +244,30 @@ MaybeHandle<String> URIEscape::Escape(Isolate* isolate, Handle<String> string) {
|
||||
|
||||
Handle<SeqOneByteString> dest;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, dest,
|
||||
isolate->factory()->NewRawOneByteString(escaped_length),
|
||||
isolate, dest, isolate->factory()->NewRawOneByteString(escaped_length),
|
||||
String);
|
||||
int dest_position = 0;
|
||||
|
||||
{ DisallowHeapAllocation no_allocation;
|
||||
{
|
||||
DisallowHeapAllocation no_allocation;
|
||||
Vector<const Char> vector = GetCharVector<Char>(string);
|
||||
for (int i = 0; i < length; i++) {
|
||||
uint16_t c = vector[i];
|
||||
if (c >= 256) {
|
||||
dest->SeqOneByteStringSet(dest_position, '%');
|
||||
dest->SeqOneByteStringSet(dest_position+1, 'u');
|
||||
dest->SeqOneByteStringSet(dest_position+2, kHexChars[c >> 12]);
|
||||
dest->SeqOneByteStringSet(dest_position+3, kHexChars[(c >> 8) & 0xf]);
|
||||
dest->SeqOneByteStringSet(dest_position+4, kHexChars[(c >> 4) & 0xf]);
|
||||
dest->SeqOneByteStringSet(dest_position+5, kHexChars[c & 0xf]);
|
||||
dest->SeqOneByteStringSet(dest_position + 1, 'u');
|
||||
dest->SeqOneByteStringSet(dest_position + 2, kHexChars[c >> 12]);
|
||||
dest->SeqOneByteStringSet(dest_position + 3, kHexChars[(c >> 8) & 0xf]);
|
||||
dest->SeqOneByteStringSet(dest_position + 4, kHexChars[(c >> 4) & 0xf]);
|
||||
dest->SeqOneByteStringSet(dest_position + 5, kHexChars[c & 0xf]);
|
||||
dest_position += 6;
|
||||
} else if (IsNotEscaped(c)) {
|
||||
dest->SeqOneByteStringSet(dest_position, c);
|
||||
dest_position++;
|
||||
} else {
|
||||
dest->SeqOneByteStringSet(dest_position, '%');
|
||||
dest->SeqOneByteStringSet(dest_position+1, kHexChars[c >> 4]);
|
||||
dest->SeqOneByteStringSet(dest_position+2, kHexChars[c & 0xf]);
|
||||
dest->SeqOneByteStringSet(dest_position + 1, kHexChars[c >> 4]);
|
||||
dest->SeqOneByteStringSet(dest_position + 2, kHexChars[c & 0xf]);
|
||||
dest_position += 3;
|
||||
}
|
||||
}
|
||||
@ -285,6 +276,34 @@ MaybeHandle<String> URIEscape::Escape(Isolate* isolate, Handle<String> string) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_URI_H_
|
||||
RUNTIME_FUNCTION(Runtime_URIEscape) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
|
||||
Handle<String> string = String::Flatten(source);
|
||||
DCHECK(string->IsFlat());
|
||||
Handle<String> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result, string->IsOneByteRepresentationUnderneath()
|
||||
? URIEscape::Escape<uint8_t>(isolate, source)
|
||||
: URIEscape::Escape<uc16>(isolate, source));
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_URIUnescape) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
|
||||
Handle<String> string = String::Flatten(source);
|
||||
DCHECK(string->IsFlat());
|
||||
Handle<String> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result, string->IsOneByteRepresentationUnderneath()
|
||||
? URIUnescape::Unescape<uint8_t>(isolate, source)
|
||||
: URIUnescape::Unescape<uc16>(isolate, source));
|
||||
return *result;
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal
|
File diff suppressed because it is too large
Load Diff
@ -822,8 +822,6 @@ class Runtime : public AllStatic {
|
||||
static int StringMatch(Isolate* isolate, Handle<String> sub,
|
||||
Handle<String> pat, int index);
|
||||
|
||||
static bool IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch);
|
||||
|
||||
// TODO(1240886): Some of the following methods are *not* handle safe, but
|
||||
// accept handle arguments. This seems fragile.
|
||||
|
||||
|
296
src/runtime/string-builder.h
Normal file
296
src/runtime/string-builder.h
Normal file
@ -0,0 +1,296 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_STRING_BUILDER_H_
|
||||
#define V8_STRING_BUILDER_H_
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
const int kStringBuilderConcatHelperLengthBits = 11;
|
||||
const int kStringBuilderConcatHelperPositionBits = 19;
|
||||
|
||||
typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
|
||||
StringBuilderSubstringLength;
|
||||
typedef BitField<int, kStringBuilderConcatHelperLengthBits,
|
||||
kStringBuilderConcatHelperPositionBits>
|
||||
StringBuilderSubstringPosition;
|
||||
|
||||
|
||||
template <typename sinkchar>
|
||||
static inline void StringBuilderConcatHelper(String* special, sinkchar* sink,
|
||||
FixedArray* fixed_array,
|
||||
int array_length) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
int position = 0;
|
||||
for (int i = 0; i < array_length; i++) {
|
||||
Object* element = fixed_array->get(i);
|
||||
if (element->IsSmi()) {
|
||||
// Smi encoding of position and length.
|
||||
int encoded_slice = Smi::cast(element)->value();
|
||||
int pos;
|
||||
int len;
|
||||
if (encoded_slice > 0) {
|
||||
// Position and length encoded in one smi.
|
||||
pos = StringBuilderSubstringPosition::decode(encoded_slice);
|
||||
len = StringBuilderSubstringLength::decode(encoded_slice);
|
||||
} else {
|
||||
// Position and length encoded in two smis.
|
||||
Object* obj = fixed_array->get(++i);
|
||||
DCHECK(obj->IsSmi());
|
||||
pos = Smi::cast(obj)->value();
|
||||
len = -encoded_slice;
|
||||
}
|
||||
String::WriteToFlat(special, sink + position, pos, pos + len);
|
||||
position += len;
|
||||
} else {
|
||||
String* string = String::cast(element);
|
||||
int element_length = string->length();
|
||||
String::WriteToFlat(string, sink + position, 0, element_length);
|
||||
position += element_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Returns the result length of the concatenation.
|
||||
// On illegal argument, -1 is returned.
|
||||
static inline int StringBuilderConcatLength(int special_length,
|
||||
FixedArray* fixed_array,
|
||||
int array_length, bool* one_byte) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
int position = 0;
|
||||
for (int i = 0; i < array_length; i++) {
|
||||
int increment = 0;
|
||||
Object* elt = fixed_array->get(i);
|
||||
if (elt->IsSmi()) {
|
||||
// Smi encoding of position and length.
|
||||
int smi_value = Smi::cast(elt)->value();
|
||||
int pos;
|
||||
int len;
|
||||
if (smi_value > 0) {
|
||||
// Position and length encoded in one smi.
|
||||
pos = StringBuilderSubstringPosition::decode(smi_value);
|
||||
len = StringBuilderSubstringLength::decode(smi_value);
|
||||
} else {
|
||||
// Position and length encoded in two smis.
|
||||
len = -smi_value;
|
||||
// Get the position and check that it is a positive smi.
|
||||
i++;
|
||||
if (i >= array_length) return -1;
|
||||
Object* next_smi = fixed_array->get(i);
|
||||
if (!next_smi->IsSmi()) return -1;
|
||||
pos = Smi::cast(next_smi)->value();
|
||||
if (pos < 0) return -1;
|
||||
}
|
||||
DCHECK(pos >= 0);
|
||||
DCHECK(len >= 0);
|
||||
if (pos > special_length || len > special_length - pos) return -1;
|
||||
increment = len;
|
||||
} else if (elt->IsString()) {
|
||||
String* element = String::cast(elt);
|
||||
int element_length = element->length();
|
||||
increment = element_length;
|
||||
if (*one_byte && !element->HasOnlyOneByteChars()) {
|
||||
*one_byte = false;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
if (increment > String::kMaxLength - position) {
|
||||
return kMaxInt; // Provoke throw on allocation.
|
||||
}
|
||||
position += increment;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
class FixedArrayBuilder {
|
||||
public:
|
||||
explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
|
||||
: array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
|
||||
length_(0),
|
||||
has_non_smi_elements_(false) {
|
||||
// Require a non-zero initial size. Ensures that doubling the size to
|
||||
// extend the array will work.
|
||||
DCHECK(initial_capacity > 0);
|
||||
}
|
||||
|
||||
explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
|
||||
: array_(backing_store), length_(0), has_non_smi_elements_(false) {
|
||||
// Require a non-zero initial size. Ensures that doubling the size to
|
||||
// extend the array will work.
|
||||
DCHECK(backing_store->length() > 0);
|
||||
}
|
||||
|
||||
bool HasCapacity(int elements) {
|
||||
int length = array_->length();
|
||||
int required_length = length_ + elements;
|
||||
return (length >= required_length);
|
||||
}
|
||||
|
||||
void EnsureCapacity(int elements) {
|
||||
int length = array_->length();
|
||||
int required_length = length_ + elements;
|
||||
if (length < required_length) {
|
||||
int new_length = length;
|
||||
do {
|
||||
new_length *= 2;
|
||||
} while (new_length < required_length);
|
||||
Handle<FixedArray> extended_array =
|
||||
array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
|
||||
array_->CopyTo(0, *extended_array, 0, length_);
|
||||
array_ = extended_array;
|
||||
}
|
||||
}
|
||||
|
||||
void Add(Object* value) {
|
||||
DCHECK(!value->IsSmi());
|
||||
DCHECK(length_ < capacity());
|
||||
array_->set(length_, value);
|
||||
length_++;
|
||||
has_non_smi_elements_ = true;
|
||||
}
|
||||
|
||||
void Add(Smi* value) {
|
||||
DCHECK(value->IsSmi());
|
||||
DCHECK(length_ < capacity());
|
||||
array_->set(length_, value);
|
||||
length_++;
|
||||
}
|
||||
|
||||
Handle<FixedArray> array() { return array_; }
|
||||
|
||||
int length() { return length_; }
|
||||
|
||||
int capacity() { return array_->length(); }
|
||||
|
||||
Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
|
||||
JSArray::SetContent(target_array, array_);
|
||||
target_array->set_length(Smi::FromInt(length_));
|
||||
return target_array;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Handle<FixedArray> array_;
|
||||
int length_;
|
||||
bool has_non_smi_elements_;
|
||||
};
|
||||
|
||||
|
||||
class ReplacementStringBuilder {
|
||||
public:
|
||||
ReplacementStringBuilder(Heap* heap, Handle<String> subject,
|
||||
int estimated_part_count)
|
||||
: heap_(heap),
|
||||
array_builder_(heap->isolate(), estimated_part_count),
|
||||
subject_(subject),
|
||||
character_count_(0),
|
||||
is_one_byte_(subject->IsOneByteRepresentation()) {
|
||||
// Require a non-zero initial size. Ensures that doubling the size to
|
||||
// extend the array will work.
|
||||
DCHECK(estimated_part_count > 0);
|
||||
}
|
||||
|
||||
static inline void AddSubjectSlice(FixedArrayBuilder* builder, int from,
|
||||
int to) {
|
||||
DCHECK(from >= 0);
|
||||
int length = to - from;
|
||||
DCHECK(length > 0);
|
||||
if (StringBuilderSubstringLength::is_valid(length) &&
|
||||
StringBuilderSubstringPosition::is_valid(from)) {
|
||||
int encoded_slice = StringBuilderSubstringLength::encode(length) |
|
||||
StringBuilderSubstringPosition::encode(from);
|
||||
builder->Add(Smi::FromInt(encoded_slice));
|
||||
} else {
|
||||
// Otherwise encode as two smis.
|
||||
builder->Add(Smi::FromInt(-length));
|
||||
builder->Add(Smi::FromInt(from));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EnsureCapacity(int elements) { array_builder_.EnsureCapacity(elements); }
|
||||
|
||||
|
||||
void AddSubjectSlice(int from, int to) {
|
||||
AddSubjectSlice(&array_builder_, from, to);
|
||||
IncrementCharacterCount(to - from);
|
||||
}
|
||||
|
||||
|
||||
void AddString(Handle<String> string) {
|
||||
int length = string->length();
|
||||
DCHECK(length > 0);
|
||||
AddElement(*string);
|
||||
if (!string->IsOneByteRepresentation()) {
|
||||
is_one_byte_ = false;
|
||||
}
|
||||
IncrementCharacterCount(length);
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<String> ToString() {
|
||||
Isolate* isolate = heap_->isolate();
|
||||
if (array_builder_.length() == 0) {
|
||||
return isolate->factory()->empty_string();
|
||||
}
|
||||
|
||||
Handle<String> joined_string;
|
||||
if (is_one_byte_) {
|
||||
Handle<SeqOneByteString> seq;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, seq,
|
||||
isolate->factory()->NewRawOneByteString(character_count_), String);
|
||||
|
||||
DisallowHeapAllocation no_gc;
|
||||
uint8_t* char_buffer = seq->GetChars();
|
||||
StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
|
||||
array_builder_.length());
|
||||
joined_string = Handle<String>::cast(seq);
|
||||
} else {
|
||||
// Two-byte.
|
||||
Handle<SeqTwoByteString> seq;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, seq,
|
||||
isolate->factory()->NewRawTwoByteString(character_count_), String);
|
||||
|
||||
DisallowHeapAllocation no_gc;
|
||||
uc16* char_buffer = seq->GetChars();
|
||||
StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
|
||||
array_builder_.length());
|
||||
joined_string = Handle<String>::cast(seq);
|
||||
}
|
||||
return joined_string;
|
||||
}
|
||||
|
||||
|
||||
void IncrementCharacterCount(int by) {
|
||||
if (character_count_ > String::kMaxLength - by) {
|
||||
STATIC_ASSERT(String::kMaxLength < kMaxInt);
|
||||
character_count_ = kMaxInt;
|
||||
} else {
|
||||
character_count_ += by;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void AddElement(Object* element) {
|
||||
DCHECK(element->IsSmi() || element->IsString());
|
||||
DCHECK(array_builder_.capacity() > array_builder_.length());
|
||||
array_builder_.Add(element);
|
||||
}
|
||||
|
||||
Heap* heap_;
|
||||
FixedArrayBuilder array_builder_;
|
||||
Handle<String> subject_;
|
||||
int character_count_;
|
||||
bool is_one_byte_;
|
||||
};
|
||||
}
|
||||
} // namespace v8::internal
|
||||
|
||||
#endif // V8_STRING_BUILDER_H_
|
@ -732,9 +732,14 @@
|
||||
'../../src/runtime-profiler.cc',
|
||||
'../../src/runtime-profiler.h',
|
||||
'../../src/runtime/runtime-i18n.cc',
|
||||
'../../src/runtime/runtime-json.cc',
|
||||
'../../src/runtime/runtime-regexp.cc',
|
||||
'../../src/runtime/runtime-strings.cc',
|
||||
'../../src/runtime/runtime-uri.cc',
|
||||
'../../src/runtime/runtime-utils.h',
|
||||
'../../src/runtime/runtime.cc',
|
||||
'../../src/runtime/runtime.h',
|
||||
'../../src/runtime/string-builder.h',
|
||||
'../../src/safepoint-table.cc',
|
||||
'../../src/safepoint-table.h',
|
||||
'../../src/sampler.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user