Commit 1e5b2358 authored by Matt Gardner's avatar Matt Gardner Committed by Commit Bot

Check for "SuperNotCalled" on "delete this" in a constructor

V8 implements "delete this" as "LdaTrue", but an error needs to be thrown
if done in a constructor before calling super. ThrowIfHole checks the
accumulator, so we need to load 'this' into the accumulator. The check is
inserted by the load since it has HoleCheckMode::kRequired

Bug: https://bugs.chromium.org/p/v8/issues/detail?id=6711

Change-Id: I9f2ce4439505cec4327d88d1195898782edea721
Reviewed-on: https://chromium-review.googlesource.com/c/1419084Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Commit-Queue: Matt Gardner <magardn@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#59007}
parent fa43dd91
...@@ -4573,25 +4573,21 @@ void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -4573,25 +4573,21 @@ void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
} }
} }
void BytecodeGenerator::VisitDelete(UnaryOperation* expr) { void BytecodeGenerator::VisitDelete(UnaryOperation* unary) {
if (expr->expression()->IsProperty()) { Expression* expr = unary->expression();
if (expr->IsProperty()) {
// Delete of an object property is allowed both in sloppy // Delete of an object property is allowed both in sloppy
// and strict modes. // and strict modes.
Property* property = expr->expression()->AsProperty(); Property* property = expr->AsProperty();
Register object = VisitForRegisterValue(property->obj()); Register object = VisitForRegisterValue(property->obj());
VisitForAccumulatorValue(property->key()); VisitForAccumulatorValue(property->key());
builder()->Delete(object, language_mode()); builder()->Delete(object, language_mode());
} else if (expr->expression()->IsVariableProxy()) { } else if (expr->IsVariableProxy() && !expr->AsVariableProxy()->is_this() &&
!expr->AsVariableProxy()->is_new_target()) {
// Delete of an unqualified identifier is allowed in sloppy mode but is // Delete of an unqualified identifier is allowed in sloppy mode but is
// not allowed in strict mode. Deleting 'this' and 'new.target' is allowed // not allowed in strict mode.
// in both modes. DCHECK(is_sloppy(language_mode()));
VariableProxy* proxy = expr->expression()->AsVariableProxy(); Variable* variable = expr->AsVariableProxy()->var();
DCHECK(is_sloppy(language_mode()) || proxy->is_this() ||
proxy->is_new_target());
if (proxy->is_this() || proxy->is_new_target()) {
builder()->LoadTrue();
} else {
Variable* variable = proxy->var();
switch (variable->location()) { switch (variable->location()) {
case VariableLocation::PARAMETER: case VariableLocation::PARAMETER:
case VariableLocation::LOCAL: case VariableLocation::LOCAL:
...@@ -4619,10 +4615,9 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* expr) { ...@@ -4619,10 +4615,9 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* expr) {
default: default:
UNREACHABLE(); UNREACHABLE();
} }
}
} else { } else {
// Delete of an unresolvable reference returns true. // Delete of an unresolvable reference, new.target, and this returns true.
VisitForEffect(expr->expression()); VisitForEffect(expr);
builder()->LoadTrue(); builder()->LoadTrue();
} }
} }
......
...@@ -137,3 +137,20 @@ constant pool: [ ...@@ -137,3 +137,20 @@ constant pool: [
handlers: [ handlers: [
] ]
---
snippet: "
return delete this;
"
frame size: 0
parameter count: 1
bytecode array length: 3
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaTrue),
/* 53 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
...@@ -1499,6 +1499,8 @@ TEST(Delete) { ...@@ -1499,6 +1499,8 @@ TEST(Delete) {
"return delete a[1];\n", "return delete a[1];\n",
"return delete 'test';\n", "return delete 'test';\n",
"return delete this;\n",
}; };
CHECK(CompareTexts(BuildActual(printer, snippets), CHECK(CompareTexts(BuildActual(printer, snippets),
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ensure `delete this` throws before `super` is called.
assertThrows(()=>{
new class extends Object {
constructor() {
delete this;
super();
}
}
}, ReferenceError);
// ensure `delete this` doesn't throw after `super` is called.
new class extends Object {
constructor() {
super();
delete this;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment