OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/js-global-specialization.h" | 5 #include "src/compiler/js-global-specialization.h" |
6 | 6 |
7 #include "src/compilation-dependencies.h" | 7 #include "src/compilation-dependencies.h" |
8 #include "src/compiler/access-builder.h" | 8 #include "src/compiler/access-builder.h" |
9 #include "src/compiler/js-graph.h" | 9 #include "src/compiler/js-graph.h" |
10 #include "src/compiler/js-operator.h" | 10 #include "src/compiler/js-operator.h" |
11 #include "src/contexts.h" | 11 #include "src/contexts.h" |
12 #include "src/field-index-inl.h" | |
13 #include "src/lookup.h" | 12 #include "src/lookup.h" |
14 #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker! | 13 #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker! |
15 #include "src/type-feedback-vector.h" | |
16 | 14 |
17 namespace v8 { | 15 namespace v8 { |
18 namespace internal { | 16 namespace internal { |
19 namespace compiler { | 17 namespace compiler { |
20 | 18 |
21 struct JSGlobalSpecialization::ScriptContextTableLookupResult { | 19 struct JSGlobalSpecialization::ScriptContextTableLookupResult { |
22 Handle<Context> context; | 20 Handle<Context> context; |
23 bool immutable; | 21 bool immutable; |
24 int index; | 22 int index; |
25 }; | 23 }; |
26 | 24 |
27 | 25 |
28 JSGlobalSpecialization::JSGlobalSpecialization( | 26 JSGlobalSpecialization::JSGlobalSpecialization( |
29 Editor* editor, JSGraph* jsgraph, Flags flags, | 27 Editor* editor, JSGraph* jsgraph, Flags flags, |
30 Handle<GlobalObject> global_object, CompilationDependencies* dependencies, | 28 Handle<GlobalObject> global_object, CompilationDependencies* dependencies) |
31 Zone* zone) | |
32 : AdvancedReducer(editor), | 29 : AdvancedReducer(editor), |
33 jsgraph_(jsgraph), | 30 jsgraph_(jsgraph), |
34 flags_(flags), | 31 flags_(flags), |
35 global_object_(global_object), | 32 global_object_(global_object), |
36 dependencies_(dependencies), | 33 dependencies_(dependencies) {} |
37 zone_(zone) {} | |
38 | 34 |
39 | 35 |
40 Reduction JSGlobalSpecialization::Reduce(Node* node) { | 36 Reduction JSGlobalSpecialization::Reduce(Node* node) { |
41 switch (node->opcode()) { | 37 switch (node->opcode()) { |
42 case IrOpcode::kJSLoadGlobal: | 38 case IrOpcode::kJSLoadGlobal: |
43 return ReduceJSLoadGlobal(node); | 39 return ReduceJSLoadGlobal(node); |
44 case IrOpcode::kJSStoreGlobal: | 40 case IrOpcode::kJSStoreGlobal: |
45 return ReduceJSStoreGlobal(node); | 41 return ReduceJSStoreGlobal(node); |
46 case IrOpcode::kJSLoadNamed: | |
47 return ReduceJSLoadNamed(node); | |
48 default: | 42 default: |
49 break; | 43 break; |
50 } | 44 } |
51 return NoChange(); | 45 return NoChange(); |
52 } | 46 } |
53 | 47 |
54 | 48 |
55 Reduction JSGlobalSpecialization::ReduceJSLoadGlobal(Node* node) { | 49 Reduction JSGlobalSpecialization::ReduceJSLoadGlobal(Node* node) { |
56 DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode()); | 50 DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode()); |
57 Handle<Name> name = LoadGlobalParametersOf(node->op()).name(); | 51 Handle<Name> name = LoadGlobalParametersOf(node->op()).name(); |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 break; | 223 break; |
230 } | 224 } |
231 } | 225 } |
232 effect = graph()->NewNode( | 226 effect = graph()->NewNode( |
233 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), | 227 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), |
234 jsgraph()->Constant(property_cell), value, effect, control); | 228 jsgraph()->Constant(property_cell), value, effect, control); |
235 return Replace(node, value, effect, control); | 229 return Replace(node, value, effect, control); |
236 } | 230 } |
237 | 231 |
238 | 232 |
239 // This class encapsulates all information required to access a certain | |
240 // object property, either on the object itself or on the prototype chain. | |
241 class JSGlobalSpecialization::PropertyAccessInfo final { | |
242 public: | |
243 enum Kind { kInvalid, kData, kDataConstant }; | |
244 | |
245 static PropertyAccessInfo DataConstant(Type* receiver_type, | |
246 Handle<Object> constant, | |
247 MaybeHandle<JSObject> holder) { | |
248 return PropertyAccessInfo(holder, constant, receiver_type); | |
249 } | |
250 static PropertyAccessInfo Data(Type* receiver_type, FieldIndex field_index, | |
251 Representation field_representation, | |
252 MaybeHandle<JSObject> holder) { | |
253 return PropertyAccessInfo(holder, field_index, field_representation, | |
254 receiver_type); | |
255 } | |
256 | |
257 PropertyAccessInfo() : kind_(kInvalid) {} | |
258 PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant, | |
259 Type* receiver_type) | |
260 : kind_(kDataConstant), | |
261 receiver_type_(receiver_type), | |
262 constant_(constant), | |
263 holder_(holder) {} | |
264 PropertyAccessInfo(MaybeHandle<JSObject> holder, FieldIndex field_index, | |
265 Representation field_representation, Type* receiver_type) | |
266 : kind_(kData), | |
267 receiver_type_(receiver_type), | |
268 holder_(holder), | |
269 field_index_(field_index), | |
270 field_representation_(field_representation) {} | |
271 | |
272 bool IsDataConstant() const { return kind() == kDataConstant; } | |
273 bool IsData() const { return kind() == kData; } | |
274 | |
275 Kind kind() const { return kind_; } | |
276 MaybeHandle<JSObject> holder() const { return holder_; } | |
277 Handle<Object> constant() const { return constant_; } | |
278 FieldIndex field_index() const { return field_index_; } | |
279 Representation field_representation() const { return field_representation_; } | |
280 Type* receiver_type() const { return receiver_type_; } | |
281 | |
282 private: | |
283 Kind kind_; | |
284 Type* receiver_type_; | |
285 Handle<Object> constant_; | |
286 MaybeHandle<JSObject> holder_; | |
287 FieldIndex field_index_; | |
288 Representation field_representation_; | |
289 }; | |
290 | |
291 | |
292 namespace { | |
293 | |
294 bool CanInlinePropertyAccess(Handle<Map> map) { | |
295 // TODO(bmeurer): Do something about the number stuff. | |
296 if (map->instance_type() == HEAP_NUMBER_TYPE) return false; | |
297 if (map->instance_type() < FIRST_NONSTRING_TYPE) return true; | |
298 return map->IsJSObjectMap() && !map->is_dictionary_map() && | |
299 !map->has_named_interceptor() && | |
300 // TODO(verwaest): Whitelist contexts to which we have access. | |
301 !map->is_access_check_needed(); | |
302 } | |
303 | |
304 } // namespace | |
305 | |
306 | |
307 bool JSGlobalSpecialization::ComputePropertyAccessInfo( | |
308 Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) { | |
309 MaybeHandle<JSObject> holder; | |
310 Type* receiver_type = Type::Class(map, graph()->zone()); | |
311 while (CanInlinePropertyAccess(map)) { | |
312 // Lookup the named property on the {map}. | |
313 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); | |
314 int const number = descriptors->SearchWithCache(*name, *map); | |
315 if (number != DescriptorArray::kNotFound) { | |
316 PropertyDetails const details = descriptors->GetDetails(number); | |
317 if (details.type() == DATA_CONSTANT) { | |
318 *access_info = PropertyAccessInfo::DataConstant( | |
319 receiver_type, handle(descriptors->GetValue(number), isolate()), | |
320 holder); | |
321 return true; | |
322 } else if (details.type() == DATA) { | |
323 int index = descriptors->GetFieldIndex(number); | |
324 Representation field_representation = details.representation(); | |
325 FieldIndex field_index = FieldIndex::ForPropertyIndex( | |
326 *map, index, field_representation.IsDouble()); | |
327 *access_info = PropertyAccessInfo::Data(receiver_type, field_index, | |
328 field_representation, holder); | |
329 return true; | |
330 } else { | |
331 // TODO(bmeurer): Add support for accessors. | |
332 break; | |
333 } | |
334 } | |
335 | |
336 // Don't search on the prototype chain for special indices in case of | |
337 // integer indexed exotic objects (see ES6 section 9.4.5). | |
338 if (map->IsJSTypedArrayMap() && name->IsString() && | |
339 IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) { | |
340 break; | |
341 } | |
342 | |
343 // Walk up the prototype chain. | |
344 if (!map->prototype()->IsJSObject()) { | |
345 // TODO(bmeurer): Handle the not found case if the prototype is null. | |
346 break; | |
347 } | |
348 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate()); | |
349 if (map_prototype->map()->is_deprecated()) { | |
350 // Try to migrate the prototype object so we don't embed the deprecated | |
351 // map into the optimized code. | |
352 JSObject::TryMigrateInstance(map_prototype); | |
353 } | |
354 map = handle(map_prototype->map(), isolate()); | |
355 holder = map_prototype; | |
356 } | |
357 return false; | |
358 } | |
359 | |
360 | |
361 bool JSGlobalSpecialization::ComputePropertyAccessInfos( | |
362 MapHandleList const& maps, Handle<Name> name, | |
363 ZoneVector<PropertyAccessInfo>* access_infos) { | |
364 for (Handle<Map> map : maps) { | |
365 PropertyAccessInfo access_info; | |
366 if (!ComputePropertyAccessInfo(map, name, &access_info)) return false; | |
367 access_infos->push_back(access_info); | |
368 } | |
369 return true; | |
370 } | |
371 | |
372 | |
373 Reduction JSGlobalSpecialization::ReduceJSLoadNamed(Node* node) { | |
374 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); | |
375 LoadNamedParameters const p = LoadNamedParametersOf(node->op()); | |
376 Handle<Name> name = p.name(); | |
377 Node* receiver = NodeProperties::GetValueInput(node, 0); | |
378 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | |
379 Node* effect = NodeProperties::GetEffectInput(node); | |
380 Node* control = NodeProperties::GetControlInput(node); | |
381 | |
382 // Not much we can do if deoptimization support is disabled. | |
383 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
384 | |
385 // Extract receiver maps from the LOAD_IC using the LoadICNexus. | |
386 MapHandleList receiver_maps; | |
387 if (!p.feedback().IsValid()) return NoChange(); | |
388 LoadICNexus nexus(p.feedback().vector(), p.feedback().slot()); | |
389 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); | |
390 DCHECK_LT(0, receiver_maps.length()); | |
391 | |
392 // Compute property access infos for the receiver maps. | |
393 ZoneVector<PropertyAccessInfo> access_infos(zone()); | |
394 if (!ComputePropertyAccessInfos(receiver_maps, name, &access_infos)) { | |
395 return NoChange(); | |
396 } | |
397 DCHECK(!access_infos.empty()); | |
398 | |
399 // The final states for every polymorphic branch. We join them with | |
400 // Merge+Phi+EffectPhi at the bottom. | |
401 ZoneVector<Node*> values(zone()); | |
402 ZoneVector<Node*> effects(zone()); | |
403 ZoneVector<Node*> controls(zone()); | |
404 | |
405 // The list of "exiting" controls, which currently go to a single deoptimize. | |
406 // TODO(bmeurer): Consider using an IC as fallback. | |
407 Node* const exit_effect = effect; | |
408 ZoneVector<Node*> exit_controls(zone()); | |
409 | |
410 // Ensure that {receiver} is a heap object. | |
411 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); | |
412 Node* branch = | |
413 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); | |
414 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); | |
415 control = graph()->NewNode(common()->IfFalse(), branch); | |
416 | |
417 // Load the {receiver} map. The resulting effect is the dominating effect for | |
418 // all (polymorphic) branches. | |
419 Node* receiver_map = effect = | |
420 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | |
421 receiver, effect, control); | |
422 | |
423 // Generate code for the various different property access patterns. | |
424 Node* fallthrough_control = control; | |
425 for (PropertyAccessInfo const& access_info : access_infos) { | |
426 Node* this_value = receiver; | |
427 Node* this_effect = effect; | |
428 Node* this_control; | |
429 | |
430 // Perform map check on {receiver}. | |
431 Type* receiver_type = access_info.receiver_type(); | |
432 if (receiver_type->Is(Type::String())) { | |
433 // Emit an instance type check for strings. | |
434 Node* receiver_instance_type = this_effect = graph()->NewNode( | |
435 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), | |
436 receiver_map, this_effect, fallthrough_control); | |
437 Node* check = | |
438 graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type, | |
439 jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE)); | |
440 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), | |
441 check, fallthrough_control); | |
442 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | |
443 this_control = graph()->NewNode(common()->IfTrue(), branch); | |
444 } else { | |
445 // Emit a (sequence of) map checks for other properties. | |
446 ZoneVector<Node*> this_controls(zone()); | |
447 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); | |
448 i.Advance()) { | |
449 Handle<Map> map = i.Current(); | |
450 Node* check = | |
451 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()), | |
452 receiver_map, jsgraph()->Constant(map)); | |
453 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), | |
454 check, fallthrough_control); | |
455 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); | |
456 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | |
457 } | |
458 int const this_control_count = static_cast<int>(this_controls.size()); | |
459 this_control = | |
460 (this_control_count == 1) | |
461 ? this_controls.front() | |
462 : graph()->NewNode(common()->Merge(this_control_count), | |
463 this_control_count, &this_controls.front()); | |
464 } | |
465 | |
466 // Determine actual holder and perform prototype chain checks. | |
467 Handle<JSObject> holder; | |
468 if (access_info.holder().ToHandle(&holder)) { | |
469 this_value = jsgraph()->Constant(holder); | |
470 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); | |
471 i.Advance()) { | |
472 Handle<Map> map = i.Current(); | |
473 PrototypeIterator j(map); | |
474 while (true) { | |
475 // Check that the {prototype} still has the same map. For stable | |
476 // maps, we can add a stability dependency on the prototype map; | |
477 // for everything else we need to perform a map check at runtime. | |
478 Handle<JSReceiver> prototype = | |
479 PrototypeIterator::GetCurrent<JSReceiver>(j); | |
480 if (prototype->map()->is_stable()) { | |
481 dependencies()->AssumeMapStable( | |
482 handle(prototype->map(), isolate())); | |
483 } else { | |
484 Node* prototype_map = this_effect = graph()->NewNode( | |
485 simplified()->LoadField(AccessBuilder::ForMap()), | |
486 jsgraph()->Constant(prototype), this_effect, this_control); | |
487 Node* check = graph()->NewNode( | |
488 simplified()->ReferenceEqual(Type::Internal()), prototype_map, | |
489 jsgraph()->Constant(handle(prototype->map(), isolate()))); | |
490 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), | |
491 check, this_control); | |
492 exit_controls.push_back( | |
493 graph()->NewNode(common()->IfFalse(), branch)); | |
494 this_control = graph()->NewNode(common()->IfTrue(), branch); | |
495 } | |
496 // Stop once we get to the holder. | |
497 if (prototype.is_identical_to(holder)) break; | |
498 j.Advance(); | |
499 } | |
500 } | |
501 } | |
502 | |
503 // Generate the actual property access. | |
504 if (access_info.IsDataConstant()) { | |
505 this_value = jsgraph()->Constant(access_info.constant()); | |
506 } else { | |
507 // TODO(bmeurer): This is sort of adhoc, and must be refactored into some | |
508 // common code once we also have support for stores. | |
509 DCHECK(access_info.IsData()); | |
510 FieldIndex const field_index = access_info.field_index(); | |
511 Representation const field_representation = | |
512 access_info.field_representation(); | |
513 if (!field_index.is_inobject()) { | |
514 this_value = this_effect = graph()->NewNode( | |
515 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), | |
516 this_value, this_effect, this_control); | |
517 } | |
518 FieldAccess field_access; | |
519 field_access.base_is_tagged = kTaggedBase; | |
520 field_access.offset = field_index.offset(); | |
521 field_access.name = name; | |
522 field_access.type = Type::Any(); | |
523 field_access.machine_type = kMachAnyTagged; | |
524 if (field_representation.IsSmi()) { | |
525 field_access.type = Type::Intersect( | |
526 Type::SignedSmall(), Type::TaggedSigned(), graph()->zone()); | |
527 } else if (field_representation.IsDouble()) { | |
528 if (!field_index.is_inobject() || field_index.is_hidden_field() || | |
529 !FLAG_unbox_double_fields) { | |
530 this_value = this_effect = | |
531 graph()->NewNode(simplified()->LoadField(field_access), | |
532 this_value, this_effect, this_control); | |
533 field_access.offset = HeapNumber::kValueOffset; | |
534 field_access.name = MaybeHandle<Name>(); | |
535 } | |
536 field_access.type = Type::Intersect( | |
537 Type::Number(), Type::UntaggedFloat64(), graph()->zone()); | |
538 field_access.machine_type = kMachFloat64; | |
539 } else if (field_representation.IsHeapObject()) { | |
540 field_access.type = Type::TaggedPointer(); | |
541 } | |
542 this_value = this_effect = | |
543 graph()->NewNode(simplified()->LoadField(field_access), this_value, | |
544 this_effect, this_control); | |
545 } | |
546 | |
547 // Remember the final state for this property access. | |
548 values.push_back(this_value); | |
549 effects.push_back(this_effect); | |
550 controls.push_back(this_control); | |
551 } | |
552 | |
553 // Generate the single "exit" point, where we get if either all map/instance | |
554 // type checks failed, or one of the assumptions inside one of the cases | |
555 // failes (i.e. failing prototype chain check). | |
556 // TODO(bmeurer): Consider falling back to IC here if deoptimization is | |
557 // disabled. | |
558 exit_controls.push_back(fallthrough_control); | |
559 int const exit_control_count = static_cast<int>(exit_controls.size()); | |
560 Node* exit_control = | |
561 (exit_control_count == 1) | |
562 ? exit_controls.front() | |
563 : graph()->NewNode(common()->Merge(exit_control_count), | |
564 exit_control_count, &exit_controls.front()); | |
565 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state, | |
566 exit_effect, exit_control); | |
567 // TODO(bmeurer): This should be on the AdvancedReducer somehow. | |
568 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); | |
569 | |
570 // Generate the final merge point for all (polymorphic) branches. | |
571 Node* value; | |
572 int const control_count = static_cast<int>(controls.size()); | |
573 if (control_count == 1) { | |
574 value = values.front(); | |
575 effect = effects.front(); | |
576 control = controls.front(); | |
577 } else { | |
578 control = graph()->NewNode(common()->Merge(control_count), control_count, | |
579 &controls.front()); | |
580 values.push_back(control); | |
581 value = graph()->NewNode(common()->Phi(kMachAnyTagged, control_count), | |
582 control_count + 1, &values.front()); | |
583 effects.push_back(control); | |
584 effect = graph()->NewNode(common()->EffectPhi(control_count), | |
585 control_count + 1, &effects.front()); | |
586 } | |
587 return Replace(node, value, effect, control); | |
588 } | |
589 | |
590 | |
591 Reduction JSGlobalSpecialization::Replace(Node* node, Handle<Object> value) { | 233 Reduction JSGlobalSpecialization::Replace(Node* node, Handle<Object> value) { |
| 234 // TODO(bmeurer): Move this to JSGraph::HeapConstant instead? |
| 235 if (value->IsConsString()) { |
| 236 value = String::Flatten(Handle<String>::cast(value), TENURED); |
| 237 } |
592 return Replace(node, jsgraph()->Constant(value)); | 238 return Replace(node, jsgraph()->Constant(value)); |
593 } | 239 } |
594 | 240 |
595 | 241 |
596 bool JSGlobalSpecialization::LookupInScriptContextTable( | 242 bool JSGlobalSpecialization::LookupInScriptContextTable( |
597 Handle<Name> name, ScriptContextTableLookupResult* result) { | 243 Handle<Name> name, ScriptContextTableLookupResult* result) { |
598 if (!name->IsString()) return false; | 244 if (!name->IsString()) return false; |
599 Handle<ScriptContextTable> script_context_table( | 245 Handle<ScriptContextTable> script_context_table( |
600 global_object()->native_context()->script_context_table()); | 246 global_object()->native_context()->script_context_table()); |
601 ScriptContextTable::LookupResult lookup_result; | 247 ScriptContextTable::LookupResult lookup_result; |
(...skipping 12 matching lines...) Expand all Loading... |
614 | 260 |
615 | 261 |
616 Graph* JSGlobalSpecialization::graph() const { return jsgraph()->graph(); } | 262 Graph* JSGlobalSpecialization::graph() const { return jsgraph()->graph(); } |
617 | 263 |
618 | 264 |
619 Isolate* JSGlobalSpecialization::isolate() const { | 265 Isolate* JSGlobalSpecialization::isolate() const { |
620 return jsgraph()->isolate(); | 266 return jsgraph()->isolate(); |
621 } | 267 } |
622 | 268 |
623 | 269 |
624 MachineOperatorBuilder* JSGlobalSpecialization::machine() const { | |
625 return jsgraph()->machine(); | |
626 } | |
627 | |
628 | |
629 CommonOperatorBuilder* JSGlobalSpecialization::common() const { | 270 CommonOperatorBuilder* JSGlobalSpecialization::common() const { |
630 return jsgraph()->common(); | 271 return jsgraph()->common(); |
631 } | 272 } |
632 | 273 |
633 | 274 |
634 JSOperatorBuilder* JSGlobalSpecialization::javascript() const { | 275 JSOperatorBuilder* JSGlobalSpecialization::javascript() const { |
635 return jsgraph()->javascript(); | 276 return jsgraph()->javascript(); |
636 } | 277 } |
637 | 278 |
638 | 279 |
639 SimplifiedOperatorBuilder* JSGlobalSpecialization::simplified() const { | 280 SimplifiedOperatorBuilder* JSGlobalSpecialization::simplified() const { |
640 return jsgraph()->simplified(); | 281 return jsgraph()->simplified(); |
641 } | 282 } |
642 | 283 |
643 } // namespace compiler | 284 } // namespace compiler |
644 } // namespace internal | 285 } // namespace internal |
645 } // namespace v8 | 286 } // namespace v8 |
OLD | NEW |