/ runtime / StringConstructor.cpp
StringConstructor.cpp
  1  /*
  2   *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  3   *  Copyright (C) 2004-2019 Apple Inc. All rights reserved.
  4   *
  5   *  This library is free software; you can redistribute it and/or
  6   *  modify it under the terms of the GNU Lesser General Public
  7   *  License as published by the Free Software Foundation; either
  8   *  version 2 of the License, or (at your option) any later version.
  9   *
 10   *  This library is distributed in the hope that it will be useful,
 11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13   *  Lesser General Public License for more details.
 14   *
 15   *  You should have received a copy of the GNU Lesser General Public
 16   *  License along with this library; if not, write to the Free Software
 17   *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 18   *
 19   */
 20  
 21  #include "config.h"
 22  #include "StringConstructor.h"
 23  
 24  #include "JSCInlines.h"
 25  #include "StringPrototype.h"
 26  #include <wtf/text/StringBuilder.h>
 27  
 28  namespace JSC {
 29  
 30  static JSC_DECLARE_HOST_FUNCTION(stringFromCharCode);
 31  static JSC_DECLARE_HOST_FUNCTION(stringFromCodePoint);
 32  
 33  }
 34  
 35  #include "StringConstructor.lut.h"
 36  
 37  namespace JSC {
 38  
 39  const ClassInfo StringConstructor::s_info = { "Function", &InternalFunction::s_info, &stringConstructorTable, nullptr, CREATE_METHOD_TABLE(StringConstructor) };
 40  
 41  /* Source for StringConstructor.lut.h
 42  @begin stringConstructorTable
 43    fromCharCode          stringFromCharCode         DontEnum|Function 1 FromCharCodeIntrinsic
 44    fromCodePoint         stringFromCodePoint        DontEnum|Function 1
 45    raw                   JSBuiltin                  DontEnum|Function 1
 46  @end
 47  */
 48  
 49  STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(StringConstructor);
 50  
 51  
 52  static JSC_DECLARE_HOST_FUNCTION(callStringConstructor);
 53  static JSC_DECLARE_HOST_FUNCTION(constructWithStringConstructor);
 54  
 55  StringConstructor::StringConstructor(VM& vm, Structure* structure)
 56      : InternalFunction(vm, structure, callStringConstructor, constructWithStringConstructor)
 57  {
 58  }
 59  
 60  void StringConstructor::finishCreation(VM& vm, StringPrototype* stringPrototype)
 61  {
 62      Base::finishCreation(vm, 1, vm.propertyNames->String.string(), PropertyAdditionMode::WithoutStructureTransition);
 63      putDirectWithoutTransition(vm, vm.propertyNames->prototype, stringPrototype, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete);
 64  }
 65  
 66  // ------------------------------ Functions --------------------------------
 67  
 68  JSC_DEFINE_HOST_FUNCTION(stringFromCharCode, (JSGlobalObject* globalObject, CallFrame* callFrame))
 69  {
 70      VM& vm = globalObject->vm();
 71      auto scope = DECLARE_THROW_SCOPE(vm);
 72  
 73      unsigned length = callFrame->argumentCount();
 74      if (LIKELY(length == 1)) {
 75          scope.release();
 76          unsigned code = callFrame->uncheckedArgument(0).toUInt32(globalObject);
 77          // Not checking for an exception here is ok because jsSingleCharacterString will just fetch an unused string if there's an exception.
 78          return JSValue::encode(jsSingleCharacterString(vm, code));
 79      }
 80  
 81      LChar* buf8Bit;
 82      auto impl8Bit = StringImpl::createUninitialized(length, buf8Bit);
 83      for (unsigned i = 0; i < length; ++i) {
 84          UChar character = static_cast<UChar>(callFrame->uncheckedArgument(i).toUInt32(globalObject));
 85          RETURN_IF_EXCEPTION(scope, encodedJSValue());
 86          if (UNLIKELY(!isLatin1(character))) {
 87              UChar* buf16Bit;
 88              auto impl16Bit = StringImpl::createUninitialized(length, buf16Bit);
 89              StringImpl::copyCharacters(buf16Bit, buf8Bit, i);
 90              buf16Bit[i] = character;
 91              ++i;
 92              for (; i < length; ++i) {
 93                  buf16Bit[i] = static_cast<UChar>(callFrame->uncheckedArgument(i).toUInt32(globalObject));
 94                  RETURN_IF_EXCEPTION(scope, encodedJSValue());
 95              }
 96              RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, WTFMove(impl16Bit))));
 97          }
 98          buf8Bit[i] = static_cast<LChar>(character);
 99      }
100      RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, WTFMove(impl8Bit))));
101  }
102  
103  JSString* stringFromCharCode(JSGlobalObject* globalObject, int32_t arg)
104  {
105      return jsSingleCharacterString(globalObject->vm(), arg);
106  }
107  
108  JSC_DEFINE_HOST_FUNCTION(stringFromCodePoint, (JSGlobalObject* globalObject, CallFrame* callFrame))
109  {
110      VM& vm = globalObject->vm();
111      auto scope = DECLARE_THROW_SCOPE(vm);
112  
113      unsigned length = callFrame->argumentCount();
114      StringBuilder builder;
115      builder.reserveCapacity(length);
116  
117      for (unsigned i = 0; i < length; ++i) {
118          double codePointAsDouble = callFrame->uncheckedArgument(i).toNumber(globalObject);
119          RETURN_IF_EXCEPTION(scope, encodedJSValue());
120  
121          uint32_t codePoint = static_cast<uint32_t>(codePointAsDouble);
122  
123          if (codePoint != codePointAsDouble || codePoint > UCHAR_MAX_VALUE)
124              return throwVMError(globalObject, scope, createRangeError(globalObject, "Arguments contain a value that is out of range of code points"_s));
125  
126          if (U_IS_BMP(codePoint))
127              builder.append(static_cast<UChar>(codePoint));
128          else {
129              builder.append(U16_LEAD(codePoint));
130              builder.append(U16_TRAIL(codePoint));
131          }
132      }
133  
134      RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, builder.toString())));
135  }
136  
137  JSC_DEFINE_HOST_FUNCTION(constructWithStringConstructor, (JSGlobalObject* globalObject, CallFrame* callFrame))
138  {
139      VM& vm = globalObject->vm();
140      auto scope = DECLARE_THROW_SCOPE(vm);
141  
142      JSObject* newTarget = asObject(callFrame->newTarget());
143      Structure* structure = newTarget == callFrame->jsCallee()
144          ? globalObject->stringObjectStructure()
145          : InternalFunction::createSubclassStructure(globalObject, newTarget, getFunctionRealm(vm, newTarget)->stringObjectStructure());
146      RETURN_IF_EXCEPTION(scope, { });
147  
148      if (!callFrame->argumentCount())
149          return JSValue::encode(StringObject::create(vm, structure));
150      JSString* str = callFrame->uncheckedArgument(0).toString(globalObject);
151      RETURN_IF_EXCEPTION(scope, encodedJSValue());
152      return JSValue::encode(StringObject::create(vm, structure, str));
153  }
154  
155  JSString* stringConstructor(JSGlobalObject* globalObject, JSValue argument)
156  {
157      VM& vm = globalObject->vm();
158      if (argument.isSymbol())
159          return jsNontrivialString(vm, asSymbol(argument)->descriptiveString());
160      return argument.toString(globalObject);
161  }
162  
163  JSC_DEFINE_HOST_FUNCTION(callStringConstructor, (JSGlobalObject* globalObject, CallFrame* callFrame))
164  {
165      VM& vm = globalObject->vm();
166      if (!callFrame->argumentCount())
167          return JSValue::encode(jsEmptyString(vm));
168      return JSValue::encode(stringConstructor(globalObject, callFrame->uncheckedArgument(0)));
169  }
170  
171  } // namespace JSC