Don't compile inner functions when compiling via the dispatcher

BUG=v8:5394
R=mstarzinger@chromium.org,rmcilroy@chromium.org

Review-Url: https://codereview.chromium.org/2579973002
Cr-Commit-Position: refs/heads/master@{#41754}
This commit is contained in:
jochen 2016-12-16 04:38:17 -08:00 committed by Commit bot
parent 01408ea653
commit 87bf033799
19 changed files with 127 additions and 62 deletions

View File

@ -183,8 +183,8 @@ bool CompilerDispatcherJob::PrepareToCompileOnMainThread() {
DeferredHandleScope scope(isolate_);
if (Compiler::Analyze(parse_info_.get())) {
compile_job_.reset(
Compiler::PrepareUnoptimizedCompilationJob(compile_info_.get()));
compile_job_.reset(Compiler::PrepareUnoptimizedCompilationJob(
compile_info_.get(), LazyCompilationMode::kAlways));
}
compile_info_->set_deferred_handles(scope.Detach());

View File

@ -366,7 +366,8 @@ bool ShouldUseIgnition(CompilationInfo* info) {
return shared->PassesFilter(FLAG_ignition_filter);
}
CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) {
CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info,
LazyCompilationMode mode) {
// Function should have been parsed and analyzed before creating a compilation
// job.
DCHECK_NOT_NULL(info->literal());
@ -374,9 +375,9 @@ CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) {
EnsureFeedbackMetadata(info);
if (ShouldUseIgnition(info)) {
return interpreter::Interpreter::NewCompilationJob(info);
return interpreter::Interpreter::NewCompilationJob(info, mode);
} else {
return FullCodeGenerator::NewCompilationJob(info);
return FullCodeGenerator::NewCompilationJob(info, mode);
}
}
@ -439,7 +440,8 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) {
}
}
std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info));
std::unique_ptr<CompilationJob> job(
GetUnoptimizedCompilationJob(info, LazyCompilationMode::kIfRequested));
if (job->PrepareJob() != CompilationJob::SUCCEEDED) return false;
if (job->ExecuteJob() != CompilationJob::SUCCEEDED) return false;
if (FinalizeUnoptimizedCompilationJob(job.get()) !=
@ -1565,10 +1567,9 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForStreamedScript(
return result;
}
Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
FunctionLiteral* literal, Handle<Script> script,
CompilationInfo* outer_info) {
CompilationInfo* outer_info, LazyCompilationMode mode) {
// Precondition: code has been parsed and scopes have been analyzed.
Isolate* isolate = outer_info->isolate();
MaybeHandle<SharedFunctionInfo> maybe_existing;
@ -1620,7 +1621,8 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
// This is especially important for generators. We must not replace the
// code for generators, as there may be suspended generator objects.
if (!result->is_compiled()) {
if (!literal->ShouldEagerCompile()) {
if (mode == LazyCompilationMode::kAlways ||
!literal->ShouldEagerCompile()) {
info.SetCode(isolate->builtins()->CompileLazy());
Scope* outer_scope = literal->scope()->GetOuterScopeWithContext();
if (outer_scope) {
@ -1693,9 +1695,9 @@ MaybeHandle<Code> Compiler::GetOptimizedCodeForOSR(Handle<JSFunction> function,
}
CompilationJob* Compiler::PrepareUnoptimizedCompilationJob(
CompilationInfo* info) {
CompilationInfo* info, LazyCompilationMode mode) {
VMState<COMPILER> state(info->isolate());
std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info));
std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info, mode));
if (job->PrepareJob() != CompilationJob::SUCCEEDED) {
return nullptr;
}

View File

@ -23,6 +23,8 @@ class JavaScriptFrame;
class ParseInfo;
class ScriptData;
enum class LazyCompilationMode { kAlways, kIfRequested };
// The V8 compiler API.
//
// This is the central hub for dispatching to the various compilers within V8.
@ -51,9 +53,11 @@ class Compiler : public AllStatic {
static bool CompileDebugCode(Handle<SharedFunctionInfo> shared);
static MaybeHandle<JSArray> CompileForLiveEdit(Handle<Script> script);
// Prepare a compilation job for unoptimized code. Requires ParseAndAnalyse.
// Prepare a compilation job for unoptimized code. If |mode| is
// LazyCompilationMode::kAlways, the returned job will not compile any inner
// functions. Requires ParseAndAnalyse.
static CompilationJob* PrepareUnoptimizedCompilationJob(
CompilationInfo* info);
CompilationInfo* info, LazyCompilationMode mode);
// Generate and install code from previously queued compilation job.
static bool FinalizeCompilationJob(CompilationJob* job);
@ -115,7 +119,8 @@ class Compiler : public AllStatic {
// Create a shared function info object (the code may be lazily compiled).
static Handle<SharedFunctionInfo> GetSharedFunctionInfo(
FunctionLiteral* node, Handle<Script> script, CompilationInfo* outer);
FunctionLiteral* node, Handle<Script> script, CompilationInfo* outer,
LazyCompilationMode mode = LazyCompilationMode::kIfRequested);
// Create a shared function info object for a native function literal.
static Handle<SharedFunctionInfo> GetSharedFunctionInfoForNative(

View File

@ -798,8 +798,8 @@ void FullCodeGenerator::VisitFunctionDeclaration(
FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
DCHECK(!slot.IsInvalid());
globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
declaration->fun(), script(), info_, compilation_mode_);
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
globals_->Add(function, zone());

View File

@ -793,8 +793,8 @@ void FullCodeGenerator::VisitFunctionDeclaration(
FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
DCHECK(!slot.IsInvalid());
globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
declaration->fun(), script(), info_, compilation_mode_);
// Check for stack overflow exception.
if (function.is_null()) return SetStackOverflow();
globals_->Add(function, zone());

View File

@ -28,8 +28,8 @@ namespace internal {
class FullCodegenCompilationJob final : public CompilationJob {
public:
explicit FullCodegenCompilationJob(CompilationInfo* info)
: CompilationJob(info->isolate(), info, "Full-Codegen") {}
FullCodegenCompilationJob(CompilationInfo* info, LazyCompilationMode mode)
: CompilationJob(info->isolate(), info, "Full-Codegen"), mode_(mode) {}
bool can_execute_on_background_thread() const override { return false; }
@ -37,19 +37,26 @@ class FullCodegenCompilationJob final : public CompilationJob {
CompilationJob::Status ExecuteJobImpl() final {
DCHECK(ThreadId::Current().Equals(isolate()->thread_id()));
return FullCodeGenerator::MakeCode(info(), stack_limit()) ? SUCCEEDED
: FAILED;
return FullCodeGenerator::MakeCode(info(), stack_limit(), mode_) ? SUCCEEDED
: FAILED;
}
CompilationJob::Status FinalizeJobImpl() final { return SUCCEEDED; }
private:
LazyCompilationMode mode_;
DISALLOW_COPY_AND_ASSIGN(FullCodegenCompilationJob);
};
FullCodeGenerator::FullCodeGenerator(MacroAssembler* masm,
CompilationInfo* info,
uintptr_t stack_limit)
uintptr_t stack_limit,
LazyCompilationMode mode)
: masm_(masm),
info_(info),
isolate_(info->isolate()),
compilation_mode_(mode),
zone_(info->zone()),
scope_(info->scope()),
nesting_stack_(NULL),
@ -70,17 +77,20 @@ FullCodeGenerator::FullCodeGenerator(MacroAssembler* masm,
}
// static
CompilationJob* FullCodeGenerator::NewCompilationJob(CompilationInfo* info) {
return new FullCodegenCompilationJob(info);
CompilationJob* FullCodeGenerator::NewCompilationJob(CompilationInfo* info,
LazyCompilationMode mode) {
return new FullCodegenCompilationJob(info, mode);
}
// static
bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
return MakeCode(info, info->isolate()->stack_guard()->real_climit());
return MakeCode(info, info->isolate()->stack_guard()->real_climit(),
LazyCompilationMode::kIfRequested);
}
// static
bool FullCodeGenerator::MakeCode(CompilationInfo* info, uintptr_t stack_limit) {
bool FullCodeGenerator::MakeCode(CompilationInfo* info, uintptr_t stack_limit,
LazyCompilationMode mode) {
Isolate* isolate = info->isolate();
DCHECK(!info->shared_info()->must_use_ignition_turbo());
@ -102,7 +112,7 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info, uintptr_t stack_limit) {
CodeObjectRequired::kYes);
if (info->will_serialize()) masm.enable_serializer();
FullCodeGenerator cgen(&masm, info, stack_limit);
FullCodeGenerator cgen(&masm, info, stack_limit, mode);
cgen.Generate();
if (cgen.HasStackOverflow()) {
DCHECK(!isolate->has_pending_exception());
@ -1285,7 +1295,7 @@ void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
// Build the function boilerplate and instantiate it.
Handle<SharedFunctionInfo> function_info =
Compiler::GetSharedFunctionInfo(expr, script(), info_);
Compiler::GetSharedFunctionInfo(expr, script(), info_, compilation_mode_);
if (function_info.is_null()) {
SetStackOverflow();
return;

View File

@ -25,6 +25,7 @@ class CompilationInfo;
class CompilationJob;
class JumpPatchSite;
class Scope;
enum class LazyCompilationMode;
// -----------------------------------------------------------------------------
// Full code generator.
@ -32,13 +33,15 @@ class Scope;
class FullCodeGenerator final : public AstVisitor<FullCodeGenerator> {
public:
FullCodeGenerator(MacroAssembler* masm, CompilationInfo* info,
uintptr_t stack_limit);
uintptr_t stack_limit, LazyCompilationMode mode);
void Initialize(uintptr_t stack_limit);
static CompilationJob* NewCompilationJob(CompilationInfo* info);
static CompilationJob* NewCompilationJob(CompilationInfo* info,
LazyCompilationMode mode);
static bool MakeCode(CompilationInfo* info, uintptr_t stack_limit);
static bool MakeCode(CompilationInfo* info, uintptr_t stack_limit,
LazyCompilationMode mode);
static bool MakeCode(CompilationInfo* info);
// Encode bailout state and pc-offset as a BitField<type, start, size>.
@ -804,6 +807,7 @@ class FullCodeGenerator final : public AstVisitor<FullCodeGenerator> {
MacroAssembler* masm_;
CompilationInfo* info_;
Isolate* isolate_;
LazyCompilationMode compilation_mode_;
Zone* zone_;
Scope* scope_;
Label return_label_;

View File

@ -746,8 +746,8 @@ void FullCodeGenerator::VisitFunctionDeclaration(
FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
DCHECK(!slot.IsInvalid());
globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
declaration->fun(), script(), info_, compilation_mode_);
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
globals_->Add(function, zone());

View File

@ -797,8 +797,8 @@ void FullCodeGenerator::VisitFunctionDeclaration(
FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
DCHECK(!slot.IsInvalid());
globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
declaration->fun(), script(), info_, compilation_mode_);
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
globals_->Add(function, zone());

View File

@ -797,8 +797,8 @@ void FullCodeGenerator::VisitFunctionDeclaration(
FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
DCHECK(!slot.IsInvalid());
globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
declaration->fun(), script(), info_, compilation_mode_);
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
globals_->Add(function, zone());

View File

@ -766,8 +766,8 @@ void FullCodeGenerator::VisitFunctionDeclaration(
FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
DCHECK(!slot.IsInvalid());
globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
declaration->fun(), script(), info_, compilation_mode_);
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
globals_->Add(function, zone());

View File

@ -738,8 +738,8 @@ void FullCodeGenerator::VisitFunctionDeclaration(
FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
DCHECK(!slot.IsInvalid());
globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
declaration->fun(), script(), info_, compilation_mode_);
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
globals_->Add(function, zone());

View File

@ -760,8 +760,8 @@ void FullCodeGenerator::VisitFunctionDeclaration(
FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
DCHECK(!slot.IsInvalid());
globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
declaration->fun(), script(), info_, compilation_mode_);
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
globals_->Add(function, zone());

View File

@ -742,8 +742,8 @@ void FullCodeGenerator::VisitFunctionDeclaration(
FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
DCHECK(!slot.IsInvalid());
globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
declaration->fun(), script(), info_, compilation_mode_);
// Check for stack-overflow exception.
if (function.is_null()) return SetStackOverflow();
globals_->Add(function, zone());

View File

@ -491,10 +491,11 @@ class BytecodeGenerator::TestResultScope final : public ExpressionResultScope {
// Used to build a list of global declaration initial value pairs.
class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject {
public:
explicit GlobalDeclarationsBuilder(Zone* zone)
GlobalDeclarationsBuilder(Zone* zone, LazyCompilationMode mode)
: declarations_(0, zone),
constant_pool_entry_(0),
has_constant_pool_entry_(false) {}
has_constant_pool_entry_(false),
compilation_mode_(mode) {}
void AddFunctionDeclaration(Handle<String> name, FeedbackVectorSlot slot,
FunctionLiteral* func) {
@ -518,8 +519,8 @@ class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject {
if (func == nullptr) {
initial_value = info->isolate()->factory()->undefined_value();
} else {
initial_value =
Compiler::GetSharedFunctionInfo(func, info->script(), info);
initial_value = Compiler::GetSharedFunctionInfo(
func, info->script(), info, compilation_mode_);
}
// Return a null handle if any initial values can't be created. Caller
@ -561,9 +562,11 @@ class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject {
ZoneVector<Declaration> declarations_;
size_t constant_pool_entry_;
bool has_constant_pool_entry_;
LazyCompilationMode compilation_mode_;
};
BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
BytecodeGenerator::BytecodeGenerator(CompilationInfo* info,
LazyCompilationMode mode)
: zone_(info->zone()),
builder_(new (zone()) BytecodeArrayBuilder(
info->isolate(), info->zone(), info->num_parameters_including_this(),
@ -572,7 +575,9 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
info->SourcePositionRecordingMode())),
info_(info),
scope_(info->scope()),
globals_builder_(new (zone()) GlobalDeclarationsBuilder(info->zone())),
compilation_mode_(mode),
globals_builder_(new (zone())
GlobalDeclarationsBuilder(info->zone(), mode)),
global_declarations_(0, info->zone()),
function_literals_(0, info->zone()),
native_function_literals_(0, info->zone()),
@ -611,8 +616,8 @@ void BytecodeGenerator::AllocateDeferredConstants() {
// Find or build shared function infos.
for (std::pair<FunctionLiteral*, size_t> literal : function_literals_) {
FunctionLiteral* expr = literal.first;
Handle<SharedFunctionInfo> shared_info =
Compiler::GetSharedFunctionInfo(expr, info()->script(), info());
Handle<SharedFunctionInfo> shared_info = Compiler::GetSharedFunctionInfo(
expr, info()->script(), info(), compilation_mode_);
if (shared_info.is_null()) return SetStackOverflow();
builder()->InsertConstantPoolEntryAt(literal.second, shared_info);
}
@ -949,7 +954,8 @@ void BytecodeGenerator::VisitDeclarations(Declaration::List* declarations) {
// Push and reset globals builder.
global_declarations_.push_back(globals_builder());
globals_builder_ = new (zone()) GlobalDeclarationsBuilder(zone());
globals_builder_ =
new (zone()) GlobalDeclarationsBuilder(zone(), compilation_mode_);
}
void BytecodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {

View File

@ -15,6 +15,7 @@ namespace v8 {
namespace internal {
class CompilationInfo;
enum class LazyCompilationMode;
namespace interpreter {
@ -22,7 +23,7 @@ class LoopBuilder;
class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
public:
explicit BytecodeGenerator(CompilationInfo* info);
BytecodeGenerator(CompilationInfo* info, LazyCompilationMode mode);
void GenerateBytecode(uintptr_t stack_limit);
Handle<BytecodeArray> FinalizeBytecode(Isolate* isolate);
@ -206,6 +207,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
BytecodeArrayBuilder* builder_;
CompilationInfo* info_;
DeclarationScope* scope_;
LazyCompilationMode compilation_mode_;
GlobalDeclarationsBuilder* globals_builder_;
ZoneVector<GlobalDeclarationsBuilder*> global_declarations_;

View File

@ -32,7 +32,7 @@ typedef CodeStubAssembler::Variable Variable;
class InterpreterCompilationJob final : public CompilationJob {
public:
explicit InterpreterCompilationJob(CompilationInfo* info);
InterpreterCompilationJob(CompilationInfo* info, LazyCompilationMode mode);
protected:
Status PrepareJobImpl() final;
@ -158,8 +158,10 @@ int Interpreter::InterruptBudget() {
return FLAG_interrupt_budget * kCodeSizeMultiplier;
}
InterpreterCompilationJob::InterpreterCompilationJob(CompilationInfo* info)
: CompilationJob(info->isolate(), info, "Ignition"), generator_(info) {}
InterpreterCompilationJob::InterpreterCompilationJob(CompilationInfo* info,
LazyCompilationMode mode)
: CompilationJob(info->isolate(), info, "Ignition"),
generator_(info, mode) {}
InterpreterCompilationJob::Status InterpreterCompilationJob::PrepareJobImpl() {
CodeGenerator::MakeCodePrologue(info(), "interpreter");
@ -207,8 +209,9 @@ InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl() {
return SUCCEEDED;
}
CompilationJob* Interpreter::NewCompilationJob(CompilationInfo* info) {
return new InterpreterCompilationJob(info);
CompilationJob* Interpreter::NewCompilationJob(CompilationInfo* info,
LazyCompilationMode mode) {
return new InterpreterCompilationJob(info, mode);
}
bool Interpreter::IsDispatchTableInitialized() {

View File

@ -23,6 +23,7 @@ class Isolate;
class Callable;
class CompilationInfo;
class CompilationJob;
enum class LazyCompilationMode;
namespace compiler {
class Node;
@ -44,7 +45,8 @@ class Interpreter {
static int InterruptBudget();
// Creates a compilation job which will generate bytecode for |info|.
static CompilationJob* NewCompilationJob(CompilationInfo* info);
static CompilationJob* NewCompilationJob(CompilationInfo* info,
LazyCompilationMode mode);
// Return bytecode handler for |bytecode|.
Code* GetBytecodeHandler(Bytecode bytecode, OperandScale operand_scale);

View File

@ -323,5 +323,36 @@ TEST_F(IgnitionCompilerDispatcherJobTest, CompileOnBackgroundThread) {
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
}
TEST_F(CompilerDispatcherJobTest, LazyInnerFunctions) {
const char script[] =
"function g() {\n"
" f = function() {\n"
" e = (function() { return 42; });\n"
" return e;\n"
" };\n"
" return f;\n"
"}\n"
"g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), tracer(), handle(f->shared()), FLAG_stack_size));
job->PrepareToParseOnMainThread();
job->Parse();
ASSERT_TRUE(job->FinalizeParsingOnMainThread());
ASSERT_TRUE(job->PrepareToCompileOnMainThread());
job->Compile();
ASSERT_TRUE(job->FinalizeCompilingOnMainThread());
ASSERT_TRUE(job->status() == CompileJobStatus::kDone);
Handle<JSFunction> e = Handle<JSFunction>::cast(RunJS(isolate(), "f();"));
ASSERT_FALSE(e->shared()->HasBaselineCode());
job->ResetOnMainThread();
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
}
} // namespace internal
} // namespace v8