Index: src/builtins.cc |
diff --git a/src/builtins.cc b/src/builtins.cc |
index e5b6660c394d0d29bae2b179f98bbc923efaae61..5e49eb7e0ab135c1343d5f994ba1a08a9cfe22b4 100644 |
--- a/src/builtins.cc |
+++ b/src/builtins.cc |
@@ -4633,7 +4633,7 @@ void Builtins::Generate_StringFromCharCode(CodeStubAssembler* assembler) { |
Node* code = assembler->Parameter(1); |
Node* context = assembler->Parameter(4); |
- // Check if we have exactly one arguments (plus the implicit receiver), i.e. |
+ // Check if we have exactly one argument (plus the implicit receiver), i.e. |
// if the parent frame is not an arguments adaptor frame. |
Label if_oneargument(assembler), if_notoneargument(assembler); |
Node* parent_frame_pointer = assembler->LoadParentFramePointer(); |
@@ -4811,6 +4811,99 @@ void Builtins::Generate_StringFromCharCode(CodeStubAssembler* assembler) { |
} |
} |
+namespace { // for String.fromCodePoint |
+ |
+bool IsValidCodePoint(Isolate* isolate, Handle<Object> value) { |
+ if (!value->IsNumber() && !Object::ToNumber(value).ToHandle(&value)) { |
+ return false; |
+ } |
+ |
+ if (Object::ToInteger(isolate, value).ToHandleChecked()->Number() != |
+ value->Number()) { |
+ return false; |
+ } |
+ |
+ if (value->Number() < 0 || value->Number() > 0x10FFFF) { |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+uc32 NextCodePoint(Isolate* isolate, BuiltinArguments args, int index) { |
+ Handle<Object> value = args.at<Object>(1 + index); |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::ToNumber(value), -1); |
+ if (!IsValidCodePoint(isolate, value)) { |
+ isolate->Throw(*isolate->factory()->NewRangeError( |
+ MessageTemplate::kInvalidCodePoint, value)); |
+ return -1; |
+ } |
+ return DoubleToUint32(value->Number()); |
+} |
+ |
+} // namespace |
+ |
+// ES6 section 21.1.2.2 String.fromCodePoint ( ...codePoints ) |
+BUILTIN(StringFromCodePoint) { |
+ HandleScope scope(isolate); |
+ int const length = args.length() - 1; |
+ if (length == 0) return isolate->heap()->empty_string(); |
+ DCHECK_LT(0, length); |
+ |
+ // Optimistically assume that the resulting String contains only one byte |
+ // characters. |
+ List<uint8_t> one_byte_buffer(length); |
+ uc32 code = 0; |
+ int index; |
+ for (index = 0; index < length; index++) { |
+ code = NextCodePoint(isolate, args, index); |
+ if (code < 0) { |
+ return isolate->heap()->exception(); |
+ } |
+ if (code > String::kMaxOneByteCharCode) { |
+ break; |
+ } |
+ one_byte_buffer.Add(code); |
+ } |
+ |
+ if (index == length) { |
+ RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromOneByte( |
+ one_byte_buffer.ToConstVector())); |
+ } |
+ |
+ List<uc16> two_byte_buffer(length - index); |
+ |
+ while (true) { |
+ if (code <= unibrow::Utf16::kMaxNonSurrogateCharCode) { |
+ two_byte_buffer.Add(code); |
+ } else { |
+ two_byte_buffer.Add(unibrow::Utf16::LeadSurrogate(code)); |
+ two_byte_buffer.Add(unibrow::Utf16::TrailSurrogate(code)); |
+ } |
+ |
+ if (++index == length) { |
+ break; |
+ } |
+ code = NextCodePoint(isolate, args, index); |
+ if (code < 0) { |
+ return isolate->heap()->exception(); |
+ } |
+ } |
+ |
+ Handle<SeqTwoByteString> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, result, |
+ isolate->factory()->NewRawTwoByteString(one_byte_buffer.length() + |
+ two_byte_buffer.length())); |
+ |
+ CopyChars(result->GetChars(), one_byte_buffer.ToConstVector().start(), |
+ one_byte_buffer.length()); |
+ CopyChars(result->GetChars() + one_byte_buffer.length(), |
+ two_byte_buffer.ToConstVector().start(), two_byte_buffer.length()); |
+ |
+ return *result; |
+} |
+ |
// ES6 section 21.1.3.1 String.prototype.charAt ( pos ) |
void Builtins::Generate_StringPrototypeCharAt(CodeStubAssembler* assembler) { |
typedef CodeStubAssembler::Label Label; |