6769e4169b5f20f9d6c51269c4b1f769cb5fd4ff
[WebKit-https.git] / Source / JavaScriptCore / runtime / ProgramExecutable.cpp
1 /*
2  * Copyright (C) 2009, 2010, 2013, 2015-2016 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, 0, 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 JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
62 {
63     ParserError error;
64     VM* vm = &exec->vm();
65     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
66     std::unique_ptr<ProgramNode> programNode = parse<ProgramNode>(
67         vm, m_source, Identifier(), JSParserBuiltinMode::NotBuiltin,
68         JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error);
69     if (programNode)
70         return 0;
71     ASSERT(error.isValid());
72     return error.toErrorObject(lexicalGlobalObject, m_source);
73 }
74
75 JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope)
76 {
77     auto throwScope = DECLARE_THROW_SCOPE(vm);
78     RELEASE_ASSERT(scope);
79     JSGlobalObject* globalObject = scope->globalObject();
80     RELEASE_ASSERT(globalObject);
81     ASSERT(&globalObject->vm() == &vm);
82
83     ParserError error;
84     JSParserStrictMode strictMode = isStrictMode() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict;
85     DebuggerMode debuggerMode = globalObject->hasInteractiveDebugger() ? DebuggerOn : DebuggerOff;
86
87     UnlinkedProgramCodeBlock* unlinkedCodeBlock = vm.codeCache()->getUnlinkedProgramCodeBlock(
88         vm, this, source(), strictMode, debuggerMode, error);
89
90     if (globalObject->hasDebugger())
91         globalObject->debugger()->sourceParsed(callFrame, source().provider(), error.line(), error.message());
92
93     if (error.isValid())
94         return error.toErrorObject(globalObject, source());
95
96     JSValue nextPrototype = globalObject->getPrototypeDirect();
97     while (nextPrototype && nextPrototype.isObject()) {
98         if (UNLIKELY(asObject(nextPrototype)->type() == ProxyObjectType)) {
99             ExecState* exec = globalObject->globalExec();
100             return createTypeError(exec, ASCIILiteral("Proxy is not allowed in the global prototype chain."));
101         }
102         nextPrototype = asObject(nextPrototype)->getPrototypeDirect();
103     }
104     
105     JSGlobalLexicalEnvironment* globalLexicalEnvironment = globalObject->globalLexicalEnvironment();
106     const VariableEnvironment& variableDeclarations = unlinkedCodeBlock->variableDeclarations();
107     const VariableEnvironment& lexicalDeclarations = unlinkedCodeBlock->lexicalDeclarations();
108     // The ES6 spec says that no vars/global properties/let/const can be duplicated in the global scope.
109     // This carried out section 15.1.8 of the ES6 spec: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-globaldeclarationinstantiation
110     {
111         ExecState* exec = globalObject->globalExec();
112         // Check for intersection of "var" and "let"/"const"/"class"
113         for (auto& entry : lexicalDeclarations) {
114             if (variableDeclarations.contains(entry.key))
115                 return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'"));
116         }
117
118         // Check if any new "let"/"const"/"class" will shadow any pre-existing global property names, or "var"/"let"/"const" variables.
119         // It's an error to introduce a shadow.
120         for (auto& entry : lexicalDeclarations) {
121             bool hasProperty = globalObject->hasProperty(exec, entry.key.get());
122             RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
123             if (hasProperty) {
124                 // The ES6 spec says that just RestrictedGlobalProperty can't be shadowed
125                 // This carried out section 8.1.1.4.14 of the ES6 spec: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasrestrictedglobalproperty
126                 PropertyDescriptor descriptor;
127                 globalObject->getOwnPropertyDescriptor(exec, entry.key.get(), descriptor);
128                 
129                 if (descriptor.value() != jsUndefined() && !descriptor.configurable())
130                     return createSyntaxError(exec, makeString("Can't create duplicate variable that shadows a global property: '", String(entry.key.get()), "'"));
131             }
132
133             hasProperty = globalLexicalEnvironment->hasProperty(exec, entry.key.get());
134             RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
135             if (hasProperty) {
136                 if (UNLIKELY(entry.value.isConst() && !vm.globalConstRedeclarationShouldThrow() && !isStrictMode())) {
137                     // We only allow "const" duplicate declarations under this setting.
138                     // For example, we don't "let" variables to be overridden by "const" variables.
139                     if (globalLexicalEnvironment->isConstVariable(entry.key.get()))
140                         continue;
141                 }
142                 return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'"));
143             }
144         }
145
146         // Check if any new "var"s will shadow any previous "let"/"const"/"class" names.
147         // It's an error to introduce a shadow.
148         if (!globalLexicalEnvironment->isEmpty()) {
149             for (auto& entry : variableDeclarations) {
150                 bool hasProperty = globalLexicalEnvironment->hasProperty(exec, entry.key.get());
151                 RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
152                 if (hasProperty)
153                     return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'"));
154             }
155         }
156     }
157
158
159     m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock);
160
161     BatchedTransitionOptimizer optimizer(vm, globalObject);
162
163     for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) {
164         UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i);
165         ASSERT(!unlinkedFunctionExecutable->name().isEmpty());
166         globalObject->addFunction(callFrame, unlinkedFunctionExecutable->name());
167         if (vm.typeProfiler() || vm.controlFlowProfiler()) {
168             vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(), 
169                 unlinkedFunctionExecutable->typeProfilingStartOffset(), 
170                 unlinkedFunctionExecutable->typeProfilingEndOffset());
171         }
172     }
173
174     for (auto& entry : variableDeclarations) {
175         ASSERT(entry.value.isVar());
176         globalObject->addVar(callFrame, Identifier::fromUid(&vm, entry.key.get()));
177         ASSERT(!throwScope.exception());
178     }
179
180     {
181         JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(globalObject->globalScope());
182         SymbolTable* symbolTable = globalLexicalEnvironment->symbolTable();
183         ConcurrentJSLocker locker(symbolTable->m_lock);
184         for (auto& entry : lexicalDeclarations) {
185             if (UNLIKELY(entry.value.isConst() && !vm.globalConstRedeclarationShouldThrow() && !isStrictMode())) {
186                 if (symbolTable->contains(locker, entry.key.get()))
187                     continue;
188             }
189             ScopeOffset offset = symbolTable->takeNextScopeOffset(locker);
190             SymbolTableEntry newEntry(VarOffset(offset), entry.value.isConst() ? ReadOnly : 0);
191             newEntry.prepareToWatch();
192             symbolTable->add(locker, entry.key.get(), newEntry);
193             
194             ScopeOffset offsetForAssert = globalLexicalEnvironment->addVariables(1, jsTDZValue());
195             RELEASE_ASSERT(offsetForAssert == offset);
196         }
197     }
198     return nullptr;
199 }
200
201 void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
202 {
203     ProgramExecutable* thisObject = jsCast<ProgramExecutable*>(cell);
204     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
205     ScriptExecutable::visitChildren(thisObject, visitor);
206     visitor.append(&thisObject->m_unlinkedProgramCodeBlock);
207     if (ProgramCodeBlock* programCodeBlock = thisObject->m_programCodeBlock.get())
208         programCodeBlock->visitWeakly(visitor);
209 }
210
211 } // namespace JSC