[parser] provide way to imply that a script is wrapped in a function.

This changes the implementation of
v8::ScriptCompiler::CompileFunctionInContext

See design doc: https://goo.gl/ppkK6Q

R=adamk@chromium.org, marja@chromium.org, mstarzinger@chromium.org

Bug: v8:7172, chromium:70895
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: Iab0b6e879c1a3b33b623bfa2af9c706643c06fa7
Reviewed-on: https://chromium-review.googlesource.com/810946
Commit-Queue: Yang Guo <yangguo@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50148}
This commit is contained in:
Yang Guo 2017-12-18 09:10:06 +01:00 committed by Commit Bot
parent 41e8619069
commit 1586f37f2d
24 changed files with 523 additions and 152 deletions

View File

@ -549,9 +549,8 @@ void Accessors::ScriptEvalFromScriptGetter(
Handle<Script> script(
Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
Handle<Object> result = isolate->factory()->undefined_value();
if (!script->eval_from_shared()->IsUndefined(isolate)) {
Handle<SharedFunctionInfo> eval_from_shared(
SharedFunctionInfo::cast(script->eval_from_shared()));
if (script->has_eval_from_shared()) {
Handle<SharedFunctionInfo> eval_from_shared(script->eval_from_shared());
if (eval_from_shared->script()->IsScript()) {
Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
result = Script::GetWrapper(eval_from_script);
@ -611,9 +610,8 @@ void Accessors::ScriptEvalFromFunctionNameGetter(
Handle<Script> script(
Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
Handle<Object> result = isolate->factory()->undefined_value();
if (!script->eval_from_shared()->IsUndefined(isolate)) {
Handle<SharedFunctionInfo> shared(
SharedFunctionInfo::cast(script->eval_from_shared()));
if (script->has_eval_from_shared()) {
Handle<SharedFunctionInfo> shared(script->eval_from_shared());
// Find the name of the function calling eval.
result = Handle<Object>(shared->name(), isolate);
}

View File

@ -2497,57 +2497,27 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
PREPARE_FOR_EXECUTION(v8_context, ScriptCompiler, CompileFunctionInContext,
Function);
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.ScriptCompiler");
i::Handle<i::String> source_string;
auto factory = isolate->factory();
if (arguments_count) {
source_string = factory->NewStringFromStaticChars("(function(");
for (size_t i = 0; i < arguments_count; ++i) {
IsIdentifierHelper helper;
if (!helper.Check(*Utils::OpenHandle(*arguments[i]))) {
return Local<Function>();
}
has_pending_exception =
!factory->NewConsString(source_string,
Utils::OpenHandle(*arguments[i]))
.ToHandle(&source_string);
RETURN_ON_FAILED_EXECUTION(Function);
if (i + 1 == arguments_count) continue;
has_pending_exception =
!factory->NewConsString(source_string,
factory->LookupSingleCharacterStringFromCode(
',')).ToHandle(&source_string);
RETURN_ON_FAILED_EXECUTION(Function);
}
i::Handle<i::String> brackets;
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(){");
}
int scope_position = source_string->length();
has_pending_exception =
!factory->NewConsString(source_string,
Utils::OpenHandle(*source->source_string))
.ToHandle(&source_string);
RETURN_ON_FAILED_EXECUTION(Function);
// Include \n in case the source contains a line end comment.
auto brackets = factory->NewStringFromStaticChars("\n})");
has_pending_exception =
!factory->NewConsString(source_string, brackets).ToHandle(&source_string);
RETURN_ON_FAILED_EXECUTION(Function);
i::Handle<i::Context> context = Utils::OpenHandle(*v8_context);
i::Handle<i::SharedFunctionInfo> outer_info(context->closure()->shared(),
isolate);
i::Handle<i::JSFunction> fun;
i::Handle<i::FixedArray> arguments_list =
isolate->factory()->NewFixedArray(static_cast<int>(arguments_count));
for (int i = 0; i < static_cast<int>(arguments_count); i++) {
IsIdentifierHelper helper;
i::Handle<i::String> argument = Utils::OpenHandle(*arguments[i]);
if (!helper.Check(*argument)) return Local<Function>();
arguments_list->set(i, *argument);
}
for (size_t i = 0; i < context_extension_count; ++i) {
i::Handle<i::JSReceiver> extension =
Utils::OpenHandle(*context_extensions[i]);
if (!extension->IsJSObject()) return Local<Function>();
i::Handle<i::JSFunction> closure(context->closure(), isolate);
context = factory->NewWithContext(
context = isolate->factory()->NewWithContext(
closure, context,
i::ScopeInfo::CreateForWithScope(
isolate, context->IsNativeContext()
@ -2557,8 +2527,6 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
}
i::Handle<i::Object> name_obj;
int eval_scope_position = 0;
int eval_position = i::kNoSourcePosition;
int line_offset = 0;
int column_offset = 0;
if (!source->resource_name.IsEmpty()) {
@ -2570,27 +2538,15 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
if (!source->resource_column_offset.IsEmpty()) {
column_offset = static_cast<int>(source->resource_column_offset->Value());
}
i::Handle<i::JSFunction> fun;
has_pending_exception =
!i::Compiler::GetFunctionFromEval(
source_string, outer_info, context, i::LanguageMode::kSloppy,
i::ONLY_SINGLE_FUNCTION_LITERAL, i::kNoSourcePosition,
eval_scope_position, eval_position, line_offset,
column_offset - scope_position, name_obj, source->resource_options)
.ToHandle(&fun);
if (has_pending_exception) {
isolate->ReportPendingMessages();
}
RETURN_ON_FAILED_EXECUTION(Function);
i::Handle<i::Object> result;
i::Handle<i::JSFunction> result;
has_pending_exception =
!i::Execution::Call(isolate, fun,
Utils::OpenHandle(*v8_context->Global()), 0,
nullptr).ToHandle(&result);
!i::Compiler::GetWrappedFunction(
Utils::OpenHandle(*source->source_string), arguments_list, context,
line_offset, column_offset, name_obj, source->resource_options)
.ToHandle(&result);
RETURN_ON_FAILED_EXECUTION(Function);
RETURN_ESCAPED(
Utils::CallableToLocal(i::Handle<i::JSFunction>::cast(result)));
RETURN_ESCAPED(Utils::CallableToLocal(result));
}

View File

@ -2168,7 +2168,8 @@ class FunctionLiteral final : public Expression {
kAnonymousExpression,
kNamedExpression,
kDeclaration,
kAccessorOrMethod
kAccessorOrMethod,
kWrapped,
};
enum IdType { kIdTypeInvalid = -1, kIdTypeTopLevel = 0 };
@ -2199,6 +2200,7 @@ class FunctionLiteral final : public Expression {
bool is_anonymous_expression() const {
return function_type() == kAnonymousExpression;
}
bool is_wrapped() const { return function_type() == kWrapped; }
LanguageMode language_mode() const;
static bool NeedsHomeObject(Expression* expr);
@ -2344,7 +2346,7 @@ class FunctionLiteral final : public Expression {
}
class FunctionTypeBits
: public BitField<FunctionType, Expression::kNextBitFieldIndex, 2> {};
: public BitField<FunctionType, Expression::kNextBitFieldIndex, 3> {};
class Pretenure : public BitField<bool, FunctionTypeBits::kNext, 1> {};
class HasDuplicateParameters : public BitField<bool, Pretenure::kNext, 1> {};
class DontOptimizeReasonField

View File

@ -1175,6 +1175,57 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
return result;
}
MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
Handle<String> source, Handle<FixedArray> arguments,
Handle<Context> context, int line_offset, int column_offset,
Handle<Object> script_name, ScriptOriginOptions options) {
Isolate* isolate = source->GetIsolate();
int source_length = source->length();
isolate->counters()->total_compile_size()->Increment(source_length);
Handle<Script> script = isolate->factory()->NewScript(source);
if (isolate->NeedsSourcePositionsForProfiling()) {
Script::InitLineEnds(script);
}
if (!script_name.is_null()) {
script->set_name(*script_name);
script->set_line_offset(line_offset);
script->set_column_offset(column_offset);
}
script->set_wrapped_arguments(*arguments);
script->set_origin_options(options);
ParseInfo parse_info(script);
parse_info.set_eval(); // Use an eval scope as declaration scope.
parse_info.set_wrapped_as_function();
if (!context->IsNativeContext()) {
parse_info.set_outer_scope_info(handle(context->scope_info()));
}
Handle<SharedFunctionInfo> top_level;
ASSIGN_RETURN_ON_EXCEPTION(isolate, top_level,
CompileToplevel(&parse_info, isolate), JSFunction);
Handle<JSFunction> top_level_fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(top_level, context,
NOT_TENURED);
// TODO(yangguo): consider not having to call the top-level function, and
// instead instantiate the wrapper function directly.
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result,
Execution::Call(isolate, top_level_fun, isolate->global_proxy(), 0,
nullptr),
JSFunction);
// OnAfterCompile has to be called after we create the JSFunction, which we
// may require to recompile the eval for debugging, if we find a function
// that contains break points in the eval script.
isolate->debug()->OnAfterCompile(script);
return Handle<JSFunction>::cast(result);
}
namespace {
bool ShouldProduceCodeCache(ScriptCompiler::CompileOptions options) {

View File

@ -101,6 +101,14 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
int column_offset = 0, Handle<Object> script_name = Handle<Object>(),
ScriptOriginOptions options = ScriptOriginOptions());
// Create a function that results from wrapping |source| in a function,
// with |arguments| being a list of parameters for that function.
MUST_USE_RESULT static MaybeHandle<JSFunction> GetWrappedFunction(
Handle<String> source, Handle<FixedArray> arguments,
Handle<Context> context, int line_offset = 0, int column_offset = 0,
Handle<Object> script_name = Handle<Object>(),
ScriptOriginOptions options = ScriptOriginOptions());
// Returns true if the embedder permits compiling the given source string in
// the given context.
static bool CodeGenerationFromStringsAllowed(Isolate* isolate,

View File

@ -1009,7 +1009,8 @@ static Handle<Script> CreateScriptCopy(Handle<Script> original) {
copy->set_column_offset(original->column_offset());
copy->set_type(original->type());
copy->set_context_data(original->context_data());
copy->set_eval_from_shared(original->eval_from_shared());
copy->set_eval_from_shared_or_wrapped_arguments(
original->eval_from_shared_or_wrapped_arguments());
copy->set_eval_from_position(original->eval_from_position());
Handle<FixedArray> infos(isolate->factory()->NewFixedArray(

View File

@ -1176,7 +1176,7 @@ Handle<Script> Factory::NewScript(Handle<String> source) {
script->set_type(Script::TYPE_NORMAL);
script->set_wrapper(heap->undefined_value());
script->set_line_ends(heap->undefined_value());
script->set_eval_from_shared(heap->undefined_value());
script->set_eval_from_shared_or_wrapped_arguments(heap->undefined_value());
script->set_eval_from_position(0);
script->set_shared_function_infos(*empty_fixed_array(), SKIP_WRITE_BARRIER);
script->set_flags(0);

View File

@ -189,11 +189,10 @@ std::unique_ptr<char[]> MessageHandler::GetLocalizedMessage(
namespace {
Object* EvalFromFunctionName(Isolate* isolate, Handle<Script> script) {
if (script->eval_from_shared()->IsUndefined(isolate))
if (!script->has_eval_from_shared())
return isolate->heap()->undefined_value();
Handle<SharedFunctionInfo> shared(
SharedFunctionInfo::cast(script->eval_from_shared()));
Handle<SharedFunctionInfo> shared(script->eval_from_shared());
// Find the name of the function calling eval.
if (shared->name()->BooleanValue()) {
return shared->name();
@ -203,11 +202,10 @@ Object* EvalFromFunctionName(Isolate* isolate, Handle<Script> script) {
}
Object* EvalFromScript(Isolate* isolate, Handle<Script> script) {
if (script->eval_from_shared()->IsUndefined(isolate))
if (!script->has_eval_from_shared())
return isolate->heap()->undefined_value();
Handle<SharedFunctionInfo> eval_from_shared(
SharedFunctionInfo::cast(script->eval_from_shared()));
Handle<SharedFunctionInfo> eval_from_shared(script->eval_from_shared());
return eval_from_shared->script()->IsScript()
? eval_from_shared->script()
: isolate->heap()->undefined_value();

View File

@ -1599,7 +1599,12 @@ void Script::ScriptPrint(std::ostream& os) { // NOLINT
os << "\n - wrapper: " << Brief(wrapper());
os << "\n - compilation type: " << compilation_type();
os << "\n - line ends: " << Brief(line_ends());
os << "\n - eval from shared: " << Brief(eval_from_shared());
if (has_eval_from_shared()) {
os << "\n - eval from shared: " << Brief(eval_from_shared());
}
if (is_wrapped()) {
os << "\n - wrapped arguments: " << Brief(wrapped_arguments());
}
os << "\n - eval from position: " << eval_from_position();
os << "\n - shared function infos: " << Brief(shared_function_infos());
os << "\n";

View File

@ -13194,7 +13194,21 @@ Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
builder.AppendString(handle(shared_info->name(), isolate));
}
}
if (shared_info->is_wrapped()) {
builder.AppendCharacter('(');
Handle<FixedArray> args(
Script::cast(shared_info->script())->wrapped_arguments());
int argc = args->length();
for (int i = 0; i < argc; i++) {
if (i > 0) builder.AppendCharacter(',');
builder.AppendString(Handle<String>(String::cast(args->get(i))));
}
builder.AppendCString(") {\n");
}
builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode()));
if (shared_info->is_wrapped()) {
builder.AppendCString("\n}");
}
return builder.Finish().ToHandleChecked();
}
@ -13225,10 +13239,10 @@ int Script::GetEvalPosition() {
// Due to laziness, the position may not have been translated from code
// offset yet, which would be encoded as negative integer. In that case,
// translate and set the position.
if (eval_from_shared()->IsUndefined(GetIsolate())) {
if (!has_eval_from_shared()) {
position = 0;
} else {
SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared());
SharedFunctionInfo* shared = eval_from_shared();
position = shared->abstract_code()->SourcePosition(-position);
}
DCHECK_GE(position, 0);
@ -13687,8 +13701,22 @@ Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony() {
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());
Handle<String> source = isolate->factory()->NewSubString(
script_source, start_pos, end_position());
if (!is_wrapped()) return source;
IncrementalStringBuilder builder(isolate);
builder.AppendCString("function (");
Handle<FixedArray> args(Script::cast(script())->wrapped_arguments());
int argc = args->length();
for (int i = 0; i < argc; i++) {
if (i > 0) builder.AppendCString(", ");
builder.AppendString(Handle<String>(String::cast(args->get(i))));
}
builder.AppendCString(") {\n");
builder.AppendString(source);
builder.AppendCString("\n}");
return builder.Finish().ToHandleChecked();
}
bool SharedFunctionInfo::IsInlineable() {
@ -13818,6 +13846,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
shared_info->set_inferred_name(*lit->inferred_name());
shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
shared_info->set_language_mode(lit->language_mode());
shared_info->set_is_wrapped(lit->is_wrapped());
// shared_info->set_kind(lit->kind());
// FunctionKind must have already been set.
DCHECK(lit->kind() == shared_info->kind());

View File

@ -26,7 +26,8 @@ ACCESSORS(Script, context_data, Object, kContextOffset)
ACCESSORS(Script, wrapper, HeapObject, kWrapperOffset)
SMI_ACCESSORS(Script, type, kTypeOffset)
ACCESSORS(Script, line_ends, Object, kLineEndsOffset)
ACCESSORS_CHECKED(Script, eval_from_shared, Object, kEvalFromSharedOffset,
ACCESSORS_CHECKED(Script, eval_from_shared_or_wrapped_arguments, Object,
kEvalFromSharedOrWrappedArgumentsOffset,
this->type() != TYPE_WASM)
SMI_ACCESSORS_CHECKED(Script, eval_from_position, kEvalFromPositionOffset,
this->type() != TYPE_WASM)
@ -35,9 +36,39 @@ SMI_ACCESSORS(Script, flags, kFlagsOffset)
ACCESSORS(Script, source_url, Object, kSourceUrlOffset)
ACCESSORS(Script, source_mapping_url, Object, kSourceMappingUrlOffset)
ACCESSORS(Script, host_defined_options, FixedArray, kHostDefinedOptionsOffset)
ACCESSORS_CHECKED(Script, wasm_compiled_module, Object, kEvalFromSharedOffset,
ACCESSORS_CHECKED(Script, wasm_compiled_module, Object,
kEvalFromSharedOrWrappedArgumentsOffset,
this->type() == TYPE_WASM)
bool Script::is_wrapped() const {
return eval_from_shared_or_wrapped_arguments()->IsFixedArray();
}
bool Script::has_eval_from_shared() const {
return eval_from_shared_or_wrapped_arguments()->IsSharedFunctionInfo();
}
void Script::set_eval_from_shared(SharedFunctionInfo* shared,
WriteBarrierMode mode) {
DCHECK(!is_wrapped());
set_eval_from_shared_or_wrapped_arguments(shared, mode);
}
SharedFunctionInfo* Script::eval_from_shared() const {
DCHECK(has_eval_from_shared());
return SharedFunctionInfo::cast(eval_from_shared_or_wrapped_arguments());
}
void Script::set_wrapped_arguments(FixedArray* value, WriteBarrierMode mode) {
DCHECK(!has_eval_from_shared());
set_eval_from_shared_or_wrapped_arguments(value, mode);
}
FixedArray* Script::wrapped_arguments() const {
DCHECK(is_wrapped());
return FixedArray::cast(eval_from_shared_or_wrapped_arguments());
}
Script::CompilationType Script::compilation_type() {
return BooleanBit::get(flags(), kCompilationTypeBit) ? COMPILATION_TYPE_EVAL
: COMPILATION_TYPE_HOST;

View File

@ -63,9 +63,21 @@ class Script : public Struct {
// [line_ends]: FixedArray of line ends positions.
DECL_ACCESSORS(line_ends, Object)
DECL_ACCESSORS(eval_from_shared_or_wrapped_arguments, Object)
// [eval_from_shared]: for eval scripts the shared function info for the
// function from which eval was called.
DECL_ACCESSORS(eval_from_shared, Object)
DECL_ACCESSORS(eval_from_shared, SharedFunctionInfo)
// [wrapped_arguments]: for the list of arguments in a wrapped script.
DECL_ACCESSORS(wrapped_arguments, FixedArray)
// Whether the script is implicitly wrapped in a function.
inline bool is_wrapped() const;
// Whether the eval_from_shared field is set with a shared function info
// for the eval site.
inline bool has_eval_from_shared() const;
// [eval_from_position]: the source position in the code for the function
// from which eval was called, as positive integer. Or the code offset in the
@ -190,9 +202,10 @@ class Script : public Struct {
static const int kTypeOffset = kWrapperOffset + kPointerSize;
static const int kLineEndsOffset = kTypeOffset + kPointerSize;
static const int kIdOffset = kLineEndsOffset + kPointerSize;
static const int kEvalFromSharedOffset = kIdOffset + kPointerSize;
static const int kEvalFromSharedOrWrappedArgumentsOffset =
kIdOffset + kPointerSize;
static const int kEvalFromPositionOffset =
kEvalFromSharedOffset + kPointerSize;
kEvalFromSharedOrWrappedArgumentsOffset + kPointerSize;
static const int kSharedFunctionInfosOffset =
kEvalFromPositionOffset + kPointerSize;
static const int kFlagsOffset = kSharedFunctionInfosOffset + kPointerSize;

View File

@ -80,6 +80,8 @@ AbstractCode* SharedFunctionInfo::abstract_code() {
}
}
BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, is_wrapped,
SharedFunctionInfo::IsWrappedBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, allows_lazy_compilation,
SharedFunctionInfo::AllowLazyCompilationBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints,

View File

@ -288,6 +288,9 @@ class SharedFunctionInfo : public HeapObject {
inline LanguageMode language_mode();
inline void set_language_mode(LanguageMode language_mode);
// Indicates whether the source is implicitly wrapped in a function.
DECL_BOOLEAN_ACCESSORS(is_wrapped)
// True if the function has any duplicated parameter names.
DECL_BOOLEAN_ACCESSORS(has_duplicate_parameters)
@ -465,6 +468,7 @@ class SharedFunctionInfo : public HeapObject {
#define COMPILER_HINTS_BIT_FIELDS(V, _) \
V(IsNativeBit, bool, 1, _) \
V(IsStrictBit, bool, 1, _) \
V(IsWrappedBit, bool, 1, _) \
V(FunctionKindBits, FunctionKind, 10, _) \
V(HasDuplicateParametersBit, bool, 1, _) \
V(AllowLazyCompilationBit, bool, 1, _) \

View File

@ -45,7 +45,13 @@ ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared)
Isolate* isolate = shared->GetIsolate();
InitFromIsolate(isolate);
// Do not support re-parsing top-level function of a wrapped script.
// TODO(yangguo): consider whether we need a top-level function in a
// wrapped script at all.
DCHECK_IMPLIES(is_toplevel(), !Script::cast(shared->script())->is_wrapped());
set_toplevel(shared->is_toplevel());
set_wrapped_as_function(shared->is_wrapped());
set_allow_lazy_parsing(FLAG_lazy_inner_functions);
set_is_named_expression(shared->is_named_expression());
set_compiler_hints(shared->compiler_hints());
@ -90,6 +96,7 @@ ParseInfo::ParseInfo(Handle<Script> script)
set_allow_lazy_parsing();
set_toplevel();
set_script(script);
set_wrapped_as_function(script->is_wrapped());
set_native(script->type() == Script::TYPE_NATIVE);
set_eval(script->compilation_type() == Script::COMPILATION_TYPE_EVAL);

View File

@ -86,6 +86,8 @@ class V8_EXPORT_PRIVATE ParseInfo {
set_block_coverage_enabled)
FLAG_ACCESSOR(kOnBackgroundThread, on_background_thread,
set_on_background_thread)
FLAG_ACCESSOR(kWrappedAsFunction, is_wrapped_as_function,
set_wrapped_as_function)
#undef FLAG_ACCESSOR
void set_parse_restriction(ParseRestriction restriction) {
@ -263,6 +265,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
kIsAsmWasmBroken = 1 << 12,
kRequiresInstanceFieldsInitializer = 1 << 13,
kOnBackgroundThread = 1 << 14,
kWrappedAsFunction = 1 << 15, // Implicitly wrapped as function.
};
//------------- Inputs to parsing and scope analysis -----------------------

View File

@ -2334,7 +2334,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
FLAG_harmony_function_tostring ? name_token_position
: kNoSourcePosition,
FunctionLiteral::kAccessorOrMethod, language_mode(),
FunctionLiteral::kAccessorOrMethod, language_mode(), nullptr,
CHECK_OK_CUSTOM(NullLiteralProperty));
*property_kind = ClassLiteralProperty::METHOD;
@ -2366,7 +2366,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
FLAG_harmony_function_tostring ? name_token_position
: kNoSourcePosition,
FunctionLiteral::kAccessorOrMethod, language_mode(),
FunctionLiteral::kAccessorOrMethod, language_mode(), nullptr,
CHECK_OK_CUSTOM(NullLiteralProperty));
*property_kind =
@ -2567,7 +2567,7 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
ExpressionT value = impl()->ParseFunctionLiteral(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
FLAG_harmony_function_tostring ? next_beg_pos : kNoSourcePosition,
FunctionLiteral::kAccessorOrMethod, language_mode(),
FunctionLiteral::kAccessorOrMethod, language_mode(), nullptr,
CHECK_OK_CUSTOM(NullLiteralProperty));
ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty(
@ -2599,7 +2599,7 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
FunctionLiteralT value = impl()->ParseFunctionLiteral(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
FLAG_harmony_function_tostring ? next_beg_pos : kNoSourcePosition,
FunctionLiteral::kAccessorOrMethod, language_mode(),
FunctionLiteral::kAccessorOrMethod, language_mode(), nullptr,
CHECK_OK_CUSTOM(NullLiteralProperty));
ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty(
@ -3505,7 +3505,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
is_strict_reserved_name ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown,
function_kind, function_token_position, function_type, language_mode(),
CHECK_OK);
nullptr, CHECK_OK);
} else if (peek() == Token::SUPER) {
const bool is_new = false;
result = ParseSuperExpression(is_new, CHECK_OK);
@ -3993,7 +3993,7 @@ ParserBase<Impl>::ParseHoistableDeclaration(
FunctionLiteralT function = impl()->ParseFunctionLiteral(
name, scanner()->location(), name_validity, kind, pos,
FunctionLiteral::kDeclaration, language_mode(),
FunctionLiteral::kDeclaration, language_mode(), nullptr,
CHECK_OK_CUSTOM(NullStatement));
// In ES6, a function behaves as a lexical binding, except in
@ -4118,6 +4118,11 @@ void ParserBase<Impl>::ParseFunctionBody(
body = inner_block->statements();
}
// If we are parsing the source as if it is wrapped in a function, the source
// ends without a closing brace.
Token::Value closing_token =
function_type == FunctionLiteral::kWrapped ? Token::EOS : Token::RBRACE;
{
BlockState block_state(&scope_, inner_scope);
@ -4130,7 +4135,7 @@ void ParserBase<Impl>::ParseFunctionBody(
} else if (IsAsyncFunction(kind)) {
ParseAsyncFunctionBody(inner_scope, body, CHECK_OK_VOID);
} else {
ParseStatementList(body, Token::RBRACE, CHECK_OK_VOID);
ParseStatementList(body, closing_token, CHECK_OK_VOID);
}
if (IsDerivedConstructor(kind)) {
@ -4140,7 +4145,7 @@ void ParserBase<Impl>::ParseFunctionBody(
}
}
Expect(Token::RBRACE, CHECK_OK_VOID);
Expect(closing_token, CHECK_OK_VOID);
scope()->set_end_position(scanner()->location().end_pos);
if (!parameters.is_simple) {
@ -4559,7 +4564,7 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) {
name, scanner()->location(),
is_strict_reserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown,
kind, pos, type, language_mode(), CHECK_OK);
kind, pos, type, language_mode(), nullptr, CHECK_OK);
}
template <typename Impl>

View File

@ -668,11 +668,9 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
}
DeclarationScope* scope = outer->AsDeclarationScope();
scope->set_start_position(0);
FunctionState function_state(&function_state_, &scope_, scope);
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
bool ok = true;
int beg_pos = scanner()->location().beg_pos;
@ -699,6 +697,8 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
ParseModuleItemList(body, &ok);
ok = ok && module()->Validate(this->scope()->AsModuleScope(),
pending_error_handler(), zone());
} else if (info->is_wrapped_as_function()) {
ParseWrapped(info, body, scope, zone(), &ok);
} else {
// Don't count the mode in the use counters--give the program a chance
// to enable script-wide strict mode below.
@ -751,6 +751,46 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
return result;
}
ZoneList<const AstRawString*>* Parser::PrepareWrappedArguments(ParseInfo* info,
Zone* zone) {
DCHECK(parsing_on_main_thread_);
Handle<FixedArray> arguments(info->script()->wrapped_arguments());
int arguments_length = arguments->length();
ZoneList<const AstRawString*>* arguments_for_wrapped_function =
new (zone) ZoneList<const AstRawString*>(arguments_length, zone);
for (int i = 0; i < arguments_length; i++) {
const AstRawString* argument_string = ast_value_factory()->GetString(
Handle<String>(String::cast(arguments->get(i))));
arguments_for_wrapped_function->Add(argument_string, zone);
}
return arguments_for_wrapped_function;
}
void Parser::ParseWrapped(ParseInfo* info, ZoneList<Statement*>* body,
DeclarationScope* outer_scope, Zone* zone, bool* ok) {
DCHECK(info->is_wrapped_as_function());
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
// Set function and block state for the outer eval scope.
DCHECK(outer_scope->is_eval_scope());
FunctionState function_state(&function_state_, &scope_, outer_scope);
const AstRawString* function_name = nullptr;
Scanner::Location location(0, 0);
ZoneList<const AstRawString*>* arguments_for_wrapped_function =
PrepareWrappedArguments(info, zone);
FunctionLiteral* function_literal = ParseFunctionLiteral(
function_name, location, kSkipFunctionNameCheck, kNormalFunction,
kNoSourcePosition, FunctionLiteral::kWrapped, LanguageMode::kSloppy,
arguments_for_wrapped_function, CHECK_OK_VOID);
Statement* return_statement = factory()->NewReturnStatement(
function_literal, kNoSourcePosition, kNoSourcePosition);
body->Add(return_statement, zone);
}
FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
Handle<SharedFunctionInfo> shared_info) {
// It's OK to use the Isolate & counters here, since this function is only
@ -794,7 +834,9 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
}
static FunctionLiteral::FunctionType ComputeFunctionType(ParseInfo* info) {
if (info->is_declaration()) {
if (info->is_wrapped_as_function()) {
return FunctionLiteral::kWrapped;
} else if (info->is_declaration()) {
return FunctionLiteral::kDeclaration;
} else if (info->is_named_expression()) {
return FunctionLiteral::kNamedExpression;
@ -927,9 +969,13 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info,
result = DefaultConstructor(raw_name, IsDerivedConstructor(kind),
info->start_position(), info->end_position());
} else {
ZoneList<const AstRawString*>* arguments_for_wrapped_function =
info->is_wrapped_as_function() ? PrepareWrappedArguments(info, zone())
: nullptr;
result = ParseFunctionLiteral(
raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind,
kNoSourcePosition, function_type, info->language_mode(), &ok);
kNoSourcePosition, function_type, info->language_mode(),
arguments_for_wrapped_function, &ok);
}
if (ok) {
@ -2509,7 +2555,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
const AstRawString* function_name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_pos, FunctionLiteral::FunctionType function_type,
LanguageMode language_mode, bool* ok) {
LanguageMode language_mode,
ZoneList<const AstRawString*>* arguments_for_wrapped_function, bool* ok) {
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
//
@ -2519,8 +2566,12 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// Setter ::
// '(' PropertySetParameterList ')' '{' FunctionBody '}'
bool is_wrapped = function_type == FunctionLiteral::kWrapped;
DCHECK_EQ(is_wrapped, arguments_for_wrapped_function != nullptr);
int pos = function_token_pos == kNoSourcePosition ? peek_position()
: function_token_pos;
DCHECK_NE(kNoSourcePosition, pos);
// Anonymous functions were passed either the empty symbol or a null
// handle as the function name. Remember if we were passed a non-empty
@ -2534,7 +2585,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
}
FunctionLiteral::EagerCompileHint eager_compile_hint =
function_state_->next_function_is_likely_called()
function_state_->next_function_is_likely_called() || is_wrapped
? FunctionLiteral::kShouldEagerCompile
: default_eager_compile_hint();
@ -2649,7 +2700,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
if (should_preparse) scope->set_needs_migration();
#endif
Expect(Token::LPAREN, CHECK_OK);
if (!is_wrapped) Expect(Token::LPAREN, CHECK_OK);
scope->set_start_position(scanner()->location().beg_pos);
// Eager or lazy parse? If is_lazy_top_level_function, we'll parse
@ -2660,6 +2711,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
if (should_preparse) {
DCHECK(parse_lazily());
DCHECK(is_lazy_top_level_function || is_lazy_inner_function);
DCHECK(!is_wrapped);
Scanner::BookmarkScope bookmark(scanner());
bookmark.Set();
LazyParsingResult result = SkipFunction(
@ -2686,7 +2738,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
body = ParseFunction(function_name, pos, kind, function_type, scope,
&num_parameters, &function_length,
&has_duplicate_parameters, &expected_property_count,
CHECK_OK);
arguments_for_wrapped_function, CHECK_OK);
}
DCHECK_EQ(should_preparse, temp_zoned_);
@ -3119,11 +3171,14 @@ ZoneList<Statement*>* Parser::ParseFunction(
const AstRawString* function_name, int pos, FunctionKind kind,
FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, int* num_parameters, int* function_length,
bool* has_duplicate_parameters, int* expected_property_count, bool* ok) {
bool* has_duplicate_parameters, int* expected_property_count,
ZoneList<const AstRawString*>* arguments_for_wrapped_function, bool* ok) {
ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY);
FunctionState function_state(&function_state_, &scope_, function_scope);
bool is_wrapped = function_type == FunctionLiteral::kWrapped;
DuplicateFinder duplicate_finder;
ExpressionClassifier formals_classifier(this, &duplicate_finder);
@ -3137,34 +3192,53 @@ ZoneList<Statement*>* Parser::ParseFunction(
}
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;
if (is_wrapped) {
// For a function implicitly wrapped in function header and footer, the
// function arguments are provided separately to the source, and are
// declared directly here.
int arguments_length = arguments_for_wrapped_function->length();
for (int i = 0; i < arguments_length; i++) {
const bool is_rest = false;
Expression* argument = ExpressionFromIdentifier(
arguments_for_wrapped_function->at(i), kNoSourcePosition);
AddFormalParameter(&formals, argument, NullExpression(),
kNoSourcePosition, is_rest);
}
DCHECK_EQ(arguments_length, formals.num_parameters());
DeclareFormalParameters(formals.scope, formals.params, formals.is_simple);
} else {
// For a regular function, the function arguments are parsed from source.
DCHECK_NULL(arguments_for_wrapped_function);
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;
CheckArityRestrictions(formals.arity, kind, formals.has_rest,
function_scope->start_position(),
formals_end_position, CHECK_OK);
Expect(Token::LBRACE, CHECK_OK);
}
Expect(Token::RPAREN, CHECK_OK);
int formals_end_position = scanner()->location().end_pos;
*num_parameters = formals.num_parameters();
*function_length = formals.function_length;
CheckArityRestrictions(formals.arity, kind, formals.has_rest,
function_scope->start_position(), formals_end_position,
CHECK_OK);
Expect(Token::LBRACE, CHECK_OK);
ZoneList<Statement*>* body = new (zone()) ZoneList<Statement*>(8, zone());
ParseFunctionBody(body, function_name, pos, formals, kind, function_type, ok);

View File

@ -267,6 +267,15 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// Called by ParseProgram after setting up the scanner.
FunctionLiteral* DoParseProgram(ParseInfo* info);
// Parse with the script as if the source is implicitly wrapped in a function.
// We manually construct the AST and scopes for a top-level function and the
// function wrapper.
void ParseWrapped(ParseInfo* info, ZoneList<Statement*>* body,
DeclarationScope* scope, Zone* zone, bool* ok);
ZoneList<const AstRawString*>* PrepareWrappedArguments(ParseInfo* info,
Zone* zone);
void SetCachedData(ParseInfo* info);
void StitchAst(ParseInfo* top_level_parse_info, Isolate* isolate);
@ -425,7 +434,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
const AstRawString* name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_position, FunctionLiteral::FunctionType type,
LanguageMode language_mode, bool* ok);
LanguageMode language_mode,
ZoneList<const AstRawString*>* arguments_for_wrapped_function, bool* ok);
// Check if the scope has conflicting var/let declarations from different
// scopes. This covers for example
@ -488,7 +498,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, int* num_parameters,
int* function_length, bool* has_duplicate_parameters,
int* expected_property_count, bool* ok);
int* expected_property_count,
ZoneList<const AstRawString*>* arguments_for_wrapped_function, bool* ok);
void ThrowPendingError(Isolate* isolate, Handle<Script> script);

View File

@ -266,7 +266,11 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
Identifier function_name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_pos, FunctionLiteral::FunctionType function_type,
LanguageMode language_mode, bool* ok) {
LanguageMode language_mode,
ZoneList<const AstRawString*>* arguments_for_wrapped_function, bool* ok) {
// Wrapped functions are not parsed in the preparser.
DCHECK_NULL(arguments_for_wrapped_function);
DCHECK_NE(FunctionLiteral::kWrapped, function_type);
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
const RuntimeCallCounterId counters[2][2] = {

View File

@ -956,12 +956,12 @@ class PreParser : public ParserBase<PreParser> {
bool is_inner_function, bool may_abort, bool* ok) {
UNREACHABLE();
}
Expression ParseFunctionLiteral(Identifier name,
Scanner::Location function_name_location,
FunctionNameValidity function_name_validity,
FunctionKind kind, int function_token_pos,
FunctionLiteral::FunctionType function_type,
LanguageMode language_mode, bool* ok);
Expression ParseFunctionLiteral(
Identifier name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_pos, FunctionLiteral::FunctionType function_type,
LanguageMode language_mode,
ZoneList<const AstRawString*>* arguments_for_wrapped_function, bool* ok);
LazyParsingResult ParseStatementListAndLogFunction(
PreParserFormalParameters* formals, bool maybe_abort, bool* ok);

View File

@ -19,11 +19,9 @@ RUNTIME_FUNCTION(Runtime_DynamicImportCall) {
Handle<Script> script(Script::cast(function->shared()->script()));
while (script->eval_from_shared()->IsSharedFunctionInfo()) {
script = handle(
Script::cast(
SharedFunctionInfo::cast(script->eval_from_shared())->script()),
isolate);
while (script->has_eval_from_shared()) {
script =
handle(Script::cast(script->eval_from_shared()->script()), isolate);
}
RETURN_RESULT_OR_FAILURE(

View File

@ -405,6 +405,7 @@ TEST(OptimizedCodeSharing1) {
}
TEST(CompileFunctionInContext) {
if (i::FLAG_always_opt) return;
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
LocalContext env;
@ -420,6 +421,8 @@ TEST(CompileFunctionInContext) {
0, nullptr, 1, &math)
.ToLocalChecked();
CHECK(!fun.IsEmpty());
i::DisallowCompilation no_compile(CcTest::i_isolate());
fun->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
CHECK(env->Global()->Has(env.local(), v8_str("a")).FromJust());
v8::Local<v8::Value> a =
@ -483,7 +486,11 @@ TEST(CompileFunctionInContextArgs) {
v8::ScriptCompiler::CompileFunctionInContext(env.local(), &script_source,
1, &arg, 1, ext)
.ToLocalChecked();
CHECK(!fun.IsEmpty());
CHECK_EQ(1, fun->Get(env.local(), v8_str("length"))
.ToLocalChecked()
->ToInt32(env.local())
.ToLocalChecked()
->Value());
v8::Local<v8::Value> b_value = v8::Number::New(CcTest::isolate(), 42.0);
fun->Call(env.local(), env->Global(), 1, &b_value).ToLocalChecked();
CHECK(env->Global()->Has(env.local(), v8_str("result")).FromJust());
@ -531,6 +538,97 @@ TEST(CompileFunctionInContextNonIdentifierArgs) {
.IsEmpty());
}
TEST(CompileFunctionInContextRenderCallSite) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
LocalContext env;
static const char* source1 =
"try {"
" var a = [];"
" a[0]();"
"} catch (e) {"
" return e.toString();"
"}";
static const char* expect1 = "TypeError: a[0] is not a function";
static const char* source2 =
"try {"
" (function() {"
" var a = [];"
" a[0]();"
" })()"
"} catch (e) {"
" return e.toString();"
"}";
static const char* expect2 = "TypeError: a[0] is not a function";
{
v8::ScriptCompiler::Source script_source(v8_str(source1));
v8::Local<v8::Function> fun =
v8::ScriptCompiler::CompileFunctionInContext(
env.local(), &script_source, 0, nullptr, 0, nullptr)
.ToLocalChecked();
CHECK(!fun.IsEmpty());
v8::Local<v8::Value> result =
fun->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
CHECK(result->IsString());
CHECK(v8::Local<v8::String>::Cast(result)
->Equals(env.local(), v8_str(expect1))
.FromJust());
}
{
v8::ScriptCompiler::Source script_source(v8_str(source2));
v8::Local<v8::Function> fun =
v8::ScriptCompiler::CompileFunctionInContext(
env.local(), &script_source, 0, nullptr, 0, nullptr)
.ToLocalChecked();
v8::Local<v8::Value> result =
fun->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
CHECK(result->IsString());
CHECK(v8::Local<v8::String>::Cast(result)
->Equals(env.local(), v8_str(expect2))
.FromJust());
}
}
TEST(CompileFunctionInContextQuirks) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
LocalContext env;
{
static const char* source =
"[x, y] = ['ab', 'cd'];"
"return x + y";
static const char* expect = "abcd";
v8::ScriptCompiler::Source script_source(v8_str(source));
v8::Local<v8::Function> fun =
v8::ScriptCompiler::CompileFunctionInContext(
env.local(), &script_source, 0, nullptr, 0, nullptr)
.ToLocalChecked();
v8::Local<v8::Value> result =
fun->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked();
CHECK(result->IsString());
CHECK(v8::Local<v8::String>::Cast(result)
->Equals(env.local(), v8_str(expect))
.FromJust());
}
{
static const char* source = "'use strict'; var a = 077";
v8::ScriptCompiler::Source script_source(v8_str(source));
v8::TryCatch try_catch(CcTest::isolate());
CHECK(v8::ScriptCompiler::CompileFunctionInContext(
env.local(), &script_source, 0, nullptr, 0, nullptr)
.IsEmpty());
CHECK(try_catch.HasCaught());
}
{
static const char* source = "{ let x; { var x } }";
v8::ScriptCompiler::Source script_source(v8_str(source));
v8::TryCatch try_catch(CcTest::isolate());
CHECK(v8::ScriptCompiler::CompileFunctionInContext(
env.local(), &script_source, 0, nullptr, 0, nullptr)
.IsEmpty());
CHECK(try_catch.HasCaught());
}
}
TEST(CompileFunctionInContextScriptOrigin) {
CcTest::InitializeVM();
@ -559,7 +657,7 @@ TEST(CompileFunctionInContextScriptOrigin) {
CHECK_EQ(42 + strlen("throw "), static_cast<unsigned>(frame->GetColumn()));
}
TEST(CompileFunctionInContextHarmonyFunctionToString) {
void TestCompileFunctionInContextToStringImpl() {
#define CHECK_NOT_CAUGHT(__local_context__, try_catch, __op__) \
do { \
const char* op = (__op__); \
@ -573,9 +671,7 @@ TEST(CompileFunctionInContextHarmonyFunctionToString) {
} \
} while (0)
auto previous_flag = v8::internal::FLAG_harmony_function_tostring;
v8::internal::FLAG_harmony_function_tostring = true;
{
{ // NOLINT
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
LocalContext env;
@ -601,7 +697,8 @@ TEST(CompileFunctionInContextHarmonyFunctionToString) {
v8::Local<v8::String> result =
fun->ToString(env.local()).ToLocalChecked();
v8::Local<v8::String> expected = v8_str(
"function(event){return event\n"
"function (event) {\n"
"return event\n"
"}");
CHECK(expected->Equals(env.local(), result).FromJust());
}
@ -625,16 +722,24 @@ TEST(CompileFunctionInContextHarmonyFunctionToString) {
v8::Local<v8::String> result =
fun->ToString(env.local()).ToLocalChecked();
v8::Local<v8::String> expected = v8_str(
"function(){return 0\n"
"function () {\n"
"return 0\n"
"}");
CHECK(expected->Equals(env.local(), result).FromJust());
}
}
v8::internal::FLAG_harmony_function_tostring = previous_flag;
#undef CHECK_NOT_CAUGHT
}
TEST(CompileFunctionInContextHarmonyFunctionToString) {
v8::internal::FLAG_harmony_function_tostring = true;
TestCompileFunctionInContextToStringImpl();
}
TEST(CompileFunctionInContextFunctionToString) {
TestCompileFunctionInContextToStringImpl();
}
TEST(InvocationCount) {
FLAG_allow_natives_syntax = true;
FLAG_always_opt = false;

View File

@ -3951,6 +3951,72 @@ TEST(DebugBreak) {
CheckDebuggerUnloaded();
}
static void DebugScopingListener(const v8::Debug::EventDetails& event_details) {
v8::DebugEvent event = event_details.GetEvent();
if (event != v8::Exception) return;
auto stack_traces = v8::debug::StackTraceIterator::Create(CcTest::isolate());
v8::debug::Location location = stack_traces->GetSourceLocation();
CHECK_EQ(26, location.GetColumnNumber());
CHECK_EQ(0, location.GetLineNumber());
auto scopes = stack_traces->GetScopeIterator();
CHECK_EQ(v8::debug::ScopeIterator::ScopeTypeWith, scopes->GetType());
CHECK_EQ(20, scopes->GetStartLocation().GetColumnNumber());
CHECK_EQ(31, scopes->GetEndLocation().GetColumnNumber());
scopes->Advance();
CHECK_EQ(v8::debug::ScopeIterator::ScopeTypeLocal, scopes->GetType());
CHECK_EQ(0, scopes->GetStartLocation().GetColumnNumber());
CHECK_EQ(68, scopes->GetEndLocation().GetColumnNumber());
scopes->Advance();
CHECK_EQ(v8::debug::ScopeIterator::ScopeTypeGlobal, scopes->GetType());
CHECK(scopes->GetFunction().IsEmpty());
scopes->Advance();
CHECK(scopes->Done());
}
TEST(DebugBreakInWrappedScript) {
i::FLAG_stress_compaction = false;
#ifdef VERIFY_HEAP
i::FLAG_verify_heap = true;
#endif
DebugLocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
// Register a debug event listener which sets the break flag and counts.
SetDebugEventListener(isolate, DebugScopingListener);
static const char* source =
// 0 1 2 3 4 5 6 7
"try { with({o : []}){ o[0](); } } catch (e) { return e.toString(); }";
static const char* expect = "TypeError: o[0] is not a function";
// For this test, we want to break on uncaught exceptions:
ChangeBreakOnException(true, true);
{
v8::ScriptCompiler::Source script_source(v8_str(source));
v8::Local<v8::Function> fun =
v8::ScriptCompiler::CompileFunctionInContext(
env.context(), &script_source, 0, nullptr, 0, nullptr)
.ToLocalChecked();
v8::Local<v8::Value> result =
fun->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
CHECK(result->IsString());
CHECK(v8::Local<v8::String>::Cast(result)
->Equals(env.context(), v8_str(expect))
.FromJust());
}
// Get rid of the debug event listener.
SetDebugEventListener(isolate, nullptr);
CheckDebuggerUnloaded();
}
TEST(DebugBreakWithoutJS) {
i::FLAG_stress_compaction = false;
#ifdef VERIFY_HEAP