OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 | 45 |
46 // A reference is a C++ stack-allocated object that keeps an ECMA | 46 // A reference is a C++ stack-allocated object that keeps an ECMA |
47 // reference on the execution stack while in scope. For variables | 47 // reference on the execution stack while in scope. For variables |
48 // the reference is empty, indicating that it isn't necessary to | 48 // the reference is empty, indicating that it isn't necessary to |
49 // store state on the stack for keeping track of references to those. | 49 // store state on the stack for keeping track of references to those. |
50 // For properties, we keep either one (named) or two (indexed) values | 50 // For properties, we keep either one (named) or two (indexed) values |
51 // on the execution stack to represent the reference. | 51 // on the execution stack to represent the reference. |
52 | 52 |
53 class Reference BASE_EMBEDDED { | 53 class Reference BASE_EMBEDDED { |
54 public: | 54 public: |
55 enum Type { ILLEGAL = -1, EMPTY = 0, NAMED = 1, KEYED = 2 }; | 55 // The values of the types is important, see size(). |
| 56 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; |
56 Reference(ArmCodeGenerator* cgen, Expression* expression); | 57 Reference(ArmCodeGenerator* cgen, Expression* expression); |
57 ~Reference(); | 58 ~Reference(); |
58 | 59 |
59 Expression* expression() const { return expression_; } | 60 Expression* expression() const { return expression_; } |
60 Type type() const { return type_; } | 61 Type type() const { return type_; } |
61 void set_type(Type value) { | 62 void set_type(Type value) { |
62 ASSERT(type_ == ILLEGAL); | 63 ASSERT(type_ == ILLEGAL); |
63 type_ = value; | 64 type_ = value; |
64 } | 65 } |
65 int size() const { return type_; } | 66 // The size of the reference or -1 if the reference is illegal. |
| 67 int size() const { return type_; } |
66 | 68 |
67 bool is_illegal() const { return type_ == ILLEGAL; } | 69 bool is_illegal() const { return type_ == ILLEGAL; } |
| 70 bool is_slot() const { return type_ == SLOT; } |
| 71 bool is_property() const { return type_ == NAMED || type_ == KEYED; } |
68 | 72 |
69 private: | 73 private: |
70 ArmCodeGenerator* cgen_; | 74 ArmCodeGenerator* cgen_; |
71 Expression* expression_; | 75 Expression* expression_; |
72 Type type_; | 76 Type type_; |
73 }; | 77 }; |
74 | 78 |
75 | 79 |
76 // ------------------------------------------------------------------------- | 80 // ------------------------------------------------------------------------- |
77 // Code generation state | 81 // Code generation state |
(...skipping 717 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
795 cgen_->UnloadReference(this); | 799 cgen_->UnloadReference(this); |
796 } | 800 } |
797 | 801 |
798 | 802 |
799 void ArmCodeGenerator::LoadReference(Reference* ref) { | 803 void ArmCodeGenerator::LoadReference(Reference* ref) { |
800 Expression* e = ref->expression(); | 804 Expression* e = ref->expression(); |
801 Property* property = e->AsProperty(); | 805 Property* property = e->AsProperty(); |
802 Variable* var = e->AsVariableProxy()->AsVariable(); | 806 Variable* var = e->AsVariableProxy()->AsVariable(); |
803 | 807 |
804 if (property != NULL) { | 808 if (property != NULL) { |
| 809 // The expression is either a property or a variable proxy that rewrites |
| 810 // to a property. |
805 Load(property->obj()); | 811 Load(property->obj()); |
806 // Used a named reference if the key is a literal symbol. | 812 // We use a named reference if the key is a literal symbol, unless it is |
807 // We don't use a named reference if they key is a string that can be | 813 // a string that can be legally parsed as an integer. This is because |
808 // legally parsed as an integer. This is because, otherwise we don't | 814 // otherwise we will not get into the slow case code that handles [] on |
809 // get into the slow case code that handles [] on String objects. | 815 // String objects. |
810 Literal* literal = property->key()->AsLiteral(); | 816 Literal* literal = property->key()->AsLiteral(); |
811 uint32_t dummy; | 817 uint32_t dummy; |
812 if (literal != NULL && literal->handle()->IsSymbol() && | 818 if (literal != NULL && |
813 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { | 819 literal->handle()->IsSymbol() && |
| 820 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { |
814 ref->set_type(Reference::NAMED); | 821 ref->set_type(Reference::NAMED); |
815 } else { | 822 } else { |
816 Load(property->key()); | 823 Load(property->key()); |
817 ref->set_type(Reference::KEYED); | 824 ref->set_type(Reference::KEYED); |
818 } | 825 } |
819 } else if (var != NULL) { | 826 } else if (var != NULL) { |
| 827 // The expression is a variable proxy that does not rewrite to a |
| 828 // property. Global variables are treated as named property references. |
820 if (var->is_global()) { | 829 if (var->is_global()) { |
821 // global variable | |
822 LoadGlobal(); | 830 LoadGlobal(); |
823 ref->set_type(Reference::NAMED); | 831 ref->set_type(Reference::NAMED); |
824 } else { | 832 } else { |
825 // local variable | 833 ASSERT(var->slot() != NULL); |
826 ref->set_type(Reference::EMPTY); | 834 ref->set_type(Reference::SLOT); |
827 } | 835 } |
828 } else { | 836 } else { |
| 837 // Anything else is a runtime error. |
829 Load(e); | 838 Load(e); |
830 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 839 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
831 __ push(r0); | |
832 } | 840 } |
833 } | 841 } |
834 | 842 |
835 | 843 |
836 void ArmCodeGenerator::UnloadReference(Reference* ref) { | 844 void ArmCodeGenerator::UnloadReference(Reference* ref) { |
837 int size = ref->size(); | 845 int size = ref->size(); |
838 if (size <= 0) { | 846 if (size <= 0) { |
839 // Do nothing. No popping is necessary. | 847 // Do nothing. No popping is necessary. |
840 } else { | 848 } else { |
841 __ pop(r0); | 849 __ pop(r0); |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
964 PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n", | 972 PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n", |
965 static_cast<int>(kind_), | 973 static_cast<int>(kind_), |
966 argc_); | 974 argc_); |
967 } | 975 } |
968 #endif | 976 #endif |
969 }; | 977 }; |
970 | 978 |
971 | 979 |
972 void ArmCodeGenerator::GetReferenceProperty(Expression* key) { | 980 void ArmCodeGenerator::GetReferenceProperty(Expression* key) { |
973 ASSERT(!ref()->is_illegal()); | 981 ASSERT(!ref()->is_illegal()); |
974 Reference::Type type = ref()->type(); | |
975 | 982 |
976 // TODO(1241834): Make sure that this it is safe to ignore the distinction | 983 // TODO(1241834): Make sure that this it is safe to ignore the distinction |
977 // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance | 984 // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance |
978 // that reference errors can be thrown below, we must distinguish between | 985 // that reference errors can be thrown below, we must distinguish between |
979 // the two kinds of loads (typeof expression loads must not throw a | 986 // the two kinds of loads (typeof expression loads must not throw a |
980 // reference error). | 987 // reference error). |
981 if (type == Reference::NAMED) { | 988 if (ref()->type() == Reference::NAMED) { |
982 // Compute the name of the property. | 989 // Compute the name of the property. |
983 Literal* literal = key->AsLiteral(); | 990 Literal* literal = key->AsLiteral(); |
984 Handle<String> name(String::cast(*literal->handle())); | 991 Handle<String> name(String::cast(*literal->handle())); |
985 | 992 |
986 // Call the appropriate IC code. | 993 // Call the appropriate IC code. |
987 // Setup the name register. | 994 // Setup the name register. |
988 __ mov(r2, Operand(name)); | 995 __ mov(r2, Operand(name)); |
989 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 996 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
990 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); | 997 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); |
991 if (var != NULL) { | 998 if (var != NULL) { |
992 ASSERT(var->is_global()); | 999 ASSERT(var->is_global()); |
993 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1000 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
994 } else { | 1001 } else { |
995 __ Call(ic, RelocInfo::CODE_TARGET); | 1002 __ Call(ic, RelocInfo::CODE_TARGET); |
996 } | 1003 } |
997 | 1004 |
998 } else { | 1005 } else { |
999 // Access keyed property. | 1006 // Access keyed property. |
1000 ASSERT(type == Reference::KEYED); | 1007 ASSERT(ref()->type() == Reference::KEYED); |
1001 | 1008 |
1002 // TODO(1224671): Implement inline caching for keyed loads as on ia32. | 1009 // TODO(1224671): Implement inline caching for keyed loads as on ia32. |
1003 GetPropertyStub stub; | 1010 GetPropertyStub stub; |
1004 __ CallStub(&stub); | 1011 __ CallStub(&stub); |
1005 } | 1012 } |
1006 __ push(r0); | 1013 __ push(r0); |
1007 } | 1014 } |
1008 | 1015 |
1009 | 1016 |
1010 void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) { | 1017 void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) { |
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1453 Expression* val = NULL; | 1460 Expression* val = NULL; |
1454 if (node->mode() == Variable::CONST) { | 1461 if (node->mode() == Variable::CONST) { |
1455 val = new Literal(Factory::the_hole_value()); | 1462 val = new Literal(Factory::the_hole_value()); |
1456 } else { | 1463 } else { |
1457 val = node->fun(); // NULL if we don't have a function | 1464 val = node->fun(); // NULL if we don't have a function |
1458 } | 1465 } |
1459 | 1466 |
1460 if (val != NULL) { | 1467 if (val != NULL) { |
1461 // Set initial value. | 1468 // Set initial value. |
1462 Reference target(this, node->proxy()); | 1469 Reference target(this, node->proxy()); |
| 1470 ASSERT(target.is_slot()); |
1463 Load(val); | 1471 Load(val); |
1464 SetValue(&target); | 1472 SetValue(&target); |
1465 // Get rid of the assigned value (declarations are statements). | 1473 // Get rid of the assigned value (declarations are statements). It's |
| 1474 // safe to pop the value lying on top of the reference before unloading |
| 1475 // the reference itself (which preserves the top of stack) because we |
| 1476 // know it is a zero-sized reference. |
1466 __ pop(); | 1477 __ pop(); |
1467 } | 1478 } |
1468 } | 1479 } |
1469 | 1480 |
1470 | 1481 |
1471 void ArmCodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1482 void ArmCodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
1472 Comment cmnt(masm_, "[ ExpressionStatement"); | 1483 Comment cmnt(masm_, "[ ExpressionStatement"); |
1473 if (FLAG_debug_info) RecordStatementPosition(node); | 1484 if (FLAG_debug_info) RecordStatementPosition(node); |
1474 Expression* expression = node->expression(); | 1485 Expression* expression = node->expression(); |
1475 expression->MarkAsStatement(); | 1486 expression->MarkAsStatement(); |
(...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1937 | 1948 |
1938 | 1949 |
1939 __ bind(&end_del_check); | 1950 __ bind(&end_del_check); |
1940 | 1951 |
1941 // Store the entry in the 'each' expression and take another spin in the loop. | 1952 // Store the entry in the 'each' expression and take another spin in the loop. |
1942 // r3: i'th entry of the enum cache (or string there of) | 1953 // r3: i'th entry of the enum cache (or string there of) |
1943 __ push(r3); // push entry | 1954 __ push(r3); // push entry |
1944 { Reference each(this, node->each()); | 1955 { Reference each(this, node->each()); |
1945 if (!each.is_illegal()) { | 1956 if (!each.is_illegal()) { |
1946 if (each.size() > 0) { | 1957 if (each.size() > 0) { |
| 1958 // Reference's size is positive. |
1947 __ ldr(r0, MemOperand(sp, kPointerSize * each.size())); | 1959 __ ldr(r0, MemOperand(sp, kPointerSize * each.size())); |
1948 __ push(r0); | 1960 __ push(r0); |
1949 } | 1961 } |
| 1962 // If the reference was to a slot we rely on the convenient property |
| 1963 // that it doesn't matter whether a value (eg, r3 pushed above) is |
| 1964 // right on top of or right underneath a zero-sized reference. |
1950 SetValue(&each); | 1965 SetValue(&each); |
1951 if (each.size() > 0) { | 1966 if (each.size() > 0) { |
1952 __ pop(r0); // discard the value | 1967 // It's safe to pop the value lying on top of the reference before |
| 1968 // unloading the reference itself (which preserves the top of stack, |
| 1969 // ie, now the topmost value of the non-zero sized reference), since |
| 1970 // we will discard the top of stack after unloading the reference |
| 1971 // anyway. |
| 1972 __ pop(r0); |
1953 } | 1973 } |
1954 } | 1974 } |
1955 } | 1975 } |
1956 __ pop(); // pop the i'th entry pushed above | 1976 // Discard the i'th entry pushed above or else the remainder of the |
| 1977 // reference, whichever is currently on top of the stack. |
| 1978 __ pop(); |
1957 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1979 CheckStack(); // TODO(1222600): ignore if body contains calls. |
1958 __ jmp(&loop); | 1980 __ jmp(&loop); |
1959 | 1981 |
1960 // Cleanup. | 1982 // Cleanup. |
1961 __ bind(&cleanup); | 1983 __ bind(&cleanup); |
1962 __ bind(node->break_target()); | 1984 __ bind(node->break_target()); |
1963 __ add(sp, sp, Operand(5 * kPointerSize)); | 1985 __ add(sp, sp, Operand(5 * kPointerSize)); |
1964 | 1986 |
1965 // Exit. | 1987 // Exit. |
1966 __ bind(&exit); | 1988 __ bind(&exit); |
1967 | 1989 |
1968 break_stack_height_ -= kForInStackSize; | 1990 break_stack_height_ -= kForInStackSize; |
1969 } | 1991 } |
1970 | 1992 |
1971 | 1993 |
1972 void ArmCodeGenerator::VisitTryCatch(TryCatch* node) { | 1994 void ArmCodeGenerator::VisitTryCatch(TryCatch* node) { |
1973 Comment cmnt(masm_, "[ TryCatch"); | 1995 Comment cmnt(masm_, "[ TryCatch"); |
1974 | 1996 |
1975 Label try_block, exit; | 1997 Label try_block, exit; |
1976 | 1998 |
1977 __ bl(&try_block); | 1999 __ bl(&try_block); |
1978 | 2000 |
1979 // --- Catch block --- | 2001 // --- Catch block --- |
1980 | 2002 |
1981 // Store the caught exception in the catch variable. | 2003 // Store the caught exception in the catch variable. |
1982 __ push(r0); | 2004 __ push(r0); |
1983 { Reference ref(this, node->catch_var()); | 2005 { Reference ref(this, node->catch_var()); |
1984 // Load the exception to the top of the stack. | 2006 ASSERT(ref.is_slot()); |
1985 __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize)); | 2007 // Here we make use of the convenient property that it doesn't matter |
1986 __ push(r0); | 2008 // whether a value is immediately on top of or underneath a zero-sized |
| 2009 // reference. |
1987 SetValue(&ref); | 2010 SetValue(&ref); |
1988 __ pop(r0); | |
1989 } | 2011 } |
1990 | 2012 |
1991 // Remove the exception from the stack. | 2013 // Remove the exception from the stack. |
1992 __ pop(); | 2014 __ pop(); |
1993 | 2015 |
1994 VisitStatements(node->catch_block()->statements()); | 2016 VisitStatements(node->catch_block()->statements()); |
1995 __ b(&exit); | 2017 __ b(&exit); |
1996 | 2018 |
1997 | 2019 |
1998 // --- Try block --- | 2020 // --- Try block --- |
(...skipping 2567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4566 bool is_eval) { | 4588 bool is_eval) { |
4567 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval); | 4589 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval); |
4568 if (!code.is_null()) { | 4590 if (!code.is_null()) { |
4569 Counters::total_compiled_code_size.Increment(code->instruction_size()); | 4591 Counters::total_compiled_code_size.Increment(code->instruction_size()); |
4570 } | 4592 } |
4571 return code; | 4593 return code; |
4572 } | 4594 } |
4573 | 4595 |
4574 | 4596 |
4575 } } // namespace v8::internal | 4597 } } // namespace v8::internal |
OLD | NEW |