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 12636 : class LocationReference {
28 : public:
29 : // An assignable stack range.
30 : static LocationReference VariableAccess(VisitResult variable) {
31 : DCHECK(variable.IsOnStack());
32 1647 : 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 4112 : LocationReference result;
40 : result.temporary_ = std::move(temporary);
41 : result.temporary_description_ = std::move(description);
42 : return result;
43 : }
44 195 : static LocationReference ArrayAccess(VisitResult base, VisitResult offset) {
45 195 : LocationReference result;
46 390 : result.eval_function_ = std::string{"[]"};
47 390 : result.assign_function_ = std::string{"[]="};
48 585 : result.call_arguments_ = {base, offset};
49 195 : return result;
50 : }
51 244 : static LocationReference FieldAccess(VisitResult object,
52 : std::string fieldname) {
53 244 : LocationReference result;
54 488 : result.eval_function_ = "." + fieldname;
55 732 : result.assign_function_ = "." + fieldname + "=";
56 732 : result.call_arguments_ = {object};
57 244 : return result;
58 : }
59 :
60 : bool IsConst() const { return temporary_.has_value(); }
61 :
62 2451 : bool IsVariableAccess() const { return variable_.has_value(); }
63 : const VisitResult& variable() const {
64 : DCHECK(IsVariableAccess());
65 : return *variable_;
66 : }
67 5973 : bool IsTemporary() const { return temporary_.has_value(); }
68 : const VisitResult& temporary() const {
69 : DCHECK(IsTemporary());
70 : return *temporary_;
71 : }
72 :
73 : const VisitResult& GetVisitResult() const {
74 49 : if (IsVariableAccess()) return variable();
75 : DCHECK(IsTemporary());
76 15 : return temporary();
77 : }
78 :
79 : // For error reporting.
80 : const std::string& temporary_description() const {
81 : DCHECK(IsTemporary());
82 : return *temporary_description_;
83 : }
84 :
85 : bool IsCallAccess() const {
86 510 : bool is_call_access = eval_function_.has_value();
87 : DCHECK_EQ(is_call_access, assign_function_.has_value());
88 : return is_call_access;
89 : }
90 : const VisitResultVector& call_arguments() const {
91 : DCHECK(IsCallAccess());
92 : return call_arguments_;
93 : }
94 : const std::string& eval_function() const {
95 : DCHECK(IsCallAccess());
96 : return *eval_function_;
97 : }
98 : const std::string& assign_function() const {
99 : DCHECK(IsCallAccess());
100 : return *assign_function_;
101 : }
102 :
103 : private:
104 : base::Optional<VisitResult> variable_;
105 : base::Optional<VisitResult> temporary_;
106 : base::Optional<std::string> temporary_description_;
107 : base::Optional<std::string> eval_function_;
108 : base::Optional<std::string> assign_function_;
109 : VisitResultVector call_arguments_;
110 :
111 12396 : LocationReference() = default;
112 : };
113 :
114 : template <class T>
115 : class Binding;
116 :
117 : template <class T>
118 1224 : class BindingsManager {
119 : public:
120 14035 : base::Optional<Binding<T>*> TryLookup(const std::string& name) {
121 14035 : return current_bindings_[name];
122 : }
123 :
124 : private:
125 : friend class Binding<T>;
126 : std::unordered_map<std::string, base::Optional<Binding<T>*>>
127 : current_bindings_;
128 : };
129 :
130 : template <class T>
131 : class Binding : public T {
132 : public:
133 : template <class... Args>
134 4560 : Binding(BindingsManager<T>* manager, const std::string& name, Args&&... args)
135 : : T(std::forward<Args>(args)...),
136 : manager_(manager),
137 : name_(name),
138 9120 : previous_binding_(this) {
139 9120 : std::swap(previous_binding_, manager_->current_bindings_[name]);
140 4560 : }
141 9120 : ~Binding() { manager_->current_bindings_[name_] = previous_binding_; }
142 :
143 : const std::string& name() const { return name_; }
144 0 : SourcePosition declaration_position() const { return declaration_position_; }
145 :
146 : private:
147 : BindingsManager<T>* manager_;
148 : const std::string name_;
149 : base::Optional<Binding*> previous_binding_;
150 : SourcePosition declaration_position_ = CurrentSourcePosition::Get();
151 : DISALLOW_COPY_AND_ASSIGN(Binding);
152 : };
153 :
154 : template <class T>
155 2010 : class BlockBindings {
156 : public:
157 2462 : explicit BlockBindings(BindingsManager<T>* manager) : manager_(manager) {}
158 2536 : void Add(std::string name, T value) {
159 8537 : for (const auto& binding : bindings_) {
160 3465 : if (binding->name() == name) {
161 0 : ReportError(
162 : "redeclaration of name \"", name,
163 : "\" in the same block is illegal, previous declaration at: ",
164 0 : binding->declaration_position());
165 : }
166 : }
167 5072 : bindings_.push_back(base::make_unique<Binding<T>>(manager_, std::move(name),
168 : std::move(value)));
169 2536 : }
170 :
171 : std::vector<Binding<T>*> bindings() const {
172 : std::vector<Binding<T>*> result;
173 : result.reserve(bindings_.size());
174 : for (auto& b : bindings_) {
175 : result.push_back(b.get());
176 : }
177 : return result;
178 : }
179 :
180 : private:
181 : BindingsManager<T>* manager_;
182 : std::vector<std::unique_ptr<Binding<T>>> bindings_;
183 : };
184 :
185 2435 : struct LocalValue {
186 : bool is_const;
187 : VisitResult value;
188 : };
189 :
190 2150 : struct LocalLabel {
191 : Block* block;
192 : std::vector<const Type*> parameter_types;
193 :
194 : explicit LocalLabel(Block* block,
195 : std::vector<const Type*> parameter_types = {})
196 2150 : : block(block), parameter_types(std::move(parameter_types)) {}
197 : };
198 :
199 32869 : struct Arguments {
200 : VisitResultVector parameters;
201 : std::vector<Binding<LocalLabel>*> labels;
202 : };
203 :
204 : bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
205 : const std::vector<Binding<LocalLabel>*>& labels);
206 :
207 : class ImplementationVisitor : public FileVisitor {
208 : public:
209 : void GenerateBuiltinDefinitions(std::string& file_name);
210 : void GenerateClassDefinitions(std::string& file_name);
211 :
212 : VisitResult Visit(Expression* expr);
213 : const Type* Visit(Statement* stmt);
214 :
215 : VisitResult Visit(StructExpression* decl);
216 :
217 : LocationReference GetLocationReference(Expression* location);
218 : LocationReference GetLocationReference(IdentifierExpression* expr);
219 : LocationReference GetLocationReference(FieldAccessExpression* expr);
220 : LocationReference GetLocationReference(ElementAccessExpression* expr);
221 :
222 : VisitResult GenerateFetchFromLocation(const LocationReference& reference);
223 :
224 : VisitResult GetBuiltinCode(Builtin* builtin);
225 :
226 : VisitResult Visit(IdentifierExpression* expr);
227 259 : VisitResult Visit(FieldAccessExpression* expr) {
228 : StackScope scope(this);
229 777 : return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
230 : }
231 134 : VisitResult Visit(ElementAccessExpression* expr) {
232 : StackScope scope(this);
233 402 : return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
234 : }
235 :
236 : void VisitAllDeclarables();
237 : void Visit(Declarable* delarable);
238 : void Visit(TypeAlias* decl);
239 : VisitResult InlineMacro(Macro* macro,
240 : base::Optional<LocationReference> this_reference,
241 : const std::vector<VisitResult>& arguments,
242 : const std::vector<Block*> label_blocks);
243 : void VisitMacroCommon(Macro* macro);
244 : void Visit(Macro* macro);
245 : void Visit(Method* macro);
246 : void Visit(Builtin* builtin);
247 : void Visit(NamespaceConstant* decl);
248 :
249 : VisitResult Visit(CallExpression* expr, bool is_tail = false);
250 : VisitResult Visit(CallMethodExpression* expr);
251 : VisitResult Visit(IntrinsicCallExpression* intrinsic);
252 : VisitResult Visit(LoadObjectFieldExpression* intrinsic);
253 : VisitResult Visit(StoreObjectFieldExpression* intrinsic);
254 : const Type* Visit(TailCallStatement* stmt);
255 :
256 : VisitResult Visit(ConditionalExpression* expr);
257 :
258 : VisitResult Visit(LogicalOrExpression* expr);
259 : VisitResult Visit(LogicalAndExpression* expr);
260 :
261 : VisitResult Visit(IncrementDecrementExpression* expr);
262 : VisitResult Visit(AssignmentExpression* expr);
263 : VisitResult Visit(StringLiteralExpression* expr);
264 : VisitResult Visit(NumberLiteralExpression* expr);
265 : VisitResult Visit(AssumeTypeImpossibleExpression* expr);
266 : VisitResult Visit(TryLabelExpression* expr);
267 : VisitResult Visit(StatementExpression* expr);
268 : VisitResult Visit(NewExpression* expr);
269 :
270 : const Type* Visit(ReturnStatement* stmt);
271 : const Type* Visit(GotoStatement* stmt);
272 : const Type* Visit(IfStatement* stmt);
273 : const Type* Visit(WhileStatement* stmt);
274 : const Type* Visit(BreakStatement* stmt);
275 : const Type* Visit(ContinueStatement* stmt);
276 : const Type* Visit(ForLoopStatement* stmt);
277 : const Type* Visit(VarDeclarationStatement* stmt);
278 : const Type* Visit(VarDeclarationStatement* stmt,
279 : BlockBindings<LocalValue>* block_bindings);
280 : const Type* Visit(ForOfLoopStatement* stmt);
281 : const Type* Visit(BlockStatement* block);
282 : const Type* Visit(ExpressionStatement* stmt);
283 : const Type* Visit(DebugStatement* stmt);
284 : const Type* Visit(AssertStatement* stmt);
285 :
286 : void BeginNamespaceFile(Namespace* nspace);
287 : void EndNamespaceFile(Namespace* nspace);
288 :
289 : void GenerateImplementation(const std::string& dir, Namespace* nspace);
290 :
291 : struct ConstructorInfo {
292 : int super_calls;
293 : bool accessed_this;
294 : };
295 :
296 : DECLARE_CONTEXTUAL_VARIABLE(ValueBindingsManager,
297 : BindingsManager<LocalValue>);
298 : DECLARE_CONTEXTUAL_VARIABLE(LabelBindingsManager,
299 : BindingsManager<LocalLabel>);
300 : DECLARE_CONTEXTUAL_VARIABLE(CurrentCallable, Callable*);
301 : DECLARE_CONTEXTUAL_VARIABLE(CurrentReturnValue, base::Optional<VisitResult>);
302 : DECLARE_CONTEXTUAL_VARIABLE(CurrentConstructorInfo,
303 : base::Optional<ConstructorInfo>);
304 :
305 : // A BindingsManagersScope has to be active for local bindings to be created.
306 : // Shadowing an existing BindingsManagersScope by creating a new one hides all
307 : // existing bindings while the additional BindingsManagersScope is active.
308 1224 : struct BindingsManagersScope {
309 : ValueBindingsManager::Scope value_bindings_manager;
310 : LabelBindingsManager::Scope label_bindings_manager;
311 : };
312 :
313 : private:
314 : base::Optional<Block*> GetCatchBlock();
315 : void GenerateCatchBlock(base::Optional<Block*> catch_block);
316 :
317 : // {StackScope} records the stack height at creation time and reconstructs it
318 : // when being destructed by emitting a {DeleteRangeInstruction}, except for
319 : // the slots protected by {StackScope::Yield}. Calling {Yield(v)} deletes all
320 : // slots above the initial stack height except for the slots of {v}, which are
321 : // moved to form the only slots above the initial height and marks them to
322 : // survive destruction of the {StackScope}. A typical pattern is the
323 : // following:
324 : //
325 : // VisitResult result;
326 : // {
327 : // StackScope stack_scope(this);
328 : // // ... create temporary slots ...
329 : // result = stack_scope.Yield(surviving_slots);
330 : // }
331 : class StackScope {
332 : public:
333 24479 : explicit StackScope(ImplementationVisitor* visitor) : visitor_(visitor) {
334 24479 : base_ = visitor_->assembler().CurrentStack().AboveTop();
335 : }
336 38496 : VisitResult Yield(VisitResult result) {
337 : DCHECK(!closed_);
338 20628 : closed_ = true;
339 20628 : if (!result.IsOnStack()) {
340 5520 : if (!visitor_->assembler().CurrentBlockIsComplete()) {
341 2646 : visitor_->assembler().DropTo(base_);
342 : }
343 2760 : return result;
344 : }
345 : DCHECK_LE(base_, result.stack_range().begin());
346 : DCHECK_LE(result.stack_range().end(),
347 : visitor_->assembler().CurrentStack().AboveTop());
348 17868 : visitor_->assembler().DropTo(result.stack_range().end());
349 17868 : visitor_->assembler().DeleteRange(
350 17868 : StackRange{base_, result.stack_range().begin()});
351 35736 : base_ = visitor_->assembler().CurrentStack().AboveTop();
352 : return VisitResult(result.type(), visitor_->assembler().TopRange(
353 : result.stack_range().Size()));
354 : }
355 :
356 3851 : void Close() {
357 : DCHECK(!closed_);
358 3851 : closed_ = true;
359 7702 : if (!visitor_->assembler().CurrentBlockIsComplete()) {
360 1947 : visitor_->assembler().DropTo(base_);
361 : }
362 3851 : }
363 :
364 : ~StackScope() {
365 24479 : if (closed_) {
366 : DCHECK_IMPLIES(
367 : !visitor_->assembler().CurrentBlockIsComplete(),
368 : base_ == visitor_->assembler().CurrentStack().AboveTop());
369 : } else {
370 3851 : Close();
371 : }
372 : }
373 :
374 : private:
375 : ImplementationVisitor* visitor_;
376 : BottomOffset base_;
377 : bool closed_ = false;
378 : };
379 :
380 78 : class BreakContinueActivator {
381 : public:
382 78 : BreakContinueActivator(Block* break_block, Block* continue_block)
383 : : break_binding_{&LabelBindingsManager::Get(), "_break",
384 : LocalLabel{break_block}},
385 : continue_binding_{&LabelBindingsManager::Get(), "_continue",
386 624 : LocalLabel{continue_block}} {}
387 :
388 : private:
389 : Binding<LocalLabel> break_binding_;
390 : Binding<LocalLabel> continue_binding_;
391 : };
392 :
393 : base::Optional<Binding<LocalValue>*> TryLookupLocalValue(
394 : const std::string& name);
395 : base::Optional<Binding<LocalLabel>*> TryLookupLabel(const std::string& name);
396 : Binding<LocalLabel>* LookupLabel(const std::string& name);
397 : Block* LookupSimpleLabel(const std::string& name);
398 : template <class Container>
399 : Callable* LookupCall(const QualifiedName& name,
400 : const Container& declaration_container,
401 : const Arguments& arguments,
402 : const TypeVector& specialization_types);
403 :
404 : const Type* GetCommonType(const Type* left, const Type* right);
405 :
406 : VisitResult GenerateCopy(const VisitResult& to_copy);
407 :
408 : void GenerateAssignToLocation(const LocationReference& reference,
409 : const VisitResult& assignment_value);
410 :
411 : void AddCallParameter(Callable* callable, VisitResult parameter,
412 : const Type* parameter_type,
413 : std::vector<VisitResult>* converted_arguments,
414 : StackRange* argument_range,
415 : std::vector<std::string>* constexpr_arguments);
416 :
417 : VisitResult GenerateCall(Callable* callable,
418 : base::Optional<LocationReference> this_parameter,
419 : Arguments parameters,
420 : const TypeVector& specialization_types = {},
421 : bool tail_call = false);
422 : VisitResult GenerateCall(const QualifiedName& callable_name,
423 : Arguments parameters,
424 : const TypeVector& specialization_types = {},
425 : bool tail_call = false);
426 1766 : VisitResult GenerateCall(std::string callable_name, Arguments parameters,
427 : const TypeVector& specialization_types = {},
428 : bool tail_call = false) {
429 : return GenerateCall(QualifiedName(std::move(callable_name)),
430 5298 : std::move(parameters), specialization_types, tail_call);
431 : }
432 : VisitResult GeneratePointerCall(Expression* callee,
433 : const Arguments& parameters, bool tail_call);
434 :
435 : void GenerateBranch(const VisitResult& condition, Block* true_block,
436 : Block* false_block);
437 :
438 : void GenerateExpressionBranch(Expression* expression, Block* true_block,
439 : Block* false_block);
440 :
441 : void GenerateMacroFunctionDeclaration(std::ostream& o,
442 : const std::string& macro_prefix,
443 : Macro* macro);
444 : void GenerateFunctionDeclaration(std::ostream& o,
445 : const std::string& macro_prefix,
446 : const std::string& name,
447 : const Signature& signature,
448 : const NameVector& parameter_names);
449 :
450 : VisitResult GenerateImplicitConvert(const Type* destination_type,
451 : VisitResult source);
452 :
453 : StackRange GenerateLabelGoto(LocalLabel* label,
454 : base::Optional<StackRange> arguments = {});
455 :
456 : std::vector<Binding<LocalLabel>*> LabelsFromIdentifiers(
457 : const std::vector<std::string>& names);
458 :
459 : StackRange LowerParameter(const Type* type, const std::string& parameter_name,
460 : Stack<std::string>* lowered_parameters);
461 :
462 : std::string ExternalLabelName(const std::string& label_name);
463 : std::string ExternalLabelParameterName(const std::string& label_name,
464 : size_t i);
465 : std::string ExternalParameterName(const std::string& name);
466 :
467 4286 : std::ostream& source_out() { return CurrentNamespace()->source_stream(); }
468 :
469 1626 : std::ostream& header_out() { return CurrentNamespace()->header_stream(); }
470 :
471 : CfgAssembler& assembler() { return *assembler_; }
472 :
473 : void SetReturnValue(VisitResult return_value) {
474 : base::Optional<VisitResult>& current_return_value =
475 : CurrentReturnValue::Get();
476 : DCHECK_IMPLIES(current_return_value, *current_return_value == return_value);
477 : current_return_value = std::move(return_value);
478 : }
479 :
480 : VisitResult GetAndClearReturnValue() {
481 452 : VisitResult return_value = *CurrentReturnValue::Get();
482 : CurrentReturnValue::Get() = base::nullopt;
483 : return return_value;
484 : }
485 :
486 : base::Optional<CfgAssembler> assembler_;
487 : };
488 :
489 : } // namespace torque
490 : } // namespace internal
491 : } // namespace v8
492 :
493 : #endif // V8_TORQUE_IMPLEMENTATION_VISITOR_H_
|