[strong] class objects created in strong mode have their prototype frozen
authorconradw <conradw@chromium.org>
Tue, 14 Jul 2015 11:31:38 +0000 (04:31 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 14 Jul 2015 11:31:47 +0000 (11:31 +0000)
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
src/arm64/full-codegen-arm64.cc
src/compiler/ast-graph-builder.cc
src/full-codegen.cc
src/ia32/full-codegen-ia32.cc
src/mips/full-codegen-mips.cc
src/mips64/full-codegen-mips64.cc
src/ppc/full-codegen-ppc.cc
src/x64/full-codegen-x64.cc
src/x87/full-codegen-x87.cc
test/mjsunit/strong/class-object-frozen.js

index bd6e4ab..2ed37e4 100644 (file)
@@ -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);
+  }
 }
 
 
index 7dad7d9..ad8bb90 100644 (file)
@@ -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);
+  }
 }
 
 
index 99510e3..fab7437 100644 (file)
@@ -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());
   }
 
index a97ea22..6366981 100644 (file)
@@ -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());
index 3d375fc..6615af1 100644 (file)
@@ -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);
+  }
 }
 
 
index 8f45b7d..7fca1c1 100644 (file)
@@ -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);
+  }
 }
 
 
index 9fad990..ee76d9d 100644 (file)
@@ -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);
+  }
 }
 
 
index 97850a1..0f455a0 100644 (file)
@@ -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);
+  }
 }
 
 
index eb12a47..5237e7c 100644 (file)
@@ -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);
+  }
 }
 
 
index 6a15650..584c2b9 100644 (file)
@@ -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);
+  }
 }
 
 
index 011a11d..2c442c0 100644 (file)
@@ -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);
 })();