Line data Source code
1 : // Copyright 2017 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_TORQUE_IMPLEMENTATION_VISITOR_H_
6 : #define V8_TORQUE_IMPLEMENTATION_VISITOR_H_
7 :
8 : #include <string>
9 :
10 : #include "src/base/macros.h"
11 : #include "src/torque/ast.h"
12 : #include "src/torque/cfg.h"
13 : #include "src/torque/file-visitor.h"
14 : #include "src/torque/global-context.h"
15 : #include "src/torque/types.h"
16 : #include "src/torque/utils.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 : namespace torque {
21 :
22 : // LocationReference is the representation of an l-value, so a value that might
23 : // allow for assignment. For uniformity, this class can also represent
24 : // unassignable temporaries. Assignable values fall in two categories:
25 : // - stack ranges that represent mutable variables, including structs.
26 : // - field or element access expressions that generate operator calls.
27 20752 : class LocationReference {
28 : public:
29 : // An assignable stack range.
30 : static LocationReference VariableAccess(VisitResult variable) {
31 : DCHECK(variable.IsOnStack());
32 2997 : LocationReference result;
33 : result.variable_ = std::move(variable);
34 : return result;
35 : }
36 : // An unassignable value. {description} is only used for error messages.
37 : static LocationReference Temporary(VisitResult temporary,
38 : std::string description) {
39 5025 : LocationReference result;
40 : result.temporary_ = std::move(temporary);
41 : result.temporary_description_ = std::move(description);
42 : return result;
43 : }
44 99 : static LocationReference ArrayAccess(VisitResult base, VisitResult offset) {
45 99 : LocationReference result;
46 198 : result.eval_function_ = std::string{"[]"};
47 198 : result.assign_function_ = std::string{"[]="};
48 297 : result.call_arguments_ = {base, offset};
49 99 : return result;
50 : }
51 428 : static LocationReference FieldAccess(VisitResult object,
52 : std::string fieldname) {
53 428 : LocationReference result;
54 856 : result.eval_function_ = "." + fieldname;
55 1284 : result.assign_function_ = "." + fieldname + "=";
56 1284 : result.call_arguments_ = {object};
57 : result.index_field_ = base::nullopt;
58 428 : return result;
59 : }
60 134 : static LocationReference IndexedFieldIndexedAccess(
61 : const LocationReference& indexed_field, VisitResult index) {
62 134 : LocationReference result;
63 : DCHECK(indexed_field.IsIndexedFieldAccess());
64 134 : std::string fieldname = *indexed_field.index_field_;
65 402 : result.eval_function_ = "." + fieldname + "[]";
66 402 : result.assign_function_ = "." + fieldname + "[]=";
67 : result.call_arguments_ = indexed_field.call_arguments_;
68 134 : result.call_arguments_.push_back(index);
69 : result.index_field_ = fieldname;
70 134 : return result;
71 : }
72 134 : static LocationReference IndexedFieldAccess(VisitResult object,
73 : std::string fieldname) {
74 134 : LocationReference result;
75 402 : result.call_arguments_ = {object};
76 : result.index_field_ = fieldname;
77 134 : return result;
78 : }
79 :
80 : bool IsConst() const { return temporary_.has_value(); }
81 :
82 5197 : bool IsVariableAccess() const { return variable_.has_value(); }
83 : const VisitResult& variable() const {
84 : DCHECK(IsVariableAccess());
85 : return *variable_;
86 : }
87 7573 : bool IsTemporary() const { return temporary_.has_value(); }
88 : const VisitResult& temporary() const {
89 : DCHECK(IsTemporary());
90 : return *temporary_;
91 : }
92 :
93 : const VisitResult& GetVisitResult() const {
94 1038 : if (IsVariableAccess()) return variable();
95 : DCHECK(IsTemporary());
96 49 : return temporary();
97 : }
98 :
99 : // For error reporting.
100 : const std::string& temporary_description() const {
101 : DCHECK(IsTemporary());
102 : return *temporary_description_;
103 : }
104 :
105 784 : bool IsArrayField() const { return index_field_.has_value(); }
106 : bool IsIndexedFieldAccess() const {
107 987 : return IsArrayField() && !IsCallAccess();
108 : }
109 : bool IsIndexedFieldIndexedAccess() const {
110 : return IsArrayField() && IsCallAccess();
111 : }
112 : bool IsCallAccess() const {
113 1141 : bool is_call_access = eval_function_.has_value();
114 : DCHECK_EQ(is_call_access, assign_function_.has_value());
115 : return is_call_access;
116 : }
117 : const VisitResultVector& call_arguments() const {
118 : DCHECK(IsCallAccess());
119 : return call_arguments_;
120 : }
121 : const std::string& eval_function() const {
122 : DCHECK(IsCallAccess());
123 : return *eval_function_;
124 : }
125 : const std::string& assign_function() const {
126 : DCHECK(IsCallAccess());
127 : return *assign_function_;
128 : }
129 :
130 : private:
131 : base::Optional<VisitResult> variable_;
132 : base::Optional<VisitResult> temporary_;
133 : base::Optional<std::string> temporary_description_;
134 : base::Optional<std::string> eval_function_;
135 : base::Optional<std::string> assign_function_;
136 : VisitResultVector call_arguments_;
137 : base::Optional<std::string> index_field_;
138 :
139 17634 : LocationReference() = default;
140 : };
141 :
142 : template <class T>
143 : class Binding;
144 :
145 : template <class T>
146 1822 : class BindingsManager {
147 : public:
148 16258 : base::Optional<Binding<T>*> TryLookup(const std::string& name) {
149 16258 : return current_bindings_[name];
150 : }
151 :
152 : private:
153 : friend class Binding<T>;
154 : std::unordered_map<std::string, base::Optional<Binding<T>*>>
155 : current_bindings_;
156 : };
157 :
158 : template <class T>
159 : class Binding : public T {
160 : public:
161 : template <class... Args>
162 6273 : Binding(BindingsManager<T>* manager, const std::string& name, Args&&... args)
163 : : T(std::forward<Args>(args)...),
164 : manager_(manager),
165 : name_(name),
166 12546 : previous_binding_(this) {
167 12546 : std::swap(previous_binding_, manager_->current_bindings_[name]);
168 6273 : }
169 12546 : ~Binding() { manager_->current_bindings_[name_] = previous_binding_; }
170 :
171 : const std::string& name() const { return name_; }
172 0 : SourcePosition declaration_position() const { return declaration_position_; }
173 :
174 : private:
175 : BindingsManager<T>* manager_;
176 : const std::string name_;
177 : base::Optional<Binding*> previous_binding_;
178 : SourcePosition declaration_position_ = CurrentSourcePosition::Get();
179 : DISALLOW_COPY_AND_ASSIGN(Binding);
180 : };
181 :
182 : template <class T>
183 2851 : class BlockBindings {
184 : public:
185 3606 : explicit BlockBindings(BindingsManager<T>* manager) : manager_(manager) {}
186 3542 : void Add(std::string name, T value) {
187 11854 : for (const auto& binding : bindings_) {
188 4770 : if (binding->name() == name) {
189 0 : ReportError(
190 : "redeclaration of name \"", name,
191 : "\" in the same block is illegal, previous declaration at: ",
192 : binding->declaration_position());
193 : }
194 : }
195 7084 : bindings_.push_back(base::make_unique<Binding<T>>(manager_, std::move(name),
196 : std::move(value)));
197 3542 : }
198 :
199 : std::vector<Binding<T>*> bindings() const {
200 : std::vector<Binding<T>*> result;
201 : result.reserve(bindings_.size());
202 : for (auto& b : bindings_) {
203 : result.push_back(b.get());
204 : }
205 : return result;
206 : }
207 :
208 : private:
209 : BindingsManager<T>* manager_;
210 : std::vector<std::unique_ptr<Binding<T>>> bindings_;
211 : };
212 :
213 3620 : struct LocalValue {
214 : bool is_const;
215 : VisitResult value;
216 : };
217 :
218 2880 : struct LocalLabel {
219 : Block* block;
220 : std::vector<const Type*> parameter_types;
221 :
222 : explicit LocalLabel(Block* block,
223 : std::vector<const Type*> parameter_types = {})
224 2880 : : block(block), parameter_types(std::move(parameter_types)) {}
225 : };
226 :
227 39943 : struct Arguments {
228 : VisitResultVector parameters;
229 : std::vector<Binding<LocalLabel>*> labels;
230 : };
231 :
232 : // Determine if a callable should be considered as an overload.
233 : bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
234 : size_t label_count);
235 :
236 3 : class ImplementationVisitor : public FileVisitor {
237 : public:
238 : void GenerateBuiltinDefinitions(std::string& file_name);
239 : void GenerateClassDefinitions(std::string& file_name);
240 :
241 : VisitResult Visit(Expression* expr);
242 : const Type* Visit(Statement* stmt);
243 :
244 : VisitResult TemporaryUninitializedStruct(const StructType* struct_type,
245 : const std::string& reason);
246 : VisitResult Visit(StructExpression* decl);
247 :
248 : LocationReference GetLocationReference(Expression* location);
249 : LocationReference GetLocationReference(IdentifierExpression* expr);
250 : LocationReference GetLocationReference(FieldAccessExpression* expr);
251 : LocationReference GetLocationReference(ElementAccessExpression* expr);
252 :
253 : VisitResult GenerateFetchFromLocation(const LocationReference& reference);
254 :
255 : VisitResult GetBuiltinCode(Builtin* builtin);
256 :
257 : VisitResult Visit(IdentifierExpression* expr);
258 520 : VisitResult Visit(FieldAccessExpression* expr) {
259 : StackScope scope(this);
260 1560 : return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
261 : }
262 165 : VisitResult Visit(ElementAccessExpression* expr) {
263 : StackScope scope(this);
264 495 : return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
265 : }
266 :
267 : void VisitAllDeclarables();
268 : void Visit(Declarable* delarable);
269 : void Visit(TypeAlias* decl);
270 : VisitResult InlineMacro(Macro* macro,
271 : base::Optional<LocationReference> this_reference,
272 : const std::vector<VisitResult>& arguments,
273 : const std::vector<Block*> label_blocks);
274 : void VisitMacroCommon(Macro* macro);
275 : void Visit(Macro* macro);
276 : void Visit(Method* macro);
277 : void Visit(Builtin* builtin);
278 : void Visit(NamespaceConstant* decl);
279 :
280 : VisitResult Visit(CallExpression* expr, bool is_tail = false);
281 : VisitResult Visit(CallMethodExpression* expr);
282 : VisitResult Visit(IntrinsicCallExpression* intrinsic);
283 : VisitResult Visit(LoadObjectFieldExpression* expr);
284 : VisitResult Visit(StoreObjectFieldExpression* expr);
285 : const Type* Visit(TailCallStatement* stmt);
286 :
287 : VisitResult Visit(ConditionalExpression* expr);
288 :
289 : VisitResult Visit(LogicalOrExpression* expr);
290 : VisitResult Visit(LogicalAndExpression* expr);
291 :
292 : VisitResult Visit(IncrementDecrementExpression* expr);
293 : VisitResult Visit(AssignmentExpression* expr);
294 : VisitResult Visit(StringLiteralExpression* expr);
295 : VisitResult Visit(NumberLiteralExpression* expr);
296 : VisitResult Visit(AssumeTypeImpossibleExpression* expr);
297 : VisitResult Visit(TryLabelExpression* expr);
298 : VisitResult Visit(StatementExpression* expr);
299 : VisitResult Visit(NewExpression* expr);
300 :
301 : const Type* Visit(ReturnStatement* stmt);
302 : const Type* Visit(GotoStatement* stmt);
303 : const Type* Visit(IfStatement* stmt);
304 : const Type* Visit(WhileStatement* stmt);
305 : const Type* Visit(BreakStatement* stmt);
306 : const Type* Visit(ContinueStatement* stmt);
307 : const Type* Visit(ForLoopStatement* stmt);
308 : const Type* Visit(VarDeclarationStatement* stmt);
309 : const Type* Visit(VarDeclarationStatement* stmt,
310 : BlockBindings<LocalValue>* block_bindings);
311 : const Type* Visit(ForOfLoopStatement* stmt);
312 : const Type* Visit(BlockStatement* block);
313 : const Type* Visit(ExpressionStatement* stmt);
314 : const Type* Visit(DebugStatement* stmt);
315 : const Type* Visit(AssertStatement* stmt);
316 :
317 : void BeginNamespaceFile(Namespace* nspace);
318 : void EndNamespaceFile(Namespace* nspace);
319 :
320 : void GenerateImplementation(const std::string& dir, Namespace* nspace);
321 :
322 : struct ConstructorInfo {
323 : int super_calls;
324 : };
325 :
326 : DECLARE_CONTEXTUAL_VARIABLE(ValueBindingsManager,
327 : BindingsManager<LocalValue>);
328 : DECLARE_CONTEXTUAL_VARIABLE(LabelBindingsManager,
329 : BindingsManager<LocalLabel>);
330 : DECLARE_CONTEXTUAL_VARIABLE(CurrentCallable, Callable*);
331 : DECLARE_CONTEXTUAL_VARIABLE(CurrentReturnValue, base::Optional<VisitResult>);
332 : DECLARE_CONTEXTUAL_VARIABLE(CurrentConstructorInfo,
333 : base::Optional<ConstructorInfo>);
334 :
335 : // A BindingsManagersScope has to be active for local bindings to be created.
336 : // Shadowing an existing BindingsManagersScope by creating a new one hides all
337 : // existing bindings while the additional BindingsManagersScope is active.
338 1822 : struct BindingsManagersScope {
339 : ValueBindingsManager::Scope value_bindings_manager;
340 : LabelBindingsManager::Scope label_bindings_manager;
341 : };
342 :
343 : private:
344 : base::Optional<Block*> GetCatchBlock();
345 : void GenerateCatchBlock(base::Optional<Block*> catch_block);
346 :
347 : // {StackScope} records the stack height at creation time and reconstructs it
348 : // when being destructed by emitting a {DeleteRangeInstruction}, except for
349 : // the slots protected by {StackScope::Yield}. Calling {Yield(v)} deletes all
350 : // slots above the initial stack height except for the slots of {v}, which are
351 : // moved to form the only slots above the initial height and marks them to
352 : // survive destruction of the {StackScope}. A typical pattern is the
353 : // following:
354 : //
355 : // VisitResult result;
356 : // {
357 : // StackScope stack_scope(this);
358 : // // ... create temporary slots ...
359 : // result = stack_scope.Yield(surviving_slots);
360 : // }
361 : class StackScope {
362 : public:
363 30016 : explicit StackScope(ImplementationVisitor* visitor) : visitor_(visitor) {
364 30016 : base_ = visitor_->assembler().CurrentStack().AboveTop();
365 : }
366 46680 : VisitResult Yield(VisitResult result) {
367 : DCHECK(!closed_);
368 24835 : closed_ = true;
369 24835 : if (!result.IsOnStack()) {
370 5980 : if (!visitor_->assembler().CurrentBlockIsComplete()) {
371 2850 : visitor_->assembler().DropTo(base_);
372 : }
373 2990 : return result;
374 : }
375 : DCHECK_LE(base_, result.stack_range().begin());
376 : DCHECK_LE(result.stack_range().end(),
377 : visitor_->assembler().CurrentStack().AboveTop());
378 21845 : visitor_->assembler().DropTo(result.stack_range().end());
379 21845 : visitor_->assembler().DeleteRange(
380 21845 : StackRange{base_, result.stack_range().begin()});
381 43690 : base_ = visitor_->assembler().CurrentStack().AboveTop();
382 : return VisitResult(result.type(), visitor_->assembler().TopRange(
383 : result.stack_range().Size()));
384 : }
385 :
386 5181 : void Close() {
387 : DCHECK(!closed_);
388 5181 : closed_ = true;
389 10362 : if (!visitor_->assembler().CurrentBlockIsComplete()) {
390 2943 : visitor_->assembler().DropTo(base_);
391 : }
392 5181 : }
393 :
394 : ~StackScope() {
395 30016 : if (closed_) {
396 : DCHECK_IMPLIES(
397 : !visitor_->assembler().CurrentBlockIsComplete(),
398 : base_ == visitor_->assembler().CurrentStack().AboveTop());
399 : } else {
400 5181 : Close();
401 : }
402 : }
403 :
404 : private:
405 : ImplementationVisitor* visitor_;
406 : BottomOffset base_;
407 : bool closed_ = false;
408 : };
409 :
410 93 : class BreakContinueActivator {
411 : public:
412 93 : BreakContinueActivator(Block* break_block, Block* continue_block)
413 : : break_binding_{&LabelBindingsManager::Get(), "_break",
414 : LocalLabel{break_block}},
415 : continue_binding_{&LabelBindingsManager::Get(), "_continue",
416 744 : LocalLabel{continue_block}} {}
417 :
418 : private:
419 : Binding<LocalLabel> break_binding_;
420 : Binding<LocalLabel> continue_binding_;
421 : };
422 :
423 : base::Optional<Binding<LocalValue>*> TryLookupLocalValue(
424 : const std::string& name);
425 : base::Optional<Binding<LocalLabel>*> TryLookupLabel(const std::string& name);
426 : Binding<LocalLabel>* LookupLabel(const std::string& name);
427 : Block* LookupSimpleLabel(const std::string& name);
428 : template <class Container>
429 : Callable* LookupCallable(const QualifiedName& name,
430 : const Container& declaration_container,
431 : const TypeVector& types,
432 : const std::vector<Binding<LocalLabel>*>& labels,
433 : const TypeVector& specialization_types);
434 :
435 : template <class Container>
436 : Callable* LookupCallable(const QualifiedName& name,
437 : const Container& declaration_container,
438 : const Arguments& arguments,
439 : const TypeVector& specialization_types);
440 :
441 : Method* LookupMethod(const std::string& name, LocationReference target,
442 : const Arguments& arguments,
443 : const TypeVector& specialization_types);
444 :
445 105 : Method* LookupConstructor(LocationReference target,
446 : const Arguments& arguments,
447 : const TypeVector& specialization_types) {
448 : return LookupMethod(kConstructMethodName, target, arguments,
449 210 : specialization_types);
450 : }
451 :
452 : const Type* GetCommonType(const Type* left, const Type* right);
453 :
454 : VisitResult GenerateCopy(const VisitResult& to_copy);
455 :
456 : void GenerateAssignToLocation(const LocationReference& reference,
457 : const VisitResult& assignment_value);
458 :
459 : void AddCallParameter(Callable* callable, VisitResult parameter,
460 : const Type* parameter_type,
461 : std::vector<VisitResult>* converted_arguments,
462 : StackRange* argument_range,
463 : std::vector<std::string>* constexpr_arguments);
464 :
465 : VisitResult GenerateCall(Callable* callable,
466 : base::Optional<LocationReference> this_parameter,
467 : Arguments parameters,
468 : const TypeVector& specialization_types = {},
469 : bool tail_call = false);
470 : VisitResult GenerateCall(const QualifiedName& callable_name,
471 : Arguments parameters,
472 : const TypeVector& specialization_types = {},
473 : bool tail_call = false);
474 2229 : VisitResult GenerateCall(std::string callable_name, Arguments parameters,
475 : const TypeVector& specialization_types = {},
476 : bool tail_call = false) {
477 : return GenerateCall(QualifiedName(std::move(callable_name)),
478 6687 : std::move(parameters), specialization_types, tail_call);
479 : }
480 : VisitResult GeneratePointerCall(Expression* callee,
481 : const Arguments& parameters, bool tail_call);
482 :
483 : void GenerateBranch(const VisitResult& condition, Block* true_block,
484 : Block* false_block);
485 :
486 : void GenerateExpressionBranch(Expression* expression, Block* true_block,
487 : Block* false_block);
488 :
489 : void GenerateMacroFunctionDeclaration(std::ostream& o,
490 : const std::string& macro_prefix,
491 : Macro* macro);
492 : void GenerateFunctionDeclaration(std::ostream& o,
493 : const std::string& macro_prefix,
494 : const std::string& name,
495 : const Signature& signature,
496 : const NameVector& parameter_names);
497 :
498 : VisitResult GenerateImplicitConvert(const Type* destination_type,
499 : VisitResult source);
500 :
501 : StackRange GenerateLabelGoto(LocalLabel* label,
502 : base::Optional<StackRange> arguments = {});
503 :
504 : std::vector<Binding<LocalLabel>*> LabelsFromIdentifiers(
505 : const std::vector<std::string>& names);
506 :
507 : StackRange LowerParameter(const Type* type, const std::string& parameter_name,
508 : Stack<std::string>* lowered_parameters);
509 :
510 : void LowerLabelParameter(const Type* type, const std::string& parameter_name,
511 : std::vector<std::string>* lowered_parameters);
512 :
513 : std::string ExternalLabelName(const std::string& label_name);
514 : std::string ExternalLabelParameterName(const std::string& label_name,
515 : size_t i);
516 : std::string ExternalParameterName(const std::string& name);
517 :
518 5022 : std::ostream& source_out() {
519 5022 : Callable* callable = CurrentCallable::Get();
520 5022 : if (!callable || callable->ShouldGenerateExternalCode()) {
521 4835 : return CurrentNamespace()->source_stream();
522 : } else {
523 187 : return null_stream_;
524 : }
525 : }
526 2654 : std::ostream& header_out() {
527 2654 : Callable* callable = CurrentCallable::Get();
528 2654 : if (!callable || callable->ShouldGenerateExternalCode()) {
529 2525 : return CurrentNamespace()->header_stream();
530 : } else {
531 129 : return null_stream_;
532 : }
533 : }
534 : CfgAssembler& assembler() { return *assembler_; }
535 :
536 : void SetReturnValue(VisitResult return_value) {
537 : base::Optional<VisitResult>& current_return_value =
538 : CurrentReturnValue::Get();
539 : DCHECK_IMPLIES(current_return_value, *current_return_value == return_value);
540 : current_return_value = std::move(return_value);
541 : }
542 :
543 : VisitResult GetAndClearReturnValue() {
544 755 : VisitResult return_value = *CurrentReturnValue::Get();
545 : CurrentReturnValue::Get() = base::nullopt;
546 : return return_value;
547 : }
548 :
549 : base::Optional<CfgAssembler> assembler_;
550 : NullOStream null_stream_;
551 : };
552 :
553 : } // namespace torque
554 : } // namespace internal
555 : } // namespace v8
556 :
557 : #endif // V8_TORQUE_IMPLEMENTATION_VISITOR_H_
|