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 22578 : class LocationReference {
28 : public:
29 : // An assignable stack range.
30 : static LocationReference VariableAccess(VisitResult variable) {
31 : DCHECK(variable.IsOnStack());
32 : LocationReference result;
33 : result.variable_ = std::move(variable);
34 : return result;
35 : }
36 : // An unassignable value. {description} is only used for error messages.
37 6417 : static LocationReference Temporary(VisitResult temporary,
38 : std::string description) {
39 : LocationReference result;
40 : result.temporary_ = std::move(temporary);
41 : result.temporary_description_ = std::move(description);
42 6417 : return result;
43 : }
44 : // A heap reference, that is, a tagged value and an offset to encode an inner
45 : // pointer.
46 : static LocationReference HeapReference(VisitResult heap_reference) {
47 : LocationReference result;
48 : DCHECK(heap_reference.type()->IsReferenceType());
49 : result.heap_reference_ = std::move(heap_reference);
50 : return result;
51 : }
52 155 : static LocationReference ArrayAccess(VisitResult base, VisitResult offset) {
53 : LocationReference result;
54 310 : result.eval_function_ = std::string{"[]"};
55 310 : result.assign_function_ = std::string{"[]="};
56 310 : result.call_arguments_ = {base, offset};
57 155 : return result;
58 : }
59 100 : static LocationReference FieldAccess(VisitResult object,
60 : std::string fieldname) {
61 : LocationReference result;
62 200 : result.eval_function_ = "." + fieldname;
63 300 : result.assign_function_ = "." + fieldname + "=";
64 200 : result.call_arguments_ = {object};
65 : result.index_field_ = base::nullopt;
66 100 : return result;
67 : }
68 128 : static LocationReference IndexedFieldIndexedAccess(
69 : const LocationReference& indexed_field, VisitResult index) {
70 : LocationReference result;
71 : DCHECK(indexed_field.IsIndexedFieldAccess());
72 : std::string fieldname = *indexed_field.index_field_;
73 384 : result.eval_function_ = "." + fieldname + "[]";
74 384 : result.assign_function_ = "." + fieldname + "[]=";
75 : result.call_arguments_ = indexed_field.call_arguments_;
76 128 : result.call_arguments_.push_back(index);
77 : result.index_field_ = fieldname;
78 128 : return result;
79 : }
80 128 : static LocationReference IndexedFieldAccess(VisitResult object,
81 : std::string fieldname) {
82 : LocationReference result;
83 256 : result.call_arguments_ = {object};
84 : result.index_field_ = fieldname;
85 128 : return result;
86 : }
87 :
88 : bool IsConst() const { return temporary_.has_value(); }
89 :
90 : bool IsVariableAccess() const { return variable_.has_value(); }
91 : const VisitResult& variable() const {
92 : DCHECK(IsVariableAccess());
93 : return *variable_;
94 : }
95 : bool IsTemporary() const { return temporary_.has_value(); }
96 : const VisitResult& temporary() const {
97 : DCHECK(IsTemporary());
98 : return *temporary_;
99 : }
100 : bool IsHeapReference() const { return heap_reference_.has_value(); }
101 : const VisitResult& heap_reference() const {
102 : DCHECK(IsHeapReference());
103 : return *heap_reference_;
104 : }
105 :
106 : const Type* ReferencedType() const {
107 1905 : if (IsHeapReference()) {
108 : return ReferenceType::cast(heap_reference().type())->referenced_type();
109 : }
110 : return GetVisitResult().type();
111 : }
112 :
113 : const VisitResult& GetVisitResult() const {
114 669 : if (IsVariableAccess()) return variable();
115 : DCHECK(IsTemporary());
116 : return temporary();
117 : }
118 :
119 : // For error reporting.
120 : const std::string& temporary_description() const {
121 : DCHECK(IsTemporary());
122 : return *temporary_description_;
123 : }
124 :
125 : bool IsArrayField() const { return index_field_.has_value(); }
126 : bool IsIndexedFieldAccess() const {
127 1019 : return IsArrayField() && !IsCallAccess();
128 : }
129 : bool IsIndexedFieldIndexedAccess() const {
130 : return IsArrayField() && IsCallAccess();
131 : }
132 : bool IsCallAccess() const {
133 : bool is_call_access = eval_function_.has_value();
134 : DCHECK_EQ(is_call_access, assign_function_.has_value());
135 : return is_call_access;
136 : }
137 : const VisitResultVector& call_arguments() const {
138 : DCHECK(IsCallAccess());
139 : return call_arguments_;
140 : }
141 : const std::string& eval_function() const {
142 : DCHECK(IsCallAccess());
143 : return *eval_function_;
144 : }
145 : const std::string& assign_function() const {
146 : DCHECK(IsCallAccess());
147 : return *assign_function_;
148 : }
149 :
150 : private:
151 : base::Optional<VisitResult> variable_;
152 : base::Optional<VisitResult> temporary_;
153 : base::Optional<std::string> temporary_description_;
154 : base::Optional<VisitResult> heap_reference_;
155 : base::Optional<std::string> eval_function_;
156 : base::Optional<std::string> assign_function_;
157 : VisitResultVector call_arguments_;
158 : base::Optional<std::string> index_field_;
159 :
160 : LocationReference() = default;
161 : };
162 :
163 66 : struct InitializerResults {
164 : std::vector<Identifier*> names;
165 : NameValueMap field_value_map;
166 : };
167 :
168 : template <class T>
169 : class Binding;
170 :
171 : template <class T>
172 2892 : class BindingsManager {
173 : public:
174 : base::Optional<Binding<T>*> TryLookup(const std::string& name) {
175 18849 : return current_bindings_[name];
176 : }
177 :
178 : private:
179 : friend class Binding<T>;
180 : std::unordered_map<std::string, base::Optional<Binding<T>*>>
181 : current_bindings_;
182 : };
183 :
184 : template <class T>
185 : class Binding : public T {
186 : public:
187 : template <class... Args>
188 8068 : Binding(BindingsManager<T>* manager, const std::string& name, Args&&... args)
189 : : T(std::forward<Args>(args)...),
190 : manager_(manager),
191 : name_(name),
192 16136 : previous_binding_(this) {
193 16136 : std::swap(previous_binding_, manager_->current_bindings_[name]);
194 8068 : }
195 : template <class... Args>
196 : Binding(BindingsManager<T>* manager, const Identifier* name, Args&&... args)
197 4121 : : Binding(manager, name->value, std::forward<Args>(args)...) {
198 4121 : declaration_position_ = name->pos;
199 : }
200 16136 : ~Binding() { manager_->current_bindings_[name_] = previous_binding_; }
201 :
202 5028 : const std::string& name() const { return name_; }
203 1 : SourcePosition declaration_position() const { return declaration_position_; }
204 :
205 : private:
206 : BindingsManager<T>* manager_;
207 : const std::string name_;
208 : base::Optional<Binding*> previous_binding_;
209 : SourcePosition declaration_position_ = CurrentSourcePosition::Get();
210 : DISALLOW_COPY_AND_ASSIGN(Binding);
211 : };
212 :
213 : template <class T>
214 3634 : class BlockBindings {
215 : public:
216 4863 : explicit BlockBindings(BindingsManager<T>* manager) : manager_(manager) {}
217 401 : void Add(std::string name, T value) {
218 401 : ReportErrorIfAlreadyBound(name);
219 802 : bindings_.push_back(base::make_unique<Binding<T>>(manager_, std::move(name),
220 : std::move(value)));
221 401 : }
222 :
223 4121 : void Add(const Identifier* name, T value) {
224 4121 : ReportErrorIfAlreadyBound(name->value);
225 8242 : bindings_.push_back(
226 : base::make_unique<Binding<T>>(manager_, name, std::move(value)));
227 4121 : }
228 :
229 : std::vector<Binding<T>*> bindings() const {
230 : std::vector<Binding<T>*> result;
231 : result.reserve(bindings_.size());
232 : for (auto& b : bindings_) {
233 : result.push_back(b.get());
234 : }
235 : return result;
236 : }
237 :
238 : private:
239 4522 : void ReportErrorIfAlreadyBound(const std::string& name) {
240 9550 : for (const auto& binding : bindings_) {
241 5028 : if (binding->name() == name) {
242 0 : ReportError(
243 : "redeclaration of name \"", name,
244 : "\" in the same block is illegal, previous declaration at: ",
245 : binding->declaration_position());
246 : }
247 : }
248 4522 : }
249 :
250 : BindingsManager<T>* manager_;
251 : std::vector<std::unique_ptr<Binding<T>>> bindings_;
252 : };
253 :
254 13329 : struct LocalValue {
255 : bool is_const;
256 : VisitResult value;
257 : };
258 :
259 11169 : struct LocalLabel {
260 : Block* block;
261 : std::vector<const Type*> parameter_types;
262 :
263 : explicit LocalLabel(Block* block,
264 : std::vector<const Type*> parameter_types = {})
265 3723 : : block(block), parameter_types(std::move(parameter_types)) {}
266 : };
267 :
268 51922 : struct Arguments {
269 : VisitResultVector parameters;
270 : std::vector<Binding<LocalLabel>*> labels;
271 : };
272 :
273 : // Determine if a callable should be considered as an overload.
274 : bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
275 : size_t label_count);
276 :
277 12 : class ImplementationVisitor : public FileVisitor {
278 : public:
279 : void GenerateBuiltinDefinitions(std::string& file_name);
280 : void GenerateClassDefinitions(std::string& file_name);
281 : void GeneratePrintDefinitions(std::string& file_name);
282 :
283 : VisitResult Visit(Expression* expr);
284 : const Type* Visit(Statement* stmt);
285 :
286 : InitializerResults VisitInitializerResults(
287 : const AggregateType* aggregate,
288 : const std::vector<NameAndExpression>& expressions);
289 :
290 : void InitializeFieldFromSpread(VisitResult object, const Field& field,
291 : const InitializerResults& initializer_results);
292 :
293 : size_t InitializeAggregateHelper(
294 : const AggregateType* aggregate_type, VisitResult allocate_result,
295 : const InitializerResults& initializer_results);
296 :
297 : VisitResult AddVariableObjectSize(
298 : VisitResult object_size, const ClassType* current_class,
299 : const InitializerResults& initializer_results);
300 :
301 : void InitializeAggregate(const AggregateType* aggregate_type,
302 : VisitResult allocate_result,
303 : const InitializerResults& initializer_results);
304 :
305 : VisitResult TemporaryUninitializedStruct(const StructType* struct_type,
306 : const std::string& reason);
307 : VisitResult Visit(StructExpression* decl);
308 :
309 : LocationReference GetLocationReference(Expression* location);
310 : LocationReference GetLocationReference(IdentifierExpression* expr);
311 : LocationReference GetLocationReference(DereferenceExpression* expr);
312 : LocationReference GetLocationReference(FieldAccessExpression* expr);
313 : LocationReference GetLocationReference(ElementAccessExpression* expr);
314 :
315 : VisitResult GenerateFetchFromLocation(const LocationReference& reference);
316 :
317 : VisitResult GetBuiltinCode(Builtin* builtin);
318 :
319 : VisitResult Visit(LocationExpression* expr);
320 :
321 : void VisitAllDeclarables();
322 : void Visit(Declarable* delarable);
323 : void Visit(TypeAlias* decl);
324 : VisitResult InlineMacro(Macro* macro,
325 : base::Optional<LocationReference> this_reference,
326 : const std::vector<VisitResult>& arguments,
327 : const std::vector<Block*> label_blocks);
328 : void VisitMacroCommon(Macro* macro);
329 : void Visit(Macro* macro);
330 : void Visit(Method* macro);
331 : void Visit(Builtin* builtin);
332 : void Visit(NamespaceConstant* decl);
333 :
334 : VisitResult Visit(CallExpression* expr, bool is_tail = false);
335 : VisitResult Visit(CallMethodExpression* expr);
336 : VisitResult Visit(IntrinsicCallExpression* intrinsic);
337 : const Type* Visit(TailCallStatement* stmt);
338 :
339 : VisitResult Visit(ConditionalExpression* expr);
340 :
341 : VisitResult Visit(LogicalOrExpression* expr);
342 : VisitResult Visit(LogicalAndExpression* expr);
343 :
344 : VisitResult Visit(IncrementDecrementExpression* expr);
345 : VisitResult Visit(AssignmentExpression* expr);
346 : VisitResult Visit(StringLiteralExpression* expr);
347 : VisitResult Visit(NumberLiteralExpression* expr);
348 : VisitResult Visit(AssumeTypeImpossibleExpression* expr);
349 : VisitResult Visit(TryLabelExpression* expr);
350 : VisitResult Visit(StatementExpression* expr);
351 : VisitResult Visit(NewExpression* expr);
352 : VisitResult Visit(SpreadExpression* expr);
353 :
354 : const Type* Visit(ReturnStatement* stmt);
355 : const Type* Visit(GotoStatement* stmt);
356 : const Type* Visit(IfStatement* stmt);
357 : const Type* Visit(WhileStatement* stmt);
358 : const Type* Visit(BreakStatement* stmt);
359 : const Type* Visit(ContinueStatement* stmt);
360 : const Type* Visit(ForLoopStatement* stmt);
361 : const Type* Visit(VarDeclarationStatement* stmt);
362 : const Type* Visit(VarDeclarationStatement* stmt,
363 : BlockBindings<LocalValue>* block_bindings);
364 : const Type* Visit(ForOfLoopStatement* stmt);
365 : const Type* Visit(BlockStatement* block);
366 : const Type* Visit(ExpressionStatement* stmt);
367 : const Type* Visit(DebugStatement* stmt);
368 : const Type* Visit(AssertStatement* stmt);
369 :
370 : void BeginNamespaceFile(Namespace* nspace);
371 : void EndNamespaceFile(Namespace* nspace);
372 :
373 : void GenerateImplementation(const std::string& dir, Namespace* nspace);
374 :
375 : DECLARE_CONTEXTUAL_VARIABLE(ValueBindingsManager,
376 : BindingsManager<LocalValue>);
377 : DECLARE_CONTEXTUAL_VARIABLE(LabelBindingsManager,
378 : BindingsManager<LocalLabel>);
379 : DECLARE_CONTEXTUAL_VARIABLE(CurrentCallable, Callable*);
380 : DECLARE_CONTEXTUAL_VARIABLE(CurrentReturnValue, base::Optional<VisitResult>);
381 :
382 : // A BindingsManagersScope has to be active for local bindings to be created.
383 : // Shadowing an existing BindingsManagersScope by creating a new one hides all
384 : // existing bindings while the additional BindingsManagersScope is active.
385 5784 : struct BindingsManagersScope {
386 : ValueBindingsManager::Scope value_bindings_manager;
387 : LabelBindingsManager::Scope label_bindings_manager;
388 : };
389 :
390 : private:
391 : base::Optional<Block*> GetCatchBlock();
392 : void GenerateCatchBlock(base::Optional<Block*> catch_block);
393 :
394 : // {StackScope} records the stack height at creation time and reconstructs it
395 : // when being destructed by emitting a {DeleteRangeInstruction}, except for
396 : // the slots protected by {StackScope::Yield}. Calling {Yield(v)} deletes all
397 : // slots above the initial stack height except for the slots of {v}, which are
398 : // moved to form the only slots above the initial height and marks them to
399 : // survive destruction of the {StackScope}. A typical pattern is the
400 : // following:
401 : //
402 : // VisitResult result;
403 : // {
404 : // StackScope stack_scope(this);
405 : // // ... create temporary slots ...
406 : // result = stack_scope.Yield(surviving_slots);
407 : // }
408 : class StackScope {
409 : public:
410 34641 : explicit StackScope(ImplementationVisitor* visitor) : visitor_(visitor) {
411 34641 : base_ = visitor_->assembler().CurrentStack().AboveTop();
412 : }
413 28571 : VisitResult Yield(VisitResult result) {
414 : DCHECK(!closed_);
415 28571 : closed_ = true;
416 28571 : if (!result.IsOnStack()) {
417 6490 : if (!visitor_->assembler().CurrentBlockIsComplete()) {
418 6092 : visitor_->assembler().DropTo(base_);
419 : }
420 3245 : return result;
421 : }
422 : DCHECK_LE(base_, result.stack_range().begin());
423 : DCHECK_LE(result.stack_range().end(),
424 : visitor_->assembler().CurrentStack().AboveTop());
425 50652 : visitor_->assembler().DropTo(result.stack_range().end());
426 50652 : visitor_->assembler().DeleteRange(
427 25326 : StackRange{base_, result.stack_range().begin()});
428 50652 : base_ = visitor_->assembler().CurrentStack().AboveTop();
429 : return VisitResult(result.type(), visitor_->assembler().TopRange(
430 : result.stack_range().Size()));
431 : }
432 :
433 6070 : void Close() {
434 : DCHECK(!closed_);
435 6070 : closed_ = true;
436 12140 : if (!visitor_->assembler().CurrentBlockIsComplete()) {
437 5740 : visitor_->assembler().DropTo(base_);
438 : }
439 6070 : }
440 :
441 34641 : ~StackScope() {
442 34641 : if (closed_) {
443 : DCHECK_IMPLIES(
444 : !visitor_->assembler().CurrentBlockIsComplete(),
445 : base_ == visitor_->assembler().CurrentStack().AboveTop());
446 : } else {
447 6070 : Close();
448 : }
449 : }
450 :
451 : private:
452 : ImplementationVisitor* visitor_;
453 : BottomOffset base_;
454 : bool closed_ = false;
455 : };
456 :
457 104 : class BreakContinueActivator {
458 : public:
459 104 : BreakContinueActivator(Block* break_block, Block* continue_block)
460 : : break_binding_{&LabelBindingsManager::Get(), "_break",
461 : LocalLabel{break_block}},
462 : continue_binding_{&LabelBindingsManager::Get(), "_continue",
463 832 : LocalLabel{continue_block}} {}
464 :
465 : private:
466 : Binding<LocalLabel> break_binding_;
467 : Binding<LocalLabel> continue_binding_;
468 : };
469 :
470 : base::Optional<Binding<LocalValue>*> TryLookupLocalValue(
471 : const std::string& name);
472 : base::Optional<Binding<LocalLabel>*> TryLookupLabel(const std::string& name);
473 : Binding<LocalLabel>* LookupLabel(const std::string& name);
474 : Block* LookupSimpleLabel(const std::string& name);
475 : template <class Container>
476 : Callable* LookupCallable(const QualifiedName& name,
477 : const Container& declaration_container,
478 : const TypeVector& types,
479 : const std::vector<Binding<LocalLabel>*>& labels,
480 : const TypeVector& specialization_types,
481 : bool silence_errors = false);
482 : bool TestLookupCallable(const QualifiedName& name,
483 : const TypeVector& parameter_types);
484 :
485 : template <class Container>
486 : Callable* LookupCallable(const QualifiedName& name,
487 : const Container& declaration_container,
488 : const Arguments& arguments,
489 : const TypeVector& specialization_types);
490 :
491 : Method* LookupMethod(const std::string& name, LocationReference target,
492 : const Arguments& arguments,
493 : const TypeVector& specialization_types);
494 :
495 : const Type* GetCommonType(const Type* left, const Type* right);
496 :
497 : VisitResult GenerateCopy(const VisitResult& to_copy);
498 :
499 : void GenerateAssignToLocation(const LocationReference& reference,
500 : const VisitResult& assignment_value);
501 :
502 : void AddCallParameter(Callable* callable, VisitResult parameter,
503 : const Type* parameter_type,
504 : std::vector<VisitResult>* converted_arguments,
505 : StackRange* argument_range,
506 : std::vector<std::string>* constexpr_arguments);
507 :
508 : VisitResult GenerateCall(Callable* callable,
509 : base::Optional<LocationReference> this_parameter,
510 : Arguments parameters,
511 : const TypeVector& specialization_types = {},
512 : bool tail_call = false);
513 : VisitResult GenerateCall(const QualifiedName& callable_name,
514 : Arguments parameters,
515 : const TypeVector& specialization_types = {},
516 : bool tail_call = false);
517 2133 : VisitResult GenerateCall(std::string callable_name, Arguments parameters,
518 : const TypeVector& specialization_types = {},
519 : bool tail_call = false) {
520 : return GenerateCall(QualifiedName(std::move(callable_name)),
521 6399 : std::move(parameters), specialization_types, tail_call);
522 : }
523 : VisitResult GeneratePointerCall(Expression* callee,
524 : const Arguments& parameters, bool tail_call);
525 :
526 : void GenerateBranch(const VisitResult& condition, Block* true_block,
527 : Block* false_block);
528 :
529 : typedef std::function<VisitResult()> VisitResultGenerator;
530 : void GenerateExpressionBranch(VisitResultGenerator, Block* true_block,
531 : Block* false_block);
532 : void GenerateExpressionBranch(Expression* expression, Block* true_block,
533 : Block* false_block);
534 :
535 : void GenerateMacroFunctionDeclaration(std::ostream& o,
536 : const std::string& macro_prefix,
537 : Macro* macro);
538 : void GenerateFunctionDeclaration(std::ostream& o,
539 : const std::string& macro_prefix,
540 : const std::string& name,
541 : const Signature& signature,
542 : const NameVector& parameter_names);
543 :
544 : VisitResult GenerateImplicitConvert(const Type* destination_type,
545 : VisitResult source);
546 :
547 : StackRange GenerateLabelGoto(LocalLabel* label,
548 : base::Optional<StackRange> arguments = {});
549 :
550 : std::vector<Binding<LocalLabel>*> LabelsFromIdentifiers(
551 : const std::vector<std::string>& names);
552 :
553 : StackRange LowerParameter(const Type* type, const std::string& parameter_name,
554 : Stack<std::string>* lowered_parameters);
555 :
556 : void LowerLabelParameter(const Type* type, const std::string& parameter_name,
557 : std::vector<std::string>* lowered_parameters);
558 :
559 : std::string ExternalLabelName(const std::string& label_name);
560 : std::string ExternalLabelParameterName(const std::string& label_name,
561 : size_t i);
562 : std::string ExternalParameterName(const std::string& name);
563 :
564 8946 : std::ostream& source_out() {
565 8946 : Callable* callable = CurrentCallable::Get();
566 8946 : if (!callable || callable->ShouldGenerateExternalCode()) {
567 17542 : return CurrentNamespace()->source_stream();
568 : } else {
569 175 : return null_stream_;
570 : }
571 : }
572 3839 : std::ostream& header_out() {
573 3839 : Callable* callable = CurrentCallable::Get();
574 3839 : if (!callable || callable->ShouldGenerateExternalCode()) {
575 7492 : return CurrentNamespace()->header_stream();
576 : } else {
577 93 : return null_stream_;
578 : }
579 : }
580 : CfgAssembler& assembler() { return *assembler_; }
581 :
582 : void SetReturnValue(VisitResult return_value) {
583 : base::Optional<VisitResult>& current_return_value =
584 : CurrentReturnValue::Get();
585 : DCHECK_IMPLIES(current_return_value, *current_return_value == return_value);
586 : current_return_value = std::move(return_value);
587 : }
588 :
589 1229 : VisitResult GetAndClearReturnValue() {
590 : VisitResult return_value = *CurrentReturnValue::Get();
591 : CurrentReturnValue::Get() = base::nullopt;
592 1229 : return return_value;
593 : }
594 :
595 : base::Optional<CfgAssembler> assembler_;
596 : NullOStream null_stream_;
597 : };
598 :
599 : } // namespace torque
600 : } // namespace internal
601 : } // namespace v8
602 :
603 : #endif // V8_TORQUE_IMPLEMENTATION_VISITOR_H_
|