[JSC] Pass VM& parameter as much as possible
[WebKit.git] / Source / JavaScriptCore / runtime / FunctionConstructor.cpp
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003-2017 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, functionPrototype->classInfo()->className);
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 (!globalObject->evalEnabled())
73         return throwException(exec, scope, createEvalError(exec, globalObject->evalDisabledErrorMessage()));
74     scope.release();
75     return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceOrigin, sourceURL, position, -1, functionConstructionMode, newTarget);
76 }
77
78 JSObject* constructFunctionSkippingEvalEnabledCheck(
79     ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, 
80     const Identifier& functionName, const SourceOrigin& sourceOrigin, const String& sourceURL, 
81     const TextPosition& position, int overrideLineNumber, FunctionConstructionMode functionConstructionMode, JSValue newTarget)
82 {
83     VM& vm = exec->vm();
84     auto scope = DECLARE_THROW_SCOPE(vm);
85
86     const char* prefix = nullptr;
87     switch (functionConstructionMode) {
88     case FunctionConstructionMode::Function:
89         prefix = "function ";
90         break;
91     case FunctionConstructionMode::Generator:
92         prefix = "function *";
93         break;
94     case FunctionConstructionMode::Async:
95         prefix = "async function ";
96         break;
97     case FunctionConstructionMode::AsyncGenerator:
98         prefix = "{async function*";
99         break;
100     }
101
102     auto checkBody = [&] (const String& body) {
103         // The spec mandates that the body parses a valid function body independent
104         // of the parameters.
105         String program = makeString("(", prefix, "(){\n", body, "\n})");
106         SourceCode source = makeSource(program, sourceOrigin, sourceURL, position);
107         JSValue exception;
108         checkSyntax(exec, source, &exception);
109         if (exception) {
110             scope.throwException(exec, exception);
111             return;
112         }
113     };
114
115     // How we stringify functions is sometimes important for web compatibility.
116     // See https://bugs.webkit.org/show_bug.cgi?id=24350.
117     String program;
118     if (args.isEmpty())
119         program = makeString("{", prefix, functionName.string(), "() {\n\n}}");
120     else if (args.size() == 1) {
121         auto body = args.at(0).toWTFString(exec);
122         RETURN_IF_EXCEPTION(scope, nullptr);
123         checkBody(body);
124         RETURN_IF_EXCEPTION(scope, nullptr);
125         program = makeString("{", prefix, functionName.string(), "() {\n", body, "\n}}");
126     } else {
127         StringBuilder builder;
128         builder.append('{');
129         builder.append(prefix);
130         builder.append(functionName.string());
131         builder.append('(');
132         StringBuilder parameterBuilder;
133         auto viewWithString = args.at(0).toString(exec)->viewWithUnderlyingString(exec);
134         RETURN_IF_EXCEPTION(scope, nullptr);
135         parameterBuilder.append(viewWithString.view);
136         for (size_t i = 1; i < args.size() - 1; i++) {
137             parameterBuilder.appendLiteral(", ");
138             auto viewWithString = args.at(i).toString(exec)->viewWithUnderlyingString(exec);
139             RETURN_IF_EXCEPTION(scope, nullptr);
140             parameterBuilder.append(viewWithString.view);
141         }
142
143         {
144             // The spec mandates that the parameters parse as a valid parameter list
145             // independent of the function body.
146             String program = makeString("(", prefix, "(", parameterBuilder.toString(), "){\n\n})");
147             SourceCode source = makeSource(program, sourceOrigin, sourceURL, position);
148             JSValue exception;
149             checkSyntax(exec, source, &exception);
150             if (exception) {
151                 scope.throwException(exec, exception);
152                 return nullptr;
153             }
154         }
155
156         builder.append(parameterBuilder);
157         builder.appendLiteral(") {\n");
158         auto body = args.at(args.size() - 1).toWTFString(exec);
159         RETURN_IF_EXCEPTION(scope, nullptr);
160         checkBody(body);
161         RETURN_IF_EXCEPTION(scope, nullptr);
162         builder.append(body);
163         builder.appendLiteral("\n}}");
164         program = builder.toString();
165     }
166
167     SourceCode source = makeSource(program, sourceOrigin, sourceURL, position);
168     JSObject* exception = nullptr;
169     FunctionExecutable* function = FunctionExecutable::fromGlobalCode(functionName, *exec, source, exception, overrideLineNumber);
170     if (!function) {
171         ASSERT(exception);
172         return throwException(exec, scope, exception);
173     }
174
175     Structure* structure = nullptr;
176     switch (functionConstructionMode) {
177     case FunctionConstructionMode::Function:
178         structure = JSFunction::selectStructureForNewFuncExp(globalObject, function);
179         break;
180     case FunctionConstructionMode::Generator:
181         structure = globalObject->generatorFunctionStructure();
182         break;
183     case FunctionConstructionMode::Async:
184         structure = globalObject->asyncFunctionStructure();
185         break;
186     case FunctionConstructionMode::AsyncGenerator:
187         structure = globalObject->asyncGeneratorFunctionStructure();
188         break;
189     }
190
191     Structure* subclassStructure = InternalFunction::createSubclassStructure(exec, newTarget, structure);
192     RETURN_IF_EXCEPTION(scope, nullptr);
193
194     switch (functionConstructionMode) {
195     case FunctionConstructionMode::Function:
196         return JSFunction::create(vm, function, globalObject->globalScope(), subclassStructure);
197     case FunctionConstructionMode::Generator:
198         return JSGeneratorFunction::create(vm, function, globalObject->globalScope(), subclassStructure);
199     case FunctionConstructionMode::Async:
200         return JSAsyncFunction::create(vm, function, globalObject->globalScope(), subclassStructure);
201     case FunctionConstructionMode::AsyncGenerator:
202         return JSAsyncGeneratorFunction::create(vm, function, globalObject->globalScope(), subclassStructure);
203     }
204
205     ASSERT_NOT_REACHED();
206     return nullptr;
207 }
208
209 // ECMA 15.3.2 The Function Constructor
210 JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, FunctionConstructionMode functionConstructionMode, JSValue newTarget)
211 {
212     VM& vm = exec->vm();
213     return constructFunction(exec, globalObject, args, vm.propertyNames->anonymous, exec->callerSourceOrigin(), String(), TextPosition(), functionConstructionMode, newTarget);
214 }
215
216 } // namespace JSC