v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
unary-op-assembler.cc
Go to the documentation of this file.
1// Copyright 2020 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
6
8#include "torque-generated/src/objects/oddball-tq-csa.h"
9
10namespace v8 {
11namespace internal {
12
14
15namespace {
16
17class UnaryOpAssemblerImpl final : public CodeStubAssembler {
18 public:
19 explicit UnaryOpAssemblerImpl(compiler::CodeAssemblerState* state)
20 : CodeStubAssembler(state) {}
21
22 TNode<Object> BitwiseNot(TNode<Context> context, TNode<Object> value,
23 TNode<UintPtrT> slot,
24 TNode<HeapObject> maybe_feedback_vector,
25 UpdateFeedbackMode update_feedback_mode) {
26 // TODO(jgruber): Make this implementation more consistent with other unary
27 // ops (i.e. have them all use UnaryOpWithFeedback or some other common
28 // mechanism).
29 TVARIABLE(Word32T, var_word32);
30 TVARIABLE(Smi, var_feedback);
31 TVARIABLE(BigInt, var_bigint);
32 TVARIABLE(Object, var_result);
33 Label if_number(this), if_bigint(this, Label::kDeferred), out(this);
34 LazyNode<HeapObject> get_vector = [&]() { return maybe_feedback_vector; };
35 FeedbackValues feedback = {&var_feedback, &get_vector, &slot,
36 update_feedback_mode};
37 TaggedToWord32OrBigIntWithFeedback(context, value, &if_number, &var_word32,
38 &if_bigint, nullptr, &var_bigint,
39 feedback);
40
41 // Number case.
42 BIND(&if_number);
43 var_result =
44 ChangeInt32ToTagged(Signed(Word32BitwiseNot(var_word32.value())));
45 TNode<Smi> result_type = SelectSmiConstant(
46 TaggedIsSmi(var_result.value()), BinaryOperationFeedback::kSignedSmall,
48 UpdateFeedback(SmiOr(result_type, var_feedback.value()),
49 maybe_feedback_vector, slot, update_feedback_mode);
50 Goto(&out);
51
52 // BigInt case.
53 BIND(&if_bigint);
54 UpdateFeedback(SmiConstant(BinaryOperationFeedback::kBigInt),
55 maybe_feedback_vector, slot, update_feedback_mode);
56 var_result =
57 CallRuntime(Runtime::kBigIntUnaryOp, context, var_bigint.value(),
58 SmiConstant(Operation::kBitwiseNot));
59 Goto(&out);
60
61 BIND(&out);
62 return var_result.value();
63 }
64
65 TNode<Object> Decrement(TNode<Context> context, TNode<Object> value,
66 TNode<UintPtrT> slot,
67 TNode<HeapObject> maybe_feedback_vector,
68 UpdateFeedbackMode update_feedback_mode) {
69 return IncrementOrDecrement<Operation::kDecrement>(
70 context, value, slot, maybe_feedback_vector, update_feedback_mode);
71 }
72
73 TNode<Object> Increment(TNode<Context> context, TNode<Object> value,
74 TNode<UintPtrT> slot,
75 TNode<HeapObject> maybe_feedback_vector,
76 UpdateFeedbackMode update_feedback_mode) {
77 return IncrementOrDecrement<Operation::kIncrement>(
78 context, value, slot, maybe_feedback_vector, update_feedback_mode);
79 }
80
81 TNode<Object> Negate(TNode<Context> context, TNode<Object> value,
82 TNode<UintPtrT> slot,
83 TNode<HeapObject> maybe_feedback_vector,
84 UpdateFeedbackMode update_feedback_mode) {
85 SmiOperation smi_op =
86 [=, this](TNode<Smi> smi_value, TVariable<Smi>* var_feedback,
87 Label* do_float_op, TVariable<Float64T>* var_float) {
88 TVARIABLE(Number, var_result);
89 Label if_zero(this), if_min_smi(this), end(this);
90 // Return -0 if operand is 0.
91 GotoIf(SmiEqual(smi_value, SmiConstant(0)), &if_zero);
92
93 // Special-case the minimum Smi to avoid overflow.
94 GotoIf(SmiEqual(smi_value, SmiConstant(Smi::kMinValue)), &if_min_smi);
95
96 // Else simply subtract operand from 0.
97 CombineFeedback(var_feedback, BinaryOperationFeedback::kSignedSmall);
98 var_result = SmiSub(SmiConstant(0), smi_value);
99 Goto(&end);
100
101 BIND(&if_zero);
102 CombineFeedback(var_feedback, BinaryOperationFeedback::kNumber);
103 var_result = MinusZeroConstant();
104 Goto(&end);
105
106 BIND(&if_min_smi);
107 *var_float = SmiToFloat64(smi_value);
108 Goto(do_float_op);
109
110 BIND(&end);
111 return var_result.value();
112 };
113 FloatOperation float_op = [=, this](TNode<Float64T> float_value) {
114 return Float64Neg(float_value);
115 };
116 BigIntOperation bigint_op = [=, this](TNode<Context> context,
117 TNode<HeapObject> bigint_value) {
118 return CAST(CallRuntime(Runtime::kBigIntUnaryOp, context, bigint_value,
119 SmiConstant(Operation::kNegate)));
120 };
121 return UnaryOpWithFeedback(context, value, slot, maybe_feedback_vector,
122 smi_op, float_op, bigint_op,
123 update_feedback_mode);
124 }
125
126 private:
127 using SmiOperation = std::function<TNode<Number>(
128 TNode<Smi> /* smi_value */, TVariable<Smi>* /* var_feedback */,
129 Label* /* do_float_op */, TVariable<Float64T>* /* var_float */)>;
130 using FloatOperation =
131 std::function<TNode<Float64T>(TNode<Float64T> /* float_value */)>;
132 using BigIntOperation = std::function<TNode<HeapObject>(
133 TNode<Context> /* context */, TNode<HeapObject> /* bigint_value */)>;
134
135 TNode<Object> UnaryOpWithFeedback(TNode<Context> context, TNode<Object> value,
136 TNode<UintPtrT> slot,
137 TNode<HeapObject> maybe_feedback_vector,
138 const SmiOperation& smi_op,
139 const FloatOperation& float_op,
140 const BigIntOperation& bigint_op,
141 UpdateFeedbackMode update_feedback_mode) {
142 TVARIABLE(Object, var_value, value);
143 TVARIABLE(Object, var_result);
144 TVARIABLE(Float64T, var_float_value);
145 TVARIABLE(Smi, var_feedback, SmiConstant(BinaryOperationFeedback::kNone));
146 TVARIABLE(Object, var_exception);
147 Label start(this, {&var_value, &var_feedback}), end(this);
148 Label do_float_op(this, &var_float_value);
149 Label if_exception(this, Label::kDeferred);
150 Goto(&start);
151 // We might have to try again after ToNumeric conversion.
152 BIND(&start);
153 {
154 Label if_smi(this), if_heapnumber(this), if_oddball(this);
155 Label if_bigint(this, Label::kDeferred);
156 Label if_other(this, Label::kDeferred);
157 value = var_value.value();
158 GotoIf(TaggedIsSmi(value), &if_smi);
159
160 TNode<HeapObject> value_heap_object = CAST(value);
161 TNode<Map> map = LoadMap(value_heap_object);
162 GotoIf(IsHeapNumberMap(map), &if_heapnumber);
163 TNode<Uint16T> instance_type = LoadMapInstanceType(map);
164 GotoIf(IsBigIntInstanceType(instance_type), &if_bigint);
165 Branch(InstanceTypeEqual(instance_type, ODDBALL_TYPE), &if_oddball,
166 &if_other);
167
168 BIND(&if_smi);
169 {
170 var_result =
171 smi_op(CAST(value), &var_feedback, &do_float_op, &var_float_value);
172 Goto(&end);
173 }
174
175 BIND(&if_heapnumber);
176 {
177 var_float_value = LoadHeapNumberValue(value_heap_object);
178 Goto(&do_float_op);
179 }
180
181 BIND(&if_bigint);
182 {
183 var_result = bigint_op(context, value_heap_object);
184 CombineFeedback(&var_feedback, BinaryOperationFeedback::kBigInt);
185 Goto(&end);
186 }
187
188 BIND(&if_oddball);
189 {
190 // We do not require an Or with earlier feedback here because once we
191 // convert the value to a number, we cannot reach this path. We can
192 // only reach this path on the first pass when the feedback is kNone.
193 CSA_DCHECK(this, SmiEqual(var_feedback.value(),
194 SmiConstant(BinaryOperationFeedback::kNone)));
195 OverwriteFeedback(&var_feedback,
197 var_value = LoadOddballToNumber(CAST(value_heap_object));
198 Goto(&start);
199 }
200
201 BIND(&if_other);
202 {
203 // We do not require an Or with earlier feedback here because once we
204 // convert the value to a number, we cannot reach this path. We can
205 // only reach this path on the first pass when the feedback is kNone.
206 CSA_DCHECK(this, SmiEqual(var_feedback.value(),
207 SmiConstant(BinaryOperationFeedback::kNone)));
208 OverwriteFeedback(&var_feedback, BinaryOperationFeedback::kAny);
209 {
210 ScopedExceptionHandler handler(this, &if_exception, &var_exception);
211 var_value = CallBuiltin(Builtin::kNonNumberToNumeric, context,
212 value_heap_object);
213 }
214 Goto(&start);
215 }
216 }
217
218 BIND(&if_exception);
219 {
220 UpdateFeedback(var_feedback.value(), maybe_feedback_vector, slot,
221 update_feedback_mode);
222 CallRuntime(Runtime::kReThrow, context, var_exception.value());
223 Unreachable();
224 }
225
226 BIND(&do_float_op);
227 {
228 CombineFeedback(&var_feedback, BinaryOperationFeedback::kNumber);
229 var_result =
230 AllocateHeapNumberWithValue(float_op(var_float_value.value()));
231 Goto(&end);
232 }
233
234 BIND(&end);
235 UpdateFeedback(var_feedback.value(), maybe_feedback_vector, slot,
236 update_feedback_mode);
237 return var_result.value();
238 }
239
240 template <Operation kOperation>
241 TNode<Object> IncrementOrDecrement(TNode<Context> context,
242 TNode<Object> value, TNode<UintPtrT> slot,
243 TNode<HeapObject> maybe_feedback_vector,
244 UpdateFeedbackMode update_feedback_mode) {
245 static_assert(kOperation == Operation::kIncrement ||
246 kOperation == Operation::kDecrement);
247 static constexpr int kAddValue =
248 (kOperation == Operation::kIncrement) ? 1 : -1;
249
250 SmiOperation smi_op = [=, this](TNode<Smi> smi_value,
251 TVariable<Smi>* var_feedback,
252 Label* do_float_op,
253 TVariable<Float64T>* var_float) {
254 Label if_overflow(this), out(this);
255 TNode<Smi> result =
256 TrySmiAdd(smi_value, SmiConstant(kAddValue), &if_overflow);
257 CombineFeedback(var_feedback, BinaryOperationFeedback::kSignedSmall);
258 Goto(&out);
259
260 BIND(&if_overflow);
261 *var_float = SmiToFloat64(smi_value);
262 Goto(do_float_op);
263
264 BIND(&out);
265 return result;
266 };
267 FloatOperation float_op = [=, this](TNode<Float64T> float_value) {
268 return Float64Add(float_value, Float64Constant(kAddValue));
269 };
270 BigIntOperation bigint_op = [=, this](TNode<Context> context,
271 TNode<HeapObject> bigint_value) {
272 return CAST(CallRuntime(Runtime::kBigIntUnaryOp, context, bigint_value,
273 SmiConstant(kOperation)));
274 };
275 return UnaryOpWithFeedback(context, value, slot, maybe_feedback_vector,
276 smi_op, float_op, bigint_op,
277 update_feedback_mode);
278 }
279};
280
281} // namespace
282
284 TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
285 TNode<HeapObject> maybe_feedback_vector,
286 UpdateFeedbackMode update_feedback_mode) {
287 UnaryOpAssemblerImpl a(state_);
288 return a.BitwiseNot(context, value, slot, maybe_feedback_vector,
289 update_feedback_mode);
290}
291
293 TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
294 TNode<HeapObject> maybe_feedback_vector,
295 UpdateFeedbackMode update_feedback_mode) {
296 UnaryOpAssemblerImpl a(state_);
297 return a.Decrement(context, value, slot, maybe_feedback_vector,
298 update_feedback_mode);
299}
300
302 TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
303 TNode<HeapObject> maybe_feedback_vector,
304 UpdateFeedbackMode update_feedback_mode) {
305 UnaryOpAssemblerImpl a(state_);
306 return a.Increment(context, value, slot, maybe_feedback_vector,
307 update_feedback_mode);
308}
309
311 TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
312 TNode<HeapObject> maybe_feedback_vector,
313 UpdateFeedbackMode update_feedback_mode) {
314 UnaryOpAssemblerImpl a(state_);
315 return a.Negate(context, value, slot, maybe_feedback_vector,
316 update_feedback_mode);
317}
318
320
321} // namespace internal
322} // namespace v8
#define BIND(label)
#define TVARIABLE(...)
#define CSA_DCHECK(csa,...)
static constexpr int kMinValue
Definition smi.h:100
TNode< Object > Generate_IncrementWithFeedback(TNode< Context > context, TNode< Object > value, TNode< UintPtrT > slot, TNode< HeapObject > maybe_feedback_vector, UpdateFeedbackMode update_feedback_mode)
TNode< Object > Generate_DecrementWithFeedback(TNode< Context > context, TNode< Object > value, TNode< UintPtrT > slot, TNode< HeapObject > maybe_feedback_vector, UpdateFeedbackMode update_feedback_mode)
compiler::CodeAssemblerState *const state_
TNode< Object > Generate_NegateWithFeedback(TNode< Context > context, TNode< Object > value, TNode< UintPtrT > slot, TNode< HeapObject > maybe_feedback_vector, UpdateFeedbackMode update_feedback_mode)
TNode< Object > Generate_BitwiseNotWithFeedback(TNode< Context > context, TNode< Object > value, TNode< UintPtrT > slot, TNode< HeapObject > maybe_feedback_vector, UpdateFeedbackMode update_feedback_mode)
#define CAST(x)
int start
int end
TNode< Context > context
std::optional< TNode< JSArray > > a
ZoneVector< RpoNumber > & result
MovableLabel handler
constexpr std::make_signed_t< T > Signed(T value)
Definition bits.h:91
TNode< Float64T > Float64Add(TNode< Float64T > a, TNode< Float64T > b)
constexpr Condition Negate(Condition cond)
compiler::TypedCodeAssemblerVariable< T > TVariable
Union< Smi, HeapNumber > Number
Definition globals.h:1181