diff --git a/runtime/lib/errors.cc b/runtime/lib/errors.cc index cce88cf68fd..049e919acce 100644 --- a/runtime/lib/errors.cc +++ b/runtime/lib/errors.cc @@ -67,9 +67,9 @@ static ScriptPtr FindScript(DartFrameIterator* iterator) { DEFINE_NATIVE_ENTRY(AssertionError_throwNew, 0, 3) { // No need to type check the arguments. This function can only be called // internally from the VM. - const TokenPosition assertion_start = TokenPosition( + const TokenPosition assertion_start = TokenPosition::Deserialize( Smi::CheckedHandle(zone, arguments->NativeArgAt(0)).Value()); - const TokenPosition assertion_end = TokenPosition( + const TokenPosition assertion_end = TokenPosition::Deserialize( Smi::CheckedHandle(zone, arguments->NativeArgAt(1)).Value()); const Instance& message = @@ -151,7 +151,7 @@ DEFINE_NATIVE_ENTRY(AssertionError_throwNewSource, 0, 4) { DEFINE_NATIVE_ENTRY(TypeError_throwNew, 0, 4) { // No need to type check the arguments. This function can only be called // internally from the VM. - const TokenPosition location = TokenPosition( + const TokenPosition location = TokenPosition::Deserialize( Smi::CheckedHandle(zone, arguments->NativeArgAt(0)).Value()); const Instance& src_value = Instance::CheckedHandle(zone, arguments->NativeArgAt(1)); @@ -171,7 +171,7 @@ DEFINE_NATIVE_ENTRY(TypeError_throwNew, 0, 4) { // Return value: none, throws an exception. DEFINE_NATIVE_ENTRY(FallThroughError_throwNew, 0, 1) { GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_pos, arguments->NativeArgAt(0)); - TokenPosition fallthrough_pos = TokenPosition(smi_pos.Value()); + TokenPosition fallthrough_pos = TokenPosition::Deserialize(smi_pos.Value()); const Array& args = Array::Handle(Array::New(2)); @@ -197,7 +197,7 @@ DEFINE_NATIVE_ENTRY(FallThroughError_throwNew, 0, 1) { DEFINE_NATIVE_ENTRY(AbstractClassInstantiationError_throwNew, 0, 2) { GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_pos, arguments->NativeArgAt(0)); GET_NON_NULL_NATIVE_ARGUMENT(String, class_name, arguments->NativeArgAt(1)); - TokenPosition error_pos = TokenPosition(smi_pos.Value()); + TokenPosition error_pos = TokenPosition::Deserialize(smi_pos.Value()); const Array& args = Array::Handle(Array::New(3)); diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc index cf1e6ff0cd2..4e92dc7ee2c 100644 --- a/runtime/lib/object.cc +++ b/runtime/lib/object.cc @@ -447,7 +447,7 @@ DEFINE_NATIVE_ENTRY(Internal_boundsCheckForPartialInstantiation, 0, 2) { if (!AbstractType::InstantiateAndTestSubtype( &subtype, &supertype, instantiator_type_args, function_type_args)) { // Throw a dynamic type error. - TokenPosition location; + TokenPosition location = TokenPosition::kNoSource; { DartFrameIterator iterator(Thread::Current(), StackFrameIterator::kNoCrossThreadIteration); diff --git a/runtime/observatory/tests/service/async_generator_breakpoint_test.dart b/runtime/observatory/tests/service/async_generator_breakpoint_test.dart index 44f5c2aeb85..b607ea86ee9 100644 --- a/runtime/observatory/tests/service/async_generator_breakpoint_test.dart +++ b/runtime/observatory/tests/service/async_generator_breakpoint_test.dart @@ -53,15 +53,19 @@ Future testAsync(Isolate isolate) async { var script = isolate.rootLibrary.scripts[0]; var bp1 = await isolate.addBreakpoint(script, 13); + print("BP1 - $bp1"); expect(bp1, isNotNull); expect(bp1 is Breakpoint, isTrue); var bp2 = await isolate.addBreakpoint(script, 18); + print("BP2 - $bp2"); expect(bp2, isNotNull); expect(bp2 is Breakpoint, isTrue); var bp3 = await isolate.addBreakpoint(script, 23); + print("BP3 - $bp3"); expect(bp3, isNotNull); expect(bp3 is Breakpoint, isTrue); var bp4 = await isolate.addBreakpoint(script, 27); + print("BP4 - $bp4"); expect(bp4, isNotNull); expect(bp4 is Breakpoint, isTrue); var bp5 = await isolate.addBreakpoint(script, 44); diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status index bc2bb426ff7..5896d37aa6f 100644 --- a/runtime/observatory/tests/service/service.status +++ b/runtime/observatory/tests/service/service.status @@ -23,6 +23,10 @@ process_service_test: Pass, Fail # Issue 24344 developer_extension_test: SkipByDesign get_isolate_after_language_error_test: SkipByDesign +# The _1 versions of this test can be slow due to stress testing flags. +[ $mode == debug ] +async_generator_breakpoint_test: Pass, Slow + # Service protocol is not supported in product mode. [ $mode == product ] *: SkipByDesign diff --git a/runtime/observatory_2/tests/service_2/async_generator_breakpoint_test.dart b/runtime/observatory_2/tests/service_2/async_generator_breakpoint_test.dart index 1abcb9fc65c..4f916736097 100644 --- a/runtime/observatory_2/tests/service_2/async_generator_breakpoint_test.dart +++ b/runtime/observatory_2/tests/service_2/async_generator_breakpoint_test.dart @@ -53,15 +53,19 @@ Future testAsync(Isolate isolate) async { var script = isolate.rootLibrary.scripts[0]; var bp1 = await isolate.addBreakpoint(script, 13); + print("BP1 - $bp1"); expect(bp1, isNotNull); expect(bp1 is Breakpoint, isTrue); var bp2 = await isolate.addBreakpoint(script, 18); + print("BP2 - $bp2"); expect(bp2, isNotNull); expect(bp2 is Breakpoint, isTrue); var bp3 = await isolate.addBreakpoint(script, 23); + print("BP3 - $bp3"); expect(bp3, isNotNull); expect(bp3 is Breakpoint, isTrue); var bp4 = await isolate.addBreakpoint(script, 27); + print("BP4 - $bp4"); expect(bp4, isNotNull); expect(bp4 is Breakpoint, isTrue); var bp5 = await isolate.addBreakpoint(script, 44); diff --git a/runtime/observatory_2/tests/service_2/service_2.status b/runtime/observatory_2/tests/service_2/service_2.status index c16feabdcea..874b3f47486 100644 --- a/runtime/observatory_2/tests/service_2/service_2.status +++ b/runtime/observatory_2/tests/service_2/service_2.status @@ -25,6 +25,10 @@ dominator_tree_vm_with_double_field_test: SkipByDesign developer_extension_test: SkipByDesign get_isolate_after_language_error_test: SkipByDesign +# The _1 versions of this test can be slow due to stress testing flags. +[ $mode == debug ] +async_generator_breakpoint_test: Pass, Slow + # Service protocol is not supported in product mode. [ $mode == product ] *: SkipByDesign diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h index 031ab05a982..2b2ab859471 100644 --- a/runtime/vm/clustered_snapshot.h +++ b/runtime/vm/clustered_snapshot.h @@ -340,9 +340,7 @@ class Serializer : public ThreadStackResource { } } - void WriteTokenPosition(TokenPosition pos) { - Write(pos.SnapshotEncode()); - } + void WriteTokenPosition(TokenPosition pos) { Write(pos.Serialize()); } void WriteCid(intptr_t cid) { COMPILE_ASSERT(ObjectLayout::kClassIdTagSize <= 32); @@ -616,7 +614,7 @@ class Deserializer : public ThreadStackResource { } TokenPosition ReadTokenPosition() { - return TokenPosition::SnapshotDecode(Read()); + return TokenPosition::Deserialize(Read()); } intptr_t ReadCid() { diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc index edce815b09c..e75d7028c88 100644 --- a/runtime/vm/code_descriptors.cc +++ b/runtime/vm/code_descriptors.cc @@ -40,10 +40,11 @@ void DescriptorList::AddDescriptor(PcDescriptorsLayout::Kind kind, prev_pc_offset = pc_offset; if (!FLAG_precompiled_mode) { + const int32_t encoded_pos = token_pos.Serialize(); encoded_data_.WriteSLEB128(deopt_id - prev_deopt_id); - encoded_data_.WriteSLEB128(token_pos.value() - prev_token_pos); + encoded_data_.WriteSLEB128(encoded_pos - prev_token_pos); prev_deopt_id = deopt_id; - prev_token_pos = token_pos.value(); + prev_token_pos = encoded_pos; } } } @@ -197,8 +198,8 @@ TypedDataPtr CatchEntryMovesMapBuilder::FinalizeCatchEntryMovesMap() { } #endif // !defined(DART_PRECOMPILED_RUNTIME) -const TokenPosition CodeSourceMapBuilder::kInitialPosition = - TokenPosition(TokenPosition::kDartCodeProloguePos); +const TokenPosition& CodeSourceMapBuilder::kInitialPosition = + TokenPosition::kDartCodePrologue; CodeSourceMapBuilder::CodeSourceMapBuilder( Zone* zone, @@ -311,7 +312,7 @@ void CodeSourceMapBuilder::StartInliningInterval(int32_t pc_offset, } for (intptr_t i = to_push.length() - 1; i >= 0; i--) { intptr_t callee_id = to_push[i]; - TokenPosition call_token; + TokenPosition call_token = TokenPosition::kNoSource; if (callee_id != 0) { // TODO(rmacnak): Should make this array line up with the others. call_token = inline_id_to_token_pos_[callee_id - 1]; @@ -396,20 +397,19 @@ CodeSourceMapPtr CodeSourceMapBuilder::Finalize() { void CodeSourceMapBuilder::WriteChangePosition(TokenPosition pos) { stream_.Write(kChangePosition); - intptr_t position_or_line = pos.value(); + intptr_t position_or_line = pos.Serialize(); #if defined(DART_PRECOMPILER) - intptr_t column = TokenPosition::kNoSourcePos; + intptr_t column = TokenPosition::kNoSource.Serialize(); if (FLAG_precompiled_mode) { // Don't use the raw position value directly in precompiled mode. Instead, // use the value of kNoSource as a fallback when no line or column // information is found. - position_or_line = TokenPosition::kNoSourcePos; + position_or_line = TokenPosition::kNoSource.Serialize(); intptr_t inline_id = buffered_inline_id_stack_.Last(); if (inline_id < inline_id_to_function_.length()) { const Function* function = inline_id_to_function_[inline_id]; Script& script = Script::Handle(function->script()); - script.GetTokenLocationUsingLineStarts(pos.SourcePosition(), - &position_or_line, &column); + script.GetTokenLocation(pos, &position_or_line, &column); } } #endif @@ -619,8 +619,8 @@ void CodeSourceMapReader::DumpSourcePositions(uword start) { THR_Print("%" Px "-%" Px ": ", start + current_pc_offset, start + current_pc_offset + delta - 1); for (intptr_t i = 0; i < function_stack.length(); i++) { - THR_Print("%s@%" Pd " ", function_stack[i]->ToCString(), - token_positions[i].value()); + THR_Print("%s@%s", function_stack[i]->ToCString(), + token_positions[i].ToCString()); } THR_Print("\n"); current_pc_offset += delta; @@ -698,7 +698,8 @@ intptr_t CodeSourceMapReader::GetNullCheckNameIndexAt(int32_t pc_offset) { } TokenPosition CodeSourceMapReader::ReadPosition(ReadStream* stream) { - const intptr_t line = stream->Read(); + const TokenPosition line = + TokenPosition::Deserialize(stream->Read()); #if defined(DART_PRECOMPILER) // The special handling for non-symbolic stack trace mode only needs to // happen in the precompiler, because those CSMs are not serialized in @@ -707,7 +708,7 @@ TokenPosition CodeSourceMapReader::ReadPosition(ReadStream* stream) { stream->Read(); // Discard the column information. } #endif - return TokenPosition(line); + return line; } } // namespace dart diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h index f42190bb4f7..bb2f7736b71 100644 --- a/runtime/vm/code_descriptors.h +++ b/runtime/vm/code_descriptors.h @@ -42,7 +42,7 @@ class DescriptorList : public ZoneAllocated { intptr_t prev_pc_offset; intptr_t prev_deopt_id; - intptr_t prev_token_pos; + int32_t prev_token_pos; DISALLOW_COPY_AND_ASSIGN(DescriptorList); }; @@ -186,7 +186,7 @@ class CodeSourceMapBuilder : public ZoneAllocated { // The position at which a function implicitly starts, for both the root and // after a push bytecode. We use the classifying position kDartCodePrologue // since it is the most common. - static const TokenPosition kInitialPosition; + static const TokenPosition& kInitialPosition; static const uint8_t kChangePosition = 0; static const uint8_t kAdvancePC = 1; diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc index d8e2c410f82..1f5cb520527 100644 --- a/runtime/vm/code_descriptors_test.cc +++ b/runtime/vm/code_descriptors_test.cc @@ -123,7 +123,7 @@ TEST_CASE(StackMapGC) { ISOLATE_UNIT_TEST_CASE(DescriptorList_TokenPositions) { DescriptorList* descriptors = new DescriptorList(thread->zone()); ASSERT(descriptors != NULL); - const intptr_t token_positions[] = { + const int32_t token_positions[] = { kMinInt32, 5, 13, @@ -141,12 +141,12 @@ ISOLATE_UNIT_TEST_CASE(DescriptorList_TokenPositions) { TokenPosition::kMinSourcePos, TokenPosition::kMaxSourcePos, }; - const intptr_t num_token_positions = - sizeof(token_positions) / sizeof(token_positions[0]); + const intptr_t num_token_positions = ARRAY_SIZE(token_positions); for (intptr_t i = 0; i < num_token_positions; i++) { - descriptors->AddDescriptor(PcDescriptorsLayout::kRuntimeCall, 0, 0, - TokenPosition(token_positions[i]), 0, 1); + const TokenPosition& tp = TokenPosition::Deserialize(token_positions[i]); + descriptors->AddDescriptor(PcDescriptorsLayout::kRuntimeCall, 0, 0, tp, 0, + 1); } const PcDescriptors& finalized_descriptors = @@ -158,11 +158,12 @@ ISOLATE_UNIT_TEST_CASE(DescriptorList_TokenPositions) { intptr_t i = 0; while (it.MoveNext()) { - if (token_positions[i] != it.TokenPos().value()) { - OS::PrintErr("[%" Pd "]: Expected: %" Pd " != %" Pd "\n", i, - token_positions[i], it.TokenPos().value()); + const TokenPosition& tp = TokenPosition::Deserialize(token_positions[i]); + if (tp != it.TokenPos()) { + OS::PrintErr("[%" Pd "]: Expected: %s != %s\n", i, tp.ToCString(), + it.TokenPos().ToCString()); } - EXPECT(token_positions[i] == it.TokenPos().value()); + EXPECT(tp == it.TokenPos()); i++; } } diff --git a/runtime/vm/compilation_trace.cc b/runtime/vm/compilation_trace.cc index d2f88ed1fec..8b1a53baca1 100644 --- a/runtime/vm/compilation_trace.cc +++ b/runtime/vm/compilation_trace.cc @@ -516,7 +516,7 @@ void TypeFeedbackSaver::VisitFunction(const Function& function) { WriteString(str_); WriteInt(function.kind()); - WriteInt(function.token_pos().value()); + WriteInt(function.token_pos().Serialize()); code_ = function.CurrentCode(); intptr_t usage = function.usage_counter(); @@ -814,7 +814,7 @@ ObjectPtr TypeFeedbackLoader::LoadFunction() { func_name_ = ReadString(); // Without private mangling. FunctionLayout::Kind kind = static_cast(ReadInt()); - intptr_t token_pos = ReadInt(); + const TokenPosition& token_pos = TokenPosition::Deserialize(ReadInt()); intptr_t usage = ReadInt(); intptr_t inlining_depth = ReadInt(); intptr_t num_call_sites = ReadInt(); @@ -926,7 +926,7 @@ ObjectPtr TypeFeedbackLoader::LoadFunction() { } FunctionPtr TypeFeedbackLoader::FindFunction(FunctionLayout::Kind kind, - intptr_t token_pos) { + const TokenPosition& token_pos) { if (cls_name_.Equals(Symbols::TopLevel())) { func_ = lib_.LookupFunctionAllowPrivate(func_name_); } else { @@ -969,8 +969,7 @@ FunctionPtr TypeFeedbackLoader::FindFunction(FunctionLayout::Kind kind, bool found = false; for (intptr_t i = 0; i < closure_functions.Length(); i++) { func_ ^= closure_functions.At(i); - if ((func_.Owner() == cls_.raw()) && - (func_.token_pos().value() == token_pos)) { + if (func_.Owner() == cls_.raw() && func_.token_pos() == token_pos) { found = true; break; } diff --git a/runtime/vm/compilation_trace.h b/runtime/vm/compilation_trace.h index 80d671eeb70..459ca273cd7 100644 --- a/runtime/vm/compilation_trace.h +++ b/runtime/vm/compilation_trace.h @@ -102,7 +102,8 @@ class TypeFeedbackLoader : public ValueObject { ObjectPtr LoadClasses(); ObjectPtr LoadFields(); ObjectPtr LoadFunction(); - FunctionPtr FindFunction(FunctionLayout::Kind kind, intptr_t token_pos); + FunctionPtr FindFunction(FunctionLayout::Kind kind, + const TokenPosition& token_pos); ClassPtr ReadClassByName(); StringPtr ReadString(); diff --git a/runtime/vm/compiler/aot/precompiler.h b/runtime/vm/compiler/aot/precompiler.h index 41a7902aa4e..a1da918f8a3 100644 --- a/runtime/vm/compiler/aot/precompiler.h +++ b/runtime/vm/compiler/aot/precompiler.h @@ -94,7 +94,7 @@ class FieldKeyValueTrait { static inline intptr_t Hashcode(Key key) { const TokenPosition token_pos = key->token_pos(); if (token_pos.IsReal()) { - return token_pos.value(); + return token_pos.Hash(); } return key->kernel_offset(); } @@ -117,7 +117,7 @@ class ClassKeyValueTrait { static Value ValueOf(Pair kv) { return kv; } - static inline intptr_t Hashcode(Key key) { return key->token_pos().value(); } + static inline intptr_t Hashcode(Key key) { return key->token_pos().Hash(); } static inline bool IsKeyEqual(Pair pair, Key key) { return pair->raw() == key->raw(); diff --git a/runtime/vm/compiler/assembler/disassembler.cc b/runtime/vm/compiler/assembler/disassembler.cc index e7e73a5ae97..8df2bfcee0d 100644 --- a/runtime/vm/compiler/assembler/disassembler.cc +++ b/runtime/vm/compiler/assembler/disassembler.cc @@ -339,7 +339,8 @@ void Disassembler::DisassembleCodeHelper(const char* function_fullname, THR_Print("%s}\n", handlers.ToCString()); #if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER) - if (code.catch_entry_moves_maps() != Object::null()) { + if (FLAG_precompiled_mode && + code.catch_entry_moves_maps() != Object::null()) { THR_Print("Catch entry moves for function '%s' {\n", function_fullname); CatchEntryMovesMapReader reader( TypedData::Handle(code.catch_entry_moves_maps())); diff --git a/runtime/vm/compiler/backend/il_deserializer.cc b/runtime/vm/compiler/backend/il_deserializer.cc index 6c30d952cf0..fec331ac049 100644 --- a/runtime/vm/compiler/backend/il_deserializer.cc +++ b/runtime/vm/compiler/backend/il_deserializer.cc @@ -768,7 +768,7 @@ Instruction* FlowGraphDeserializer::ParseInstruction(SExpList* list) { TokenPosition token_pos = TokenPosition::kNoSource; if (auto const token_int = CheckInteger(list->ExtraLookupValue("token_pos"))) { - token_pos = TokenPosition(token_int->value()); + token_pos = TokenPosition::Deserialize(token_int->value()); } InstrInfo common_info = {deopt_id, token_pos}; @@ -1833,7 +1833,7 @@ bool FlowGraphDeserializer::ParseType(SExpression* sexp, Object* out) { } TokenPosition token_pos = TokenPosition::kNoSource; if (const auto pos_sexp = CheckInteger(list->ExtraLookupValue("token_pos"))) { - token_pos = TokenPosition(pos_sexp->value()); + token_pos = TokenPosition::Deserialize(pos_sexp->value()); } auto type_args_ptr = &Object::null_type_arguments(); if (const auto ta_sexp = list->ExtraLookupValue("type_args")) { diff --git a/runtime/vm/compiler/backend/il_serializer.cc b/runtime/vm/compiler/backend/il_serializer.cc index 5e6fc92a50d..979c410ff83 100644 --- a/runtime/vm/compiler/backend/il_serializer.cc +++ b/runtime/vm/compiler/backend/il_serializer.cc @@ -437,7 +437,7 @@ SExpression* FlowGraphSerializer::AbstractTypeToSExp(const AbstractType& t) { AddSymbol(sexp, "Type"); const auto& type = Type::Cast(t); if (!type.token_pos().IsNoSource()) { - AddExtraInteger(sexp, "token_pos", type.token_pos().value()); + AddExtraInteger(sexp, "token_pos", type.token_pos().Serialize()); } // We want to check for the type being recursive before we may serialize // any sub-parts that include possible TypeRefs to this type. @@ -823,7 +823,7 @@ void Instruction::AddExtraInfoToSExpression(SExpList* sexp, sexp->AddExtra("env", env()->ToSExpression(s)); } if (!token_pos().IsNoSource()) { - s->AddExtraInteger(sexp, "token_pos", token_pos().value()); + s->AddExtraInteger(sexp, "token_pos", token_pos().Serialize()); } } diff --git a/runtime/vm/compiler/backend/redundancy_elimination.cc b/runtime/vm/compiler/backend/redundancy_elimination.cc index 269a793246e..c682aeffb0c 100644 --- a/runtime/vm/compiler/backend/redundancy_elimination.cc +++ b/runtime/vm/compiler/backend/redundancy_elimination.cc @@ -1692,9 +1692,7 @@ class LoadOptimizer : public ValueObject { // For now, bail out for large functions to avoid OOM situations. // TODO(fschneider): Fix the memory consumption issue. - intptr_t function_length = graph->function().end_token_pos().Pos() - - graph->function().token_pos().Pos(); - if (function_length >= FLAG_huge_method_cutoff_in_tokens) { + if (graph->function().SourceSize() >= FLAG_huge_method_cutoff_in_tokens) { return false; } @@ -2850,9 +2848,7 @@ class StoreOptimizer : public LivenessAnalysis { // For now, bail out for large functions to avoid OOM situations. // TODO(fschneider): Fix the memory consumption issue. - intptr_t function_length = graph->function().end_token_pos().Pos() - - graph->function().token_pos().Pos(); - if (function_length >= FLAG_huge_method_cutoff_in_tokens) { + if (graph->function().SourceSize() >= FLAG_huge_method_cutoff_in_tokens) { return; } diff --git a/runtime/vm/compiler/backend/yield_position_test.cc b/runtime/vm/compiler/backend/yield_position_test.cc index a32bb74242d..e90be85e0c9 100644 --- a/runtime/vm/compiler/backend/yield_position_test.cc +++ b/runtime/vm/compiler/backend/yield_position_test.cc @@ -103,11 +103,11 @@ void RunTestInMode(CompilerPass::PipelineMode mode) { EXPECT_EQ(3, yield_points.length()); EXPECT_EQ(1, yield_points[0].first); - EXPECT_EQ(88, yield_points[0].second.value()); + EXPECT_EQ(88, yield_points[0].second.Pos()); EXPECT_EQ(2, yield_points[1].first); - EXPECT_EQ(129, yield_points[1].second.value()); + EXPECT_EQ(129, yield_points[1].second.Pos()); EXPECT_EQ(3, yield_points[2].first); - EXPECT_EQ(170, yield_points[2].second.value()); + EXPECT_EQ(170, yield_points[2].second.Pos()); }; validate_indices(*GetYieldPointsFromGraph(flow_graph)); diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc index 7b3e6a0358b..7378aa768dc 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc @@ -4839,8 +4839,9 @@ Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration() { // Use position of equal sign if it exists. If the equal sign does not exist // use the position of the identifier. - TokenPosition debug_position = - Utils::Maximum(helper.position_, helper.equals_position_); + const TokenPosition debug_position = helper.equals_position_.IsReal() + ? helper.equals_position_ + : helper.position_; if (NeedsDebugStepCheck(stack(), debug_position)) { instructions = DebugStepCheck(debug_position) + instructions; } @@ -4882,7 +4883,7 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode( // Positions has to be unique in regards to the parent. // A non-real at this point is probably -1, we cannot blindly use that // as others might use it too. Create a new dummy non-real TokenPosition. - position = TokenPosition(offset).ToSynthetic(); + position = TokenPosition::Synthetic(offset); } // The VM has a per-isolate table of functions indexed by the enclosing diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h index 36c8a5e6e93..72b310618d1 100644 --- a/runtime/vm/compiler/frontend/kernel_translation_helper.h +++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h @@ -296,8 +296,8 @@ class FunctionNodeHelper { void SetNext(Field field) { next_read_ = field; } void SetJustRead(Field field) { next_read_ = field + 1; } - TokenPosition position_; - TokenPosition end_position_; + TokenPosition position_ = TokenPosition::kNoSource; + TokenPosition end_position_ = TokenPosition::kNoSource; AsyncMarker async_marker_; AsyncMarker dart_async_marker_; intptr_t total_parameter_count_ = 0; @@ -352,7 +352,7 @@ class TypeParameterHelper { return (flags_ & kIsGenericCovariantImpl) != 0; } - TokenPosition position_; + TokenPosition position_ = TokenPosition::kNoSource; uint8_t flags_ = 0; StringIndex name_index_; @@ -415,8 +415,8 @@ class VariableDeclarationHelper { return (flags_ & kIsGenericCovariantImpl) != 0; } - TokenPosition position_; - TokenPosition equals_position_; + TokenPosition position_ = TokenPosition::kNoSource; + TokenPosition equals_position_ = TokenPosition::kNoSource; uint8_t flags_ = 0; StringIndex name_index_; intptr_t annotation_count_ = 0; @@ -488,8 +488,8 @@ class FieldHelper { NameIndex canonical_name_getter_; NameIndex canonical_name_setter_; - TokenPosition position_; - TokenPosition end_position_; + TokenPosition position_ = TokenPosition::kNoSource; + TokenPosition end_position_ = TokenPosition::kNoSource; uint32_t flags_ = 0; intptr_t source_uri_index_ = 0; intptr_t annotation_count_ = 0; @@ -589,9 +589,9 @@ class ProcedureHelper { } NameIndex canonical_name_; - TokenPosition start_position_; - TokenPosition position_; - TokenPosition end_position_; + TokenPosition start_position_ = TokenPosition::kNoSource; + TokenPosition position_ = TokenPosition::kNoSource; + TokenPosition end_position_ = TokenPosition::kNoSource; Kind kind_; uint32_t flags_ = 0; intptr_t source_uri_index_ = 0; @@ -655,9 +655,9 @@ class ConstructorHelper { bool IsSynthetic() { return (flags_ & kSynthetic) != 0; } NameIndex canonical_name_; - TokenPosition start_position_; - TokenPosition position_; - TokenPosition end_position_; + TokenPosition start_position_ = TokenPosition::kNoSource; + TokenPosition position_ = TokenPosition::kNoSource; + TokenPosition end_position_ = TokenPosition::kNoSource; uint8_t flags_ = 0; intptr_t source_uri_index_ = 0; intptr_t annotation_count_ = 0; @@ -733,9 +733,9 @@ class ClassHelper { } NameIndex canonical_name_; - TokenPosition start_position_; - TokenPosition position_; - TokenPosition end_position_; + TokenPosition start_position_ = TokenPosition::kNoSource; + TokenPosition position_ = TokenPosition::kNoSource; + TokenPosition end_position_ = TokenPosition::kNoSource; StringIndex name_index_; intptr_t source_uri_index_ = 0; intptr_t annotation_count_ = 0; diff --git a/runtime/vm/compiler/frontend/scope_builder.h b/runtime/vm/compiler/frontend/scope_builder.h index c8680c34974..15315080840 100644 --- a/runtime/vm/compiler/frontend/scope_builder.h +++ b/runtime/vm/compiler/frontend/scope_builder.h @@ -162,7 +162,7 @@ class ScopeBuilder { intptr_t name_index_; bool needs_expr_temp_; - TokenPosition first_body_token_position_; + TokenPosition first_body_token_position_ = TokenPosition::kNoSource; KernelReaderHelper helper_; ConstantReader constant_reader_; diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc index d88ab4dcb32..37606511964 100644 --- a/runtime/vm/compiler/jit/compiler.cc +++ b/runtime/vm/compiler/jit/compiler.cc @@ -724,8 +724,7 @@ static ObjectPtr CompileFunctionHelper(CompilationPipeline* pipeline, ParsedFunction* parsed_function = new (zone) ParsedFunction(thread, Function::ZoneHandle(zone, function.raw())); if (trace_compiler) { - const intptr_t token_size = - function.end_token_pos().Pos() - function.token_pos().Pos(); + const intptr_t token_size = function.SourceSize(); THR_Print("Compiling %s%sfunction %s: '%s' @ token %s, size %" Pd "\n", (osr_id == Compiler::kNoOSRDeoptId ? "" : "osr "), (optimized ? "optimized " : ""), @@ -1300,9 +1299,9 @@ CompilationPipeline* CompilationPipeline::New(Zone* zone, DEFINE_RUNTIME_ENTRY(CompileFunction, 1) { const Function& function = Function::CheckedHandle(zone, arguments.ArgAt(0)); - FATAL3("Precompilation missed function %s (%" Pd ", %s)\n", + FATAL3("Precompilation missed function %s (%s, %s)\n", function.ToLibNamePrefixedQualifiedCString(), - function.token_pos().value(), + function.token_pos().ToCString(), Function::KindToCString(function.kind())); } diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc index d1096d765e5..6120b67e59b 100644 --- a/runtime/vm/debugger.cc +++ b/runtime/vm/debugger.cc @@ -109,8 +109,7 @@ void BreakpointLocation::SetResolved(const Function& func, TokenPosition token_pos) { ASSERT(!IsLatent()); ASSERT(func.script() == script_); - ASSERT((func.token_pos() <= token_pos) && - (token_pos <= func.end_token_pos())); + ASSERT(token_pos.IsWithin(func.token_pos(), func.end_token_pos())); ASSERT(func.is_debuggable()); function_ = func.raw(); token_pos_ = token_pos; @@ -394,11 +393,10 @@ static bool FunctionOverlaps(const Function& func, const Script& script, TokenPosition token_pos, TokenPosition end_token_pos) { - TokenPosition func_start = func.token_pos(); - if (((func_start <= token_pos) && (token_pos <= func.end_token_pos())) || - ((token_pos <= func_start) && (func_start <= end_token_pos))) { - // Check script equality second because it allocates - // handles as a side effect. + const TokenPosition& func_start = func.token_pos(); + if (token_pos.IsWithin(func_start, func.end_token_pos()) || + func_start.IsWithin(token_pos, end_token_pos)) { + // Check script equality last because it allocates handles as a side effect. return func.script() == script.raw(); } return false; @@ -566,24 +564,20 @@ intptr_t ActivationFrame::DeoptId() { intptr_t ActivationFrame::LineNumber() { // Compute line number lazily since it causes scanning of the script. - if ((line_number_ < 0) && TokenPos().IsSourcePosition()) { - const TokenPosition token_pos = TokenPos().SourcePosition(); + const TokenPosition& token_pos = TokenPos(); + if ((line_number_ < 0) && token_pos.IsReal()) { const Script& script = Script::Handle(SourceScript()); - script.GetTokenLocation(token_pos, &line_number_, NULL); + script.GetTokenLocation(token_pos, &line_number_, nullptr); } return line_number_; } intptr_t ActivationFrame::ColumnNumber() { // Compute column number lazily since it causes scanning of the script. - if ((column_number_ < 0) && TokenPos().IsSourcePosition()) { - const TokenPosition token_pos = TokenPos().SourcePosition(); + const TokenPosition& token_pos = TokenPos(); + if ((column_number_ < 0) && token_pos.IsReal()) { const Script& script = Script::Handle(SourceScript()); - if (script.HasSource()) { - script.GetTokenLocation(token_pos, &line_number_, &column_number_); - } else { - column_number_ = -1; - } + script.GetTokenLocation(token_pos, &line_number_, &column_number_); } return column_number_; } @@ -648,13 +642,14 @@ intptr_t ActivationFrame::ContextLevel() { } intptr_t var_desc_len = var_descriptors_.Length(); bool found = false; + // We store the deopt ids as real token positions. + const auto to_compare = TokenPosition::Deserialize(deopt_id); for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) { LocalVarDescriptorsLayout::VarInfo var_info; var_descriptors_.GetInfo(cur_idx, &var_info); const int8_t kind = var_info.kind(); if ((kind == LocalVarDescriptorsLayout::kContextLevel) && - (deopt_id >= var_info.begin_pos.value()) && - (deopt_id <= var_info.end_pos.value())) { + to_compare.IsWithin(var_info.begin_pos, var_info.end_pos)) { context_level_ = var_info.index(); found = true; break; @@ -925,51 +920,51 @@ void ActivationFrame::GetDescIndices() { (kind != LocalVarDescriptorsLayout::kContextVar)) { continue; } - if ((var_info.begin_pos <= activation_token_pos) && - (activation_token_pos <= var_info.end_pos)) { - if ((kind == LocalVarDescriptorsLayout::kContextVar) && - (ContextLevel() < var_info.scope_id)) { - // The variable is textually in scope but the context level - // at the activation frame's PC is lower than the context - // level of the variable. The context containing the variable - // has already been removed from the chain. This can happen when we - // break at a return statement, since the contexts get discarded - // before the debugger gets called. - continue; - } - // The current variable is textually in scope. Now check whether - // there is another local variable with the same name that shadows - // or is shadowed by this variable. - String& var_name = String::Handle(var_descriptors_.GetName(cur_idx)); - intptr_t indices_len = desc_indices_.length(); - bool name_match_found = false; - for (intptr_t i = 0; i < indices_len; i++) { - if (var_name.Equals(*var_names[i])) { - // Found two local variables with the same name. Now determine - // which one is shadowed. - name_match_found = true; - LocalVarDescriptorsLayout::VarInfo i_var_info; - var_descriptors_.GetInfo(desc_indices_[i], &i_var_info); - if (i_var_info.begin_pos < var_info.begin_pos) { - // The variable we found earlier is in an outer scope - // and is shadowed by the current variable. Replace the - // descriptor index of the previously found variable - // with the descriptor index of the current variable. - desc_indices_[i] = cur_idx; - } else { - // The variable we found earlier is in an inner scope - // and shadows the current variable. Skip the current - // variable. (Nothing to do.) - } - break; // Stop looking for name matches. + if (!activation_token_pos.IsWithin(var_info.begin_pos, var_info.end_pos)) { + continue; + } + if ((kind == LocalVarDescriptorsLayout::kContextVar) && + (ContextLevel() < var_info.scope_id)) { + // The variable is textually in scope but the context level + // at the activation frame's PC is lower than the context + // level of the variable. The context containing the variable + // has already been removed from the chain. This can happen when we + // break at a return statement, since the contexts get discarded + // before the debugger gets called. + continue; + } + // The current variable is textually in scope. Now check whether + // there is another local variable with the same name that shadows + // or is shadowed by this variable. + String& var_name = String::Handle(var_descriptors_.GetName(cur_idx)); + intptr_t indices_len = desc_indices_.length(); + bool name_match_found = false; + for (intptr_t i = 0; i < indices_len; i++) { + if (var_name.Equals(*var_names[i])) { + // Found two local variables with the same name. Now determine + // which one is shadowed. + name_match_found = true; + LocalVarDescriptorsLayout::VarInfo i_var_info; + var_descriptors_.GetInfo(desc_indices_[i], &i_var_info); + if (i_var_info.begin_pos < var_info.begin_pos) { + // The variable we found earlier is in an outer scope + // and is shadowed by the current variable. Replace the + // descriptor index of the previously found variable + // with the descriptor index of the current variable. + desc_indices_[i] = cur_idx; + } else { + // The variable we found earlier is in an inner scope + // and shadows the current variable. Skip the current + // variable. (Nothing to do.) } + break; // Stop looking for name matches. } - if (!name_match_found) { - // No duplicate name found. Add the current descriptor index to the - // list of visible variables. - desc_indices_.Add(cur_idx); - var_names.Add(&var_name); - } + } + if (!name_match_found) { + // No duplicate name found. Add the current descriptor index to the + // list of visible variables. + desc_indices_.Add(cur_idx); + var_names.Add(&var_name); } } vars_initialized_ = true; @@ -1167,7 +1162,7 @@ ArrayPtr ActivationFrame::GetLocalVariables() { Object& value = Instance::Handle(); const Array& list = Array::Handle(Array::New(2 * num_variables)); for (intptr_t i = 0; i < num_variables; i++) { - TokenPosition ignore; + TokenPosition ignore = TokenPosition::kNoSource; VariableAt(i, &var_name, &ignore, &ignore, &ignore, &value); list.SetAt(2 * i, var_name); list.SetAt((2 * i) + 1, value); @@ -1181,7 +1176,7 @@ ObjectPtr ActivationFrame::GetReceiver() { String& var_name = String::Handle(); Instance& value = Instance::Handle(); for (intptr_t i = 0; i < num_variables; i++) { - TokenPosition ignore; + TokenPosition ignore = TokenPosition::kNoSource; VariableAt(i, &var_name, &ignore, &ignore, &ignore, &value); if (var_name.Equals(Symbols::This())) { return value.raw(); @@ -1232,7 +1227,7 @@ TypeArgumentsPtr ActivationFrame::BuildParameters( TypeArguments& type_arguments = TypeArguments::Handle(); intptr_t num_variables = desc_indices_.length(); for (intptr_t i = 0; i < num_variables; i++) { - TokenPosition ignore; + TokenPosition ignore = TokenPosition::kNoSource; VariableAt(i, &name, &ignore, &ignore, &ignore, &value); if (name.Equals(Symbols::FunctionTypeArgumentsVar())) { type_arguments_available = true; @@ -1347,7 +1342,7 @@ void ActivationFrame::PrintToJSONObjectRegular(JSONObject* jsobj) { const Script& script = Script::Handle(SourceScript()); jsobj->AddProperty("type", "Frame"); jsobj->AddProperty("kind", KindToCString(kind_)); - const TokenPosition pos = TokenPos().SourcePosition(); + const TokenPosition& pos = TokenPos(); jsobj->AddLocation(script, pos); jsobj->AddProperty("function", function()); jsobj->AddProperty("code", code()); @@ -1357,9 +1352,9 @@ void ActivationFrame::PrintToJSONObjectRegular(JSONObject* jsobj) { for (intptr_t v = 0; v < num_vars; v++) { String& var_name = String::Handle(); Instance& var_value = Instance::Handle(); - TokenPosition declaration_token_pos; - TokenPosition visible_start_token_pos; - TokenPosition visible_end_token_pos; + TokenPosition declaration_token_pos = TokenPosition::kNoSource; + TokenPosition visible_start_token_pos = TokenPosition::kNoSource; + TokenPosition visible_end_token_pos = TokenPosition::kNoSource; VariableAt(v, &var_name, &declaration_token_pos, &visible_start_token_pos, &visible_end_token_pos, &var_value); if (!IsSyntheticVariableName(var_name)) { @@ -1383,7 +1378,7 @@ void ActivationFrame::PrintToJSONObjectAsyncCausal(JSONObject* jsobj) { jsobj->AddProperty("type", "Frame"); jsobj->AddProperty("kind", KindToCString(kind_)); const Script& script = Script::Handle(SourceScript()); - const TokenPosition pos = TokenPos().SourcePosition(); + const TokenPosition& pos = TokenPos(); jsobj->AddLocation(script, pos); jsobj->AddProperty("function", function()); jsobj->AddProperty("code", code()); @@ -2239,16 +2234,14 @@ static void RefineBreakpointPos(const Script& script, intptr_t token_start_column = -1; intptr_t token_line = -1; if (requested_column >= 0) { - TokenPosition ignored; - TokenPosition end_of_line_pos; + TokenPosition ignored = TokenPosition::kNoSource; + TokenPosition end_of_line_pos = TokenPosition::kNoSource; script.GetTokenLocation(pos, &token_line, &token_start_column); script.TokenRangeAtLine(token_line, &ignored, &end_of_line_pos); TokenPosition token_end_pos = - (end_of_line_pos < next_closest_token_position) - ? end_of_line_pos - : next_closest_token_position; + TokenPosition::Min(next_closest_token_position, end_of_line_pos); - if ((token_end_pos < exact_token_pos) || + if ((exact_token_pos.IsReal() && (token_end_pos < exact_token_pos)) || (token_start_column > *best_column)) { // Prefer the token with the lowest column number compatible // with the requested column. @@ -2261,9 +2254,11 @@ static void RefineBreakpointPos(const Script& script, *best_fit_pos = pos; *best_line = token_line; *best_column = token_start_column; - // best_token_pos is only used when column number is specified. - *best_token_pos = TokenPosition(exact_token_pos.value() - - (requested_column - *best_column)); + // best_token_pos should only be real when the column number is specified. + if (requested_column >= 0 && exact_token_pos.IsReal()) { + *best_token_pos = TokenPosition::Deserialize( + exact_token_pos.Pos() - (requested_column - *best_column)); + } } } @@ -2330,12 +2325,9 @@ TokenPosition Debugger::ResolveBreakpointPos(const Function& func, TokenPosition exact_token_pos) { ASSERT(!func.HasOptimizedCode()); - if (requested_token_pos < func.token_pos()) { - requested_token_pos = func.token_pos(); - } - if (last_token_pos > func.end_token_pos()) { - last_token_pos = func.end_token_pos(); - } + requested_token_pos = + TokenPosition::Max(requested_token_pos, func.token_pos()); + last_token_pos = TokenPosition::Min(last_token_pos, func.end_token_pos()); Zone* zone = Thread::Current()->zone(); Script& script = Script::Handle(zone, func.script()); @@ -2351,15 +2343,19 @@ TokenPosition Debugger::ResolveBreakpointPos(const Function& func, TokenPosition best_fit_pos = TokenPosition::kMaxSource; intptr_t best_column = INT_MAX; intptr_t best_line = INT_MAX; - // best_token_pos and exact_token_pos are only used - // if column number is provided. + // best_token_pos is only set to a real position if a real exact_token_pos + // and a column number are provided. TokenPosition best_token_pos = TokenPosition::kNoSource; PcDescriptors::Iterator iter(desc, kSafepointKind); while (iter.MoveNext()) { - const TokenPosition pos = iter.TokenPos(); - if ((!pos.IsReal()) || (pos < requested_token_pos) || - (pos > last_token_pos)) { + const TokenPosition& pos = iter.TokenPos(); + if (pos.IsSynthetic() && pos == requested_token_pos) { + // if there's a safepoint for a synthetic function start and the start + // was requested, we're done. + return pos; + } + if (!pos.IsWithin(requested_token_pos, last_token_pos)) { // Token is not in the target range. continue; } @@ -2368,8 +2364,9 @@ TokenPosition Debugger::ResolveBreakpointPos(const Function& func, // Find next closest safepoint PcDescriptors::Iterator iter2(desc, kSafepointKind); while (iter2.MoveNext()) { - const TokenPosition next = iter2.TokenPos(); - if (next < next_closest_token_position && next > pos) { + const TokenPosition& next = iter2.TokenPos(); + if (!next.IsReal()) continue; + if ((pos < next) && (next < next_closest_token_position)) { next_closest_token_position = next; } } @@ -2384,33 +2381,31 @@ TokenPosition Debugger::ResolveBreakpointPos(const Function& func, // the token on the line which is at the best fit column (if column // was specified) and has the lowest code address. if (best_fit_pos != TokenPosition::kMaxSource) { + ASSERT(best_fit_pos.IsReal()); const Script& script = Script::Handle(zone, func.script()); const TokenPosition begin_pos = best_fit_pos; - TokenPosition end_of_line_pos; + TokenPosition end_of_line_pos = TokenPosition::kNoSource; if (best_line == -1) { - script.GetTokenLocation(begin_pos, &best_line, NULL); + script.GetTokenLocation(begin_pos, &best_line, nullptr); } ASSERT(best_line > 0); - TokenPosition ignored; + TokenPosition ignored = TokenPosition::kNoSource; script.TokenRangeAtLine(best_line, &ignored, &end_of_line_pos); - if (end_of_line_pos < begin_pos) { - end_of_line_pos = begin_pos; - } + end_of_line_pos = TokenPosition::Max(end_of_line_pos, begin_pos); uword lowest_pc_offset = kUwordMax; PcDescriptors::Iterator iter(desc, kSafepointKind); while (iter.MoveNext()) { - const TokenPosition pos = iter.TokenPos(); - if (!pos.IsReal() || (pos < begin_pos) || (pos > end_of_line_pos)) { - // Token is not on same line as best fit. - continue; - } - - if (requested_column >= 0) { + const TokenPosition& pos = iter.TokenPos(); + if (best_token_pos.IsReal()) { if (pos != best_token_pos) { + // Not an match for the requested column. continue; } + } else if (!pos.IsWithin(begin_pos, end_of_line_pos)) { + // Token is not on same line as best fit. + continue; } // Prefer the lowest pc offset. @@ -2557,14 +2552,14 @@ void Debugger::FindCompiledFunctions( } } -static void SelectBestFit(Function* best_fit, Function* func) { +static void UpdateBestFit(Function* best_fit, const Function& func) { if (best_fit->IsNull()) { - *best_fit = func->raw(); - } else { - if ((func->token_pos() > best_fit->token_pos()) && - ((func->end_token_pos() <= best_fit->end_token_pos()))) { - *best_fit = func->raw(); - } + *best_fit = func.raw(); + } else if ((best_fit->token_pos().IsSynthetic() || + func.token_pos().IsSynthetic() || + (best_fit->token_pos() < func.token_pos())) && + (func.end_token_pos() <= best_fit->end_token_pos())) { + *best_fit = func.raw(); } } @@ -2623,7 +2618,7 @@ bool Debugger::FindBestFit(const Script& script, function ^= closures.At(i); if (FunctionOverlaps(function, script, token_pos, last_token_pos)) { // Select the inner most closure. - SelectBestFit(best_fit, &function); + UpdateBestFit(best_fit, function); } } if (!best_fit->IsNull()) { @@ -2688,8 +2683,8 @@ bool Debugger::FindBestFit(const Script& script, if (!fields.IsNull()) { const intptr_t num_fields = fields.Length(); for (intptr_t pos = 0; pos < num_fields; pos++) { - TokenPosition start; - TokenPosition end; + TokenPosition start = TokenPosition::kNoSource; + TokenPosition end = TokenPosition::kNoSource; field ^= fields.At(pos); ASSERT(!field.IsNull()); if (field.Script() != script.raw()) { @@ -2702,8 +2697,8 @@ bool Debugger::FindBestFit(const Script& script, } start = field.token_pos(); end = field.end_token_pos(); - if ((start <= token_pos && token_pos <= end) || - (token_pos <= start && start <= last_token_pos)) { + if (token_pos.IsWithin(start, end) || + start.IsWithin(token_pos, last_token_pos)) { return true; } } @@ -2803,7 +2798,7 @@ BreakpointLocation* Debugger::SetBreakpoint(const Script& script, // have already been compiled. We can resolve the breakpoint now. // If requested_column is larger than zero, [token_pos, last_token_pos] // governs one single line of code. - TokenPosition exact_token_pos = TokenPosition(-1); + TokenPosition exact_token_pos = TokenPosition::kNoSource; if (token_pos != last_token_pos && requested_column >= 0) { #if !defined(DART_PRECOMPILED_RUNTIME) exact_token_pos = @@ -3010,7 +3005,8 @@ BreakpointLocation* Debugger::BreakpointLocationAtLineCol( } return latent_bpt; } - TokenPosition first_token_idx, last_token_idx; + TokenPosition first_token_idx = TokenPosition::kNoSource; + TokenPosition last_token_idx = TokenPosition::kNoSource; script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx); if (!first_token_idx.IsReal()) { // Script does not contain the given line number. @@ -3825,6 +3821,8 @@ void Debugger::NotifyIsolateCreated() { // the given token position. FunctionPtr Debugger::FindInnermostClosure(const Function& function, TokenPosition token_pos) { + ASSERT(function.end_token_pos().IsReal()); + const TokenPosition& func_start = function.token_pos(); Zone* zone = Thread::Current()->zone(); const Script& outer_origin = Script::Handle(zone, function.script()); const GrowableObjectArray& closures = GrowableObjectArray::Handle( @@ -3834,12 +3832,16 @@ FunctionPtr Debugger::FindInnermostClosure(const Function& function, Function& best_fit = Function::Handle(zone); for (intptr_t i = 0; i < num_closures; i++) { closure ^= closures.At(i); - if ((function.token_pos() < closure.token_pos()) && - (closure.end_token_pos() < function.end_token_pos()) && - (closure.token_pos() <= token_pos) && - (token_pos <= closure.end_token_pos()) && + const TokenPosition& closure_start = closure.token_pos(); + const TokenPosition& closure_end = closure.end_token_pos(); + // We're only interested in closures that have real ending token positions. + // The starting token position can be synthetic. + if (closure_end.IsReal() && (function.end_token_pos() > closure_end) && + (!closure_start.IsReal() || !func_start.IsReal() || + (closure_start > func_start)) && + token_pos.IsWithin(closure_start, closure_end) && (closure.script() == outer_origin.raw())) { - SelectBestFit(&best_fit, &closure); + UpdateBestFit(&best_fit, closure); } } return best_fit.raw(); @@ -3851,13 +3853,14 @@ FunctionPtr Debugger::FindInnermostClosure(const Function& function, TokenPosition Debugger::FindExactTokenPosition(const Script& script, TokenPosition start_of_line, intptr_t column_number) { - intptr_t line = -1; - intptr_t col = -1; - Zone* zone = Thread::Current()->zone(); - kernel::KernelLineStartsReader line_starts_reader( - TypedData::Handle(zone, script.line_starts()), zone); - line_starts_reader.LocationForPosition(start_of_line.value(), &line, &col); - return TokenPosition(start_of_line.value() + (column_number - col)); + intptr_t line; + intptr_t col; + script.GetTokenLocation(start_of_line, &line, &col); + if (line < 0) { + return TokenPosition::kNoSource; + } + return TokenPosition::Deserialize(start_of_line.Pos() + + (column_number - col)); } #endif // !defined(DART_PRECOMPILED_RUNTIME) @@ -3988,7 +3991,8 @@ void Debugger::NotifyDoneLoading() { intptr_t line_number = matched_loc->requested_line_number(); intptr_t column_number = matched_loc->requested_column_number(); ASSERT(line_number >= 0); - TokenPosition first_token_pos, last_token_pos; + TokenPosition first_token_pos = TokenPosition::kNoSource; + TokenPosition last_token_pos = TokenPosition::kNoSource; script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos); if (!first_token_pos.IsDebugPause() || !last_token_pos.IsDebugPause()) { // Script does not contain the given line number or there are no diff --git a/runtime/vm/dwarf.h b/runtime/vm/dwarf.h index 22df262077e..ef72088c8c1 100644 --- a/runtime/vm/dwarf.h +++ b/runtime/vm/dwarf.h @@ -60,7 +60,7 @@ struct FunctionIndexPair { static Value ValueOf(Pair kv) { return kv.index_; } - static inline intptr_t Hashcode(Key key) { return key->token_pos().value(); } + static inline intptr_t Hashcode(Key key) { return key->token_pos().Hash(); } static inline bool IsKeyEqual(Pair pair, Key key) { return pair.function_->raw() == key->raw(); diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc index adfc624a7db..5b3c8fe91e5 100644 --- a/runtime/vm/json_stream.cc +++ b/runtime/vm/json_stream.cc @@ -320,7 +320,7 @@ void JSONStream::PrintValue(Breakpoint* bpt) { void JSONStream::PrintValue(TokenPosition tp) { PrintCommaIfNeeded(); - PrintValue(tp.value()); + PrintValue(static_cast(tp.Serialize())); } void JSONStream::PrintValue(const ServiceEvent* event) { diff --git a/runtime/vm/kernel.cc b/runtime/vm/kernel.cc index ed497425c34..4a65c475480 100644 --- a/runtime/vm/kernel.cc +++ b/runtime/vm/kernel.cc @@ -78,11 +78,11 @@ void KernelLineStartsReader::TokenRangeAtLine( for (intptr_t i = 0; i < line_number; ++i) { cumulative += helper_->At(line_starts_data_, i); } - *first_token_index = dart::TokenPosition(cumulative); + *first_token_index = dart::TokenPosition::Deserialize(cumulative); if (line_number == line_starts_data_.Length()) { - *last_token_index = dart::TokenPosition(source_length); + *last_token_index = dart::TokenPosition::Deserialize(source_length); } else { - *last_token_index = dart::TokenPosition( + *last_token_index = dart::TokenPosition::Deserialize( cumulative + helper_->At(line_starts_data_, line_number) - 1); } } @@ -168,7 +168,7 @@ void KernelTokenPositionCollector::CollectTokenPositions( void KernelTokenPositionCollector::RecordTokenPosition(TokenPosition position) { if (record_for_script_id_ == current_script_id_ && record_token_positions_into_ != NULL && position.IsReal()) { - record_token_positions_into_->Add(position.value()); + record_token_positions_into_->Add(position.Serialize()); } } @@ -259,8 +259,8 @@ void CollectTokenPositionsFor(const Script& interesting_script) { if (entry.IsClass()) { const Class& klass = Class::Cast(entry); if (klass.script() == interesting_script.raw()) { - token_positions.Add(klass.token_pos().value()); - token_positions.Add(klass.end_token_pos().value()); + token_positions.Add(klass.token_pos().Serialize()); + token_positions.Add(klass.end_token_pos().Serialize()); } if (klass.is_finalized()) { temp_array = klass.fields(); diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h index 38f1474a7bb..48e323145ca 100644 --- a/runtime/vm/kernel_binary.h +++ b/runtime/vm/kernel_binary.h @@ -229,14 +229,18 @@ class Reader : public ValueObject { raw_buffer_(buffer), typed_data_(NULL), size_(size), - offset_(0) {} + offset_(0), + max_position_(TokenPosition::kNoSource), + min_position_(TokenPosition::kNoSource) {} explicit Reader(const ExternalTypedData& typed_data) : thread_(Thread::Current()), raw_buffer_(NULL), typed_data_(&typed_data), size_(typed_data.IsNull() ? 0 : typed_data.Length()), - offset_(0) {} + offset_(0), + max_position_(TokenPosition::kNoSource), + min_position_(TokenPosition::kNoSource) {} uint32_t ReadFromIndex(intptr_t end_offset, intptr_t fields_before, @@ -329,14 +333,9 @@ class Reader : public ValueObject { // Position is saved as unsigned, // but actually ranges from -1 and up (thus the -1) intptr_t value = ReadUInt() - 1; - TokenPosition result = TokenPosition(value); - max_position_ = Utils::Maximum(max_position_, result); - if (min_position_.IsNoSource()) { - min_position_ = result; - } else if (result.IsReal()) { - min_position_ = Utils::Minimum(min_position_, result); - } - + TokenPosition result = TokenPosition::Deserialize(value); + max_position_ = TokenPosition::Max(max_position_, result); + min_position_ = TokenPosition::Min(min_position_, result); return result; } @@ -553,12 +552,8 @@ class PositionScope { } ~PositionScope() { - if (reader_->min_position_.IsNoSource()) { - reader_->min_position_ = min_; - } else if (min_.IsReal()) { - reader_->min_position_ = Utils::Minimum(reader_->min_position_, min_); - } - reader_->max_position_ = Utils::Maximum(reader_->max_position_, max_); + reader_->min_position_ = TokenPosition::Min(reader_->min_position_, min_); + reader_->max_position_ = TokenPosition::Max(reader_->max_position_, max_); } private: diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index f2f98771b93..6cb5b658358 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -3959,7 +3959,7 @@ static ObjectPtr ThrowTypeError(const TokenPosition token_pos, const AbstractType& dst_type, const String& dst_name) { const Array& args = Array::Handle(Array::New(4)); - const Smi& pos = Smi::Handle(Smi::New(token_pos.value())); + const Smi& pos = Smi::Handle(Smi::New(token_pos.Serialize())); args.SetAt(0, pos); args.SetAt(1, src_value); args.SetAt(2, dst_type); @@ -7640,9 +7640,8 @@ bool Function::IsOptimizable() const { // Native methods don't need to be optimized. return false; } - const intptr_t function_length = end_token_pos().Pos() - token_pos().Pos(); if (is_optimizable() && (script() != Script::null()) && - (function_length < FLAG_huge_method_cutoff_in_tokens)) { + SourceSize() < FLAG_huge_method_cutoff_in_tokens) { // Additional check needed for implicit getters. return (unoptimized_code() == Object::null()) || (Code::Handle(unoptimized_code()).Size() < @@ -9398,7 +9397,7 @@ StringPtr Function::GetSource() const { if (src.IsNull() || src.Length() == 0) { return Symbols::OptimizedOut().raw(); } - uint16_t end_char = src.CharAt(end_token_pos().value()); + uint16_t end_char = src.CharAt(end_token_pos().Pos()); if ((end_char == ',') || // Case 1. (end_char == ')') || // Case 2. (end_char == ';' && String::Handle(zone, name()) @@ -9662,6 +9661,27 @@ bool Function::MayHaveUncheckedEntryPoint() const { (NeedsTypeArgumentTypeChecks() || NeedsArgumentTypeChecks()); } +intptr_t Function::SourceSize() const { + const TokenPosition& start = token_pos(); + const TokenPosition& end = end_token_pos(); + if (!end.IsReal() || start.IsNoSource() || start.IsClassifying()) { + // No source information, so just return 0. + return 0; + } + if (start.IsSynthetic()) { + // Try and approximate the source size using the parent's source size. + const auto& parent = Function::Handle(parent_function()); + ASSERT(!parent.IsNull()); + const intptr_t parent_size = parent.SourceSize(); + if (parent_size == 0) { + return parent_size; + } + // Parent must have a real ending position. + return parent_size - (parent.end_token_pos().Pos() - end.Pos()); + } + return end.Pos() - start.Pos(); +} + const char* Function::ToCString() const { if (IsNull()) { return "Function: null"; @@ -11231,31 +11251,6 @@ void Script::SetLocationOffset(intptr_t line_offset, StoreNonPointer(&raw_ptr()->col_offset_, col_offset); } -// Specialized for AOT compilation, which does this lookup for every token -// position that could be part of a stack trace. -bool Script::GetTokenLocationUsingLineStarts(TokenPosition target_token_pos, - intptr_t* line, - intptr_t* column) const { -#if defined(DART_PRECOMPILED_RUNTIME) - return false; -#else - // Negative positions denote positions that do not correspond to Dart code. - if (target_token_pos.value() < 0) return false; - - Zone* zone = Thread::Current()->zone(); - TypedData& line_starts_data = TypedData::Handle(zone, line_starts()); - ASSERT(!line_starts_data.IsNull()); - - kernel::KernelLineStartsReader line_starts_reader(line_starts_data, zone); - line_starts_reader.LocationForPosition(target_token_pos.value(), line, - column); - // The line and column numbers returned are ordinals, so we shouldn't get 0. - ASSERT(*line > 0); - ASSERT(*column > 0); - return true; -#endif -} - #if !defined(DART_PRECOMPILED_RUNTIME) static bool IsLetter(int32_t c) { return (('A' <= c) && (c <= 'Z')) || (('a' <= c) && (c <= 'z')); @@ -11278,37 +11273,36 @@ void Script::GetTokenLocation(TokenPosition token_pos, intptr_t* line, intptr_t* column, intptr_t* token_len) const { - ASSERT(line != NULL); - Zone* zone = Thread::Current()->zone(); - - LookupSourceAndLineStarts(zone); - if (line_starts() == TypedData::null()) { - // Scripts in the AOT snapshot do not have a line starts array. - *line = -1; - if (column != NULL) { - *column = -1; - } - if (token_len != NULL) { - *token_len = 1; - } - return; + ASSERT(line != nullptr); + // Set up appropriate values for any early returns. + *line = -1; + if (column != nullptr) { + *column = -1; } + if (token_len != nullptr) { + *token_len = 1; + } + // Scripts in the AOT snapshot do not have a line starts array. #if !defined(DART_PRECOMPILED_RUNTIME) + if (!token_pos.IsReal()) return; + + auto const zone = Thread::Current()->zone(); + LookupSourceAndLineStarts(zone); const TypedData& line_starts_data = TypedData::Handle(zone, line_starts()); kernel::KernelLineStartsReader line_starts_reader(line_starts_data, zone); - line_starts_reader.LocationForPosition(token_pos.value(), line, column); - if (token_len != NULL) { - *token_len = 1; - // We don't explicitly save this data: Load the source - // and find it from there. - const String& source = String::Handle(zone, Source()); - if (!source.IsNull()) { - intptr_t offset = token_pos.value(); - if (offset < source.Length() && IsIdentStartChar(source.CharAt(offset))) { - for (intptr_t i = offset + 1; - i < source.Length() && IsIdentChar(source.CharAt(i)); ++i) { - ++*token_len; - } + const intptr_t pos = token_pos.Pos(); + line_starts_reader.LocationForPosition(pos, line, column); + if (token_len == nullptr) return; + *token_len = 1; + // We don't explicitly save this data: Load the source + // and find it from there. + const String& source = String::Handle(zone, Source()); + if (!source.IsNull()) { + intptr_t offset = pos; + if (offset < source.Length() && IsIdentStartChar(source.CharAt(offset))) { + for (intptr_t i = offset + 1; + i < source.Length() && IsIdentChar(source.CharAt(i)); ++i) { + ++*token_len; } } } @@ -11321,16 +11315,10 @@ void Script::TokenRangeAtLine(intptr_t line_number, ASSERT(first_token_index != NULL && last_token_index != NULL); ASSERT(line_number > 0); - Thread* thread = Thread::Current(); - Zone* zone = thread->zone(); - LookupSourceAndLineStarts(zone); - if (line_starts() == TypedData::null()) { - // Scripts in the AOT snapshot do not have a line starts array. - *first_token_index = TokenPosition::kNoSource; - *last_token_index = TokenPosition::kNoSource; - return; - } + // Scripts in the AOT snapshot do not have a line starts array. #if !defined(DART_PRECOMPILED_RUNTIME) + Zone* zone = Thread::Current()->zone(); + LookupSourceAndLineStarts(zone); const String& source = String::Handle(zone, Source()); intptr_t source_length; if (source.IsNull()) { @@ -11342,8 +11330,7 @@ void Script::TokenRangeAtLine(intptr_t line_number, source_length = source.Length(); } const TypedData& line_starts_data = TypedData::Handle(zone, line_starts()); - kernel::KernelLineStartsReader line_starts_reader(line_starts_data, - Thread::Current()->zone()); + kernel::KernelLineStartsReader line_starts_reader(line_starts_data, zone); line_starts_reader.TokenRangeAtLine(source_length, line_number, first_token_index, last_token_index); #endif // !defined(DART_PRECOMPILED_RUNTIME) @@ -14359,8 +14346,8 @@ static int PrintVarInfo(char* buffer, " %-13s level=%-3d" " begin=%-3d end=%d\n", i, LocalVarDescriptors::KindToCString(kind), index, - static_cast(info.begin_pos.value()), - static_cast(info.end_pos.value())); + static_cast(info.begin_pos.Pos()), + static_cast(info.end_pos.Pos())); } else if (kind == LocalVarDescriptorsLayout::kContextVar) { return Utils::SNPrint( buffer, len, @@ -16810,18 +16797,19 @@ ContextScopePtr ContextScope::New(intptr_t num_variables, bool is_implicit) { } TokenPosition ContextScope::TokenIndexAt(intptr_t scope_index) const { - return TokenPosition(Smi::Value(VariableDescAddr(scope_index)->token_pos)); + return TokenPosition::Deserialize( + Smi::Value(VariableDescAddr(scope_index)->token_pos)); } void ContextScope::SetTokenIndexAt(intptr_t scope_index, TokenPosition token_pos) const { StoreSmi(&VariableDescAddr(scope_index)->token_pos, - Smi::New(token_pos.value())); + Smi::New(token_pos.Serialize())); } TokenPosition ContextScope::DeclarationTokenIndexAt( intptr_t scope_index) const { - return TokenPosition( + return TokenPosition::Deserialize( Smi::Value(VariableDescAddr(scope_index)->declaration_token_pos)); } @@ -16829,7 +16817,7 @@ void ContextScope::SetDeclarationTokenIndexAt( intptr_t scope_index, TokenPosition declaration_token_pos) const { StoreSmi(&VariableDescAddr(scope_index)->declaration_token_pos, - Smi::New(declaration_token_pos.value())); + Smi::New(declaration_token_pos.Serialize())); } StringPtr ContextScope::NameAt(intptr_t scope_index) const { @@ -24238,13 +24226,14 @@ static void PrintSymbolicStackFrame(Zone* zone, intptr_t line = -1; intptr_t column = -1; - if (FLAG_precompiled_mode) { - line = token_pos.value(); - } else if (token_pos.IsSourcePosition()) { - ASSERT(!script.IsNull()); - script.GetTokenLocation(token_pos.SourcePosition(), &line, &column); + if (token_pos.IsReal()) { + if (FLAG_precompiled_mode) { + line = token_pos.Pos(); + } else { + ASSERT(!script.IsNull()); + script.GetTokenLocation(token_pos, &line, &column); + } } - PrintSymbolicStackFrameIndex(buffer, frame_index); PrintSymbolicStackFrameBody(buffer, function_name, url, line, column); } diff --git a/runtime/vm/object.h b/runtime/vm/object.h index aab845631bc..b94c5a3d51d 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -2954,7 +2954,7 @@ class Function : public Object { TokenPosition token_pos() const { #if defined(DART_PRECOMPILED_RUNTIME) - return TokenPosition(); + return TokenPosition::kNoSource; #else return raw_ptr()->token_pos_; #endif @@ -2963,7 +2963,7 @@ class Function : public Object { TokenPosition end_token_pos() const { #if defined(DART_PRECOMPILED_RUNTIME) - return TokenPosition(); + return TokenPosition::kNoSource; #else return raw_ptr()->end_token_pos_; #endif @@ -2976,6 +2976,9 @@ class Function : public Object { #endif } + // Returns the size of the source for this function. + intptr_t SourceSize() const; + intptr_t num_fixed_parameters() const { return FunctionLayout::PackedNumFixedParameters::decode( raw_ptr()->packed_fields_); @@ -4540,9 +4543,6 @@ class Script : public Object { void SetLocationOffset(intptr_t line_offset, intptr_t col_offset) const; - bool GetTokenLocationUsingLineStarts(TokenPosition token_pos, - intptr_t* line, - intptr_t* column) const; void GetTokenLocation(TokenPosition token_pos, intptr_t* line, intptr_t* column, @@ -5587,7 +5587,7 @@ class PcDescriptors : public Object { if (!FLAG_precompiled_mode) { cur_deopt_id_ += stream.ReadSLEB128(); - cur_token_pos_ += stream.ReadSLEB128(); + cur_token_pos_ += stream.ReadSLEB128(); } byte_index_ = stream.Position(); @@ -5600,7 +5600,9 @@ class PcDescriptors : public Object { uword PcOffset() const { return cur_pc_offset_; } intptr_t DeoptId() const { return cur_deopt_id_; } - TokenPosition TokenPos() const { return TokenPosition(cur_token_pos_); } + TokenPosition TokenPos() const { + return TokenPosition::Deserialize(cur_token_pos_); + } intptr_t TryIndex() const { return cur_try_index_; } intptr_t YieldIndex() const { return cur_yield_index_; } PcDescriptorsLayout::Kind Kind() const { @@ -5630,7 +5632,7 @@ class PcDescriptors : public Object { intptr_t cur_pc_offset_; intptr_t cur_kind_; intptr_t cur_deopt_id_; - intptr_t cur_token_pos_; + int32_t cur_token_pos_; intptr_t cur_try_index_; intptr_t cur_yield_index_; }; diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc index 1dfe634810e..459b2793f29 100644 --- a/runtime/vm/object_service.cc +++ b/runtime/vm/object_service.cc @@ -808,7 +808,7 @@ void ICData::PrintToJSONArray(const JSONArray& jsarray, JSONObject jsobj(&jsarray); jsobj.AddProperty("name", String::Handle(target_name()).ToCString()); - jsobj.AddProperty("tokenPos", token_pos.value()); + jsobj.AddProperty("tokenPos", static_cast(token_pos.Serialize())); // TODO(rmacnak): Figure out how to stringify DeoptReasons(). // jsobj.AddProperty("deoptReasons", ...); diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc index cc5e5c11d7d..fdd67840e99 100644 --- a/runtime/vm/object_test.cc +++ b/runtime/vm/object_test.cc @@ -2914,18 +2914,18 @@ ISOLATE_UNIT_TEST_CASE(PcDescriptors) { DescriptorList* builder = new DescriptorList(thread->zone()); // kind, pc_offset, deopt_id, token_pos, try_index, yield_index - builder->AddDescriptor(PcDescriptorsLayout::kOther, 10, 1, TokenPosition(20), - 1, 1); - builder->AddDescriptor(PcDescriptorsLayout::kDeopt, 20, 2, TokenPosition(30), - 0, -1); - builder->AddDescriptor(PcDescriptorsLayout::kOther, 30, 3, TokenPosition(40), - 1, 10); - builder->AddDescriptor(PcDescriptorsLayout::kOther, 10, 4, TokenPosition(40), - 2, 20); - builder->AddDescriptor(PcDescriptorsLayout::kOther, 10, 5, TokenPosition(80), - 3, 30); - builder->AddDescriptor(PcDescriptorsLayout::kOther, 80, 6, TokenPosition(150), - 3, 30); + builder->AddDescriptor(PcDescriptorsLayout::kOther, 10, 1, + TokenPosition::Deserialize(20), 1, 1); + builder->AddDescriptor(PcDescriptorsLayout::kDeopt, 20, 2, + TokenPosition::Deserialize(30), 0, -1); + builder->AddDescriptor(PcDescriptorsLayout::kOther, 30, 3, + TokenPosition::Deserialize(40), 1, 10); + builder->AddDescriptor(PcDescriptorsLayout::kOther, 10, 4, + TokenPosition::Deserialize(40), 2, 20); + builder->AddDescriptor(PcDescriptorsLayout::kOther, 10, 5, + TokenPosition::Deserialize(80), 3, 30); + builder->AddDescriptor(PcDescriptorsLayout::kOther, 80, 6, + TokenPosition::Deserialize(150), 3, 30); PcDescriptors& descriptors = PcDescriptors::Handle(); descriptors ^= builder->FinalizePcDescriptors(0); @@ -2945,7 +2945,7 @@ ISOLATE_UNIT_TEST_CASE(PcDescriptors) { EXPECT_EQ(true, iter.MoveNext()); EXPECT_EQ(1, iter.YieldIndex()); - EXPECT_EQ(20, iter.TokenPos().value()); + EXPECT_EQ(20, iter.TokenPos().Pos()); EXPECT_EQ(1, iter.TryIndex()); EXPECT_EQ(static_cast(10), iter.PcOffset()); EXPECT_EQ(1, iter.DeoptId()); @@ -2953,28 +2953,28 @@ ISOLATE_UNIT_TEST_CASE(PcDescriptors) { EXPECT_EQ(true, iter.MoveNext()); EXPECT_EQ(-1, iter.YieldIndex()); - EXPECT_EQ(30, iter.TokenPos().value()); + EXPECT_EQ(30, iter.TokenPos().Pos()); EXPECT_EQ(PcDescriptorsLayout::kDeopt, iter.Kind()); EXPECT_EQ(true, iter.MoveNext()); EXPECT_EQ(10, iter.YieldIndex()); - EXPECT_EQ(40, iter.TokenPos().value()); + EXPECT_EQ(40, iter.TokenPos().Pos()); EXPECT_EQ(true, iter.MoveNext()); EXPECT_EQ(20, iter.YieldIndex()); - EXPECT_EQ(40, iter.TokenPos().value()); + EXPECT_EQ(40, iter.TokenPos().Pos()); EXPECT_EQ(true, iter.MoveNext()); EXPECT_EQ(30, iter.YieldIndex()); - EXPECT_EQ(80, iter.TokenPos().value()); + EXPECT_EQ(80, iter.TokenPos().Pos()); EXPECT_EQ(true, iter.MoveNext()); EXPECT_EQ(30, iter.YieldIndex()); - EXPECT_EQ(150, iter.TokenPos().value()); + EXPECT_EQ(150, iter.TokenPos().Pos()); EXPECT_EQ(3, iter.TryIndex()); EXPECT_EQ(static_cast(80), iter.PcOffset()); - EXPECT_EQ(150, iter.TokenPos().value()); + EXPECT_EQ(150, iter.TokenPos().Pos()); EXPECT_EQ(PcDescriptorsLayout::kOther, iter.Kind()); EXPECT_EQ(false, iter.MoveNext()); @@ -2985,17 +2985,17 @@ ISOLATE_UNIT_TEST_CASE(PcDescriptorsLargeDeltas) { // kind, pc_offset, deopt_id, token_pos, try_index builder->AddDescriptor(PcDescriptorsLayout::kOther, 100, 1, - TokenPosition(200), 1, 10); + TokenPosition::Deserialize(200), 1, 10); builder->AddDescriptor(PcDescriptorsLayout::kDeopt, 200, 2, - TokenPosition(300), 0, -1); + TokenPosition::Deserialize(300), 0, -1); builder->AddDescriptor(PcDescriptorsLayout::kOther, 300, 3, - TokenPosition(400), 1, 10); - builder->AddDescriptor(PcDescriptorsLayout::kOther, 100, 4, TokenPosition(0), - 2, 20); + TokenPosition::Deserialize(400), 1, 10); + builder->AddDescriptor(PcDescriptorsLayout::kOther, 100, 4, + TokenPosition::Deserialize(0), 2, 20); builder->AddDescriptor(PcDescriptorsLayout::kOther, 100, 5, - TokenPosition(800), 3, 30); + TokenPosition::Deserialize(800), 3, 30); builder->AddDescriptor(PcDescriptorsLayout::kOther, 800, 6, - TokenPosition(150), 3, 30); + TokenPosition::Deserialize(150), 3, 30); PcDescriptors& descriptors = PcDescriptors::Handle(); descriptors ^= builder->FinalizePcDescriptors(0); @@ -3015,7 +3015,7 @@ ISOLATE_UNIT_TEST_CASE(PcDescriptorsLargeDeltas) { EXPECT_EQ(true, iter.MoveNext()); EXPECT_EQ(10, iter.YieldIndex()); - EXPECT_EQ(200, iter.TokenPos().value()); + EXPECT_EQ(200, iter.TokenPos().Pos()); EXPECT_EQ(1, iter.TryIndex()); EXPECT_EQ(static_cast(100), iter.PcOffset()); EXPECT_EQ(1, iter.DeoptId()); @@ -3023,28 +3023,28 @@ ISOLATE_UNIT_TEST_CASE(PcDescriptorsLargeDeltas) { EXPECT_EQ(true, iter.MoveNext()); EXPECT_EQ(-1, iter.YieldIndex()); - EXPECT_EQ(300, iter.TokenPos().value()); + EXPECT_EQ(300, iter.TokenPos().Pos()); EXPECT_EQ(PcDescriptorsLayout::kDeopt, iter.Kind()); EXPECT_EQ(true, iter.MoveNext()); EXPECT_EQ(10, iter.YieldIndex()); - EXPECT_EQ(400, iter.TokenPos().value()); + EXPECT_EQ(400, iter.TokenPos().Pos()); EXPECT_EQ(true, iter.MoveNext()); EXPECT_EQ(20, iter.YieldIndex()); - EXPECT_EQ(0, iter.TokenPos().value()); + EXPECT_EQ(0, iter.TokenPos().Pos()); EXPECT_EQ(true, iter.MoveNext()); EXPECT_EQ(30, iter.YieldIndex()); - EXPECT_EQ(800, iter.TokenPos().value()); + EXPECT_EQ(800, iter.TokenPos().Pos()); EXPECT_EQ(true, iter.MoveNext()); EXPECT_EQ(30, iter.YieldIndex()); - EXPECT_EQ(150, iter.TokenPos().value()); + EXPECT_EQ(150, iter.TokenPos().Pos()); EXPECT_EQ(3, iter.TryIndex()); EXPECT_EQ(static_cast(800), iter.PcOffset()); - EXPECT_EQ(150, iter.TokenPos().value()); + EXPECT_EQ(150, iter.TokenPos().Pos()); EXPECT_EQ(PcDescriptorsLayout::kOther, iter.Kind()); EXPECT_EQ(false, iter.MoveNext()); diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc index 4f88ae4ee98..d539a35eb14 100644 --- a/runtime/vm/profiler_service.cc +++ b/runtime/vm/profiler_service.cc @@ -174,7 +174,12 @@ void ProfileFunction::TickSourcePosition(TokenPosition token_position, intptr_t i = 0; for (; i < source_position_ticks_.length(); i++) { ProfileFunctionSourcePosition& position = source_position_ticks_[i]; - if (position.token_pos().value() == token_position.value()) { + const intptr_t cmp = + TokenPosition::CompareForSorting(position.token_pos(), token_position); + if (cmp > 0) { + // Found insertion point. + break; + } else if (cmp == 0) { if (FLAG_trace_profiler_verbose) { OS::PrintErr("Ticking source position %s %s\n", exclusive ? "exclusive" : "inclusive", @@ -184,9 +189,6 @@ void ProfileFunction::TickSourcePosition(TokenPosition token_position, position.Tick(exclusive); return; } - if (position.token_pos().value() > token_position.value()) { - break; - } } // Add new one, sorted by token position value. @@ -934,7 +936,7 @@ void ProfileCodeInlinedFunctionsCache::Add( if (cache_entry->inlined_functions.length() == 0) { *inlined_functions = NULL; *inlined_token_positions = NULL; - *token_position = cache_entry->token_position = TokenPosition(); + *token_position = cache_entry->token_position = TokenPosition::kNoSource; return; } diff --git a/runtime/vm/profiler_service.h b/runtime/vm/profiler_service.h index 0ad1e7f3e8b..a3d42a85a7e 100644 --- a/runtime/vm/profiler_service.h +++ b/runtime/vm/profiler_service.h @@ -115,7 +115,7 @@ class ProfileCodeInlinedFunctionsCache : public ZoneAllocated { intptr_t offset; GrowableArray inlined_functions; GrowableArray inlined_token_positions; - TokenPosition token_position; + TokenPosition token_position = TokenPosition::kNoSource; }; static const intptr_t kCacheSize = 128; diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc index 6c3589e5cac..048a8bfba76 100644 --- a/runtime/vm/profiler_test.cc +++ b/runtime/vm/profiler_test.cc @@ -282,13 +282,10 @@ class ProfileStackWalker { return NULL; } TokenPosition token_pos = pfsp.token_pos(); - if (!token_pos.IsSourcePosition()) { + if (!token_pos.IsReal()) { // Not a location in a script. return NULL; } - if (token_pos.IsSynthetic()) { - token_pos = token_pos.FromSynthetic(); - } intptr_t line = 0, column = 0, token_len = 0; script.GetTokenLocation(token_pos, &line, &column, &token_len); @@ -2315,10 +2312,10 @@ ISOLATE_UNIT_TEST_CASE(Profiler_GetSourceReport) { "}\n"; // Token position of * in `i * i`. - const TokenPosition squarePosition = TokenPosition(19); + const TokenPosition squarePosition = TokenPosition::Deserialize(19); // Token position of the call to `doWork`. - const TokenPosition callPosition = TokenPosition(95); + const TokenPosition callPosition = TokenPosition::Deserialize(95); DisableNativeProfileScope dnps; // Disable profiling for this thread. diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 19a19347ec6..fd85941af03 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -1919,9 +1919,12 @@ class LocalVarDescriptorsLayout : public ObjectLayout { struct VarInfo { int32_t index_kind = 0; // Bitfield for slot index on stack or in context, // and Entry kind of type VarInfoKind. - TokenPosition declaration_pos; // Token position of declaration. - TokenPosition begin_pos; // Token position of scope start. - TokenPosition end_pos; // Token position of scope end. + TokenPosition declaration_pos = + TokenPosition::kNoSource; // Token position of declaration. + TokenPosition begin_pos = + TokenPosition::kNoSource; // Token position of scope start. + TokenPosition end_pos = + TokenPosition::kNoSource; // Token position of scope end. int16_t scope_id; // Scope to which the variable belongs. VarInfoKind kind() const { diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc index 853c1cac364..639d14983b6 100644 --- a/runtime/vm/raw_object_snapshot.cc +++ b/runtime/vm/raw_object_snapshot.cc @@ -87,7 +87,7 @@ TypePtr Type::ReadFrom(SnapshotReader* reader, reader->AddBackRef(object_id, &type, kIsDeserialized); // Set all non object fields. - type.set_token_pos(TokenPosition::SnapshotDecode(reader->Read())); + type.set_token_pos(TokenPosition::Deserialize(reader->Read())); const uint8_t combined = reader->Read(); type.set_type_state(combined >> 4); type.set_nullability(static_cast(combined & 0xf)); @@ -160,7 +160,7 @@ void TypeLayout::WriteTo(SnapshotWriter* writer, writer->Write(typeclass_is_in_fullsnapshot); // Write out all the non object pointer fields. - writer->Write(token_pos_.SnapshotEncode()); + writer->Write(token_pos_.Serialize()); const uint8_t combined = (type_state_ << 4) | nullability_; ASSERT(type_state_ == (combined >> 4)); ASSERT(nullability_ == (combined & 0xf)); @@ -234,7 +234,7 @@ TypeParameterPtr TypeParameter::ReadFrom(SnapshotReader* reader, // Set all non object fields. type_parameter.set_token_pos( - TokenPosition::SnapshotDecode(reader->Read())); + TokenPosition::Deserialize(reader->Read())); type_parameter.set_index(reader->Read()); const uint8_t combined = reader->Read(); type_parameter.set_flags(combined >> 4); @@ -285,7 +285,7 @@ void TypeParameterLayout::WriteTo(SnapshotWriter* writer, writer->WriteTags(writer->GetObjectTags(this)); // Write out all the non object pointer fields. - writer->Write(token_pos_.SnapshotEncode()); + writer->Write(token_pos_.Serialize()); writer->Write(index_); const uint8_t combined = (flags_ << 4) | nullability_; ASSERT(flags_ == (combined >> 4)); @@ -637,7 +637,7 @@ LanguageErrorPtr LanguageError::ReadFrom(SnapshotReader* reader, // Set all non object fields. language_error.set_token_pos( - TokenPosition::SnapshotDecode(reader->Read())); + TokenPosition::Deserialize(reader->Read())); language_error.set_report_after_token(reader->Read()); language_error.set_kind(reader->Read()); @@ -662,7 +662,7 @@ void LanguageErrorLayout::WriteTo(SnapshotWriter* writer, writer->WriteTags(writer->GetObjectTags(this)); // Write out all the non object fields. - writer->Write(token_pos_.SnapshotEncode()); + writer->Write(token_pos_.Serialize()); writer->Write(report_after_token_); writer->Write(kind_); diff --git a/runtime/vm/scopes.cc b/runtime/vm/scopes.cc index c84dc2630b7..155ac8e4bc7 100644 --- a/runtime/vm/scopes.cc +++ b/runtime/vm/scopes.cc @@ -32,8 +32,8 @@ LocalScope::LocalScope(LocalScope* parent, int function_level, int loop_level) function_level_(function_level), loop_level_(loop_level), context_level_(LocalScope::kUninitializedContextLevel), - begin_token_pos_(TokenPosition::kNoSourcePos), - end_token_pos_(TokenPosition::kNoSourcePos), + begin_token_pos_(TokenPosition::kNoSource), + end_token_pos_(TokenPosition::kNoSource), variables_(), labels_(), context_variables_(), @@ -779,8 +779,9 @@ void LocalVarDescriptorsBuilder::AddDeoptIdToContextLevelMappings( desc.name = &Symbols::Empty(); // No name. desc.info.set_kind(LocalVarDescriptorsLayout::kContextLevel); desc.info.scope_id = 0; - desc.info.begin_pos = TokenPosition(start_deopt_id); - desc.info.end_pos = TokenPosition(end_deopt_id); + // We repurpose the token position fields to store deopt IDs in this case. + desc.info.begin_pos = TokenPosition::Deserialize(start_deopt_id); + desc.info.end_pos = TokenPosition::Deserialize(end_deopt_id); desc.info.set_index(start_context_level); Add(desc); diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc index 6a674bba3e2..6118c2bfda3 100644 --- a/runtime/vm/service.cc +++ b/runtime/vm/service.cc @@ -3283,8 +3283,8 @@ static bool GetSourceReport(Thread* thread, JSONStream* js) { } } SourceReport report(report_set, compile_mode); - report.PrintJSON(js, script, TokenPosition(start_pos), - TokenPosition(end_pos)); + report.PrintJSON(js, script, TokenPosition::Deserialize(start_pos), + TokenPosition::Deserialize(end_pos)); return true; #endif // !DART_PRECOMPILED_RUNTIME } diff --git a/runtime/vm/source_report.cc b/runtime/vm/source_report.cc index b52f017f80b..d065499f9da 100644 --- a/runtime/vm/source_report.cc +++ b/runtime/vm/source_report.cc @@ -26,8 +26,8 @@ SourceReport::SourceReport(intptr_t report_set, CompileMode compile_mode) compile_mode_(compile_mode), thread_(NULL), script_(NULL), - start_pos_(TokenPosition::kNoSource), - end_pos_(TokenPosition::kNoSource), + start_pos_(TokenPosition::kMinSource), + end_pos_(TokenPosition::kMaxSource), profile_(Isolate::Current()), next_script_index_(0) {} @@ -51,8 +51,8 @@ void SourceReport::Init(Thread* thread, TokenPosition end_pos) { thread_ = thread; script_ = script; - start_pos_ = start_pos; - end_pos_ = end_pos; + start_pos_ = TokenPosition::Max(start_pos, TokenPosition::kMinSource); + end_pos_ = TokenPosition::Min(end_pos, TokenPosition::kMaxSource); ClearScriptTable(); if (IsReportRequested(kProfile)) { // Build the profile. @@ -79,10 +79,7 @@ bool SourceReport::ShouldSkipFunction(const Function& func) { // The function is from the wrong script. return true; } - if (((start_pos_ > TokenPosition::kMinSource) && - (func.end_token_pos() < start_pos_)) || - ((end_pos_ > TokenPosition::kMinSource) && - (func.token_pos() > end_pos_))) { + if ((func.end_token_pos() < start_pos_) || (func.token_pos() > end_pos_)) { // The function does not intersect with the requested token range. return true; } @@ -129,10 +126,8 @@ bool SourceReport::ShouldSkipField(const Field& field) { // The field is from the wrong script. return true; } - if (((start_pos_ > TokenPosition::kMinSource) && - (field.end_token_pos() < start_pos_)) || - ((end_pos_ > TokenPosition::kMinSource) && - (field.token_pos() > end_pos_))) { + if ((field.end_token_pos() < start_pos_) || + (field.token_pos() > end_pos_)) { // The field does not intersect with the requested token range. return true; } @@ -195,9 +190,8 @@ void SourceReport::PrintCallSitesData(JSONObject* jsobj, const Function& function, const Code& code) { ASSERT(!code.IsNull()); - const TokenPosition begin_pos = function.token_pos(); - const TokenPosition end_pos = function.end_token_pos(); - + const TokenPosition& begin_pos = function.token_pos(); + const TokenPosition& end_pos = function.end_token_pos(); ZoneGrowableArray* ic_data_array = new (zone()) ZoneGrowableArray(); function.RestoreICDataMap(ic_data_array, false /* clone ic-data */); @@ -214,8 +208,8 @@ void SourceReport::PrintCallSitesData(JSONObject* jsobj, ASSERT(iter.DeoptId() < ic_data_array->length()); const ICData* ic_data = (*ic_data_array)[iter.DeoptId()]; if (ic_data != NULL) { - const TokenPosition token_pos = iter.TokenPos(); - if ((token_pos < begin_pos) || (token_pos > end_pos)) { + const TokenPosition& token_pos = iter.TokenPos(); + if (!token_pos.IsWithin(begin_pos, end_pos)) { // Does not correspond to a valid source position. continue; } @@ -228,8 +222,8 @@ void SourceReport::PrintCoverageData(JSONObject* jsobj, const Function& function, const Code& code) { ASSERT(!code.IsNull()); - const TokenPosition begin_pos = function.token_pos(); - const TokenPosition end_pos = function.end_token_pos(); + const TokenPosition& begin_pos = function.token_pos(); + const TokenPosition& end_pos = function.end_token_pos(); ZoneGrowableArray* ic_data_array = new (zone()) ZoneGrowableArray(); @@ -241,7 +235,7 @@ void SourceReport::PrintCoverageData(JSONObject* jsobj, const int kCoverageMiss = 1; const int kCoverageHit = 2; - intptr_t func_length = (end_pos.Pos() - begin_pos.Pos()) + 1; + intptr_t func_length = function.SourceSize() + 1; GrowableArray coverage(func_length); coverage.SetLength(func_length); for (int i = 0; i < func_length; i++) { @@ -262,8 +256,8 @@ void SourceReport::PrintCoverageData(JSONObject* jsobj, ASSERT(iter.DeoptId() < ic_data_array->length()); const ICData* ic_data = (*ic_data_array)[iter.DeoptId()]; if (ic_data != NULL) { - const TokenPosition token_pos = iter.TokenPos(); - if ((token_pos < begin_pos) || (token_pos > end_pos)) { + const TokenPosition& token_pos = iter.TokenPos(); + if (!token_pos.IsWithin(begin_pos, end_pos)) { // Does not correspond to a valid source position. continue; } @@ -303,9 +297,9 @@ void SourceReport::PrintCoverageData(JSONObject* jsobj, void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj, const Function& func, const Code& code) { - const TokenPosition begin_pos = func.token_pos(); - const TokenPosition end_pos = func.end_token_pos(); - intptr_t func_length = (end_pos.Pos() - begin_pos.Pos()) + 1; + const TokenPosition& begin_pos = func.token_pos(); + const TokenPosition& end_pos = func.end_token_pos(); + intptr_t func_length = func.SourceSize() + 1; BitVector possible(zone(), func_length); @@ -320,8 +314,8 @@ void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj, PcDescriptors::Iterator iter(descriptors, kSafepointKind); while (iter.MoveNext()) { - const TokenPosition token_pos = iter.TokenPos(); - if ((token_pos < begin_pos) || (token_pos > end_pos)) { + const TokenPosition& token_pos = iter.TokenPos(); + if (!token_pos.IsWithin(begin_pos, end_pos)) { // Does not correspond to a valid source position. continue; } @@ -357,7 +351,7 @@ void SourceReport::PrintProfileData(JSONObject* jsobj, for (intptr_t i = 0; i < profile_function->NumSourcePositions(); i++) { const ProfileFunctionSourcePosition& position = profile_function->GetSourcePosition(i); - if (position.token_pos().IsSourcePosition()) { + if (position.token_pos().IsReal()) { // Add as an integer. positions.AddValue(position.token_pos().Pos()); } else { diff --git a/runtime/vm/source_report.h b/runtime/vm/source_report.h index 4ec20c9f1c8..246f64a83f7 100644 --- a/runtime/vm/source_report.h +++ b/runtime/vm/source_report.h @@ -47,8 +47,8 @@ class SourceReport { // in the isolate. void PrintJSON(JSONStream* js, const Script& script, - TokenPosition start_pos = TokenPosition::kNoSource, - TokenPosition end_pos = TokenPosition::kNoSource); + TokenPosition start_pos = TokenPosition::kMinSource, + TokenPosition end_pos = TokenPosition::kMaxSource); private: void ClearScriptTable(); diff --git a/runtime/vm/token_position.cc b/runtime/vm/token_position.cc index 0f8ae68a0ff..507a528d188 100644 --- a/runtime/vm/token_position.cc +++ b/runtime/vm/token_position.cc @@ -4,34 +4,29 @@ #include "vm/token_position.h" +#include "vm/hash.h" #include "vm/object.h" +#include "vm/zone_text_buffer.h" namespace dart { -TokenPosition TokenPosition::SnapshotDecode(int32_t value) { - return TokenPosition(static_cast(value)); +intptr_t TokenPosition::Hash() const { + return FinalizeHash(value_, 31); } -int32_t TokenPosition::SnapshotEncode() { +TokenPosition TokenPosition::Deserialize(int32_t value) { + return TokenPosition(value); +} + +int32_t TokenPosition::Serialize() const { return static_cast(value_); } -bool TokenPosition::IsSynthetic() const { - if (value_ >= kMinSourcePos) { - return false; - } - if (value_ < kLast.value()) { - return true; - } - return false; -} - #define DEFINE_VALUES(name, value) \ const TokenPosition TokenPosition::k##name(value); SENTINEL_TOKEN_DESCRIPTORS(DEFINE_VALUES); #undef DEFINE_VALUES const TokenPosition TokenPosition::kMinSource(kMinSourcePos); - const TokenPosition TokenPosition::kMaxSource(kMaxSourcePos); const char* TokenPosition::ToCString() const { @@ -41,17 +36,16 @@ const char* TokenPosition::ToCString() const { return #name; SENTINEL_TOKEN_DESCRIPTORS(DEFINE_CASE); #undef DEFINE_CASE - default: { - Zone* zone = Thread::Current()->zone(); - ASSERT(zone != NULL); - if (IsSynthetic()) { - // TODO(johnmccutchan): Print synthetic positions differently. - return FromSynthetic().ToCString(); - } else { - return OS::SCreate(zone, "%d", value_); - } - } + default: + break; } + ASSERT(IsReal() || IsSynthetic()); + ZoneTextBuffer buffer(Thread::Current()->zone()); + if (IsSynthetic()) { + buffer.AddString("syn:"); + } + buffer.Printf("%" Pd32 "", value_); + return buffer.buffer(); } } // namespace dart diff --git a/runtime/vm/token_position.h b/runtime/vm/token_position.h index 270a14c0229..d15553e1a1b 100644 --- a/runtime/vm/token_position.h +++ b/runtime/vm/token_position.h @@ -17,14 +17,26 @@ namespace dart { // ClassifyingTokenPositions 1 -> -1 - 1 // ClassifyingTokenPositions N -> -1 - N // -// Synthetically created AstNodes are given real source positions but encoded -// as negative numbers from [kSmiMin32, -1 - N]. For example: +// Real token positions represent source offsets in some script, and are encoded +// as non-negative values which are equal to that offset. // -// A source position of 0 in a synthetic AstNode would be encoded as -2 - N. -// A source position of 1 in a synthetic AstNode would be encoded as -3 - N. +// Synthetically created functions that correspond to user code are given +// starting token positions unique from other synthetic functions. The value for +// these token positions encode a unique non-negative value as a negative number +// within [kSmiMin32, -1 - N). // -// All other AstNodes are given real source positions encoded as positive -// integers. +// For example: +// A synthetic token with value 0 is encoded as ((-1 - N) - (0 + 1)) = -2 - N. +// A synthetic token with value 1 is encoded as ((-1 - N) - (1 + 1)) = -3 - N. +// +// Note that the encoded value is _not_ related to any possible real token +// position, as two real token positions for different scripts can have the same +// value and thus cannot serve as a unique nonce for a synthetic node. +// +// All other nodes read from user code, such as non-synthetic functions, fields, +// etc., are given real starting token positions. All nodes coming from user +// code, both real or synthetic, with ending token positions have real ending +// token positions. // // This organization allows for ~1 billion token positions. @@ -44,56 +56,112 @@ namespace dart { V(DartCodeEpilogue, -13) \ V(Last, -14) // Always keep this at the end. -// A token position representing a debug safe source (real) position, -// non-debug safe source (synthetic) positions, or a classifying value used +// A token position represents either a debug safe source (real) position, +// non-debug safe unique (synthetic) position, or a classifying value used // by the profiler. class TokenPosition { public: - TokenPosition() : value_(kNoSource.value()) {} - - explicit TokenPosition(intptr_t value) : value_(value) {} + intptr_t Hash() const; + // Returns whether the token positions are equal. Defined for all token + // positions. bool operator==(const TokenPosition& b) const { return value() == b.value(); } + // Returns whether the token positions are not equal. Defined for all token + // positions. bool operator!=(const TokenPosition& b) const { return !(*this == b); } - bool operator<(const TokenPosition& b) const { - // TODO(johnmccutchan): Assert that this is a source position. - return value() < b.value(); + // Returns whether the token position is less than [b]. Only defined for + // real token positions. + inline bool operator<(const TokenPosition& b) const { + return Pos() < b.Pos(); } - bool operator>(const TokenPosition& b) const { - // TODO(johnmccutchan): Assert that this is a source position. - return b < *this; + // Returns whether the token position is greater than [b]. Only defined for + // real token positions. + inline bool operator>(const TokenPosition& b) const { return b < *this; } + + // Returns whether the token position is less than or equal to [b]. Only + // defined for real token positions. + inline bool operator<=(const TokenPosition& b) const { return !(*this > b); } + + // Returns whether the token position is greater than or equal to [b]. Only + // defined for real token positions. + inline bool operator>=(const TokenPosition& b) const { return !(*this < b); } + + // For real token positions, returns whether this is between [a] and [b], + // inclusive. If [a] or [b] is non-real, they are treated as less than + // any real token position. + // + // For synthetic token positions, returns whether [a] or [b] equals this. + // + // For other token positions, always returns false. + bool IsWithin(const TokenPosition& a, const TokenPosition& b) const { + if (IsReal()) return (a.value() <= value()) && (value() <= b.value()); + if (IsSynthetic()) return (a == *this) || (b == *this); + return false; } - bool operator<=(const TokenPosition& b) { - // TODO(johnmccutchan): Assert that this is a source position. - return !(*this > b); + // Returns [a] if both positions are not real, the real position if only one + // of [a] and [b] is real, or the minimum position of [a] and [b]. + static const TokenPosition& Min(const TokenPosition& a, + const TokenPosition& b) { + if (!b.IsReal()) return a; + if (!a.IsReal()) return b; + return b.value() < a.value() ? b : a; + } + // Returns [a] if both positions are not real, the real position if only one + // of [a] and [b] is real, or the maximum position of [a] and [b]. + static const TokenPosition& Max(const TokenPosition& a, + const TokenPosition& b) { + if (!b.IsReal()) return a; + if (!a.IsReal()) return b; + return b.value() > a.value() ? b : a; } - bool operator>=(const TokenPosition& b) { - // TODO(johnmccutchan): Assert that this is a source position. - return !(*this < b); + // Compares two arbitrary source positions for use in sorting, where a + // negative return means [a] sorts before [b], a return of 0 means [a] is the + // same as [b], and a positive return means [a] sorts after [b]. + // + // Does _not_ correspond to the relational operators on token positions, as + // this also allows comparison of kNoSource, classifying, and synthetic token + // positions to each other. + static intptr_t CompareForSorting(const TokenPosition& a, + const TokenPosition& b) { + return a.value() - b.value(); } - static const intptr_t kMaxSentinelDescriptors = 64; + static constexpr int32_t kMaxSentinelDescriptors = 64; #define DECLARE_VALUES(name, value) \ - static const intptr_t k##name##Pos = value; \ + static constexpr int32_t k##name##Pos = value; \ static const TokenPosition k##name; SENTINEL_TOKEN_DESCRIPTORS(DECLARE_VALUES); #undef DECLARE_VALUES - static const intptr_t kMinSourcePos = 0; + // Check assumptions used in Is methods below. +#define CHECK_VALUES(name, value) \ + static_assert(k##name##Pos < 0, "Non-negative sentinel descriptor"); \ + static_assert( \ + k##name##Pos == kNoSourcePos || k##name##Pos <= kBoxPos, \ + "Box sentinel descriptor is not greatest classifying sentinel value"); \ + static_assert(kLastPos <= k##name##Pos, \ + "Last sentinel descriptor is not least sentinel valu"); \ + SENTINEL_TOKEN_DESCRIPTORS(CHECK_VALUES); +#undef CHECK_VALUES + static_assert(kLastPos > -kMaxSentinelDescriptors, + "More sentinel descriptors than expected"); + + static constexpr int32_t kMinSourcePos = 0; static const TokenPosition kMinSource; - static const intptr_t kMaxSourcePos = kSmiMax32 - kMaxSentinelDescriptors - 2; + static constexpr int32_t kMaxSourcePos = + kSmiMax32 - kMaxSentinelDescriptors - 2; static const TokenPosition kMaxSource; - // Decode from a snapshot. - static TokenPosition SnapshotDecode(int32_t value); + // Decode from a serialized form. + static TokenPosition Deserialize(int32_t value); - // Encode for writing into a snapshot. - int32_t SnapshotEncode(); + // Encode into a serialized form. + int32_t Serialize() const; // Given a real token position, returns the next real token position. TokenPosition Next() { @@ -101,88 +169,47 @@ class TokenPosition { return TokenPosition(value_ + 1); } - // The raw value. - // TODO(johnmccutchan): Make this private. - intptr_t value() const { return value_; } - - // Return the source position. - intptr_t Pos() const { - if (IsSynthetic()) { - return FromSynthetic().Pos(); - } + // Return the source position for real token positions. + inline intptr_t Pos() const { + ASSERT(IsReal()); return value_; } // Is |this| a classifying sentinel source position? // Classifying positions are used by the profiler to group instructions whose // cost isn't naturally attributable to a source location. - bool IsClassifying() const { + inline bool IsClassifying() const { return (value_ >= kBox.value()) && (value_ <= kLast.value()); } // Is |this| the no source position sentinel? - bool IsNoSource() const { return *this == kNoSource; } + inline bool IsNoSource() const { return value_ == kNoSourcePos; } // Is |this| a synthetic source position? // Synthetic source positions are used by the profiler to attribute ticks to a // pieces of source, but ignored by the debugger as potential breakpoints. - bool IsSynthetic() const; + inline bool IsSynthetic() const { return value_ < kLastPos; } // Is |this| a real source position? - bool IsReal() const { return value_ >= kMinSourcePos; } - - // Is |this| a source position? - bool IsSourcePosition() const { return IsReal() || IsSynthetic(); } - - // Convert |this| into a real source position. Sentinel values remain - // unchanged. - TokenPosition SourcePosition() const { return FromSynthetic(); } + inline bool IsReal() const { return value_ >= kMinSourcePos; } // Is |this| a debug pause source position? - bool IsDebugPause() const { - // Sanity check some values here. - ASSERT(kNoSource.value() == kNoSourcePos); - ASSERT(kLast.value() < kNoSource.value()); - ASSERT(kLast.value() > -kMaxSentinelDescriptors); - return IsReal(); - } + inline bool IsDebugPause() const { return IsReal(); } - // Convert |this| into a synthetic source position. Sentinel values remain - // unchanged. - TokenPosition ToSynthetic() const { - const intptr_t value = value_; - if (IsClassifying() || IsNoSource()) { - return *this; - } - if (IsSynthetic()) { - return *this; - } - const TokenPosition synthetic_value = - TokenPosition((kLast.value() - 1) - value); - ASSERT(synthetic_value.IsSynthetic()); - ASSERT(synthetic_value.value() < kLast.value()); - return synthetic_value; - } - - // Convert |this| from a synthetic source position. Sentinel values remain - // unchanged. - TokenPosition FromSynthetic() const { - const intptr_t synthetic_value = value_; - if (IsClassifying() || IsNoSource()) { - return *this; - } - if (!IsSynthetic()) { - return *this; - } - const TokenPosition value = - TokenPosition(-synthetic_value + (kLast.value() - 1)); - ASSERT(!value.IsSynthetic()); - return value; + // Creates a synthetic source position from a non-negative value. + static TokenPosition Synthetic(intptr_t value) { + ASSERT(value >= 0 && value <= kMaxSourcePos); + return TokenPosition((kLastPos - 1) - value); } const char* ToCString() const; private: + explicit TokenPosition(intptr_t value) : value_(value) {} + + // The raw value of this TokenPosition. + intptr_t value() const { return value_; } + int32_t value_; DISALLOW_ALLOCATION();