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 |