diff --git a/src/api.cc b/src/api.cc index 6a3ecdbdac..a5929975a9 100644 --- a/src/api.cc +++ b/src/api.cc @@ -2296,8 +2296,10 @@ MaybeLocal ScriptCompiler::CompileFunctionInContext( } i::Handle brackets; if (i::FLAG_harmony_function_tostring) { + // Append linefeed and signal that text beyond the linefeed is not part of + // the formal parameters. brackets = factory->NewStringFromStaticChars("\n) {"); - parameters_end_pos = source_string->length() - 3; + parameters_end_pos = source_string->length() + 1; } else { brackets = factory->NewStringFromStaticChars("){"); } diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h index 412a219e49..7ff55446b1 100644 --- a/test/cctest/cctest.h +++ b/test/cctest/cctest.h @@ -318,6 +318,9 @@ static inline v8::Local v8_num(double x) { return v8::Number::New(v8::Isolate::GetCurrent(), x); } +static inline v8::Local v8_int(int32_t x) { + return v8::Integer::New(v8::Isolate::GetCurrent(), x); +} static inline v8::Local v8_str(const char* x) { return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x, diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc index 3554adf74f..8a633027dd 100644 --- a/test/cctest/test-compiler.cc +++ b/test/cctest/test-compiler.cc @@ -563,6 +563,82 @@ TEST(CompileFunctionInContextScriptOrigin) { CHECK_EQ(42 + strlen("throw "), static_cast(frame->GetColumn())); } +TEST(CompileFunctionInContextHarmonyFunctionToString) { +#define CHECK_NOT_CAUGHT(__local_context__, try_catch, __op__) \ + do { \ + const char* op = (__op__); \ + v8::Local context = (__local_context__); \ + if (try_catch.HasCaught()) { \ + v8::String::Utf8Value error( \ + try_catch.Exception()->ToString(context).ToLocalChecked()); \ + V8_Fatal(__FILE__, __LINE__, \ + "Unexpected exception thrown during %s:\n\t%s\n", op, *error); \ + } \ + } while (0) + + auto previous_flag = v8::internal::FLAG_harmony_function_tostring; + v8::internal::FLAG_harmony_function_tostring = true; + { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + LocalContext env; + + // Regression test for v8:6190 + { + v8::ScriptOrigin origin(v8_str("test"), v8_int(22), v8_int(41)); + v8::ScriptCompiler::Source script_source(v8_str("return event"), origin); + + v8::Local params[] = {v8_str("event")}; + v8::TryCatch try_catch(CcTest::isolate()); + v8::MaybeLocal maybe_fun = + v8::ScriptCompiler::CompileFunctionInContext( + env.local(), &script_source, arraysize(params), params, 0, + nullptr); + + CHECK_NOT_CAUGHT(env.local(), try_catch, + "v8::ScriptCompiler::CompileFunctionInContext"); + + v8::Local fun = maybe_fun.ToLocalChecked(); + CHECK(!fun.IsEmpty()); + CHECK(!try_catch.HasCaught()); + v8::Local result = + fun->ToString(env.local()).ToLocalChecked(); + v8::Local expected = v8_str( + "function anonymous(event\n" + ") {return event\n" + "}"); + CHECK(expected->Equals(env.local(), result).FromJust()); + } + + // With no parameters: + { + v8::ScriptOrigin origin(v8_str("test"), v8_int(17), v8_int(31)); + v8::ScriptCompiler::Source script_source(v8_str("return 0"), origin); + + v8::TryCatch try_catch(CcTest::isolate()); + v8::MaybeLocal maybe_fun = + v8::ScriptCompiler::CompileFunctionInContext( + env.local(), &script_source, 0, nullptr, 0, nullptr); + + CHECK_NOT_CAUGHT(env.local(), try_catch, + "v8::ScriptCompiler::CompileFunctionInContext"); + + v8::Local fun = maybe_fun.ToLocalChecked(); + CHECK(!fun.IsEmpty()); + CHECK(!try_catch.HasCaught()); + v8::Local result = + fun->ToString(env.local()).ToLocalChecked(); + v8::Local expected = v8_str( + "function anonymous(\n" + ") {return 0\n" + "}"); + CHECK(expected->Equals(env.local(), result).FromJust()); + } + } + v8::internal::FLAG_harmony_function_tostring = previous_flag; + +#undef CHECK_NOT_CAUGHT +} #ifdef ENABLE_DISASSEMBLER static Handle GetJSFunction(v8::Local obj,