OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
11 // with the distribution. | 11 // with the distribution. |
12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
15 // | 15 // |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
| 30 #if defined(V8_TARGET_ARCH_ARM) |
| 31 |
30 #include "codegen-inl.h" | 32 #include "codegen-inl.h" |
31 #include "compiler.h" | 33 #include "compiler.h" |
32 #include "debug.h" | 34 #include "debug.h" |
33 #include "full-codegen.h" | 35 #include "full-codegen.h" |
34 #include "parser.h" | 36 #include "parser.h" |
35 #include "scopes.h" | 37 #include "scopes.h" |
36 | 38 |
37 namespace v8 { | 39 namespace v8 { |
38 namespace internal { | 40 namespace internal { |
39 | 41 |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 case Expression::kUninitialized: | 392 case Expression::kUninitialized: |
391 | 393 |
392 case Expression::kEffect: | 394 case Expression::kEffect: |
393 ASSERT_EQ(materialize_true, materialize_false); | 395 ASSERT_EQ(materialize_true, materialize_false); |
394 __ bind(materialize_true); | 396 __ bind(materialize_true); |
395 break; | 397 break; |
396 | 398 |
397 case Expression::kValue: { | 399 case Expression::kValue: { |
398 Label done; | 400 Label done; |
399 __ bind(materialize_true); | 401 __ bind(materialize_true); |
400 __ mov(result_register(), Operand(Factory::true_value())); | 402 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex); |
401 __ jmp(&done); | 403 __ jmp(&done); |
402 __ bind(materialize_false); | 404 __ bind(materialize_false); |
403 __ mov(result_register(), Operand(Factory::false_value())); | 405 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex); |
404 __ bind(&done); | 406 __ bind(&done); |
405 switch (location_) { | 407 switch (location_) { |
406 case kAccumulator: | 408 case kAccumulator: |
407 break; | 409 break; |
408 case kStack: | 410 case kStack: |
409 __ push(result_register()); | 411 __ push(result_register()); |
410 break; | 412 break; |
411 } | 413 } |
412 break; | 414 break; |
413 } | 415 } |
414 | 416 |
415 case Expression::kTest: | 417 case Expression::kTest: |
416 break; | 418 break; |
417 | 419 |
418 case Expression::kValueTest: | 420 case Expression::kValueTest: |
419 __ bind(materialize_true); | 421 __ bind(materialize_true); |
420 __ mov(result_register(), Operand(Factory::true_value())); | 422 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex); |
421 switch (location_) { | 423 switch (location_) { |
422 case kAccumulator: | 424 case kAccumulator: |
423 break; | 425 break; |
424 case kStack: | 426 case kStack: |
425 __ push(result_register()); | 427 __ push(result_register()); |
426 break; | 428 break; |
427 } | 429 } |
428 __ jmp(true_label_); | 430 __ jmp(true_label_); |
429 break; | 431 break; |
430 | 432 |
431 case Expression::kTestValue: | 433 case Expression::kTestValue: |
432 __ bind(materialize_false); | 434 __ bind(materialize_false); |
433 __ mov(result_register(), Operand(Factory::false_value())); | 435 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex); |
434 switch (location_) { | 436 switch (location_) { |
435 case kAccumulator: | 437 case kAccumulator: |
436 break; | 438 break; |
437 case kStack: | 439 case kStack: |
438 __ push(result_register()); | 440 __ push(result_register()); |
439 break; | 441 break; |
440 } | 442 } |
441 __ jmp(false_label_); | 443 __ jmp(false_label_); |
442 break; | 444 break; |
443 } | 445 } |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
633 VisitForValue(prop->obj(), kStack); | 635 VisitForValue(prop->obj(), kStack); |
634 VisitForValue(prop->key(), kStack); | 636 VisitForValue(prop->key(), kStack); |
635 | 637 |
636 if (decl->fun() != NULL) { | 638 if (decl->fun() != NULL) { |
637 VisitForValue(decl->fun(), kAccumulator); | 639 VisitForValue(decl->fun(), kAccumulator); |
638 } else { | 640 } else { |
639 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex); | 641 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex); |
640 } | 642 } |
641 | 643 |
642 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 644 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 645 __ pop(r1); // Key. |
| 646 __ pop(r2); // Receiver. |
643 __ Call(ic, RelocInfo::CODE_TARGET); | 647 __ Call(ic, RelocInfo::CODE_TARGET); |
644 | 648 |
645 // Value in r0 is ignored (declarations are statements). Receiver | 649 // Value in r0 is ignored (declarations are statements). |
646 // and key on stack are discarded. | |
647 __ Drop(2); | |
648 } | 650 } |
649 } | 651 } |
650 } | 652 } |
651 | 653 |
652 | 654 |
653 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 655 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
654 // Call the runtime to declare the globals. | 656 // Call the runtime to declare the globals. |
655 // The context is the first argument. | 657 // The context is the first argument. |
656 __ mov(r1, Operand(pairs)); | 658 __ mov(r1, Operand(pairs)); |
657 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); | 659 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); |
658 __ stm(db_w, sp, cp.bit() | r1.bit() | r0.bit()); | 660 __ stm(db_w, sp, cp.bit() | r1.bit() | r0.bit()); |
659 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 661 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
660 // Return value is ignored. | 662 // Return value is ignored. |
661 } | 663 } |
662 | 664 |
663 | 665 |
664 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 666 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
665 Comment cmnt(masm_, "[ FunctionLiteral"); | 667 UNREACHABLE(); |
| 668 } |
666 | 669 |
667 // Build the shared function info and instantiate the function based | |
668 // on it. | |
669 Handle<SharedFunctionInfo> function_info = | |
670 Compiler::BuildFunctionInfo(expr, script(), this); | |
671 if (HasStackOverflow()) return; | |
672 | 670 |
673 // Create a new closure. | 671 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
674 __ mov(r0, Operand(function_info)); | 672 UNREACHABLE(); |
675 __ stm(db_w, sp, cp.bit() | r0.bit()); | 673 } |
676 __ CallRuntime(Runtime::kNewClosure, 2); | 674 |
| 675 |
| 676 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) { |
| 677 // Use the fast case closure allocation code that allocates in new |
| 678 // space for nested functions that don't need literals cloning. |
| 679 if (scope()->is_function_scope() && info->num_literals() == 0) { |
| 680 FastNewClosureStub stub; |
| 681 __ mov(r0, Operand(info)); |
| 682 __ push(r0); |
| 683 __ CallStub(&stub); |
| 684 } else { |
| 685 __ mov(r0, Operand(info)); |
| 686 __ stm(db_w, sp, cp.bit() | r0.bit()); |
| 687 __ CallRuntime(Runtime::kNewClosure, 2); |
| 688 } |
677 Apply(context_, r0); | 689 Apply(context_, r0); |
678 } | 690 } |
679 | 691 |
680 | 692 |
681 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 693 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
682 Comment cmnt(masm_, "[ VariableProxy"); | 694 Comment cmnt(masm_, "[ VariableProxy"); |
683 EmitVariableLoad(expr->var(), context_); | 695 EmitVariableLoad(expr->var(), context_); |
684 } | 696 } |
685 | 697 |
686 | 698 |
687 void FullCodeGenerator::EmitVariableLoad(Variable* var, | 699 void FullCodeGenerator::EmitVariableLoad(Variable* var, |
688 Expression::Context context) { | 700 Expression::Context context) { |
689 // Four cases: non-this global variables, lookup slots, all other | 701 // Four cases: non-this global variables, lookup slots, all other |
690 // types of slots, and parameters that rewrite to explicit property | 702 // types of slots, and parameters that rewrite to explicit property |
691 // accesses on the arguments object. | 703 // accesses on the arguments object. |
692 Slot* slot = var->slot(); | 704 Slot* slot = var->slot(); |
693 Property* property = var->AsProperty(); | 705 Property* property = var->AsProperty(); |
694 | 706 |
695 if (var->is_global() && !var->is_this()) { | 707 if (var->is_global() && !var->is_this()) { |
696 Comment cmnt(masm_, "Global variable"); | 708 Comment cmnt(masm_, "Global variable"); |
697 // Use inline caching. Variable name is passed in r2 and the global | 709 // Use inline caching. Variable name is passed in r2 and the global |
698 // object on the stack. | 710 // object (receiver) in r0. |
699 __ ldr(r0, CodeGenerator::GlobalObject()); | 711 __ ldr(r0, CodeGenerator::GlobalObject()); |
700 __ push(r0); | |
701 __ mov(r2, Operand(var->name())); | 712 __ mov(r2, Operand(var->name())); |
702 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 713 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
703 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 714 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
704 DropAndApply(1, context, r0); | 715 Apply(context, r0); |
705 | 716 |
706 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 717 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
707 Comment cmnt(masm_, "Lookup slot"); | 718 Comment cmnt(masm_, "Lookup slot"); |
708 __ mov(r1, Operand(var->name())); | 719 __ mov(r1, Operand(var->name())); |
709 __ stm(db_w, sp, cp.bit() | r1.bit()); // Context and name. | 720 __ stm(db_w, sp, cp.bit() | r1.bit()); // Context and name. |
710 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 721 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
711 Apply(context, r0); | 722 Apply(context, r0); |
712 | 723 |
713 } else if (slot != NULL) { | 724 } else if (slot != NULL) { |
714 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 725 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
897 if (result_saved) { | 908 if (result_saved) { |
898 ApplyTOS(context_); | 909 ApplyTOS(context_); |
899 } else { | 910 } else { |
900 Apply(context_, r0); | 911 Apply(context_, r0); |
901 } | 912 } |
902 } | 913 } |
903 | 914 |
904 | 915 |
905 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 916 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
906 Comment cmnt(masm_, "[ Assignment"); | 917 Comment cmnt(masm_, "[ Assignment"); |
907 ASSERT(expr->op() != Token::INIT_CONST); | 918 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 919 // on the left-hand side. |
| 920 if (!expr->target()->IsValidLeftHandSide()) { |
| 921 VisitForEffect(expr->target()); |
| 922 return; |
| 923 } |
| 924 |
908 // Left-hand side can only be a property, a global or a (parameter or local) | 925 // Left-hand side can only be a property, a global or a (parameter or local) |
909 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 926 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
910 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 927 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
911 LhsKind assign_type = VARIABLE; | 928 LhsKind assign_type = VARIABLE; |
912 Property* prop = expr->target()->AsProperty(); | 929 Property* prop = expr->target()->AsProperty(); |
913 if (prop != NULL) { | 930 if (prop != NULL) { |
914 assign_type = | 931 assign_type = |
915 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 932 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
916 } | 933 } |
917 | 934 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
977 location_ = saved_location; | 994 location_ = saved_location; |
978 } | 995 } |
979 | 996 |
980 // Record source position before possible IC call. | 997 // Record source position before possible IC call. |
981 SetSourcePosition(expr->position()); | 998 SetSourcePosition(expr->position()); |
982 | 999 |
983 // Store the value. | 1000 // Store the value. |
984 switch (assign_type) { | 1001 switch (assign_type) { |
985 case VARIABLE: | 1002 case VARIABLE: |
986 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), | 1003 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), |
| 1004 expr->op(), |
987 context_); | 1005 context_); |
988 break; | 1006 break; |
989 case NAMED_PROPERTY: | 1007 case NAMED_PROPERTY: |
990 EmitNamedPropertyAssignment(expr); | 1008 EmitNamedPropertyAssignment(expr); |
991 break; | 1009 break; |
992 case KEYED_PROPERTY: | 1010 case KEYED_PROPERTY: |
993 EmitKeyedPropertyAssignment(expr); | 1011 EmitKeyedPropertyAssignment(expr); |
994 break; | 1012 break; |
995 } | 1013 } |
996 } | 1014 } |
997 | 1015 |
998 | 1016 |
999 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { | 1017 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
1000 SetSourcePosition(prop->position()); | 1018 SetSourcePosition(prop->position()); |
1001 Literal* key = prop->key()->AsLiteral(); | 1019 Literal* key = prop->key()->AsLiteral(); |
1002 __ mov(r2, Operand(key->handle())); | 1020 __ mov(r2, Operand(key->handle())); |
1003 __ ldr(r0, MemOperand(sp, 0)); | 1021 // Call load IC. It has arguments receiver and property name r0 and r2. |
1004 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1022 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
1005 __ Call(ic, RelocInfo::CODE_TARGET); | 1023 __ Call(ic, RelocInfo::CODE_TARGET); |
1006 } | 1024 } |
1007 | 1025 |
1008 | 1026 |
1009 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 1027 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
1010 SetSourcePosition(prop->position()); | 1028 SetSourcePosition(prop->position()); |
1011 // Call keyed load IC. It has arguments key and receiver in r0 and r1. | 1029 // Call keyed load IC. It has arguments key and receiver in r0 and r1. |
1012 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1030 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
1013 __ Call(ic, RelocInfo::CODE_TARGET); | 1031 __ Call(ic, RelocInfo::CODE_TARGET); |
1014 } | 1032 } |
1015 | 1033 |
1016 | 1034 |
1017 void FullCodeGenerator::EmitBinaryOp(Token::Value op, | 1035 void FullCodeGenerator::EmitBinaryOp(Token::Value op, |
1018 Expression::Context context) { | 1036 Expression::Context context) { |
1019 __ pop(r1); | 1037 __ pop(r1); |
1020 GenericBinaryOpStub stub(op, NO_OVERWRITE, r1, r0); | 1038 GenericBinaryOpStub stub(op, NO_OVERWRITE, r1, r0); |
1021 __ CallStub(&stub); | 1039 __ CallStub(&stub); |
1022 Apply(context, r0); | 1040 Apply(context, r0); |
1023 } | 1041 } |
1024 | 1042 |
1025 | 1043 |
1026 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1044 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1045 Token::Value op, |
1027 Expression::Context context) { | 1046 Expression::Context context) { |
1028 // Three main cases: global variables, lookup slots, and all other | 1047 // Left-hand sides that rewrite to explicit property accesses do not reach |
1029 // types of slots. Left-hand-side parameters that rewrite to | 1048 // here. |
1030 // explicit property accesses do not reach here. | |
1031 ASSERT(var != NULL); | 1049 ASSERT(var != NULL); |
1032 ASSERT(var->is_global() || var->slot() != NULL); | 1050 ASSERT(var->is_global() || var->slot() != NULL); |
1033 | 1051 |
1034 Slot* slot = var->slot(); | |
1035 if (var->is_global()) { | 1052 if (var->is_global()) { |
1036 ASSERT(!var->is_this()); | 1053 ASSERT(!var->is_this()); |
1037 // Assignment to a global variable. Use inline caching for the | 1054 // Assignment to a global variable. Use inline caching for the |
1038 // assignment. Right-hand-side value is passed in r0, variable name in | 1055 // assignment. Right-hand-side value is passed in r0, variable name in |
1039 // r2, and the global object in r1. | 1056 // r2, and the global object in r1. |
1040 __ mov(r2, Operand(var->name())); | 1057 __ mov(r2, Operand(var->name())); |
1041 __ ldr(r1, CodeGenerator::GlobalObject()); | 1058 __ ldr(r1, CodeGenerator::GlobalObject()); |
1042 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1059 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
1043 __ Call(ic, RelocInfo::CODE_TARGET); | 1060 __ Call(ic, RelocInfo::CODE_TARGET); |
1044 | 1061 |
1045 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1062 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { |
1046 __ push(result_register()); // Value. | 1063 // Perform the assignment for non-const variables and for initialization |
1047 __ mov(r1, Operand(var->name())); | 1064 // of const variables. Const assignments are simply skipped. |
1048 __ stm(db_w, sp, cp.bit() | r1.bit()); // Context and name. | 1065 Label done; |
1049 __ CallRuntime(Runtime::kStoreContextSlot, 3); | |
1050 | |
1051 } else if (var->slot() != NULL) { | |
1052 Slot* slot = var->slot(); | 1066 Slot* slot = var->slot(); |
1053 switch (slot->type()) { | 1067 switch (slot->type()) { |
| 1068 case Slot::PARAMETER: |
1054 case Slot::LOCAL: | 1069 case Slot::LOCAL: |
1055 case Slot::PARAMETER: | 1070 if (op == Token::INIT_CONST) { |
| 1071 // Detect const reinitialization by checking for the hole value. |
| 1072 __ ldr(r1, MemOperand(fp, SlotOffset(slot))); |
| 1073 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 1074 __ cmp(r1, ip); |
| 1075 __ b(ne, &done); |
| 1076 } |
| 1077 // Perform the assignment. |
1056 __ str(result_register(), MemOperand(fp, SlotOffset(slot))); | 1078 __ str(result_register(), MemOperand(fp, SlotOffset(slot))); |
1057 break; | 1079 break; |
1058 | 1080 |
1059 case Slot::CONTEXT: { | 1081 case Slot::CONTEXT: { |
1060 MemOperand target = EmitSlotSearch(slot, r1); | 1082 MemOperand target = EmitSlotSearch(slot, r1); |
| 1083 if (op == Token::INIT_CONST) { |
| 1084 // Detect const reinitialization by checking for the hole value. |
| 1085 __ ldr(r1, target); |
| 1086 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 1087 __ cmp(r1, ip); |
| 1088 __ b(ne, &done); |
| 1089 } |
| 1090 // Perform the assignment and issue the write barrier. |
1061 __ str(result_register(), target); | 1091 __ str(result_register(), target); |
1062 | |
1063 // RecordWrite may destroy all its register arguments. | 1092 // RecordWrite may destroy all its register arguments. |
1064 __ mov(r3, result_register()); | 1093 __ mov(r3, result_register()); |
1065 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 1094 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
1066 | |
1067 __ mov(r2, Operand(offset)); | 1095 __ mov(r2, Operand(offset)); |
1068 __ RecordWrite(r1, r2, r3); | 1096 __ RecordWrite(r1, r2, r3); |
1069 break; | 1097 break; |
1070 } | 1098 } |
1071 | 1099 |
1072 case Slot::LOOKUP: | 1100 case Slot::LOOKUP: |
1073 UNREACHABLE(); | 1101 // Call the runtime for the assignment. The runtime will ignore |
| 1102 // const reinitialization. |
| 1103 __ push(r0); // Value. |
| 1104 __ mov(r0, Operand(slot->var()->name())); |
| 1105 __ Push(cp, r0); // Context and name. |
| 1106 if (op == Token::INIT_CONST) { |
| 1107 // The runtime will ignore const redeclaration. |
| 1108 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 1109 } else { |
| 1110 __ CallRuntime(Runtime::kStoreContextSlot, 3); |
| 1111 } |
1074 break; | 1112 break; |
1075 } | 1113 } |
| 1114 __ bind(&done); |
| 1115 } |
1076 | 1116 |
1077 } else { | |
1078 // Variables rewritten as properties are not treated as variables in | |
1079 // assignments. | |
1080 UNREACHABLE(); | |
1081 } | |
1082 Apply(context, result_register()); | 1117 Apply(context, result_register()); |
1083 } | 1118 } |
1084 | 1119 |
1085 | 1120 |
1086 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1121 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
1087 // Assignment to a property, using a named store IC. | 1122 // Assignment to a property, using a named store IC. |
1088 Property* prop = expr->target()->AsProperty(); | 1123 Property* prop = expr->target()->AsProperty(); |
1089 ASSERT(prop != NULL); | 1124 ASSERT(prop != NULL); |
1090 ASSERT(prop->key()->AsLiteral() != NULL); | 1125 ASSERT(prop->key()->AsLiteral() != NULL); |
1091 | 1126 |
1092 // If the assignment starts a block of assignments to the same object, | 1127 // If the assignment starts a block of assignments to the same object, |
1093 // change to slow case to avoid the quadratic behavior of repeatedly | 1128 // change to slow case to avoid the quadratic behavior of repeatedly |
1094 // adding fast properties. | 1129 // adding fast properties. |
1095 if (expr->starts_initialization_block()) { | 1130 if (expr->starts_initialization_block()) { |
1096 __ push(result_register()); | 1131 __ push(result_register()); |
1097 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is now under value. | 1132 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is now under value. |
1098 __ push(ip); | 1133 __ push(ip); |
1099 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1134 __ CallRuntime(Runtime::kToSlowProperties, 1); |
1100 __ pop(result_register()); | 1135 __ pop(result_register()); |
1101 } | 1136 } |
1102 | 1137 |
1103 // Record source code position before IC call. | 1138 // Record source code position before IC call. |
1104 SetSourcePosition(expr->position()); | 1139 SetSourcePosition(expr->position()); |
1105 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); | 1140 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); |
| 1141 // Load receiver to r1. Leave a copy in the stack if needed for turning the |
| 1142 // receiver into fast case. |
1106 if (expr->ends_initialization_block()) { | 1143 if (expr->ends_initialization_block()) { |
1107 __ ldr(r1, MemOperand(sp)); | 1144 __ ldr(r1, MemOperand(sp)); |
1108 } else { | 1145 } else { |
1109 __ pop(r1); | 1146 __ pop(r1); |
1110 } | 1147 } |
1111 | 1148 |
1112 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1149 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
1113 __ Call(ic, RelocInfo::CODE_TARGET); | 1150 __ Call(ic, RelocInfo::CODE_TARGET); |
1114 | 1151 |
1115 // If the assignment ends an initialization block, revert to fast case. | 1152 // If the assignment ends an initialization block, revert to fast case. |
1116 if (expr->ends_initialization_block()) { | 1153 if (expr->ends_initialization_block()) { |
1117 __ push(r0); // Result of assignment, saved even if not needed. | 1154 __ push(r0); // Result of assignment, saved even if not needed. |
1118 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is under value. | 1155 // Receiver is under the result value. |
| 1156 __ ldr(ip, MemOperand(sp, kPointerSize)); |
1119 __ push(ip); | 1157 __ push(ip); |
1120 __ CallRuntime(Runtime::kToFastProperties, 1); | 1158 __ CallRuntime(Runtime::kToFastProperties, 1); |
1121 __ pop(r0); | 1159 __ pop(r0); |
1122 DropAndApply(1, context_, r0); | 1160 DropAndApply(1, context_, r0); |
1123 } else { | 1161 } else { |
1124 Apply(context_, r0); | 1162 Apply(context_, r0); |
1125 } | 1163 } |
1126 } | 1164 } |
1127 | 1165 |
1128 | 1166 |
1129 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 1167 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
1130 // Assignment to a property, using a keyed store IC. | 1168 // Assignment to a property, using a keyed store IC. |
1131 | 1169 |
1132 // If the assignment starts a block of assignments to the same object, | 1170 // If the assignment starts a block of assignments to the same object, |
1133 // change to slow case to avoid the quadratic behavior of repeatedly | 1171 // change to slow case to avoid the quadratic behavior of repeatedly |
1134 // adding fast properties. | 1172 // adding fast properties. |
1135 if (expr->starts_initialization_block()) { | 1173 if (expr->starts_initialization_block()) { |
1136 __ push(result_register()); | 1174 __ push(result_register()); |
1137 // Receiver is now under the key and value. | 1175 // Receiver is now under the key and value. |
1138 __ ldr(ip, MemOperand(sp, 2 * kPointerSize)); | 1176 __ ldr(ip, MemOperand(sp, 2 * kPointerSize)); |
1139 __ push(ip); | 1177 __ push(ip); |
1140 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1178 __ CallRuntime(Runtime::kToSlowProperties, 1); |
1141 __ pop(result_register()); | 1179 __ pop(result_register()); |
1142 } | 1180 } |
1143 | 1181 |
1144 // Record source code position before IC call. | 1182 // Record source code position before IC call. |
1145 SetSourcePosition(expr->position()); | 1183 SetSourcePosition(expr->position()); |
| 1184 __ pop(r1); // Key. |
| 1185 // Load receiver to r2. Leave a copy in the stack if needed for turning the |
| 1186 // receiver into fast case. |
| 1187 if (expr->ends_initialization_block()) { |
| 1188 __ ldr(r2, MemOperand(sp)); |
| 1189 } else { |
| 1190 __ pop(r2); |
| 1191 } |
| 1192 |
1146 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1193 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
1147 __ Call(ic, RelocInfo::CODE_TARGET); | 1194 __ Call(ic, RelocInfo::CODE_TARGET); |
1148 | 1195 |
1149 // If the assignment ends an initialization block, revert to fast case. | 1196 // If the assignment ends an initialization block, revert to fast case. |
1150 if (expr->ends_initialization_block()) { | 1197 if (expr->ends_initialization_block()) { |
1151 __ push(r0); // Result of assignment, saved even if not needed. | 1198 __ push(r0); // Result of assignment, saved even if not needed. |
1152 // Receiver is under the key and value. | 1199 // Receiver is under the result value. |
1153 __ ldr(ip, MemOperand(sp, 2 * kPointerSize)); | 1200 __ ldr(ip, MemOperand(sp, kPointerSize)); |
1154 __ push(ip); | 1201 __ push(ip); |
1155 __ CallRuntime(Runtime::kToFastProperties, 1); | 1202 __ CallRuntime(Runtime::kToFastProperties, 1); |
1156 __ pop(r0); | 1203 __ pop(r0); |
| 1204 DropAndApply(1, context_, r0); |
| 1205 } else { |
| 1206 Apply(context_, r0); |
1157 } | 1207 } |
1158 | |
1159 // Receiver and key are still on stack. | |
1160 DropAndApply(2, context_, r0); | |
1161 } | 1208 } |
1162 | 1209 |
1163 | 1210 |
1164 void FullCodeGenerator::VisitProperty(Property* expr) { | 1211 void FullCodeGenerator::VisitProperty(Property* expr) { |
1165 Comment cmnt(masm_, "[ Property"); | 1212 Comment cmnt(masm_, "[ Property"); |
1166 Expression* key = expr->key(); | 1213 Expression* key = expr->key(); |
1167 | 1214 |
1168 // Evaluate receiver. | |
1169 VisitForValue(expr->obj(), kStack); | |
1170 | |
1171 if (key->IsPropertyName()) { | 1215 if (key->IsPropertyName()) { |
| 1216 VisitForValue(expr->obj(), kAccumulator); |
1172 EmitNamedPropertyLoad(expr); | 1217 EmitNamedPropertyLoad(expr); |
1173 // Drop receiver left on the stack by IC. | 1218 Apply(context_, r0); |
1174 DropAndApply(1, context_, r0); | |
1175 } else { | 1219 } else { |
| 1220 VisitForValue(expr->obj(), kStack); |
1176 VisitForValue(expr->key(), kAccumulator); | 1221 VisitForValue(expr->key(), kAccumulator); |
1177 __ pop(r1); | 1222 __ pop(r1); |
1178 EmitKeyedPropertyLoad(expr); | 1223 EmitKeyedPropertyLoad(expr); |
1179 Apply(context_, r0); | 1224 Apply(context_, r0); |
1180 } | 1225 } |
1181 } | 1226 } |
1182 | 1227 |
1183 void FullCodeGenerator::EmitCallWithIC(Call* expr, | 1228 void FullCodeGenerator::EmitCallWithIC(Call* expr, |
1184 Handle<Object> name, | 1229 Handle<Object> name, |
1185 RelocInfo::Mode mode) { | 1230 RelocInfo::Mode mode) { |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1438 } | 1483 } |
1439 | 1484 |
1440 case Token::TYPEOF: { | 1485 case Token::TYPEOF: { |
1441 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 1486 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
1442 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 1487 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
1443 if (proxy != NULL && | 1488 if (proxy != NULL && |
1444 !proxy->var()->is_this() && | 1489 !proxy->var()->is_this() && |
1445 proxy->var()->is_global()) { | 1490 proxy->var()->is_global()) { |
1446 Comment cmnt(masm_, "Global variable"); | 1491 Comment cmnt(masm_, "Global variable"); |
1447 __ ldr(r0, CodeGenerator::GlobalObject()); | 1492 __ ldr(r0, CodeGenerator::GlobalObject()); |
1448 __ push(r0); | |
1449 __ mov(r2, Operand(proxy->name())); | 1493 __ mov(r2, Operand(proxy->name())); |
1450 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1494 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
1451 // Use a regular load, not a contextual load, to avoid a reference | 1495 // Use a regular load, not a contextual load, to avoid a reference |
1452 // error. | 1496 // error. |
1453 __ Call(ic, RelocInfo::CODE_TARGET); | 1497 __ Call(ic, RelocInfo::CODE_TARGET); |
1454 __ str(r0, MemOperand(sp)); | 1498 __ push(r0); |
1455 } else if (proxy != NULL && | 1499 } else if (proxy != NULL && |
1456 proxy->var()->slot() != NULL && | 1500 proxy->var()->slot() != NULL && |
1457 proxy->var()->slot()->type() == Slot::LOOKUP) { | 1501 proxy->var()->slot()->type() == Slot::LOOKUP) { |
1458 __ mov(r0, Operand(proxy->name())); | 1502 __ mov(r0, Operand(proxy->name())); |
1459 __ stm(db_w, sp, cp.bit() | r0.bit()); | 1503 __ stm(db_w, sp, cp.bit() | r0.bit()); |
1460 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 1504 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
1461 __ push(r0); | 1505 __ push(r0); |
1462 } else { | 1506 } else { |
1463 // This expression cannot throw a reference error at the top level. | 1507 // This expression cannot throw a reference error at the top level. |
1464 VisitForValue(expr->expression(), kStack); | 1508 VisitForValue(expr->expression(), kStack); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1550 location_ = kAccumulator; | 1594 location_ = kAccumulator; |
1551 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), | 1595 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), |
1552 Expression::kValue); | 1596 Expression::kValue); |
1553 location_ = saved_location; | 1597 location_ = saved_location; |
1554 } else { | 1598 } else { |
1555 // Reserve space for result of postfix operation. | 1599 // Reserve space for result of postfix operation. |
1556 if (expr->is_postfix() && context_ != Expression::kEffect) { | 1600 if (expr->is_postfix() && context_ != Expression::kEffect) { |
1557 __ mov(ip, Operand(Smi::FromInt(0))); | 1601 __ mov(ip, Operand(Smi::FromInt(0))); |
1558 __ push(ip); | 1602 __ push(ip); |
1559 } | 1603 } |
1560 VisitForValue(prop->obj(), kStack); | |
1561 if (assign_type == NAMED_PROPERTY) { | 1604 if (assign_type == NAMED_PROPERTY) { |
| 1605 // Put the object both on the stack and in the accumulator. |
| 1606 VisitForValue(prop->obj(), kAccumulator); |
| 1607 __ push(r0); |
1562 EmitNamedPropertyLoad(prop); | 1608 EmitNamedPropertyLoad(prop); |
1563 } else { | 1609 } else { |
| 1610 VisitForValue(prop->obj(), kStack); |
1564 VisitForValue(prop->key(), kAccumulator); | 1611 VisitForValue(prop->key(), kAccumulator); |
1565 __ ldr(r1, MemOperand(sp, 0)); | 1612 __ ldr(r1, MemOperand(sp, 0)); |
1566 __ push(r0); | 1613 __ push(r0); |
1567 EmitKeyedPropertyLoad(prop); | 1614 EmitKeyedPropertyLoad(prop); |
1568 } | 1615 } |
1569 } | 1616 } |
1570 | 1617 |
1571 // Call ToNumber only if operand is not a smi. | 1618 // Call ToNumber only if operand is not a smi. |
1572 Label no_conversion; | 1619 Label no_conversion; |
1573 __ tst(r0, Operand(kSmiTagMask)); | 1620 __ tst(r0, Operand(kSmiTagMask)); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1624 __ mov(r1, Operand(Smi::FromInt(count_value))); | 1671 __ mov(r1, Operand(Smi::FromInt(count_value))); |
1625 GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE, r1, r0); | 1672 GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE, r1, r0); |
1626 __ CallStub(&stub); | 1673 __ CallStub(&stub); |
1627 __ bind(&done); | 1674 __ bind(&done); |
1628 | 1675 |
1629 // Store the value returned in r0. | 1676 // Store the value returned in r0. |
1630 switch (assign_type) { | 1677 switch (assign_type) { |
1631 case VARIABLE: | 1678 case VARIABLE: |
1632 if (expr->is_postfix()) { | 1679 if (expr->is_postfix()) { |
1633 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1680 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 1681 Token::ASSIGN, |
1634 Expression::kEffect); | 1682 Expression::kEffect); |
1635 // For all contexts except kEffect: We have the result on | 1683 // For all contexts except kEffect: We have the result on |
1636 // top of the stack. | 1684 // top of the stack. |
1637 if (context_ != Expression::kEffect) { | 1685 if (context_ != Expression::kEffect) { |
1638 ApplyTOS(context_); | 1686 ApplyTOS(context_); |
1639 } | 1687 } |
1640 } else { | 1688 } else { |
1641 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1689 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 1690 Token::ASSIGN, |
1642 context_); | 1691 context_); |
1643 } | 1692 } |
1644 break; | 1693 break; |
1645 case NAMED_PROPERTY: { | 1694 case NAMED_PROPERTY: { |
1646 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); | 1695 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); |
1647 __ pop(r1); | 1696 __ pop(r1); |
1648 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1697 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
1649 __ Call(ic, RelocInfo::CODE_TARGET); | 1698 __ Call(ic, RelocInfo::CODE_TARGET); |
1650 if (expr->is_postfix()) { | 1699 if (expr->is_postfix()) { |
1651 if (context_ != Expression::kEffect) { | 1700 if (context_ != Expression::kEffect) { |
1652 ApplyTOS(context_); | 1701 ApplyTOS(context_); |
1653 } | 1702 } |
1654 } else { | 1703 } else { |
1655 Apply(context_, r0); | 1704 Apply(context_, r0); |
1656 } | 1705 } |
1657 break; | 1706 break; |
1658 } | 1707 } |
1659 case KEYED_PROPERTY: { | 1708 case KEYED_PROPERTY: { |
| 1709 __ pop(r1); // Key. |
| 1710 __ pop(r2); // Receiver. |
1660 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1711 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
1661 __ Call(ic, RelocInfo::CODE_TARGET); | 1712 __ Call(ic, RelocInfo::CODE_TARGET); |
1662 if (expr->is_postfix()) { | 1713 if (expr->is_postfix()) { |
1663 __ Drop(2); // Result is on the stack under the key and the receiver. | |
1664 if (context_ != Expression::kEffect) { | 1714 if (context_ != Expression::kEffect) { |
1665 ApplyTOS(context_); | 1715 ApplyTOS(context_); |
1666 } | 1716 } |
1667 } else { | 1717 } else { |
1668 DropAndApply(2, context_, r0); | 1718 Apply(context_, r0); |
1669 } | 1719 } |
1670 break; | 1720 break; |
1671 } | 1721 } |
1672 } | 1722 } |
1673 } | 1723 } |
1674 | 1724 |
1675 | 1725 |
1676 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 1726 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
1677 Comment cmnt(masm_, "[ BinaryOperation"); | 1727 Comment cmnt(masm_, "[ BinaryOperation"); |
1678 switch (expr->op()) { | 1728 switch (expr->op()) { |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1870 __ pop(result_register()); | 1920 __ pop(result_register()); |
1871 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 1921 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); |
1872 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 1922 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
1873 __ add(pc, r1, Operand(masm_->CodeObject())); | 1923 __ add(pc, r1, Operand(masm_->CodeObject())); |
1874 } | 1924 } |
1875 | 1925 |
1876 | 1926 |
1877 #undef __ | 1927 #undef __ |
1878 | 1928 |
1879 } } // namespace v8::internal | 1929 } } // namespace v8::internal |
| 1930 |
| 1931 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |