Classes: Add support for toString
authorarv@chromium.org <arv@chromium.org>
Wed, 8 Oct 2014 14:48:48 +0000 (14:48 +0000)
committerarv@chromium.org <arv@chromium.org>
Wed, 8 Oct 2014 14:48:48 +0000 (14:48 +0000)
BUG=v8:3330
LOG=Y
R=dslomov@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24472 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/ast.h
src/full-codegen.cc
src/heap/heap.h
src/parser.cc
src/parser.h
src/preparser.h
src/runtime/runtime-classes.cc
src/runtime/runtime.h
src/v8natives.js
test/mjsunit/harmony/classes.js

index c75938e..506afa2 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -2536,22 +2536,26 @@ class ClassLiteral FINAL : public Expression {
   Expression* extends() const { return extends_; }
   Expression* constructor() const { return constructor_; }
   ZoneList<Property*>* properties() const { return properties_; }
+  int start_position() const { return position(); }
+  int end_position() const { return end_position_; }
 
  protected:
   ClassLiteral(Zone* zone, const AstRawString* name, Expression* extends,
                Expression* constructor, ZoneList<Property*>* properties,
-               int position, IdGen* id_gen)
-      : Expression(zone, position, id_gen),
+               int start_position, int end_position, IdGen* id_gen)
+      : Expression(zone, start_position, id_gen),
         raw_name_(name),
         extends_(extends),
         constructor_(constructor),
-        properties_(properties) {}
+        properties_(properties),
+        end_position_(end_position) {}
 
  private:
   const AstRawString* raw_name_;
   Expression* extends_;
   Expression* constructor_;
   ZoneList<Property*>* properties_;
+  int end_position_;
 };
 
 
@@ -3550,9 +3554,10 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
   ClassLiteral* NewClassLiteral(const AstRawString* name, Expression* extends,
                                 Expression* constructor,
                                 ZoneList<ObjectLiteral::Property*>* properties,
-                                int position) {
-    ClassLiteral* lit = new (zone_) ClassLiteral(
-        zone_, name, extends, constructor, properties, position, id_gen_);
+                                int start_position, int end_position) {
+    ClassLiteral* lit =
+        new (zone_) ClassLiteral(zone_, name, extends, constructor, properties,
+                                 start_position, end_position, id_gen_);
     VISIT_AND_RETURN(ClassLiteral, lit)
   }
 
index 8177a35..a5814c5 100644 (file)
@@ -1541,30 +1541,34 @@ void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
 }
 
 
-void FullCodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
+void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) {
   Comment cmnt(masm_, "[ ClassLiteral");
 
-  if (expr->raw_name() != NULL) {
-    __ Push(expr->name());
+  if (lit->raw_name() != NULL) {
+    __ Push(lit->name());
   } else {
     __ Push(isolate()->factory()->undefined_value());
   }
 
-  if (expr->extends() != NULL) {
-    VisitForStackValue(expr->extends());
+  if (lit->extends() != NULL) {
+    VisitForStackValue(lit->extends());
   } else {
     __ Push(isolate()->factory()->the_hole_value());
   }
 
-  if (expr->constructor() != NULL) {
-    VisitForStackValue(expr->constructor());
+  if (lit->constructor() != NULL) {
+    VisitForStackValue(lit->constructor());
   } else {
     __ Push(isolate()->factory()->undefined_value());
   }
 
+  __ Push(script());
+  __ Push(Smi::FromInt(lit->start_position()));
+  __ Push(Smi::FromInt(lit->end_position()));
+
   // TODO(arv): Process methods
 
-  __ CallRuntime(Runtime::kDefineClass, 3);
+  __ CallRuntime(Runtime::kDefineClass, 6);
   context()->Plug(result_register());
 }
 
index f26fd77..110237a 100644 (file)
@@ -340,7 +340,10 @@ namespace internal {
   V(intl_initialized_marker_symbol) \
   V(intl_impl_object_symbol)        \
   V(promise_debug_marker_symbol)    \
-  V(promise_has_handler_symbol)
+  V(promise_has_handler_symbol)     \
+  V(class_script_symbol)            \
+  V(class_start_position_symbol)    \
+  V(class_end_position_symbol)
 
 // Forward declarations.
 class HeapStats;
index 04efd1e..24d1f8a 100644 (file)
@@ -648,9 +648,10 @@ Expression* ParserTraits::SuperReference(
 
 Expression* ParserTraits::ClassExpression(
     const AstRawString* name, Expression* extends, Expression* constructor,
-    ZoneList<ObjectLiteral::Property*>* properties, int pos,
-    AstNodeFactory<AstConstructionVisitor>* factory) {
-  return factory->NewClassLiteral(name, extends, constructor, properties, pos);
+    ZoneList<ObjectLiteral::Property*>* properties, int start_position,
+    int end_position, AstNodeFactory<AstConstructionVisitor>* factory) {
+  return factory->NewClassLiteral(name, extends, constructor, properties,
+                                  start_position, end_position);
 }
 
 Literal* ParserTraits::ExpressionFromLiteral(
index e461a99..7d77767 100644 (file)
@@ -558,7 +558,7 @@ class ParserTraits {
   Expression* ClassExpression(const AstRawString* name, Expression* extends,
                               Expression* constructor,
                               ZoneList<ObjectLiteral::Property*>* properties,
-                              int pos,
+                              int start_position, int end_position,
                               AstNodeFactory<AstConstructionVisitor>* factory);
 
   Literal* ExpressionFromLiteral(
index 1def94f..ba58c10 100644 (file)
@@ -1102,7 +1102,7 @@ class PreParserFactory {
                                       PreParserExpression extends,
                                       PreParserExpression constructor,
                                       PreParserExpressionList properties,
-                                      int position) {
+                                      int start_position, int end_position) {
     return PreParserExpression::Default();
   }
 
@@ -1334,12 +1334,10 @@ class PreParserTraits {
     return PreParserExpression::Super();
   }
 
-  static PreParserExpression ClassExpression(PreParserIdentifier name,
-                                             PreParserExpression extends,
-                                             PreParserExpression constructor,
-                                             PreParserExpressionList properties,
-                                             int position,
-                                             PreParserFactory* factory) {
+  static PreParserExpression ClassExpression(
+      PreParserIdentifier name, PreParserExpression extends,
+      PreParserExpression constructor, PreParserExpressionList properties,
+      int start_position, int end_position, PreParserFactory* factory) {
     return PreParserExpression::Default();
   }
 
@@ -2805,10 +2803,12 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseClassLiteral(
       fni_->Leave();
     }
   }
+
+  int end_pos = peek_position();
   Expect(Token::RBRACE, CHECK_OK);
 
   return this->ClassExpression(name, extends, constructor, properties, pos,
-                               factory());
+                               end_pos + 1, factory());
 }
 
 
index b8cfa9b..74f3372 100644 (file)
@@ -155,10 +155,13 @@ RUNTIME_FUNCTION(Runtime_StoreToSuper_Sloppy) {
 
 RUNTIME_FUNCTION(Runtime_DefineClass) {
   HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
+  DCHECK(args.length() == 6);
   CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
   CONVERT_ARG_HANDLE_CHECKED(Object, super_class, 1);
   CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Script, script, 3);
+  CONVERT_SMI_ARG_CHECKED(start_position, 4);
+  CONVERT_SMI_ARG_CHECKED(end_position, 5);
 
   Handle<Object> prototype_parent;
   Handle<Object> constructor_parent;
@@ -228,7 +231,58 @@ RUNTIME_FUNCTION(Runtime_DefineClass) {
   JSObject::AddProperty(prototype, isolate->factory()->constructor_string(),
                         ctor, DONT_ENUM);
 
+  // Install private properties that are used to construct the FunctionToString.
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate,
+      Object::SetProperty(ctor, isolate->factory()->class_script_symbol(),
+                          script, STRICT));
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, Object::SetProperty(
+                   ctor, isolate->factory()->class_start_position_symbol(),
+                   handle(Smi::FromInt(start_position), isolate), STRICT));
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate,
+      Object::SetProperty(ctor, isolate->factory()->class_end_position_symbol(),
+                          handle(Smi::FromInt(end_position), isolate), STRICT));
+
   return *ctor;
 }
+
+
+RUNTIME_FUNCTION(Runtime_ClassGetSourceCode) {
+  HandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+
+  Handle<Object> script;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, script,
+      Object::GetProperty(fun, isolate->factory()->class_script_symbol()));
+  if (!script->IsScript()) {
+    return isolate->heap()->undefined_value();
+  }
+
+  Handle<Symbol> start_position_symbol(
+      isolate->heap()->class_start_position_symbol());
+  Handle<Object> start_position;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, start_position, Object::GetProperty(fun, start_position_symbol));
+
+  Handle<Symbol> end_position_symbol(
+      isolate->heap()->class_end_position_symbol());
+  Handle<Object> end_position;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, end_position, Object::GetProperty(fun, end_position_symbol));
+
+  if (!start_position->IsSmi() || !end_position->IsSmi() ||
+      !Handle<Script>::cast(script)->HasValidSource()) {
+    return isolate->ThrowIllegalOperation();
+  }
+
+  Handle<String> source(String::cast(Handle<Script>::cast(script)->source()));
+  return *isolate->factory()->NewSubString(
+      source, Handle<Smi>::cast(start_position)->value(),
+      Handle<Smi>::cast(end_position)->value());
+}
 }
 }  // namespace v8::internal
index b42063a..aaf98c4 100644 (file)
@@ -193,7 +193,8 @@ namespace internal {
   F(LoadKeyedFromSuper, 3, 1)                              \
   F(StoreToSuper_Strict, 4, 1)                             \
   F(StoreToSuper_Sloppy, 4, 1)                             \
-  F(DefineClass, 3, 1)
+  F(DefineClass, 6, 1)                                     \
+  F(ClassGetSourceCode, 1, 1)
 
 
 #define RUNTIME_FUNCTION_LIST_ALWAYS_2(F)              \
index 782b953..5adbca2 100644 (file)
@@ -1739,6 +1739,11 @@ function FunctionSourceString(func) {
     throw new $TypeError('Function.prototype.toString is not generic');
   }
 
+  var classSource = %ClassGetSourceCode(func);
+  if (IS_STRING(classSource)) {
+    return classSource;
+  }
+
   var source = %FunctionGetSourceCode(func);
   if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
     var name = %FunctionGetName(func);
index 7156dbd..a83d483 100644 (file)
   new C();
 })();
 */
+
+
+(function TestToString() {
+  class C {}
+  assertEquals('class C {}', C.toString());
+
+  class D { constructor() { 42; } }
+  assertEquals('class D { constructor() { 42; } }', D.toString());
+
+  class E { x() { 42; } }
+  assertEquals('class E { x() { 42; } }', E.toString());
+})();