| 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 "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
| 8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
| 9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
| 10 #include "src/interpreter/bytecode-flags.h" | 10 #include "src/interpreter/bytecode-flags.h" |
| (...skipping 1983 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1994 // performed? Or should there be a ThrowIfNotHole bytecode. | 1994 // performed? Or should there be a ThrowIfNotHole bytecode. |
| 1995 BytecodeLabel no_reference_error, reference_error; | 1995 BytecodeLabel no_reference_error, reference_error; |
| 1996 builder() | 1996 builder() |
| 1997 ->JumpIfNotHole(&reference_error) | 1997 ->JumpIfNotHole(&reference_error) |
| 1998 .Jump(&no_reference_error) | 1998 .Jump(&no_reference_error) |
| 1999 .Bind(&reference_error); | 1999 .Bind(&reference_error); |
| 2000 BuildThrowReferenceError(name); | 2000 BuildThrowReferenceError(name); |
| 2001 builder()->Bind(&no_reference_error); | 2001 builder()->Bind(&no_reference_error); |
| 2002 } | 2002 } |
| 2003 | 2003 |
| 2004 void BytecodeGenerator::BuildThrowReassignConstant(Handle<String> name) { | |
| 2005 // TODO(mythria): This will be replaced by a new bytecode that throws an | |
| 2006 // appropriate error depending on the whether the value is a hole or not. | |
| 2007 BytecodeLabel const_assign_error; | |
| 2008 builder()->JumpIfNotHole(&const_assign_error); | |
| 2009 BuildThrowReferenceError(name); | |
| 2010 builder() | |
| 2011 ->Bind(&const_assign_error) | |
| 2012 .CallRuntime(Runtime::kThrowConstAssignError, Register(), 0); | |
| 2013 } | |
| 2014 | |
| 2015 void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable, | 2004 void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable, |
| 2016 Token::Value op) { | 2005 Token::Value op) { |
| 2017 VariableMode mode = variable->mode(); | 2006 DCHECK(variable->mode() != CONST_LEGACY); |
| 2018 DCHECK(mode != CONST_LEGACY); | 2007 if (op != Token::INIT) { |
| 2019 if (mode == CONST && op != Token::INIT) { | 2008 // Perform an initialization check for let/const declared variables. |
| 2020 // Non-intializing assignments to constant is not allowed. | |
| 2021 BuildThrowReassignConstant(variable->name()); | |
| 2022 } else if (mode == LET && op != Token::INIT) { | |
| 2023 // Perform an initialization check for let declared variables. | |
| 2024 // E.g. let x = (x = 20); is not allowed. | 2009 // E.g. let x = (x = 20); is not allowed. |
| 2025 BuildThrowIfHole(variable->name()); | 2010 BuildThrowIfHole(variable->name()); |
| 2026 } else { | 2011 } else { |
| 2027 DCHECK(variable->is_this() && mode == CONST && op == Token::INIT); | 2012 DCHECK(variable->is_this() && variable->mode() == CONST && |
| 2013 op == Token::INIT); |
| 2028 // Perform an initialization check for 'this'. 'this' variable is the | 2014 // Perform an initialization check for 'this'. 'this' variable is the |
| 2029 // only variable able to trigger bind operations outside the TDZ | 2015 // only variable able to trigger bind operations outside the TDZ |
| 2030 // via 'super' calls. | 2016 // via 'super' calls. |
| 2031 BuildThrowIfNotHole(variable->name()); | 2017 BuildThrowIfNotHole(variable->name()); |
| 2032 } | 2018 } |
| 2033 } | 2019 } |
| 2034 | 2020 |
| 2035 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, | 2021 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
| 2036 Token::Value op, | 2022 Token::Value op, |
| 2037 FeedbackVectorSlot slot) { | 2023 FeedbackVectorSlot slot) { |
| 2038 VariableMode mode = variable->mode(); | 2024 VariableMode mode = variable->mode(); |
| 2039 RegisterAllocationScope assignment_register_scope(this); | 2025 RegisterAllocationScope assignment_register_scope(this); |
| 2040 BytecodeLabel end_label; | 2026 BytecodeLabel end_label; |
| 2041 bool hole_check_required = | 2027 bool hole_check_required = |
| 2042 (mode == LET && op != Token::INIT) || | 2028 variable->binding_needs_init() && |
| 2043 (mode == CONST && op != Token::INIT) || | 2029 ((IsLexicalVariableMode(mode) && op != Token::INIT) || |
| 2044 (mode == CONST && op == Token::INIT && variable->is_this()); | 2030 (mode == CONST && op == Token::INIT && variable->is_this())); |
| 2045 switch (variable->location()) { | 2031 switch (variable->location()) { |
| 2046 case VariableLocation::PARAMETER: | 2032 case VariableLocation::PARAMETER: |
| 2047 case VariableLocation::LOCAL: { | 2033 case VariableLocation::LOCAL: { |
| 2048 Register destination; | 2034 Register destination; |
| 2049 if (VariableLocation::PARAMETER == variable->location()) { | 2035 if (VariableLocation::PARAMETER == variable->location()) { |
| 2050 destination = Register(builder()->Parameter(variable->index() + 1)); | 2036 destination = Register(builder()->Parameter(variable->index() + 1)); |
| 2051 } else { | 2037 } else { |
| 2052 destination = Register(variable->index()); | 2038 destination = Register(variable->index()); |
| 2053 } | 2039 } |
| 2054 | 2040 |
| 2055 if (mode == CONST_LEGACY && op != Token::INIT) { | |
| 2056 if (is_strict(language_mode())) { | |
| 2057 builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), | |
| 2058 0); | |
| 2059 } | |
| 2060 // Non-initializing assignments to legacy constants are ignored | |
| 2061 // in sloppy mode. Break here to avoid storing into variable. | |
| 2062 break; | |
| 2063 } | |
| 2064 | |
| 2065 if (hole_check_required) { | 2041 if (hole_check_required) { |
| 2066 // Load destination to check for hole. | 2042 // Load destination to check for hole. |
| 2067 Register value_temp = register_allocator()->NewRegister(); | 2043 Register value_temp = register_allocator()->NewRegister(); |
| 2068 builder() | 2044 builder() |
| 2069 ->StoreAccumulatorInRegister(value_temp) | 2045 ->StoreAccumulatorInRegister(value_temp) |
| 2070 .LoadAccumulatorWithRegister(destination); | 2046 .LoadAccumulatorWithRegister(destination); |
| 2071 | 2047 |
| 2072 BuildHoleCheckForVariableAssignment(variable, op); | 2048 BuildHoleCheckForVariableAssignment(variable, op); |
| 2073 builder()->LoadAccumulatorWithRegister(value_temp); | 2049 builder()->LoadAccumulatorWithRegister(value_temp); |
| 2074 } | 2050 } |
| 2051 |
| 2052 if ((mode == CONST || mode == CONST_LEGACY) && op != Token::INIT) { |
| 2053 if (mode == CONST || is_strict(language_mode())) { |
| 2054 builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), |
| 2055 0); |
| 2056 } |
| 2057 // Non-initializing assignments to legacy constants are ignored |
| 2058 // in sloppy mode. Break here to avoid storing into variable. |
| 2059 break; |
| 2060 } |
| 2061 |
| 2075 builder()->StoreAccumulatorInRegister(destination); | 2062 builder()->StoreAccumulatorInRegister(destination); |
| 2076 break; | 2063 break; |
| 2077 } | 2064 } |
| 2078 case VariableLocation::GLOBAL: | 2065 case VariableLocation::GLOBAL: |
| 2079 case VariableLocation::UNALLOCATED: { | 2066 case VariableLocation::UNALLOCATED: { |
| 2080 builder()->StoreGlobal(variable->name(), feedback_index(slot), | 2067 builder()->StoreGlobal(variable->name(), feedback_index(slot), |
| 2081 language_mode()); | 2068 language_mode()); |
| 2082 break; | 2069 break; |
| 2083 } | 2070 } |
| 2084 case VariableLocation::CONTEXT: { | 2071 case VariableLocation::CONTEXT: { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2101 .LoadAccumulatorWithRegister(execution_context()->reg()) | 2088 .LoadAccumulatorWithRegister(execution_context()->reg()) |
| 2102 .StoreAccumulatorInRegister(context_reg); | 2089 .StoreAccumulatorInRegister(context_reg); |
| 2103 for (int i = 0; i < depth; ++i) { | 2090 for (int i = 0; i < depth; ++i) { |
| 2104 builder() | 2091 builder() |
| 2105 ->LoadContextSlot(context_reg, Context::PREVIOUS_INDEX) | 2092 ->LoadContextSlot(context_reg, Context::PREVIOUS_INDEX) |
| 2106 .StoreAccumulatorInRegister(context_reg); | 2093 .StoreAccumulatorInRegister(context_reg); |
| 2107 } | 2094 } |
| 2108 builder()->LoadAccumulatorWithRegister(value_temp); | 2095 builder()->LoadAccumulatorWithRegister(value_temp); |
| 2109 } | 2096 } |
| 2110 | 2097 |
| 2111 if (mode == CONST_LEGACY && op != Token::INIT) { | |
| 2112 if (is_strict(language_mode())) { | |
| 2113 builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), | |
| 2114 0); | |
| 2115 } | |
| 2116 // Non-initializing assignments to legacy constants are ignored | |
| 2117 // in sloppy mode. Break here to avoid storing into variable. | |
| 2118 break; | |
| 2119 } | |
| 2120 | |
| 2121 if (hole_check_required) { | 2098 if (hole_check_required) { |
| 2122 // Load destination to check for hole. | 2099 // Load destination to check for hole. |
| 2123 Register value_temp = register_allocator()->NewRegister(); | 2100 Register value_temp = register_allocator()->NewRegister(); |
| 2124 builder() | 2101 builder() |
| 2125 ->StoreAccumulatorInRegister(value_temp) | 2102 ->StoreAccumulatorInRegister(value_temp) |
| 2126 .LoadContextSlot(context_reg, variable->index()); | 2103 .LoadContextSlot(context_reg, variable->index()); |
| 2127 | 2104 |
| 2128 BuildHoleCheckForVariableAssignment(variable, op); | 2105 BuildHoleCheckForVariableAssignment(variable, op); |
| 2129 builder()->LoadAccumulatorWithRegister(value_temp); | 2106 builder()->LoadAccumulatorWithRegister(value_temp); |
| 2130 } | 2107 } |
| 2131 | 2108 |
| 2109 if ((mode == CONST || mode == CONST_LEGACY) && op != Token::INIT) { |
| 2110 if (mode == CONST || is_strict(language_mode())) { |
| 2111 builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), |
| 2112 0); |
| 2113 } |
| 2114 // Non-initializing assignments to legacy constants are ignored |
| 2115 // in sloppy mode. Break here to avoid storing into variable. |
| 2116 break; |
| 2117 } |
| 2118 |
| 2132 builder()->StoreContextSlot(context_reg, variable->index()); | 2119 builder()->StoreContextSlot(context_reg, variable->index()); |
| 2133 break; | 2120 break; |
| 2134 } | 2121 } |
| 2135 case VariableLocation::LOOKUP: { | 2122 case VariableLocation::LOOKUP: { |
| 2136 DCHECK_NE(CONST_LEGACY, variable->mode()); | 2123 DCHECK_NE(CONST_LEGACY, variable->mode()); |
| 2137 builder()->StoreLookupSlot(variable->name(), language_mode()); | 2124 builder()->StoreLookupSlot(variable->name(), language_mode()); |
| 2138 break; | 2125 break; |
| 2139 } | 2126 } |
| 2140 case VariableLocation::MODULE: | 2127 case VariableLocation::MODULE: |
| 2141 UNREACHABLE(); | 2128 UNREACHABLE(); |
| (...skipping 1139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3281 return execution_context()->scope()->language_mode(); | 3268 return execution_context()->scope()->language_mode(); |
| 3282 } | 3269 } |
| 3283 | 3270 |
| 3284 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 3271 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
| 3285 return TypeFeedbackVector::GetIndex(slot); | 3272 return TypeFeedbackVector::GetIndex(slot); |
| 3286 } | 3273 } |
| 3287 | 3274 |
| 3288 } // namespace interpreter | 3275 } // namespace interpreter |
| 3289 } // namespace internal | 3276 } // namespace internal |
| 3290 } // namespace v8 | 3277 } // namespace v8 |
| OLD | NEW |