OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/code-stubs.h" | 5 #include "src/code-stubs.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "src/bailout-reason.h" | 9 #include "src/bailout-reason.h" |
10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 { | 369 { |
370 HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key); | 370 HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key); |
371 HValue* index = AddUncasted<HAdd>(key, length); | 371 HValue* index = AddUncasted<HAdd>(key, length); |
372 AddElementAccess(elements, index, argument, object, nullptr, kind, STORE); | 372 AddElementAccess(elements, index, argument, object, nullptr, kind, STORE); |
373 } | 373 } |
374 builder.EndBody(); | 374 builder.EndBody(); |
375 return new_length; | 375 return new_length; |
376 } | 376 } |
377 | 377 |
378 template <> | 378 template <> |
379 HValue* CodeStubGraphBuilder<FastFunctionBindStub>::BuildCodeStub() { | |
380 // TODO(verwaest): Fix deoptimizer messages. | |
381 HValue* argc = GetArgumentsLength(); | |
382 HInstruction* argument_elements = Add<HArgumentsElements>(false, false); | |
383 HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc, | |
384 graph()->GetConstantMinus1()); | |
385 BuildCheckHeapObject(object); | |
386 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap()); | |
387 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_FUNCTION); | |
388 | |
389 // Disallow binding of slow-mode functions. We need to figure out whether the | |
390 // length and name property are in the original state. | |
391 { | |
392 HValue* bit_field3 = | |
393 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3()); | |
394 HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask)); | |
395 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask); | |
396 IfBuilder check(this); | |
397 check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); | |
398 check.ThenDeopt(DeoptimizeReason::kFastPathFailed); | |
399 check.End(); | |
400 } | |
401 | |
402 // Check whether the length and name properties are still present as | |
403 // AccessorInfo objects. In that case, their value can be recomputed even if | |
404 // the actual value on the object changes. | |
405 { | |
406 HValue* descriptors = | |
407 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors()); | |
408 | |
409 HValue* descriptors_length = Add<HLoadNamedField>( | |
410 descriptors, nullptr, HObjectAccess::ForFixedArrayLength()); | |
411 IfBuilder range(this); | |
412 range.If<HCompareNumericAndBranch>(descriptors_length, | |
413 graph()->GetConstant1(), Token::LTE); | |
414 range.ThenDeopt(DeoptimizeReason::kFastPathFailed); | |
415 range.End(); | |
416 | |
417 // Verify .length. | |
418 const int length_index = JSFunction::kLengthDescriptorIndex; | |
419 HValue* maybe_length = Add<HLoadKeyed>( | |
420 descriptors, Add<HConstant>(DescriptorArray::ToKeyIndex(length_index)), | |
421 nullptr, nullptr, FAST_ELEMENTS); | |
422 Unique<Name> length_string = Unique<Name>::CreateUninitialized( | |
423 isolate()->factory()->length_string()); | |
424 Add<HCheckValue>(maybe_length, length_string, false); | |
425 | |
426 HValue* maybe_length_accessor = Add<HLoadKeyed>( | |
427 descriptors, | |
428 Add<HConstant>(DescriptorArray::ToValueIndex(length_index)), nullptr, | |
429 nullptr, FAST_ELEMENTS); | |
430 BuildCheckHeapObject(maybe_length_accessor); | |
431 Add<HCheckMaps>(maybe_length_accessor, | |
432 isolate()->factory()->accessor_info_map()); | |
433 | |
434 // Verify .name. | |
435 const int name_index = JSFunction::kNameDescriptorIndex; | |
436 HValue* maybe_name = Add<HLoadKeyed>( | |
437 descriptors, Add<HConstant>(DescriptorArray::ToKeyIndex(name_index)), | |
438 nullptr, nullptr, FAST_ELEMENTS); | |
439 Unique<Name> name_string = | |
440 Unique<Name>::CreateUninitialized(isolate()->factory()->name_string()); | |
441 Add<HCheckValue>(maybe_name, name_string, false); | |
442 | |
443 HValue* maybe_name_accessor = Add<HLoadKeyed>( | |
444 descriptors, Add<HConstant>(DescriptorArray::ToValueIndex(name_index)), | |
445 nullptr, nullptr, FAST_ELEMENTS); | |
446 BuildCheckHeapObject(maybe_name_accessor); | |
447 Add<HCheckMaps>(maybe_name_accessor, | |
448 isolate()->factory()->accessor_info_map()); | |
449 } | |
450 | |
451 // Choose the right bound function map based on whether the target is | |
452 // constructable. | |
453 { | |
454 HValue* bit_field = | |
455 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField()); | |
456 HValue* mask = Add<HConstant>(static_cast<int>(1 << Map::kIsConstructor)); | |
457 HValue* bits = AddUncasted<HBitwise>(Token::BIT_AND, bit_field, mask); | |
458 | |
459 HValue* native_context = BuildGetNativeContext(); | |
460 IfBuilder is_constructor(this); | |
461 is_constructor.If<HCompareNumericAndBranch>(bits, mask, Token::EQ); | |
462 is_constructor.Then(); | |
463 { | |
464 HValue* map = Add<HLoadNamedField>( | |
465 native_context, nullptr, | |
466 HObjectAccess::ForContextSlot( | |
467 Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX)); | |
468 environment()->Push(map); | |
469 } | |
470 is_constructor.Else(); | |
471 { | |
472 HValue* map = Add<HLoadNamedField>( | |
473 native_context, nullptr, | |
474 HObjectAccess::ForContextSlot( | |
475 Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX)); | |
476 environment()->Push(map); | |
477 } | |
478 is_constructor.End(); | |
479 } | |
480 HValue* bound_function_map = environment()->Pop(); | |
481 | |
482 // Verify that __proto__ matches that of a the target bound function. | |
483 { | |
484 HValue* prototype = | |
485 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForPrototype()); | |
486 HValue* expected_prototype = Add<HLoadNamedField>( | |
487 bound_function_map, nullptr, HObjectAccess::ForPrototype()); | |
488 IfBuilder equal_prototype(this); | |
489 equal_prototype.IfNot<HCompareObjectEqAndBranch>(prototype, | |
490 expected_prototype); | |
491 equal_prototype.ThenDeopt(DeoptimizeReason::kFastPathFailed); | |
492 equal_prototype.End(); | |
493 } | |
494 | |
495 // Allocate the arguments array. | |
496 IfBuilder empty_args(this); | |
497 empty_args.If<HCompareNumericAndBranch>(argc, graph()->GetConstant1(), | |
498 Token::LTE); | |
499 empty_args.Then(); | |
500 { environment()->Push(Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex)); } | |
501 empty_args.Else(); | |
502 { | |
503 HValue* elements_length = AddUncasted<HSub>(argc, graph()->GetConstant1()); | |
504 HValue* elements = | |
505 BuildAllocateAndInitializeArray(FAST_ELEMENTS, elements_length); | |
506 | |
507 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); | |
508 HValue* start = graph()->GetConstant1(); | |
509 HValue* key = builder.BeginBody(start, argc, Token::LT); | |
510 { | |
511 HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key); | |
512 HValue* index = AddUncasted<HSub>(key, graph()->GetConstant1()); | |
513 AddElementAccess(elements, index, argument, elements, nullptr, | |
514 FAST_ELEMENTS, STORE); | |
515 } | |
516 builder.EndBody(); | |
517 environment()->Push(elements); | |
518 } | |
519 empty_args.End(); | |
520 HValue* elements = environment()->Pop(); | |
521 | |
522 // Find the 'this' to bind. | |
523 IfBuilder no_receiver(this); | |
524 no_receiver.If<HCompareNumericAndBranch>(argc, graph()->GetConstant0(), | |
525 Token::EQ); | |
526 no_receiver.Then(); | |
527 { environment()->Push(Add<HLoadRoot>(Heap::kUndefinedValueRootIndex)); } | |
528 no_receiver.Else(); | |
529 { | |
530 environment()->Push(Add<HAccessArgumentsAt>(argument_elements, argc, | |
531 graph()->GetConstant0())); | |
532 } | |
533 no_receiver.End(); | |
534 HValue* receiver = environment()->Pop(); | |
535 | |
536 // Allocate the resulting bound function. | |
537 HValue* size = Add<HConstant>(JSBoundFunction::kSize); | |
538 HValue* bound_function = | |
539 Add<HAllocate>(size, HType::JSObject(), NOT_TENURED, | |
540 JS_BOUND_FUNCTION_TYPE, graph()->GetConstant0()); | |
541 Add<HStoreNamedField>(bound_function, HObjectAccess::ForMap(), | |
542 bound_function_map); | |
543 HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); | |
544 Add<HStoreNamedField>(bound_function, HObjectAccess::ForPropertiesPointer(), | |
545 empty_fixed_array); | |
546 Add<HStoreNamedField>(bound_function, HObjectAccess::ForElementsPointer(), | |
547 empty_fixed_array); | |
548 Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundTargetFunction(), | |
549 object); | |
550 | |
551 Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundThis(), | |
552 receiver); | |
553 Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundArguments(), | |
554 elements); | |
555 | |
556 return bound_function; | |
557 } | |
558 | |
559 Handle<Code> FastFunctionBindStub::GenerateCode() { | |
560 return DoGenerateCode(this); | |
561 } | |
562 | |
563 template <> | |
564 HValue* CodeStubGraphBuilder<LoadFastElementStub>::BuildCodeStub() { | 379 HValue* CodeStubGraphBuilder<LoadFastElementStub>::BuildCodeStub() { |
565 LoadKeyedHoleMode hole_mode = casted_stub()->convert_hole_to_undefined() | 380 LoadKeyedHoleMode hole_mode = casted_stub()->convert_hole_to_undefined() |
566 ? CONVERT_HOLE_TO_UNDEFINED | 381 ? CONVERT_HOLE_TO_UNDEFINED |
567 : NEVER_RETURN_HOLE; | 382 : NEVER_RETURN_HOLE; |
568 | 383 |
569 HInstruction* load = BuildUncheckedMonomorphicElementAccess( | 384 HInstruction* load = BuildUncheckedMonomorphicElementAccess( |
570 GetParameter(Descriptor::kReceiver), GetParameter(Descriptor::kName), | 385 GetParameter(Descriptor::kReceiver), GetParameter(Descriptor::kName), |
571 NULL, casted_stub()->is_js_array(), casted_stub()->elements_kind(), LOAD, | 386 NULL, casted_stub()->is_js_array(), casted_stub()->elements_kind(), LOAD, |
572 hole_mode, STANDARD_STORE); | 387 hole_mode, STANDARD_STORE); |
573 return load; | 388 return load; |
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
997 return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash); | 812 return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash); |
998 } | 813 } |
999 | 814 |
1000 | 815 |
1001 Handle<Code> LoadDictionaryElementStub::GenerateCode() { | 816 Handle<Code> LoadDictionaryElementStub::GenerateCode() { |
1002 return DoGenerateCode(this); | 817 return DoGenerateCode(this); |
1003 } | 818 } |
1004 | 819 |
1005 } // namespace internal | 820 } // namespace internal |
1006 } // namespace v8 | 821 } // namespace v8 |
OLD | NEW |