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<FastArrayPushStub>::BuildCodeStub() { | |
380 // TODO(verwaest): Fix deoptimizer messages. | |
381 HValue* argc = GetArgumentsLength(); | |
382 | |
383 HInstruction* argument_elements = Add<HArgumentsElements>(false, false); | |
384 HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc, | |
385 graph()->GetConstantMinus1()); | |
386 BuildCheckHeapObject(object); | |
387 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap()); | |
388 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_ARRAY); | |
389 | |
390 // Disallow pushing onto prototypes. It might be the JSArray prototype. | |
391 // Disallow pushing onto non-extensible objects. | |
392 { | |
393 HValue* bit_field2 = | |
394 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2()); | |
395 HValue* mask = | |
396 Add<HConstant>(static_cast<int>(Map::IsPrototypeMapBits::kMask) | | |
397 (1 << Map::kIsExtensible)); | |
398 HValue* bits = AddUncasted<HBitwise>(Token::BIT_AND, bit_field2, mask); | |
399 IfBuilder check(this); | |
400 check.If<HCompareNumericAndBranch>( | |
401 bits, Add<HConstant>(1 << Map::kIsExtensible), Token::NE); | |
402 check.ThenDeopt(DeoptimizeReason::kFastPathFailed); | |
403 check.End(); | |
404 } | |
405 | |
406 // Disallow pushing onto arrays in dictionary named property mode. We need to | |
407 // figure out whether the length property is still writable. | |
408 { | |
409 HValue* bit_field3 = | |
410 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3()); | |
411 HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask)); | |
412 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask); | |
413 IfBuilder check(this); | |
414 check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); | |
415 check.ThenDeopt(DeoptimizeReason::kFastPathFailed); | |
416 check.End(); | |
417 } | |
418 | |
419 // Check whether the length property is writable. The length property is the | |
420 // only default named property on arrays. It's nonconfigurable, hence is | |
421 // guaranteed to stay the first property. | |
422 { | |
423 HValue* descriptors = | |
424 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors()); | |
425 HValue* details = Add<HLoadKeyed>( | |
426 descriptors, Add<HConstant>(DescriptorArray::ToDetailsIndex(0)), | |
427 nullptr, nullptr, FAST_SMI_ELEMENTS); | |
428 HValue* mask = | |
429 Add<HConstant>(READ_ONLY << PropertyDetails::AttributesField::kShift); | |
430 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, details, mask); | |
431 IfBuilder readonly(this); | |
432 readonly.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); | |
433 readonly.ThenDeopt(DeoptimizeReason::kFastPathFailed); | |
434 readonly.End(); | |
435 } | |
436 | |
437 HValue* null = Add<HLoadRoot>(Heap::kNullValueRootIndex); | |
438 HValue* empty = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); | |
439 environment()->Push(map); | |
440 LoopBuilder check_prototypes(this); | |
441 check_prototypes.BeginBody(1); | |
442 { | |
443 HValue* parent_map = environment()->Pop(); | |
444 HValue* prototype = Add<HLoadNamedField>(parent_map, nullptr, | |
445 HObjectAccess::ForPrototype()); | |
446 | |
447 IfBuilder is_null(this); | |
448 is_null.If<HCompareObjectEqAndBranch>(prototype, null); | |
449 is_null.Then(); | |
450 check_prototypes.Break(); | |
451 is_null.End(); | |
452 | |
453 HValue* prototype_map = | |
454 Add<HLoadNamedField>(prototype, nullptr, HObjectAccess::ForMap()); | |
455 HValue* instance_type = Add<HLoadNamedField>( | |
456 prototype_map, nullptr, HObjectAccess::ForMapInstanceType()); | |
457 IfBuilder check_instance_type(this); | |
458 check_instance_type.If<HCompareNumericAndBranch>( | |
459 instance_type, Add<HConstant>(LAST_CUSTOM_ELEMENTS_RECEIVER), | |
460 Token::LTE); | |
461 check_instance_type.ThenDeopt(DeoptimizeReason::kFastPathFailed); | |
462 check_instance_type.End(); | |
463 | |
464 HValue* elements = Add<HLoadNamedField>( | |
465 prototype, nullptr, HObjectAccess::ForElementsPointer()); | |
466 IfBuilder no_elements(this); | |
467 no_elements.IfNot<HCompareObjectEqAndBranch>(elements, empty); | |
468 no_elements.ThenDeopt(DeoptimizeReason::kFastPathFailed); | |
469 no_elements.End(); | |
470 | |
471 environment()->Push(prototype_map); | |
472 } | |
473 check_prototypes.EndBody(); | |
474 | |
475 HValue* bit_field2 = | |
476 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2()); | |
477 HValue* kind = BuildDecodeField<Map::ElementsKindBits>(bit_field2); | |
478 | |
479 // Below we only check the upper bound of the relevant ranges to include both | |
480 // holey and non-holey versions. We check them in order smi, object, double | |
481 // since smi < object < double. | |
482 STATIC_ASSERT(FAST_SMI_ELEMENTS < FAST_HOLEY_SMI_ELEMENTS); | |
483 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS < FAST_HOLEY_ELEMENTS); | |
484 STATIC_ASSERT(FAST_ELEMENTS < FAST_HOLEY_ELEMENTS); | |
485 STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FAST_HOLEY_DOUBLE_ELEMENTS); | |
486 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FAST_HOLEY_DOUBLE_ELEMENTS); | |
487 IfBuilder has_smi_elements(this); | |
488 has_smi_elements.If<HCompareNumericAndBranch>( | |
489 kind, Add<HConstant>(FAST_HOLEY_SMI_ELEMENTS), Token::LTE); | |
490 has_smi_elements.Then(); | |
491 { | |
492 HValue* new_length = BuildPushElement(object, argc, argument_elements, | |
493 FAST_HOLEY_SMI_ELEMENTS); | |
494 environment()->Push(new_length); | |
495 } | |
496 has_smi_elements.Else(); | |
497 { | |
498 IfBuilder has_object_elements(this); | |
499 has_object_elements.If<HCompareNumericAndBranch>( | |
500 kind, Add<HConstant>(FAST_HOLEY_ELEMENTS), Token::LTE); | |
501 has_object_elements.Then(); | |
502 { | |
503 HValue* new_length = BuildPushElement(object, argc, argument_elements, | |
504 FAST_HOLEY_ELEMENTS); | |
505 environment()->Push(new_length); | |
506 } | |
507 has_object_elements.Else(); | |
508 { | |
509 IfBuilder has_double_elements(this); | |
510 has_double_elements.If<HCompareNumericAndBranch>( | |
511 kind, Add<HConstant>(FAST_HOLEY_DOUBLE_ELEMENTS), Token::LTE); | |
512 has_double_elements.Then(); | |
513 { | |
514 HValue* new_length = BuildPushElement(object, argc, argument_elements, | |
515 FAST_HOLEY_DOUBLE_ELEMENTS); | |
516 environment()->Push(new_length); | |
517 } | |
518 has_double_elements.ElseDeopt(DeoptimizeReason::kFastPathFailed); | |
519 has_double_elements.End(); | |
520 } | |
521 has_object_elements.End(); | |
522 } | |
523 has_smi_elements.End(); | |
524 | |
525 return environment()->Pop(); | |
526 } | |
527 | |
528 Handle<Code> FastArrayPushStub::GenerateCode() { return DoGenerateCode(this); } | |
529 | |
530 template <> | |
531 HValue* CodeStubGraphBuilder<FastFunctionBindStub>::BuildCodeStub() { | 379 HValue* CodeStubGraphBuilder<FastFunctionBindStub>::BuildCodeStub() { |
532 // TODO(verwaest): Fix deoptimizer messages. | 380 // TODO(verwaest): Fix deoptimizer messages. |
533 HValue* argc = GetArgumentsLength(); | 381 HValue* argc = GetArgumentsLength(); |
534 HInstruction* argument_elements = Add<HArgumentsElements>(false, false); | 382 HInstruction* argument_elements = Add<HArgumentsElements>(false, false); |
535 HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc, | 383 HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc, |
536 graph()->GetConstantMinus1()); | 384 graph()->GetConstantMinus1()); |
537 BuildCheckHeapObject(object); | 385 BuildCheckHeapObject(object); |
538 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap()); | 386 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap()); |
539 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_FUNCTION); | 387 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_FUNCTION); |
540 | 388 |
(...skipping 608 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1149 return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash); | 997 return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash); |
1150 } | 998 } |
1151 | 999 |
1152 | 1000 |
1153 Handle<Code> LoadDictionaryElementStub::GenerateCode() { | 1001 Handle<Code> LoadDictionaryElementStub::GenerateCode() { |
1154 return DoGenerateCode(this); | 1002 return DoGenerateCode(this); |
1155 } | 1003 } |
1156 | 1004 |
1157 } // namespace internal | 1005 } // namespace internal |
1158 } // namespace v8 | 1006 } // namespace v8 |
OLD | NEW |