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