Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(636)

Side by Side Diff: src/interpreter/bytecode-generator.cc

Issue 2227203002: [interpreter] Logically separate hole-checking and const assignment errors (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Remove unused var Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/interpreter/bytecode-generator.h ('k') | test/cctest/interpreter/bytecode_expectations/ConstVariable.golden » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698