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