Revert "[Compiler] Remove CompileDebugCode and EnsureBytecode and replace with Compile"
This reverts commit 21da12a983
.
Reason for revert: Failing on arm64 simulator
Original change's description:
> [Compiler] Remove CompileDebugCode and EnsureBytecode and replace with Compile
>
> Removes the Compiler::CompileDebugCode and Compiler::EnsureBytecode functions
> and replaces them with a Compiler::Compile(Handle<SharedFunctionInfo> shared)
> function. The code in compiler.cc is refactored to use this function to compile
> the SharedFunctionInfo when compiling a JSFunction.
>
> Also does some other cleanup:
> - Removes CompileUnoptimizedFunction and inlines into new Compiler function
> - Moves code to create top level SharedFunctionInfo into CompilerTopLevel and
> out of FinalizeUnoptimizedCompile.
>
> BUG=v8:6409
>
> Change-Id: Ic54afcd8eb005c17f3ae6b2355060846e3091ca3
> Reviewed-on: https://chromium-review.googlesource.com/613760
> Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Yang Guo <yangguo@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#47394}
TBR=rmcilroy@chromium.org,yangguo@chromium.org,jarin@chromium.org,leszeks@chromium.org
Change-Id: I4ba63e82417a185f1528ff2633eb6c8872fbbfe5
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:6409
Reviewed-on: https://chromium-review.googlesource.com/618687
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47397}
This commit is contained in:
parent
89ac7fcdb4
commit
0f40415b6b
@ -30,6 +30,7 @@ CompilationInfo::CompilationInfo(Zone* zone, Isolate* isolate,
|
||||
literal_ = literal;
|
||||
source_range_map_ = parse_info->source_range_map();
|
||||
|
||||
if (parse_info->is_debug()) MarkAsDebug();
|
||||
if (parse_info->is_eval()) MarkAsEval();
|
||||
if (parse_info->is_native()) MarkAsNative();
|
||||
if (parse_info->will_serialize()) MarkAsSerializing();
|
||||
|
@ -36,17 +36,18 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
|
||||
// Various configuration flags for a compilation, as well as some properties
|
||||
// of the compiled code produced by a compilation.
|
||||
enum Flag {
|
||||
kIsEval = 1 << 0,
|
||||
kIsNative = 1 << 1,
|
||||
kSerializing = 1 << 2,
|
||||
kAccessorInliningEnabled = 1 << 3,
|
||||
kFunctionContextSpecializing = 1 << 4,
|
||||
kInliningEnabled = 1 << 5,
|
||||
kDisableFutureOptimization = 1 << 6,
|
||||
kSplittingEnabled = 1 << 7,
|
||||
kSourcePositionsEnabled = 1 << 8,
|
||||
kBailoutOnUninitialized = 1 << 9,
|
||||
kLoopPeelingEnabled = 1 << 10,
|
||||
kIsDebug = 1 << 0,
|
||||
kIsEval = 1 << 1,
|
||||
kIsNative = 1 << 2,
|
||||
kSerializing = 1 << 3,
|
||||
kAccessorInliningEnabled = 1 << 4,
|
||||
kFunctionContextSpecializing = 1 << 5,
|
||||
kInliningEnabled = 1 << 6,
|
||||
kDisableFutureOptimization = 1 << 7,
|
||||
kSplittingEnabled = 1 << 8,
|
||||
kSourcePositionsEnabled = 1 << 9,
|
||||
kBailoutOnUninitialized = 1 << 10,
|
||||
kLoopPeelingEnabled = 1 << 11,
|
||||
};
|
||||
|
||||
// Construct a compilation info for unoptimized compilation.
|
||||
@ -107,6 +108,11 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
|
||||
|
||||
// Flags used by unoptimized compilation.
|
||||
|
||||
// Compiles marked as debug produce unoptimized code with debug break slots.
|
||||
// Inner functions that cannot be compiled w/o context are compiled eagerly.
|
||||
void MarkAsDebug() { SetFlag(kIsDebug); }
|
||||
bool is_debug() const { return GetFlag(kIsDebug); }
|
||||
|
||||
void MarkAsSerializing() { SetFlag(kSerializing); }
|
||||
bool will_serialize() const { return GetFlag(kSerializing); }
|
||||
|
||||
@ -155,7 +161,7 @@ class V8_EXPORT_PRIVATE CompilationInfo final {
|
||||
// Generate a pre-aged prologue if we are optimizing for size, which
|
||||
// will make code old more aggressive. Only apply to Code::FUNCTION,
|
||||
// since only functions are aged in the compilation cache.
|
||||
return FLAG_optimize_for_size && FLAG_age_code &&
|
||||
return FLAG_optimize_for_size && FLAG_age_code && !is_debug() &&
|
||||
output_code_kind() == Code::FUNCTION;
|
||||
}
|
||||
|
||||
|
412
src/compiler.cc
412
src/compiler.cc
@ -255,7 +255,7 @@ void EnsureFeedbackMetadata(CompilationInfo* compilation_info) {
|
||||
compilation_info->literal()->feedback_vector_spec()));
|
||||
}
|
||||
|
||||
bool UseAsmWasm(FunctionLiteral* literal, bool asm_wasm_broken) {
|
||||
bool UseAsmWasm(FunctionLiteral* literal, bool asm_wasm_broken, bool is_debug) {
|
||||
// Check whether asm.js validation is enabled.
|
||||
if (!FLAG_validate_asm) return false;
|
||||
|
||||
@ -263,6 +263,9 @@ bool UseAsmWasm(FunctionLiteral* literal, bool asm_wasm_broken) {
|
||||
// invalid module instantiation attempts are off limit forever.
|
||||
if (asm_wasm_broken) return false;
|
||||
|
||||
// Compiling for debugging is not supported, fall back.
|
||||
if (is_debug) return false;
|
||||
|
||||
// In stress mode we want to run the validator on everything.
|
||||
if (FLAG_stress_validate_asm) return true;
|
||||
|
||||
@ -293,6 +296,13 @@ void InstallUnoptimizedCode(CompilationInfo* compilation_info) {
|
||||
shared->set_outer_scope_info(*outer_scope->scope_info());
|
||||
}
|
||||
|
||||
// Install compilation result on the shared function info.
|
||||
// TODO(mstarzinger): Compiling for debug code might be used to reveal inner
|
||||
// functions via {FindSharedFunctionInfoInScript}, in which case we end up
|
||||
// regenerating existing bytecode. Fix this!
|
||||
if (compilation_info->is_debug() && compilation_info->has_bytecode_array()) {
|
||||
shared->ClearBytecodeArray();
|
||||
}
|
||||
DCHECK(!compilation_info->code().is_null());
|
||||
shared->ReplaceCode(*compilation_info->code());
|
||||
if (compilation_info->has_bytecode_array()) {
|
||||
@ -375,7 +385,8 @@ bool Renumber(ParseInfo* parse_info,
|
||||
|
||||
std::unique_ptr<CompilationJob> PrepareAndExecuteUnoptimizedCompileJob(
|
||||
ParseInfo* parse_info, FunctionLiteral* literal, Isolate* isolate) {
|
||||
if (UseAsmWasm(literal, parse_info->is_asm_wasm_broken())) {
|
||||
if (UseAsmWasm(literal, parse_info->is_asm_wasm_broken(),
|
||||
parse_info->is_debug())) {
|
||||
std::unique_ptr<CompilationJob> asm_job(
|
||||
AsmJs::NewCompilationJob(parse_info, literal, isolate));
|
||||
if (asm_job->PrepareJob() == CompilationJob::SUCCEEDED &&
|
||||
@ -437,10 +448,26 @@ bool FinalizeUnoptimizedCode(
|
||||
std::forward_list<std::unique_ptr<CompilationJob>>* inner_function_jobs) {
|
||||
DCHECK(AllowCompilation::IsAllowed(isolate));
|
||||
|
||||
// Internalize ast values onto the heap.
|
||||
parse_info->ast_value_factory()->Internalize(isolate);
|
||||
|
||||
// Allocate scope infos for the literal.
|
||||
DeclarationScope::AllocateScopeInfos(parse_info, isolate,
|
||||
AnalyzeMode::kRegular);
|
||||
|
||||
// If compiling top-level code, allocate a shared function info and an array
|
||||
// for shared function infos for inner functions.
|
||||
if (parse_info->is_toplevel()) {
|
||||
EnsureSharedFunctionInfosArrayOnScript(parse_info, isolate);
|
||||
DCHECK_EQ(kNoSourcePosition,
|
||||
parse_info->literal()->function_token_position());
|
||||
if (shared_info.is_null()) {
|
||||
shared_info = isolate->factory()->NewSharedFunctionInfoForLiteral(
|
||||
parse_info->literal(), parse_info->script());
|
||||
shared_info->set_is_toplevel(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize the outer-most function's compilation job.
|
||||
outer_function_job->compilation_info()->set_shared_info(shared_info);
|
||||
if (FinalizeUnoptimizedCompilationJob(outer_function_job) !=
|
||||
@ -466,6 +493,39 @@ bool FinalizeUnoptimizedCode(
|
||||
return true;
|
||||
}
|
||||
|
||||
MUST_USE_RESULT MaybeHandle<Code> CompileUnoptimizedFunction(
|
||||
ParseInfo* parse_info, Isolate* isolate,
|
||||
Handle<SharedFunctionInfo> shared_info) {
|
||||
RuntimeCallTimerScope runtimeTimer(
|
||||
isolate, &RuntimeCallStats::CompileUnoptimizedFunction);
|
||||
VMState<BYTECODE_COMPILER> state(isolate);
|
||||
PostponeInterruptsScope postpone(isolate);
|
||||
|
||||
// Parse and update ParseInfo with the results.
|
||||
if (!parsing::ParseFunction(parse_info, shared_info, isolate)) {
|
||||
return MaybeHandle<Code>();
|
||||
}
|
||||
|
||||
// Generate the unoptimized bytecode or asm-js data.
|
||||
std::forward_list<std::unique_ptr<CompilationJob>> inner_function_jobs;
|
||||
std::unique_ptr<CompilationJob> outer_function_job(
|
||||
GenerateUnoptimizedCode(parse_info, isolate, &inner_function_jobs));
|
||||
if (!outer_function_job) {
|
||||
if (!isolate->has_pending_exception()) isolate->StackOverflow();
|
||||
return MaybeHandle<Code>();
|
||||
}
|
||||
|
||||
// Finalize compilation of the unoptimized bytecode or asm-js data.
|
||||
if (!FinalizeUnoptimizedCode(parse_info, isolate, shared_info,
|
||||
outer_function_job.get(),
|
||||
&inner_function_jobs)) {
|
||||
if (!isolate->has_pending_exception()) isolate->StackOverflow();
|
||||
return MaybeHandle<Code>();
|
||||
}
|
||||
|
||||
return handle(shared_info->code(), isolate);
|
||||
}
|
||||
|
||||
MUST_USE_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeCache(
|
||||
Handle<JSFunction> function, BailoutId osr_ast_id) {
|
||||
RuntimeCallTimerScope runtimeTimer(
|
||||
@ -754,9 +814,81 @@ CompilationJob::Status FinalizeOptimizedCompilationJob(CompilationJob* job) {
|
||||
return CompilationJob::FAILED;
|
||||
}
|
||||
|
||||
MaybeHandle<SharedFunctionInfo> CompileToplevel(ParseInfo* parse_info,
|
||||
Isolate* isolate) {
|
||||
TimerEventScope<TimerEventCompileCode> top_level_timer(isolate);
|
||||
MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) {
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
DCHECK(!isolate->has_pending_exception());
|
||||
DCHECK(!function->is_compiled());
|
||||
TimerEventScope<TimerEventCompileCode> compile_timer(isolate);
|
||||
RuntimeCallTimerScope runtimeTimer(isolate,
|
||||
&RuntimeCallStats::CompileFunction);
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode");
|
||||
AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy());
|
||||
|
||||
if (function->shared()->is_compiled()) {
|
||||
// Function has already been compiled. Normally we'd expect the CompileLazy
|
||||
// builtin to catch cases where we already have compiled code or optimized
|
||||
// code, but there are paths that call the CompileLazy runtime function
|
||||
// directly (e.g. failed asm.js compilations), so we include a check for
|
||||
// those.
|
||||
Handle<Code> cached_code;
|
||||
if (GetCodeFromOptimizedCodeCache(function, BailoutId::None())
|
||||
.ToHandle(&cached_code)) {
|
||||
if (FLAG_trace_opt) {
|
||||
PrintF("[found optimized code for ");
|
||||
function->ShortPrint();
|
||||
PrintF(" during unoptimized compile]\n");
|
||||
}
|
||||
return cached_code;
|
||||
}
|
||||
// TODO(leszeks): Either handle optimization markers here, or DCHECK that
|
||||
// there aren't any.
|
||||
return Handle<Code>(function->shared()->code());
|
||||
} else {
|
||||
// Function doesn't have any baseline compiled code, compile now.
|
||||
DCHECK(!function->shared()->HasBytecodeArray());
|
||||
|
||||
Handle<SharedFunctionInfo> shared(function->shared());
|
||||
ParseInfo parse_info(shared);
|
||||
parse_info.set_lazy_compile();
|
||||
if (FLAG_preparser_scope_analysis) {
|
||||
if (shared->HasPreParsedScopeData()) {
|
||||
Handle<PreParsedScopeData> data(
|
||||
PreParsedScopeData::cast(shared->preparsed_scope_data()));
|
||||
parse_info.consumed_preparsed_scope_data()->SetData(data);
|
||||
// After we've compiled the function, we don't need data about its
|
||||
// skippable functions any more.
|
||||
shared->set_preparsed_scope_data(isolate->heap()->null_value());
|
||||
}
|
||||
}
|
||||
Handle<Code> result;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, result,
|
||||
CompileUnoptimizedFunction(&parse_info, isolate, shared), Code);
|
||||
|
||||
if (FLAG_always_opt && !shared->HasAsmWasmData()) {
|
||||
if (FLAG_trace_opt) {
|
||||
PrintF("[optimizing ");
|
||||
function->ShortPrint();
|
||||
PrintF(" because --always-opt]\n");
|
||||
}
|
||||
// Getting optimized code assumes that we have literals.
|
||||
JSFunction::EnsureLiterals(function);
|
||||
|
||||
Handle<Code> opt_code;
|
||||
if (GetOptimizedCode(function, ConcurrencyMode::kNotConcurrent)
|
||||
.ToHandle(&opt_code)) {
|
||||
result = opt_code;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Handle<SharedFunctionInfo> CompileToplevel(
|
||||
ParseInfo* parse_info, Isolate* isolate,
|
||||
Handle<SharedFunctionInfo> shared_info) {
|
||||
TimerEventScope<TimerEventCompileCode> timer(isolate);
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode");
|
||||
PostponeInterruptsScope postpone(isolate);
|
||||
DCHECK(!isolate->native_context().is_null());
|
||||
@ -766,66 +898,48 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel(ParseInfo* parse_info,
|
||||
|
||||
Handle<Script> script = parse_info->script();
|
||||
Handle<SharedFunctionInfo> result;
|
||||
VMState<BYTECODE_COMPILER> state(isolate);
|
||||
if (parse_info->literal() == nullptr &&
|
||||
!parsing::ParseProgram(parse_info, isolate)) {
|
||||
return MaybeHandle<SharedFunctionInfo>();
|
||||
}
|
||||
// Measure how long it takes to do the compilation; only take the
|
||||
// rest of the function into account to avoid overlap with the
|
||||
// parsing statistics.
|
||||
HistogramTimer* rate = parse_info->is_eval()
|
||||
? isolate->counters()->compile_eval()
|
||||
: isolate->counters()->compile();
|
||||
HistogramTimerScope timer(rate);
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
|
||||
parse_info->is_eval() ? "V8.CompileEval" : "V8.Compile");
|
||||
|
||||
// Generate the unoptimized bytecode or asm-js data.
|
||||
std::forward_list<std::unique_ptr<CompilationJob>> inner_function_jobs;
|
||||
std::unique_ptr<CompilationJob> outer_function_job(
|
||||
GenerateUnoptimizedCode(parse_info, isolate, &inner_function_jobs));
|
||||
if (!outer_function_job) {
|
||||
if (!isolate->has_pending_exception()) isolate->StackOverflow();
|
||||
return MaybeHandle<SharedFunctionInfo>();
|
||||
{
|
||||
VMState<BYTECODE_COMPILER> state(isolate);
|
||||
if (parse_info->literal() == nullptr &&
|
||||
!parsing::ParseProgram(parse_info, isolate)) {
|
||||
return Handle<SharedFunctionInfo>::null();
|
||||
}
|
||||
// Measure how long it takes to do the compilation; only take the
|
||||
// rest of the function into account to avoid overlap with the
|
||||
// parsing statistics.
|
||||
HistogramTimer* rate = parse_info->is_eval()
|
||||
? isolate->counters()->compile_eval()
|
||||
: isolate->counters()->compile();
|
||||
HistogramTimerScope timer(rate);
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
|
||||
parse_info->is_eval() ? "V8.CompileEval" : "V8.Compile");
|
||||
|
||||
// Generate the unoptimized bytecode or asm-js data.
|
||||
std::forward_list<std::unique_ptr<CompilationJob>> inner_function_jobs;
|
||||
std::unique_ptr<CompilationJob> outer_function_job(
|
||||
GenerateUnoptimizedCode(parse_info, isolate, &inner_function_jobs));
|
||||
if (!outer_function_job) {
|
||||
if (!isolate->has_pending_exception()) isolate->StackOverflow();
|
||||
return Handle<SharedFunctionInfo>::null();
|
||||
}
|
||||
|
||||
// Finalize compilation of the unoptimized bytecode or asm-js data.
|
||||
if (!FinalizeUnoptimizedCode(parse_info, isolate, shared_info,
|
||||
outer_function_job.get(),
|
||||
&inner_function_jobs)) {
|
||||
if (!isolate->has_pending_exception()) isolate->StackOverflow();
|
||||
return Handle<SharedFunctionInfo>::null();
|
||||
}
|
||||
result = outer_function_job->compilation_info()->shared_info();
|
||||
DCHECK_IMPLIES(!shared_info.is_null(), shared_info.is_identical_to(result));
|
||||
|
||||
if (!script.is_null()) {
|
||||
script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
|
||||
}
|
||||
}
|
||||
|
||||
// Internalize ast values onto the heap.
|
||||
parse_info->ast_value_factory()->Internalize(isolate);
|
||||
|
||||
// Create shared function infos for top level and shared function infos array
|
||||
// for inner functions.
|
||||
EnsureSharedFunctionInfosArrayOnScript(parse_info, isolate);
|
||||
DCHECK_EQ(kNoSourcePosition,
|
||||
parse_info->literal()->function_token_position());
|
||||
Handle<SharedFunctionInfo> shared_info =
|
||||
isolate->factory()->NewSharedFunctionInfoForLiteral(parse_info->literal(),
|
||||
parse_info->script());
|
||||
shared_info->set_is_toplevel(true);
|
||||
|
||||
// Finalize compilation of the unoptimized bytecode or asm-js data.
|
||||
if (!FinalizeUnoptimizedCode(parse_info, isolate, shared_info,
|
||||
outer_function_job.get(),
|
||||
&inner_function_jobs)) {
|
||||
if (!isolate->has_pending_exception()) isolate->StackOverflow();
|
||||
return MaybeHandle<SharedFunctionInfo>();
|
||||
}
|
||||
|
||||
if (!script.is_null()) {
|
||||
script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
|
||||
}
|
||||
|
||||
return shared_info;
|
||||
}
|
||||
|
||||
bool FailWithPendingException(Isolate* isolate,
|
||||
Compiler::ClearExceptionFlag flag) {
|
||||
if (flag == Compiler::CLEAR_EXCEPTION) {
|
||||
isolate->clear_pending_exception();
|
||||
} else if (!isolate->has_pending_exception()) {
|
||||
isolate->StackOverflow();
|
||||
}
|
||||
return false;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -853,107 +967,35 @@ bool Compiler::ParseAndAnalyze(ParseInfo* parse_info,
|
||||
return Compiler::Analyze(parse_info);
|
||||
}
|
||||
|
||||
bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
|
||||
ClearExceptionFlag flag) {
|
||||
// We should never reach here if the function is already compiled.
|
||||
DCHECK(!shared_info->is_compiled());
|
||||
|
||||
Isolate* isolate = shared_info->GetIsolate();
|
||||
DCHECK(!isolate->has_pending_exception());
|
||||
DCHECK(!shared_info->HasBytecodeArray());
|
||||
VMState<BYTECODE_COMPILER> state(isolate);
|
||||
PostponeInterruptsScope postpone(isolate);
|
||||
TimerEventScope<TimerEventCompileCode> compile_timer(isolate);
|
||||
RuntimeCallTimerScope runtimeTimer(isolate,
|
||||
&RuntimeCallStats::CompileFunction);
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode");
|
||||
AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy());
|
||||
|
||||
// Check if the compiler dispatcher has shared_info enqueued for compile.
|
||||
CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
|
||||
if (dispatcher->IsEnqueued(shared_info)) {
|
||||
if (!dispatcher->FinishNow(shared_info)) {
|
||||
return FailWithPendingException(isolate, flag);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set up parse info.
|
||||
ParseInfo parse_info(shared_info);
|
||||
parse_info.set_lazy_compile();
|
||||
if (FLAG_preparser_scope_analysis) {
|
||||
if (shared_info->HasPreParsedScopeData()) {
|
||||
Handle<PreParsedScopeData> data(
|
||||
PreParsedScopeData::cast(shared_info->preparsed_scope_data()));
|
||||
parse_info.consumed_preparsed_scope_data()->SetData(data);
|
||||
// After we've compiled the function, we don't need data about its
|
||||
// skippable functions any more.
|
||||
shared_info->set_preparsed_scope_data(isolate->heap()->null_value());
|
||||
}
|
||||
}
|
||||
|
||||
// Parse and update ParseInfo with the results.
|
||||
if (!parsing::ParseFunction(&parse_info, shared_info, isolate)) {
|
||||
return FailWithPendingException(isolate, flag);
|
||||
}
|
||||
|
||||
// Generate the unoptimized bytecode or asm-js data.
|
||||
std::forward_list<std::unique_ptr<CompilationJob>> inner_function_jobs;
|
||||
std::unique_ptr<CompilationJob> outer_function_job(
|
||||
GenerateUnoptimizedCode(&parse_info, isolate, &inner_function_jobs));
|
||||
if (!outer_function_job) {
|
||||
return FailWithPendingException(isolate, flag);
|
||||
}
|
||||
|
||||
// Internalize ast values onto the heap.
|
||||
parse_info.ast_value_factory()->Internalize(isolate);
|
||||
|
||||
// Finalize compilation of the unoptimized bytecode or asm-js data.
|
||||
if (!FinalizeUnoptimizedCode(&parse_info, isolate, shared_info,
|
||||
outer_function_job.get(),
|
||||
&inner_function_jobs)) {
|
||||
return FailWithPendingException(isolate, flag);
|
||||
}
|
||||
|
||||
DCHECK(!isolate->has_pending_exception());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) {
|
||||
// We should never reach here if the function is already compiled or optimized
|
||||
DCHECK(!function->is_compiled());
|
||||
DCHECK(!function->IsOptimized());
|
||||
// TODO(leszeks): DCHECK that there there aren't any optimization markers or
|
||||
// optimized code on the feedback vector once asm.js calls the compile lazy
|
||||
// builtin rather than the runtime function.
|
||||
|
||||
if (function->is_compiled()) return true;
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
Handle<SharedFunctionInfo> shared_info = handle(function->shared());
|
||||
DCHECK(AllowCompilation::IsAllowed(isolate));
|
||||
|
||||
// Ensure shared function info is compiled.
|
||||
if (!shared_info->is_compiled() && !Compile(shared_info, flag)) return false;
|
||||
Handle<Code> code = handle(shared_info->code(), isolate);
|
||||
|
||||
// Allocate literals for the JSFunction.
|
||||
JSFunction::EnsureLiterals(function);
|
||||
|
||||
// Optimize now if --always-opt is enabled.
|
||||
if (FLAG_always_opt && !function->shared()->HasAsmWasmData()) {
|
||||
if (FLAG_trace_opt) {
|
||||
PrintF("[optimizing ");
|
||||
function->ShortPrint();
|
||||
PrintF(" because --always-opt]\n");
|
||||
CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
|
||||
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
|
||||
Handle<Code> code;
|
||||
if (dispatcher->IsEnqueued(shared)) {
|
||||
if (!dispatcher->FinishNow(shared)) {
|
||||
if (flag == CLEAR_EXCEPTION) {
|
||||
isolate->clear_pending_exception();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Handle<Code> opt_code;
|
||||
if (GetOptimizedCode(function, ConcurrencyMode::kNotConcurrent)
|
||||
.ToHandle(&opt_code)) {
|
||||
code = opt_code;
|
||||
code = handle(shared->code(), isolate);
|
||||
} else {
|
||||
// Start a compilation.
|
||||
if (!GetLazyCode(function).ToHandle(&code)) {
|
||||
if (flag == CLEAR_EXCEPTION) {
|
||||
isolate->clear_pending_exception();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Install code on closure.
|
||||
function->ReplaceCode(*code);
|
||||
JSFunction::EnsureLiterals(function);
|
||||
|
||||
// Check postconditions on success.
|
||||
DCHECK(!isolate->has_pending_exception());
|
||||
@ -994,6 +1036,32 @@ bool Compiler::CompileOptimized(Handle<JSFunction> function,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Compiler::CompileDebugCode(Handle<SharedFunctionInfo> shared) {
|
||||
Isolate* isolate = shared->GetIsolate();
|
||||
DCHECK(AllowCompilation::IsAllowed(isolate));
|
||||
|
||||
// Start a compilation.
|
||||
ParseInfo parse_info(shared);
|
||||
parse_info.set_is_debug();
|
||||
if (parse_info.is_toplevel()) {
|
||||
if (CompileToplevel(&parse_info, isolate, shared).is_null()) {
|
||||
isolate->clear_pending_exception();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (CompileUnoptimizedFunction(&parse_info, isolate, shared).is_null()) {
|
||||
isolate->clear_pending_exception();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check postconditions on success.
|
||||
DCHECK(!isolate->has_pending_exception());
|
||||
DCHECK(shared->is_compiled());
|
||||
DCHECK(shared->HasBytecodeArray());
|
||||
return true;
|
||||
}
|
||||
|
||||
MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) {
|
||||
Isolate* isolate = script->GetIsolate();
|
||||
DCHECK(AllowCompilation::IsAllowed(isolate));
|
||||
@ -1011,8 +1079,8 @@ MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) {
|
||||
|
||||
// TODO(635): support extensions.
|
||||
Handle<JSArray> infos;
|
||||
Handle<SharedFunctionInfo> shared_info;
|
||||
if (CompileToplevel(&parse_info, isolate).ToHandle(&shared_info)) {
|
||||
if (!CompileToplevel(&parse_info, isolate, Handle<SharedFunctionInfo>::null())
|
||||
.is_null()) {
|
||||
// Check postconditions on success.
|
||||
DCHECK(!isolate->has_pending_exception());
|
||||
infos = LiveEditFunctionTracker::Collect(parse_info.literal(), script,
|
||||
@ -1027,6 +1095,23 @@ MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) {
|
||||
return infos;
|
||||
}
|
||||
|
||||
bool Compiler::EnsureBytecode(ParseInfo* parse_info, Isolate* isolate,
|
||||
Handle<SharedFunctionInfo> shared_info) {
|
||||
if (!shared_info->is_compiled()) {
|
||||
DCHECK(!parse_info->is_toplevel());
|
||||
CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
|
||||
if (dispatcher->IsEnqueued(shared_info)) {
|
||||
if (!dispatcher->FinishNow(shared_info)) return false;
|
||||
} else if (CompileUnoptimizedFunction(parse_info, isolate, shared_info)
|
||||
.is_null()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DCHECK(shared_info->is_compiled());
|
||||
if (shared_info->HasAsmWasmData()) return false;
|
||||
return shared_info->HasBytecodeArray();
|
||||
}
|
||||
|
||||
MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
|
||||
Handle<String> source, Handle<SharedFunctionInfo> outer_info,
|
||||
Handle<Context> context, LanguageMode language_mode,
|
||||
@ -1092,7 +1177,9 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
|
||||
parse_info.set_outer_scope_info(handle(context->scope_info()));
|
||||
}
|
||||
|
||||
if (!CompileToplevel(&parse_info, isolate).ToHandle(&shared_info)) {
|
||||
shared_info = CompileToplevel(&parse_info, isolate,
|
||||
Handle<SharedFunctionInfo>::null());
|
||||
if (shared_info.is_null()) {
|
||||
return MaybeHandle<JSFunction>();
|
||||
}
|
||||
}
|
||||
@ -1310,7 +1397,8 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
|
||||
|
||||
parse_info.set_language_mode(
|
||||
static_cast<LanguageMode>(parse_info.language_mode() | language_mode));
|
||||
CompileToplevel(&parse_info, isolate).ToHandle(&result);
|
||||
result = CompileToplevel(&parse_info, isolate,
|
||||
Handle<SharedFunctionInfo>::null());
|
||||
if (extension == NULL && !result.is_null()) {
|
||||
// We need a feedback vector.
|
||||
DCHECK(result->is_compiled());
|
||||
@ -1358,10 +1446,12 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForStreamedScript(
|
||||
parse_info->set_language_mode(
|
||||
static_cast<LanguageMode>(parse_info->language_mode() | language_mode));
|
||||
|
||||
Handle<SharedFunctionInfo> result;
|
||||
if (CompileToplevel(parse_info, isolate).ToHandle(&result)) {
|
||||
isolate->debug()->OnAfterCompile(script);
|
||||
}
|
||||
// The source was parsed lazily, so compiling for debugging is not possible.
|
||||
DCHECK(!parse_info->is_debug());
|
||||
|
||||
Handle<SharedFunctionInfo> result =
|
||||
CompileToplevel(parse_info, isolate, Handle<SharedFunctionInfo>::null());
|
||||
if (!result.is_null()) isolate->debug()->OnAfterCompile(script);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -47,10 +47,9 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
|
||||
// whereas successful compilation ensures the {is_compiled} predicate on the
|
||||
// given function holds (except for live-edit, which compiles the world).
|
||||
|
||||
static bool Compile(Handle<SharedFunctionInfo> shared,
|
||||
ClearExceptionFlag flag);
|
||||
static bool Compile(Handle<JSFunction> function, ClearExceptionFlag flag);
|
||||
static bool CompileOptimized(Handle<JSFunction> function, ConcurrencyMode);
|
||||
static bool CompileDebugCode(Handle<SharedFunctionInfo> shared);
|
||||
static MaybeHandle<JSArray> CompileForLiveEdit(Handle<Script> script);
|
||||
|
||||
// Prepare a compilation job for unoptimized code. Requires ParseAndAnalyse.
|
||||
@ -76,6 +75,9 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
|
||||
// is appended with inner function literals which should be eagerly compiled.
|
||||
static bool Analyze(ParseInfo* parse_info,
|
||||
EagerInnerFunctionLiterals* eager_literals = nullptr);
|
||||
// Ensures that bytecode is generated, calls ParseAndAnalyze internally.
|
||||
static bool EnsureBytecode(ParseInfo* parse_info, Isolate* isolate,
|
||||
Handle<SharedFunctionInfo> shared_info);
|
||||
|
||||
// ===========================================================================
|
||||
// The following family of methods instantiates new functions for scripts or
|
||||
|
@ -504,11 +504,14 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
if (!shared_info->is_compiled() &&
|
||||
!Compiler::Compile(shared_info, Compiler::CLEAR_EXCEPTION)) {
|
||||
ParseInfo parse_info(shared_info);
|
||||
if (!Compiler::EnsureBytecode(&parse_info, info_->isolate(), shared_info)) {
|
||||
TRACE("Not inlining %s into %s because bytecode generation failed\n",
|
||||
shared_info->DebugName()->ToCString().get(),
|
||||
info_->shared_info()->DebugName()->ToCString().get());
|
||||
if (info_->isolate()->has_pending_exception()) {
|
||||
info_->isolate()->clear_pending_exception();
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
@ -540,8 +543,9 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
|
||||
flags |= JSTypeHintLowering::kBailoutOnUninitialized;
|
||||
}
|
||||
BytecodeGraphBuilder graph_builder(
|
||||
zone(), shared_info, feedback_vector, BailoutId::None(), jsgraph(),
|
||||
call.frequency(), source_positions_, inlining_id, flags, false);
|
||||
parse_info.zone(), shared_info, feedback_vector, BailoutId::None(),
|
||||
jsgraph(), call.frequency(), source_positions_, inlining_id, flags,
|
||||
false);
|
||||
graph_builder.CreateGraph();
|
||||
|
||||
// Extract the inlinee start/end nodes.
|
||||
|
@ -41,7 +41,6 @@ class JSInliner final : public AdvancedReducer {
|
||||
Reduction ReduceJSCall(Node* node);
|
||||
|
||||
private:
|
||||
Zone* zone() const { return local_zone_; }
|
||||
CommonOperatorBuilder* common() const;
|
||||
JSOperatorBuilder* javascript() const;
|
||||
SimplifiedOperatorBuilder* simplified() const;
|
||||
|
@ -767,6 +767,7 @@ class RuntimeCallTimer final {
|
||||
V(CompileBackgroundIgnition) \
|
||||
V(CompileFunction) \
|
||||
V(CompileGetFromOptimizedCodeMap) \
|
||||
V(CompileUnoptimizedFunction) \
|
||||
V(CompileIgnition) \
|
||||
V(CompileIgnitionFinalization) \
|
||||
V(CompileInnerFunction) \
|
||||
|
@ -1190,7 +1190,7 @@ bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position,
|
||||
// Code that cannot be compiled lazily are internal and not debuggable.
|
||||
DCHECK(candidates[i]->allows_lazy_compilation());
|
||||
if (!candidates[i]->is_compiled()) {
|
||||
if (!Compiler::Compile(candidates[i], Compiler::CLEAR_EXCEPTION)) {
|
||||
if (!Compiler::CompileDebugCode(candidates[i])) {
|
||||
return false;
|
||||
} else {
|
||||
was_compiled = true;
|
||||
@ -1317,7 +1317,7 @@ Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
|
||||
HandleScope scope(isolate_);
|
||||
// Code that cannot be compiled lazily are internal and not debuggable.
|
||||
DCHECK(shared->allows_lazy_compilation());
|
||||
if (!Compiler::Compile(handle(shared), Compiler::CLEAR_EXCEPTION)) break;
|
||||
if (!Compiler::CompileDebugCode(handle(shared))) break;
|
||||
}
|
||||
return isolate_->factory()->undefined_value();
|
||||
}
|
||||
@ -1328,8 +1328,7 @@ bool Debug::EnsureBreakInfo(Handle<SharedFunctionInfo> shared) {
|
||||
// Return if we already have the break info for shared.
|
||||
if (shared->HasBreakInfo()) return true;
|
||||
if (!shared->IsSubjectToDebugging()) return false;
|
||||
if (!shared->is_compiled() &&
|
||||
!Compiler::Compile(shared, Compiler::CLEAR_EXCEPTION)) {
|
||||
if (!shared->is_compiled() && !Compiler::CompileDebugCode(shared)) {
|
||||
return false;
|
||||
}
|
||||
CreateBreakInfo(shared);
|
||||
@ -2161,10 +2160,7 @@ ReturnValueScope::~ReturnValueScope() {
|
||||
bool Debug::PerformSideEffectCheck(Handle<JSFunction> function) {
|
||||
DCHECK(isolate_->needs_side_effect_check());
|
||||
DisallowJavascriptExecution no_js(isolate_);
|
||||
if (!function->is_compiled() &&
|
||||
!Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
|
||||
return false;
|
||||
}
|
||||
if (!Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) return false;
|
||||
Deoptimizer::DeoptimizeFunction(*function);
|
||||
if (!function->shared()->HasNoSideEffect()) {
|
||||
if (FLAG_trace_side_effect_free_debug_evaluate) {
|
||||
|
@ -742,8 +742,7 @@ RUNTIME_FUNCTION(Runtime_DisassembleFunction) {
|
||||
DCHECK_EQ(1, args.length());
|
||||
// Get the function and make sure it is compiled.
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
|
||||
if (!func->is_compiled() &&
|
||||
!Compiler::Compile(func, Compiler::KEEP_EXCEPTION)) {
|
||||
if (!Compiler::Compile(func, Compiler::KEEP_EXCEPTION)) {
|
||||
return isolate->heap()->exception();
|
||||
}
|
||||
OFStream os(stdout);
|
||||
|
@ -146,8 +146,7 @@ Handle<JSFunction> FunctionTester::Compile(Handle<JSFunction> function) {
|
||||
info.MarkAsInliningEnabled();
|
||||
}
|
||||
|
||||
CHECK(function->is_compiled() ||
|
||||
Compiler::Compile(function, Compiler::CLEAR_EXCEPTION));
|
||||
CHECK(Compiler::Compile(function, Compiler::CLEAR_EXCEPTION));
|
||||
CHECK(info.shared_info()->HasBytecodeArray());
|
||||
JSFunction::EnsureLiterals(function);
|
||||
|
||||
|
@ -3845,7 +3845,6 @@ TEST(EnsureAllocationSiteDependentCodesProcessed) {
|
||||
}
|
||||
|
||||
TEST(AllocationSiteCreation) {
|
||||
FLAG_always_opt = false;
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Heap* heap = isolate->heap();
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --no-always-opt --no-stress-opt
|
||||
|
||||
Debug = debug.Debug
|
||||
var exception = null;
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --no-always-opt --no-stress-opt
|
||||
|
||||
Debug = debug.Debug
|
||||
|
||||
|
@ -25,7 +25,6 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --no-always-opt --no-stress-opt
|
||||
|
||||
Debug = debug.Debug
|
||||
|
||||
|
@ -50,20 +50,46 @@ Paused #2
|
||||
- [0] {"functionName":"testFunction","function_lineNumber":0,"function_columnNumber":21,"lineNumber":18,"columnNumber":12}
|
||||
- [1] {"functionName":"","function_lineNumber":0,"function_columnNumber":0,"lineNumber":0,"columnNumber":0}
|
||||
Paused #3
|
||||
- [0] {"functionName":"generateAsmJs","function_lineNumber":1,"function_columnNumber":24,"lineNumber":3,"columnNumber":31}
|
||||
- [1] {"functionName":"testFunction","function_lineNumber":0,"function_columnNumber":21,"lineNumber":18,"columnNumber":12}
|
||||
- [2] {"functionName":"","function_lineNumber":0,"function_columnNumber":0,"lineNumber":0,"columnNumber":0}
|
||||
Paused #4
|
||||
- [0] {"functionName":"generateAsmJs","function_lineNumber":1,"function_columnNumber":24,"lineNumber":10,"columnNumber":4}
|
||||
- [1] {"functionName":"testFunction","function_lineNumber":0,"function_columnNumber":21,"lineNumber":18,"columnNumber":12}
|
||||
- [2] {"functionName":"","function_lineNumber":0,"function_columnNumber":0,"lineNumber":0,"columnNumber":0}
|
||||
Paused #5
|
||||
- [0] {"functionName":"testFunction","function_lineNumber":0,"function_columnNumber":21,"lineNumber":19,"columnNumber":2}
|
||||
- [1] {"functionName":"","function_lineNumber":0,"function_columnNumber":0,"lineNumber":0,"columnNumber":0}
|
||||
Paused #4
|
||||
Paused #6
|
||||
- [0] {"functionName":"redirectFun","function_lineNumber":7,"function_columnNumber":24,"lineNumber":8,"columnNumber":6}
|
||||
- [1] {"functionName":"testFunction","function_lineNumber":0,"function_columnNumber":21,"lineNumber":19,"columnNumber":2}
|
||||
- [2] {"functionName":"","function_lineNumber":0,"function_columnNumber":0,"lineNumber":0,"columnNumber":0}
|
||||
Paused #7
|
||||
- [0] {"functionName":"callDebugger","function_lineNumber":4,"function_columnNumber":25,"lineNumber":5,"columnNumber":6}
|
||||
- [1] {"functionName":"redirectFun","function_lineNumber":7,"function_columnNumber":24,"lineNumber":8,"columnNumber":6}
|
||||
- [2] {"functionName":"testFunction","function_lineNumber":0,"function_columnNumber":21,"lineNumber":19,"columnNumber":2}
|
||||
- [3] {"functionName":"","function_lineNumber":0,"function_columnNumber":0,"lineNumber":0,"columnNumber":0}
|
||||
Paused #8
|
||||
- [0] {"functionName":"call_debugger","function_lineNumber":13,"function_columnNumber":24,"lineNumber":14,"columnNumber":4}
|
||||
- [1] {"functionName":"callDebugger","lineNumber":5,"columnNumber":6}
|
||||
- [2] {"functionName":"redirectFun","lineNumber":8,"columnNumber":6}
|
||||
- [1] {"functionName":"callDebugger","function_lineNumber":4,"function_columnNumber":25,"lineNumber":5,"columnNumber":6}
|
||||
- [2] {"functionName":"redirectFun","function_lineNumber":7,"function_columnNumber":24,"lineNumber":8,"columnNumber":6}
|
||||
- [3] {"functionName":"testFunction","function_lineNumber":0,"function_columnNumber":21,"lineNumber":19,"columnNumber":2}
|
||||
- [4] {"functionName":"","function_lineNumber":0,"function_columnNumber":0,"lineNumber":0,"columnNumber":0}
|
||||
Paused #5
|
||||
Paused #9
|
||||
- [0] {"functionName":"call_debugger","function_lineNumber":13,"function_columnNumber":24,"lineNumber":15,"columnNumber":2}
|
||||
- [1] {"functionName":"callDebugger","lineNumber":5,"columnNumber":6}
|
||||
- [2] {"functionName":"redirectFun","lineNumber":8,"columnNumber":6}
|
||||
- [1] {"functionName":"callDebugger","function_lineNumber":4,"function_columnNumber":25,"lineNumber":5,"columnNumber":6}
|
||||
- [2] {"functionName":"redirectFun","function_lineNumber":7,"function_columnNumber":24,"lineNumber":8,"columnNumber":6}
|
||||
- [3] {"functionName":"testFunction","function_lineNumber":0,"function_columnNumber":21,"lineNumber":19,"columnNumber":2}
|
||||
- [4] {"functionName":"","function_lineNumber":0,"function_columnNumber":0,"lineNumber":0,"columnNumber":0}
|
||||
Paused #10
|
||||
- [0] {"functionName":"callDebugger","function_lineNumber":4,"function_columnNumber":25,"lineNumber":6,"columnNumber":4}
|
||||
- [1] {"functionName":"redirectFun","function_lineNumber":7,"function_columnNumber":24,"lineNumber":8,"columnNumber":6}
|
||||
- [2] {"functionName":"testFunction","function_lineNumber":0,"function_columnNumber":21,"lineNumber":19,"columnNumber":2}
|
||||
- [3] {"functionName":"","function_lineNumber":0,"function_columnNumber":0,"lineNumber":0,"columnNumber":0}
|
||||
Paused #11
|
||||
- [0] {"functionName":"redirectFun","function_lineNumber":7,"function_columnNumber":24,"lineNumber":9,"columnNumber":4}
|
||||
- [1] {"functionName":"testFunction","function_lineNumber":0,"function_columnNumber":21,"lineNumber":19,"columnNumber":2}
|
||||
- [2] {"functionName":"","function_lineNumber":0,"function_columnNumber":0,"lineNumber":0,"columnNumber":0}
|
||||
|
||||
Running test: finished
|
||||
Finished TestSuite.
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --no-always-opt --no-stress-opt
|
||||
|
||||
// Generate a function with a very large closure.
|
||||
source = "(function() {\n"
|
||||
for (var i = 0; i < 65000; i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user