OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/service.h" | 5 #include "vm/service.h" |
6 | 6 |
7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
8 #include "platform/globals.h" | 8 #include "platform/globals.h" |
9 | 9 |
10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 return zone->PrintToString("objects/%" Pd "", id); | 67 return zone->PrintToString("objects/%" Pd "", id); |
68 } | 68 } |
69 | 69 |
70 | 70 |
71 // TODO(johnmccutchan): Unify embedder service handler lists and their APIs. | 71 // TODO(johnmccutchan): Unify embedder service handler lists and their APIs. |
72 EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL; | 72 EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL; |
73 EmbedderServiceHandler* Service::root_service_handler_head_ = NULL; | 73 EmbedderServiceHandler* Service::root_service_handler_head_ = NULL; |
74 struct ServiceMethodDescriptor; | 74 struct ServiceMethodDescriptor; |
75 ServiceMethodDescriptor* FindMethod(const char* method_name); | 75 ServiceMethodDescriptor* FindMethod(const char* method_name); |
76 | 76 |
| 77 // TODO(turnidge): Build a general framework later. For now, we have |
| 78 // a small set of well-known streams. |
| 79 bool Service::needs_isolate_events_ = false; |
| 80 bool Service::needs_debug_events_ = false; |
| 81 bool Service::needs_gc_events_ = false; |
| 82 bool Service::needs_echo_events_ = false; |
| 83 bool Service::needs_graph_events_ = false; |
| 84 |
| 85 void Service::ListenStream(const char* stream_id) { |
| 86 if (FLAG_trace_service) { |
| 87 OS::Print("vm-service: starting stream '%s'\n", |
| 88 stream_id); |
| 89 } |
| 90 if (strcmp(stream_id, "Isolate") == 0) { |
| 91 needs_isolate_events_ = true; |
| 92 } else if (strcmp(stream_id, "Debug") == 0) { |
| 93 needs_debug_events_ = true; |
| 94 } else if (strcmp(stream_id, "GC") == 0) { |
| 95 needs_gc_events_ = true; |
| 96 } else if (strcmp(stream_id, "_Echo") == 0) { |
| 97 needs_echo_events_ = true; |
| 98 } else if (strcmp(stream_id, "_Graph") == 0) { |
| 99 needs_graph_events_ = true; |
| 100 } else { |
| 101 UNREACHABLE(); |
| 102 } |
| 103 } |
| 104 |
| 105 void Service::CancelStream(const char* stream_id) { |
| 106 if (FLAG_trace_service) { |
| 107 OS::Print("vm-service: stopping stream '%s'\n", |
| 108 stream_id); |
| 109 } |
| 110 if (strcmp(stream_id, "Isolate") == 0) { |
| 111 needs_isolate_events_ = false; |
| 112 } else if (strcmp(stream_id, "Debug") == 0) { |
| 113 needs_debug_events_ = false; |
| 114 } else if (strcmp(stream_id, "GC") == 0) { |
| 115 needs_gc_events_ = false; |
| 116 } else if (strcmp(stream_id, "_Echo") == 0) { |
| 117 needs_echo_events_ = false; |
| 118 } else if (strcmp(stream_id, "_Graph") == 0) { |
| 119 needs_graph_events_ = false; |
| 120 } else { |
| 121 UNREACHABLE(); |
| 122 } |
| 123 } |
| 124 |
77 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { | 125 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { |
78 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); | 126 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); |
79 return reinterpret_cast<uint8_t*>(new_ptr); | 127 return reinterpret_cast<uint8_t*>(new_ptr); |
80 } | 128 } |
81 | 129 |
82 static void PrintMissingParamError(JSONStream* js, | 130 static void PrintMissingParamError(JSONStream* js, |
83 const char* param) { | 131 const char* param) { |
84 js->PrintError(kInvalidParams, | 132 js->PrintError(kInvalidParams, |
85 "%s expects the '%s' parameter", js->method(), param); | 133 "%s expects the '%s' parameter", js->method(), param); |
86 } | 134 } |
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 InvokeMethod(isolate, msg_instance); | 538 InvokeMethod(isolate, msg_instance); |
491 } | 539 } |
492 | 540 |
493 | 541 |
494 void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) { | 542 void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) { |
495 ASSERT(isolate != NULL); | 543 ASSERT(isolate != NULL); |
496 InvokeMethod(isolate, msg); | 544 InvokeMethod(isolate, msg); |
497 } | 545 } |
498 | 546 |
499 | 547 |
500 bool Service::NeedsEvents() { | 548 void Service::SendEvent(const char* stream_id, |
501 return ServiceIsolate::IsRunning(); | 549 const char* event_type, |
502 } | 550 const Object& event_message) { |
503 | |
504 | |
505 void Service::SendEvent(intptr_t eventType, | |
506 const Object& eventMessage) { | |
507 ASSERT(!ServiceIsolate::IsServiceIsolateDescendant(Isolate::Current())); | 551 ASSERT(!ServiceIsolate::IsServiceIsolateDescendant(Isolate::Current())); |
508 if (!ServiceIsolate::IsRunning()) { | 552 if (!ServiceIsolate::IsRunning()) { |
509 return; | 553 return; |
510 } | 554 } |
511 Isolate* isolate = Isolate::Current(); | 555 Isolate* isolate = Isolate::Current(); |
512 ASSERT(isolate != NULL); | 556 ASSERT(isolate != NULL); |
513 HANDLESCOPE(isolate); | 557 HANDLESCOPE(isolate); |
514 | 558 |
| 559 const Array& list = Array::Handle(Array::New(2)); |
| 560 ASSERT(!list.IsNull()); |
| 561 const String& stream_id_str = String::Handle(String::New(stream_id)); |
| 562 list.SetAt(0, stream_id_str); |
| 563 list.SetAt(1, event_message); |
| 564 |
515 // Push the event to port_. | 565 // Push the event to port_. |
516 uint8_t* data = NULL; | 566 uint8_t* data = NULL; |
517 MessageWriter writer(&data, &allocator, false); | 567 MessageWriter writer(&data, &allocator, false); |
518 writer.WriteMessage(eventMessage); | 568 writer.WriteMessage(list); |
519 intptr_t len = writer.BytesWritten(); | 569 intptr_t len = writer.BytesWritten(); |
520 if (FLAG_trace_service) { | 570 if (FLAG_trace_service) { |
521 OS::Print("vm-service: Pushing event of type %" Pd ", len %" Pd "\n", | 571 OS::Print( |
522 eventType, len); | 572 "vm-service: Pushing event of type %s to stream %s, len %" Pd "\n", |
| 573 event_type, stream_id, len); |
523 } | 574 } |
524 // TODO(turnidge): For now we ignore failure to send an event. Revisit? | 575 // TODO(turnidge): For now we ignore failure to send an event. Revisit? |
525 PortMap::PostMessage( | 576 PortMap::PostMessage( |
526 new Message(ServiceIsolate::Port(), data, len, Message::kNormalPriority)); | 577 new Message(ServiceIsolate::Port(), data, len, Message::kNormalPriority)); |
527 } | 578 } |
528 | 579 |
529 | 580 |
530 void Service::SendEvent(const String& meta, | 581 void Service::SendEventWithData(const char* stream_id, |
531 const uint8_t* data, | 582 const char* event_type, |
532 intptr_t size) { | 583 const String& meta, |
| 584 const uint8_t* data, |
| 585 intptr_t size) { |
533 // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data] | 586 // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data] |
534 const intptr_t meta_bytes = Utf8::Length(meta); | 587 const intptr_t meta_bytes = Utf8::Length(meta); |
535 const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size; | 588 const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size; |
536 const TypedData& message = TypedData::Handle( | 589 const TypedData& message = TypedData::Handle( |
537 TypedData::New(kTypedDataUint8ArrayCid, total_bytes)); | 590 TypedData::New(kTypedDataUint8ArrayCid, total_bytes)); |
538 intptr_t offset = 0; | 591 intptr_t offset = 0; |
539 // TODO(koda): Rename these methods SetHostUint64, etc. | 592 // TODO(koda): Rename these methods SetHostUint64, etc. |
540 message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes)); | 593 message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes)); |
541 offset += sizeof(uint64_t); | 594 offset += sizeof(uint64_t); |
542 { | 595 { |
543 NoSafepointScope no_safepoint; | 596 NoSafepointScope no_safepoint; |
544 meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes); | 597 meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes); |
545 offset += meta_bytes; | 598 offset += meta_bytes; |
546 } | 599 } |
547 // TODO(koda): It would be nice to avoid this copy (requires changes to | 600 // TODO(koda): It would be nice to avoid this copy (requires changes to |
548 // MessageWriter code). | 601 // MessageWriter code). |
549 { | 602 { |
550 NoSafepointScope no_safepoint; | 603 NoSafepointScope no_safepoint; |
551 memmove(message.DataAddr(offset), data, size); | 604 memmove(message.DataAddr(offset), data, size); |
552 offset += size; | 605 offset += size; |
553 } | 606 } |
554 ASSERT(offset == total_bytes); | 607 ASSERT(offset == total_bytes); |
555 // TODO(turnidge): Pass the real eventType here. | 608 SendEvent(stream_id, event_type, message); |
556 SendEvent(0, message); | |
557 } | 609 } |
558 | 610 |
559 | 611 |
560 void Service::HandleEvent(ServiceEvent* event) { | 612 void Service::HandleEvent(ServiceEvent* event) { |
561 if (ServiceIsolate::IsServiceIsolateDescendant(event->isolate())) { | 613 if (ServiceIsolate::IsServiceIsolateDescendant(event->isolate())) { |
562 return; | 614 return; |
563 } | 615 } |
564 JSONStream js; | 616 JSONStream js; |
| 617 const char* stream_id = event->stream_id(); |
| 618 ASSERT(stream_id != NULL); |
565 { | 619 { |
566 JSONObject jsobj(&js); | 620 JSONObject jsobj(&js); |
567 jsobj.AddProperty("event", event); | 621 jsobj.AddProperty("event", event); |
| 622 jsobj.AddProperty("streamId", stream_id); |
568 } | 623 } |
569 const String& message = String::Handle(String::New(js.ToCString())); | 624 const String& message = String::Handle(String::New(js.ToCString())); |
570 SendEvent(event->type(), message); | 625 SendEvent(stream_id, ServiceEvent::EventTypeToCString(event->type()), |
| 626 message); |
571 } | 627 } |
572 | 628 |
573 | 629 |
574 class EmbedderServiceHandler { | 630 class EmbedderServiceHandler { |
575 public: | 631 public: |
576 explicit EmbedderServiceHandler(const char* name) : name_(NULL), | 632 explicit EmbedderServiceHandler(const char* name) : name_(NULL), |
577 callback_(NULL), | 633 callback_(NULL), |
578 user_data_(NULL), | 634 user_data_(NULL), |
579 next_(NULL) { | 635 next_(NULL) { |
580 ASSERT(name != NULL); | 636 ASSERT(name != NULL); |
(...skipping 28 matching lines...) Expand all Loading... |
609 EmbedderServiceHandler* next_; | 665 EmbedderServiceHandler* next_; |
610 }; | 666 }; |
611 | 667 |
612 | 668 |
613 void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler, | 669 void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler, |
614 JSONStream* js) { | 670 JSONStream* js) { |
615 ASSERT(handler != NULL); | 671 ASSERT(handler != NULL); |
616 Dart_ServiceRequestCallback callback = handler->callback(); | 672 Dart_ServiceRequestCallback callback = handler->callback(); |
617 ASSERT(callback != NULL); | 673 ASSERT(callback != NULL); |
618 const char* r = NULL; | 674 const char* r = NULL; |
619 const char* name = js->method(); | 675 const char* method = js->method(); |
620 const char** keys = js->param_keys(); | 676 const char** keys = js->param_keys(); |
621 const char** values = js->param_values(); | 677 const char** values = js->param_values(); |
622 r = callback(name, keys, values, js->num_params(), handler->user_data()); | 678 r = callback(method, keys, values, js->num_params(), handler->user_data()); |
623 ASSERT(r != NULL); | 679 ASSERT(r != NULL); |
624 // TODO(johnmccutchan): Allow for NULL returns? | 680 // TODO(johnmccutchan): Allow for NULL returns? |
625 TextBuffer* buffer = js->buffer(); | 681 TextBuffer* buffer = js->buffer(); |
626 buffer->AddString(r); | 682 buffer->AddString(r); |
627 free(const_cast<char*>(r)); | 683 free(const_cast<char*>(r)); |
628 } | 684 } |
629 | 685 |
630 | 686 |
631 void Service::RegisterIsolateEmbedderCallback( | 687 void Service::RegisterIsolateEmbedderCallback( |
632 const char* name, | 688 const char* name, |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
767 JSONObject jsobj(&js); | 823 JSONObject jsobj(&js); |
768 { | 824 { |
769 JSONObject event(&jsobj, "event"); | 825 JSONObject event(&jsobj, "event"); |
770 event.AddProperty("type", "Event"); | 826 event.AddProperty("type", "Event"); |
771 event.AddProperty("kind", "_Echo"); | 827 event.AddProperty("kind", "_Echo"); |
772 event.AddProperty("isolate", isolate); | 828 event.AddProperty("isolate", isolate); |
773 if (text != NULL) { | 829 if (text != NULL) { |
774 event.AddProperty("text", text); | 830 event.AddProperty("text", text); |
775 } | 831 } |
776 } | 832 } |
| 833 jsobj.AddProperty("streamId", "_Echo"); |
777 } | 834 } |
778 const String& message = String::Handle(String::New(js.ToCString())); | 835 const String& message = String::Handle(String::New(js.ToCString())); |
779 uint8_t data[] = {0, 128, 255}; | 836 uint8_t data[] = {0, 128, 255}; |
780 SendEvent(message, data, sizeof(data)); | 837 SendEventWithData("_Echo", "_Echo", message, data, sizeof(data)); |
781 } | 838 } |
782 | 839 |
783 | 840 |
784 static bool TriggerEchoEvent(Isolate* isolate, JSONStream* js) { | 841 static bool TriggerEchoEvent(Isolate* isolate, JSONStream* js) { |
785 Service::SendEchoEvent(isolate, js->LookupParam("text")); | 842 if (Service::NeedsEchoEvents()) { |
| 843 Service::SendEchoEvent(isolate, js->LookupParam("text")); |
| 844 } |
786 JSONObject jsobj(js); | 845 JSONObject jsobj(js); |
787 return HandleCommonEcho(&jsobj, js); | 846 return HandleCommonEcho(&jsobj, js); |
788 } | 847 } |
789 | 848 |
790 | 849 |
791 static bool DumpIdZone(Isolate* isolate, JSONStream* js) { | 850 static bool DumpIdZone(Isolate* isolate, JSONStream* js) { |
792 // TODO(johnmccutchan): Respect _idZone parameter passed to RPC. For now, | 851 // TODO(johnmccutchan): Respect _idZone parameter passed to RPC. For now, |
793 // always send the ObjectIdRing. | 852 // always send the ObjectIdRing. |
794 // | 853 // |
795 ObjectIdRing* ring = isolate->object_id_ring(); | 854 ObjectIdRing* ring = isolate->object_id_ring(); |
(...skipping 1288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2084 static const MethodParameter* resume_params[] = { | 2143 static const MethodParameter* resume_params[] = { |
2085 ISOLATE_PARAMETER, | 2144 ISOLATE_PARAMETER, |
2086 NULL, | 2145 NULL, |
2087 }; | 2146 }; |
2088 | 2147 |
2089 | 2148 |
2090 static bool Resume(Isolate* isolate, JSONStream* js) { | 2149 static bool Resume(Isolate* isolate, JSONStream* js) { |
2091 const char* step_param = js->LookupParam("step"); | 2150 const char* step_param = js->LookupParam("step"); |
2092 if (isolate->message_handler()->paused_on_start()) { | 2151 if (isolate->message_handler()->paused_on_start()) { |
2093 isolate->message_handler()->set_pause_on_start(false); | 2152 isolate->message_handler()->set_pause_on_start(false); |
2094 { | 2153 if (Service::NeedsDebugEvents()) { |
2095 ServiceEvent event(isolate, ServiceEvent::kResume); | 2154 ServiceEvent event(isolate, ServiceEvent::kResume); |
2096 Service::HandleEvent(&event); | 2155 Service::HandleEvent(&event); |
2097 } | 2156 } |
2098 PrintSuccess(js); | 2157 PrintSuccess(js); |
2099 return true; | 2158 return true; |
2100 } | 2159 } |
2101 if (isolate->message_handler()->paused_on_exit()) { | 2160 if (isolate->message_handler()->paused_on_exit()) { |
2102 isolate->message_handler()->set_pause_on_exit(false); | 2161 isolate->message_handler()->set_pause_on_exit(false); |
2103 // We don't send a resume event because we will be exiting. | 2162 // We don't send a resume event because we will be exiting. |
2104 PrintSuccess(js); | 2163 PrintSuccess(js); |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2253 } | 2312 } |
2254 | 2313 |
2255 | 2314 |
2256 static const MethodParameter* request_heap_snapshot_params[] = { | 2315 static const MethodParameter* request_heap_snapshot_params[] = { |
2257 ISOLATE_PARAMETER, | 2316 ISOLATE_PARAMETER, |
2258 NULL, | 2317 NULL, |
2259 }; | 2318 }; |
2260 | 2319 |
2261 | 2320 |
2262 static bool RequestHeapSnapshot(Isolate* isolate, JSONStream* js) { | 2321 static bool RequestHeapSnapshot(Isolate* isolate, JSONStream* js) { |
2263 Service::SendGraphEvent(isolate); | 2322 if (Service::NeedsGraphEvents()) { |
| 2323 Service::SendGraphEvent(isolate); |
| 2324 } |
2264 // TODO(koda): Provide some id that ties this request to async response(s). | 2325 // TODO(koda): Provide some id that ties this request to async response(s). |
2265 JSONObject jsobj(js); | 2326 JSONObject jsobj(js); |
2266 jsobj.AddProperty("type", "OK"); | 2327 jsobj.AddProperty("type", "OK"); |
2267 return true; | 2328 return true; |
2268 } | 2329 } |
2269 | 2330 |
2270 | 2331 |
2271 void Service::SendGraphEvent(Isolate* isolate) { | 2332 void Service::SendGraphEvent(Isolate* isolate) { |
2272 uint8_t* buffer = NULL; | 2333 uint8_t* buffer = NULL; |
2273 WriteStream stream(&buffer, &allocator, 1 * MB); | 2334 WriteStream stream(&buffer, &allocator, 1 * MB); |
(...skipping 22 matching lines...) Expand all Loading... |
2296 jsobj.AddProperty("streamId", "_Graph"); | 2357 jsobj.AddProperty("streamId", "_Graph"); |
2297 } | 2358 } |
2298 | 2359 |
2299 const String& message = String::Handle(String::New(js.ToCString())); | 2360 const String& message = String::Handle(String::New(js.ToCString())); |
2300 | 2361 |
2301 uint8_t* chunk_start = buffer + (i * kChunkSize); | 2362 uint8_t* chunk_start = buffer + (i * kChunkSize); |
2302 intptr_t chunk_size = (i + 1 == num_chunks) | 2363 intptr_t chunk_size = (i + 1 == num_chunks) |
2303 ? stream.bytes_written() - (i * kChunkSize) | 2364 ? stream.bytes_written() - (i * kChunkSize) |
2304 : kChunkSize; | 2365 : kChunkSize; |
2305 | 2366 |
2306 SendEvent(message, chunk_start, chunk_size); | 2367 SendEventWithData("_Graph", "_Graph", message, chunk_start, chunk_size); |
2307 } | 2368 } |
2308 } | 2369 } |
2309 | 2370 |
2310 | 2371 |
2311 void Service::SendInspectEvent(Isolate* isolate, const Object& inspectee) { | 2372 void Service::SendInspectEvent(Isolate* isolate, const Object& inspectee) { |
| 2373 if (!Service::NeedsDebugEvents()) { |
| 2374 return; |
| 2375 } |
2312 ServiceEvent event(isolate, ServiceEvent::kInspect); | 2376 ServiceEvent event(isolate, ServiceEvent::kInspect); |
2313 event.set_inspectee(&inspectee); | 2377 event.set_inspectee(&inspectee); |
2314 Service::HandleEvent(&event); | 2378 Service::HandleEvent(&event); |
2315 } | 2379 } |
2316 | 2380 |
2317 | 2381 |
2318 class ContainsAddressVisitor : public FindObjectVisitor { | 2382 class ContainsAddressVisitor : public FindObjectVisitor { |
2319 public: | 2383 public: |
2320 ContainsAddressVisitor(Isolate* isolate, uword addr) | 2384 ContainsAddressVisitor(Isolate* isolate, uword addr) |
2321 : FindObjectVisitor(isolate), addr_(addr) { } | 2385 : FindObjectVisitor(isolate), addr_(addr) { } |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2626 | 2690 |
2627 static const MethodParameter* set_name_params[] = { | 2691 static const MethodParameter* set_name_params[] = { |
2628 ISOLATE_PARAMETER, | 2692 ISOLATE_PARAMETER, |
2629 new MethodParameter("name", true), | 2693 new MethodParameter("name", true), |
2630 NULL, | 2694 NULL, |
2631 }; | 2695 }; |
2632 | 2696 |
2633 | 2697 |
2634 static bool SetName(Isolate* isolate, JSONStream* js) { | 2698 static bool SetName(Isolate* isolate, JSONStream* js) { |
2635 isolate->set_debugger_name(js->LookupParam("name")); | 2699 isolate->set_debugger_name(js->LookupParam("name")); |
2636 { | 2700 if (Service::NeedsIsolateEvents()) { |
2637 ServiceEvent event(isolate, ServiceEvent::kIsolateUpdate); | 2701 ServiceEvent event(isolate, ServiceEvent::kIsolateUpdate); |
2638 Service::HandleEvent(&event); | 2702 Service::HandleEvent(&event); |
2639 } | 2703 } |
2640 PrintSuccess(js); | 2704 PrintSuccess(js); |
2641 return true; | 2705 return true; |
2642 } | 2706 } |
2643 | 2707 |
2644 | 2708 |
2645 static ServiceMethodDescriptor service_methods_[] = { | 2709 static ServiceMethodDescriptor service_methods_[] = { |
2646 { "_dumpIdZone", DumpIdZone, NULL }, | 2710 { "_dumpIdZone", DumpIdZone, NULL }, |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2734 ServiceMethodDescriptor& method = service_methods_[i]; | 2798 ServiceMethodDescriptor& method = service_methods_[i]; |
2735 if (strcmp(method_name, method.name) == 0) { | 2799 if (strcmp(method_name, method.name) == 0) { |
2736 return &method; | 2800 return &method; |
2737 } | 2801 } |
2738 } | 2802 } |
2739 return NULL; | 2803 return NULL; |
2740 } | 2804 } |
2741 | 2805 |
2742 | 2806 |
2743 } // namespace dart | 2807 } // namespace dart |
OLD | NEW |