/src/hermes/lib/IRGen/ESTreeIRGen-func.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) Meta Platforms, Inc. and affiliates. |
3 | | * |
4 | | * This source code is licensed under the MIT license found in the |
5 | | * LICENSE file in the root directory of this source tree. |
6 | | */ |
7 | | |
8 | | #include "ESTreeIRGen.h" |
9 | | |
10 | | #include "llvh/ADT/SmallString.h" |
11 | | |
12 | | #include <variant> |
13 | | |
14 | | namespace hermes { |
15 | | namespace irgen { |
16 | | |
17 | | //===----------------------------------------------------------------------===// |
18 | | // FunctionContext |
19 | | |
20 | | FunctionContext::FunctionContext( |
21 | | ESTreeIRGen *irGen, |
22 | | Function *function, |
23 | | sem::FunctionInfo *semInfo) |
24 | 1.33k | : irGen_(irGen), |
25 | 1.33k | semInfo_(semInfo), |
26 | 1.33k | oldContext_(irGen->functionContext_), |
27 | 1.33k | builderSaveState_(irGen->Builder), |
28 | 1.33k | function(function), |
29 | 1.33k | anonymousIDs_(function->getContext().getStringTable()), |
30 | 1.33k | enterFunctionScope(this) { |
31 | 1.33k | setupFunctionScope(&enterFunctionScope); |
32 | 1.33k | irGen->functionContext_ = this; |
33 | 1.33k | irGen->currentIRScopeDesc_ = function->getFunctionScopeDesc(); |
34 | | |
35 | | // Temporarily set the current IR scope to nullptr. IRGen should materialize |
36 | | // currentIRScopeDesc_ before trying to access it. |
37 | 1.33k | irGen->currentIRScope_ = nullptr; |
38 | | |
39 | | // Initialize it to LiteralUndefined by default to avoid corner cases. |
40 | 1.33k | this->capturedNewTarget = irGen->Builder.getLiteralUndefined(); |
41 | | |
42 | 1.33k | if (semInfo_) { |
43 | | // Allocate the label table. Each label definition will be encountered in |
44 | | // the AST before it is referenced (because of the nature of JavaScript), at |
45 | | // which point we will initialize the GotoLabel structure with basic blocks |
46 | | // targets. |
47 | 1.33k | labels_.resize(semInfo_->labelCount); |
48 | 1.33k | } |
49 | 1.33k | } |
50 | | |
51 | 1.33k | void FunctionContext::setupFunctionScope(EnterBlockScope *scope) { |
52 | 1.33k | functionScope = &scope->blockScope_; |
53 | 1.33k | blockScope = functionScope; |
54 | 1.33k | } |
55 | | |
56 | 1.33k | FunctionContext::~FunctionContext() { |
57 | 1.33k | irGen_->functionContext_ = oldContext_; |
58 | 1.33k | irGen_->Builder.setCurrentSourceLevelScope(irGen_->currentIRScopeDesc_); |
59 | 1.33k | } |
60 | | |
61 | 1.72k | Identifier FunctionContext::genAnonymousLabelName(llvh::StringRef hint) { |
62 | 1.72k | return anonymousIDs_.next(hint); |
63 | 1.72k | } |
64 | | |
65 | | //===----------------------------------------------------------------------===// |
66 | | // EnterBlockScope |
67 | | EnterBlockScope::EnterBlockScope(FunctionContext *currentContext) |
68 | 1.33k | : currentContext_(currentContext), |
69 | 1.33k | oldIRScopeDesc_(currentContext->irGen_->currentIRScopeDesc_), |
70 | 1.33k | oldIRScope_(currentContext->irGen_->currentIRScope_), |
71 | 1.33k | oldBlockScope_(currentContext->blockScope), |
72 | 1.33k | blockScope_(currentContext->irGen_->nameTable_) { |
73 | 1.33k | currentContext->blockScope = &blockScope_; |
74 | 1.33k | } |
75 | | |
76 | 1.33k | EnterBlockScope::~EnterBlockScope() { |
77 | 1.33k | ESTreeIRGen *irgen = currentContext_->irGen_; |
78 | 1.33k | currentContext_->blockScope = oldBlockScope_; |
79 | 1.33k | irgen->currentIRScope_ = oldIRScope_; |
80 | 1.33k | irgen->currentIRScopeDesc_ = oldIRScopeDesc_; |
81 | 1.33k | irgen->Builder.setCurrentSourceLevelScope(irgen->currentIRScopeDesc_); |
82 | 1.33k | } |
83 | | |
84 | | //===----------------------------------------------------------------------===// |
85 | | // ESTreeIRGen |
86 | | |
87 | | void ESTreeIRGen::genFunctionDeclaration( |
88 | 0 | ESTree::FunctionDeclarationNode *func) { |
89 | | // Find the name of the function. |
90 | 0 | Identifier functionName = getNameFieldFromID(func->_id); |
91 | 0 | LLVM_DEBUG(llvh::dbgs() << "IRGen function \"" << functionName << "\".\n"); |
92 | |
|
93 | 0 | Function *newFunc = func->_async |
94 | 0 | ? genAsyncFunction(functionName, nullptr, func) |
95 | 0 | : func->_generator ? genGeneratorFunction(functionName, nullptr, func) |
96 | 0 | : genES5Function(functionName, nullptr, func); |
97 | |
|
98 | 0 | functionForDecl[func] = {newFunc, AlreadyEmitted::No}; |
99 | 0 | } |
100 | | |
101 | 0 | void ESTreeIRGen::emitCreateFunction(ESTree::FunctionDeclarationNode *func) { |
102 | 0 | Identifier functionName = getNameFieldFromID(func->_id); |
103 | |
|
104 | 0 | auto it = functionForDecl.find(func); |
105 | 0 | assert(it != functionForDecl.end() && "all inner functions should be known"); |
106 | | |
107 | 0 | if (it->second.second == AlreadyEmitted::Yes) { |
108 | 0 | return; |
109 | 0 | } |
110 | | |
111 | 0 | it->second.second = AlreadyEmitted::Yes; |
112 | |
|
113 | 0 | auto *funcStorage = nameTable_.lookup(functionName); |
114 | 0 | assert( |
115 | 0 | funcStorage && "function declaration variable should have been hoisted"); |
116 | | |
117 | | // Store the newly created closure into a frame variable with the same name. |
118 | 0 | auto *newClosure = |
119 | 0 | Builder.createCreateFunctionInst(it->second.first, currentIRScope_); |
120 | |
|
121 | 0 | emitStore(newClosure, funcStorage, true); |
122 | 0 | } |
123 | | |
124 | 1.37k | void ESTreeIRGen::hoistCreateFunctions(ESTree::Node *containingNode) { |
125 | 1.37k | const auto &closures = curFunction()->getSemInfo()->closures; |
126 | 1.37k | auto it = closures.find(containingNode); |
127 | 1.37k | if (it == closures.end()) { |
128 | 0 | return; |
129 | 0 | } |
130 | | |
131 | 1.37k | for (ESTree::FunctionDeclarationNode *funcDecl : *it->second) { |
132 | 0 | emitCreateFunction(funcDecl); |
133 | 0 | } |
134 | 1.37k | } |
135 | | |
136 | | Value *ESTreeIRGen::genFunctionExpression( |
137 | | ESTree::FunctionExpressionNode *FE, |
138 | 6 | Identifier nameHint) { |
139 | 6 | LLVM_DEBUG( |
140 | 6 | llvh::dbgs() |
141 | 6 | << "Creating anonymous closure. " |
142 | 6 | << Builder.getInsertionBlock()->getParent()->getInternalName() << ".\n"); |
143 | | |
144 | 6 | std::variant<std::monostate, NameTableScopeTy, EnterBlockScope> newScope; |
145 | | |
146 | 6 | if (!Mod->getContext().getCodeGenerationSettings().enableBlockScoping) { |
147 | 6 | newScope.emplace<NameTableScopeTy>(nameTable_); |
148 | 6 | } else { |
149 | 0 | newScope.emplace<EnterBlockScope>(curFunction()); |
150 | 0 | newDeclarativeEnvironment(); |
151 | 0 | } |
152 | 6 | Variable *tempClosureVar = nullptr; |
153 | | |
154 | 6 | Identifier originalNameIden = nameHint; |
155 | 6 | if (FE->_id) { |
156 | 0 | if (!Mod->getContext().getCodeGenerationSettings().enableBlockScoping) { |
157 | 0 | auto closureName = genAnonymousLabelName("closure"); |
158 | 0 | tempClosureVar = Builder.createVariable( |
159 | 0 | curFunction()->function->getFunctionScopeDesc(), |
160 | 0 | Variable::DeclKind::Var, |
161 | 0 | closureName); |
162 | | |
163 | | // Insert the synthesized variable into the name table, so it can be |
164 | | // looked up internally as well. |
165 | 0 | nameTable_.insertIntoScope( |
166 | 0 | curFunction()->functionScope, |
167 | 0 | tempClosureVar->getName(), |
168 | 0 | tempClosureVar); |
169 | | |
170 | | // Alias the lexical name to the synthesized variable. |
171 | 0 | originalNameIden = getNameFieldFromID(FE->_id); |
172 | 0 | nameTable_.insert(originalNameIden, tempClosureVar); |
173 | 0 | } else { |
174 | | // Use the expression's ID for its closure name, as well as its variable |
175 | | // name -- which is OK because we're in a new scope. |
176 | 0 | originalNameIden = getNameFieldFromID(FE->_id); |
177 | |
|
178 | 0 | auto closureName = genAnonymousLabelName(originalNameIden.str()); |
179 | 0 | tempClosureVar = Builder.createVariable( |
180 | 0 | currentIRScopeDesc_, Variable::DeclKind::Const, closureName); |
181 | | |
182 | | // ES2023 dictates that function expression's ID are non-strict immutable |
183 | | // bindings. |
184 | 0 | tempClosureVar->setStrictImmutableBinding(false); |
185 | |
|
186 | 0 | nameTable_.insertIntoScope( |
187 | 0 | curFunction()->blockScope, originalNameIden, tempClosureVar); |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | 6 | Function *newFunc = FE->_async |
192 | 6 | ? genAsyncFunction(originalNameIden, tempClosureVar, FE) |
193 | 6 | : FE->_generator |
194 | 6 | ? genGeneratorFunction(originalNameIden, tempClosureVar, FE) |
195 | 6 | : genES5Function(originalNameIden, tempClosureVar, FE); |
196 | | |
197 | 6 | Value *closure = Builder.createCreateFunctionInst(newFunc, currentIRScope_); |
198 | | |
199 | 6 | if (tempClosureVar) |
200 | 0 | emitStore(closure, tempClosureVar, true); |
201 | | |
202 | 6 | return closure; |
203 | 6 | } |
204 | | |
205 | | Value *ESTreeIRGen::genArrowFunctionExpression( |
206 | | ESTree::ArrowFunctionExpressionNode *AF, |
207 | 1.30k | Identifier nameHint) { |
208 | 1.30k | LLVM_DEBUG( |
209 | 1.30k | llvh::dbgs() |
210 | 1.30k | << "Creating arrow function. " |
211 | 1.30k | << Builder.getInsertionBlock()->getParent()->getInternalName() << ".\n"); |
212 | | |
213 | 1.30k | if (AF->_async) { |
214 | 0 | Builder.getModule()->getContext().getSourceErrorManager().error( |
215 | 0 | AF->getSourceRange(), Twine("async functions are unsupported")); |
216 | 0 | return Builder.getLiteralUndefined(); |
217 | 0 | } |
218 | | |
219 | 1.30k | auto *newFunc = Builder.createFunction( |
220 | 1.30k | newScopeDesc(), |
221 | 1.30k | genAnonymousFunctionNameIfNeeded(nameHint), |
222 | 1.30k | Function::DefinitionKind::ES6Arrow, |
223 | 1.30k | ESTree::isStrict(AF->strictness), |
224 | 1.30k | AF->sourceVisibility, |
225 | 1.30k | AF->getSourceRange()); |
226 | | |
227 | 1.30k | { |
228 | 1.30k | FunctionContext newFunctionContext{this, newFunc, AF->getSemInfo()}; |
229 | | |
230 | | // Propagate captured "this", "new.target" and "arguments" from parents. |
231 | 1.30k | auto *prev = curFunction()->getPreviousContext(); |
232 | 1.30k | curFunction()->capturedThis = prev->capturedThis; |
233 | 1.30k | curFunction()->capturedNewTarget = prev->capturedNewTarget; |
234 | 1.30k | curFunction()->capturedArguments = prev->capturedArguments; |
235 | | |
236 | 1.30k | emitFunctionPreamble(Builder.createBasicBlock(newFunc)); |
237 | 1.30k | emitTopLevelDeclarations(AF, AF->_body, DoEmitParameters::YesMultiScopes); |
238 | | |
239 | 1.30k | genFunctionBody(AF->_body); |
240 | 1.30k | emitFunctionEpilogue(Builder.getLiteralUndefined()); |
241 | 1.30k | } |
242 | | |
243 | | // Emit CreateFunctionInst after we have restored the builder state. |
244 | 1.30k | return Builder.createCreateFunctionInst(newFunc, currentIRScope_); |
245 | 1.30k | } |
246 | | |
247 | | namespace { |
248 | 6 | ESTree::NodeKind getLazyFunctionKind(ESTree::FunctionLikeNode *node) { |
249 | 6 | if (node->isMethodDefinition) { |
250 | | // This is not a regular function expression but getter/setter. |
251 | | // If we want to reparse it later, we have to start from an |
252 | | // identifier and not from a 'function' keyword. |
253 | 0 | return ESTree::NodeKind::Property; |
254 | 0 | } |
255 | 6 | return node->getKind(); |
256 | 6 | } |
257 | | } // namespace |
258 | | Function *ESTreeIRGen::genES5Function( |
259 | | Identifier originalName, |
260 | | Variable *lazyClosureAlias, |
261 | | ESTree::FunctionLikeNode *functionNode, |
262 | 6 | bool isGeneratorInnerFunction) { |
263 | 6 | assert(functionNode && "Function AST cannot be null"); |
264 | | |
265 | 6 | auto *body = ESTree::getBlockStatement(functionNode); |
266 | 6 | assert(body && "body of ES5 function cannot be null"); |
267 | | |
268 | 6 | Function *newFunction = isGeneratorInnerFunction |
269 | 6 | ? Builder.createGeneratorInnerFunction( |
270 | 0 | newScopeDesc(), |
271 | 0 | genAnonymousFunctionNameIfNeeded(originalName), |
272 | 0 | Function::DefinitionKind::ES5Function, |
273 | 0 | ESTree::isStrict(functionNode->strictness), |
274 | 0 | functionNode->getSourceRange(), |
275 | 0 | /* insertBefore */ nullptr) |
276 | 6 | : Builder.createFunction( |
277 | 6 | newScopeDesc(), |
278 | 6 | genAnonymousFunctionNameIfNeeded(originalName), |
279 | 6 | Function::DefinitionKind::ES5Function, |
280 | 6 | ESTree::isStrict(functionNode->strictness), |
281 | 6 | functionNode->sourceVisibility, |
282 | 6 | functionNode->getSourceRange(), |
283 | 6 | /* isGlobal */ false, |
284 | 6 | /* insertBefore */ nullptr); |
285 | | |
286 | 6 | newFunction->setLazyClosureAlias(lazyClosureAlias); |
287 | | |
288 | 6 | if (auto *bodyBlock = llvh::dyn_cast<ESTree::BlockStatementNode>(body)) { |
289 | 6 | if (bodyBlock->isLazyFunctionBody) { |
290 | 6 | assert( |
291 | 6 | !isGeneratorInnerFunction && |
292 | 6 | "generator inner function should be included with outer function"); |
293 | 6 | setupLazyScope(functionNode, newFunction, body); |
294 | 6 | return newFunction; |
295 | 6 | } |
296 | 6 | } |
297 | | |
298 | 0 | FunctionContext newFunctionContext{ |
299 | 0 | this, newFunction, functionNode->getSemInfo()}; |
300 | |
|
301 | 0 | if (isGeneratorInnerFunction) { |
302 | | // StartGeneratorInst |
303 | | // ResumeGeneratorInst |
304 | | // at the beginning of the function, to allow for the first .next() call. |
305 | 0 | auto *initGenBB = Builder.createBasicBlock(newFunction); |
306 | 0 | Builder.setInsertionBlock(initGenBB); |
307 | 0 | Builder.createStartGeneratorInst(); |
308 | 0 | auto *prologueBB = Builder.createBasicBlock(newFunction); |
309 | 0 | auto *prologueResumeIsReturn = Builder.createAllocStackInst( |
310 | 0 | genAnonymousLabelName("isReturn_prologue")); |
311 | 0 | genResumeGenerator(GenFinally::No, prologueResumeIsReturn, prologueBB); |
312 | |
|
313 | 0 | if (hasSimpleParams(functionNode)) { |
314 | | // If there are simple params, then we don't need an extra yield/resume. |
315 | | // They can simply be initialized on the first call to `.next`. |
316 | 0 | Builder.setInsertionBlock(prologueBB); |
317 | 0 | emitFunctionPreamble(prologueBB); |
318 | 0 | initCaptureStateInES5Function(); |
319 | 0 | emitTopLevelDeclarations( |
320 | 0 | functionNode, body, DoEmitParameters::YesMultiScopes); |
321 | 0 | } else { |
322 | | // If there are non-simple params, then we must add a new yield/resume. |
323 | | // The `.next()` call will occur once in the outer function, before |
324 | | // the iterator is returned to the caller of the `function*`. |
325 | 0 | auto *entryPointBB = Builder.createBasicBlock(newFunction); |
326 | 0 | auto *entryPointResumeIsReturn = |
327 | 0 | Builder.createAllocStackInst(genAnonymousLabelName("isReturn_entry")); |
328 | | |
329 | | // Initialize parameters. |
330 | 0 | Builder.setInsertionBlock(prologueBB); |
331 | 0 | emitFunctionPreamble(prologueBB); |
332 | 0 | initCaptureStateInES5Function(); |
333 | 0 | emitTopLevelDeclarations( |
334 | 0 | functionNode, body, DoEmitParameters::YesMultiScopes); |
335 | 0 | Builder.createSaveAndYieldInst( |
336 | 0 | Builder.getLiteralUndefined(), entryPointBB); |
337 | | |
338 | | // Actual entry point of function from the caller's perspective. |
339 | 0 | Builder.setInsertionBlock(entryPointBB); |
340 | 0 | genResumeGenerator( |
341 | 0 | GenFinally::No, |
342 | 0 | entryPointResumeIsReturn, |
343 | 0 | Builder.createBasicBlock(newFunction)); |
344 | 0 | } |
345 | 0 | } else { |
346 | 0 | emitFunctionPreamble(Builder.createBasicBlock(newFunction)); |
347 | 0 | initCaptureStateInES5Function(); |
348 | 0 | emitTopLevelDeclarations( |
349 | 0 | functionNode, body, DoEmitParameters::YesMultiScopes); |
350 | 0 | } |
351 | |
|
352 | 0 | genFunctionBody(body); |
353 | 0 | emitFunctionEpilogue(Builder.getLiteralUndefined()); |
354 | |
|
355 | 0 | return curFunction()->function; |
356 | 6 | } |
357 | | |
358 | | Function *ESTreeIRGen::genGeneratorFunction( |
359 | | Identifier originalName, |
360 | | Variable *lazyClosureAlias, |
361 | 0 | ESTree::FunctionLikeNode *functionNode) { |
362 | 0 | assert(functionNode && "Function AST cannot be null"); |
363 | | |
364 | 0 | if (!Builder.getModule()->getContext().isGeneratorEnabled()) { |
365 | 0 | Builder.getModule()->getContext().getSourceErrorManager().error( |
366 | 0 | functionNode->getSourceRange(), "generator compilation is disabled"); |
367 | 0 | } |
368 | | |
369 | | // Build the outer function which creates the generator. |
370 | | // Does not have an associated source range. |
371 | 0 | auto *outerFn = Builder.createGeneratorFunction( |
372 | 0 | newScopeDesc(), |
373 | 0 | genAnonymousFunctionNameIfNeeded(originalName), |
374 | 0 | Function::DefinitionKind::ES5Function, |
375 | 0 | ESTree::isStrict(functionNode->strictness), |
376 | 0 | functionNode->sourceVisibility, |
377 | 0 | functionNode->getSourceRange(), |
378 | 0 | /* insertBefore */ nullptr); |
379 | 0 | outerFn->setLazyClosureAlias(lazyClosureAlias); |
380 | |
|
381 | 0 | auto *body = ESTree::getBlockStatement(functionNode); |
382 | 0 | if (auto *bodyBlock = llvh::dyn_cast<ESTree::BlockStatementNode>(body)) { |
383 | 0 | if (bodyBlock->isLazyFunctionBody) { |
384 | 0 | setupLazyScope(functionNode, outerFn, body); |
385 | 0 | return outerFn; |
386 | 0 | } |
387 | 0 | } |
388 | | |
389 | 0 | { |
390 | 0 | FunctionContext outerFnContext{this, outerFn, functionNode->getSemInfo()}; |
391 | | |
392 | | // Build the inner function. This must be done in the outerFnContext |
393 | | // since it's lexically considered a child function. |
394 | 0 | auto *innerFn = genES5Function( |
395 | 0 | genAnonymousLabelName(originalName.isValid() ? originalName.str() : ""), |
396 | 0 | nullptr, |
397 | 0 | functionNode, |
398 | 0 | true); |
399 | |
|
400 | 0 | emitFunctionPreamble(Builder.createBasicBlock(outerFn)); |
401 | 0 | initCaptureStateInES5Function(); |
402 | 0 | emitTopLevelDeclarations( |
403 | 0 | functionNode, |
404 | 0 | ESTree::getBlockStatement(functionNode), |
405 | 0 | DoEmitParameters::No); |
406 | | |
407 | | // Create a generator function, which will store the arguments. |
408 | 0 | auto *gen = Builder.createCreateGeneratorInst(innerFn, currentIRScope_); |
409 | |
|
410 | 0 | if (!hasSimpleParams(functionNode)) { |
411 | | // If there are non-simple params, step the inner function once to |
412 | | // initialize them. |
413 | 0 | Value *next = Builder.createLoadPropertyInst(gen, "next"); |
414 | 0 | Builder.createCallInst(CallInst::kNoTextifiedCallee, next, gen, {}); |
415 | 0 | } |
416 | |
|
417 | 0 | emitFunctionEpilogue(gen); |
418 | 0 | } |
419 | |
|
420 | 0 | return outerFn; |
421 | 0 | } |
422 | | |
423 | | void ESTreeIRGen::setupLazyScope( |
424 | | ESTree::FunctionLikeNode *functionNode, |
425 | | Function *function, |
426 | 6 | ESTree::BlockStatementNode *bodyBlock) { |
427 | 6 | assert( |
428 | 6 | bodyBlock->isLazyFunctionBody && |
429 | 6 | "setupLazyScope can only be used with lazy function bodies"); |
430 | | // Set the AST position and variable context so we can continue later. |
431 | | // Save the scope chain starting from function's parent (i.e., the last |
432 | | // materialized scope). |
433 | 6 | function->setLazyScope( |
434 | 6 | saveScopeChain(function->getFunctionScopeDesc()->getParent())); |
435 | 6 | auto &lazySource = function->getLazySource(); |
436 | 6 | lazySource.bufferId = bodyBlock->bufferId; |
437 | 6 | lazySource.nodeKind = getLazyFunctionKind(functionNode); |
438 | 6 | lazySource.functionRange = functionNode->getSourceRange(); |
439 | 6 | lazySource.paramYield = bodyBlock->paramYield; |
440 | 6 | lazySource.paramAwait = bodyBlock->paramAwait; |
441 | | |
442 | | // Set the function's .length. |
443 | 6 | function->setExpectedParamCountIncludingThis( |
444 | 6 | countExpectedArgumentsIncludingThis(functionNode)); |
445 | 6 | } |
446 | | |
447 | | Function *ESTreeIRGen::genAsyncFunction( |
448 | | Identifier originalName, |
449 | | Variable *lazyClosureAlias, |
450 | 0 | ESTree::FunctionLikeNode *functionNode) { |
451 | 0 | assert(functionNode && "Function AST cannot be null"); |
452 | | |
453 | 0 | if (!Builder.getModule()->getContext().isGeneratorEnabled()) { |
454 | 0 | Builder.getModule()->getContext().getSourceErrorManager().error( |
455 | 0 | functionNode->getSourceRange(), |
456 | 0 | "async function compilation requires enabling generator"); |
457 | 0 | } |
458 | |
|
459 | 0 | auto *asyncFn = Builder.createAsyncFunction( |
460 | 0 | newScopeDesc(), |
461 | 0 | genAnonymousFunctionNameIfNeeded(originalName), |
462 | 0 | Function::DefinitionKind::ES5Function, |
463 | 0 | ESTree::isStrict(functionNode->strictness), |
464 | 0 | functionNode->sourceVisibility, |
465 | 0 | functionNode->getSourceRange(), |
466 | 0 | /* insertBefore */ nullptr); |
467 | | |
468 | | // Setup lazy compilation |
469 | 0 | asyncFn->setLazyClosureAlias(lazyClosureAlias); |
470 | |
|
471 | 0 | auto *body = ESTree::getBlockStatement(functionNode); |
472 | 0 | if (auto *bodyBlock = llvh::dyn_cast<ESTree::BlockStatementNode>(body)) { |
473 | 0 | if (bodyBlock->isLazyFunctionBody) { |
474 | 0 | setupLazyScope(functionNode, asyncFn, body); |
475 | 0 | return asyncFn; |
476 | 0 | } |
477 | 0 | } |
478 | | |
479 | 0 | { |
480 | 0 | FunctionContext asyncFnContext{this, asyncFn, functionNode->getSemInfo()}; |
481 | | |
482 | | // Build the inner generator. This must be done in the outerFnContext |
483 | | // since it's lexically considered a child function. |
484 | 0 | auto *gen = genGeneratorFunction( |
485 | 0 | genAnonymousLabelName(originalName.isValid() ? originalName.str() : ""), |
486 | 0 | lazyClosureAlias, |
487 | 0 | functionNode); |
488 | | |
489 | | // The outer async function need not emit code for parameters. |
490 | | // It would simply delegate `arguments` object down to inner generator. |
491 | | // This avoid emitting code e.g. destructuring parameters twice. |
492 | 0 | emitFunctionPreamble(Builder.createBasicBlock(asyncFn)); |
493 | 0 | initCaptureStateInES5Function(); |
494 | 0 | emitTopLevelDeclarations( |
495 | 0 | functionNode, |
496 | 0 | ESTree::getBlockStatement(functionNode), |
497 | 0 | DoEmitParameters::No); |
498 | |
|
499 | 0 | auto *genClosure = Builder.createCreateFunctionInst(gen, currentIRScope_); |
500 | 0 | auto *thisArg = curFunction()->function->getThisParameter(); |
501 | 0 | auto *argumentsList = curFunction()->createArgumentsInst; |
502 | |
|
503 | 0 | auto *spawnAsyncClosure = Builder.createGetBuiltinClosureInst( |
504 | 0 | BuiltinMethod::HermesBuiltin_spawnAsync); |
505 | |
|
506 | 0 | auto *res = Builder.createCallInst( |
507 | 0 | CallInst::kNoTextifiedCallee, |
508 | 0 | spawnAsyncClosure, |
509 | 0 | Builder.getLiteralUndefined(), |
510 | 0 | {genClosure, thisArg, argumentsList}); |
511 | |
|
512 | 0 | emitFunctionEpilogue(res); |
513 | 0 | } |
514 | 0 | return asyncFn; |
515 | 0 | } |
516 | | |
517 | 36 | void ESTreeIRGen::initCaptureStateInES5Function() { |
518 | | // Capture "this", "new.target" and "arguments" if there are inner arrows. |
519 | 36 | if (!curFunction()->getSemInfo()->containsArrowFunctions) |
520 | 31 | return; |
521 | | |
522 | | // "this". |
523 | 5 | curFunction()->capturedThis = Builder.createVariable( |
524 | 5 | currentIRScopeDesc_, |
525 | 5 | Variable::DeclKind::Var, |
526 | 5 | genAnonymousLabelName("this")); |
527 | 5 | emitStore( |
528 | 5 | Builder.getFunction()->getThisParameter(), |
529 | 5 | curFunction()->capturedThis, |
530 | 5 | true); |
531 | | |
532 | | // "new.target". |
533 | 5 | curFunction()->capturedNewTarget = Builder.createVariable( |
534 | 5 | currentIRScopeDesc_, |
535 | 5 | Variable::DeclKind::Var, |
536 | 5 | genAnonymousLabelName("new.target")); |
537 | 5 | emitStore( |
538 | 5 | Builder.createGetNewTargetInst(), curFunction()->capturedNewTarget, true); |
539 | | |
540 | | // "arguments". |
541 | 5 | if (curFunction()->getSemInfo()->containsArrowFunctionsUsingArguments) { |
542 | 0 | curFunction()->capturedArguments = Builder.createVariable( |
543 | 0 | currentIRScopeDesc_, |
544 | 0 | Variable::DeclKind::Var, |
545 | 0 | genAnonymousLabelName("arguments")); |
546 | 0 | emitStore( |
547 | 0 | curFunction()->createArgumentsInst, |
548 | 0 | curFunction()->capturedArguments, |
549 | 0 | true); |
550 | 0 | } |
551 | 5 | } |
552 | | |
553 | 1.33k | void ESTreeIRGen::emitFunctionPreamble(BasicBlock *entry) { |
554 | 1.33k | auto *newFunc = curFunction()->function; |
555 | | |
556 | 1.33k | Builder.setLocation(newFunc->getSourceRange().Start); |
557 | 1.33k | Builder.setCurrentSourceLevelScope(nullptr); |
558 | | |
559 | 1.33k | BasicBlock *realEntry = &newFunc->front(); |
560 | 1.33k | if (realEntry->empty()) { |
561 | 1.33k | Builder.setInsertionBlock(realEntry); |
562 | 1.33k | } else { |
563 | 0 | Builder.setInsertionPoint(&realEntry->front()); |
564 | 0 | } |
565 | | // Create the function scope. |
566 | 1.33k | currentIRScope_ = |
567 | 1.33k | Builder.createCreateScopeInst(newFunc->getFunctionScopeDesc()); |
568 | | |
569 | | // Start pumping instructions into the entry basic block. |
570 | 1.33k | Builder.setInsertionBlock(entry); |
571 | 1.33k | Builder.setCurrentSourceLevelScope(newFunc->getFunctionScopeDesc()); |
572 | | |
573 | | // Always insert a CreateArgumentsInst. We will delete it later if it is |
574 | | // unused. |
575 | 1.33k | curFunction()->createArgumentsInst = Builder.createCreateArgumentsInst(); |
576 | | |
577 | | // Always create the "this" parameter. It needs to be created before we |
578 | | // initialized the ES5 capture state. |
579 | 1.33k | Builder.createThisParameter(newFunc); |
580 | 1.33k | } |
581 | | |
582 | | void ESTreeIRGen::emitTopLevelDeclarations( |
583 | | ESTree::FunctionLikeNode *funcNode, |
584 | | ESTree::Node *body, |
585 | 1.33k | DoEmitParameters doEmitParameters) { |
586 | | // There is a lot happening in this function w.r.t. function scopes, but that |
587 | | // can be summarizes as follows: |
588 | | // |
589 | | // topLevelScope = Scope(); #1 |
590 | | // currentScope = topLevelScope |
591 | | // |
592 | | // if !isStrict and hasParamExpressions: |
593 | | // paramExpressionScope = InnerScope(currentScope) |
594 | | // currentScope = paramExpressionScope #2 |
595 | | // |
596 | | // << emit parameter expressions >> |
597 | | // |
598 | | // if hasParamExpressions: |
599 | | // varScope = InnerScope(currentScope) |
600 | | // currentScope = varScope #3 |
601 | | // |
602 | | // << emit var declarations >> |
603 | | // |
604 | | // if !isStrict: |
605 | | // lexicalScope = InnerScope(currentScope) #4 |
606 | | // currentScope = lexicalScope |
607 | | // |
608 | | // << emit lexical declarations >> |
609 | | // |
610 | | // Thus at the end of this method, currentIRScopeDesc_ (i.e., currentScope |
611 | | // above) should be |
612 | | // |
613 | | // 1. !isStrict and !hasParamExpressions: |
614 | | // currentIRScopeDesc_ == lexicalScope |
615 | | // lexicalScope.parent == topLevelScope |
616 | | // paramExpressionScope == null |
617 | | // varScope == null |
618 | | // 2. !isStrict and hasParamExpressions: |
619 | | // currentIRScopeDesc_ == lexicalScope |
620 | | // lexicalScope.parent == varScope |
621 | | // varScope.parent == paramExpressionScope |
622 | | // paramExpressionScope.parent == topLevelScope |
623 | | // 3. isStrict and !hasParamExpressions: |
624 | | // currentIRScopeDesc_ == topLevelScope |
625 | | // paramExpressionScope == null |
626 | | // varScope == null |
627 | | // lexicalScope == null |
628 | | // 4. isStrict and hasParamExpressions: |
629 | | // currentIRScopeDesc_ == varScope |
630 | | // varScope.parent == topLevelScope |
631 | | // paramExpressionScope == null |
632 | | // lexicalScope == null |
633 | | // |
634 | | // The following variables are used to assert those conditions. |
635 | 1.33k | ScopeDesc *topLevelScope = currentIRScopeDesc_; |
636 | 1.33k | ScopeDesc *paramExpressionScope{}; |
637 | 1.33k | ScopeDesc *varScope{}; |
638 | 1.33k | ScopeDesc *lexicalScope{}; |
639 | | |
640 | 1.33k | if (!Mod->getContext().getCodeGenerationSettings().enableBlockScoping) { |
641 | 1.33k | if (doEmitParameters == DoEmitParameters::YesMultiScopes) { |
642 | | // Block scoping is disabled, so there's no point in emitting separate |
643 | | // scopes. |
644 | 1.30k | doEmitParameters = DoEmitParameters::Yes; |
645 | 1.30k | } |
646 | 1.33k | } |
647 | | |
648 | 1.33k | const bool hasParamExpressions = ESTree::hasParamExpressions(funcNode); |
649 | 1.33k | if (doEmitParameters == DoEmitParameters::YesMultiScopes) { |
650 | 0 | if (!ESTree::isStrict(funcNode->strictness) && hasParamExpressions) { |
651 | 0 | curFunction()->enterOptionalFunctionScope( |
652 | 0 | &FunctionContext::enterParamScope); |
653 | 0 | newDeclarativeEnvironment(); |
654 | 0 | paramExpressionScope = currentIRScopeDesc_; |
655 | 0 | } |
656 | 0 | } |
657 | | |
658 | 1.33k | if (doEmitParameters != DoEmitParameters::No) { |
659 | | // Create function parameters, register them in the scope, and initialize |
660 | | // them with their income values. |
661 | 1.33k | emitParameters(funcNode, hasParamExpressions); |
662 | 1.33k | } else { |
663 | 0 | curFunction()->function->setExpectedParamCountIncludingThis( |
664 | 0 | countExpectedArgumentsIncludingThis(funcNode)); |
665 | 0 | } |
666 | | |
667 | 1.33k | auto *semInfo = curFunction()->getSemInfo(); |
668 | 1.33k | if (doEmitParameters != DoEmitParameters::YesMultiScopes || |
669 | 1.33k | !hasParamExpressions) { |
670 | | // Create variable declarations for each of the hoisted variables and |
671 | | // functions. Initialize them to undefined. |
672 | 1.33k | for (const sem::FunctionInfo::VarDecl &decl : semInfo->varScoped) { |
673 | 23 | createNewBinding( |
674 | 23 | currentIRScopeDesc_, |
675 | 23 | decl.kind, |
676 | 23 | decl.identifier, |
677 | 23 | decl.needsInitializer); |
678 | 23 | } |
679 | | |
680 | 1.33k | } else { |
681 | 0 | curFunction()->enterOptionalFunctionScope(&FunctionContext::enterVarScope); |
682 | 0 | newDeclarativeEnvironment(); |
683 | 0 | varScope = currentIRScopeDesc_; |
684 | |
|
685 | 0 | for (const sem::FunctionInfo::VarDecl &decl : semInfo->varScoped) { |
686 | 0 | Value *init = nameTable_.lookup(getNameFieldFromID(decl.identifier)); |
687 | 0 | if (init) { |
688 | 0 | init = emitLoad(init); |
689 | 0 | } |
690 | 0 | createNewBinding( |
691 | 0 | currentIRScopeDesc_, |
692 | 0 | decl.kind, |
693 | 0 | decl.identifier, |
694 | 0 | decl.needsInitializer, |
695 | 0 | init); |
696 | 0 | } |
697 | 0 | } |
698 | | |
699 | 1.33k | if (doEmitParameters == DoEmitParameters::YesMultiScopes) { |
700 | 0 | if (!ESTree::isStrict(funcNode->strictness)) { |
701 | 0 | curFunction()->enterOptionalFunctionScope( |
702 | 0 | &FunctionContext::enterTopLevelLexicalDeclarationsScope); |
703 | 0 | newDeclarativeEnvironment(); |
704 | 0 | lexicalScope = currentIRScopeDesc_; |
705 | 0 | } |
706 | 0 | } |
707 | | |
708 | | // Now that scope creation is completed, ensure that the expectations hold: |
709 | 1.33k | if (doEmitParameters == DoEmitParameters::YesMultiScopes) { |
710 | 0 | (void)topLevelScope; |
711 | 0 | (void)paramExpressionScope; |
712 | 0 | (void)varScope; |
713 | 0 | (void)lexicalScope; |
714 | 0 | if (!ESTree::isStrict(funcNode->strictness)) { |
715 | 0 | if (!hasParamExpressions) { |
716 | | // 1. !isStrict and !hasParamExpressions: |
717 | 0 | assert(currentIRScopeDesc_ == lexicalScope); |
718 | 0 | assert(lexicalScope->getParent() == topLevelScope); |
719 | 0 | assert(paramExpressionScope == nullptr); |
720 | 0 | assert(varScope == nullptr); |
721 | 0 | } else { |
722 | | // 2. !isStrict and hasParamExpressions: |
723 | 0 | assert(currentIRScopeDesc_ == lexicalScope); |
724 | 0 | assert(lexicalScope->getParent() == varScope); |
725 | 0 | assert(varScope->getParent() == paramExpressionScope); |
726 | 0 | assert(paramExpressionScope->getParent() == topLevelScope); |
727 | 0 | } |
728 | 0 | } else { |
729 | 0 | if (!hasParamExpressions) { |
730 | | // 3. isStrict and !hasParamExpressions: |
731 | 0 | assert(currentIRScopeDesc_ == topLevelScope); |
732 | 0 | assert(paramExpressionScope == nullptr); |
733 | 0 | assert(varScope == nullptr); |
734 | 0 | assert(lexicalScope == nullptr); |
735 | 0 | } else { |
736 | | // 4. isStrict and hasParamExpressions: |
737 | 0 | assert(currentIRScopeDesc_ == varScope); |
738 | 0 | assert(varScope->getParent() == topLevelScope); |
739 | 0 | assert(paramExpressionScope == nullptr); |
740 | 0 | assert(lexicalScope == nullptr); |
741 | 0 | } |
742 | 0 | } |
743 | 0 | } |
744 | | |
745 | | // Now create variable declarations for each scoped variable/function in body. |
746 | | // let/const bindings are initialized to empty, and functions to undefined. |
747 | 1.33k | createScopeBindings(currentIRScopeDesc_, body); |
748 | | |
749 | | // Generate the code for import declarations before generating the rest of the |
750 | | // body. |
751 | 1.33k | for (ESTree::ImportDeclarationNode *importDecl : semInfo->imports) { |
752 | 0 | genImportDeclaration(importDecl); |
753 | 0 | } |
754 | | |
755 | | // Generate all closures declared in body. Any hoisted |
756 | | // functions from inner scopes have already been declared. |
757 | 1.33k | genFunctionDeclarations(body); |
758 | | |
759 | | // Pre-hoists all functions that are defined within body (but not in |
760 | | // BlockStatments in it). |
761 | 1.33k | hoistCreateFunctions(body); |
762 | 1.33k | } |
763 | | |
764 | 1.33k | void ESTreeIRGen::genFunctionDeclarations(ESTree::Node *containingNode) { |
765 | 1.33k | auto *semInfo = curFunction()->getSemInfo(); |
766 | | |
767 | 1.33k | auto it = semInfo->closures.find(containingNode); |
768 | 1.33k | if (it != semInfo->closures.end()) { |
769 | 1.33k | for (ESTree::FunctionDeclarationNode *fd : *it->second) { |
770 | 0 | genFunctionDeclaration(fd); |
771 | 0 | } |
772 | 1.33k | } |
773 | 1.33k | } |
774 | | |
775 | | void ESTreeIRGen::createScopeBindings( |
776 | | ScopeDesc *scopeDesc, |
777 | 1.33k | ESTree::Node *containingNode) { |
778 | 1.33k | auto *semInfo = curFunction()->getSemInfo(); |
779 | | |
780 | 1.33k | auto it = semInfo->lexicallyScoped.find(containingNode); |
781 | 1.33k | if (it != semInfo->lexicallyScoped.end()) { |
782 | 1.33k | for (const sem::FunctionInfo::VarDecl &decl : *it->second) { |
783 | 0 | LLVM_DEBUG( |
784 | 0 | llvh::dbgs() << "creating binding " << decl.identifier->_name |
785 | 0 | << " in scope " << scopeDesc << "\n"); |
786 | 0 | createNewBinding( |
787 | 0 | scopeDesc, decl.kind, decl.identifier, decl.needsInitializer); |
788 | 0 | if (Mod->getContext().getCodeGenerationSettings().enableBlockScoping) { |
789 | 0 | if (decl.kind != VarDecl::Kind::Var && scopeDesc->isGlobalScope() && |
790 | 0 | llvh::isa<ESTree::ProgramNode>(containingNode)) { |
791 | | // The newly created Variable is a const/let declaration, so the |
792 | | // running program must check whether it is a valid name. For example, |
793 | | // |
794 | | // let undefined; |
795 | | // |
796 | | // is an invalid global let declaration because undefined is a |
797 | | // restricted global name. |
798 | 0 | IRBuilder::ScopedLocationChange slc( |
799 | 0 | Builder, decl.identifier->getSourceRange().Start); |
800 | 0 | Builder.createThrowIfHasRestrictedGlobalPropertyInst( |
801 | 0 | decl.identifier->_name->str()); |
802 | 0 | } |
803 | 0 | } |
804 | 0 | } |
805 | 1.33k | } |
806 | 1.33k | } |
807 | | |
808 | | void ESTreeIRGen::createNewBinding( |
809 | | ScopeDesc *scopeDesc, |
810 | | VarDecl::Kind kind, |
811 | | ESTree::Node *id, |
812 | | bool needsInitializer, |
813 | 23 | Value *init) { |
814 | 23 | Identifier name = getNameFieldFromID(id); |
815 | 23 | auto res = declareVariableOrGlobalProperty(scopeDesc, kind, name); |
816 | | // If this is not a frame variable or it was already declared, skip. |
817 | 23 | auto *var = llvh::dyn_cast<Variable>(res.first); |
818 | 23 | if (!needsInitializer || !var || !res.second) |
819 | 19 | return; |
820 | | |
821 | 4 | if (!init) { |
822 | 4 | init = var->getObeysTDZ() ? (Literal *)Builder.getLiteralEmpty() |
823 | 4 | : (Literal *)Builder.getLiteralUndefined(); |
824 | 4 | } |
825 | | |
826 | | // Otherwise, initialize it to undefined or empty, depending on TDZ. |
827 | 4 | Builder.createStoreFrameInst(init, var, currentIRScope_); |
828 | 4 | } |
829 | | |
830 | | void ESTreeIRGen::emitParameters( |
831 | | ESTree::FunctionLikeNode *funcNode, |
832 | 1.33k | bool hasParamExpressions) { |
833 | 1.33k | auto *newFunc = curFunction()->function; |
834 | | |
835 | 1.33k | LLVM_DEBUG(llvh::dbgs() << "IRGen function parameters.\n"); |
836 | | |
837 | 1.33k | if (!Mod->getContext().getCodeGenerationSettings().enableBlockScoping) { |
838 | | // Disable parameter TDZ if block scoping support is disabled. |
839 | 1.33k | hasParamExpressions = false; |
840 | 1.33k | } |
841 | | |
842 | 1.33k | llvh::SmallVector<Variable *, 4> tdzParams; |
843 | | |
844 | | // Create a variable for every parameter. |
845 | 1.33k | Value *empty = Builder.getLiteralEmpty(); |
846 | 1.33k | Variable::DeclKind paramKind = |
847 | 1.33k | hasParamExpressions ? Variable::DeclKind::Let : Variable::DeclKind::Var; |
848 | 1.33k | for (auto paramDecl : funcNode->getSemInfo()->paramNames) { |
849 | 1.30k | Identifier paramName = getNameFieldFromID(paramDecl.identifier); |
850 | 1.30k | LLVM_DEBUG(llvh::dbgs() << "Adding parameter: " << paramName << "\n"); |
851 | 1.30k | auto *paramStorage = Builder.createVariable( |
852 | 1.30k | newFunc->getFunctionScopeDesc(), paramKind, paramName); |
853 | 1.30k | if (hasParamExpressions) { |
854 | | // funcNode has parameter expressions, thus the parameters are first |
855 | | // copied to tdz variables which need to be initialized to empty. |
856 | 0 | Builder.createStoreFrameInst(empty, paramStorage, currentIRScope_); |
857 | | |
858 | | // Also keep track of all created Variables to copy them into regular Var |
859 | | // declarations. |
860 | 0 | tdzParams.push_back(paramStorage); |
861 | 0 | } |
862 | | // Register the storage for the parameter. |
863 | 1.30k | nameTable_.insert(paramName, paramStorage); |
864 | 1.30k | } |
865 | | |
866 | 1.33k | uint32_t paramIndex = uint32_t{0} - 1; |
867 | 1.33k | for (auto &elem : ESTree::getParams(funcNode)) { |
868 | 1.30k | ESTree::Node *param = &elem; |
869 | 1.30k | ESTree::Node *init = nullptr; |
870 | 1.30k | ++paramIndex; |
871 | | |
872 | 1.30k | if (auto *rest = llvh::dyn_cast<ESTree::RestElementNode>(param)) { |
873 | 0 | createLRef(rest->_argument, true) |
874 | 0 | .emitStore(genBuiltinCall( |
875 | 0 | BuiltinMethod::HermesBuiltin_copyRestArgs, |
876 | 0 | Builder.getLiteralNumber(paramIndex))); |
877 | 0 | break; |
878 | 0 | } |
879 | | |
880 | | // Unpack the optional initialization. |
881 | 1.30k | if (auto *assign = llvh::dyn_cast<ESTree::AssignmentPatternNode>(param)) { |
882 | 0 | param = assign->_left; |
883 | 0 | init = assign->_right; |
884 | 0 | } |
885 | | |
886 | 1.30k | Identifier formalParamName = llvh::isa<ESTree::IdentifierNode>(param) |
887 | 1.30k | ? getNameFieldFromID(param) |
888 | 1.30k | : genAnonymousLabelName("param"); |
889 | | |
890 | 1.30k | auto *formalParam = Builder.createParameter(newFunc, formalParamName); |
891 | 1.30k | createLRef(param, true) |
892 | 1.30k | .emitStore( |
893 | 1.30k | emitOptionalInitialization(formalParam, init, formalParamName)); |
894 | 1.30k | } |
895 | | |
896 | | // Now copy the TDZ parameters to Var declarations. This improves codegen by |
897 | | // removing tdz checks when accessing the parameters. |
898 | 1.33k | assert( |
899 | 1.33k | (tdzParams.empty() || hasParamExpressions) && |
900 | 1.33k | "funcNode does not have param expressions, so it doesn't" |
901 | 1.33k | " need tdz params."); |
902 | 1.33k | for (Variable *oldParamStorage : tdzParams) { |
903 | 0 | auto *paramStorage = Builder.createVariable( |
904 | 0 | newFunc->getFunctionScopeDesc(), |
905 | 0 | Variable::DeclKind::Let, |
906 | 0 | oldParamStorage->getName()); |
907 | 0 | constexpr bool declInit = true; |
908 | 0 | emitStore(emitLoad(oldParamStorage), paramStorage, declInit); |
909 | 0 | nameTable_.setInCurrentScope(oldParamStorage->getName(), paramStorage); |
910 | 0 | } |
911 | | |
912 | 1.33k | newFunc->setExpectedParamCountIncludingThis( |
913 | 1.33k | countExpectedArgumentsIncludingThis(funcNode)); |
914 | 1.33k | } |
915 | | |
916 | | uint32_t ESTreeIRGen::countExpectedArgumentsIncludingThis( |
917 | 1.34k | ESTree::FunctionLikeNode *funcNode) { |
918 | | // Start at 1 to account for "this". |
919 | 1.34k | uint32_t count = 1; |
920 | 1.34k | for (auto ¶m : ESTree::getParams(funcNode)) { |
921 | 1.30k | if (llvh::isa<ESTree::AssignmentPatternNode>(param)) { |
922 | | // Found an initializer, stop counting expected arguments. |
923 | 0 | break; |
924 | 0 | } |
925 | 1.30k | ++count; |
926 | 1.30k | } |
927 | 1.34k | return count; |
928 | 1.34k | } |
929 | | |
930 | 1.33k | void ESTreeIRGen::emitFunctionEpilogue(Value *returnValue) { |
931 | 1.33k | if (returnValue) { |
932 | 1.33k | Builder.setLocation(SourceErrorManager::convertEndToLocation( |
933 | 1.33k | Builder.getFunction()->getSourceRange())); |
934 | 1.33k | Builder.createReturnInst(returnValue); |
935 | 1.33k | } |
936 | | |
937 | | // Delete CreateArgumentsInst if it is unused. |
938 | 1.33k | if (!curFunction()->createArgumentsInst->hasUsers()) |
939 | 1.33k | curFunction()->createArgumentsInst->eraseFromParent(); |
940 | | |
941 | 1.33k | curFunction()->function->clearStatementCount(); |
942 | 1.33k | } |
943 | | |
944 | 0 | void ESTreeIRGen::genDummyFunction(Function *dummy) { |
945 | 0 | IRBuilder builder{dummy}; |
946 | |
|
947 | 0 | builder.createThisParameter(dummy); |
948 | 0 | BasicBlock *firstBlock = builder.createBasicBlock(dummy); |
949 | 0 | builder.setInsertionBlock(firstBlock); |
950 | 0 | builder.createUnreachableInst(); |
951 | 0 | builder.createReturnInst(builder.getLiteralUndefined()); |
952 | 0 | } |
953 | | |
954 | | /// Generate a function which immediately throws the specified SyntaxError |
955 | | /// message. |
956 | | Function *ESTreeIRGen::genSyntaxErrorFunction( |
957 | | Module *M, |
958 | | ScopeDesc *scopeDesc, |
959 | | Identifier originalName, |
960 | | SMRange sourceRange, |
961 | 0 | llvh::StringRef error) { |
962 | 0 | IRBuilder builder{M}; |
963 | |
|
964 | 0 | Function *function = builder.createFunction( |
965 | 0 | scopeDesc, |
966 | 0 | originalName, |
967 | 0 | Function::DefinitionKind::ES5Function, |
968 | 0 | true, |
969 | 0 | SourceVisibility::Sensitive, |
970 | 0 | sourceRange, |
971 | 0 | false); |
972 | |
|
973 | 0 | builder.createThisParameter(function); |
974 | 0 | BasicBlock *firstBlock = builder.createBasicBlock(function); |
975 | 0 | builder.setInsertionBlock(firstBlock); |
976 | 0 | builder.createCreateScopeInst(scopeDesc); |
977 | |
|
978 | 0 | genRaiseNativeError(builder, NativeErrorTypes::SyntaxError, error); |
979 | |
|
980 | 0 | return function; |
981 | 0 | } |
982 | | |
983 | | } // namespace irgen |
984 | | } // namespace hermes |