/ runtime / FunctionConstructor.cpp
FunctionConstructor.cpp
  1  /*
  2   *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  3   *  Copyright (C) 2003-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 "FunctionConstructor.h"
 23  
 24  #include "ExceptionHelpers.h"
 25  #include "FunctionPrototype.h"
 26  #include "JSAsyncFunction.h"
 27  #include "JSAsyncGeneratorFunction.h"
 28  #include "JSFunction.h"
 29  #include "JSGeneratorFunction.h"
 30  #include "JSGlobalObject.h"
 31  #include "JSCInlines.h"
 32  #include <wtf/text/StringBuilder.h>
 33  
 34  namespace JSC {
 35  
 36  STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(FunctionConstructor);
 37  
 38  const ClassInfo FunctionConstructor::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(FunctionConstructor) };
 39  
 40  static JSC_DECLARE_HOST_FUNCTION(constructWithFunctionConstructor);
 41  static JSC_DECLARE_HOST_FUNCTION(callFunctionConstructor);
 42  
 43  JSC_DEFINE_HOST_FUNCTION(constructWithFunctionConstructor, (JSGlobalObject* globalObject, CallFrame* callFrame))
 44  {
 45      ArgList args(callFrame);
 46      return JSValue::encode(constructFunction(globalObject, callFrame, args, FunctionConstructionMode::Function, callFrame->newTarget()));
 47  }
 48  
 49  // ECMA 15.3.1 The Function Constructor Called as a Function
 50  JSC_DEFINE_HOST_FUNCTION(callFunctionConstructor, (JSGlobalObject* globalObject, CallFrame* callFrame))
 51  {
 52      ArgList args(callFrame);
 53      return JSValue::encode(constructFunction(globalObject, callFrame, args));
 54  }
 55  
 56  FunctionConstructor::FunctionConstructor(VM& vm, Structure* structure)
 57      : InternalFunction(vm, structure, callFunctionConstructor, constructWithFunctionConstructor)
 58  {
 59  }
 60  
 61  void FunctionConstructor::finishCreation(VM& vm, FunctionPrototype* functionPrototype)
 62  {
 63      Base::finishCreation(vm, 1, vm.propertyNames->Function.string(), PropertyAdditionMode::WithoutStructureTransition);
 64      putDirectWithoutTransition(vm, vm.propertyNames->prototype, functionPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
 65  }
 66  
 67  // ECMA 15.3.2 The Function Constructor
 68  JSObject* constructFunction(JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const SourceOrigin& sourceOrigin, const String& sourceURL, const TextPosition& position, FunctionConstructionMode functionConstructionMode, JSValue newTarget)
 69  {
 70      VM& vm = globalObject->vm();
 71      auto scope = DECLARE_THROW_SCOPE(vm);
 72  
 73      if (UNLIKELY(!globalObject->evalEnabled())) {
 74          throwException(globalObject, scope, createEvalError(globalObject, globalObject->evalDisabledErrorMessage()));
 75          return nullptr;
 76      }
 77      RELEASE_AND_RETURN(scope, constructFunctionSkippingEvalEnabledCheck(globalObject, args, functionName, sourceOrigin, sourceURL, position, -1, functionConstructionMode, newTarget));
 78  }
 79  
 80  JSObject* constructFunctionSkippingEvalEnabledCheck(
 81      JSGlobalObject* globalObject, const ArgList& args, 
 82      const Identifier& functionName, const SourceOrigin& sourceOrigin, const String& sourceURL, 
 83      const TextPosition& position, int overrideLineNumber, FunctionConstructionMode functionConstructionMode, JSValue newTarget)
 84  {
 85      VM& vm = globalObject->vm();
 86      auto scope = DECLARE_THROW_SCOPE(vm);
 87  
 88      const char* prefix = nullptr;
 89      switch (functionConstructionMode) {
 90      case FunctionConstructionMode::Function:
 91          prefix = "function ";
 92          break;
 93      case FunctionConstructionMode::Generator:
 94          prefix = "function *";
 95          break;
 96      case FunctionConstructionMode::Async:
 97          prefix = "async function ";
 98          break;
 99      case FunctionConstructionMode::AsyncGenerator:
100          prefix = "async function*";
101          break;
102      }
103  
104      // How we stringify functions is sometimes important for web compatibility.
105      // See https://bugs.webkit.org/show_bug.cgi?id=24350.
106      String program;
107      Optional<int> functionConstructorParametersEndPosition = WTF::nullopt;
108      if (args.isEmpty())
109          program = makeString(prefix, functionName.string(), "() {\n\n}");
110      else if (args.size() == 1) {
111          auto body = args.at(0).toWTFString(globalObject);
112          RETURN_IF_EXCEPTION(scope, nullptr);
113          program = tryMakeString(prefix, functionName.string(), "() {\n", body, "\n}");
114          if (UNLIKELY(!program)) {
115              throwOutOfMemoryError(globalObject, scope);
116              return nullptr;
117          }
118      } else {
119          StringBuilder builder(StringBuilder::OverflowHandler::RecordOverflow);
120          builder.append(prefix, functionName.string(), '(');
121  
122          auto* jsString = args.at(0).toString(globalObject);
123          RETURN_IF_EXCEPTION(scope, nullptr);
124          auto viewWithString = jsString->viewWithUnderlyingString(globalObject);
125          RETURN_IF_EXCEPTION(scope, nullptr);
126          builder.append(viewWithString.view);
127          for (size_t i = 1; !builder.hasOverflowed() && i < args.size() - 1; i++) {
128              auto* jsString = args.at(i).toString(globalObject);
129              RETURN_IF_EXCEPTION(scope, nullptr);
130              auto viewWithString = jsString->viewWithUnderlyingString(globalObject);
131              RETURN_IF_EXCEPTION(scope, nullptr);
132              builder.append(", ", viewWithString.view);
133          }
134          if (UNLIKELY(builder.hasOverflowed())) {
135              throwOutOfMemoryError(globalObject, scope);
136              return nullptr;
137          }
138  
139          functionConstructorParametersEndPosition = builder.length() + 1;
140  
141          auto* bodyString = args.at(args.size() - 1).toString(globalObject);
142          RETURN_IF_EXCEPTION(scope, nullptr);
143          auto body = bodyString->viewWithUnderlyingString(globalObject);
144          RETURN_IF_EXCEPTION(scope, nullptr);
145          builder.append(") {\n", body.view, "\n}");
146          if (UNLIKELY(builder.hasOverflowed())) {
147              throwOutOfMemoryError(globalObject, scope);
148              return nullptr;
149          }
150          program = builder.toString();
151      }
152  
153      SourceCode source = makeSource(program, sourceOrigin, sourceURL, position);
154      JSObject* exception = nullptr;
155      FunctionExecutable* function = FunctionExecutable::fromGlobalCode(functionName, globalObject, source, exception, overrideLineNumber, functionConstructorParametersEndPosition);
156      if (UNLIKELY(!function)) {
157          ASSERT(exception);
158          throwException(globalObject, scope, exception);
159          return nullptr;
160      }
161  
162      bool needsSubclassStructure = newTarget && newTarget != globalObject->functionConstructor();
163      JSGlobalObject* structureGlobalObject = needsSubclassStructure ? getFunctionRealm(vm, asObject(newTarget)) : globalObject;
164      Structure* structure = nullptr;
165      switch (functionConstructionMode) {
166      case FunctionConstructionMode::Function:
167          structure = JSFunction::selectStructureForNewFuncExp(structureGlobalObject, function);
168          break;
169      case FunctionConstructionMode::Generator:
170          structure = structureGlobalObject->generatorFunctionStructure();
171          break;
172      case FunctionConstructionMode::Async:
173          structure = structureGlobalObject->asyncFunctionStructure();
174          break;
175      case FunctionConstructionMode::AsyncGenerator:
176          structure = structureGlobalObject->asyncGeneratorFunctionStructure();
177          break;
178      }
179  
180      if (needsSubclassStructure) {
181          structure = InternalFunction::createSubclassStructure(globalObject, asObject(newTarget), structure);
182          RETURN_IF_EXCEPTION(scope, nullptr);
183      }
184  
185      switch (functionConstructionMode) {
186      case FunctionConstructionMode::Function:
187          return JSFunction::create(vm, function, globalObject->globalScope(), structure);
188      case FunctionConstructionMode::Generator:
189          return JSGeneratorFunction::create(vm, function, globalObject->globalScope(), structure);
190      case FunctionConstructionMode::Async:
191          return JSAsyncFunction::create(vm, function, globalObject->globalScope(), structure);
192      case FunctionConstructionMode::AsyncGenerator:
193          return JSAsyncGeneratorFunction::create(vm, function, globalObject->globalScope(), structure);
194      }
195  
196      ASSERT_NOT_REACHED();
197      return nullptr;
198  }
199  
200  // ECMA 15.3.2 The Function Constructor
201  JSObject* constructFunction(JSGlobalObject* globalObject, CallFrame* callFrame, const ArgList& args, FunctionConstructionMode functionConstructionMode, JSValue newTarget)
202  {
203      VM& vm = globalObject->vm();
204      return constructFunction(globalObject, args, vm.propertyNames->anonymous, callFrame->callerSourceOrigin(vm), String(), TextPosition(), functionConstructionMode, newTarget);
205  }
206  
207  } // namespace JSC