| 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 |