[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:
parent
41e8619069
commit
1586f37f2d
@ -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);
|
||||
}
|
||||
|
80
src/api.cc
80
src/api.cc
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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";
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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, _) \
|
||||
|
@ -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);
|
||||
|
@ -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 -----------------------
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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] = {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user