Flutter Engine
The Flutter Engine
evaluator.cc
Go to the documentation of this file.
1// Copyright (c) 2019, 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
6
7namespace dart {
8
9static IntegerPtr BinaryIntegerEvaluateRaw(const Integer& left,
10 const Integer& right,
11 Token::Kind token_kind) {
12 switch (token_kind) {
13 case Token::kTRUNCDIV:
15 case Token::kMOD:
16 // Check right value for zero.
17 if (right.AsInt64Value() == 0) {
18 break; // Will throw.
19 }
21 case Token::kADD:
23 case Token::kSUB:
25 case Token::kMUL:
26 return left.ArithmeticOp(token_kind, right, Heap::kOld);
27 case Token::kSHL:
29 case Token::kSHR:
31 case Token::kUSHR:
32 if (right.AsInt64Value() >= 0) {
33 return left.ShiftOp(token_kind, right, Heap::kOld);
34 }
35 break;
36 case Token::kBIT_AND:
38 case Token::kBIT_OR:
40 case Token::kBIT_XOR:
41 return left.BitOp(token_kind, right, Heap::kOld);
42 case Token::kDIV:
43 break;
44 default:
46 }
47
48 return Integer::null();
49}
50
51static IntegerPtr UnaryIntegerEvaluateRaw(const Integer& value,
52 Token::Kind token_kind,
53 Zone* zone) {
54 switch (token_kind) {
55 case Token::kNEGATE:
56 return value.ArithmeticOp(Token::kMUL, Smi::Handle(zone, Smi::New(-1)),
58 case Token::kBIT_NOT:
59 if (value.IsSmi()) {
60 return Integer::New(~Smi::Cast(value).Value(), Heap::kOld);
61 } else if (value.IsMint()) {
62 return Integer::New(~Mint::Cast(value).value(), Heap::kOld);
63 }
64 break;
65 default:
67 }
68 return Integer::null();
69}
70
71static IntegerPtr BitLengthEvaluateRaw(const Integer& value, Zone* zone) {
72 if (value.IsSmi()) {
73 return Integer::New(Utils::BitLength(Smi::Cast(value).Value()), Heap::kOld);
74 } else if (value.IsMint()) {
75 return Integer::New(Utils::BitLength(Mint::Cast(value).value()),
77 }
78 return Integer::null();
79}
80
82 switch (r) {
83 case kTagged: {
84 const intptr_t kTruncateBits =
85 kBitsPerInt64 - (compiler::target::kSmiBits + 1 /*sign bit*/);
86 return Utils::ShiftLeftWithTruncation(v, kTruncateBits) >> kTruncateBits;
87 }
88 case kUnboxedInt32:
90 case kUnboxedUint32:
91 return v & kMaxUint32;
92 case kUnboxedInt64:
93 return v;
94 default:
96 }
97}
98
100 const Object& right,
101 Token::Kind token_kind,
102 bool is_truncating,
103 Representation representation,
104 Thread* thread) {
105 if (!left.IsInteger() || !right.IsInteger()) {
106 return Integer::null();
107 }
108 Zone* zone = thread->zone();
109 const Integer& left_int = Integer::Cast(left);
110 const Integer& right_int = Integer::Cast(right);
112 zone, BinaryIntegerEvaluateRaw(left_int, right_int, token_kind));
113
114 if (!result.IsNull()) {
115 if (is_truncating) {
116 const int64_t truncated =
117 TruncateTo(result.AsTruncatedInt64Value(), representation);
118 result = Integer::New(truncated, Heap::kOld);
120 result, representation, /*tagged_value_must_be_smi=*/true));
122 result, representation, /*tagged_value_must_be_smi=*/true)) {
123 // If this operation is not truncating it would deoptimize on overflow.
124 // Check that we match this behavior and don't produce a value that is
125 // larger than something this operation can produce. We could have
126 // specialized instructions that use this value under this assumption.
127 return Integer::null();
128 }
129 result ^= result.Canonicalize(thread);
130 }
131
132 return result.ptr();
133}
134
136 Token::Kind token_kind,
137 Representation representation,
138 Thread* thread) {
139 if (!value.IsInteger()) {
140 return Integer::null();
141 }
142 Zone* zone = thread->zone();
143 const Integer& value_int = Integer::Cast(value);
145 zone, UnaryIntegerEvaluateRaw(value_int, token_kind, zone));
146
147 if (!result.IsNull()) {
149 result, representation,
150 /*tagged_value_must_be_smi=*/true)) {
151 // If this operation is not truncating it would deoptimize on overflow.
152 // Check that we match this behavior and don't produce a value that is
153 // larger than something this operation can produce. We could have
154 // specialized instructions that use this value under this assumption.
155 return Integer::null();
156 }
157
158 result ^= result.Canonicalize(thread);
159 }
160
161 return result.ptr();
162}
163
165 Representation representation,
166 Thread* thread) {
167 if (!value.IsInteger()) {
168 return Integer::null();
169 }
170 Zone* zone = thread->zone();
171 const Integer& value_int = Integer::Cast(value);
172 Integer& result =
173 Integer::Handle(zone, BitLengthEvaluateRaw(value_int, zone));
174
175 if (!result.IsNull()) {
177 result, representation,
178 /*tagged_value_must_be_smi=*/true)) {
179 // If this operation is not truncating it would deoptimize on overflow.
180 // Check that we match this behavior and don't produce a value that is
181 // larger than something this operation can produce. We could have
182 // specialized instructions that use this value under this assumption.
183 return Integer::null();
184 }
185
186 result ^= result.Canonicalize(thread);
187 }
188
189 return result.ptr();
190}
191
193 Token::Kind token_kind,
194 Representation representation) {
195 // The different set of operations for float32 and float64 is due to the
196 // different set of operations made available by dart:core.double and
197 // dart:typed_data.Float64x2 versus dart:typed_data.Float32x4.
198 if (representation == kUnboxedDouble) {
199 switch (token_kind) {
200 case Token::kABS:
201 return fabs(value);
202 case Token::kNEGATE:
203 return -value;
204 case Token::kSQRT:
205 return sqrt(value);
206 case Token::kSQUARE:
207 return value * value;
208 case Token::kTRUNCATE:
209 return trunc(value);
210 case Token::kFLOOR:
211 return floor(value);
212 case Token::kCEILING:
213 return ceil(value);
214 default:
215 UNREACHABLE();
216 }
217 } else {
218 ASSERT(representation == kUnboxedFloat);
219 switch (token_kind) {
220 case Token::kABS:
221 return fabsf(static_cast<float>(value));
222 case Token::kNEGATE:
223 return -static_cast<float>(value);
224 case Token::kRECIPROCAL:
225 return 1.0f / static_cast<float>(value);
226 case Token::kRECIPROCAL_SQRT:
227 return sqrtf(1.0f / static_cast<float>(value));
228 case Token::kSQRT:
229 return sqrtf(static_cast<float>(value));
230 case Token::kSQUARE:
231 return static_cast<float>(value) * static_cast<float>(value);
232 default:
233 UNREACHABLE();
234 }
235 }
236}
237
238double Evaluator::EvaluateBinaryDoubleOp(const double left,
239 const double right,
240 Token::Kind token_kind,
241 Representation representation) {
242 if (representation == kUnboxedDouble) {
243 switch (token_kind) {
244 case Token::kADD:
245 return left + right;
246 case Token::kSUB:
247 return left - right;
248 case Token::kMUL:
249 return left * right;
250 case Token::kDIV:
251 return Utils::DivideAllowZero(left, right);
252 case Token::kMIN:
253 return fmin(left, right);
254 case Token::kMAX:
255 return fmax(left, right);
256 default:
257 UNREACHABLE();
258 }
259 } else {
260 ASSERT(representation == kUnboxedFloat);
261 switch (token_kind) {
262 case Token::kADD:
263 return static_cast<float>(left) + static_cast<float>(right);
264 case Token::kSUB:
265 return static_cast<float>(left) - static_cast<float>(right);
266 case Token::kMUL:
267 return static_cast<float>(left) * static_cast<float>(right);
268 case Token::kDIV:
269 return Utils::DivideAllowZero(static_cast<float>(left),
270 static_cast<float>(right));
271 case Token::kMIN:
272 return fminf(static_cast<float>(left), static_cast<float>(right));
273 case Token::kMAX:
274 return fmaxf(static_cast<float>(left), static_cast<float>(right));
275 default:
276 UNREACHABLE();
277 }
278 }
279}
280
282 if (!value->BindsToConstant()) {
283 UnboxInstr* unbox = value->definition()->AsUnbox();
284 if (unbox != nullptr) {
285 switch (unbox->representation()) {
286 case kUnboxedDouble:
287 case kUnboxedInt64:
288 return ToIntegerConstant(unbox->value(), result);
289 case kUnboxedUint32:
290 if (ToIntegerConstant(unbox->value(), result)) {
291 *result = Evaluator::TruncateTo(*result, kUnboxedUint32);
292 return true;
293 }
294 break;
295 // No need to handle Unbox<Int32>(Constant(C)) because it gets
296 // canonicalized to UnboxedConstant<Int32>(C).
297 case kUnboxedInt32:
298 default:
299 break;
300 }
301 }
302 return false;
303 }
304 const Object& constant = value->BoundConstant();
305 if (constant.IsDouble()) {
306 const Double& double_constant = Double::Cast(constant);
307 *result = Utils::SafeDoubleToInt<int64_t>(double_constant.value());
308 return (static_cast<double>(*result) == double_constant.value());
309 } else if (constant.IsSmi()) {
310 *result = Smi::Cast(constant).Value();
311 return true;
312 } else if (constant.IsMint()) {
313 *result = Mint::Cast(constant).value();
314 return true;
315 }
316 return false;
317}
318
319} // namespace dart
#define UNREACHABLE()
Definition: assert.h:248
double value() const
Definition: object.h:10115
static int64_t TruncateTo(int64_t v, Representation r)
Definition: evaluator.cc:81
static IntegerPtr BitLengthEvaluate(const Object &value, Representation representation, Thread *thread)
Definition: evaluator.cc:164
static double EvaluateUnaryDoubleOp(const double value, Token::Kind token_kind, Representation representation)
Definition: evaluator.cc:192
static IntegerPtr UnaryIntegerEvaluate(const Object &value, Token::Kind token_kind, Representation representation, Thread *thread)
Definition: evaluator.cc:135
static IntegerPtr BinaryIntegerEvaluate(const Object &left, const Object &right, Token::Kind token_kind, bool is_truncating, Representation representation, Thread *thread)
Definition: evaluator.cc:99
static double EvaluateBinaryDoubleOp(const double left, const double right, Token::Kind token_kind, Representation representation)
Definition: evaluator.cc:238
static bool ToIntegerConstant(Value *value, int64_t *result)
Definition: evaluator.cc:281
static bool IsConstantRepresentable(const Object &value, Representation target_rep, bool tagged_value_must_be_smi)
Definition: flow_graph.cc:205
@ kOld
Definition: heap.h:39
static IntegerPtr New(const String &str, Heap::Space space=Heap::kNew)
Definition: object.cc:22984
static ObjectPtr null()
Definition: object.h:433
static Object & Handle()
Definition: object.h:407
static SmiPtr New(intptr_t value)
Definition: object.h:10006
Zone * zone() const
Definition: thread_state.h:37
virtual Representation representation() const
Definition: il.h:8703
Value * value() const
Definition: il.h:8678
static constexpr size_t BitLength(int64_t value)
Definition: utils.h:213
static float DivideAllowZero(float a, float b)
Definition: utils.h:496
static int64_t ShiftLeftWithTruncation(int64_t a, int64_t b)
Definition: utils.h:464
Definition: il.h:75
#define ASSERT(E)
uint8_t value
GAsyncResult * result
constexpr intptr_t kSmiBits
Definition: runtime_api.h:301
Definition: dart_vm.cc:33
static IntegerPtr BinaryIntegerEvaluateRaw(const Integer &left, const Integer &right, Token::Kind token_kind)
Definition: evaluator.cc:9
Representation
Definition: locations.h:66
constexpr uint32_t kMaxUint32
Definition: globals.h:484
static IntegerPtr BitLengthEvaluateRaw(const Integer &value, Zone *zone)
Definition: evaluator.cc:71
constexpr intptr_t kBitsPerInt32
Definition: globals.h:466
static IntegerPtr UnaryIntegerEvaluateRaw(const Integer &value, Token::Kind token_kind, Zone *zone)
Definition: evaluator.cc:51
constexpr intptr_t kBitsPerInt64
Definition: globals.h:467
SIN Vec< N, float > trunc(const Vec< N, float > &x)
Definition: SkVx.h:704
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition: SkVx.h:706
SIN Vec< N, float > floor(const Vec< N, float > &x)
Definition: SkVx.h:703
SIN Vec< N, float > ceil(const Vec< N, float > &x)
Definition: SkVx.h:702
#define FALL_THROUGH
Definition: globals.h:15