V8 Project
machine-operator-reducer.cc
Go to the documentation of this file.
1 // Copyright 2014 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 
7 #include "src/base/bits.h"
9 #include "src/compiler/graph.h"
10 #include "src/compiler/js-graph.h"
12 
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16 
17 MachineOperatorReducer::MachineOperatorReducer(JSGraph* jsgraph)
18  : jsgraph_(jsgraph) {}
19 
20 
21 MachineOperatorReducer::~MachineOperatorReducer() {}
22 
23 
24 Node* MachineOperatorReducer::Float32Constant(volatile float value) {
25  return graph()->NewNode(common()->Float32Constant(value));
26 }
27 
28 
29 Node* MachineOperatorReducer::Float64Constant(volatile double value) {
30  return jsgraph()->Float64Constant(value);
31 }
32 
33 
34 Node* MachineOperatorReducer::Int32Constant(int32_t value) {
35  return jsgraph()->Int32Constant(value);
36 }
37 
38 
39 Node* MachineOperatorReducer::Int64Constant(int64_t value) {
40  return graph()->NewNode(common()->Int64Constant(value));
41 }
42 
43 
44 // Perform constant folding and strength reduction on machine operators.
45 Reduction MachineOperatorReducer::Reduce(Node* node) {
46  switch (node->opcode()) {
47  case IrOpcode::kProjection:
48  return ReduceProjection(OpParameter<size_t>(node), node->InputAt(0));
49  case IrOpcode::kWord32And: {
50  Int32BinopMatcher m(node);
51  if (m.right().Is(0)) return Replace(m.right().node()); // x & 0 => 0
52  if (m.right().Is(-1)) return Replace(m.left().node()); // x & -1 => x
53  if (m.IsFoldable()) { // K & K => K
54  return ReplaceInt32(m.left().Value() & m.right().Value());
55  }
56  if (m.LeftEqualsRight()) return Replace(m.left().node()); // x & x => x
57  break;
58  }
59  case IrOpcode::kWord32Or: {
60  Int32BinopMatcher m(node);
61  if (m.right().Is(0)) return Replace(m.left().node()); // x | 0 => x
62  if (m.right().Is(-1)) return Replace(m.right().node()); // x | -1 => -1
63  if (m.IsFoldable()) { // K | K => K
64  return ReplaceInt32(m.left().Value() | m.right().Value());
65  }
66  if (m.LeftEqualsRight()) return Replace(m.left().node()); // x | x => x
67  if (m.left().IsWord32Shl() && m.right().IsWord32Shr()) {
68  Int32BinopMatcher mleft(m.left().node());
69  Int32BinopMatcher mright(m.right().node());
70  if (mleft.left().node() == mright.left().node()) {
71  // (x << y) | (x >> (32 - y)) => x ror y
72  if (mright.right().IsInt32Sub()) {
73  Int32BinopMatcher mrightright(mright.right().node());
74  if (mrightright.left().Is(32) &&
75  mrightright.right().node() == mleft.right().node()) {
76  node->set_op(machine()->Word32Ror());
77  node->ReplaceInput(0, mleft.left().node());
78  node->ReplaceInput(1, mleft.right().node());
79  return Changed(node);
80  }
81  }
82  // (x << K) | (x >> (32 - K)) => x ror K
83  if (mleft.right().IsInRange(0, 31) &&
84  mright.right().Is(32 - mleft.right().Value())) {
85  node->set_op(machine()->Word32Ror());
86  node->ReplaceInput(0, mleft.left().node());
87  node->ReplaceInput(1, mleft.right().node());
88  return Changed(node);
89  }
90  }
91  }
92  if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) {
93  // (x >> (32 - y)) | (x << y) => x ror y
94  Int32BinopMatcher mleft(m.left().node());
95  Int32BinopMatcher mright(m.right().node());
96  if (mleft.left().node() == mright.left().node()) {
97  if (mleft.right().IsInt32Sub()) {
98  Int32BinopMatcher mleftright(mleft.right().node());
99  if (mleftright.left().Is(32) &&
100  mleftright.right().node() == mright.right().node()) {
101  node->set_op(machine()->Word32Ror());
102  node->ReplaceInput(0, mright.left().node());
103  node->ReplaceInput(1, mright.right().node());
104  return Changed(node);
105  }
106  }
107  // (x >> (32 - K)) | (x << K) => x ror K
108  if (mright.right().IsInRange(0, 31) &&
109  mleft.right().Is(32 - mright.right().Value())) {
110  node->set_op(machine()->Word32Ror());
111  node->ReplaceInput(0, mright.left().node());
112  node->ReplaceInput(1, mright.right().node());
113  return Changed(node);
114  }
115  }
116  }
117  break;
118  }
119  case IrOpcode::kWord32Xor: {
120  Int32BinopMatcher m(node);
121  if (m.right().Is(0)) return Replace(m.left().node()); // x ^ 0 => x
122  if (m.IsFoldable()) { // K ^ K => K
123  return ReplaceInt32(m.left().Value() ^ m.right().Value());
124  }
125  if (m.LeftEqualsRight()) return ReplaceInt32(0); // x ^ x => 0
126  break;
127  }
128  case IrOpcode::kWord32Shl: {
129  Int32BinopMatcher m(node);
130  if (m.right().Is(0)) return Replace(m.left().node()); // x << 0 => x
131  if (m.IsFoldable()) { // K << K => K
132  return ReplaceInt32(m.left().Value() << m.right().Value());
133  }
134  if (m.right().IsInRange(1, 31)) {
135  // (x >>> K) << K => x & ~(2^K - 1)
136  // (x >> K) << K => x & ~(2^K - 1)
137  if (m.left().IsWord32Sar() || m.left().IsWord32Shr()) {
138  Int32BinopMatcher mleft(m.left().node());
139  if (mleft.right().Is(m.right().Value())) {
140  node->set_op(machine()->Word32And());
141  node->ReplaceInput(0, mleft.left().node());
142  node->ReplaceInput(
143  1, Uint32Constant(~((1U << m.right().Value()) - 1U)));
144  return Changed(node);
145  }
146  }
147  }
148  break;
149  }
150  case IrOpcode::kWord32Shr: {
151  Uint32BinopMatcher m(node);
152  if (m.right().Is(0)) return Replace(m.left().node()); // x >>> 0 => x
153  if (m.IsFoldable()) { // K >>> K => K
154  return ReplaceInt32(m.left().Value() >> m.right().Value());
155  }
156  break;
157  }
158  case IrOpcode::kWord32Sar: {
159  Int32BinopMatcher m(node);
160  if (m.right().Is(0)) return Replace(m.left().node()); // x >> 0 => x
161  if (m.IsFoldable()) { // K >> K => K
162  return ReplaceInt32(m.left().Value() >> m.right().Value());
163  }
164  break;
165  }
166  case IrOpcode::kWord32Ror: {
167  Int32BinopMatcher m(node);
168  if (m.right().Is(0)) return Replace(m.left().node()); // x ror 0 => x
169  if (m.IsFoldable()) { // K ror K => K
170  return ReplaceInt32(
171  base::bits::RotateRight32(m.left().Value(), m.right().Value()));
172  }
173  break;
174  }
175  case IrOpcode::kWord32Equal: {
176  Int32BinopMatcher m(node);
177  if (m.IsFoldable()) { // K == K => K
178  return ReplaceBool(m.left().Value() == m.right().Value());
179  }
180  if (m.left().IsInt32Sub() && m.right().Is(0)) { // x - y == 0 => x == y
181  Int32BinopMatcher msub(m.left().node());
182  node->ReplaceInput(0, msub.left().node());
183  node->ReplaceInput(1, msub.right().node());
184  return Changed(node);
185  }
186  // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares
187  if (m.LeftEqualsRight()) return ReplaceBool(true); // x == x => true
188  break;
189  }
190  case IrOpcode::kInt32Add: {
191  Int32BinopMatcher m(node);
192  if (m.right().Is(0)) return Replace(m.left().node()); // x + 0 => x
193  if (m.IsFoldable()) { // K + K => K
194  return ReplaceInt32(static_cast<uint32_t>(m.left().Value()) +
195  static_cast<uint32_t>(m.right().Value()));
196  }
197  break;
198  }
199  case IrOpcode::kInt32Sub: {
200  Int32BinopMatcher m(node);
201  if (m.right().Is(0)) return Replace(m.left().node()); // x - 0 => x
202  if (m.IsFoldable()) { // K - K => K
203  return ReplaceInt32(static_cast<uint32_t>(m.left().Value()) -
204  static_cast<uint32_t>(m.right().Value()));
205  }
206  if (m.LeftEqualsRight()) return ReplaceInt32(0); // x - x => 0
207  break;
208  }
209  case IrOpcode::kInt32Mul: {
210  Int32BinopMatcher m(node);
211  if (m.right().Is(0)) return Replace(m.right().node()); // x * 0 => 0
212  if (m.right().Is(1)) return Replace(m.left().node()); // x * 1 => x
213  if (m.IsFoldable()) { // K * K => K
214  return ReplaceInt32(m.left().Value() * m.right().Value());
215  }
216  if (m.right().Is(-1)) { // x * -1 => 0 - x
217  node->set_op(machine()->Int32Sub());
218  node->ReplaceInput(0, Int32Constant(0));
219  node->ReplaceInput(1, m.left().node());
220  return Changed(node);
221  }
222  if (m.right().IsPowerOf2()) { // x * 2^n => x << n
223  node->set_op(machine()->Word32Shl());
224  node->ReplaceInput(1, Int32Constant(WhichPowerOf2(m.right().Value())));
225  return Changed(node);
226  }
227  break;
228  }
229  case IrOpcode::kInt32Div: {
230  Int32BinopMatcher m(node);
231  if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x
232  // TODO(turbofan): if (m.left().Is(0))
233  // TODO(turbofan): if (m.right().IsPowerOf2())
234  // TODO(turbofan): if (m.right().Is(0))
235  // TODO(turbofan): if (m.LeftEqualsRight())
236  if (m.IsFoldable() && !m.right().Is(0)) { // K / K => K
237  if (m.right().Is(-1)) return ReplaceInt32(-m.left().Value());
238  return ReplaceInt32(m.left().Value() / m.right().Value());
239  }
240  if (m.right().Is(-1)) { // x / -1 => 0 - x
241  node->set_op(machine()->Int32Sub());
242  node->ReplaceInput(0, Int32Constant(0));
243  node->ReplaceInput(1, m.left().node());
244  return Changed(node);
245  }
246  break;
247  }
248  case IrOpcode::kInt32UDiv: {
249  Uint32BinopMatcher m(node);
250  if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x
251  // TODO(turbofan): if (m.left().Is(0))
252  // TODO(turbofan): if (m.right().Is(0))
253  // TODO(turbofan): if (m.LeftEqualsRight())
254  if (m.IsFoldable() && !m.right().Is(0)) { // K / K => K
255  return ReplaceInt32(m.left().Value() / m.right().Value());
256  }
257  if (m.right().IsPowerOf2()) { // x / 2^n => x >> n
258  node->set_op(machine()->Word32Shr());
259  node->ReplaceInput(1, Int32Constant(WhichPowerOf2(m.right().Value())));
260  return Changed(node);
261  }
262  break;
263  }
264  case IrOpcode::kInt32Mod: {
265  Int32BinopMatcher m(node);
266  if (m.right().Is(1)) return ReplaceInt32(0); // x % 1 => 0
267  if (m.right().Is(-1)) return ReplaceInt32(0); // x % -1 => 0
268  // TODO(turbofan): if (m.left().Is(0))
269  // TODO(turbofan): if (m.right().IsPowerOf2())
270  // TODO(turbofan): if (m.right().Is(0))
271  // TODO(turbofan): if (m.LeftEqualsRight())
272  if (m.IsFoldable() && !m.right().Is(0)) { // K % K => K
273  return ReplaceInt32(m.left().Value() % m.right().Value());
274  }
275  break;
276  }
277  case IrOpcode::kInt32UMod: {
278  Uint32BinopMatcher m(node);
279  if (m.right().Is(1)) return ReplaceInt32(0); // x % 1 => 0
280  // TODO(turbofan): if (m.left().Is(0))
281  // TODO(turbofan): if (m.right().Is(0))
282  // TODO(turbofan): if (m.LeftEqualsRight())
283  if (m.IsFoldable() && !m.right().Is(0)) { // K % K => K
284  return ReplaceInt32(m.left().Value() % m.right().Value());
285  }
286  if (m.right().IsPowerOf2()) { // x % 2^n => x & 2^n-1
287  node->set_op(machine()->Word32And());
288  node->ReplaceInput(1, Int32Constant(m.right().Value() - 1));
289  return Changed(node);
290  }
291  break;
292  }
293  case IrOpcode::kInt32LessThan: {
294  Int32BinopMatcher m(node);
295  if (m.IsFoldable()) { // K < K => K
296  return ReplaceBool(m.left().Value() < m.right().Value());
297  }
298  if (m.left().IsInt32Sub() && m.right().Is(0)) { // x - y < 0 => x < y
299  Int32BinopMatcher msub(m.left().node());
300  node->ReplaceInput(0, msub.left().node());
301  node->ReplaceInput(1, msub.right().node());
302  return Changed(node);
303  }
304  if (m.left().Is(0) && m.right().IsInt32Sub()) { // 0 < x - y => y < x
305  Int32BinopMatcher msub(m.right().node());
306  node->ReplaceInput(0, msub.right().node());
307  node->ReplaceInput(1, msub.left().node());
308  return Changed(node);
309  }
310  if (m.LeftEqualsRight()) return ReplaceBool(false); // x < x => false
311  break;
312  }
313  case IrOpcode::kInt32LessThanOrEqual: {
314  Int32BinopMatcher m(node);
315  if (m.IsFoldable()) { // K <= K => K
316  return ReplaceBool(m.left().Value() <= m.right().Value());
317  }
318  if (m.left().IsInt32Sub() && m.right().Is(0)) { // x - y <= 0 => x <= y
319  Int32BinopMatcher msub(m.left().node());
320  node->ReplaceInput(0, msub.left().node());
321  node->ReplaceInput(1, msub.right().node());
322  return Changed(node);
323  }
324  if (m.left().Is(0) && m.right().IsInt32Sub()) { // 0 <= x - y => y <= x
325  Int32BinopMatcher msub(m.right().node());
326  node->ReplaceInput(0, msub.right().node());
327  node->ReplaceInput(1, msub.left().node());
328  return Changed(node);
329  }
330  if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true
331  break;
332  }
333  case IrOpcode::kUint32LessThan: {
334  Uint32BinopMatcher m(node);
335  if (m.left().Is(kMaxUInt32)) return ReplaceBool(false); // M < x => false
336  if (m.right().Is(0)) return ReplaceBool(false); // x < 0 => false
337  if (m.IsFoldable()) { // K < K => K
338  return ReplaceBool(m.left().Value() < m.right().Value());
339  }
340  if (m.LeftEqualsRight()) return ReplaceBool(false); // x < x => false
341  break;
342  }
343  case IrOpcode::kUint32LessThanOrEqual: {
344  Uint32BinopMatcher m(node);
345  if (m.left().Is(0)) return ReplaceBool(true); // 0 <= x => true
346  if (m.right().Is(kMaxUInt32)) return ReplaceBool(true); // x <= M => true
347  if (m.IsFoldable()) { // K <= K => K
348  return ReplaceBool(m.left().Value() <= m.right().Value());
349  }
350  if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true
351  break;
352  }
353  case IrOpcode::kFloat64Add: {
354  Float64BinopMatcher m(node);
355  if (m.right().IsNaN()) { // x + NaN => NaN
356  return Replace(m.right().node());
357  }
358  if (m.IsFoldable()) { // K + K => K
359  return ReplaceFloat64(m.left().Value() + m.right().Value());
360  }
361  break;
362  }
363  case IrOpcode::kFloat64Sub: {
364  Float64BinopMatcher m(node);
365  if (m.right().Is(0) && (Double(m.right().Value()).Sign() > 0)) {
366  return Replace(m.left().node()); // x - 0 => x
367  }
368  if (m.right().IsNaN()) { // x - NaN => NaN
369  return Replace(m.right().node());
370  }
371  if (m.left().IsNaN()) { // NaN - x => NaN
372  return Replace(m.left().node());
373  }
374  if (m.IsFoldable()) { // K - K => K
375  return ReplaceFloat64(m.left().Value() - m.right().Value());
376  }
377  break;
378  }
379  case IrOpcode::kFloat64Mul: {
380  Float64BinopMatcher m(node);
381  if (m.right().Is(1)) return Replace(m.left().node()); // x * 1.0 => x
382  if (m.right().IsNaN()) { // x * NaN => NaN
383  return Replace(m.right().node());
384  }
385  if (m.IsFoldable()) { // K * K => K
386  return ReplaceFloat64(m.left().Value() * m.right().Value());
387  }
388  break;
389  }
390  case IrOpcode::kFloat64Div: {
391  Float64BinopMatcher m(node);
392  if (m.right().Is(1)) return Replace(m.left().node()); // x / 1.0 => x
393  if (m.right().IsNaN()) { // x / NaN => NaN
394  return Replace(m.right().node());
395  }
396  if (m.left().IsNaN()) { // NaN / x => NaN
397  return Replace(m.left().node());
398  }
399  if (m.IsFoldable()) { // K / K => K
400  return ReplaceFloat64(m.left().Value() / m.right().Value());
401  }
402  break;
403  }
404  case IrOpcode::kFloat64Mod: {
405  Float64BinopMatcher m(node);
406  if (m.right().Is(0)) { // x % 0 => NaN
407  return ReplaceFloat64(base::OS::nan_value());
408  }
409  if (m.right().IsNaN()) { // x % NaN => NaN
410  return Replace(m.right().node());
411  }
412  if (m.left().IsNaN()) { // NaN % x => NaN
413  return Replace(m.left().node());
414  }
415  if (m.IsFoldable()) { // K % K => K
416  return ReplaceFloat64(modulo(m.left().Value(), m.right().Value()));
417  }
418  break;
419  }
420  case IrOpcode::kChangeFloat32ToFloat64: {
421  Float32Matcher m(node->InputAt(0));
422  if (m.HasValue()) return ReplaceFloat64(m.Value());
423  break;
424  }
425  case IrOpcode::kChangeFloat64ToInt32: {
426  Float64Matcher m(node->InputAt(0));
427  if (m.HasValue()) return ReplaceInt32(FastD2I(m.Value()));
428  if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
429  break;
430  }
431  case IrOpcode::kChangeFloat64ToUint32: {
432  Float64Matcher m(node->InputAt(0));
433  if (m.HasValue()) return ReplaceInt32(FastD2UI(m.Value()));
434  if (m.IsChangeUint32ToFloat64()) return Replace(m.node()->InputAt(0));
435  break;
436  }
437  case IrOpcode::kChangeInt32ToFloat64: {
438  Int32Matcher m(node->InputAt(0));
439  if (m.HasValue()) return ReplaceFloat64(FastI2D(m.Value()));
440  break;
441  }
442  case IrOpcode::kChangeInt32ToInt64: {
443  Int32Matcher m(node->InputAt(0));
444  if (m.HasValue()) return ReplaceInt64(m.Value());
445  break;
446  }
447  case IrOpcode::kChangeUint32ToFloat64: {
448  Uint32Matcher m(node->InputAt(0));
449  if (m.HasValue()) return ReplaceFloat64(FastUI2D(m.Value()));
450  break;
451  }
452  case IrOpcode::kChangeUint32ToUint64: {
453  Uint32Matcher m(node->InputAt(0));
454  if (m.HasValue()) return ReplaceInt64(static_cast<uint64_t>(m.Value()));
455  break;
456  }
457  case IrOpcode::kTruncateFloat64ToInt32: {
458  Float64Matcher m(node->InputAt(0));
459  if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value()));
460  if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
461  break;
462  }
463  case IrOpcode::kTruncateInt64ToInt32: {
464  Int64Matcher m(node->InputAt(0));
465  if (m.HasValue()) return ReplaceInt32(static_cast<int32_t>(m.Value()));
466  if (m.IsChangeInt32ToInt64()) return Replace(m.node()->InputAt(0));
467  break;
468  }
469  case IrOpcode::kTruncateFloat64ToFloat32: {
470  Float64Matcher m(node->InputAt(0));
471  if (m.HasValue()) return ReplaceFloat32(DoubleToFloat32(m.Value()));
472  if (m.IsChangeFloat32ToFloat64()) return Replace(m.node()->InputAt(0));
473  break;
474  }
475  default:
476  break;
477  }
478  return NoChange();
479 }
480 
481 
482 Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) {
483  switch (node->opcode()) {
484  case IrOpcode::kInt32AddWithOverflow: {
485  DCHECK(index == 0 || index == 1);
486  Int32BinopMatcher m(node);
487  if (m.IsFoldable()) {
488  int32_t val;
489  bool ovf = base::bits::SignedAddOverflow32(m.left().Value(),
490  m.right().Value(), &val);
491  return ReplaceInt32((index == 0) ? val : ovf);
492  }
493  if (m.right().Is(0)) {
494  return (index == 0) ? Replace(m.left().node()) : ReplaceInt32(0);
495  }
496  break;
497  }
498  case IrOpcode::kInt32SubWithOverflow: {
499  DCHECK(index == 0 || index == 1);
500  Int32BinopMatcher m(node);
501  if (m.IsFoldable()) {
502  int32_t val;
503  bool ovf = base::bits::SignedSubOverflow32(m.left().Value(),
504  m.right().Value(), &val);
505  return ReplaceInt32((index == 0) ? val : ovf);
506  }
507  if (m.right().Is(0)) {
508  return (index == 0) ? Replace(m.left().node()) : ReplaceInt32(0);
509  }
510  break;
511  }
512  default:
513  break;
514  }
515  return NoChange();
516 }
517 
518 
519 CommonOperatorBuilder* MachineOperatorReducer::common() const {
520  return jsgraph()->common();
521 }
522 
523 
524 MachineOperatorBuilder* MachineOperatorReducer::machine() const {
525  return jsgraph()->machine();
526 }
527 
528 
529 Graph* MachineOperatorReducer::graph() const { return jsgraph()->graph(); }
530 
531 } // namespace compiler
532 } // namespace internal
533 } // namespace v8
#define DCHECK(condition)
Definition: logging.h:205
int int32_t
Definition: unicode.cc:24
uint32_t RotateRight32(uint32_t value, uint32_t shift)
Definition: bits.h:107
bool SignedAddOverflow32(int32_t lhs, int32_t rhs, int32_t *val)
Definition: bits.h:122
bool SignedSubOverflow32(int32_t lhs, int32_t rhs, int32_t *val)
Definition: bits.h:136
FloatMatcher< float, IrOpcode::kFloat32Constant > Float32Matcher
Definition: node-matchers.h:93
IntMatcher< int64_t, IrOpcode::kInt64Constant > Int64Matcher
Definition: node-matchers.h:81
BinopMatcher< Uint32Matcher, Uint32Matcher > Uint32BinopMatcher
BinopMatcher< Int32Matcher, Int32Matcher > Int32BinopMatcher
FloatMatcher< double, IrOpcode::kFloat64Constant > Float64Matcher
Definition: node-matchers.h:94
BinopMatcher< Float64Matcher, Float64Matcher > Float64BinopMatcher
IntMatcher< int32_t, IrOpcode::kInt32Constant > Int32Matcher
Definition: node-matchers.h:79
IntMatcher< uint32_t, IrOpcode::kInt32Constant > Uint32Matcher
Definition: node-matchers.h:80
int WhichPowerOf2(uint32_t x)
Definition: utils.h:37
unsigned int FastD2UI(double x)
double modulo(double x, double y)
Definition: codegen.cc:50
double FastI2D(int x)
Definition: conversions.h:64
int32_t DoubleToInt32(double x)
int FastD2I(double x)
Definition: conversions.h:57
float DoubleToFloat32(double x)
double FastUI2D(unsigned x)
Definition: conversions.h:72
const uint32_t kMaxUInt32
Definition: globals.h:120
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20