Implement new Function.prototype.toString --harmony-function-tostring

For functions declared in source code, the .toString() representation
will be an excerpt of the source code.
* For functions declared with the "function" keyword, the excerpt
  starts at the "function" or "async" keyword and ends at the final "}".
  The previous behavior would start the excerpt at the "(" of the
  parameter list, and prepend a canonical `"function " + name` or
  similar, which would discard comments and formatting surrounding the
  function's name. Anonymous functions declared as function expressions
  no longer get the name "anonymous" in their toString representation.
* For methods, the excerpt starts at the "get", "set", "*" (for
  generator methods), or property name, whichever comes first.
  Previously, the toString representation for methods would use a
  canonical prefix before the "(" of the parameter list. Note that any
  "static" keyword is omitted.
* For arrow functions and class declarations, the excerpt is unchanged.

For functions created with the Function, GeneratorFunction, or
AsyncFunction constructors:
* The string separating the parameter text and body text is now
  "\n) {\n", where previously it was "\n/*``*/) {\n" or ") {\n".
* At one point, newline normalization was required by the spec here,
  but that was removed from the spec, and so this CL does not do it.

Included in this CL is a fix for CreateDynamicFunction parsing. ')'
and '`' characters in the parameter string are no longer disallowed,
and Function("a=function(", "}){") is no longer allowed.

BUG=v8:4958, v8:4230

Review-Url: https://codereview.chromium.org/2156303002
Cr-Commit-Position: refs/heads/master@{#43262}
diff --git a/src/api.cc b/src/api.cc
index 955e083..f7bdf67 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -2275,9 +2275,14 @@
                         Function);
   TRACE_EVENT0("v8", "V8.ScriptCompiler");
   i::Handle<i::String> source_string;
+  int parameters_end_pos = i::kNoSourcePosition;
   auto factory = isolate->factory();
   if (arguments_count) {
-    source_string = factory->NewStringFromStaticChars("(function(");
+    if (i::FLAG_harmony_function_tostring) {
+      source_string = factory->NewStringFromStaticChars("(function anonymous(");
+    } else {
+      source_string = factory->NewStringFromStaticChars("(function(");
+    }
     for (size_t i = 0; i < arguments_count; ++i) {
       IsIdentifierHelper helper;
       if (!helper.Check(*Utils::OpenHandle(*arguments[i]))) {
@@ -2295,12 +2300,24 @@
                                       ',')).ToHandle(&source_string);
       RETURN_ON_FAILED_EXECUTION(Function);
     }
-    auto brackets = factory->NewStringFromStaticChars("){");
+    i::Handle<i::String> brackets;
+    if (i::FLAG_harmony_function_tostring) {
+      brackets = factory->NewStringFromStaticChars("\n) {");
+      parameters_end_pos = source_string->length() - 3;
+    } else {
+      brackets = factory->NewStringFromStaticChars("){");
+    }
     has_pending_exception = !factory->NewConsString(source_string, brackets)
                                  .ToHandle(&source_string);
     RETURN_ON_FAILED_EXECUTION(Function);
   } else {
-    source_string = factory->NewStringFromStaticChars("(function(){");
+    if (i::FLAG_harmony_function_tostring) {
+      source_string =
+          factory->NewStringFromStaticChars("(function anonymous(\n) {");
+      parameters_end_pos = source_string->length() - 3;
+    } else {
+      source_string = factory->NewStringFromStaticChars("(function(){");
+    }
   }
 
   int scope_position = source_string->length();
@@ -2350,9 +2367,9 @@
   has_pending_exception =
       !i::Compiler::GetFunctionFromEval(
            source_string, outer_info, context, i::SLOPPY,
-           i::ONLY_SINGLE_FUNCTION_LITERAL, eval_scope_position, eval_position,
-           line_offset, column_offset - scope_position, name_obj,
-           source->resource_options)
+           i::ONLY_SINGLE_FUNCTION_LITERAL, parameters_end_pos,
+           eval_scope_position, eval_position, line_offset,
+           column_offset - scope_position, name_obj, source->resource_options)
            .ToHandle(&fun);
   if (has_pending_exception) {
     isolate->ReportPendingMessages();
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index c9069db..e894279 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -3522,6 +3522,7 @@
 EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_tailcalls)
 EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrictive_generators)
 EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_trailing_commas)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_tostring)
 EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_class_fields)
 EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_object_rest_spread)
 EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_dynamic_import)
@@ -4147,6 +4148,7 @@
 #endif
   static const char* harmony_restrictive_generators_natives[] = {nullptr};
   static const char* harmony_trailing_commas_natives[] = {nullptr};
+  static const char* harmony_function_tostring_natives[] = {nullptr};
   static const char* harmony_class_fields_natives[] = {nullptr};
   static const char* harmony_object_rest_spread_natives[] = {nullptr};
   static const char* harmony_async_iteration_natives[] = {nullptr};
diff --git a/src/builtins/builtins-function.cc b/src/builtins/builtins-function.cc
index f306ea2..1e9b7f7 100644
--- a/src/builtins/builtins-function.cc
+++ b/src/builtins/builtins-function.cc
@@ -32,11 +32,16 @@
 
   // Build the source string.
   Handle<String> source;
+  int parameters_end_pos = kNoSourcePosition;
   {
     IncrementalStringBuilder builder(isolate);
     builder.AppendCharacter('(');
     builder.AppendCString(token);
-    builder.AppendCharacter('(');
+    if (FLAG_harmony_function_tostring) {
+      builder.AppendCString(" anonymous(");
+    } else {
+      builder.AppendCharacter('(');
+    }
     bool parenthesis_in_arg_string = false;
     if (argc > 1) {
       for (int i = 1; i < argc; ++i) {
@@ -46,22 +51,30 @@
             isolate, param, Object::ToString(isolate, args.at(i)), Object);
         param = String::Flatten(param);
         builder.AppendString(param);
-        // If the formal parameters string include ) - an illegal
-        // character - it may make the combined function expression
-        // compile. We avoid this problem by checking for this early on.
-        DisallowHeapAllocation no_gc;  // Ensure vectors stay valid.
-        String::FlatContent param_content = param->GetFlatContent();
-        for (int i = 0, length = param->length(); i < length; ++i) {
-          if (param_content.Get(i) == ')') {
-            parenthesis_in_arg_string = true;
-            break;
+        if (!FLAG_harmony_function_tostring) {
+          // If the formal parameters string include ) - an illegal
+          // character - it may make the combined function expression
+          // compile. We avoid this problem by checking for this early on.
+          DisallowHeapAllocation no_gc;  // Ensure vectors stay valid.
+          String::FlatContent param_content = param->GetFlatContent();
+          for (int i = 0, length = param->length(); i < length; ++i) {
+            if (param_content.Get(i) == ')') {
+              parenthesis_in_arg_string = true;
+              break;
+            }
           }
         }
       }
-      // If the formal parameters include an unbalanced block comment, the
-      // function must be rejected. Since JavaScript does not allow nested
-      // comments we can include a trailing block comment to catch this.
-      builder.AppendCString("\n/*``*/");
+      if (!FLAG_harmony_function_tostring) {
+        // If the formal parameters include an unbalanced block comment, the
+        // function must be rejected. Since JavaScript does not allow nested
+        // comments we can include a trailing block comment to catch this.
+        builder.AppendCString("\n/*``*/");
+      }
+    }
+    if (FLAG_harmony_function_tostring) {
+      builder.AppendCharacter('\n');
+      parameters_end_pos = builder.Length();
     }
     builder.AppendCString(") {\n");
     if (argc > 0) {
@@ -86,11 +99,12 @@
   // come from here.
   Handle<JSFunction> function;
   {
-    ASSIGN_RETURN_ON_EXCEPTION(isolate, function,
-                               Compiler::GetFunctionFromString(
-                                   handle(target->native_context(), isolate),
-                                   source, ONLY_SINGLE_FUNCTION_LITERAL),
-                               Object);
+    ASSIGN_RETURN_ON_EXCEPTION(
+        isolate, function,
+        Compiler::GetFunctionFromString(
+            handle(target->native_context(), isolate), source,
+            ONLY_SINGLE_FUNCTION_LITERAL, parameters_end_pos),
+        Object);
     Handle<Object> result;
     ASSIGN_RETURN_ON_EXCEPTION(
         isolate, result,
diff --git a/src/builtins/builtins-global.cc b/src/builtins/builtins-global.cc
index 6c97a0b..e70ecda 100644
--- a/src/builtins/builtins-global.cc
+++ b/src/builtins/builtins-global.cc
@@ -92,9 +92,10 @@
   }
   Handle<JSFunction> function;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, function, Compiler::GetFunctionFromString(
-                             handle(target->native_context(), isolate),
-                             Handle<String>::cast(x), NO_PARSE_RESTRICTION));
+      isolate, function,
+      Compiler::GetFunctionFromString(handle(target->native_context(), isolate),
+                                      Handle<String>::cast(x),
+                                      NO_PARSE_RESTRICTION, kNoSourcePosition));
   RETURN_RESULT_OR_FAILURE(
       isolate,
       Execution::Call(isolate, function, target_global_proxy, 0, nullptr));
diff --git a/src/compilation-cache.cc b/src/compilation-cache.cc
index 15cf9ac..8b2e51e 100644
--- a/src/compilation-cache.cc
+++ b/src/compilation-cache.cc
@@ -194,8 +194,7 @@
 
 InfoVectorPair CompilationCacheEval::Lookup(
     Handle<String> source, Handle<SharedFunctionInfo> outer_info,
-    Handle<Context> native_context, LanguageMode language_mode,
-    int scope_position) {
+    Handle<Context> native_context, LanguageMode language_mode, int position) {
   HandleScope scope(isolate());
   // Make sure not to leak the table into the surrounding handle
   // scope. Otherwise, we risk keeping old tables around even after
@@ -205,7 +204,7 @@
   DCHECK(generations() == 1);
   Handle<CompilationCacheTable> table = GetTable(generation);
   result = table->LookupEval(source, outer_info, native_context, language_mode,
-                             scope_position);
+                             position);
   if (result.has_shared()) {
     isolate()->counters()->compilation_cache_hits()->Increment();
   } else {
@@ -218,12 +217,12 @@
                                Handle<SharedFunctionInfo> outer_info,
                                Handle<SharedFunctionInfo> function_info,
                                Handle<Context> native_context,
-                               Handle<Cell> literals, int scope_position) {
+                               Handle<Cell> literals, int position) {
   HandleScope scope(isolate());
   Handle<CompilationCacheTable> table = GetFirstTable();
   table =
       CompilationCacheTable::PutEval(table, source, outer_info, function_info,
-                                     native_context, literals, scope_position);
+                                     native_context, literals, position);
   SetFirstTable(table);
 }
 
@@ -286,18 +285,18 @@
 
 InfoVectorPair CompilationCache::LookupEval(
     Handle<String> source, Handle<SharedFunctionInfo> outer_info,
-    Handle<Context> context, LanguageMode language_mode, int scope_position) {
+    Handle<Context> context, LanguageMode language_mode, int position) {
   InfoVectorPair result;
   if (!IsEnabled()) return result;
 
   if (context->IsNativeContext()) {
     result = eval_global_.Lookup(source, outer_info, context, language_mode,
-                                 scope_position);
+                                 position);
   } else {
-    DCHECK(scope_position != kNoSourcePosition);
+    DCHECK(position != kNoSourcePosition);
     Handle<Context> native_context(context->native_context(), isolate());
     result = eval_contextual_.Lookup(source, outer_info, native_context,
-                                     language_mode, scope_position);
+                                     language_mode, position);
   }
 
   return result;
@@ -324,18 +323,18 @@
                                Handle<SharedFunctionInfo> outer_info,
                                Handle<Context> context,
                                Handle<SharedFunctionInfo> function_info,
-                               Handle<Cell> literals, int scope_position) {
+                               Handle<Cell> literals, int position) {
   if (!IsEnabled()) return;
 
   HandleScope scope(isolate());
   if (context->IsNativeContext()) {
     eval_global_.Put(source, outer_info, function_info, context, literals,
-                     scope_position);
+                     position);
   } else {
-    DCHECK(scope_position != kNoSourcePosition);
+    DCHECK(position != kNoSourcePosition);
     Handle<Context> native_context(context->native_context(), isolate());
     eval_contextual_.Put(source, outer_info, function_info, native_context,
-                         literals, scope_position);
+                         literals, position);
   }
 }
 
diff --git a/src/compilation-cache.h b/src/compilation-cache.h
index d1c3504..229fe07 100644
--- a/src/compilation-cache.h
+++ b/src/compilation-cache.h
@@ -116,12 +116,11 @@
   InfoVectorPair Lookup(Handle<String> source,
                         Handle<SharedFunctionInfo> outer_info,
                         Handle<Context> native_context,
-                        LanguageMode language_mode, int scope_position);
+                        LanguageMode language_mode, int position);
 
   void Put(Handle<String> source, Handle<SharedFunctionInfo> outer_info,
            Handle<SharedFunctionInfo> function_info,
-           Handle<Context> native_context, Handle<Cell> literals,
-           int scope_position);
+           Handle<Context> native_context, Handle<Cell> literals, int position);
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval);
@@ -164,7 +163,7 @@
   InfoVectorPair LookupEval(Handle<String> source,
                             Handle<SharedFunctionInfo> outer_info,
                             Handle<Context> context, LanguageMode language_mode,
-                            int scope_position);
+                            int position);
 
   // Returns the regexp data associated with the given regexp if it
   // is in cache, otherwise an empty handle.
@@ -183,7 +182,7 @@
   void PutEval(Handle<String> source, Handle<SharedFunctionInfo> outer_info,
                Handle<Context> context,
                Handle<SharedFunctionInfo> function_info, Handle<Cell> literals,
-               int scope_position);
+               int position);
 
   // Associate the (source, flags) pair to the given regexp data.
   // This may overwrite an existing mapping.
diff --git a/src/compiler.cc b/src/compiler.cc
index 8c5deb2..4e34407 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -1476,17 +1476,35 @@
 MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
     Handle<String> source, Handle<SharedFunctionInfo> outer_info,
     Handle<Context> context, LanguageMode language_mode,
-    ParseRestriction restriction, int eval_scope_position, int eval_position,
-    int line_offset, int column_offset, Handle<Object> script_name,
+    ParseRestriction restriction, int parameters_end_pos,
+    int eval_scope_position, int eval_position, int line_offset,
+    int column_offset, Handle<Object> script_name,
     ScriptOriginOptions options) {
   Isolate* isolate = source->GetIsolate();
   int source_length = source->length();
   isolate->counters()->total_eval_size()->Increment(source_length);
   isolate->counters()->total_compile_size()->Increment(source_length);
 
+  // The cache lookup key needs to be aware of the separation between the
+  // parameters and the body to prevent this valid invocation:
+  //   Function("", "function anonymous(\n/**/) {\n}");
+  // from adding an entry that falsely approves this invalid invocation:
+  //   Function("\n/**/) {\nfunction anonymous(", "}");
+  // The actual eval_scope_position for indirect eval and CreateDynamicFunction
+  // is unused (just 0), which means it's an available field to use to indicate
+  // this separation. But to make sure we're not causing other false hits, we
+  // negate the scope position.
+  int position = eval_scope_position;
+  if (FLAG_harmony_function_tostring &&
+      restriction == ONLY_SINGLE_FUNCTION_LITERAL &&
+      parameters_end_pos != kNoSourcePosition) {
+    // use the parameters_end_pos as the eval_scope_position in the eval cache.
+    DCHECK_EQ(eval_scope_position, 0);
+    position = -parameters_end_pos;
+  }
   CompilationCache* compilation_cache = isolate->compilation_cache();
   InfoVectorPair eval_result = compilation_cache->LookupEval(
-      source, outer_info, context, language_mode, eval_scope_position);
+      source, outer_info, context, language_mode, position);
   Handle<SharedFunctionInfo> shared_info;
   if (eval_result.has_shared()) {
     shared_info = Handle<SharedFunctionInfo>(eval_result.shared(), isolate);
@@ -1518,6 +1536,7 @@
     parse_info.set_eval();
     parse_info.set_language_mode(language_mode);
     parse_info.set_parse_restriction(restriction);
+    parse_info.set_parameters_end_pos(parameters_end_pos);
     if (!context->IsNativeContext()) {
       parse_info.set_outer_scope_info(handle(context->scope_info()));
     }
@@ -1595,7 +1614,7 @@
 
 MaybeHandle<JSFunction> Compiler::GetFunctionFromString(
     Handle<Context> context, Handle<String> source,
-    ParseRestriction restriction) {
+    ParseRestriction restriction, int parameters_end_pos) {
   Isolate* const isolate = context->GetIsolate();
   Handle<Context> native_context(context->native_context(), isolate);
 
@@ -1615,8 +1634,8 @@
   int eval_position = kNoSourcePosition;
   Handle<SharedFunctionInfo> outer_info(native_context->closure()->shared());
   return Compiler::GetFunctionFromEval(source, outer_info, native_context,
-                                       SLOPPY, restriction, eval_scope_position,
-                                       eval_position);
+                                       SLOPPY, restriction, parameters_end_pos,
+                                       eval_scope_position, eval_position);
 }
 
 Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
diff --git a/src/compiler.h b/src/compiler.h
index 7261889..e26484a 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -98,15 +98,15 @@
   MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionFromEval(
       Handle<String> source, Handle<SharedFunctionInfo> outer_info,
       Handle<Context> context, LanguageMode language_mode,
-      ParseRestriction restriction, int eval_scope_position, int eval_position,
-      int line_offset = 0, int column_offset = 0,
-      Handle<Object> script_name = Handle<Object>(),
+      ParseRestriction restriction, int parameters_end_pos,
+      int eval_scope_position, int eval_position, int line_offset = 0,
+      int column_offset = 0, Handle<Object> script_name = Handle<Object>(),
       ScriptOriginOptions options = ScriptOriginOptions());
 
   // Create a (bound) function for a String source within a context for eval.
   MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionFromString(
       Handle<Context> context, Handle<String> source,
-      ParseRestriction restriction);
+      ParseRestriction restriction, int parameters_end_pos);
 
   // Create a shared function info object for a String source within a context.
   static Handle<SharedFunctionInfo> GetSharedFunctionInfoForScript(
diff --git a/src/debug/debug-evaluate.cc b/src/debug/debug-evaluate.cc
index 281e6fd..51b3b51 100644
--- a/src/debug/debug-evaluate.cc
+++ b/src/debug/debug-evaluate.cc
@@ -93,7 +93,7 @@
       isolate, eval_fun,
       Compiler::GetFunctionFromEval(source, outer_info, context, SLOPPY,
                                     NO_PARSE_RESTRICTION, kNoSourcePosition,
-                                    kNoSourcePosition),
+                                    kNoSourcePosition, kNoSourcePosition),
       Object);
 
   Handle<Object> result;
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index b24a91c..8377875 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -202,6 +202,7 @@
   V(harmony_do_expressions, "harmony do-expressions")                   \
   V(harmony_regexp_named_captures, "harmony regexp named captures")     \
   V(harmony_regexp_property, "harmony unicode regexp property classes") \
+  V(harmony_function_tostring, "harmony Function.prototype.toString")   \
   V(harmony_class_fields, "harmony public fields in class literals")    \
   V(harmony_async_iteration, "harmony async iteration")                 \
   V(harmony_dynamic_import, "harmony dynamic import")
diff --git a/src/messages.h b/src/messages.h
index 814470c..bb595c2 100644
--- a/src/messages.h
+++ b/src/messages.h
@@ -593,6 +593,9 @@
     "Setter function argument must not be a rest parameter")                   \
   T(ParamDupe, "Duplicate parameter name not allowed in this context")         \
   T(ParenthesisInArgString, "Function arg string contains parenthesis")        \
+  T(ArgStringTerminatesParametersEarly,                                        \
+    "Arg string terminates parameters early")                                  \
+  T(UnexpectedEndOfArgString, "Unexpected end of arg string")                  \
   T(RuntimeWrongNumArgs, "Runtime function given wrong number of arguments")   \
   T(SingleFunctionLiteral, "Single function literal required")                 \
   T(SloppyFunction,                                                            \
diff --git a/src/objects.cc b/src/objects.cc
index 2d3fa68..989d678 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -12820,6 +12820,10 @@
     return NativeCodeFunctionSourceString(shared_info);
   }
 
+  if (FLAG_harmony_function_tostring) {
+    return Handle<String>::cast(shared_info->GetSourceCodeHarmony());
+  }
+
   IncrementalStringBuilder builder(isolate);
   FunctionKind kind = shared_info->kind();
   if (!IsArrowFunction(kind)) {
@@ -13290,6 +13294,15 @@
       source, start_position(), end_position());
 }
 
+Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony() {
+  Isolate* isolate = GetIsolate();
+  if (!HasSourceCode()) return isolate->factory()->undefined_value();
+  Handle<String> script_source(String::cast(Script::cast(script())->source()));
+  int start_pos = function_token_position();
+  if (start_pos == kNoSourcePosition) start_pos = start_position();
+  return isolate->factory()->NewSubString(script_source, start_pos,
+                                          end_position());
+}
 
 bool SharedFunctionInfo::IsInlineable() {
   // Check that the function has a script associated with it.
@@ -15767,12 +15780,22 @@
 // StringSharedKeys are used as keys in the eval cache.
 class StringSharedKey : public HashTableKey {
  public:
+  // This tuple unambiguously identifies calls to eval() or
+  // CreateDynamicFunction() (such as through the Function() constructor).
+  // * source is the string passed into eval(). For dynamic functions, this is
+  //   the effective source for the function, some of which is implicitly
+  //   generated.
+  // * shared is the shared function info for the function containing the call
+  //   to eval(). for dynamic functions, shared is the native context closure.
+  // * When positive, position is the position in the source where eval is
+  //   called. When negative, position is the negation of the position in the
+  //   dynamic function's effective source where the ')' ends the parameters.
   StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
-                  LanguageMode language_mode, int scope_position)
+                  LanguageMode language_mode, int position)
       : source_(source),
         shared_(shared),
         language_mode_(language_mode),
-        scope_position_(scope_position) {}
+        position_(position) {}
 
   bool IsMatch(Object* other) override {
     DisallowHeapAllocation no_allocation;
@@ -15788,8 +15811,8 @@
     DCHECK(is_valid_language_mode(language_unchecked));
     LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
     if (language_mode != language_mode_) return false;
-    int scope_position = Smi::cast(other_array->get(3))->value();
-    if (scope_position != scope_position_) return false;
+    int position = Smi::cast(other_array->get(3))->value();
+    if (position != position_) return false;
     String* source = String::cast(other_array->get(1));
     return source->Equals(*source_);
   }
@@ -15797,7 +15820,7 @@
   static uint32_t StringSharedHashHelper(String* source,
                                          SharedFunctionInfo* shared,
                                          LanguageMode language_mode,
-                                         int scope_position) {
+                                         int position) {
     uint32_t hash = source->Hash();
     if (shared->HasSourceCode()) {
       // Instead of using the SharedFunctionInfo pointer in the hash
@@ -15809,14 +15832,14 @@
       hash ^= String::cast(script->source())->Hash();
       STATIC_ASSERT(LANGUAGE_END == 2);
       if (is_strict(language_mode)) hash ^= 0x8000;
-      hash += scope_position;
+      hash += position;
     }
     return hash;
   }
 
   uint32_t Hash() override {
     return StringSharedHashHelper(*source_, *shared_, language_mode_,
-                                  scope_position_);
+                                  position_);
   }
 
   uint32_t HashForObject(Object* obj) override {
@@ -15830,9 +15853,8 @@
     int language_unchecked = Smi::cast(other_array->get(2))->value();
     DCHECK(is_valid_language_mode(language_unchecked));
     LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
-    int scope_position = Smi::cast(other_array->get(3))->value();
-    return StringSharedHashHelper(source, shared, language_mode,
-                                  scope_position);
+    int position = Smi::cast(other_array->get(3))->value();
+    return StringSharedHashHelper(source, shared, language_mode, position);
   }
 
 
@@ -15841,7 +15863,7 @@
     array->set(0, *shared_);
     array->set(1, *source_);
     array->set(2, Smi::FromInt(language_mode_));
-    array->set(3, Smi::FromInt(scope_position_));
+    array->set(3, Smi::FromInt(position_));
     return array;
   }
 
@@ -15849,7 +15871,7 @@
   Handle<String> source_;
   Handle<SharedFunctionInfo> shared_;
   LanguageMode language_mode_;
-  int scope_position_;
+  int position_;
 };
 
 // static
@@ -17451,12 +17473,9 @@
 
 InfoVectorPair CompilationCacheTable::LookupEval(
     Handle<String> src, Handle<SharedFunctionInfo> outer_info,
-    Handle<Context> native_context, LanguageMode language_mode,
-    int scope_position) {
+    Handle<Context> native_context, LanguageMode language_mode, int position) {
   InfoVectorPair empty_result;
-  // Cache key is the tuple (source, outer shared function info, scope position)
-  // to unambiguously identify the context chain the cached eval code assumes.
-  StringSharedKey key(src, outer_info, language_mode, scope_position);
+  StringSharedKey key(src, outer_info, language_mode, position);
   int entry = FindEntry(&key);
   if (entry == kNotFound) return empty_result;
   int index = EntryToIndex(entry);
@@ -17517,9 +17536,9 @@
 Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
     Handle<CompilationCacheTable> cache, Handle<String> src,
     Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
-    Handle<Context> native_context, Handle<Cell> literals, int scope_position) {
+    Handle<Context> native_context, Handle<Cell> literals, int position) {
   Isolate* isolate = cache->GetIsolate();
-  StringSharedKey key(src, outer_info, value->language_mode(), scope_position);
+  StringSharedKey key(src, outer_info, value->language_mode(), position);
   {
     Handle<Object> k = key.AsHandle(isolate);
     int entry = cache->FindEntry(&key);
diff --git a/src/objects.h b/src/objects.h
index 3f8f54f..7a3fa76 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -7291,6 +7291,7 @@
   // [source code]: Source code for the function.
   bool HasSourceCode() const;
   Handle<Object> GetSourceCode();
+  Handle<Object> GetSourceCodeHarmony();
 
   // Number of times the function was optimized.
   inline int opt_count();
@@ -8677,7 +8678,7 @@
   InfoVectorPair LookupEval(Handle<String> src,
                             Handle<SharedFunctionInfo> shared,
                             Handle<Context> native_context,
-                            LanguageMode language_mode, int scope_position);
+                            LanguageMode language_mode, int position);
   Handle<Object> LookupRegExp(Handle<String> source, JSRegExp::Flags flags);
   static Handle<CompilationCacheTable> Put(
       Handle<CompilationCacheTable> cache, Handle<String> src,
@@ -8690,8 +8691,7 @@
   static Handle<CompilationCacheTable> PutEval(
       Handle<CompilationCacheTable> cache, Handle<String> src,
       Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
-      Handle<Context> native_context, Handle<Cell> literals,
-      int scope_position);
+      Handle<Context> native_context, Handle<Cell> literals, int position);
   static Handle<CompilationCacheTable> PutRegExp(
       Handle<CompilationCacheTable> cache, Handle<String> src,
       JSRegExp::Flags flags, Handle<FixedArray> value);
diff --git a/src/parsing/parse-info.cc b/src/parsing/parse-info.cc
index 535021e..37dca66 100644
--- a/src/parsing/parse-info.cc
+++ b/src/parsing/parse-info.cc
@@ -31,6 +31,7 @@
       compiler_hints_(0),
       start_position_(0),
       end_position_(0),
+      parameters_end_pos_(kNoSourcePosition),
       function_literal_id_(FunctionLiteral::kIdTypeInvalid),
       max_function_literal_id_(FunctionLiteral::kIdTypeInvalid),
       isolate_(nullptr),
diff --git a/src/parsing/parse-info.h b/src/parsing/parse-info.h
index a53626f..4828690 100644
--- a/src/parsing/parse-info.h
+++ b/src/parsing/parse-info.h
@@ -169,6 +169,11 @@
   int end_position() const { return end_position_; }
   void set_end_position(int end_position) { end_position_ = end_position; }
 
+  int parameters_end_pos() const { return parameters_end_pos_; }
+  void set_parameters_end_pos(int parameters_end_pos) {
+    parameters_end_pos_ = parameters_end_pos;
+  }
+
   int function_literal_id() const { return function_literal_id_; }
   void set_function_literal_id(int function_literal_id) {
     function_literal_id_ = function_literal_id;
@@ -262,6 +267,7 @@
   int compiler_hints_;
   int start_position_;
   int end_position_;
+  int parameters_end_pos_;
   int function_literal_id_;
   int max_function_literal_id_;
 
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
index 1260378..b6458a1 100644
--- a/src/parsing/parser-base.h
+++ b/src/parsing/parser-base.h
@@ -2191,10 +2191,12 @@
 
   Token::Value name_token = peek();
 
+  int function_token_position = scanner()->peek_location().beg_pos;
   IdentifierT name = impl()->EmptyIdentifier();
   ExpressionT name_expression;
   if (name_token == Token::STATIC) {
     Consume(Token::STATIC);
+    function_token_position = scanner()->peek_location().beg_pos;
     if (peek() == Token::LPAREN) {
       kind = PropertyKind::kMethodProperty;
       name = impl()->GetSymbol();  // TODO(bakkot) specialize on 'static'
@@ -2271,8 +2273,10 @@
 
       ExpressionT value = impl()->ParseFunctionLiteral(
           name, scanner()->location(), kSkipFunctionNameCheck, kind,
-          kNoSourcePosition, FunctionLiteral::kAccessorOrMethod,
-          language_mode(), CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+          FLAG_harmony_function_tostring ? function_token_position
+                                         : kNoSourcePosition,
+          FunctionLiteral::kAccessorOrMethod, language_mode(),
+          CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
 
       *property_kind = ClassLiteralProperty::METHOD;
       return factory()->NewClassLiteralProperty(name_expression, value,
@@ -2299,8 +2303,10 @@
 
       FunctionLiteralT value = impl()->ParseFunctionLiteral(
           name, scanner()->location(), kSkipFunctionNameCheck, kind,
-          kNoSourcePosition, FunctionLiteral::kAccessorOrMethod,
-          language_mode(), CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+          FLAG_harmony_function_tostring ? function_token_position
+                                         : kNoSourcePosition,
+          FunctionLiteral::kAccessorOrMethod, language_mode(),
+          CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
 
       if (!*is_computed_name) {
         impl()->AddAccessorPrefixToFunctionName(is_get, value, name);
@@ -2494,8 +2500,9 @@
 
       ExpressionT value = impl()->ParseFunctionLiteral(
           name, scanner()->location(), kSkipFunctionNameCheck, kind,
-          kNoSourcePosition, FunctionLiteral::kAccessorOrMethod,
-          language_mode(), CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+          FLAG_harmony_function_tostring ? next_beg_pos : kNoSourcePosition,
+          FunctionLiteral::kAccessorOrMethod, language_mode(),
+          CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
 
       return factory()->NewObjectLiteralProperty(
           name_expression, value, ObjectLiteralProperty::COMPUTED,
@@ -2523,8 +2530,9 @@
 
       FunctionLiteralT value = impl()->ParseFunctionLiteral(
           name, scanner()->location(), kSkipFunctionNameCheck, kind,
-          kNoSourcePosition, FunctionLiteral::kAccessorOrMethod,
-          language_mode(), CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+          FLAG_harmony_function_tostring ? next_beg_pos : kNoSourcePosition,
+          FunctionLiteral::kAccessorOrMethod, language_mode(),
+          CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
 
       if (!*is_computed_name) {
         impl()->AddAccessorPrefixToFunctionName(is_get, value, name);
@@ -3363,7 +3371,12 @@
     Scanner::Location function_name_location = Scanner::Location::invalid();
     FunctionLiteral::FunctionType function_type =
         FunctionLiteral::kAnonymousExpression;
-    if (peek_any_identifier()) {
+    if (impl()->ParsingDynamicFunctionDeclaration()) {
+      // We don't want dynamic functions to actually declare their name
+      // "anonymous". We just want that name in the toString().
+      Consume(Token::IDENTIFIER);
+      DCHECK(scanner()->UnescapedLiteralMatches("anonymous", 9));
+    } else if (peek_any_identifier()) {
       name = ParseIdentifierOrStrictReservedWord(
           function_kind, &is_strict_reserved_name, CHECK_OK);
       function_name_location = scanner()->location();
@@ -4376,7 +4389,12 @@
   IdentifierT name = impl()->EmptyIdentifier();
   FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression;
 
-  if (peek_any_identifier()) {
+  if (impl()->ParsingDynamicFunctionDeclaration()) {
+    // We don't want dynamic functions to actually declare their name
+    // "anonymous". We just want that name in the toString().
+    Consume(Token::IDENTIFIER);
+    DCHECK(scanner()->UnescapedLiteralMatches("anonymous", 9));
+  } else if (peek_any_identifier()) {
     type = FunctionLiteral::kNamedExpression;
     name = ParseIdentifierOrStrictReservedWord(FunctionKind::kAsyncFunction,
                                                &is_strict_reserved, CHECK_OK);
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
index 2455aa2..8b92eb2 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -516,7 +516,8 @@
       total_preparse_skipped_(0),
       temp_zoned_(false),
       log_(nullptr),
-      preparsed_scope_data_(info->preparsed_scope_data()) {
+      preparsed_scope_data_(info->preparsed_scope_data()),
+      parameters_end_pos_(info->parameters_end_pos()) {
   // Even though we were passed ParseInfo, we should not store it in
   // Parser - this makes sure that Isolate is not accidentally accessed via
   // ParseInfo during background parsing.
@@ -2749,6 +2750,7 @@
     int* expected_property_count, bool is_inner_function, bool may_abort,
     bool* ok) {
   DCHECK_NE(kNoSourcePosition, function_scope->start_position());
+  DCHECK_EQ(kNoSourcePosition, parameters_end_pos_);
   if (produce_cached_parse_data()) CHECK(log_);
 
   DCHECK_IMPLIES(IsArrowFunction(kind),
@@ -3127,8 +3129,34 @@
 
   if (IsResumableFunction(kind)) PrepareGeneratorVariables();
 
+  int expected_parameters_end_pos = parameters_end_pos_;
+  if (expected_parameters_end_pos != kNoSourcePosition) {
+    // This is the first function encountered in a CreateDynamicFunction eval.
+    parameters_end_pos_ = kNoSourcePosition;
+    // The function name should have been ignored, giving us the empty string
+    // here.
+    DCHECK_EQ(function_name, ast_value_factory()->empty_string());
+  }
+
   ParserFormalParameters formals(function_scope);
   ParseFormalParameterList(&formals, CHECK_OK);
+  if (expected_parameters_end_pos != kNoSourcePosition) {
+    // Check for '(' or ')' shenanigans in the parameter string for dynamic
+    // functions.
+    int position = peek_position();
+    if (position < expected_parameters_end_pos) {
+      ReportMessageAt(Scanner::Location(position, position + 1),
+                      MessageTemplate::kArgStringTerminatesParametersEarly);
+      *ok = false;
+      return nullptr;
+    } else if (position > expected_parameters_end_pos) {
+      ReportMessageAt(Scanner::Location(expected_parameters_end_pos - 2,
+                                        expected_parameters_end_pos),
+                      MessageTemplate::kUnexpectedEndOfArgString);
+      *ok = false;
+      return nullptr;
+    }
+  }
   Expect(Token::RPAREN, CHECK_OK);
   int formals_end_position = scanner()->location().end_pos;
   *num_parameters = formals.num_parameters();
diff --git a/src/parsing/parser.h b/src/parsing/parser.h
index a74fda8..668f0e7 100644
--- a/src/parsing/parser.h
+++ b/src/parsing/parser.h
@@ -1121,6 +1121,12 @@
     ++use_counts_[feature];
   }
 
+  // Returns true iff we're parsing the first function literal during
+  // CreateDynamicFunction().
+  V8_INLINE bool ParsingDynamicFunctionDeclaration() const {
+    return parameters_end_pos_ != kNoSourcePosition;
+  }
+
   // Parser's private field members.
   friend class DiscardableZoneScope;  // Uses reusable_preparser_.
   // FIXME(marja): Make reusable_preparser_ always use its own temp Zone (call
@@ -1149,6 +1155,12 @@
   ParserLogger* log_;
 
   PreParsedScopeData* preparsed_scope_data_;
+
+  // If not kNoSourcePosition, indicates that the first function literal
+  // encountered is a dynamic function, see CreateDynamicFunction(). This field
+  // indicates the correct position of the ')' that closes the parameter list.
+  // After that ')' is encountered, this field is reset to kNoSourcePosition.
+  int parameters_end_pos_;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/src/parsing/preparser.h b/src/parsing/preparser.h
index 30a77d1..0c5e269 100644
--- a/src/parsing/preparser.h
+++ b/src/parsing/preparser.h
@@ -1690,6 +1690,8 @@
     if (use_counts_ != nullptr) ++use_counts_[feature];
   }
 
+  V8_INLINE bool ParsingDynamicFunctionDeclaration() const { return false; }
+
   // Preparser's private field members.
 
   int* use_counts_;
diff --git a/src/runtime/runtime-compiler.cc b/src/runtime/runtime-compiler.cc
index 699c4c3..f929d73 100644
--- a/src/runtime/runtime-compiler.cc
+++ b/src/runtime/runtime-compiler.cc
@@ -446,9 +446,10 @@
   static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
   Handle<JSFunction> compiled;
   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-      isolate, compiled, Compiler::GetFunctionFromEval(
-                             source, outer_info, context, language_mode,
-                             restriction, eval_scope_position, eval_position),
+      isolate, compiled,
+      Compiler::GetFunctionFromEval(source, outer_info, context, language_mode,
+                                    restriction, kNoSourcePosition,
+                                    eval_scope_position, eval_position),
       isolate->heap()->exception());
   return *compiled;
 }
diff --git a/src/string-builder.h b/src/string-builder.h
index edc6476..c8c1329 100644
--- a/src/string-builder.h
+++ b/src/string-builder.h
@@ -310,6 +310,8 @@
 
   INLINE(bool HasOverflowed()) const { return overflowed_; }
 
+  INLINE(int Length()) const { return accumulator_->length() + current_index_; }
+
   // Change encoding to two-byte.
   void ChangeEncoding() {
     DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_);
diff --git a/test/cctest/wasm/test-wasm-breakpoints.cc b/test/cctest/wasm/test-wasm-breakpoints.cc
index b38d1bc..d23f255 100644
--- a/test/cctest/wasm/test-wasm-breakpoints.cc
+++ b/test/cctest/wasm/test-wasm-breakpoints.cc
@@ -138,7 +138,8 @@
   Handle<String> source = isolate->factory()->NewStringFromStaticChars("true");
   Handle<Context> context(isolate->context(), isolate);
   Handle<JSFunction> triggered_fun =
-      Compiler::GetFunctionFromString(context, source, NO_PARSE_RESTRICTION)
+      Compiler::GetFunctionFromString(context, source, NO_PARSE_RESTRICTION,
+                                      kNoSourcePosition)
           .ToHandleChecked();
   PropertyDescriptor desc;
   desc.set_value(triggered_fun);
diff --git a/test/mjsunit/harmony/function-tostring.js b/test/mjsunit/harmony/function-tostring.js
new file mode 100644
index 0000000..949ac22
--- /dev/null
+++ b/test/mjsunit/harmony/function-tostring.js
@@ -0,0 +1,124 @@
+// Copyright 2016 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: --harmony-function-tostring
+
+var prefix = "/*before*/";
+var suffix = "/*after*/";
+
+function checkStringRepresentation(f, source) {
+  assertEquals(typeof f, "function");
+  assertEquals(source, f.toString());
+}
+
+function testDeclaration(source) {
+  // this eval should define a local variable f that is a function
+  eval(prefix + source + suffix);
+  checkStringRepresentation(f, source);
+}
+testDeclaration(          "function f(){}");
+testDeclaration(          "function*f(){}");
+testDeclaration("async     function f(){}");
+testDeclaration(          "function/*A*/ f/*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
+testDeclaration(          "function/*A*/*f/*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
+testDeclaration("async/*Z*/function/*A*/ f/*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
+testDeclaration(          "function  \t  f  \n ( \r  a \r\n,\n\r b     )  {'\u2654'}");
+testDeclaration(          "function  \t *f  \n ( \r  a \r\n,\n\r b     )     {     }");
+testDeclaration(          "function *\t  f  \n ( \r  a \r\n,\n\r b     )     {     }");
+testDeclaration("async \t  function      f  \n ( \r  a \r\n,\n\r b     )     {     }");
+
+function testExpression(source) {
+  // this eval should return a function
+  var f = eval("(" + prefix + source + suffix + ")");
+  checkStringRepresentation(f, source);
+}
+testExpression(          "function  (){}");
+testExpression(          "function f(){}");
+testExpression(          "function* (){}");
+testExpression(          "function*f(){}");
+testExpression("async     function  (){}");
+testExpression("async     function f(){}");
+testExpression(          "function/*A*/  /*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
+testExpression(          "function/*A*/ f/*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
+testExpression(          "function/*A*/* /*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
+testExpression(          "function/*A*/*f/*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
+testExpression("async/*Z*/function/*A*/ f/*B*/(/*C*/a/*D*/,/*E*/b/*G*/)/*H*/{/*I*/}");
+testExpression(          "function  \t     \n ( \r  a \r\n,\n\r b     )     {     }");
+testExpression(          "function  \t  f  \n ( \r  a \r\n,\n\r b     )     {     }");
+testExpression(          "function  \t *   \n ( \r  a \r\n,\n\r b     )     {     }");
+testExpression(          "function  \t *f  \n ( \r  a \r\n,\n\r b     )     {     }");
+testExpression(          "function *\t     \n ( \r  a \r\n,\n\r b     )     {     }");
+testExpression(          "function *\t  f  \n ( \r  a \r\n,\n\r b     )     {     }");
+testExpression("async \t  function         \n ( \r  a \r\n,\n\r b     )     {     }");
+
+testExpression(      "(/*A*/ /*B*/ /*C*/ /*D*/ /*E*/ /*F*/)/*G*/=>/*H*/0");
+testExpression(            "a/*B*/ /*C*/ /*D*/ /*E*/ /*F*/ /*G*/=>/*H*/{}");
+testExpression(      "(/*A*/a/*B*/ /*C*/ /*D*/ /*E*/ /*F*/)/*G*/=>/*H*/0");
+testExpression(      "(/*A*/a/*B*/,/*C*/b/*D*/,/*E*/c/*F*/)/*G*/=>/*H*/{}");
+testExpression("async (/*A*/ /*B*/ /*C*/ /*D*/ /*E*/ /*F*/)/*G*/=>/*H*/0");
+testExpression("async       a/*B*/ /*C*/ /*D*/ /*E*/ /*F*/ /*G*/=>/*H*/{}");
+testExpression("async (/*A*/a/*B*/ /*C*/ /*D*/ /*E*/ /*F*/)/*G*/=>/*H*/0");
+testExpression("async (/*A*/a/*B*/,/*C*/b/*D*/,/*E*/c/*F*/)/*G*/=>/*H*/{}");
+
+function testSimpleMethod(source) {
+  // the source should define a method f
+
+  // object method
+  var f = eval("({" + prefix + source + suffix + "}.f)");
+  checkStringRepresentation(f, source);
+
+  // nonstatic class method
+  var f = eval("new class{" + prefix + source + suffix + "}().f");
+  checkStringRepresentation(f, source);
+
+  // static class method
+  var f = eval("(class{static" + prefix + source + suffix + "}).f");
+  checkStringRepresentation(f, source);
+}
+testSimpleMethod("f(){}");
+testSimpleMethod("*f(){}");
+testSimpleMethod("async f(){}");
+testSimpleMethod("f \t (){}");
+testSimpleMethod("* \tf(){}");
+testSimpleMethod("async \t f (){}");
+
+function testAccessorMethod(source, getOrSet) {
+  // the source should define a getter or setter method
+
+  // object method
+  var f = Object.getOwnPropertyDescriptor(eval("({" + prefix + source + suffix + "})"), "f")[getOrSet];
+  checkStringRepresentation(f, source);
+
+  // nonstatic class method
+  var f = Object.getOwnPropertyDescriptor(eval("(class{" + prefix + source + suffix + "})").prototype, "f")[getOrSet];
+
+  // static class method
+  var f = Object.getOwnPropertyDescriptor(eval("(class{static" + prefix + source + suffix + "})"), "f")[getOrSet];
+  checkStringRepresentation(f, source);
+}
+
+testAccessorMethod("get f( ){}", "get");
+testAccessorMethod("set f(a){}", "set");
+testAccessorMethod("get/*A*/f/*B*/(/*C*/ /*D*/)/*E*/{/*F*/}", "get");
+testAccessorMethod("set/*A*/f/*B*/(/*C*/a/*D*/)/*E*/{/*F*/}", "set");
+
+const GeneratorFunction = function*(){}.constructor;
+const AsyncFunction = async function(){}.constructor;
+function testDynamicFunction(...args) {
+  var P = args.slice(0, args.length - 1).join(",");
+  var bodyText = args.length > 0 ? args[args.length - 1] : "";
+  var source = " anonymous(" + P + "\n) {\n" + bodyText + "\n}";
+  checkStringRepresentation(         Function(...args),       "function"  + source);
+  checkStringRepresentation(GeneratorFunction(...args),       "function*" + source);
+  checkStringRepresentation(    AsyncFunction(...args), "async function"  + source);
+}
+testDynamicFunction();
+testDynamicFunction(";");
+testDynamicFunction("return");
+testDynamicFunction("a", "return a");
+testDynamicFunction("a", "b", "return a");
+testDynamicFunction("a,   b", "return a");
+testDynamicFunction("a,/*A*/b", "return a");
+testDynamicFunction("/*A*/a,b", "return a");
+testDynamicFunction("a,b", "return a/*A*/");
diff --git a/test/test262/test262.status b/test/test262/test262.status
index e034228..ca2d2e4 100644
--- a/test/test262/test262.status
+++ b/test/test262/test262.status
@@ -248,32 +248,32 @@
   'built-ins/Simd/*': [SKIP],
 
   # https://bugs.chromium.org/p/v8/issues/detail?id=4958
-  'built-ins/Function/prototype/toString/AsyncFunction': [FAIL],
-  'built-ins/Function/prototype/toString/async-function-declaration': [FAIL],
-  'built-ins/Function/prototype/toString/async-function-expression': [FAIL],
-  'built-ins/Function/prototype/toString/async-method': [FAIL],
-  'built-ins/Function/prototype/toString/Function': [FAIL],
-  'built-ins/Function/prototype/toString/GeneratorFunction': [FAIL],
-  'built-ins/Function/prototype/toString/function-declaration': [FAIL],
-  'built-ins/Function/prototype/toString/function-declaration-non-simple-parameter-list': [FAIL],
-  'built-ins/Function/prototype/toString/function-expression': [FAIL],
-  'built-ins/Function/prototype/toString/generator-function-declaration': [FAIL],
-  'built-ins/Function/prototype/toString/generator-function-expression': [FAIL],
-  'built-ins/Function/prototype/toString/generator-method': [FAIL],
-  'built-ins/Function/prototype/toString/getter-class': [FAIL],
-  'built-ins/Function/prototype/toString/getter-class-static': [FAIL],
-  'built-ins/Function/prototype/toString/getter-object': [FAIL],
-  'built-ins/Function/prototype/toString/line-terminator-normalisation-CR': [FAIL],
-  'built-ins/Function/prototype/toString/line-terminator-normalisation-CR-LF': [FAIL],
-  'built-ins/Function/prototype/toString/line-terminator-normalisation-LF': [FAIL],
-  'built-ins/Function/prototype/toString/method-class': [FAIL],
-  'built-ins/Function/prototype/toString/method-class-static': [FAIL],
-  'built-ins/Function/prototype/toString/method-computed-property-name': [FAIL],
-  'built-ins/Function/prototype/toString/method-object': [FAIL],
-  'built-ins/Function/prototype/toString/setter-class': [FAIL],
-  'built-ins/Function/prototype/toString/setter-class-static': [FAIL],
-  'built-ins/Function/prototype/toString/setter-object': [FAIL],
-  'built-ins/Function/prototype/toString/unicode': [FAIL],
+  'built-ins/Function/prototype/toString/AsyncFunction': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/async-function-declaration': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/async-function-expression': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/async-method': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/Function': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/GeneratorFunction': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/function-declaration': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/function-declaration-non-simple-parameter-list': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/function-expression': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/generator-function-declaration': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/generator-function-expression': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/generator-method': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/getter-class': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/getter-class-static': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/getter-object': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/line-terminator-normalisation-CR': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/line-terminator-normalisation-CR-LF': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/line-terminator-normalisation-LF': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/method-class': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/method-class-static': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/method-computed-property-name': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/method-object': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/setter-class': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/setter-class-static': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/setter-object': ['--harmony-function-tostring'],
+  'built-ins/Function/prototype/toString/unicode': ['--harmony-function-tostring'],
 
   # https://bugs.chromium.org/p/v8/issues/detail?id=5115
   'language/statements/class/subclass/class-definition-null-proto-missing-return-override': [FAIL],