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