source: webkit/trunk/Source/JavaScriptCore/parser/ParserModes.h

Last change on this file was 278588, checked in by Alexey Shvayka, 4 years ago

Introduce LexicalScopeFeatures to enable future bytecode optimizations
https://bugs.webkit.org/show_bug.cgi?id=224072

Reviewed by Keith Miller.

Before this patch, BytecodeGenerator was capable of reasoning about the presence of with
statements, direct eval, or any other code features only within the current executable:

`
with (foo) {

(function() {

There was no way to detect WithScope during generation of this function.

})();

}
`

This change is required for op_to_this rewrite (#225397): if FunctionCallResolveNode and
friends knew there is no WithScope, op_call could be emitted with |this| value of
undefined as per spec [1], instead of resolved scope. This would:

  • simplify op_to_this on all tiers, likely resulting in minor perf boost;
  • save 1 instruction per strict function by removing op_to_this;
  • remove toThis() from the method table and ~30 its call sites from built-ins;
  • fix built-in methods that were observably lacking toThis();
  • fix proto getter / setter called on global scope;
  • fix WebIDL accessors called with |this| value of undefined and null.

Also, if ResolveNode knew that unforgeable global properties are not shadowed and there
is no with statement or sloppy mode direct eval, then undefined / Infinity / NaN
lookups could be constant-folded. This would save up to 3 bytecode ops per each usage
and allow emitting op_is_undefined_or_null for x === undefined || x === null.
V8 performs this optimization [2].

This patch introduces LexicalScopeFeatures to allow passing such information from Parser
to BytecodeGenerator with a minimal code diff. These features are kept separate from
CodeFeature to simplify reasoning about feature's scope and because we need to propagate
lexical features from parent to child scope.

Strict mode is the first use case of LexicalScopeFeatures, which this change carefully
fits into existing abstractions without increasing their memory usage even by 1 byte.

[1]: https://tc39.es/ecma262/#sec-evaluatecall (step 2)
[2]: https://medium.com/@bmeurer/sometimes-undefined-is-defined-7701e1c9eff8

  • builtins/BuiltinExecutables.cpp:

(JSC::BuiltinExecutables::createExecutable):

  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):

  • bytecode/UnlinkedCodeBlock.h:

(JSC::UnlinkedCodeBlock::recordParse):
(JSC::UnlinkedCodeBlock::lexicalScopeFeatures const):

  • bytecode/UnlinkedFunctionExecutable.cpp:

(JSC::generateUnlinkedFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
(JSC::UnlinkedFunctionExecutable::setInvalidTypeProfilingOffsets):

  • bytecode/UnlinkedFunctionExecutable.h:
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitNewClassFieldInitializerFunction):

  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::lexicalScopeFeatures const):
(JSC::BytecodeGenerator::generate):

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createFunctionMetadata):

  • parser/Nodes.cpp:

(JSC::ScopeNode::ScopeNode):
(JSC::ProgramNode::ProgramNode):
(JSC::ModuleProgramNode::ModuleProgramNode):
(JSC::EvalNode::EvalNode):
(JSC::FunctionMetadataNode::FunctionMetadataNode):
(JSC::FunctionMetadataNode::operator== const):
(JSC::FunctionMetadataNode::dump const):
(JSC::FunctionNode::FunctionNode):

  • parser/Nodes.h:

(JSC::ScopeNode::lexicalScopeFeatures):
(JSC::ScopeNode::isStrictMode const):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::parseGeneratorFunctionSourceElements):
(JSC::Parser<LexerType>::parseAsyncFunctionSourceElements):
(JSC::Parser<LexerType>::parseAsyncGeneratorFunctionSourceElements):
(JSC::Parser<LexerType>::parseFunctionBody):
(JSC::Parser<LexerType>::parseFunctionInfo):

  • parser/Parser.h:

(JSC::Scope::Scope):
(JSC::Scope::lexicalScopeFeatures const):
(JSC::Scope::setStrictMode):
(JSC::Scope::strictMode const):
(JSC::Scope::fillParametersForSourceProviderCache):
(JSC::Scope::restoreFromSourceProviderCache):
(JSC::Parser::pushScope):
(JSC::Parser::lexicalScopeFeatures):
(JSC::Parser<LexerType>::parse):

  • parser/ParserModes.h:
  • parser/SourceProviderCacheItem.h:

(JSC::SourceProviderCacheItem::lexicalScopeFeatures const):
(JSC::SourceProviderCacheItem::SourceProviderCacheItem):

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createFunctionMetadata):

  • runtime/CachedBytecode.cpp:

(JSC::CachedBytecode::addFunctionUpdate):

  • runtime/CachedTypes.cpp:

(JSC::CachedFunctionExecutable::lexicalScopeFeatures const):
(JSC::CachedCodeBlock::lexicalScopeFeatures const):
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
(JSC::CachedFunctionExecutable::encode):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
(JSC::CachedCodeBlock<CodeBlockType>::encode):
(JSC::CachedFunctionExecutable::isInStrictContext const): Deleted.

  • runtime/CachedTypes.h:
  • runtime/CodeCache.cpp:

(JSC::generateUnlinkedCodeBlockImpl):
(JSC::CodeCache::getUnlinkedGlobalCodeBlock):

  • runtime/ECMAMode.h:

(JSC::ECMAMode::fromBool):

  • runtime/FunctionExecutable.cpp:

(JSC::FunctionExecutable::FunctionExecutable):

  • runtime/GlobalExecutable.h:

(JSC::GlobalExecutable::recordParse):
(JSC::GlobalExecutable::GlobalExecutable):

  • runtime/ScriptExecutable.cpp:

(JSC::ScriptExecutable::ScriptExecutable):
(JSC::ScriptExecutable::newCodeBlockFor):
(JSC::ScriptExecutable::recordParse):

  • runtime/ScriptExecutable.h:

(JSC::ScriptExecutable::isInStrictContext const):
(JSC::ScriptExecutable::recordParse):

File size: 13.3 KB
Line 
1/*
2 * Copyright (C) 2012-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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "ConstructAbility.h"
29#include "ConstructorKind.h"
30#include "Identifier.h"
31
32namespace JSC {
33
34enum class JSParserStrictMode { NotStrict, Strict };
35enum class JSParserBuiltinMode { NotBuiltin, Builtin };
36enum class JSParserScriptMode { Classic, Module };
37
38enum class SuperBinding { Needed, NotNeeded };
39
40enum class PrivateBrandRequirement { None, Needed };
41
42enum class CodeGenerationMode : uint8_t {
43 Debugger = 1 << 0,
44 TypeProfiler = 1 << 1,
45 ControlFlowProfiler = 1 << 2,
46};
47
48enum class FunctionMode { FunctionExpression, FunctionDeclaration, MethodDefinition };
49
50// Keep it less than 32, it means this should be within 5 bits.
51enum class SourceParseMode : uint8_t {
52 NormalFunctionMode = 0,
53 GeneratorBodyMode = 1,
54 GeneratorWrapperFunctionMode = 2,
55 GetterMode = 3,
56 SetterMode = 4,
57 MethodMode = 5,
58 ArrowFunctionMode = 6,
59 AsyncFunctionBodyMode = 7,
60 AsyncArrowFunctionBodyMode = 8,
61 AsyncFunctionMode = 9,
62 AsyncMethodMode = 10,
63 AsyncArrowFunctionMode = 11,
64 ProgramMode = 12,
65 ModuleAnalyzeMode = 13,
66 ModuleEvaluateMode = 14,
67 AsyncGeneratorBodyMode = 15,
68 AsyncGeneratorWrapperFunctionMode = 16,
69 AsyncGeneratorWrapperMethodMode = 17,
70 GeneratorWrapperMethodMode = 18,
71 ClassFieldInitializerMode = 19,
72};
73
74class SourceParseModeSet {
75public:
76 template<typename... Modes>
77 constexpr SourceParseModeSet(Modes... args)
78 : m_mask(mergeSourceParseModes(args...))
79 {
80 }
81
82 ALWAYS_INLINE constexpr bool contains(SourceParseMode mode)
83 {
84 return (1U << static_cast<unsigned>(mode)) & m_mask;
85 }
86
87private:
88 ALWAYS_INLINE static constexpr unsigned mergeSourceParseModes(SourceParseMode mode)
89 {
90 return (1U << static_cast<unsigned>(mode));
91 }
92
93 template<typename... Rest>
94 ALWAYS_INLINE static constexpr unsigned mergeSourceParseModes(SourceParseMode mode, Rest... rest)
95 {
96 return (1U << static_cast<unsigned>(mode)) | mergeSourceParseModes(rest...);
97 }
98
99 const unsigned m_mask;
100};
101
102ALWAYS_INLINE bool isFunctionParseMode(SourceParseMode parseMode)
103{
104 return SourceParseModeSet(
105 SourceParseMode::NormalFunctionMode,
106 SourceParseMode::GeneratorBodyMode,
107 SourceParseMode::GeneratorWrapperFunctionMode,
108 SourceParseMode::GeneratorWrapperMethodMode,
109 SourceParseMode::GetterMode,
110 SourceParseMode::SetterMode,
111 SourceParseMode::MethodMode,
112 SourceParseMode::ArrowFunctionMode,
113 SourceParseMode::AsyncFunctionBodyMode,
114 SourceParseMode::AsyncFunctionMode,
115 SourceParseMode::AsyncMethodMode,
116 SourceParseMode::AsyncArrowFunctionMode,
117 SourceParseMode::AsyncArrowFunctionBodyMode,
118 SourceParseMode::AsyncGeneratorBodyMode,
119 SourceParseMode::AsyncGeneratorWrapperFunctionMode,
120 SourceParseMode::AsyncGeneratorWrapperMethodMode,
121 SourceParseMode::ClassFieldInitializerMode).contains(parseMode);
122}
123
124ALWAYS_INLINE bool isAsyncFunctionParseMode(SourceParseMode parseMode)
125{
126 return SourceParseModeSet(
127 SourceParseMode::AsyncGeneratorWrapperFunctionMode,
128 SourceParseMode::AsyncGeneratorBodyMode,
129 SourceParseMode::AsyncGeneratorWrapperMethodMode,
130 SourceParseMode::AsyncFunctionBodyMode,
131 SourceParseMode::AsyncFunctionMode,
132 SourceParseMode::AsyncMethodMode,
133 SourceParseMode::AsyncArrowFunctionMode,
134 SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode);
135}
136
137ALWAYS_INLINE bool isAsyncArrowFunctionParseMode(SourceParseMode parseMode)
138{
139 return SourceParseModeSet(
140 SourceParseMode::AsyncArrowFunctionMode,
141 SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode);
142}
143
144ALWAYS_INLINE bool isAsyncGeneratorParseMode(SourceParseMode parseMode)
145{
146 return SourceParseModeSet(
147 SourceParseMode::AsyncGeneratorWrapperFunctionMode,
148 SourceParseMode::AsyncGeneratorWrapperMethodMode,
149 SourceParseMode::AsyncGeneratorBodyMode).contains(parseMode);
150}
151
152ALWAYS_INLINE bool isAsyncGeneratorWrapperParseMode(SourceParseMode parseMode)
153{
154 return SourceParseModeSet(
155 SourceParseMode::AsyncGeneratorWrapperFunctionMode,
156 SourceParseMode::AsyncGeneratorWrapperMethodMode).contains(parseMode);
157}
158
159ALWAYS_INLINE bool isAsyncFunctionOrAsyncGeneratorWrapperParseMode(SourceParseMode parseMode)
160{
161 return SourceParseModeSet(
162 SourceParseMode::AsyncArrowFunctionMode,
163 SourceParseMode::AsyncFunctionMode,
164 SourceParseMode::AsyncGeneratorWrapperFunctionMode,
165 SourceParseMode::AsyncGeneratorWrapperMethodMode,
166 SourceParseMode::AsyncMethodMode).contains(parseMode);
167 }
168
169ALWAYS_INLINE bool isAsyncFunctionWrapperParseMode(SourceParseMode parseMode)
170{
171 return SourceParseModeSet(
172 SourceParseMode::AsyncArrowFunctionMode,
173 SourceParseMode::AsyncFunctionMode,
174 SourceParseMode::AsyncMethodMode).contains(parseMode);
175}
176
177ALWAYS_INLINE bool isAsyncFunctionBodyParseMode(SourceParseMode parseMode)
178{
179 return SourceParseModeSet(
180 SourceParseMode::AsyncFunctionBodyMode,
181 SourceParseMode::AsyncGeneratorBodyMode,
182 SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode);
183}
184
185ALWAYS_INLINE bool isGeneratorMethodParseMode(SourceParseMode parseMode)
186{
187 return SourceParseModeSet(
188 SourceParseMode::GeneratorWrapperMethodMode).contains(parseMode);
189}
190
191ALWAYS_INLINE bool isAsyncMethodParseMode(SourceParseMode parseMode)
192{
193 return SourceParseModeSet(SourceParseMode::AsyncMethodMode).contains(parseMode);
194}
195
196ALWAYS_INLINE bool isAsyncGeneratorMethodParseMode(SourceParseMode parseMode)
197{
198 return SourceParseModeSet(SourceParseMode::AsyncGeneratorWrapperMethodMode).contains(parseMode);
199}
200
201ALWAYS_INLINE bool isMethodParseMode(SourceParseMode parseMode)
202{
203 return SourceParseModeSet(
204 SourceParseMode::GeneratorWrapperMethodMode,
205 SourceParseMode::GetterMode,
206 SourceParseMode::SetterMode,
207 SourceParseMode::MethodMode,
208 SourceParseMode::AsyncMethodMode,
209 SourceParseMode::AsyncGeneratorWrapperMethodMode).contains(parseMode);
210}
211
212ALWAYS_INLINE bool isGeneratorOrAsyncFunctionBodyParseMode(SourceParseMode parseMode)
213{
214 return SourceParseModeSet(
215 SourceParseMode::GeneratorBodyMode,
216 SourceParseMode::AsyncFunctionBodyMode,
217 SourceParseMode::AsyncGeneratorBodyMode,
218 SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode);
219}
220
221ALWAYS_INLINE bool isGeneratorOrAsyncFunctionWrapperParseMode(SourceParseMode parseMode)
222{
223 return SourceParseModeSet(
224 SourceParseMode::GeneratorWrapperFunctionMode,
225 SourceParseMode::GeneratorWrapperMethodMode,
226 SourceParseMode::AsyncFunctionMode,
227 SourceParseMode::AsyncArrowFunctionMode,
228 SourceParseMode::AsyncGeneratorWrapperFunctionMode,
229 SourceParseMode::AsyncMethodMode,
230 SourceParseMode::AsyncGeneratorWrapperMethodMode).contains(parseMode);
231}
232
233ALWAYS_INLINE bool isGeneratorParseMode(SourceParseMode parseMode)
234{
235 return SourceParseModeSet(
236 SourceParseMode::GeneratorBodyMode,
237 SourceParseMode::GeneratorWrapperFunctionMode,
238 SourceParseMode::GeneratorWrapperMethodMode).contains(parseMode);
239}
240
241ALWAYS_INLINE bool isGeneratorWrapperParseMode(SourceParseMode parseMode)
242{
243 return SourceParseModeSet(
244 SourceParseMode::GeneratorWrapperFunctionMode,
245 SourceParseMode::GeneratorWrapperMethodMode).contains(parseMode);
246}
247
248ALWAYS_INLINE bool isArrowFunctionParseMode(SourceParseMode parseMode)
249{
250 return SourceParseModeSet(
251 SourceParseMode::ArrowFunctionMode,
252 SourceParseMode::AsyncArrowFunctionMode,
253 SourceParseMode::AsyncArrowFunctionBodyMode).contains(parseMode);
254}
255
256ALWAYS_INLINE bool isModuleParseMode(SourceParseMode parseMode)
257{
258 return SourceParseModeSet(
259 SourceParseMode::ModuleAnalyzeMode,
260 SourceParseMode::ModuleEvaluateMode).contains(parseMode);
261}
262
263ALWAYS_INLINE bool isProgramParseMode(SourceParseMode parseMode)
264{
265 return SourceParseModeSet(SourceParseMode::ProgramMode).contains(parseMode);
266}
267
268ALWAYS_INLINE bool isProgramOrModuleParseMode(SourceParseMode parseMode)
269{
270 return SourceParseModeSet(
271 SourceParseMode::ProgramMode,
272 SourceParseMode::ModuleAnalyzeMode,
273 SourceParseMode::ModuleEvaluateMode).contains(parseMode);
274}
275
276ALWAYS_INLINE ConstructAbility constructAbilityForParseMode(SourceParseMode parseMode)
277{
278 if (parseMode == SourceParseMode::NormalFunctionMode)
279 return ConstructAbility::CanConstruct;
280
281 return ConstructAbility::CannotConstruct;
282}
283
284inline bool functionNameIsInScope(const Identifier& name, FunctionMode functionMode)
285{
286 if (name.isNull())
287 return false;
288
289 if (functionMode != FunctionMode::FunctionExpression)
290 return false;
291
292 return true;
293}
294
295inline bool functionNameScopeIsDynamic(bool usesEval, bool isStrictMode)
296{
297 // If non-strict eval is in play, a function gets a separate object in the scope chain for its name.
298 // This enables eval to declare and then delete a name that shadows the function's name.
299
300 if (!usesEval)
301 return false;
302
303 if (isStrictMode)
304 return false;
305
306 return true;
307}
308
309typedef uint8_t LexicalScopeFeatures;
310
311const LexicalScopeFeatures NoLexicalFeatures = 0;
312const LexicalScopeFeatures StrictModeLexicalFeature = 1 << 0;
313
314const LexicalScopeFeatures AllLexicalFeatures = NoLexicalFeatures | StrictModeLexicalFeature;
315static_assert(AllLexicalFeatures <= 0b1111, "LexicalScopeFeatures must be 4bits");
316
317typedef uint16_t CodeFeatures;
318
319const CodeFeatures NoFeatures = 0;
320const CodeFeatures EvalFeature = 1 << 0;
321const CodeFeatures ArgumentsFeature = 1 << 1;
322const CodeFeatures WithFeature = 1 << 2;
323const CodeFeatures ThisFeature = 1 << 3;
324const CodeFeatures NonSimpleParameterListFeature = 1 << 4;
325const CodeFeatures ShadowsArgumentsFeature = 1 << 5;
326const CodeFeatures ArrowFunctionFeature = 1 << 6;
327const CodeFeatures AwaitFeature = 1 << 7;
328const CodeFeatures SuperCallFeature = 1 << 8;
329const CodeFeatures SuperPropertyFeature = 1 << 9;
330const CodeFeatures NewTargetFeature = 1 << 10;
331const CodeFeatures NoEvalCacheFeature = 1 << 11;
332
333const CodeFeatures AllFeatures = EvalFeature | ArgumentsFeature | WithFeature | ThisFeature | NonSimpleParameterListFeature | ShadowsArgumentsFeature | ArrowFunctionFeature | AwaitFeature | SuperCallFeature | SuperPropertyFeature | NewTargetFeature | NoEvalCacheFeature;
334static_assert(AllFeatures < (1 << 14), "CodeFeatures must be 14bits");
335
336typedef uint8_t InnerArrowFunctionCodeFeatures;
337
338const InnerArrowFunctionCodeFeatures NoInnerArrowFunctionFeatures = 0;
339const InnerArrowFunctionCodeFeatures EvalInnerArrowFunctionFeature = 1 << 0;
340const InnerArrowFunctionCodeFeatures ArgumentsInnerArrowFunctionFeature = 1 << 1;
341const InnerArrowFunctionCodeFeatures ThisInnerArrowFunctionFeature = 1 << 2;
342const InnerArrowFunctionCodeFeatures SuperCallInnerArrowFunctionFeature = 1 << 3;
343const InnerArrowFunctionCodeFeatures SuperPropertyInnerArrowFunctionFeature = 1 << 4;
344const InnerArrowFunctionCodeFeatures NewTargetInnerArrowFunctionFeature = 1 << 5;
345
346const InnerArrowFunctionCodeFeatures AllInnerArrowFunctionCodeFeatures = EvalInnerArrowFunctionFeature | ArgumentsInnerArrowFunctionFeature | ThisInnerArrowFunctionFeature | SuperCallInnerArrowFunctionFeature | SuperPropertyInnerArrowFunctionFeature | NewTargetInnerArrowFunctionFeature;
347static_assert(AllInnerArrowFunctionCodeFeatures <= 0b111111, "InnerArrowFunctionCodeFeatures must be 6bits");
348} // namespace JSC
Note: See TracBrowser for help on using the repository browser.