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(ExecState* exec) |
42 | { |
43 | ArgList args(exec); |
44 | return JSValue::encode(constructFunction(exec, jsCast<InternalFunction*>(exec->jsCallee())->globalObject(exec->vm()), args, FunctionConstructionMode::Function, exec->newTarget())); |
45 | } |
46 | |
47 | // ECMA 15.3.1 The Function Constructor Called as a Function |
48 | static EncodedJSValue JSC_HOST_CALL callFunctionConstructor(ExecState* exec) |
49 | { |
50 | ArgList args(exec); |
51 | return JSValue::encode(constructFunction(exec, jsCast<InternalFunction*>(exec->jsCallee())->globalObject(exec->vm()), 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(), NameVisibility::Visible, 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(ExecState* exec, 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 = exec->vm(); |
70 | auto scope = DECLARE_THROW_SCOPE(vm); |
71 | |
72 | if (UNLIKELY(!globalObject->evalEnabled())) { |
73 | throwException(exec, scope, createEvalError(exec, globalObject->evalDisabledErrorMessage())); |
74 | return nullptr; |
75 | } |
76 | RELEASE_AND_RETURN(scope, constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceOrigin, sourceURL, position, -1, functionConstructionMode, newTarget)); |
77 | } |
78 | |
79 | JSObject* constructFunctionSkippingEvalEnabledCheck( |
80 | ExecState* exec, 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 = exec->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(exec); |
111 | RETURN_IF_EXCEPTION(scope, nullptr); |
112 | program = makeString(prefix, functionName.string(), "() {\n" , body, "\n}" ); |
113 | } else { |
114 | StringBuilder builder(StringBuilder::OverflowHandler::RecordOverflow); |
115 | builder.append(prefix); |
116 | builder.append(functionName.string()); |
117 | |
118 | builder.append('('); |
119 | auto viewWithString = args.at(0).toString(exec)->viewWithUnderlyingString(exec); |
120 | RETURN_IF_EXCEPTION(scope, nullptr); |
121 | builder.append(viewWithString.view); |
122 | for (size_t i = 1; !builder.hasOverflowed() && i < args.size() - 1; i++) { |
123 | builder.appendLiteral(", " ); |
124 | auto viewWithString = args.at(i).toString(exec)->viewWithUnderlyingString(exec); |
125 | RETURN_IF_EXCEPTION(scope, nullptr); |
126 | builder.append(viewWithString.view); |
127 | } |
128 | if (builder.hasOverflowed()) { |
129 | throwOutOfMemoryError(exec, scope); |
130 | return nullptr; |
131 | } |
132 | |
133 | functionConstructorParametersEndPosition = builder.length() + 1; |
134 | builder.appendLiteral(") {\n" ); |
135 | |
136 | auto body = args.at(args.size() - 1).toString(exec)->viewWithUnderlyingString(exec); |
137 | RETURN_IF_EXCEPTION(scope, nullptr); |
138 | builder.append(body.view); |
139 | builder.appendLiteral("\n}" ); |
140 | if (builder.hasOverflowed()) { |
141 | throwOutOfMemoryError(exec, scope); |
142 | return nullptr; |
143 | } |
144 | program = builder.toString(); |
145 | } |
146 | |
147 | SourceCode source = makeSource(program, sourceOrigin, URL({ }, sourceURL), position); |
148 | JSObject* exception = nullptr; |
149 | FunctionExecutable* function = FunctionExecutable::fromGlobalCode(functionName, *exec, source, exception, overrideLineNumber, functionConstructorParametersEndPosition); |
150 | if (UNLIKELY(!function)) { |
151 | ASSERT(exception); |
152 | throwException(exec, scope, exception); |
153 | return nullptr; |
154 | } |
155 | |
156 | Structure* structure = nullptr; |
157 | switch (functionConstructionMode) { |
158 | case FunctionConstructionMode::Function: |
159 | structure = JSFunction::selectStructureForNewFuncExp(globalObject, function); |
160 | break; |
161 | case FunctionConstructionMode::Generator: |
162 | structure = globalObject->generatorFunctionStructure(); |
163 | break; |
164 | case FunctionConstructionMode::Async: |
165 | structure = globalObject->asyncFunctionStructure(); |
166 | break; |
167 | case FunctionConstructionMode::AsyncGenerator: |
168 | structure = globalObject->asyncGeneratorFunctionStructure(); |
169 | break; |
170 | } |
171 | |
172 | Structure* subclassStructure = InternalFunction::createSubclassStructure(exec, newTarget, structure); |
173 | RETURN_IF_EXCEPTION(scope, nullptr); |
174 | |
175 | switch (functionConstructionMode) { |
176 | case FunctionConstructionMode::Function: |
177 | return JSFunction::create(vm, function, globalObject->globalScope(), subclassStructure); |
178 | case FunctionConstructionMode::Generator: |
179 | return JSGeneratorFunction::create(vm, function, globalObject->globalScope(), subclassStructure); |
180 | case FunctionConstructionMode::Async: |
181 | return JSAsyncFunction::create(vm, function, globalObject->globalScope(), subclassStructure); |
182 | case FunctionConstructionMode::AsyncGenerator: |
183 | return JSAsyncGeneratorFunction::create(vm, function, globalObject->globalScope(), subclassStructure); |
184 | } |
185 | |
186 | ASSERT_NOT_REACHED(); |
187 | return nullptr; |
188 | } |
189 | |
190 | // ECMA 15.3.2 The Function Constructor |
191 | JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, FunctionConstructionMode functionConstructionMode, JSValue newTarget) |
192 | { |
193 | VM& vm = exec->vm(); |
194 | return constructFunction(exec, globalObject, args, vm.propertyNames->anonymous, exec->callerSourceOrigin(), String(), TextPosition(), functionConstructionMode, newTarget); |
195 | } |
196 | |
197 | } // namespace JSC |
198 | |