Unreviewed, roll out r240220 due to date-format-xparb regression
[WebKit-https.git] / Source / JavaScriptCore / runtime / ProgramExecutable.cpp
1 /*
2  * Copyright (C) 2009-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #include "BatchedTransitionOptimizer.h"
29 #include "CodeBlock.h"
30 #include "CodeCache.h"
31 #include "Debugger.h"
32 #include "Exception.h"
33 #include "JIT.h"
34 #include "JSCInlines.h"
35 #include "LLIntEntrypoint.h"
36 #include "Parser.h"
37 #include "ProgramCodeBlock.h"
38 #include "TypeProfiler.h"
39 #include "VMInlines.h"
40 #include <wtf/CommaPrinter.h>
41
42 namespace JSC {
43
44 const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ProgramExecutable) };
45
46 ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source)
47     : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec->vm(), source, false, DerivedContextType::None, false, EvalContextType::None, NoIntrinsic)
48 {
49     ASSERT(source.provider()->sourceType() == SourceProviderSourceType::Program);
50     m_typeProfilingStartOffset = 0;
51     m_typeProfilingEndOffset = source.length() - 1;
52     if (exec->vm().typeProfiler() || exec->vm().controlFlowProfiler())
53         exec->vm().functionHasExecutedCache()->insertUnexecutedRange(sourceID(), m_typeProfilingStartOffset, m_typeProfilingEndOffset);
54 }
55
56 void ProgramExecutable::destroy(JSCell* cell)
57 {
58     static_cast<ProgramExecutable*>(cell)->ProgramExecutable::~ProgramExecutable();
59 }
60
61 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasrestrictedglobalproperty
62 enum class GlobalPropertyLookUpStatus {
63     NotFound,
64     Configurable,
65     NonConfigurable,
66 };
67 static GlobalPropertyLookUpStatus hasRestrictedGlobalProperty(ExecState* exec, JSGlobalObject* globalObject, PropertyName propertyName)
68 {
69     PropertyDescriptor descriptor;
70     if (!globalObject->getOwnPropertyDescriptor(exec, propertyName, descriptor))
71         return GlobalPropertyLookUpStatus::NotFound;
72     if (descriptor.configurable())
73         return GlobalPropertyLookUpStatus::Configurable;
74     return GlobalPropertyLookUpStatus::NonConfigurable;
75 }
76
77 JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope)
78 {
79     auto throwScope = DECLARE_THROW_SCOPE(vm);
80     RELEASE_ASSERT(scope);
81     JSGlobalObject* globalObject = scope->globalObject(vm);
82     RELEASE_ASSERT(globalObject);
83     ASSERT(&globalObject->vm() == &vm);
84
85     ParserError error;
86     JSParserStrictMode strictMode = isStrictMode() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict;
87     DebuggerMode debuggerMode = globalObject->hasInteractiveDebugger() ? DebuggerOn : DebuggerOff;
88
89     UnlinkedProgramCodeBlock* unlinkedCodeBlock = vm.codeCache()->getUnlinkedProgramCodeBlock(
90         vm, this, source(), strictMode, debuggerMode, error);
91
92     if (globalObject->hasDebugger())
93         globalObject->debugger()->sourceParsed(callFrame, source().provider(), error.line(), error.message());
94
95     if (error.isValid())
96         return error.toErrorObject(globalObject, source());
97
98     JSValue nextPrototype = globalObject->getPrototypeDirect(vm);
99     while (nextPrototype && nextPrototype.isObject()) {
100         if (UNLIKELY(asObject(nextPrototype)->type() == ProxyObjectType)) {
101             ExecState* exec = globalObject->globalExec();
102             return createTypeError(exec, "Proxy is not allowed in the global prototype chain."_s);
103         }
104         nextPrototype = asObject(nextPrototype)->getPrototypeDirect(vm);
105     }
106     
107     JSGlobalLexicalEnvironment* globalLexicalEnvironment = globalObject->globalLexicalEnvironment();
108     const VariableEnvironment& variableDeclarations = unlinkedCodeBlock->variableDeclarations();
109     const VariableEnvironment& lexicalDeclarations = unlinkedCodeBlock->lexicalDeclarations();
110     IdentifierSet shadowedProperties;
111     // The ES6 spec says that no vars/global properties/let/const can be duplicated in the global scope.
112     // This carried out section 15.1.8 of the ES6 spec: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-globaldeclarationinstantiation
113     {
114         ExecState* exec = globalObject->globalExec();
115         // Check for intersection of "var" and "let"/"const"/"class"
116         for (auto& entry : lexicalDeclarations) {
117             if (variableDeclarations.contains(entry.key))
118                 return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'"));
119         }
120
121         // Check if any new "let"/"const"/"class" will shadow any pre-existing global property names (with configurable = false), or "var"/"let"/"const" variables.
122         // It's an error to introduce a shadow.
123         for (auto& entry : lexicalDeclarations) {
124             // The ES6 spec says that RestrictedGlobalProperty can't be shadowed.
125             GlobalPropertyLookUpStatus status = hasRestrictedGlobalProperty(exec, globalObject, entry.key.get());
126             RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
127             switch (status) {
128             case GlobalPropertyLookUpStatus::NonConfigurable:
129                 return createSyntaxError(exec, makeString("Can't create duplicate variable that shadows a global property: '", String(entry.key.get()), "'"));
130             case GlobalPropertyLookUpStatus::Configurable:
131                 // Lexical bindings can shadow global properties if the given property's attribute is configurable.
132                 // https://tc39.github.io/ecma262/#sec-globaldeclarationinstantiation step 5-c, `hasRestrictedGlobal` becomes false
133                 // However we may emit GlobalProperty look up in bytecodes already and it may cache the value for the global scope.
134                 // To make it invalid, we iterate all the CodeBlocks and rewrite the instruction to convert GlobalProperty to GlobalLexicalVar.
135                 // 1. In LLInt, we always check metadata's resolveType. So rewritten instruction just works.
136                 // 2. In Baseline JIT, we check metadata's resolveType in GlobalProperty case so that we can notice once it is changed.
137                 // 3. In DFG and FTL, we watch the watchpoint and jettison once it is fired.
138                 shadowedProperties.add(entry.key.get());
139                 break;
140             case GlobalPropertyLookUpStatus::NotFound:
141                 break;
142             }
143
144             bool hasProperty = globalLexicalEnvironment->hasProperty(exec, entry.key.get());
145             RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
146             if (hasProperty) {
147                 if (UNLIKELY(entry.value.isConst() && !vm.globalConstRedeclarationShouldThrow() && !isStrictMode())) {
148                     // We only allow "const" duplicate declarations under this setting.
149                     // For example, we don't "let" variables to be overridden by "const" variables.
150                     if (globalLexicalEnvironment->isConstVariable(entry.key.get()))
151                         continue;
152                 }
153                 return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'"));
154             }
155         }
156
157         // Check if any new "var"s will shadow any previous "let"/"const"/"class" names.
158         // It's an error to introduce a shadow.
159         if (!globalLexicalEnvironment->isEmpty()) {
160             for (auto& entry : variableDeclarations) {
161                 bool hasProperty = globalLexicalEnvironment->hasProperty(exec, entry.key.get());
162                 RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
163                 if (hasProperty)
164                     return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'"));
165             }
166         }
167     }
168
169
170     m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock);
171
172     BatchedTransitionOptimizer optimizer(vm, globalObject);
173
174     for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) {
175         UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i);
176         ASSERT(!unlinkedFunctionExecutable->name().isEmpty());
177         globalObject->addFunction(callFrame, unlinkedFunctionExecutable->name());
178         if (vm.typeProfiler() || vm.controlFlowProfiler()) {
179             vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(), 
180                 unlinkedFunctionExecutable->typeProfilingStartOffset(), 
181                 unlinkedFunctionExecutable->typeProfilingEndOffset());
182         }
183     }
184
185     for (auto& entry : variableDeclarations) {
186         ASSERT(entry.value.isVar());
187         globalObject->addVar(callFrame, Identifier::fromUid(&vm, entry.key.get()));
188         throwScope.assertNoException();
189     }
190
191     {
192         JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(globalObject->globalScope());
193         SymbolTable* symbolTable = globalLexicalEnvironment->symbolTable();
194         ConcurrentJSLocker locker(symbolTable->m_lock);
195         for (auto& entry : lexicalDeclarations) {
196             if (UNLIKELY(entry.value.isConst() && !vm.globalConstRedeclarationShouldThrow() && !isStrictMode())) {
197                 if (symbolTable->contains(locker, entry.key.get()))
198                     continue;
199             }
200             ScopeOffset offset = symbolTable->takeNextScopeOffset(locker);
201             SymbolTableEntry newEntry(VarOffset(offset), static_cast<unsigned>(entry.value.isConst() ? PropertyAttribute::ReadOnly : PropertyAttribute::None));
202             newEntry.prepareToWatch();
203             symbolTable->add(locker, entry.key.get(), newEntry);
204             
205             ScopeOffset offsetForAssert = globalLexicalEnvironment->addVariables(1, jsTDZValue());
206             RELEASE_ASSERT(offsetForAssert == offset);
207         }
208     }
209
210     if (!shadowedProperties.isEmpty()) {
211         globalObject->notifyLexicalBindingShadowing(vm, WTFMove(shadowedProperties));
212         throwScope.assertNoException();
213     }
214
215     return nullptr;
216 }
217
218 void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
219 {
220     ProgramExecutable* thisObject = jsCast<ProgramExecutable*>(cell);
221     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
222     Base::visitChildren(thisObject, visitor);
223     visitor.append(thisObject->m_unlinkedProgramCodeBlock);
224     visitor.append(thisObject->m_programCodeBlock);
225 }
226
227 } // namespace JSC