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 20168 : 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 5891 : 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 5891 : return result;
43 : }
44 148 : static LocationReference ArrayAccess(VisitResult base, VisitResult offset) {
45 : LocationReference result;
46 296 : result.eval_function_ = std::string{"[]"};
47 296 : result.assign_function_ = std::string{"[]="};
48 296 : result.call_arguments_ = {base, offset};
49 148 : return result;
50 : }
51 439 : static LocationReference FieldAccess(VisitResult object,
52 : std::string fieldname) {
53 : LocationReference result;
54 878 : result.eval_function_ = "." + fieldname;
55 1317 : result.assign_function_ = "." + fieldname + "=";
56 878 : result.call_arguments_ = {object};
57 : result.index_field_ = base::nullopt;
58 439 : return result;
59 : }
60 126 : static LocationReference IndexedFieldIndexedAccess(
61 : const LocationReference& indexed_field, VisitResult index) {
62 : LocationReference result;
63 : DCHECK(indexed_field.IsIndexedFieldAccess());
64 : std::string fieldname = *indexed_field.index_field_;
65 378 : result.eval_function_ = "." + fieldname + "[]";
66 378 : result.assign_function_ = "." + fieldname + "[]=";
67 : result.call_arguments_ = indexed_field.call_arguments_;
68 126 : result.call_arguments_.push_back(index);
69 : result.index_field_ = fieldname;
70 126 : return result;
71 : }
72 126 : static LocationReference IndexedFieldAccess(VisitResult object,
73 : std::string fieldname) {
74 : LocationReference result;
75 252 : result.call_arguments_ = {object};
76 : result.index_field_ = fieldname;
77 126 : return result;
78 : }
79 :
80 : bool IsConst() const { return temporary_.has_value(); }
81 :
82 : bool IsVariableAccess() const { return variable_.has_value(); }
83 : const VisitResult& variable() const {
84 : DCHECK(IsVariableAccess());
85 : return *variable_;
86 : }
87 : 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 642 : if (IsVariableAccess()) return variable();
95 : DCHECK(IsTemporary());
96 : 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 : bool IsArrayField() const { return index_field_.has_value(); }
106 : bool IsIndexedFieldAccess() const {
107 873 : return IsArrayField() && !IsCallAccess();
108 : }
109 : bool IsIndexedFieldIndexedAccess() const {
110 : return IsArrayField() && IsCallAccess();
111 : }
112 : bool IsCallAccess() const {
113 : 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 : LocationReference() = default;
140 : };
141 :
142 24 : struct InitializerResults {
143 : std::vector<VisitResult> results;
144 : };
145 :
146 : template <class T>
147 : class Binding;
148 :
149 : template <class T>
150 2550 : class BindingsManager {
151 : public:
152 : base::Optional<Binding<T>*> TryLookup(const std::string& name) {
153 18415 : return current_bindings_[name];
154 : }
155 :
156 : private:
157 : friend class Binding<T>;
158 : std::unordered_map<std::string, base::Optional<Binding<T>*>>
159 : current_bindings_;
160 : };
161 :
162 : template <class T>
163 : class Binding : public T {
164 : public:
165 : template <class... Args>
166 7505 : Binding(BindingsManager<T>* manager, const std::string& name, Args&&... args)
167 : : T(std::forward<Args>(args)...),
168 : manager_(manager),
169 : name_(name),
170 15010 : previous_binding_(this) {
171 15010 : std::swap(previous_binding_, manager_->current_bindings_[name]);
172 7505 : }
173 : template <class... Args>
174 : Binding(BindingsManager<T>* manager, const Identifier* name, Args&&... args)
175 3811 : : Binding(manager, name->value, std::forward<Args>(args)...) {
176 3811 : declaration_position_ = name->pos;
177 : }
178 15010 : ~Binding() { manager_->current_bindings_[name_] = previous_binding_; }
179 :
180 4874 : const std::string& name() const { return name_; }
181 1 : SourcePosition declaration_position() const { return declaration_position_; }
182 :
183 : private:
184 : BindingsManager<T>* manager_;
185 : const std::string name_;
186 : base::Optional<Binding*> previous_binding_;
187 : SourcePosition declaration_position_ = CurrentSourcePosition::Get();
188 : DISALLOW_COPY_AND_ASSIGN(Binding);
189 : };
190 :
191 : template <class T>
192 3389 : class BlockBindings {
193 : public:
194 4454 : explicit BlockBindings(BindingsManager<T>* manager) : manager_(manager) {}
195 386 : void Add(std::string name, T value) {
196 386 : ReportErrorIfAlreadyBound(name);
197 772 : bindings_.push_back(base::make_unique<Binding<T>>(manager_, std::move(name),
198 : std::move(value)));
199 386 : }
200 :
201 3811 : void Add(const Identifier* name, T value) {
202 3811 : ReportErrorIfAlreadyBound(name->value);
203 7622 : bindings_.push_back(
204 : base::make_unique<Binding<T>>(manager_, name, std::move(value)));
205 3811 : }
206 :
207 : std::vector<Binding<T>*> bindings() const {
208 : std::vector<Binding<T>*> result;
209 : result.reserve(bindings_.size());
210 : for (auto& b : bindings_) {
211 : result.push_back(b.get());
212 : }
213 : return result;
214 : }
215 :
216 : private:
217 4197 : void ReportErrorIfAlreadyBound(const std::string& name) {
218 9071 : for (const auto& binding : bindings_) {
219 4874 : if (binding->name() == name) {
220 0 : ReportError(
221 : "redeclaration of name \"", name,
222 : "\" in the same block is illegal, previous declaration at: ",
223 : binding->declaration_position());
224 : }
225 : }
226 4197 : }
227 :
228 : BindingsManager<T>* manager_;
229 : std::vector<std::unique_ptr<Binding<T>>> bindings_;
230 : };
231 :
232 12363 : struct LocalValue {
233 : bool is_const;
234 : VisitResult value;
235 : };
236 :
237 10428 : struct LocalLabel {
238 : Block* block;
239 : std::vector<const Type*> parameter_types;
240 :
241 : explicit LocalLabel(Block* block,
242 : std::vector<const Type*> parameter_types = {})
243 3476 : : block(block), parameter_types(std::move(parameter_types)) {}
244 : };
245 :
246 44108 : struct Arguments {
247 : VisitResultVector parameters;
248 : std::vector<Binding<LocalLabel>*> labels;
249 : };
250 :
251 : // Determine if a callable should be considered as an overload.
252 : bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
253 : size_t label_count);
254 :
255 9 : class ImplementationVisitor : public FileVisitor {
256 : public:
257 : void GenerateBuiltinDefinitions(std::string& file_name);
258 : void GenerateClassDefinitions(std::string& file_name);
259 :
260 : VisitResult Visit(Expression* expr);
261 : const Type* Visit(Statement* stmt);
262 :
263 : InitializerResults VisitInitializerResults(
264 : const std::vector<Expression*>& expressions);
265 :
266 : size_t InitializeAggregateHelper(
267 : const AggregateType* aggregate_type, VisitResult allocate_result,
268 : const InitializerResults& initializer_results);
269 :
270 : void InitializeAggregate(const AggregateType* aggregate_type,
271 : VisitResult allocate_result,
272 : const InitializerResults& initializer_results);
273 :
274 : VisitResult TemporaryUninitializedStruct(const StructType* struct_type,
275 : const std::string& reason);
276 : VisitResult Visit(StructExpression* decl);
277 :
278 : LocationReference GetLocationReference(Expression* location);
279 : LocationReference GetLocationReference(IdentifierExpression* expr);
280 : LocationReference GetLocationReference(FieldAccessExpression* expr);
281 : LocationReference GetLocationReference(ElementAccessExpression* expr);
282 :
283 : VisitResult GenerateFetchFromLocation(const LocationReference& reference);
284 :
285 : VisitResult GetBuiltinCode(Builtin* builtin);
286 :
287 : VisitResult Visit(IdentifierExpression* expr);
288 633 : VisitResult Visit(FieldAccessExpression* expr) {
289 : StackScope scope(this);
290 1899 : return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
291 : }
292 211 : VisitResult Visit(ElementAccessExpression* expr) {
293 : StackScope scope(this);
294 633 : return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
295 : }
296 :
297 : void VisitAllDeclarables();
298 : void Visit(Declarable* delarable);
299 : void Visit(TypeAlias* decl);
300 : VisitResult InlineMacro(Macro* macro,
301 : base::Optional<LocationReference> this_reference,
302 : const std::vector<VisitResult>& arguments,
303 : const std::vector<Block*> label_blocks);
304 : void VisitMacroCommon(Macro* macro);
305 : void Visit(Macro* macro);
306 : void Visit(Method* macro);
307 : void Visit(Builtin* builtin);
308 : void Visit(NamespaceConstant* decl);
309 :
310 : VisitResult Visit(CallExpression* expr, bool is_tail = false);
311 : VisitResult Visit(CallMethodExpression* expr);
312 : VisitResult Visit(IntrinsicCallExpression* intrinsic);
313 : VisitResult Visit(LoadObjectFieldExpression* expr);
314 : VisitResult Visit(StoreObjectFieldExpression* expr);
315 : const Type* Visit(TailCallStatement* stmt);
316 :
317 : VisitResult Visit(ConditionalExpression* expr);
318 :
319 : VisitResult Visit(LogicalOrExpression* expr);
320 : VisitResult Visit(LogicalAndExpression* expr);
321 :
322 : VisitResult Visit(IncrementDecrementExpression* expr);
323 : VisitResult Visit(AssignmentExpression* expr);
324 : VisitResult Visit(StringLiteralExpression* expr);
325 : VisitResult Visit(NumberLiteralExpression* expr);
326 : VisitResult Visit(AssumeTypeImpossibleExpression* expr);
327 : VisitResult Visit(TryLabelExpression* expr);
328 : VisitResult Visit(StatementExpression* expr);
329 : VisitResult Visit(NewExpression* expr);
330 :
331 : const Type* Visit(ReturnStatement* stmt);
332 : const Type* Visit(GotoStatement* stmt);
333 : const Type* Visit(IfStatement* stmt);
334 : const Type* Visit(WhileStatement* stmt);
335 : const Type* Visit(BreakStatement* stmt);
336 : const Type* Visit(ContinueStatement* stmt);
337 : const Type* Visit(ForLoopStatement* stmt);
338 : const Type* Visit(VarDeclarationStatement* stmt);
339 : const Type* Visit(VarDeclarationStatement* stmt,
340 : BlockBindings<LocalValue>* block_bindings);
341 : const Type* Visit(ForOfLoopStatement* stmt);
342 : const Type* Visit(BlockStatement* block);
343 : const Type* Visit(ExpressionStatement* stmt);
344 : const Type* Visit(DebugStatement* stmt);
345 : const Type* Visit(AssertStatement* stmt);
346 :
347 : void BeginNamespaceFile(Namespace* nspace);
348 : void EndNamespaceFile(Namespace* nspace);
349 :
350 : void GenerateImplementation(const std::string& dir, Namespace* nspace);
351 :
352 : DECLARE_CONTEXTUAL_VARIABLE(ValueBindingsManager,
353 : BindingsManager<LocalValue>);
354 : DECLARE_CONTEXTUAL_VARIABLE(LabelBindingsManager,
355 : BindingsManager<LocalLabel>);
356 : DECLARE_CONTEXTUAL_VARIABLE(CurrentCallable, Callable*);
357 : DECLARE_CONTEXTUAL_VARIABLE(CurrentReturnValue, base::Optional<VisitResult>);
358 :
359 : // A BindingsManagersScope has to be active for local bindings to be created.
360 : // Shadowing an existing BindingsManagersScope by creating a new one hides all
361 : // existing bindings while the additional BindingsManagersScope is active.
362 5100 : struct BindingsManagersScope {
363 : ValueBindingsManager::Scope value_bindings_manager;
364 : LabelBindingsManager::Scope label_bindings_manager;
365 : };
366 :
367 : private:
368 : base::Optional<Block*> GetCatchBlock();
369 : void GenerateCatchBlock(base::Optional<Block*> catch_block);
370 :
371 : // {StackScope} records the stack height at creation time and reconstructs it
372 : // when being destructed by emitting a {DeleteRangeInstruction}, except for
373 : // the slots protected by {StackScope::Yield}. Calling {Yield(v)} deletes all
374 : // slots above the initial stack height except for the slots of {v}, which are
375 : // moved to form the only slots above the initial height and marks them to
376 : // survive destruction of the {StackScope}. A typical pattern is the
377 : // following:
378 : //
379 : // VisitResult result;
380 : // {
381 : // StackScope stack_scope(this);
382 : // // ... create temporary slots ...
383 : // result = stack_scope.Yield(surviving_slots);
384 : // }
385 : class StackScope {
386 : public:
387 33292 : explicit StackScope(ImplementationVisitor* visitor) : visitor_(visitor) {
388 33292 : base_ = visitor_->assembler().CurrentStack().AboveTop();
389 : }
390 27541 : VisitResult Yield(VisitResult result) {
391 : DCHECK(!closed_);
392 27541 : closed_ = true;
393 27541 : if (!result.IsOnStack()) {
394 6740 : if (!visitor_->assembler().CurrentBlockIsComplete()) {
395 6358 : visitor_->assembler().DropTo(base_);
396 : }
397 3370 : return result;
398 : }
399 : DCHECK_LE(base_, result.stack_range().begin());
400 : DCHECK_LE(result.stack_range().end(),
401 : visitor_->assembler().CurrentStack().AboveTop());
402 48342 : visitor_->assembler().DropTo(result.stack_range().end());
403 48342 : visitor_->assembler().DeleteRange(
404 24171 : StackRange{base_, result.stack_range().begin()});
405 48342 : base_ = visitor_->assembler().CurrentStack().AboveTop();
406 : return VisitResult(result.type(), visitor_->assembler().TopRange(
407 : result.stack_range().Size()));
408 : }
409 :
410 5751 : void Close() {
411 : DCHECK(!closed_);
412 5751 : closed_ = true;
413 11502 : if (!visitor_->assembler().CurrentBlockIsComplete()) {
414 5498 : visitor_->assembler().DropTo(base_);
415 : }
416 5751 : }
417 :
418 33292 : ~StackScope() {
419 33292 : if (closed_) {
420 : DCHECK_IMPLIES(
421 : !visitor_->assembler().CurrentBlockIsComplete(),
422 : base_ == visitor_->assembler().CurrentStack().AboveTop());
423 : } else {
424 5751 : Close();
425 : }
426 : }
427 :
428 : private:
429 : ImplementationVisitor* visitor_;
430 : BottomOffset base_;
431 : bool closed_ = false;
432 : };
433 :
434 103 : class BreakContinueActivator {
435 : public:
436 103 : BreakContinueActivator(Block* break_block, Block* continue_block)
437 : : break_binding_{&LabelBindingsManager::Get(), "_break",
438 : LocalLabel{break_block}},
439 : continue_binding_{&LabelBindingsManager::Get(), "_continue",
440 824 : LocalLabel{continue_block}} {}
441 :
442 : private:
443 : Binding<LocalLabel> break_binding_;
444 : Binding<LocalLabel> continue_binding_;
445 : };
446 :
447 : base::Optional<Binding<LocalValue>*> TryLookupLocalValue(
448 : const std::string& name);
449 : base::Optional<Binding<LocalLabel>*> TryLookupLabel(const std::string& name);
450 : Binding<LocalLabel>* LookupLabel(const std::string& name);
451 : Block* LookupSimpleLabel(const std::string& name);
452 : template <class Container>
453 : Callable* LookupCallable(const QualifiedName& name,
454 : const Container& declaration_container,
455 : const TypeVector& types,
456 : const std::vector<Binding<LocalLabel>*>& labels,
457 : const TypeVector& specialization_types);
458 :
459 : template <class Container>
460 : Callable* LookupCallable(const QualifiedName& name,
461 : const Container& declaration_container,
462 : const Arguments& arguments,
463 : const TypeVector& specialization_types);
464 :
465 : Method* LookupMethod(const std::string& name, LocationReference target,
466 : const Arguments& arguments,
467 : const TypeVector& specialization_types);
468 :
469 : const Type* GetCommonType(const Type* left, const Type* right);
470 :
471 : VisitResult GenerateCopy(const VisitResult& to_copy);
472 :
473 : void GenerateAssignToLocation(const LocationReference& reference,
474 : const VisitResult& assignment_value);
475 :
476 : void AddCallParameter(Callable* callable, VisitResult parameter,
477 : const Type* parameter_type,
478 : std::vector<VisitResult>* converted_arguments,
479 : StackRange* argument_range,
480 : std::vector<std::string>* constexpr_arguments);
481 :
482 : VisitResult GenerateCall(Callable* callable,
483 : base::Optional<LocationReference> this_parameter,
484 : Arguments parameters,
485 : const TypeVector& specialization_types = {},
486 : bool tail_call = false);
487 : VisitResult GenerateCall(const QualifiedName& callable_name,
488 : Arguments parameters,
489 : const TypeVector& specialization_types = {},
490 : bool tail_call = false);
491 2405 : VisitResult GenerateCall(std::string callable_name, Arguments parameters,
492 : const TypeVector& specialization_types = {},
493 : bool tail_call = false) {
494 : return GenerateCall(QualifiedName(std::move(callable_name)),
495 7215 : std::move(parameters), specialization_types, tail_call);
496 : }
497 : VisitResult GeneratePointerCall(Expression* callee,
498 : const Arguments& parameters, bool tail_call);
499 :
500 : void GenerateBranch(const VisitResult& condition, Block* true_block,
501 : Block* false_block);
502 :
503 : void GenerateExpressionBranch(Expression* expression, Block* true_block,
504 : Block* false_block);
505 :
506 : void GenerateMacroFunctionDeclaration(std::ostream& o,
507 : const std::string& macro_prefix,
508 : Macro* macro);
509 : void GenerateFunctionDeclaration(std::ostream& o,
510 : const std::string& macro_prefix,
511 : const std::string& name,
512 : const Signature& signature,
513 : const NameVector& parameter_names);
514 :
515 : VisitResult GenerateImplicitConvert(const Type* destination_type,
516 : VisitResult source);
517 :
518 : StackRange GenerateLabelGoto(LocalLabel* label,
519 : base::Optional<StackRange> arguments = {});
520 :
521 : std::vector<Binding<LocalLabel>*> LabelsFromIdentifiers(
522 : const std::vector<std::string>& names);
523 :
524 : StackRange LowerParameter(const Type* type, const std::string& parameter_name,
525 : Stack<std::string>* lowered_parameters);
526 :
527 : void LowerLabelParameter(const Type* type, const std::string& parameter_name,
528 : std::vector<std::string>* lowered_parameters);
529 :
530 : std::string ExternalLabelName(const std::string& label_name);
531 : std::string ExternalLabelParameterName(const std::string& label_name,
532 : size_t i);
533 : std::string ExternalParameterName(const std::string& name);
534 :
535 7893 : std::ostream& source_out() {
536 7893 : Callable* callable = CurrentCallable::Get();
537 7893 : if (!callable || callable->ShouldGenerateExternalCode()) {
538 15492 : return CurrentNamespace()->source_stream();
539 : } else {
540 147 : return null_stream_;
541 : }
542 : }
543 3293 : std::ostream& header_out() {
544 3293 : Callable* callable = CurrentCallable::Get();
545 3293 : if (!callable || callable->ShouldGenerateExternalCode()) {
546 6424 : return CurrentNamespace()->header_stream();
547 : } else {
548 81 : return null_stream_;
549 : }
550 : }
551 : CfgAssembler& assembler() { return *assembler_; }
552 :
553 : void SetReturnValue(VisitResult return_value) {
554 : base::Optional<VisitResult>& current_return_value =
555 : CurrentReturnValue::Get();
556 : DCHECK_IMPLIES(current_return_value, *current_return_value == return_value);
557 : current_return_value = std::move(return_value);
558 : }
559 :
560 1065 : VisitResult GetAndClearReturnValue() {
561 : VisitResult return_value = *CurrentReturnValue::Get();
562 : CurrentReturnValue::Get() = base::nullopt;
563 1065 : return return_value;
564 : }
565 :
566 : base::Optional<CfgAssembler> assembler_;
567 : NullOStream null_stream_;
568 : };
569 :
570 : } // namespace torque
571 : } // namespace internal
572 : } // namespace v8
573 :
574 : #endif // V8_TORQUE_IMPLEMENTATION_VISITOR_H_
|