1// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_TOKEN_POSITION_H_
6#define RUNTIME_VM_TOKEN_POSITION_H_
7
8#include "platform/utils.h"
9#include "vm/allocation.h"
10
11namespace dart {
12
13// The token space is organized as follows:
14//
15// Sentinel values start at -1 and move towards negative infinity:
16// kNoSourcePos -> -1
17// ClassifyingTokenPositions 1 -> -1 - 1
18// ClassifyingTokenPositions N -> -1 - N
19//
20// Synthetically created AstNodes are given real source positions but encoded
21// as negative numbers from [kSmiMin32, -1 - N]. For example:
22//
23// A source position of 0 in a synthetic AstNode would be encoded as -2 - N.
24// A source position of 1 in a synthetic AstNode would be encoded as -3 - N.
25//
26// All other AstNodes are given real source positions encoded as positive
27// integers.
28//
29// This organization allows for ~1 billion token positions.
30
31#define SENTINEL_TOKEN_DESCRIPTORS(V) \
32 V(NoSource, -1) \
33 V(Box, -2) \
34 V(ParallelMove, -3) \
35 V(TempMove, -4) \
36 V(Constant, -5) \
37 V(PushArgument, -6) \
38 V(ControlFlow, -7) \
39 V(Context, -8) \
40 V(MethodExtractor, -9) \
41 V(DeferredSlowPath, -10) \
42 V(DeferredDeoptInfo, -11) \
43 V(DartCodePrologue, -12) \
44 V(DartCodeEpilogue, -13) \
45 V(Last, -14) // Always keep this at the end.
46
47// A token position representing a debug safe source (real) position,
48// non-debug safe source (synthetic) positions, or a classifying value used
49// by the profiler.
50class TokenPosition {
51 public:
52 TokenPosition() : value_(kNoSource.value()) {}
53
54 explicit TokenPosition(intptr_t value) : value_(value) {}
55
56 bool operator==(const TokenPosition& b) const { return value() == b.value(); }
57
58 bool operator!=(const TokenPosition& b) const { return !(*this == b); }
59
60 bool operator<(const TokenPosition& b) const {
61 // TODO(johnmccutchan): Assert that this is a source position.
62 return value() < b.value();
63 }
64
65 bool operator>(const TokenPosition& b) const {
66 // TODO(johnmccutchan): Assert that this is a source position.
67 return b < *this;
68 }
69
70 bool operator<=(const TokenPosition& b) {
71 // TODO(johnmccutchan): Assert that this is a source position.
72 return !(*this > b);
73 }
74
75 bool operator>=(const TokenPosition& b) {
76 // TODO(johnmccutchan): Assert that this is a source position.
77 return !(*this < b);
78 }
79
80 static const intptr_t kMaxSentinelDescriptors = 64;
81
82#define DECLARE_VALUES(name, value) \
83 static const intptr_t k##name##Pos = value; \
84 static const TokenPosition k##name;
85 SENTINEL_TOKEN_DESCRIPTORS(DECLARE_VALUES);
86#undef DECLARE_VALUES
87 static const intptr_t kMinSourcePos = 0;
88 static const TokenPosition kMinSource;
89 static const intptr_t kMaxSourcePos = kSmiMax32 - kMaxSentinelDescriptors - 2;
90 static const TokenPosition kMaxSource;
91
92 // Decode from a snapshot.
93 static TokenPosition SnapshotDecode(int32_t value);
94
95 // Encode for writing into a snapshot.
96 int32_t SnapshotEncode();
97
98 // Increment the token position.
99 TokenPosition Next() {
100 ASSERT(IsReal());
101 value_++;
102 return *this;
103 }
104
105 // The raw value.
106 // TODO(johnmccutchan): Make this private.
107 intptr_t value() const { return value_; }
108
109 // Return the source position.
110 intptr_t Pos() const {
111 if (IsSynthetic()) {
112 return FromSynthetic().Pos();
113 }
114 return value_;
115 }
116
117 // Is |this| a classifying sentinel source position?
118 // Classifying positions are used by the profiler to group instructions whose
119 // cost isn't naturally attributable to a source location.
120 bool IsClassifying() const {
121 return (value_ >= kBox.value()) && (value_ <= kLast.value());
122 }
123
124 // Is |this| the no source position sentinel?
125 bool IsNoSource() const { return *this == kNoSource; }
126
127 // Is |this| a synthetic source position?
128 // Synthetic source positions are used by the profiler to attribute ticks to a
129 // pieces of source, but ignored by the debugger as potential breakpoints.
130 bool IsSynthetic() const;
131
132 // Is |this| a real source position?
133 bool IsReal() const { return value_ >= kMinSourcePos; }
134
135 // Is |this| a source position?
136 bool IsSourcePosition() const { return IsReal() || IsSynthetic(); }
137
138 // Convert |this| into a real source position. Sentinel values remain
139 // unchanged.
140 TokenPosition SourcePosition() const { return FromSynthetic(); }
141
142 // Is |this| a debug pause source position?
143 bool IsDebugPause() const {
144 // Sanity check some values here.
145 ASSERT(kNoSource.value() == kNoSourcePos);
146 ASSERT(kLast.value() < kNoSource.value());
147 ASSERT(kLast.value() > -kMaxSentinelDescriptors);
148 return IsReal();
149 }
150
151 // Convert |this| into a synthetic source position. Sentinel values remain
152 // unchanged.
153 TokenPosition ToSynthetic() const {
154 const intptr_t value = value_;
155 if (IsClassifying() || IsNoSource()) {
156 return *this;
157 }
158 if (IsSynthetic()) {
159 return *this;
160 }
161 const TokenPosition synthetic_value =
162 TokenPosition((kLast.value() - 1) - value);
163 ASSERT(synthetic_value.IsSynthetic());
164 ASSERT(synthetic_value.value() < kLast.value());
165 return synthetic_value;
166 }
167
168 // Convert |this| from a synthetic source position. Sentinel values remain
169 // unchanged.
170 TokenPosition FromSynthetic() const {
171 const intptr_t synthetic_value = value_;
172 if (IsClassifying() || IsNoSource()) {
173 return *this;
174 }
175 if (!IsSynthetic()) {
176 return *this;
177 }
178 const TokenPosition value =
179 TokenPosition(-synthetic_value + (kLast.value() - 1));
180 ASSERT(!value.IsSynthetic());
181 return value;
182 }
183
184 const char* ToCString() const;
185
186 private:
187 int32_t value_;
188
189 DISALLOW_ALLOCATION();
190};
191
192} // namespace dart
193
194#endif // RUNTIME_VM_TOKEN_POSITION_H_
195