js-builtin-reducer.cc revision f91f0611dbaf29ca0f1d4aecb357ce243a19d2fa
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 5#include "src/compiler/js-builtin-reducer.h" 6 7#include "src/compilation-dependencies.h" 8#include "src/compiler/access-builder.h" 9#include "src/compiler/js-graph.h" 10#include "src/compiler/node-matchers.h" 11#include "src/compiler/node-properties.h" 12#include "src/compiler/simplified-operator.h" 13#include "src/objects-inl.h" 14#include "src/type-cache.h" 15#include "src/types.h" 16 17namespace v8 { 18namespace internal { 19namespace compiler { 20 21 22// Helper class to access JSCallFunction nodes that are potential candidates 23// for reduction when they have a BuiltinFunctionId associated with them. 24class JSCallReduction { 25 public: 26 explicit JSCallReduction(Node* node) : node_(node) {} 27 28 // Determines whether the node is a JSCallFunction operation that targets a 29 // constant callee being a well-known builtin with a BuiltinFunctionId. 30 bool HasBuiltinFunctionId() { 31 if (node_->opcode() != IrOpcode::kJSCallFunction) return false; 32 HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0)); 33 if (!m.HasValue() || !m.Value()->IsJSFunction()) return false; 34 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); 35 return function->shared()->HasBuiltinFunctionId(); 36 } 37 38 // Retrieves the BuiltinFunctionId as described above. 39 BuiltinFunctionId GetBuiltinFunctionId() { 40 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); 41 HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0)); 42 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); 43 return function->shared()->builtin_function_id(); 44 } 45 46 bool ReceiverMatches(Type* type) { 47 return NodeProperties::GetType(receiver())->Is(type); 48 } 49 50 // Determines whether the call takes zero inputs. 51 bool InputsMatchZero() { return GetJSCallArity() == 0; } 52 53 // Determines whether the call takes one input of the given type. 54 bool InputsMatchOne(Type* t1) { 55 return GetJSCallArity() == 1 && 56 NodeProperties::GetType(GetJSCallInput(0))->Is(t1); 57 } 58 59 // Determines whether the call takes two inputs of the given types. 60 bool InputsMatchTwo(Type* t1, Type* t2) { 61 return GetJSCallArity() == 2 && 62 NodeProperties::GetType(GetJSCallInput(0))->Is(t1) && 63 NodeProperties::GetType(GetJSCallInput(1))->Is(t2); 64 } 65 66 // Determines whether the call takes inputs all of the given type. 67 bool InputsMatchAll(Type* t) { 68 for (int i = 0; i < GetJSCallArity(); i++) { 69 if (!NodeProperties::GetType(GetJSCallInput(i))->Is(t)) { 70 return false; 71 } 72 } 73 return true; 74 } 75 76 Node* receiver() { return NodeProperties::GetValueInput(node_, 1); } 77 Node* left() { return GetJSCallInput(0); } 78 Node* right() { return GetJSCallInput(1); } 79 80 int GetJSCallArity() { 81 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); 82 // Skip first (i.e. callee) and second (i.e. receiver) operand. 83 return node_->op()->ValueInputCount() - 2; 84 } 85 86 Node* GetJSCallInput(int index) { 87 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); 88 DCHECK_LT(index, GetJSCallArity()); 89 // Skip first (i.e. callee) and second (i.e. receiver) operand. 90 return NodeProperties::GetValueInput(node_, index + 2); 91 } 92 93 private: 94 Node* node_; 95}; 96 97JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph, 98 Flags flags, 99 CompilationDependencies* dependencies) 100 : AdvancedReducer(editor), 101 dependencies_(dependencies), 102 flags_(flags), 103 jsgraph_(jsgraph), 104 type_cache_(TypeCache::Get()) {} 105 106namespace { 107 108MaybeHandle<Map> GetMapWitness(Node* node) { 109 Node* receiver = NodeProperties::GetValueInput(node, 1); 110 Node* effect = NodeProperties::GetEffectInput(node); 111 // Check if the {node} is dominated by a CheckMaps with a single map 112 // for the {receiver}, and if so use that map for the lowering below. 113 for (Node* dominator = effect;;) { 114 if (dominator->opcode() == IrOpcode::kCheckMaps && 115 dominator->InputAt(0) == receiver) { 116 if (dominator->op()->ValueInputCount() == 2) { 117 HeapObjectMatcher m(dominator->InputAt(1)); 118 if (m.HasValue()) return Handle<Map>::cast(m.Value()); 119 } 120 return MaybeHandle<Map>(); 121 } 122 if (dominator->op()->EffectInputCount() != 1) { 123 // Didn't find any appropriate CheckMaps node. 124 return MaybeHandle<Map>(); 125 } 126 dominator = NodeProperties::GetEffectInput(dominator); 127 } 128} 129 130// TODO(turbofan): This was copied from Crankshaft, might be too restrictive. 131bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) { 132 DCHECK(!jsarray_map->is_dictionary_map()); 133 Isolate* isolate = jsarray_map->GetIsolate(); 134 Handle<Name> length_string = isolate->factory()->length_string(); 135 DescriptorArray* descriptors = jsarray_map->instance_descriptors(); 136 int number = 137 descriptors->SearchWithCache(isolate, *length_string, *jsarray_map); 138 DCHECK_NE(DescriptorArray::kNotFound, number); 139 return descriptors->GetDetails(number).IsReadOnly(); 140} 141 142// TODO(turbofan): This was copied from Crankshaft, might be too restrictive. 143bool CanInlineArrayResizeOperation(Handle<Map> receiver_map) { 144 Isolate* const isolate = receiver_map->GetIsolate(); 145 if (!receiver_map->prototype()->IsJSArray()) return false; 146 Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()), 147 isolate); 148 // Ensure that all prototypes of the {receiver} are stable. 149 for (PrototypeIterator it(isolate, receiver_prototype, kStartAtReceiver); 150 !it.IsAtEnd(); it.Advance()) { 151 Handle<JSReceiver> current = PrototypeIterator::GetCurrent<JSReceiver>(it); 152 if (!current->map()->is_stable()) return false; 153 } 154 return receiver_map->instance_type() == JS_ARRAY_TYPE && 155 IsFastElementsKind(receiver_map->elements_kind()) && 156 !receiver_map->is_dictionary_map() && receiver_map->is_extensible() && 157 (!receiver_map->is_prototype_map() || receiver_map->is_stable()) && 158 isolate->IsFastArrayConstructorPrototypeChainIntact() && 159 isolate->IsAnyInitialArrayPrototype(receiver_prototype) && 160 !IsReadOnlyLengthDescriptor(receiver_map); 161} 162 163} // namespace 164 165// ES6 section 22.1.3.17 Array.prototype.pop ( ) 166Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) { 167 Handle<Map> receiver_map; 168 Node* receiver = NodeProperties::GetValueInput(node, 1); 169 Node* effect = NodeProperties::GetEffectInput(node); 170 Node* control = NodeProperties::GetControlInput(node); 171 // TODO(turbofan): Extend this to also handle fast (holey) double elements 172 // once we got the hole NaN mess sorted out in TurboFan/V8. 173 if (GetMapWitness(node).ToHandle(&receiver_map) && 174 CanInlineArrayResizeOperation(receiver_map) && 175 IsFastSmiOrObjectElementsKind(receiver_map->elements_kind())) { 176 // Install code dependencies on the {receiver} prototype maps and the 177 // global array protector cell. 178 dependencies()->AssumePropertyCell(factory()->array_protector()); 179 dependencies()->AssumePrototypeMapsStable(receiver_map); 180 181 // Load the "length" property of the {receiver}. 182 Node* length = effect = graph()->NewNode( 183 simplified()->LoadField( 184 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), 185 receiver, effect, control); 186 187 // Check if the {receiver} has any elements. 188 Node* check = graph()->NewNode(simplified()->NumberEqual(), length, 189 jsgraph()->ZeroConstant()); 190 Node* branch = 191 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); 192 193 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 194 Node* etrue = effect; 195 Node* vtrue = jsgraph()->UndefinedConstant(); 196 197 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 198 Node* efalse = effect; 199 Node* vfalse; 200 { 201 // Load the elements backing store from the {receiver}. 202 Node* elements = efalse = graph()->NewNode( 203 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), 204 receiver, efalse, if_false); 205 206 // Ensure that we aren't popping from a copy-on-write backing store. 207 elements = efalse = 208 graph()->NewNode(simplified()->EnsureWritableFastElements(), receiver, 209 elements, efalse, if_false); 210 211 // Compute the new {length}. 212 length = graph()->NewNode(simplified()->NumberSubtract(), length, 213 jsgraph()->OneConstant()); 214 215 // Store the new {length} to the {receiver}. 216 efalse = graph()->NewNode( 217 simplified()->StoreField( 218 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), 219 receiver, length, efalse, if_false); 220 221 // Load the last entry from the {elements}. 222 vfalse = efalse = graph()->NewNode( 223 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement( 224 receiver_map->elements_kind())), 225 elements, length, efalse, if_false); 226 227 // Store a hole to the element we just removed from the {receiver}. 228 efalse = graph()->NewNode( 229 simplified()->StoreElement(AccessBuilder::ForFixedArrayElement( 230 GetHoleyElementsKind(receiver_map->elements_kind()))), 231 elements, length, jsgraph()->TheHoleConstant(), efalse, if_false); 232 } 233 234 control = graph()->NewNode(common()->Merge(2), if_true, if_false); 235 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); 236 Node* value = 237 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 238 vtrue, vfalse, control); 239 240 // Convert the hole to undefined. Do this last, so that we can optimize 241 // conversion operator via some smart strength reduction in many cases. 242 if (IsFastHoleyElementsKind(receiver_map->elements_kind())) { 243 value = 244 graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value); 245 } 246 247 ReplaceWithValue(node, value, effect, control); 248 return Replace(value); 249 } 250 return NoChange(); 251} 252 253// ES6 section 22.1.3.18 Array.prototype.push ( ) 254Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) { 255 Handle<Map> receiver_map; 256 // We need exactly target, receiver and value parameters. 257 if (node->op()->ValueInputCount() != 3) return NoChange(); 258 Node* receiver = NodeProperties::GetValueInput(node, 1); 259 Node* effect = NodeProperties::GetEffectInput(node); 260 Node* control = NodeProperties::GetControlInput(node); 261 Node* value = NodeProperties::GetValueInput(node, 2); 262 if (GetMapWitness(node).ToHandle(&receiver_map) && 263 CanInlineArrayResizeOperation(receiver_map)) { 264 // Install code dependencies on the {receiver} prototype maps and the 265 // global array protector cell. 266 dependencies()->AssumePropertyCell(factory()->array_protector()); 267 dependencies()->AssumePrototypeMapsStable(receiver_map); 268 269 // TODO(turbofan): Perform type checks on the {value}. We are not guaranteed 270 // to learn from these checks in case they fail, as the witness (i.e. the 271 // map check from the LoadIC for a.push) might not be executed in baseline 272 // code (after we stored the value in the builtin and thereby changed the 273 // elements kind of a) before be decide to optimize this function again. We 274 // currently don't have a proper way to deal with this; the proper solution 275 // here is to learn on deopt, i.e. disable Array.prototype.push inlining 276 // for this function. 277 if (IsFastSmiElementsKind(receiver_map->elements_kind())) { 278 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(), 279 value, effect, control); 280 } else if (IsFastDoubleElementsKind(receiver_map->elements_kind())) { 281 value = effect = 282 graph()->NewNode(simplified()->CheckNumber(), value, effect, control); 283 // Make sure we do not store signaling NaNs into double arrays. 284 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); 285 } 286 287 // Load the "length" property of the {receiver}. 288 Node* length = effect = graph()->NewNode( 289 simplified()->LoadField( 290 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), 291 receiver, effect, control); 292 293 // Load the elements backing store of the {receiver}. 294 Node* elements = effect = graph()->NewNode( 295 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, 296 effect, control); 297 298 // TODO(turbofan): Check if we need to grow the {elements} backing store. 299 // This will deopt if we cannot grow the array further, and we currently 300 // don't necessarily learn from it. See the comment on the value type check 301 // above. 302 GrowFastElementsFlags flags = GrowFastElementsFlag::kArrayObject; 303 if (IsFastDoubleElementsKind(receiver_map->elements_kind())) { 304 flags |= GrowFastElementsFlag::kDoubleElements; 305 } 306 elements = effect = 307 graph()->NewNode(simplified()->MaybeGrowFastElements(flags), receiver, 308 elements, length, length, effect, control); 309 310 // Append the value to the {elements}. 311 effect = graph()->NewNode( 312 simplified()->StoreElement( 313 AccessBuilder::ForFixedArrayElement(receiver_map->elements_kind())), 314 elements, length, value, effect, control); 315 316 // Return the new length of the {receiver}. 317 value = graph()->NewNode(simplified()->NumberAdd(), length, 318 jsgraph()->OneConstant()); 319 320 ReplaceWithValue(node, value, effect, control); 321 return Replace(value); 322 } 323 return NoChange(); 324} 325 326// ES6 section 20.2.2.1 Math.abs ( x ) 327Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) { 328 JSCallReduction r(node); 329 if (r.InputsMatchOne(Type::PlainPrimitive())) { 330 // Math.abs(a:plain-primitive) -> NumberAbs(ToNumber(a)) 331 Node* input = ToNumber(r.GetJSCallInput(0)); 332 Node* value = graph()->NewNode(simplified()->NumberAbs(), input); 333 return Replace(value); 334 } 335 return NoChange(); 336} 337 338// ES6 section 20.2.2.2 Math.acos ( x ) 339Reduction JSBuiltinReducer::ReduceMathAcos(Node* node) { 340 JSCallReduction r(node); 341 if (r.InputsMatchOne(Type::PlainPrimitive())) { 342 // Math.acos(a:plain-primitive) -> NumberAcos(ToNumber(a)) 343 Node* input = ToNumber(r.GetJSCallInput(0)); 344 Node* value = graph()->NewNode(simplified()->NumberAcos(), input); 345 return Replace(value); 346 } 347 return NoChange(); 348} 349 350// ES6 section 20.2.2.3 Math.acosh ( x ) 351Reduction JSBuiltinReducer::ReduceMathAcosh(Node* node) { 352 JSCallReduction r(node); 353 if (r.InputsMatchOne(Type::PlainPrimitive())) { 354 // Math.acosh(a:plain-primitive) -> NumberAcosh(ToNumber(a)) 355 Node* input = ToNumber(r.GetJSCallInput(0)); 356 Node* value = graph()->NewNode(simplified()->NumberAcosh(), input); 357 return Replace(value); 358 } 359 return NoChange(); 360} 361 362// ES6 section 20.2.2.4 Math.asin ( x ) 363Reduction JSBuiltinReducer::ReduceMathAsin(Node* node) { 364 JSCallReduction r(node); 365 if (r.InputsMatchOne(Type::PlainPrimitive())) { 366 // Math.asin(a:plain-primitive) -> NumberAsin(ToNumber(a)) 367 Node* input = ToNumber(r.GetJSCallInput(0)); 368 Node* value = graph()->NewNode(simplified()->NumberAsin(), input); 369 return Replace(value); 370 } 371 return NoChange(); 372} 373 374// ES6 section 20.2.2.5 Math.asinh ( x ) 375Reduction JSBuiltinReducer::ReduceMathAsinh(Node* node) { 376 JSCallReduction r(node); 377 if (r.InputsMatchOne(Type::PlainPrimitive())) { 378 // Math.asinh(a:plain-primitive) -> NumberAsinh(ToNumber(a)) 379 Node* input = ToNumber(r.GetJSCallInput(0)); 380 Node* value = graph()->NewNode(simplified()->NumberAsinh(), input); 381 return Replace(value); 382 } 383 return NoChange(); 384} 385 386// ES6 section 20.2.2.6 Math.atan ( x ) 387Reduction JSBuiltinReducer::ReduceMathAtan(Node* node) { 388 JSCallReduction r(node); 389 if (r.InputsMatchOne(Type::PlainPrimitive())) { 390 // Math.atan(a:plain-primitive) -> NumberAtan(ToNumber(a)) 391 Node* input = ToNumber(r.GetJSCallInput(0)); 392 Node* value = graph()->NewNode(simplified()->NumberAtan(), input); 393 return Replace(value); 394 } 395 return NoChange(); 396} 397 398// ES6 section 20.2.2.7 Math.atanh ( x ) 399Reduction JSBuiltinReducer::ReduceMathAtanh(Node* node) { 400 JSCallReduction r(node); 401 if (r.InputsMatchOne(Type::PlainPrimitive())) { 402 // Math.atanh(a:plain-primitive) -> NumberAtanh(ToNumber(a)) 403 Node* input = ToNumber(r.GetJSCallInput(0)); 404 Node* value = graph()->NewNode(simplified()->NumberAtanh(), input); 405 return Replace(value); 406 } 407 return NoChange(); 408} 409 410// ES6 section 20.2.2.8 Math.atan2 ( y, x ) 411Reduction JSBuiltinReducer::ReduceMathAtan2(Node* node) { 412 JSCallReduction r(node); 413 if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) { 414 // Math.atan2(a:plain-primitive, 415 // b:plain-primitive) -> NumberAtan2(ToNumber(a), 416 // ToNumber(b)) 417 Node* left = ToNumber(r.left()); 418 Node* right = ToNumber(r.right()); 419 Node* value = graph()->NewNode(simplified()->NumberAtan2(), left, right); 420 return Replace(value); 421 } 422 return NoChange(); 423} 424 425// ES6 section 20.2.2.10 Math.ceil ( x ) 426Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) { 427 JSCallReduction r(node); 428 if (r.InputsMatchOne(Type::PlainPrimitive())) { 429 // Math.ceil(a:plain-primitive) -> NumberCeil(ToNumber(a)) 430 Node* input = ToNumber(r.GetJSCallInput(0)); 431 Node* value = graph()->NewNode(simplified()->NumberCeil(), input); 432 return Replace(value); 433 } 434 return NoChange(); 435} 436 437// ES6 section 20.2.2.11 Math.clz32 ( x ) 438Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) { 439 JSCallReduction r(node); 440 if (r.InputsMatchOne(Type::PlainPrimitive())) { 441 // Math.clz32(a:plain-primitive) -> NumberClz32(ToUint32(a)) 442 Node* input = ToUint32(r.GetJSCallInput(0)); 443 Node* value = graph()->NewNode(simplified()->NumberClz32(), input); 444 return Replace(value); 445 } 446 return NoChange(); 447} 448 449// ES6 section 20.2.2.12 Math.cos ( x ) 450Reduction JSBuiltinReducer::ReduceMathCos(Node* node) { 451 JSCallReduction r(node); 452 if (r.InputsMatchOne(Type::PlainPrimitive())) { 453 // Math.cos(a:plain-primitive) -> NumberCos(ToNumber(a)) 454 Node* input = ToNumber(r.GetJSCallInput(0)); 455 Node* value = graph()->NewNode(simplified()->NumberCos(), input); 456 return Replace(value); 457 } 458 return NoChange(); 459} 460 461// ES6 section 20.2.2.13 Math.cosh ( x ) 462Reduction JSBuiltinReducer::ReduceMathCosh(Node* node) { 463 JSCallReduction r(node); 464 if (r.InputsMatchOne(Type::PlainPrimitive())) { 465 // Math.cosh(a:plain-primitive) -> NumberCosh(ToNumber(a)) 466 Node* input = ToNumber(r.GetJSCallInput(0)); 467 Node* value = graph()->NewNode(simplified()->NumberCosh(), input); 468 return Replace(value); 469 } 470 return NoChange(); 471} 472 473// ES6 section 20.2.2.14 Math.exp ( x ) 474Reduction JSBuiltinReducer::ReduceMathExp(Node* node) { 475 JSCallReduction r(node); 476 if (r.InputsMatchOne(Type::PlainPrimitive())) { 477 // Math.exp(a:plain-primitive) -> NumberExp(ToNumber(a)) 478 Node* input = ToNumber(r.GetJSCallInput(0)); 479 Node* value = graph()->NewNode(simplified()->NumberExp(), input); 480 return Replace(value); 481 } 482 return NoChange(); 483} 484 485// ES6 section 20.2.2.15 Math.expm1 ( x ) 486Reduction JSBuiltinReducer::ReduceMathExpm1(Node* node) { 487 JSCallReduction r(node); 488 if (r.InputsMatchOne(Type::Number())) { 489 // Math.expm1(a:number) -> NumberExpm1(a) 490 Node* value = graph()->NewNode(simplified()->NumberExpm1(), r.left()); 491 return Replace(value); 492 } 493 return NoChange(); 494} 495 496// ES6 section 20.2.2.16 Math.floor ( x ) 497Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) { 498 JSCallReduction r(node); 499 if (r.InputsMatchOne(Type::PlainPrimitive())) { 500 // Math.floor(a:plain-primitive) -> NumberFloor(ToNumber(a)) 501 Node* input = ToNumber(r.GetJSCallInput(0)); 502 Node* value = graph()->NewNode(simplified()->NumberFloor(), input); 503 return Replace(value); 504 } 505 return NoChange(); 506} 507 508// ES6 section 20.2.2.17 Math.fround ( x ) 509Reduction JSBuiltinReducer::ReduceMathFround(Node* node) { 510 JSCallReduction r(node); 511 if (r.InputsMatchOne(Type::PlainPrimitive())) { 512 // Math.fround(a:plain-primitive) -> NumberFround(ToNumber(a)) 513 Node* input = ToNumber(r.GetJSCallInput(0)); 514 Node* value = graph()->NewNode(simplified()->NumberFround(), input); 515 return Replace(value); 516 } 517 return NoChange(); 518} 519 520// ES6 section 20.2.2.19 Math.imul ( x, y ) 521Reduction JSBuiltinReducer::ReduceMathImul(Node* node) { 522 JSCallReduction r(node); 523 if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) { 524 // Math.imul(a:plain-primitive, 525 // b:plain-primitive) -> NumberImul(ToUint32(a), 526 // ToUint32(b)) 527 Node* left = ToUint32(r.left()); 528 Node* right = ToUint32(r.right()); 529 Node* value = graph()->NewNode(simplified()->NumberImul(), left, right); 530 return Replace(value); 531 } 532 return NoChange(); 533} 534 535// ES6 section 20.2.2.20 Math.log ( x ) 536Reduction JSBuiltinReducer::ReduceMathLog(Node* node) { 537 JSCallReduction r(node); 538 if (r.InputsMatchOne(Type::PlainPrimitive())) { 539 // Math.log(a:plain-primitive) -> NumberLog(ToNumber(a)) 540 Node* input = ToNumber(r.GetJSCallInput(0)); 541 Node* value = graph()->NewNode(simplified()->NumberLog(), input); 542 return Replace(value); 543 } 544 return NoChange(); 545} 546 547// ES6 section 20.2.2.21 Math.log1p ( x ) 548Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) { 549 JSCallReduction r(node); 550 if (r.InputsMatchOne(Type::PlainPrimitive())) { 551 // Math.log1p(a:plain-primitive) -> NumberLog1p(ToNumber(a)) 552 Node* input = ToNumber(r.GetJSCallInput(0)); 553 Node* value = graph()->NewNode(simplified()->NumberLog1p(), input); 554 return Replace(value); 555 } 556 return NoChange(); 557} 558 559// ES6 section 20.2.2.22 Math.log10 ( x ) 560Reduction JSBuiltinReducer::ReduceMathLog10(Node* node) { 561 JSCallReduction r(node); 562 if (r.InputsMatchOne(Type::Number())) { 563 // Math.log10(a:number) -> NumberLog10(a) 564 Node* value = graph()->NewNode(simplified()->NumberLog10(), r.left()); 565 return Replace(value); 566 } 567 return NoChange(); 568} 569 570// ES6 section 20.2.2.23 Math.log2 ( x ) 571Reduction JSBuiltinReducer::ReduceMathLog2(Node* node) { 572 JSCallReduction r(node); 573 if (r.InputsMatchOne(Type::Number())) { 574 // Math.log2(a:number) -> NumberLog(a) 575 Node* value = graph()->NewNode(simplified()->NumberLog2(), r.left()); 576 return Replace(value); 577 } 578 return NoChange(); 579} 580 581// ES6 section 20.2.2.24 Math.max ( value1, value2, ...values ) 582Reduction JSBuiltinReducer::ReduceMathMax(Node* node) { 583 JSCallReduction r(node); 584 if (r.InputsMatchZero()) { 585 // Math.max() -> -Infinity 586 return Replace(jsgraph()->Constant(-V8_INFINITY)); 587 } 588 if (r.InputsMatchAll(Type::PlainPrimitive())) { 589 // Math.max(a:plain-primitive, b:plain-primitive, ...) 590 Node* value = ToNumber(r.GetJSCallInput(0)); 591 for (int i = 1; i < r.GetJSCallArity(); i++) { 592 Node* input = ToNumber(r.GetJSCallInput(i)); 593 value = graph()->NewNode(simplified()->NumberMax(), value, input); 594 } 595 return Replace(value); 596 } 597 return NoChange(); 598} 599 600// ES6 section 20.2.2.25 Math.min ( value1, value2, ...values ) 601Reduction JSBuiltinReducer::ReduceMathMin(Node* node) { 602 JSCallReduction r(node); 603 if (r.InputsMatchZero()) { 604 // Math.min() -> Infinity 605 return Replace(jsgraph()->Constant(V8_INFINITY)); 606 } 607 if (r.InputsMatchAll(Type::PlainPrimitive())) { 608 // Math.min(a:plain-primitive, b:plain-primitive, ...) 609 Node* value = ToNumber(r.GetJSCallInput(0)); 610 for (int i = 1; i < r.GetJSCallArity(); i++) { 611 Node* input = ToNumber(r.GetJSCallInput(i)); 612 value = graph()->NewNode(simplified()->NumberMin(), value, input); 613 } 614 return Replace(value); 615 } 616 return NoChange(); 617} 618 619// ES6 section 20.2.2.26 Math.pow ( x, y ) 620Reduction JSBuiltinReducer::ReduceMathPow(Node* node) { 621 JSCallReduction r(node); 622 if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) { 623 // Math.pow(a:plain-primitive, 624 // b:plain-primitive) -> NumberPow(ToNumber(a), ToNumber(b)) 625 Node* left = ToNumber(r.left()); 626 Node* right = ToNumber(r.right()); 627 Node* value = graph()->NewNode(simplified()->NumberPow(), left, right); 628 return Replace(value); 629 } 630 return NoChange(); 631} 632 633// ES6 section 20.2.2.28 Math.round ( x ) 634Reduction JSBuiltinReducer::ReduceMathRound(Node* node) { 635 JSCallReduction r(node); 636 if (r.InputsMatchOne(Type::PlainPrimitive())) { 637 // Math.round(a:plain-primitive) -> NumberRound(ToNumber(a)) 638 Node* input = ToNumber(r.GetJSCallInput(0)); 639 Node* value = graph()->NewNode(simplified()->NumberRound(), input); 640 return Replace(value); 641 } 642 return NoChange(); 643} 644 645// ES6 section 20.2.2.9 Math.cbrt ( x ) 646Reduction JSBuiltinReducer::ReduceMathCbrt(Node* node) { 647 JSCallReduction r(node); 648 if (r.InputsMatchOne(Type::Number())) { 649 // Math.cbrt(a:number) -> NumberCbrt(a) 650 Node* value = graph()->NewNode(simplified()->NumberCbrt(), r.left()); 651 return Replace(value); 652 } 653 return NoChange(); 654} 655 656// ES6 section 20.2.2.29 Math.sign ( x ) 657Reduction JSBuiltinReducer::ReduceMathSign(Node* node) { 658 JSCallReduction r(node); 659 if (r.InputsMatchOne(Type::PlainPrimitive())) { 660 // Math.sign(a:plain-primitive) -> NumberSign(ToNumber(a)) 661 Node* input = ToNumber(r.GetJSCallInput(0)); 662 Node* value = graph()->NewNode(simplified()->NumberSign(), input); 663 return Replace(value); 664 } 665 return NoChange(); 666} 667 668// ES6 section 20.2.2.30 Math.sin ( x ) 669Reduction JSBuiltinReducer::ReduceMathSin(Node* node) { 670 JSCallReduction r(node); 671 if (r.InputsMatchOne(Type::PlainPrimitive())) { 672 // Math.sin(a:plain-primitive) -> NumberSin(ToNumber(a)) 673 Node* input = ToNumber(r.GetJSCallInput(0)); 674 Node* value = graph()->NewNode(simplified()->NumberSin(), input); 675 return Replace(value); 676 } 677 return NoChange(); 678} 679 680// ES6 section 20.2.2.31 Math.sinh ( x ) 681Reduction JSBuiltinReducer::ReduceMathSinh(Node* node) { 682 JSCallReduction r(node); 683 if (r.InputsMatchOne(Type::PlainPrimitive())) { 684 // Math.sinh(a:plain-primitive) -> NumberSinh(ToNumber(a)) 685 Node* input = ToNumber(r.GetJSCallInput(0)); 686 Node* value = graph()->NewNode(simplified()->NumberSinh(), input); 687 return Replace(value); 688 } 689 return NoChange(); 690} 691 692// ES6 section 20.2.2.32 Math.sqrt ( x ) 693Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) { 694 JSCallReduction r(node); 695 if (r.InputsMatchOne(Type::PlainPrimitive())) { 696 // Math.sqrt(a:plain-primitive) -> NumberSqrt(ToNumber(a)) 697 Node* input = ToNumber(r.GetJSCallInput(0)); 698 Node* value = graph()->NewNode(simplified()->NumberSqrt(), input); 699 return Replace(value); 700 } 701 return NoChange(); 702} 703 704// ES6 section 20.2.2.33 Math.tan ( x ) 705Reduction JSBuiltinReducer::ReduceMathTan(Node* node) { 706 JSCallReduction r(node); 707 if (r.InputsMatchOne(Type::PlainPrimitive())) { 708 // Math.tan(a:plain-primitive) -> NumberTan(ToNumber(a)) 709 Node* input = ToNumber(r.GetJSCallInput(0)); 710 Node* value = graph()->NewNode(simplified()->NumberTan(), input); 711 return Replace(value); 712 } 713 return NoChange(); 714} 715 716// ES6 section 20.2.2.34 Math.tanh ( x ) 717Reduction JSBuiltinReducer::ReduceMathTanh(Node* node) { 718 JSCallReduction r(node); 719 if (r.InputsMatchOne(Type::PlainPrimitive())) { 720 // Math.tanh(a:plain-primitive) -> NumberTanh(ToNumber(a)) 721 Node* input = ToNumber(r.GetJSCallInput(0)); 722 Node* value = graph()->NewNode(simplified()->NumberTanh(), input); 723 return Replace(value); 724 } 725 return NoChange(); 726} 727 728// ES6 section 20.2.2.35 Math.trunc ( x ) 729Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) { 730 JSCallReduction r(node); 731 if (r.InputsMatchOne(Type::PlainPrimitive())) { 732 // Math.trunc(a:plain-primitive) -> NumberTrunc(ToNumber(a)) 733 Node* input = ToNumber(r.GetJSCallInput(0)); 734 Node* value = graph()->NewNode(simplified()->NumberTrunc(), input); 735 return Replace(value); 736 } 737 return NoChange(); 738} 739 740// ES6 section 20.1.2.13 Number.parseInt ( string, radix ) 741Reduction JSBuiltinReducer::ReduceNumberParseInt(Node* node) { 742 JSCallReduction r(node); 743 if (r.InputsMatchOne(type_cache_.kSafeInteger) || 744 r.InputsMatchTwo(type_cache_.kSafeInteger, 745 type_cache_.kZeroOrUndefined) || 746 r.InputsMatchTwo(type_cache_.kSafeInteger, type_cache_.kTenOrUndefined)) { 747 // Number.parseInt(a:safe-integer) -> NumberToInt32(a) 748 // Number.parseInt(a:safe-integer,b:#0\/undefined) -> NumberToInt32(a) 749 // Number.parseInt(a:safe-integer,b:#10\/undefined) -> NumberToInt32(a) 750 Node* input = r.GetJSCallInput(0); 751 Node* value = graph()->NewNode(simplified()->NumberToInt32(), input); 752 return Replace(value); 753 } 754 return NoChange(); 755} 756 757// ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) 758Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) { 759 JSCallReduction r(node); 760 if (r.InputsMatchOne(Type::PlainPrimitive())) { 761 // String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a) 762 Node* input = ToNumber(r.GetJSCallInput(0)); 763 Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input); 764 return Replace(value); 765 } 766 return NoChange(); 767} 768 769namespace { 770 771Node* GetStringWitness(Node* node) { 772 Node* receiver = NodeProperties::GetValueInput(node, 1); 773 Type* receiver_type = NodeProperties::GetType(receiver); 774 Node* effect = NodeProperties::GetEffectInput(node); 775 if (receiver_type->Is(Type::String())) return receiver; 776 // Check if the {node} is dominated by a CheckString renaming for 777 // it's {receiver}, and if so use that renaming as {receiver} for 778 // the lowering below. 779 for (Node* dominator = effect;;) { 780 if (dominator->opcode() == IrOpcode::kCheckString && 781 dominator->InputAt(0) == receiver) { 782 return dominator; 783 } 784 if (dominator->op()->EffectInputCount() != 1) { 785 // Didn't find any appropriate CheckString node. 786 return nullptr; 787 } 788 dominator = NodeProperties::GetEffectInput(dominator); 789 } 790} 791 792} // namespace 793 794// ES6 section 21.1.3.1 String.prototype.charAt ( pos ) 795Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) { 796 // We need at least target, receiver and index parameters. 797 if (node->op()->ValueInputCount() >= 3) { 798 Node* index = NodeProperties::GetValueInput(node, 2); 799 Type* index_type = NodeProperties::GetType(index); 800 Node* effect = NodeProperties::GetEffectInput(node); 801 Node* control = NodeProperties::GetControlInput(node); 802 803 if (index_type->Is(Type::Unsigned32())) { 804 if (Node* receiver = GetStringWitness(node)) { 805 // Determine the {receiver} length. 806 Node* receiver_length = effect = graph()->NewNode( 807 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, 808 effect, control); 809 810 // Check if {index} is less than {receiver} length. 811 Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, 812 receiver_length); 813 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 814 check, control); 815 816 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 817 Node* vtrue; 818 { 819 // Load the character from the {receiver}. 820 vtrue = graph()->NewNode(simplified()->StringCharCodeAt(), receiver, 821 index, if_true); 822 823 // Return it as single character string. 824 vtrue = graph()->NewNode(simplified()->StringFromCharCode(), vtrue); 825 } 826 827 // Return the empty string otherwise. 828 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 829 Node* vfalse = jsgraph()->EmptyStringConstant(); 830 831 control = graph()->NewNode(common()->Merge(2), if_true, if_false); 832 Node* value = 833 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 834 vtrue, vfalse, control); 835 836 ReplaceWithValue(node, value, effect, control); 837 return Replace(value); 838 } 839 } 840 } 841 842 return NoChange(); 843} 844 845// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) 846Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) { 847 // We need at least target, receiver and index parameters. 848 if (node->op()->ValueInputCount() >= 3) { 849 Node* index = NodeProperties::GetValueInput(node, 2); 850 Type* index_type = NodeProperties::GetType(index); 851 Node* effect = NodeProperties::GetEffectInput(node); 852 Node* control = NodeProperties::GetControlInput(node); 853 854 if (index_type->Is(Type::Unsigned32())) { 855 if (Node* receiver = GetStringWitness(node)) { 856 // Determine the {receiver} length. 857 Node* receiver_length = effect = graph()->NewNode( 858 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, 859 effect, control); 860 861 // Check if {index} is less than {receiver} length. 862 Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, 863 receiver_length); 864 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 865 check, control); 866 867 // Load the character from the {receiver}. 868 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 869 Node* vtrue = graph()->NewNode(simplified()->StringCharCodeAt(), 870 receiver, index, if_true); 871 872 // Return NaN otherwise. 873 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 874 Node* vfalse = jsgraph()->NaNConstant(); 875 876 control = graph()->NewNode(common()->Merge(2), if_true, if_false); 877 Node* value = 878 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 879 vtrue, vfalse, control); 880 881 ReplaceWithValue(node, value, effect, control); 882 return Replace(value); 883 } 884 } 885 } 886 887 return NoChange(); 888} 889 890namespace { 891 892bool HasInstanceTypeWitness(Node* receiver, Node* effect, 893 InstanceType instance_type) { 894 for (Node* dominator = effect;;) { 895 if (dominator->opcode() == IrOpcode::kCheckMaps && 896 dominator->InputAt(0) == receiver) { 897 // Check if all maps have the given {instance_type}. 898 for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) { 899 Node* const map = NodeProperties::GetValueInput(dominator, i); 900 Type* const map_type = NodeProperties::GetType(map); 901 if (!map_type->IsConstant()) return false; 902 Handle<Map> const map_value = 903 Handle<Map>::cast(map_type->AsConstant()->Value()); 904 if (map_value->instance_type() != instance_type) return false; 905 } 906 return true; 907 } 908 switch (dominator->opcode()) { 909 case IrOpcode::kStoreField: { 910 FieldAccess const& access = FieldAccessOf(dominator->op()); 911 if (access.base_is_tagged == kTaggedBase && 912 access.offset == HeapObject::kMapOffset) { 913 return false; 914 } 915 break; 916 } 917 case IrOpcode::kStoreElement: 918 break; 919 default: { 920 DCHECK_EQ(1, dominator->op()->EffectOutputCount()); 921 if (dominator->op()->EffectInputCount() != 1 || 922 !dominator->op()->HasProperty(Operator::kNoWrite)) { 923 // Didn't find any appropriate CheckMaps node. 924 return false; 925 } 926 break; 927 } 928 } 929 dominator = NodeProperties::GetEffectInput(dominator); 930 } 931} 932 933} // namespace 934 935Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor( 936 Node* node, InstanceType instance_type, FieldAccess const& access) { 937 Node* receiver = NodeProperties::GetValueInput(node, 1); 938 Node* effect = NodeProperties::GetEffectInput(node); 939 Node* control = NodeProperties::GetControlInput(node); 940 if (HasInstanceTypeWitness(receiver, effect, instance_type)) { 941 // Load the {receiver}s field. 942 Node* receiver_length = effect = graph()->NewNode( 943 simplified()->LoadField(access), receiver, effect, control); 944 945 // Check if the {receiver}s buffer was neutered. 946 Node* receiver_buffer = effect = graph()->NewNode( 947 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), 948 receiver, effect, control); 949 Node* receiver_buffer_bitfield = effect = graph()->NewNode( 950 simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()), 951 receiver_buffer, effect, control); 952 Node* check = graph()->NewNode( 953 simplified()->NumberEqual(), 954 graph()->NewNode( 955 simplified()->NumberBitwiseAnd(), receiver_buffer_bitfield, 956 jsgraph()->Constant(JSArrayBuffer::WasNeutered::kMask)), 957 jsgraph()->ZeroConstant()); 958 959 // Default to zero if the {receiver}s buffer was neutered. 960 Node* value = graph()->NewNode( 961 common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue), 962 check, receiver_length, jsgraph()->ZeroConstant()); 963 964 ReplaceWithValue(node, value, effect, control); 965 return Replace(value); 966 } 967 return NoChange(); 968} 969 970Reduction JSBuiltinReducer::Reduce(Node* node) { 971 Reduction reduction = NoChange(); 972 JSCallReduction r(node); 973 974 // Dispatch according to the BuiltinFunctionId if present. 975 if (!r.HasBuiltinFunctionId()) return NoChange(); 976 switch (r.GetBuiltinFunctionId()) { 977 case kArrayPop: 978 return ReduceArrayPop(node); 979 case kArrayPush: 980 return ReduceArrayPush(node); 981 case kMathAbs: 982 reduction = ReduceMathAbs(node); 983 break; 984 case kMathAcos: 985 reduction = ReduceMathAcos(node); 986 break; 987 case kMathAcosh: 988 reduction = ReduceMathAcosh(node); 989 break; 990 case kMathAsin: 991 reduction = ReduceMathAsin(node); 992 break; 993 case kMathAsinh: 994 reduction = ReduceMathAsinh(node); 995 break; 996 case kMathAtan: 997 reduction = ReduceMathAtan(node); 998 break; 999 case kMathAtanh: 1000 reduction = ReduceMathAtanh(node); 1001 break; 1002 case kMathAtan2: 1003 reduction = ReduceMathAtan2(node); 1004 break; 1005 case kMathCbrt: 1006 reduction = ReduceMathCbrt(node); 1007 break; 1008 case kMathCeil: 1009 reduction = ReduceMathCeil(node); 1010 break; 1011 case kMathClz32: 1012 reduction = ReduceMathClz32(node); 1013 break; 1014 case kMathCos: 1015 reduction = ReduceMathCos(node); 1016 break; 1017 case kMathCosh: 1018 reduction = ReduceMathCosh(node); 1019 break; 1020 case kMathExp: 1021 reduction = ReduceMathExp(node); 1022 break; 1023 case kMathExpm1: 1024 reduction = ReduceMathExpm1(node); 1025 break; 1026 case kMathFloor: 1027 reduction = ReduceMathFloor(node); 1028 break; 1029 case kMathFround: 1030 reduction = ReduceMathFround(node); 1031 break; 1032 case kMathImul: 1033 reduction = ReduceMathImul(node); 1034 break; 1035 case kMathLog: 1036 reduction = ReduceMathLog(node); 1037 break; 1038 case kMathLog1p: 1039 reduction = ReduceMathLog1p(node); 1040 break; 1041 case kMathLog10: 1042 reduction = ReduceMathLog10(node); 1043 break; 1044 case kMathLog2: 1045 reduction = ReduceMathLog2(node); 1046 break; 1047 case kMathMax: 1048 reduction = ReduceMathMax(node); 1049 break; 1050 case kMathMin: 1051 reduction = ReduceMathMin(node); 1052 break; 1053 case kMathPow: 1054 reduction = ReduceMathPow(node); 1055 break; 1056 case kMathRound: 1057 reduction = ReduceMathRound(node); 1058 break; 1059 case kMathSign: 1060 reduction = ReduceMathSign(node); 1061 break; 1062 case kMathSin: 1063 reduction = ReduceMathSin(node); 1064 break; 1065 case kMathSinh: 1066 reduction = ReduceMathSinh(node); 1067 break; 1068 case kMathSqrt: 1069 reduction = ReduceMathSqrt(node); 1070 break; 1071 case kMathTan: 1072 reduction = ReduceMathTan(node); 1073 break; 1074 case kMathTanh: 1075 reduction = ReduceMathTanh(node); 1076 break; 1077 case kMathTrunc: 1078 reduction = ReduceMathTrunc(node); 1079 break; 1080 case kNumberParseInt: 1081 reduction = ReduceNumberParseInt(node); 1082 break; 1083 case kStringFromCharCode: 1084 reduction = ReduceStringFromCharCode(node); 1085 break; 1086 case kStringCharAt: 1087 return ReduceStringCharAt(node); 1088 case kStringCharCodeAt: 1089 return ReduceStringCharCodeAt(node); 1090 case kDataViewByteLength: 1091 return ReduceArrayBufferViewAccessor( 1092 node, JS_DATA_VIEW_TYPE, 1093 AccessBuilder::ForJSArrayBufferViewByteLength()); 1094 case kDataViewByteOffset: 1095 return ReduceArrayBufferViewAccessor( 1096 node, JS_DATA_VIEW_TYPE, 1097 AccessBuilder::ForJSArrayBufferViewByteOffset()); 1098 case kTypedArrayByteLength: 1099 return ReduceArrayBufferViewAccessor( 1100 node, JS_TYPED_ARRAY_TYPE, 1101 AccessBuilder::ForJSArrayBufferViewByteLength()); 1102 case kTypedArrayByteOffset: 1103 return ReduceArrayBufferViewAccessor( 1104 node, JS_TYPED_ARRAY_TYPE, 1105 AccessBuilder::ForJSArrayBufferViewByteOffset()); 1106 case kTypedArrayLength: 1107 return ReduceArrayBufferViewAccessor( 1108 node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength()); 1109 default: 1110 break; 1111 } 1112 1113 // Replace builtin call assuming replacement nodes are pure values that don't 1114 // produce an effect. Replaces {node} with {reduction} and relaxes effects. 1115 if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement()); 1116 1117 return reduction; 1118} 1119 1120Node* JSBuiltinReducer::ToNumber(Node* input) { 1121 Type* input_type = NodeProperties::GetType(input); 1122 if (input_type->Is(Type::Number())) return input; 1123 return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), input); 1124} 1125 1126Node* JSBuiltinReducer::ToUint32(Node* input) { 1127 input = ToNumber(input); 1128 Type* input_type = NodeProperties::GetType(input); 1129 if (input_type->Is(Type::Unsigned32())) return input; 1130 return graph()->NewNode(simplified()->NumberToUint32(), input); 1131} 1132 1133Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); } 1134 1135Factory* JSBuiltinReducer::factory() const { return isolate()->factory(); } 1136 1137Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); } 1138 1139 1140CommonOperatorBuilder* JSBuiltinReducer::common() const { 1141 return jsgraph()->common(); 1142} 1143 1144 1145SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const { 1146 return jsgraph()->simplified(); 1147} 1148 1149} // namespace compiler 1150} // namespace internal 1151} // namespace v8 1152