// Copyright 2019 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/builtins/builtins-string-gen.h' namespace string { // ES6 #sec-string.prototype.tostring transitioning javascript builtin StringPrototypeToString(js-implicit context: Context)(receiver: Object): Object { return ToThisValue(receiver, kString, 'String.prototype.toString'); } // ES6 #sec-string.prototype.valueof transitioning javascript builtin StringPrototypeValueOf(js-implicit context: Context)(receiver: Object): Object { return ToThisValue(receiver, kString, 'String.prototype.valueOf'); } extern macro StringBuiltinsAssembler::LoadSurrogatePairAt( String, intptr, intptr, constexpr UnicodeEncoding): int32; extern macro StringFromSingleUTF16EncodedCodePoint(int32): String; // This function assumes StringPrimitiveWithNoCustomIteration is true. transitioning builtin StringToList(implicit context: Context)(string: String): JSArray { const kind = PACKED_ELEMENTS; const stringLength: intptr = string.length_intptr; const map: Map = LoadJSArrayElementsMap(kind, LoadNativeContext(context)); const array: JSArray = AllocateJSArray( kind, map, stringLength, SmiTag(stringLength), kAllowLargeObjectAllocation); const elements = UnsafeCast<FixedArray>(array.elements); const encoding = UTF16; let arrayLength: Smi = 0; let i: intptr = 0; while (i < stringLength) { const ch: int32 = LoadSurrogatePairAt(string, stringLength, i, encoding); const value: String = StringFromSingleUTF16EncodedCodePoint(ch); elements[arrayLength] = value; // Increment and continue the loop. i = i + value.length_intptr; arrayLength++; } assert(arrayLength >= 0); assert(SmiTag(stringLength) >= arrayLength); array.length = arrayLength; return array; } transitioning macro GenerateStringAt(implicit context: Context)( receiver: Object, position: Object, methodName: constexpr string): never labels IfInBounds(String, intptr, intptr), IfOutOfBounds { // Check that {receiver} is coercible to Object and convert it to a String. const string: String = ToThisString(receiver, methodName); // Convert the {position} to a Smi and check that it's in bounds of // the {string}. const indexNumber: Number = ToInteger_Inline(context, position, kTruncateMinusZero); if (TaggedIsNotSmi(indexNumber)) goto IfOutOfBounds; const index: intptr = SmiUntag(UnsafeCast<Smi>(indexNumber)); const length: intptr = string.length_intptr; if (Convert<uintptr>(index) >= Convert<uintptr>(length)) goto IfOutOfBounds; goto IfInBounds(string, index, length); } // ES6 #sec-string.prototype.charat transitioning javascript builtin StringPrototypeCharAt( js-implicit context: Context, receiver: Object)(position: Object): Object { try { GenerateStringAt(receiver, position, 'String.prototype.charAt') otherwise IfInBounds, IfOutOfBounds; } label IfInBounds(string: String, index: intptr, _length: intptr) { const code: int32 = StringCharCodeAt(string, index); return StringFromSingleCharCode(code); } label IfOutOfBounds { return kEmptyString; } } // ES6 #sec-string.prototype.charcodeat transitioning javascript builtin StringPrototypeCharCodeAt( js-implicit context: Context, receiver: Object)(position: Object): Object { try { GenerateStringAt(receiver, position, 'String.prototype.charCodeAt') otherwise IfInBounds, IfOutOfBounds; } label IfInBounds(string: String, index: intptr, _length: intptr) { const code: int32 = StringCharCodeAt(string, index); return Convert<Smi>(code); } label IfOutOfBounds { return kNaN; } } // ES6 #sec-string.prototype.codepointat transitioning javascript builtin StringPrototypeCodePointAt( js-implicit context: Context, receiver: Object)(position: Object): Object { try { GenerateStringAt(receiver, position, 'String.prototype.codePointAt') otherwise IfInBounds, IfOutOfBounds; } label IfInBounds(string: String, index: intptr, length: intptr) { // This is always a call to a builtin from Javascript, so we need to // produce UTF32. const code: int32 = LoadSurrogatePairAt(string, length, index, UTF32); return Convert<Smi>(code); } label IfOutOfBounds { return Undefined; } } // ES6 String.prototype.concat(...args) // ES6 #sec-string.prototype.concat transitioning javascript builtin StringPrototypeConcat( js-implicit context: Context, receiver: Object)(...arguments): Object { // Check that {receiver} is coercible to Object and convert it to a String. let string: String = ToThisString(receiver, 'String.prototype.concat'); // Concatenate all the arguments passed to this builtin. const length: intptr = Convert<intptr>(arguments.length); for (let i: intptr = 0; i < length; i++) { const temp: String = ToString_Inline(context, arguments[i]); string = string + temp; } return string; } }