Commit 4927c82f authored by conradw's avatar conradw Committed by Commit bot

[strong] class objects created in strong mode are frozen

BUG=v8:3956
LOG=N

Review URL: https://codereview.chromium.org/1225303005

Cr-Commit-Position: refs/heads/master@{#29615}
parent 0fd9a0a3
......@@ -1640,6 +1640,14 @@ void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) {
const Operator* op = javascript()->CallRuntime(Runtime::kToFastProperties, 1);
NewNode(op, environment()->Pop()); // prototype
NewNode(op, environment()->Pop()); // literal
if (is_strong(language_mode())) {
// TODO(conradw): It would be more efficient to define the properties with
// the right attributes the first time round.
literal =
NewNode(javascript()->CallRuntime(Runtime::kObjectFreeze, 1), literal);
// Freezing the class object should never deopt.
PrepareFrameState(literal, BailoutId::None());
}
// Assign to class variable.
if (expr->scope() != NULL) {
......@@ -1652,7 +1660,6 @@ void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) {
BuildVariableAssignment(var, literal, Token::INIT_CONST, feedback,
BailoutId::None(), states);
}
ast_context()->ProduceValue(literal);
}
......
......@@ -1204,6 +1204,13 @@ void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) {
// Verify that compilation exactly consumed the number of store ic slots
// that the ClassLiteral node had to offer.
DCHECK(!FLAG_vector_stores || store_slot_index == lit->slot_count());
if (is_strong(language_mode())) {
// TODO(conradw): It would be more efficient to define the properties with
// the right attributes the first time round.
__ Push(result_register());
__ CallRuntime(Runtime::kObjectFreeze, 1);
}
}
context()->Plug(result_register());
......
// Copyright 2015 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.
// Flags: --strong-mode
"use strict";
function getClass() {
class Foo {
static get bar() { return 0 }
}
return Foo;
}
function getClassExpr() {
return (class { static get bar() { return 0 } });
}
function getClassStrong() {
"use strong";
class Foo {
static get bar() { return 0 }
}
return Foo;
}
function getClassExprStrong() {
"use strong";
return (class { static get bar() { return 0 } });
}
function addProperty(o) {
o.baz = 1;
}
function convertPropertyToData(o) {
assertTrue(o.hasOwnProperty("bar"));
Object.defineProperty(o, "bar", { value: 1 });
}
assertDoesNotThrow(function(){addProperty(getClass())});
assertDoesNotThrow(function(){convertPropertyToData(getClass())});
assertDoesNotThrow(function(){addProperty(getClassExpr())});
assertDoesNotThrow(function(){convertPropertyToData(getClassExpr())});
assertThrows(function(){addProperty(getClassStrong())}, TypeError);
assertThrows(function(){convertPropertyToData(getClassStrong())}, TypeError);
assertThrows(function(){addProperty(getClassExprStrong())}, TypeError);
assertThrows(function(){convertPropertyToData(getClassExprStrong())},
TypeError);
// Check strong classes don't freeze their parents.
(function() {
"use strong";
let parent = getClass();
class Foo extends parent {
static get bar() { return 0 }
}
assertThrows(function(){addProperty(Foo)}, TypeError);
assertThrows(function(){convertPropertyToData(Foo)}, TypeError);
assertDoesNotThrow(function(){addProperty(parent)});
assertDoesNotThrow(function(){convertPropertyToData(parent)});
})();
// Check strong classes don't freeze their children.
(function() {
let parent = getClassStrong();
class Foo extends parent {
static get bar() { return 0 }
}
assertThrows(function(){addProperty(parent)}, TypeError);
assertThrows(function(){convertPropertyToData(parent)}, TypeError);
assertDoesNotThrow(function(){addProperty(Foo)});
assertDoesNotThrow(function(){convertPropertyToData(Foo)});
})();
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