From f996793ec0be128599988671825f469eaf999982 Mon Sep 17 00:00:00 2001 From: conradw Date: Tue, 14 Jul 2015 04:31:38 -0700 Subject: [PATCH] [strong] class objects created in strong mode have their prototype frozen BUG=v8:3956 LOG=N Review URL: https://codereview.chromium.org/1235983002 Cr-Commit-Position: refs/heads/master@{#29646} --- src/arm/full-codegen-arm.cc | 13 +++++++ src/arm64/full-codegen-arm64.cc | 13 +++++++ src/compiler/ast-graph-builder.cc | 8 ++++- src/full-codegen.cc | 7 ---- src/ia32/full-codegen-ia32.cc | 13 +++++++ src/mips/full-codegen-mips.cc | 12 +++++++ src/mips64/full-codegen-mips64.cc | 12 +++++++ src/ppc/full-codegen-ppc.cc | 12 +++++++ src/x64/full-codegen-x64.cc | 13 +++++++ src/x87/full-codegen-x87.cc | 13 +++++++ test/mjsunit/strong/class-object-frozen.js | 58 +++++++++++++++++++----------- 11 files changed, 146 insertions(+), 28 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index bd6e4ab..2ed37e4 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -2661,6 +2661,19 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit, // constructor __ CallRuntime(Runtime::kToFastProperties, 1); + + if (is_strong(language_mode())) { + __ ldr(scratch, + FieldMemOperand(r0, JSFunction::kPrototypeOrInitialMapOffset)); + __ push(r0); + __ push(scratch); + // TODO(conradw): It would be more efficient to define the properties with + // the right attributes the first time round. + // Freeze the prototype. + __ CallRuntime(Runtime::kObjectFreeze, 1); + // Freeze the constructor. + __ CallRuntime(Runtime::kObjectFreeze, 1); + } } diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 7dad7d9..ad8bb90 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -2352,6 +2352,19 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit, // constructor __ CallRuntime(Runtime::kToFastProperties, 1); + + if (is_strong(language_mode())) { + __ Ldr(scratch, + FieldMemOperand(x0, JSFunction::kPrototypeOrInitialMapOffset)); + __ push(x0); + __ Push(scratch); + // TODO(conradw): It would be more efficient to define the properties with + // the right attributes the first time round. + // Freeze the prototype. + __ CallRuntime(Runtime::kObjectFreeze, 1); + // Freeze the constructor. + __ CallRuntime(Runtime::kObjectFreeze, 1); + } } diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 99510e3..fab7437 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -1643,9 +1643,15 @@ void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) { if (is_strong(language_mode())) { // TODO(conradw): It would be more efficient to define the properties with // the right attributes the first time round. + // Freeze the prototype. + proto = + NewNode(javascript()->CallRuntime(Runtime::kObjectFreeze, 1), proto); + // Freezing the prototype should never deopt. + PrepareFrameState(proto, BailoutId::None()); + // Freeze the constructor. literal = NewNode(javascript()->CallRuntime(Runtime::kObjectFreeze, 1), literal); - // Freezing the class object should never deopt. + // Freezing the constructor should never deopt. PrepareFrameState(literal, BailoutId::None()); } diff --git a/src/full-codegen.cc b/src/full-codegen.cc index a97ea22..6366981 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -1204,13 +1204,6 @@ 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()); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 3d375fc..6615af1 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -2567,6 +2567,19 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit, // constructor __ CallRuntime(Runtime::kToFastProperties, 1); + + if (is_strong(language_mode())) { + __ mov(scratch, + FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset)); + __ push(eax); + __ Push(scratch); + // TODO(conradw): It would be more efficient to define the properties with + // the right attributes the first time round. + // Freeze the prototype. + __ CallRuntime(Runtime::kObjectFreeze, 1); + // Freeze the constructor. + __ CallRuntime(Runtime::kObjectFreeze, 1); + } } diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 8f45b7d..7fca1c1 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -2646,6 +2646,18 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit, // constructor __ CallRuntime(Runtime::kToFastProperties, 1); + + if (is_strong(language_mode())) { + __ lw(scratch, + FieldMemOperand(v0, JSFunction::kPrototypeOrInitialMapOffset)); + __ Push(v0, scratch); + // TODO(conradw): It would be more efficient to define the properties with + // the right attributes the first time round. + // Freeze the prototype. + __ CallRuntime(Runtime::kObjectFreeze, 1); + // Freeze the constructor. + __ CallRuntime(Runtime::kObjectFreeze, 1); + } } diff --git a/src/mips64/full-codegen-mips64.cc b/src/mips64/full-codegen-mips64.cc index 9fad990..ee76d9d 100644 --- a/src/mips64/full-codegen-mips64.cc +++ b/src/mips64/full-codegen-mips64.cc @@ -2644,6 +2644,18 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit, // constructor __ CallRuntime(Runtime::kToFastProperties, 1); + + if (is_strong(language_mode())) { + __ ld(scratch, + FieldMemOperand(v0, JSFunction::kPrototypeOrInitialMapOffset)); + __ Push(v0, scratch); + // TODO(conradw): It would be more efficient to define the properties with + // the right attributes the first time round. + // Freeze the prototype. + __ CallRuntime(Runtime::kObjectFreeze, 1); + // Freeze the constructor. + __ CallRuntime(Runtime::kObjectFreeze, 1); + } } diff --git a/src/ppc/full-codegen-ppc.cc b/src/ppc/full-codegen-ppc.cc index 97850a1..0f455a0 100644 --- a/src/ppc/full-codegen-ppc.cc +++ b/src/ppc/full-codegen-ppc.cc @@ -2669,6 +2669,18 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit, // constructor __ CallRuntime(Runtime::kToFastProperties, 1); + + if (is_strong(language_mode())) { + __ LoadP(scratch, + FieldMemOperand(r3, JSFunction::kPrototypeOrInitialMapOffset)); + __ Push(r3, scratch); + // TODO(conradw): It would be more efficient to define the properties with + // the right attributes the first time round. + // Freeze the prototype. + __ CallRuntime(Runtime::kObjectFreeze, 1); + // Freeze the constructor. + __ CallRuntime(Runtime::kObjectFreeze, 1); + } } diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index eb12a47..5237e7c 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -2570,6 +2570,19 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit, // constructor __ CallRuntime(Runtime::kToFastProperties, 1); + + if (is_strong(language_mode())) { + __ movp(scratch, + FieldOperand(rax, JSFunction::kPrototypeOrInitialMapOffset)); + __ Push(rax); + __ Push(scratch); + // TODO(conradw): It would be more efficient to define the properties with + // the right attributes the first time round. + // Freeze the prototype. + __ CallRuntime(Runtime::kObjectFreeze, 1); + // Freeze the constructor. + __ CallRuntime(Runtime::kObjectFreeze, 1); + } } diff --git a/src/x87/full-codegen-x87.cc b/src/x87/full-codegen-x87.cc index 6a15650..584c2b9 100644 --- a/src/x87/full-codegen-x87.cc +++ b/src/x87/full-codegen-x87.cc @@ -2558,6 +2558,19 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit, // constructor __ CallRuntime(Runtime::kToFastProperties, 1); + + if (is_strong(language_mode())) { + __ mov(scratch, + FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset)); + __ push(eax); + __ push(scratch); + // TODO(conradw): It would be more efficient to define the properties with + // the right attributes the first time round. + // Freeze the prototype. + __ CallRuntime(Runtime::kObjectFreeze, 1); + // Freeze the constructor. + __ CallRuntime(Runtime::kObjectFreeze, 1); + } } diff --git a/test/mjsunit/strong/class-object-frozen.js b/test/mjsunit/strong/class-object-frozen.js index 011a11d..2c442c0 100644 --- a/test/mjsunit/strong/class-object-frozen.js +++ b/test/mjsunit/strong/class-object-frozen.js @@ -9,25 +9,27 @@ function getClass() { class Foo { static get bar() { return 0 } + get bar() { return 0 } } return Foo; } function getClassExpr() { - return (class { static get bar() { return 0 } }); + return (class { static get bar() { return 0 } get bar() { return 0 } }); } function getClassStrong() { "use strong"; class Foo { static get bar() { return 0 } + get bar() { return 0 } } return Foo; } function getClassExprStrong() { "use strong"; - return (class { static get bar() { return 0 } }); + return (class { static get bar() { return 0 } get bar() { return 0 } }); } function addProperty(o) { @@ -39,28 +41,41 @@ function convertPropertyToData(o) { Object.defineProperty(o, "bar", { value: 1 }); } -assertDoesNotThrow(function(){addProperty(getClass())}); -assertDoesNotThrow(function(){convertPropertyToData(getClass())}); -assertDoesNotThrow(function(){addProperty(getClassExpr())}); -assertDoesNotThrow(function(){convertPropertyToData(getClassExpr())}); +function testWeakClass(classFunc) { + assertDoesNotThrow(function(){addProperty(classFunc())}); + assertDoesNotThrow(function(){addProperty(classFunc().prototype)}); + assertDoesNotThrow(function(){convertPropertyToData(classFunc())}); + assertDoesNotThrow(function(){convertPropertyToData(classFunc().prototype)}); +} + +function testStrongClass(classFunc) { + assertThrows(function(){addProperty(classFunc())}, TypeError); + assertThrows(function(){addProperty(classFunc().prototype)}, TypeError); + assertThrows(function(){convertPropertyToData(classFunc())}, TypeError); + assertThrows(function(){convertPropertyToData(classFunc().prototype)}, + TypeError); +} + +testWeakClass(getClass); +testWeakClass(getClassExpr); -assertThrows(function(){addProperty(getClassStrong())}, TypeError); -assertThrows(function(){convertPropertyToData(getClassStrong())}, TypeError); -assertThrows(function(){addProperty(getClassExprStrong())}, TypeError); -assertThrows(function(){convertPropertyToData(getClassExprStrong())}, - TypeError); +testStrongClass(getClassStrong); +testStrongClass(getClassExprStrong); // Check strong classes don't freeze their parents. (function() { - "use strong"; let parent = getClass(); - class Foo extends parent { - static get bar() { return 0 } + let classFunc = function() { + "use strong"; + class Foo extends parent { + static get bar() { return 0 } + get bar() { return 0 } + } + return Foo; } - assertThrows(function(){addProperty(Foo)}, TypeError); - assertThrows(function(){convertPropertyToData(Foo)}, TypeError); + testStrongClass(classFunc); assertDoesNotThrow(function(){addProperty(parent)}); assertDoesNotThrow(function(){convertPropertyToData(parent)}); })(); @@ -69,12 +84,15 @@ assertThrows(function(){convertPropertyToData(getClassExprStrong())}, (function() { let parent = getClassStrong(); - class Foo extends parent { - static get bar() { return 0 } + let classFunc = function() { + class Foo extends parent { + static get bar() { return 0 } + get bar() { return 0 } + } + return Foo; } assertThrows(function(){addProperty(parent)}, TypeError); assertThrows(function(){convertPropertyToData(parent)}, TypeError); - assertDoesNotThrow(function(){addProperty(Foo)}); - assertDoesNotThrow(function(){convertPropertyToData(Foo)}); + testWeakClass(classFunc); })(); -- 2.7.4