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/interpreter/bytecode-generator.h" | 5 #include "src/interpreter/bytecode-generator.h" |
6 | 6 |
7 #include <stack> | 7 #include <stack> |
8 | 8 |
9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
10 #include "src/full-codegen/full-codegen.h" | |
rmcilroy
2015/10/13 09:13:14
This is only included for AccessorTable (it is als
Michael Starzinger
2015/10/13 11:06:44
Acknowledged. Works for me. As for moving it, if w
rmcilroy
2015/10/13 17:04:53
Sounds good, ast.h was what I was thinking too. I'
| |
10 #include "src/interpreter/control-flow-builders.h" | 11 #include "src/interpreter/control-flow-builders.h" |
11 #include "src/objects.h" | 12 #include "src/objects.h" |
12 #include "src/parser.h" | 13 #include "src/parser.h" |
13 #include "src/scopes.h" | 14 #include "src/scopes.h" |
14 #include "src/token.h" | 15 #include "src/token.h" |
15 | 16 |
16 namespace v8 { | 17 namespace v8 { |
17 namespace internal { | 18 namespace internal { |
18 namespace interpreter { | 19 namespace interpreter { |
19 | 20 |
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
490 } | 491 } |
491 } | 492 } |
492 | 493 |
493 | 494 |
494 void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 495 void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
495 UNIMPLEMENTED(); | 496 UNIMPLEMENTED(); |
496 } | 497 } |
497 | 498 |
498 | 499 |
499 void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 500 void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
500 UNIMPLEMENTED(); | 501 // Deep-copy the literal boilerplate. |
502 builder() | |
503 ->LoadLiteral(expr->constant_properties()) | |
504 .CreateObjectLiteral(expr->literal_index(), expr->ComputeFlags(true)); | |
505 | |
506 TemporaryRegisterScope temporary_register_scope(builder()); | |
507 Register literal; | |
508 | |
509 // Store computed values into the literal. | |
510 bool literal_in_accumulator = true; | |
511 int property_index = 0; | |
512 AccessorTable accessor_table(zone()); | |
513 for (; property_index < expr->properties()->length(); property_index++) { | |
514 TemporaryRegisterScope inner_temporary_register_scope(builder()); | |
515 ObjectLiteral::Property* property = expr->properties()->at(property_index); | |
516 if (property->is_computed_name()) break; | |
517 if (property->IsCompileTimeValue()) continue; | |
518 | |
519 if (literal_in_accumulator) { | |
520 literal = temporary_register_scope.NewRegister(); | |
521 builder()->StoreAccumulatorInRegister(literal); | |
522 literal_in_accumulator = false; | |
523 } | |
524 | |
525 Literal* literal_key = property->key()->AsLiteral(); | |
526 switch (property->kind()) { | |
527 case ObjectLiteral::Property::CONSTANT: | |
528 UNREACHABLE(); | |
529 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | |
530 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value())); | |
531 // Fall through. | |
532 case ObjectLiteral::Property::COMPUTED: { | |
533 // It is safe to use [[Put]] here because the boilerplate already | |
534 // contains computed properties with an uninitialized value. | |
535 if (literal_key->value()->IsInternalizedString()) { | |
536 if (property->emit_store()) { | |
537 Register name = inner_temporary_register_scope.NewRegister(); | |
538 builder() | |
539 ->LoadLiteral(literal_key->AsPropertyName()) | |
540 .StoreAccumulatorInRegister(name); | |
541 Visit(property->value()); | |
542 builder()->StoreNamedProperty(literal, name, | |
543 feedback_index(property->GetSlot(0)), | |
544 language_mode()); | |
545 } else { | |
546 Visit(property->value()); | |
547 } | |
548 } else { | |
549 Register key = inner_temporary_register_scope.NewRegister(); | |
550 Register value = inner_temporary_register_scope.NewRegister(); | |
551 Register language = inner_temporary_register_scope.NewRegister(); | |
552 DCHECK(Register::AreContiguous(literal, key, value, language)); | |
553 Visit(property->key()); | |
554 builder()->StoreAccumulatorInRegister(key); | |
555 Visit(property->value()); | |
556 builder()->StoreAccumulatorInRegister(value); | |
557 if (property->emit_store()) { | |
558 builder() | |
559 ->LoadLiteral(Smi::FromInt(SLOPPY)) | |
560 .StoreAccumulatorInRegister(language) | |
561 .CallRuntime(Runtime::kSetProperty, literal, 4); | |
562 VisitSetHomeObject(value, literal, property); | |
563 } | |
564 } | |
565 break; | |
566 } | |
567 case ObjectLiteral::Property::PROTOTYPE: { | |
568 DCHECK(property->emit_store()); | |
569 Register value = inner_temporary_register_scope.NewRegister(); | |
570 DCHECK(Register::AreContiguous(literal, value)); | |
571 Visit(property->value()); | |
572 builder()->StoreAccumulatorInRegister(value).CallRuntime( | |
573 Runtime::kInternalSetPrototype, literal, 2); | |
574 break; | |
575 } | |
576 case ObjectLiteral::Property::GETTER: | |
577 if (property->emit_store()) { | |
578 accessor_table.lookup(literal_key)->second->getter = property; | |
579 } | |
580 break; | |
581 case ObjectLiteral::Property::SETTER: | |
582 if (property->emit_store()) { | |
583 accessor_table.lookup(literal_key)->second->setter = property; | |
584 } | |
585 break; | |
586 } | |
587 } | |
588 | |
589 // Create nodes to define accessors, using only a single call to the runtime | |
590 // for each pair of corresponding getters and setters. | |
591 for (AccessorTable::Iterator it = accessor_table.begin(); | |
592 it != accessor_table.end(); ++it) { | |
593 TemporaryRegisterScope inner_temporary_register_scope(builder()); | |
594 Register name = inner_temporary_register_scope.NewRegister(); | |
595 Register getter = inner_temporary_register_scope.NewRegister(); | |
596 Register setter = inner_temporary_register_scope.NewRegister(); | |
597 Register attr = inner_temporary_register_scope.NewRegister(); | |
598 DCHECK(Register::AreContiguous(literal, name, getter, setter, attr)); | |
599 Visit(it->first); | |
600 builder()->StoreAccumulatorInRegister(name); | |
601 VisitObjectLiteralAccessor(literal, it->second->getter, getter); | |
602 VisitObjectLiteralAccessor(literal, it->second->setter, setter); | |
603 builder() | |
604 ->LoadLiteral(Smi::FromInt(NONE)) | |
605 .StoreAccumulatorInRegister(attr) | |
606 .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, literal, 5); | |
607 } | |
608 | |
609 // Object literals have two parts. The "static" part on the left contains no | |
610 // computed property names, and so we can compute its map ahead of time; see | |
611 // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts | |
612 // with the first computed property name and continues with all properties to | |
613 // its right. All the code from above initializes the static component of the | |
614 // object literal, and arranges for the map of the result to reflect the | |
615 // static order in which the keys appear. For the dynamic properties, we | |
616 // compile them into a series of "SetOwnProperty" runtime calls. This will | |
617 // preserve insertion order. | |
618 for (; property_index < expr->properties()->length(); property_index++) { | |
619 ObjectLiteral::Property* property = expr->properties()->at(property_index); | |
620 | |
621 if (literal_in_accumulator) { | |
622 literal = temporary_register_scope.NewRegister(); | |
623 builder()->StoreAccumulatorInRegister(literal); | |
624 literal_in_accumulator = false; | |
625 } | |
626 | |
627 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) { | |
628 DCHECK(property->emit_store()); | |
629 TemporaryRegisterScope inner_temporary_register_scope(builder()); | |
630 Register value = inner_temporary_register_scope.NewRegister(); | |
631 DCHECK(Register::AreContiguous(literal, value)); | |
632 Visit(property->value()); | |
633 builder()->StoreAccumulatorInRegister(value).CallRuntime( | |
634 Runtime::kInternalSetPrototype, literal, 2); | |
635 continue; | |
636 } | |
637 | |
638 TemporaryRegisterScope inner_temporary_register_scope(builder()); | |
639 Register key = inner_temporary_register_scope.NewRegister(); | |
640 Register value = inner_temporary_register_scope.NewRegister(); | |
641 Register attr = inner_temporary_register_scope.NewRegister(); | |
642 DCHECK(Register::AreContiguous(literal, key, value, attr)); | |
643 | |
644 Visit(property->key()); | |
645 builder()->CastAccumulatorToName().StoreAccumulatorInRegister(key); | |
646 Visit(property->value()); | |
647 builder()->StoreAccumulatorInRegister(value); | |
648 VisitSetHomeObject(value, literal, property); | |
649 builder()->LoadLiteral(Smi::FromInt(NONE)).StoreAccumulatorInRegister(attr); | |
650 Runtime::FunctionId function_id = static_cast<Runtime::FunctionId>(-1); | |
651 switch (property->kind()) { | |
652 case ObjectLiteral::Property::CONSTANT: | |
653 case ObjectLiteral::Property::COMPUTED: | |
654 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | |
655 function_id = Runtime::kDefineDataPropertyUnchecked; | |
656 break; | |
657 case ObjectLiteral::Property::PROTOTYPE: | |
658 UNREACHABLE(); // Handled specially above. | |
659 break; | |
660 case ObjectLiteral::Property::GETTER: | |
661 function_id = Runtime::kDefineGetterPropertyUnchecked; | |
662 break; | |
663 case ObjectLiteral::Property::SETTER: | |
664 function_id = Runtime::kDefineSetterPropertyUnchecked; | |
665 break; | |
666 } | |
667 builder()->CallRuntime(function_id, literal, 4); | |
668 } | |
669 | |
670 // Transform literals that contain functions to fast properties. | |
671 if (expr->has_function()) { | |
672 DCHECK(!literal_in_accumulator); | |
673 builder()->CallRuntime(Runtime::kToFastProperties, literal, 1); | |
674 } | |
675 | |
676 if (!literal_in_accumulator) { | |
677 // Restore literal array into accumulator. | |
678 builder()->LoadAccumulatorWithRegister(literal); | |
679 } | |
501 } | 680 } |
502 | 681 |
503 | 682 |
504 void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 683 void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
505 // Deep-copy the literal boilerplate. | 684 // Deep-copy the literal boilerplate. |
506 expr->BuildConstantElements(isolate()); | 685 expr->BuildConstantElements(isolate()); |
507 builder() | 686 builder() |
508 ->LoadLiteral(expr->constant_elements()) | 687 ->LoadLiteral(expr->constant_elements()) |
509 .CreateArrayLiteral(expr->literal_index(), expr->ComputeFlags(true)); | 688 .CreateArrayLiteral(expr->literal_index(), expr->ComputeFlags(true)); |
510 | 689 |
511 TemporaryRegisterScope temporary_register_scope(builder()); | 690 TemporaryRegisterScope temporary_register_scope(builder()); |
512 Register index, literal_array; | 691 Register index, literal; |
513 | 692 |
514 // Create nodes to evaluate all the non-constant subexpressions and to store | 693 // Create nodes to evaluate all the non-constant subexpressions and to store |
515 // them into the newly cloned array. | 694 // them into the newly cloned array. |
516 bool literal_array_in_accumulator = true; | 695 bool literal_in_accumulator = true; |
517 for (int array_index = 0; array_index < expr->values()->length(); | 696 for (int array_index = 0; array_index < expr->values()->length(); |
518 array_index++) { | 697 array_index++) { |
519 Expression* subexpr = expr->values()->at(array_index); | 698 Expression* subexpr = expr->values()->at(array_index); |
520 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; | 699 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; |
521 if (subexpr->IsSpread()) { | 700 if (subexpr->IsSpread()) { |
522 // TODO(rmcilroy): Deal with spread expressions. | 701 // TODO(rmcilroy): Deal with spread expressions. |
523 UNIMPLEMENTED(); | 702 UNIMPLEMENTED(); |
524 } | 703 } |
525 | 704 |
526 if (literal_array_in_accumulator) { | 705 if (literal_in_accumulator) { |
527 index = temporary_register_scope.NewRegister(); | 706 index = temporary_register_scope.NewRegister(); |
528 literal_array = temporary_register_scope.NewRegister(); | 707 literal = temporary_register_scope.NewRegister(); |
529 builder()->StoreAccumulatorInRegister(literal_array); | 708 builder()->StoreAccumulatorInRegister(literal); |
530 literal_array_in_accumulator = false; | 709 literal_in_accumulator = false; |
531 } | 710 } |
532 | 711 |
533 builder() | 712 builder() |
534 ->LoadLiteral(Smi::FromInt(array_index)) | 713 ->LoadLiteral(Smi::FromInt(array_index)) |
535 .StoreAccumulatorInRegister(index); | 714 .StoreAccumulatorInRegister(index); |
536 Visit(subexpr); | 715 Visit(subexpr); |
537 builder()->GenericStoreKeyedProperty(literal_array, index); | 716 builder()->GenericStoreKeyedProperty(literal, index); |
538 } | 717 } |
539 | 718 |
540 if (!literal_array_in_accumulator) { | 719 if (!literal_in_accumulator) { |
541 // Restore literal array into accumulator. | 720 // Restore literal array into accumulator. |
542 builder()->LoadAccumulatorWithRegister(literal_array); | 721 builder()->LoadAccumulatorWithRegister(literal); |
543 } | 722 } |
544 } | 723 } |
545 | 724 |
546 | 725 |
547 void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { | 726 void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { |
548 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); | 727 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); |
549 } | 728 } |
550 | 729 |
551 | 730 |
552 void BytecodeGenerator::VisitVariableLoad(Variable* variable, | 731 void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
930 | 1109 |
931 | 1110 |
932 void BytecodeGenerator::VisitNewLocalFunctionContext() { | 1111 void BytecodeGenerator::VisitNewLocalFunctionContext() { |
933 Scope* scope = this->scope(); | 1112 Scope* scope = this->scope(); |
934 | 1113 |
935 // Allocate a new local context. | 1114 // Allocate a new local context. |
936 if (scope->is_script_scope()) { | 1115 if (scope->is_script_scope()) { |
937 TemporaryRegisterScope temporary_register_scope(builder()); | 1116 TemporaryRegisterScope temporary_register_scope(builder()); |
938 Register closure = temporary_register_scope.NewRegister(); | 1117 Register closure = temporary_register_scope.NewRegister(); |
939 Register scope_info = temporary_register_scope.NewRegister(); | 1118 Register scope_info = temporary_register_scope.NewRegister(); |
940 DCHECK_EQ(closure.index() + 1, scope_info.index()); | 1119 DCHECK(Register::AreContiguous(closure, scope_info)); |
941 builder() | 1120 builder() |
942 ->LoadAccumulatorWithRegister(Register::function_closure()) | 1121 ->LoadAccumulatorWithRegister(Register::function_closure()) |
943 .StoreAccumulatorInRegister(closure) | 1122 .StoreAccumulatorInRegister(closure) |
944 .LoadLiteral(scope->GetScopeInfo(isolate())) | 1123 .LoadLiteral(scope->GetScopeInfo(isolate())) |
945 .StoreAccumulatorInRegister(scope_info) | 1124 .StoreAccumulatorInRegister(scope_info) |
946 .CallRuntime(Runtime::kNewScriptContext, closure, 2); | 1125 .CallRuntime(Runtime::kNewScriptContext, closure, 2); |
947 } else { | 1126 } else { |
948 builder()->CallRuntime(Runtime::kNewFunctionContext, | 1127 builder()->CallRuntime(Runtime::kNewFunctionContext, |
949 Register::function_closure(), 1); | 1128 Register::function_closure(), 1); |
950 } | 1129 } |
(...skipping 21 matching lines...) Expand all Loading... | |
972 TemporaryRegisterScope temporary_register_scope(builder()); | 1151 TemporaryRegisterScope temporary_register_scope(builder()); |
973 Register temporary = temporary_register_scope.NewRegister(); | 1152 Register temporary = temporary_register_scope.NewRegister(); |
974 | 1153 |
975 Visit(left); | 1154 Visit(left); |
976 builder()->StoreAccumulatorInRegister(temporary); | 1155 builder()->StoreAccumulatorInRegister(temporary); |
977 Visit(right); | 1156 Visit(right); |
978 builder()->BinaryOperation(op, temporary, language_mode_strength()); | 1157 builder()->BinaryOperation(op, temporary, language_mode_strength()); |
979 } | 1158 } |
980 | 1159 |
981 | 1160 |
1161 void BytecodeGenerator::VisitObjectLiteralAccessor( | |
1162 Register home_object, ObjectLiteralProperty* property, Register value_out) { | |
1163 // TODO(rmcilroy): Replace value_out with VisitForRegister(); | |
1164 if (property == nullptr) { | |
1165 builder()->LoadNull().StoreAccumulatorInRegister(value_out); | |
1166 } else { | |
1167 Visit(property->value()); | |
1168 builder()->StoreAccumulatorInRegister(value_out); | |
1169 VisitSetHomeObject(value_out, home_object, property); | |
1170 } | |
1171 } | |
1172 | |
1173 | |
1174 void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object, | |
1175 ObjectLiteralProperty* property, | |
1176 int slot_number) { | |
1177 Expression* expr = property->value(); | |
1178 if (!FunctionLiteral::NeedsHomeObject(expr)) return; | |
1179 | |
1180 // TODO(rmcilroy): Remove UNIMPLEMENTED once we have tests for setting the | |
1181 // home object. | |
1182 UNIMPLEMENTED(); | |
1183 | |
1184 TemporaryRegisterScope temporary_register_scope(builder()); | |
1185 Register name = temporary_register_scope.NewRegister(); | |
1186 isolate()->factory()->home_object_symbol(); | |
1187 builder() | |
1188 ->LoadLiteral(isolate()->factory()->home_object_symbol()) | |
1189 .StoreAccumulatorInRegister(name) | |
1190 .StoreNamedProperty(home_object, name, | |
1191 feedback_index(property->GetSlot(slot_number)), | |
1192 language_mode()); | |
1193 } | |
1194 | |
1195 | |
982 LanguageMode BytecodeGenerator::language_mode() const { | 1196 LanguageMode BytecodeGenerator::language_mode() const { |
983 return info()->language_mode(); | 1197 return info()->language_mode(); |
984 } | 1198 } |
985 | 1199 |
986 | 1200 |
987 Strength BytecodeGenerator::language_mode_strength() const { | 1201 Strength BytecodeGenerator::language_mode_strength() const { |
988 return strength(language_mode()); | 1202 return strength(language_mode()); |
989 } | 1203 } |
990 | 1204 |
991 | 1205 |
992 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 1206 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
993 return info()->feedback_vector()->GetIndex(slot); | 1207 return info()->feedback_vector()->GetIndex(slot); |
994 } | 1208 } |
995 | 1209 |
996 } // namespace interpreter | 1210 } // namespace interpreter |
997 } // namespace internal | 1211 } // namespace internal |
998 } // namespace v8 | 1212 } // namespace v8 |
OLD | NEW |