Skip to content

Commit f03ddc4

Browse files
sjindel-googlecommit-bot@chromium.org
authored andcommitted
[vm/ffi] Don't make force-optimized code masquerade as unoptimized code.
Instead, we set a bit on force-optimized code so that deoptimization knows to skip it and exception handling will execute catch-entry moves. In addition we don't throw away deoptimization info for these codes, so that exception handling works. Bug: dartbug.com/37311 Change-Id: If5bcff41a98c0053c581648a9ee22b3302ceea04 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106740 Commit-Queue: Samir Jindel <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent 31599c1 commit f03ddc4

11 files changed

Lines changed: 81 additions & 13 deletions

File tree

runtime/vm/compiler/backend/flow_graph_checker.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,23 @@ void FlowGraphChecker::VisitConstant(ConstantInstr* constant) {
351351
// ASSERT(constant->GetBlock() == flow_graph_->graph_entry());
352352
}
353353

354+
void FlowGraphChecker::VisitInstanceCall(InstanceCallInstr* instr) {
355+
const Function& function = flow_graph_->function();
356+
357+
// Force-optimized functions may not have instance calls inside them because
358+
// we do not reset ICData for these.
359+
ASSERT(!function.ForceOptimize());
360+
}
361+
362+
void FlowGraphChecker::VisitPolymorphicInstanceCall(
363+
PolymorphicInstanceCallInstr* instr) {
364+
const Function& function = flow_graph_->function();
365+
366+
// Force-optimized functions may not have instance calls inside them because
367+
// we do not reset ICData for these.
368+
ASSERT(!function.ForceOptimize());
369+
}
370+
354371
void FlowGraphChecker::VisitPhi(PhiInstr* phi) {
355372
// Make sure the definition of each input value of a Phi dominates
356373
// the corresponding incoming edge, as defined by order.

runtime/vm/compiler/backend/flow_graph_checker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ class FlowGraphChecker : public FlowGraphVisitor {
5656
void VisitIndirectGoto(IndirectGotoInstr* jmp) override;
5757
void VisitBranch(BranchInstr* branch) override;
5858
void VisitRedefinition(RedefinitionInstr* def) override;
59+
void VisitInstanceCall(InstanceCallInstr* instr) override;
60+
void VisitPolymorphicInstanceCall(
61+
PolymorphicInstanceCallInstr* instr) override;
5962

6063
FlowGraph* const flow_graph_;
6164
BlockEntryInstr* current_block_;

runtime/vm/compiler/jit/compiler.cc

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -378,9 +378,7 @@ RawCode* CompileParsedFunctionHelper::FinalizeCompilation(
378378
// CreateDeoptInfo uses the object pool and needs to be done before
379379
// FinalizeCode.
380380
Array& deopt_info_array = Array::Handle(zone, Object::empty_array().raw());
381-
if (!function.ForceOptimize()) {
382-
deopt_info_array = graph_compiler->CreateDeoptInfo(assembler);
383-
}
381+
deopt_info_array = graph_compiler->CreateDeoptInfo(assembler);
384382

385383
// Allocates instruction object. Since this occurs only at safepoint,
386384
// there can be no concurrent access to the instruction page.
@@ -408,9 +406,8 @@ RawCode* CompileParsedFunctionHelper::FinalizeCompilation(
408406

409407
if (function.ForceOptimize()) {
410408
ASSERT(optimized() && thread()->IsMutatorThread());
411-
code.set_is_optimized(false);
409+
code.set_is_force_optimized(true);
412410
function.AttachCode(code);
413-
function.set_unoptimized_code(code);
414411
function.SetWasCompiled(true);
415412
} else if (optimized()) {
416413
// Installs code while at safepoint.
@@ -947,6 +944,7 @@ RawObject* Compiler::CompileFunction(Thread* thread, const Function& function) {
947944

948945
RawError* Compiler::EnsureUnoptimizedCode(Thread* thread,
949946
const Function& function) {
947+
ASSERT(!function.ForceOptimize());
950948
if (function.unoptimized_code() != Object::null()) {
951949
return Error::null();
952950
}

runtime/vm/debugger.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ ActivationFrame::ActivationFrame(const Closure& async_activation)
304304
}
305305
#endif
306306
if (bytecode_.IsNull()) {
307+
// Force-optimize functions should not be debuggable.
308+
ASSERT(!function_.ForceOptimize());
307309
function_.EnsureHasCompiledUnoptimizedCode();
308310
code_ = function_.unoptimized_code();
309311
}

runtime/vm/deopt_instructions.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,7 @@ void DeoptInfoBuilder::AddCopy(Value* value,
11651165
deopt_instr =
11661166
new (zone()) DeoptUint32Instr(ToCpuRegisterSource(source_loc));
11671167
break;
1168+
case kUnboxedFloat:
11681169
case kUnboxedDouble:
11691170
deopt_instr = new (zone()) DeoptDoubleInstr(
11701171
ToFpuRegisterSource(source_loc, Location::kDoubleStackSlot));

runtime/vm/isolate_reload.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,11 @@ void IsolateReloadContext::EnsuredUnoptimizedCodeForStack() {
922922
if (frame->IsDartFrame() && !frame->is_interpreted()) {
923923
func = frame->LookupDartFunction();
924924
ASSERT(!func.IsNull());
925-
func.EnsureHasCompiledUnoptimizedCode();
925+
// Force-optimized functions don't need unoptimized code because their
926+
// optimized code cannot deopt.
927+
if (!func.ForceOptimize()) {
928+
func.EnsureHasCompiledUnoptimizedCode();
929+
}
926930
}
927931
}
928932
}
@@ -1889,7 +1893,7 @@ void IsolateReloadContext::ResetUnoptimizedICsOnStack() {
18891893
bytecode.ResetICDatas(zone);
18901894
} else {
18911895
code = frame->LookupDartCode();
1892-
if (code.is_optimized()) {
1896+
if (code.is_optimized() && !code.is_force_optimized()) {
18931897
// If this code is optimized, we need to reset the ICs in the
18941898
// corresponding unoptimized code, which will be executed when the stack
18951899
// unwinds to the optimized code.

runtime/vm/object.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5747,6 +5747,7 @@ void Function::ClearCode() const {
57475747
}
57485748

57495749
void Function::EnsureHasCompiledUnoptimizedCode() const {
5750+
ASSERT(!ForceOptimize());
57505751
Thread* thread = Thread::Current();
57515752
ASSERT(thread->IsMutatorThread());
57525753
DEBUG_ASSERT(thread->TopErrorHandlerIsExitFrame());
@@ -8095,7 +8096,7 @@ RawCode* Function::EnsureHasCode() const {
80958096
}
80968097
// Compiling in unoptimized mode should never fail if there are no errors.
80978098
ASSERT(HasCode());
8098-
ASSERT(unoptimized_code() == result.raw());
8099+
ASSERT(ForceOptimize() || unoptimized_code() == result.raw());
80998100
return CurrentCode();
81008101
}
81018102

@@ -14480,6 +14481,10 @@ void Code::set_is_optimized(bool value) const {
1448014481
set_state_bits(OptimizedBit::update(value, raw_ptr()->state_bits_));
1448114482
}
1448214483

14484+
void Code::set_is_force_optimized(bool value) const {
14485+
set_state_bits(ForceOptimizedBit::update(value, raw_ptr()->state_bits_));
14486+
}
14487+
1448314488
void Code::set_is_alive(bool value) const {
1448414489
set_state_bits(AliveBit::update(value, raw_ptr()->state_bits_));
1448514490
}
@@ -14753,6 +14758,7 @@ RawCode* Code::New(intptr_t pointer_offsets_length) {
1475314758
result ^= raw;
1475414759
result.set_pointer_offsets_length(pointer_offsets_length);
1475514760
result.set_is_optimized(false);
14761+
result.set_is_force_optimized(false);
1475614762
result.set_is_alive(false);
1475714763
NOT_IN_PRODUCT(result.set_comments(Comments::New(0)));
1475814764
NOT_IN_PRODUCT(result.set_compile_timestamp(0));

runtime/vm/object.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5200,6 +5200,14 @@ class Code : public Object {
52005200
return Code::OptimizedBit::decode(code->ptr()->state_bits_);
52015201
}
52025202

5203+
bool is_force_optimized() const {
5204+
return ForceOptimizedBit::decode(raw_ptr()->state_bits_);
5205+
}
5206+
void set_is_force_optimized(bool value) const;
5207+
static bool IsForceOptimized(RawCode* code) {
5208+
return Code::ForceOptimizedBit::decode(code->ptr()->state_bits_);
5209+
}
5210+
52035211
bool is_alive() const { return AliveBit::decode(raw_ptr()->state_bits_); }
52045212
void set_is_alive(bool value) const;
52055213

@@ -5553,12 +5561,19 @@ class Code : public Object {
55535561
friend class RawCode;
55545562
enum {
55555563
kOptimizedBit = 0,
5556-
kAliveBit = 1,
5557-
kPtrOffBit = 2,
5558-
kPtrOffSize = 30,
5564+
kForceOptimizedBit = 1,
5565+
kAliveBit = 2,
5566+
kPtrOffBit = 3,
5567+
kPtrOffSize = 29,
55595568
};
55605569

55615570
class OptimizedBit : public BitField<int32_t, bool, kOptimizedBit, 1> {};
5571+
5572+
// Force-optimized is true if the Code was generated for a function with
5573+
// Function::ForceOptimize().
5574+
class ForceOptimizedBit
5575+
: public BitField<int32_t, bool, kForceOptimizedBit, 1> {};
5576+
55625577
class AliveBit : public BitField<int32_t, bool, kAliveBit, 1> {};
55635578
class PtrOffBits
55645579
: public BitField<int32_t, intptr_t, kPtrOffBit, kPtrOffSize> {};

runtime/vm/runtime_entry.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,7 +2132,7 @@ static void HandleStackOverflowTestCases(Thread* thread) {
21322132
for (intptr_t i = 0; i < num_frames; i++) {
21332133
ActivationFrame* frame = stack->FrameAt(i);
21342134
#ifndef DART_PRECOMPILED_RUNTIME
2135-
if (!frame->IsInterpreted()) {
2135+
if (!frame->IsInterpreted() && !frame->function().ForceOptimize()) {
21362136
// Ensure that we have unoptimized code.
21372137
frame->function().EnsureHasCompiledUnoptimizedCode();
21382138
}
@@ -2510,6 +2510,11 @@ const char* DeoptReasonToCString(ICData::DeoptReasonId deopt_reason) {
25102510

25112511
void DeoptimizeAt(const Code& optimized_code, StackFrame* frame) {
25122512
ASSERT(optimized_code.is_optimized());
2513+
2514+
// Force-optimized code is optimized code which cannot deoptimize and doesn't
2515+
// have unoptimized code to fall back to.
2516+
ASSERT(!optimized_code.is_force_optimized());
2517+
25132518
Thread* thread = Thread::Current();
25142519
Zone* zone = thread->zone();
25152520
const Function& function = Function::Handle(zone, optimized_code.function());
@@ -2590,7 +2595,8 @@ void DeoptimizeFunctionsOnStack() {
25902595
while (frame != NULL) {
25912596
if (!frame->is_interpreted()) {
25922597
optimized_code = frame->LookupDartCode();
2593-
if (optimized_code.is_optimized()) {
2598+
if (optimized_code.is_optimized() &&
2599+
!optimized_code.is_force_optimized()) {
25942600
DeoptimizeAt(optimized_code, frame);
25952601
}
25962602
}

runtime/vm/source_report.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ bool SourceReport::ShouldSkipFunction(const Function& func) {
8888
}
8989
}
9090

91+
// These don't have unoptimized code and are only used for synthetic stubs.
92+
if (func.ForceOptimize()) return true;
93+
9194
switch (func.kind()) {
9295
case RawFunction::kRegularFunction:
9396
case RawFunction::kClosureFunction:

0 commit comments

Comments
 (0)