1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "fidl/c_generator.h" 6 7#include "fidl/attributes.h" 8#include "fidl/names.h" 9 10namespace fidl { 11 12namespace { 13 14// RAII helper class to reset the iostream to its original flags. 15class IOFlagsGuard { 16public: 17 explicit IOFlagsGuard(std::ostream* stream) 18 : stream_(stream), flags_(stream_->flags()) { 19 } 20 ~IOFlagsGuard() { 21 stream_->setf(flags_); 22 } 23 24private: 25 std::ostream* stream_; 26 std::ios::fmtflags flags_; 27}; 28 29// Various string values are looked up or computed in these 30// functions. Nothing else should be dealing in string literals, or 31// computing strings from these or AST values. 32 33constexpr const char* kIndent = " "; 34 35CGenerator::Member MessageHeader() { 36 return { 37 flat::Type::Kind::kIdentifier, 38 flat::Decl::Kind::kStruct, 39 "fidl_message_header_t", 40 "hdr", 41 {}, 42 {}, 43 types::Nullability::kNonnullable, 44 }; 45} 46 47// Functions named "Emit..." are called to actually emit to an std::ostream 48// is here. No other functions should directly emit to the streams. 49 50std::ostream& operator<<(std::ostream& stream, StringView view) { 51 stream.rdbuf()->sputn(view.data(), view.size()); 52 return stream; 53} 54 55void EmitFileComment(std::ostream* file) { 56 *file << "// WARNING: This file is machine generated by fidlc.\n\n"; 57} 58 59void EmitHeaderGuard(std::ostream* file) { 60 // TODO(704) Generate an appropriate header guard name. 61 *file << "#pragma once\n"; 62} 63 64void EmitIncludeHeader(std::ostream* file, StringView header) { 65 *file << "#include " << header << "\n"; 66} 67 68void EmitBeginExternC(std::ostream* file) { 69 *file << "#if defined(__cplusplus)\nextern \"C\" {\n#endif\n"; 70} 71 72void EmitEndExternC(std::ostream* file) { 73 *file << "#if defined(__cplusplus)\n}\n#endif\n"; 74} 75 76void EmitBlank(std::ostream* file) { 77 *file << "\n"; 78} 79 80void EmitMemberDecl(std::ostream* file, const CGenerator::Member& member) { 81 *file << member.type << " " << member.name; 82 for (uint32_t array_count : member.array_counts) { 83 *file << "[" << array_count << "]"; 84 } 85} 86 87void EmitMethodInParamDecl(std::ostream* file, const CGenerator::Member& member) { 88 switch (member.kind) { 89 case flat::Type::Kind::kArray: 90 *file << "const " << member.type << " " << member.name; 91 for (uint32_t array_count : member.array_counts) { 92 *file << "[" << array_count << "]"; 93 } 94 break; 95 case flat::Type::Kind::kVector: 96 *file << "const " << member.element_type << "* " << member.name << "_data, " 97 << "size_t " << member.name << "_count"; 98 break; 99 case flat::Type::Kind::kString: 100 *file << "const char* " << member.name << "_data, " 101 << "size_t " << member.name << "_size"; 102 break; 103 case flat::Type::Kind::kHandle: 104 case flat::Type::Kind::kRequestHandle: 105 case flat::Type::Kind::kPrimitive: 106 *file << member.type << " " << member.name; 107 break; 108 case flat::Type::Kind::kIdentifier: 109 switch (member.decl_kind) { 110 case flat::Decl::Kind::kConst: 111 assert(false && "bad decl kind for member"); 112 break; 113 case flat::Decl::Kind::kEnum: 114 case flat::Decl::Kind::kInterface: 115 *file << member.type << " " << member.name; 116 break; 117 case flat::Decl::Kind::kStruct: 118 case flat::Decl::Kind::kTable: 119 case flat::Decl::Kind::kUnion: 120 switch (member.nullability) { 121 case types::Nullability::kNullable: 122 *file << "const " << member.type << " " << member.name; 123 break; 124 case types::Nullability::kNonnullable: 125 *file << "const " << member.type << "* " << member.name; 126 break; 127 } 128 break; 129 } 130 break; 131 } 132} 133 134void EmitMethodOutParamDecl(std::ostream* file, const CGenerator::Member& member) { 135 switch (member.kind) { 136 case flat::Type::Kind::kArray: 137 *file << member.type << " out_" << member.name; 138 for (uint32_t array_count : member.array_counts) { 139 *file << "[" << array_count << "]"; 140 } 141 case flat::Type::Kind::kVector: 142 *file << member.element_type << "* " << member.name << "_buffer, " 143 << "size_t " << member.name << "_capacity, " 144 << "size_t* out_" << member.name << "_count"; 145 break; 146 case flat::Type::Kind::kString: 147 *file << "char* " << member.name << "_buffer, " 148 << "size_t " << member.name << "_capacity, " 149 << "size_t* out_" << member.name << "_size"; 150 break; 151 case flat::Type::Kind::kHandle: 152 case flat::Type::Kind::kRequestHandle: 153 case flat::Type::Kind::kPrimitive: 154 *file << member.type << "* out_" << member.name; 155 break; 156 case flat::Type::Kind::kIdentifier: 157 switch (member.decl_kind) { 158 case flat::Decl::Kind::kConst: 159 assert(false && "bad decl kind for member"); 160 break; 161 case flat::Decl::Kind::kEnum: 162 case flat::Decl::Kind::kInterface: 163 *file << member.type << "* out_" << member.name; 164 break; 165 case flat::Decl::Kind::kStruct: 166 case flat::Decl::Kind::kTable: 167 case flat::Decl::Kind::kUnion: 168 switch (member.nullability) { 169 case types::Nullability::kNullable: 170 *file << member.type << " out_" << member.name; 171 break; 172 case types::Nullability::kNonnullable: 173 *file << member.type << "* out_" << member.name; 174 break; 175 } 176 break; 177 } 178 break; 179 } 180} 181 182void EmitClientMethodDecl(std::ostream* file, StringView method_name, 183 const std::vector<CGenerator::Member>& request, 184 const std::vector<CGenerator::Member>& response) { 185 *file << "zx_status_t " << method_name << "(zx_handle_t _channel"; 186 for (const auto& member : request) { 187 *file << ", "; 188 EmitMethodInParamDecl(file, member); 189 } 190 for (auto member : response) { 191 *file << ", "; 192 EmitMethodOutParamDecl(file, member); 193 } 194 *file << ")"; 195} 196 197void EmitServerMethodDecl(std::ostream* file, StringView method_name, 198 const std::vector<CGenerator::Member>& request, 199 bool has_response) { 200 *file << "zx_status_t (*" << method_name << ")(void* ctx"; 201 for (const auto& member : request) { 202 *file << ", "; 203 EmitMethodInParamDecl(file, member); 204 } 205 if (has_response) { 206 *file << ", fidl_txn_t* txn"; 207 } 208 *file << ")"; 209} 210 211void EmitServerDispatchDecl(std::ostream* file, StringView interface_name) { 212 *file << "zx_status_t " << interface_name 213 << "_dispatch(void* ctx, fidl_txn_t* txn, fidl_msg_t* msg, const " 214 << interface_name << "_ops_t* ops)"; 215} 216 217void EmitServerTryDispatchDecl(std::ostream* file, StringView interface_name) { 218 *file << "zx_status_t " << interface_name 219 << "_try_dispatch(void* ctx, fidl_txn_t* txn, fidl_msg_t* msg, const " 220 << interface_name << "_ops_t* ops)"; 221} 222 223void EmitServerReplyDecl(std::ostream* file, StringView method_name, 224 const std::vector<CGenerator::Member>& response) { 225 *file << "zx_status_t " << method_name << "_reply(fidl_txn_t* _txn"; 226 for (const auto& member : response) { 227 *file << ", "; 228 EmitMethodInParamDecl(file, member); 229 } 230 *file << ")"; 231} 232 233bool IsStoredOutOfLine(const CGenerator::Member& member) { 234 if (member.kind == flat::Type::Kind::kVector || 235 member.kind == flat::Type::Kind::kString) 236 return true; 237 if (member.kind == flat::Type::Kind::kIdentifier) { 238 return member.nullability == types::Nullability::kNullable && 239 (member.decl_kind == flat::Decl::Kind::kStruct || member.decl_kind == flat::Decl::Kind::kUnion); 240 } 241 return false; 242} 243 244void EmitMeasureInParams(std::ostream* file, 245 const std::vector<CGenerator::Member>& params) { 246 for (const auto& member : params) { 247 if (member.kind == flat::Type::Kind::kVector) 248 *file << " + FIDL_ALIGN(sizeof(*" << member.name << "_data) * " << member.name << "_count)"; 249 else if (member.kind == flat::Type::Kind::kString) 250 *file << " + FIDL_ALIGN(" << member.name << "_size)"; 251 else if (IsStoredOutOfLine(member)) 252 *file << " + (" << member.name << " ? sizeof(*" << member.name << ") : 0u)"; 253 } 254} 255 256void EmitMeasureOutParams(std::ostream* file, 257 const std::vector<CGenerator::Member>& params) { 258 for (const auto& member : params) { 259 if (member.kind == flat::Type::Kind::kVector) 260 *file << " + FIDL_ALIGN(sizeof(*" << member.name << "_buffer) * " << member.name << "_capacity)"; 261 else if (member.kind == flat::Type::Kind::kString) 262 *file << " + FIDL_ALIGN(" << member.name << "_capacity)"; 263 else if (IsStoredOutOfLine(member)) 264 *file << " + (out_" << member.name << " ? sizeof(*out_" << member.name << ") : 0u)"; 265 } 266} 267 268// This function assumes the |params| are part of a [Layout="Simple"] interface. 269// In particular, simple interfaces don't have nullable structs or nested 270// vectors. The only secondary objects they contain are top-level vectors and 271// strings. 272size_t CountSecondaryObjects(const std::vector<CGenerator::Member>& params) { 273 size_t count = 0u; 274 for (const auto& member : params) { 275 if (IsStoredOutOfLine(member)) 276 ++count; 277 } 278 return count; 279} 280 281void EmitLinearizeMessage(std::ostream* file, 282 StringView receiver, 283 StringView bytes, 284 const std::vector<CGenerator::Member>& request) { 285 if (CountSecondaryObjects(request) > 0) 286 *file << kIndent << "uint32_t _next = sizeof(*" << receiver << ");\n"; 287 for (const auto& member : request) { 288 const auto& name = member.name; 289 switch (member.kind) { 290 case flat::Type::Kind::kArray: 291 *file << kIndent << "memcpy(" << receiver << "->" << name << ", " 292 << name << ", sizeof(" << receiver << "->" << name << "));\n"; 293 break; 294 case flat::Type::Kind::kVector: 295 *file << kIndent << receiver << "->" << name << ".data = &" << bytes << "[_next];\n"; 296 *file << kIndent << receiver << "->" << name << ".count = " << name << "_count;\n"; 297 *file << kIndent << "memcpy(" << receiver << "->" << name << ".data, " << name << "_data, sizeof(*" << name << "_data) * " << name << "_count);\n"; 298 *file << kIndent << "_next += FIDL_ALIGN(sizeof(*" << name << "_data) * " << name << "_count);\n"; 299 break; 300 case flat::Type::Kind::kString: 301 *file << kIndent << receiver << "->" << name << ".data = &" << bytes << "[_next];\n"; 302 *file << kIndent << receiver << "->" << name << ".size = " << name << "_size;\n"; 303 *file << kIndent << "memcpy(" << receiver << "->" << name << ".data, " << name << "_data, " << name << "_size);\n"; 304 *file << kIndent << "_next += FIDL_ALIGN(" << name << "_size);\n"; 305 break; 306 case flat::Type::Kind::kHandle: 307 case flat::Type::Kind::kRequestHandle: 308 case flat::Type::Kind::kPrimitive: 309 *file << kIndent << receiver << "->" << name << " = " << name << ";\n"; 310 break; 311 case flat::Type::Kind::kIdentifier: 312 switch (member.decl_kind) { 313 case flat::Decl::Kind::kConst: 314 assert(false && "bad decl kind for member"); 315 break; 316 case flat::Decl::Kind::kEnum: 317 case flat::Decl::Kind::kInterface: 318 *file << kIndent << receiver << "->" << name << " = " << name << ";\n"; 319 break; 320 case flat::Decl::Kind::kTable: 321 assert(false && "c-codegen for tables not yet implemented"); 322 break; 323 case flat::Decl::Kind::kStruct: 324 case flat::Decl::Kind::kUnion: 325 switch (member.nullability) { 326 case types::Nullability::kNullable: 327 *file << kIndent << "if (" << name << ") {\n"; 328 *file << kIndent << kIndent << receiver << "->" << name << " = (void*)&" << bytes << "[_next];\n"; 329 *file << kIndent << kIndent << "memcpy(" << receiver << "->" << name << ", " << name << ", sizeof(*" << name << "));\n"; 330 *file << kIndent << kIndent << "_next += sizeof(*" << name << ");\n"; 331 *file << kIndent << "} else {\n"; 332 *file << kIndent << kIndent << receiver << "->" << name << " = NULL;\n"; 333 *file << kIndent << "}\n"; 334 break; 335 case types::Nullability::kNonnullable: 336 *file << kIndent << receiver << "->" << name << " = *" << name << ";\n"; 337 break; 338 } 339 break; 340 } 341 } 342 } 343} 344 345// Various computational helper routines. 346 347void EnumValue(types::PrimitiveSubtype type, const flat::Constant* constant, 348 const flat::Library* library, std::string* out_value) { 349 // TODO(kulakowski) Move this into library resolution. 350 351 std::ostringstream member_value; 352 353 switch (type) { 354 case types::PrimitiveSubtype::kInt8: { 355 int8_t value; 356 bool success = library->ParseIntegerConstant(constant, &value); 357 if (!success) { 358 __builtin_trap(); 359 } 360 // The char-sized overloads of operator<< here print 361 // the character value, not the numeric value, so cast up. 362 member_value << static_cast<int>(value); 363 break; 364 } 365 case types::PrimitiveSubtype::kInt16: { 366 int16_t value; 367 bool success = library->ParseIntegerConstant(constant, &value); 368 if (!success) { 369 __builtin_trap(); 370 } 371 member_value << value; 372 break; 373 } 374 case types::PrimitiveSubtype::kInt32: { 375 int32_t value; 376 bool success = library->ParseIntegerConstant(constant, &value); 377 if (!success) { 378 __builtin_trap(); 379 } 380 member_value << value; 381 break; 382 } 383 case types::PrimitiveSubtype::kInt64: { 384 int64_t value; 385 bool success = library->ParseIntegerConstant(constant, &value); 386 if (!success) { 387 __builtin_trap(); 388 } 389 member_value << value; 390 break; 391 } 392 case types::PrimitiveSubtype::kUint8: { 393 uint8_t value; 394 bool success = library->ParseIntegerConstant(constant, &value); 395 if (!success) { 396 __builtin_trap(); 397 } 398 // The char-sized overloads of operator<< here print 399 // the character value, not the numeric value, so cast up. 400 member_value << static_cast<unsigned int>(value); 401 break; 402 } 403 case types::PrimitiveSubtype::kUint16: { 404 uint16_t value; 405 bool success = library->ParseIntegerConstant(constant, &value); 406 if (!success) { 407 __builtin_trap(); 408 } 409 member_value << value; 410 break; 411 } 412 case types::PrimitiveSubtype::kUint32: { 413 uint32_t value; 414 bool success = library->ParseIntegerConstant(constant, &value); 415 if (!success) { 416 __builtin_trap(); 417 } 418 member_value << value; 419 break; 420 } 421 case types::PrimitiveSubtype::kUint64: { 422 uint64_t value; 423 bool success = library->ParseIntegerConstant(constant, &value); 424 if (!success) { 425 __builtin_trap(); 426 } 427 member_value << value; 428 break; 429 } 430 case types::PrimitiveSubtype::kBool: 431 case types::PrimitiveSubtype::kFloat32: 432 case types::PrimitiveSubtype::kFloat64: 433 assert(false && "bad primitive type for an enum"); 434 break; 435 } 436 437 *out_value = member_value.str(); 438} 439 440std::vector<uint32_t> ArrayCounts(const flat::Library* library, const flat::Type* type) { 441 std::vector<uint32_t> array_counts; 442 for (;;) { 443 switch (type->kind) { 444 default: { return array_counts; } 445 case flat::Type::Kind::kArray: { 446 auto array_type = static_cast<const flat::ArrayType*>(type); 447 uint32_t element_count = array_type->element_count.Value(); 448 array_counts.push_back(element_count); 449 type = array_type->element_type.get(); 450 continue; 451 } 452 } 453 } 454} 455 456flat::Decl::Kind GetDeclKind(const flat::Library* library, const flat::Type* type) { 457 if (type->kind != flat::Type::Kind::kIdentifier) 458 return flat::Decl::Kind::kConst; 459 auto identifier_type = static_cast<const flat::IdentifierType*>(type); 460 auto named_decl = library->LookupDeclByName(identifier_type->name); 461 assert(named_decl && "library must contain declaration"); 462 return named_decl->kind; 463} 464 465template <typename T> 466CGenerator::Member CreateMember(const flat::Library* library, const T& decl) { 467 std::string name = NameIdentifier(decl.name); 468 const flat::Type* type = decl.type.get(); 469 auto decl_kind = GetDeclKind(library, type); 470 auto type_name = NameFlatCType(type, decl_kind); 471 std::vector<uint32_t> array_counts = ArrayCounts(library, type); 472 std::string element_type_name; 473 if (type->kind == flat::Type::Kind::kVector) { 474 auto vector_type = static_cast<const flat::VectorType*>(type); 475 const flat::Type* element_type = vector_type->element_type.get(); 476 element_type_name = NameFlatCType(element_type, GetDeclKind(library, element_type)); 477 } 478 types::Nullability nullability = types::Nullability::kNonnullable; 479 if (type->kind == flat::Type::Kind::kIdentifier) { 480 auto identifier_type = static_cast<const flat::IdentifierType*>(type); 481 nullability = identifier_type->nullability; 482 } 483 return CGenerator::Member{ 484 type->kind, 485 decl_kind, 486 std::move(type_name), 487 std::move(name), 488 std::move(element_type_name), 489 std::move(array_counts), 490 nullability, 491 }; 492} 493 494std::vector<CGenerator::Member> 495GenerateMembers(const flat::Library* library, 496 const std::vector<flat::Union::Member>& union_members) { 497 std::vector<CGenerator::Member> members; 498 members.reserve(union_members.size()); 499 for (const auto& union_member : union_members) { 500 members.push_back(CreateMember(library, union_member)); 501 } 502 return members; 503} 504 505void GetMethodParameters(const flat::Library* library, 506 const CGenerator::NamedMethod& method_info, 507 std::vector<CGenerator::Member>* request, 508 std::vector<CGenerator::Member>* response) { 509 if (request) { 510 request->reserve(method_info.request->parameters.size()); 511 for (const auto& parameter : method_info.request->parameters) { 512 request->push_back(CreateMember(library, parameter)); 513 } 514 } 515 516 if (response && method_info.response) { 517 response->reserve(method_info.request->parameters.size()); 518 for (const auto& parameter : method_info.response->parameters) { 519 response->push_back(CreateMember(library, parameter)); 520 } 521 } 522} 523 524} // namespace 525 526void CGenerator::GeneratePrologues() { 527 EmitFileComment(&file_); 528 EmitHeaderGuard(&file_); 529 EmitBlank(&file_); 530 EmitIncludeHeader(&file_, "<stdalign.h>"); 531 EmitIncludeHeader(&file_, "<stdbool.h>"); 532 EmitIncludeHeader(&file_, "<stdint.h>"); 533 EmitIncludeHeader(&file_, "<zircon/fidl.h>"); 534 EmitIncludeHeader(&file_, "<zircon/syscalls/object.h>"); 535 EmitIncludeHeader(&file_, "<zircon/types.h>"); 536 // Dependencies are in pointer order... change to a deterministic 537 // ordering prior to output. 538 std::set<std::string> add_includes; 539 for (const auto& dep_library : library_->dependencies()) { 540 if (dep_library == library_) 541 continue; 542 if (dep_library->HasAttribute("Internal")) 543 continue; 544 add_includes.insert(NameLibraryCHeader(dep_library->name())); 545 } 546 for (const auto& include : add_includes) { 547 EmitIncludeHeader(&file_, "<" + include + ">"); 548 } 549 EmitBlank(&file_); 550 EmitBeginExternC(&file_); 551 EmitBlank(&file_); 552} 553 554void CGenerator::GenerateEpilogues() { 555 EmitEndExternC(&file_); 556} 557 558void CGenerator::GenerateIntegerDefine(StringView name, types::PrimitiveSubtype subtype, 559 StringView value) { 560 std::string literal_macro = NamePrimitiveIntegerCConstantMacro(subtype); 561 file_ << "#define " << name << " " << literal_macro << "(" << value << ")\n"; 562} 563 564void CGenerator::GeneratePrimitiveDefine(StringView name, types::PrimitiveSubtype subtype, 565 StringView value) { 566 switch (subtype) { 567 case types::PrimitiveSubtype::kInt8: 568 case types::PrimitiveSubtype::kInt16: 569 case types::PrimitiveSubtype::kInt32: 570 case types::PrimitiveSubtype::kInt64: 571 case types::PrimitiveSubtype::kUint8: 572 case types::PrimitiveSubtype::kUint16: 573 case types::PrimitiveSubtype::kUint32: 574 case types::PrimitiveSubtype::kUint64: { 575 std::string literal_macro = NamePrimitiveIntegerCConstantMacro(subtype); 576 file_ << "#define " << name << " " << literal_macro << "(" << value << ")\n"; 577 break; 578 } 579 case types::PrimitiveSubtype::kBool: 580 case types::PrimitiveSubtype::kFloat32: 581 case types::PrimitiveSubtype::kFloat64: { 582 file_ << "#define " << name << " " 583 << "(" << value << ")\n"; 584 break; 585 } 586 default: 587 abort(); 588 } 589} 590 591void CGenerator::GenerateStringDefine(StringView name, StringView value) { 592 file_ << "#define " << name << " " << value << "\n"; 593} 594 595void CGenerator::GenerateIntegerTypedef(types::PrimitiveSubtype subtype, StringView name) { 596 std::string underlying_type = NamePrimitiveCType(subtype); 597 file_ << "typedef " << underlying_type << " " << name << ";\n"; 598} 599 600void CGenerator::GenerateStructTypedef(StringView name) { 601 file_ << "typedef struct " << name << " " << name << ";\n"; 602} 603 604void CGenerator::GenerateStructDeclaration(StringView name, const std::vector<Member>& members) { 605 file_ << "struct " << name << " {\n"; 606 file_ << kIndent << "FIDL_ALIGNDECL\n"; 607 for (const auto& member : members) { 608 file_ << kIndent; 609 EmitMemberDecl(&file_, member); 610 file_ << ";\n"; 611 } 612 file_ << "};\n"; 613} 614 615void CGenerator::GenerateTaggedUnionDeclaration(StringView name, 616 const std::vector<Member>& members) { 617 file_ << "struct " << name << " {\n"; 618 file_ << kIndent << "FIDL_ALIGNDECL\n"; 619 file_ << kIndent << "fidl_union_tag_t tag;\n"; 620 file_ << kIndent << "union {\n"; 621 for (const auto& member : members) { 622 file_ << kIndent << kIndent; 623 EmitMemberDecl(&file_, member); 624 file_ << ";\n"; 625 } 626 file_ << kIndent << "};\n"; 627 file_ << "};\n"; 628} 629 630// TODO(TO-702) These should maybe check for global name 631// collisions? Otherwise, is there some other way they should fail? 632std::map<const flat::Decl*, CGenerator::NamedConst> 633CGenerator::NameConsts(const std::vector<std::unique_ptr<flat::Const>>& const_infos) { 634 std::map<const flat::Decl*, NamedConst> named_consts; 635 for (const auto& const_info : const_infos) { 636 named_consts.emplace(const_info.get(), NamedConst{NameName(const_info->name, "_", "_"), *const_info}); 637 } 638 return named_consts; 639} 640 641std::map<const flat::Decl*, CGenerator::NamedEnum> 642CGenerator::NameEnums(const std::vector<std::unique_ptr<flat::Enum>>& enum_infos) { 643 std::map<const flat::Decl*, NamedEnum> named_enums; 644 for (const auto& enum_info : enum_infos) { 645 std::string enum_name = NameName(enum_info->name, "_", "_"); 646 named_enums.emplace(enum_info.get(), NamedEnum{std::move(enum_name), *enum_info}); 647 } 648 return named_enums; 649} 650 651std::map<const flat::Decl*, CGenerator::NamedInterface> 652CGenerator::NameInterfaces(const std::vector<std::unique_ptr<flat::Interface>>& interface_infos) { 653 std::map<const flat::Decl*, NamedInterface> named_interfaces; 654 for (const auto& interface_info : interface_infos) { 655 NamedInterface named_interface; 656 named_interface.c_name = NameInterface(*interface_info); 657 if (interface_info->HasAttribute("Discoverable")) { 658 named_interface.discoverable_name = NameDiscoverable(*interface_info); 659 } 660 for (const auto& method_pointer : interface_info->all_methods) { 661 assert(method_pointer != nullptr); 662 const auto& method = *method_pointer; 663 NamedMethod named_method; 664 std::string method_name = NameMethod(named_interface.c_name, method); 665 named_method.ordinal = method.ordinal.Value(); 666 named_method.ordinal_name = NameOrdinal(method_name); 667 named_method.identifier = NameIdentifier(method.name); 668 named_method.c_name = method_name; 669 if (method.maybe_request != nullptr) { 670 std::string c_name = NameMessage(method_name, types::MessageKind::kRequest); 671 std::string coded_name = NameTable(c_name); 672 named_method.request = std::make_unique<NamedMessage>(NamedMessage{ 673 std::move(c_name), std::move(coded_name), 674 method.maybe_request->parameters, method.maybe_request->typeshape}); 675 } 676 if (method.maybe_response != nullptr) { 677 if (method.maybe_request == nullptr) { 678 std::string c_name = 679 NameMessage(method_name, types::MessageKind::kEvent); 680 std::string coded_name = NameTable(c_name); 681 named_method.response = std::make_unique<NamedMessage>( 682 NamedMessage{std::move(c_name), std::move(coded_name), 683 method.maybe_response->parameters, 684 method.maybe_response->typeshape}); 685 } else { 686 std::string c_name = NameMessage(method_name, types::MessageKind::kResponse); 687 std::string coded_name = NameTable(c_name); 688 named_method.response = std::make_unique<NamedMessage>( 689 NamedMessage{std::move(c_name), std::move(coded_name), 690 method.maybe_response->parameters, 691 method.maybe_response->typeshape}); 692 } 693 } 694 named_interface.methods.push_back(std::move(named_method)); 695 } 696 named_interfaces.emplace(interface_info.get(), std::move(named_interface)); 697 } 698 return named_interfaces; 699} 700 701std::map<const flat::Decl*, CGenerator::NamedStruct> 702CGenerator::NameStructs(const std::vector<std::unique_ptr<flat::Struct>>& struct_infos) { 703 std::map<const flat::Decl*, NamedStruct> named_structs; 704 for (const auto& struct_info : struct_infos) { 705 std::string c_name = NameName(struct_info->name, "_", "_"); 706 std::string coded_name = c_name + "Coded"; 707 named_structs.emplace(struct_info.get(), 708 NamedStruct{std::move(c_name), std::move(coded_name), *struct_info}); 709 } 710 return named_structs; 711} 712 713std::map<const flat::Decl*, CGenerator::NamedTable> 714CGenerator::NameTables(const std::vector<std::unique_ptr<flat::Table>>& table_infos) { 715 std::map<const flat::Decl*, NamedTable> named_tables; 716 for (const auto& table_info : table_infos) { 717 std::string c_name = NameName(table_info->name, "_", "_"); 718 std::string coded_name = c_name + "Coded"; 719 named_tables.emplace(table_info.get(), 720 NamedTable{std::move(c_name), std::move(coded_name), *table_info}); 721 } 722 return named_tables; 723} 724 725std::map<const flat::Decl*, CGenerator::NamedUnion> 726CGenerator::NameUnions(const std::vector<std::unique_ptr<flat::Union>>& union_infos) { 727 std::map<const flat::Decl*, NamedUnion> named_unions; 728 for (const auto& union_info : union_infos) { 729 std::string union_name = NameName(union_info->name, "_", "_"); 730 named_unions.emplace(union_info.get(), NamedUnion{std::move(union_name), *union_info}); 731 } 732 return named_unions; 733} 734 735void CGenerator::ProduceConstForwardDeclaration(const NamedConst& named_const) { 736 // TODO(TO-702) 737} 738 739void CGenerator::ProduceEnumForwardDeclaration(const NamedEnum& named_enum) { 740 types::PrimitiveSubtype subtype = named_enum.enum_info.type; 741 GenerateIntegerTypedef(subtype, named_enum.name); 742 for (const auto& member : named_enum.enum_info.members) { 743 std::string member_name = named_enum.name + "_" + NameIdentifier(member.name); 744 std::string member_value; 745 EnumValue(named_enum.enum_info.type, member.value.get(), library_, &member_value); 746 GenerateIntegerDefine(member_name, subtype, std::move(member_value)); 747 } 748 749 EmitBlank(&file_); 750} 751 752void CGenerator::ProduceInterfaceForwardDeclaration(const NamedInterface& named_interface) { 753 if (!named_interface.discoverable_name.empty()) { 754 file_ << "#define " << named_interface.c_name << "_Name \"" << named_interface.discoverable_name << "\"\n"; 755 } 756 for (const auto& method_info : named_interface.methods) { 757 { 758 IOFlagsGuard reset_flags(&file_); 759 file_ << "#define " << method_info.ordinal_name << " ((uint32_t)0x" 760 << std::uppercase << std::hex << method_info.ordinal << std::dec << ")\n"; 761 } 762 if (method_info.request) 763 GenerateStructTypedef(method_info.request->c_name); 764 if (method_info.response) 765 GenerateStructTypedef(method_info.response->c_name); 766 } 767} 768 769void CGenerator::ProduceStructForwardDeclaration(const NamedStruct& named_struct) { 770 GenerateStructTypedef(named_struct.c_name); 771} 772 773void CGenerator::ProduceTableForwardDeclaration(const NamedTable& named_struct) { 774 GenerateStructTypedef(named_struct.c_name); 775} 776 777void CGenerator::ProduceUnionForwardDeclaration(const NamedUnion& named_union) { 778 GenerateStructTypedef(named_union.name); 779} 780 781void CGenerator::ProduceInterfaceExternDeclaration(const NamedInterface& named_interface) { 782 for (const auto& method_info : named_interface.methods) { 783 if (method_info.request) 784 file_ << "extern const fidl_type_t " << method_info.request->coded_name << ";\n"; 785 if (method_info.response) 786 file_ << "extern const fidl_type_t " << method_info.response->coded_name 787 << ";\n"; 788 } 789} 790 791void CGenerator::ProduceConstDeclaration(const NamedConst& named_const) { 792 const flat::Const& ci = named_const.const_info; 793 794 // Some constants are not literals. Odd. 795 if (ci.value->kind != flat::Constant::Kind::kLiteral) { 796 return; 797 } 798 799 switch (ci.type->kind) { 800 case flat::Type::Kind::kPrimitive: 801 GeneratePrimitiveDefine(named_const.name, 802 static_cast<flat::PrimitiveType*>(ci.type.get())->subtype, 803 static_cast<flat::LiteralConstant*>(ci.value.get())->literal->location().data()); 804 break; 805 case flat::Type::Kind::kString: 806 GenerateStringDefine(named_const.name, 807 static_cast<flat::LiteralConstant*>(ci.value.get())->literal->location().data()); 808 break; 809 default: 810 abort(); 811 } 812 813 EmitBlank(&file_); 814} 815 816void CGenerator::ProduceMessageDeclaration(const NamedMessage& named_message) { 817 std::vector<CGenerator::Member> members; 818 members.reserve(1 + named_message.parameters.size()); 819 members.push_back(MessageHeader()); 820 for (const auto& parameter : named_message.parameters) { 821 members.push_back(CreateMember(library_, parameter)); 822 } 823 824 GenerateStructDeclaration(named_message.c_name, members); 825 826 EmitBlank(&file_); 827} 828 829void CGenerator::ProduceInterfaceDeclaration(const NamedInterface& named_interface) { 830 for (const auto& method_info : named_interface.methods) { 831 if (method_info.request) 832 ProduceMessageDeclaration(*method_info.request); 833 if (method_info.response) 834 ProduceMessageDeclaration(*method_info.response); 835 } 836} 837 838void CGenerator::ProduceStructDeclaration(const NamedStruct& named_struct) { 839 std::vector<CGenerator::Member> members; 840 members.reserve(named_struct.struct_info.members.size()); 841 for (const auto& struct_member : named_struct.struct_info.members) { 842 members.push_back(CreateMember(library_, struct_member)); 843 } 844 845 GenerateStructDeclaration(named_struct.c_name, members); 846 847 EmitBlank(&file_); 848} 849 850void CGenerator::ProduceUnionDeclaration(const NamedUnion& named_union) { 851 std::vector<CGenerator::Member> members = 852 GenerateMembers(library_, named_union.union_info.members); 853 GenerateTaggedUnionDeclaration(named_union.name, members); 854 855 uint32_t tag = 0u; 856 for (const auto& member : named_union.union_info.members) { 857 std::string tag_name = NameUnionTag(named_union.name, member); 858 auto union_tag_type = types::PrimitiveSubtype::kUint32; 859 std::ostringstream value; 860 value << tag; 861 GenerateIntegerDefine(std::move(tag_name), union_tag_type, value.str()); 862 ++tag; 863 } 864 865 EmitBlank(&file_); 866} 867 868void CGenerator::ProduceInterfaceClientDeclaration(const NamedInterface& named_interface) { 869 for (const auto& method_info : named_interface.methods) { 870 if (!method_info.request) 871 continue; 872 std::vector<Member> request; 873 std::vector<Member> response; 874 GetMethodParameters(library_, method_info, &request, &response); 875 EmitClientMethodDecl(&file_, method_info.c_name, request, response); 876 file_ << ";\n"; 877 } 878 879 EmitBlank(&file_); 880} 881 882void CGenerator::ProduceInterfaceClientImplementation(const NamedInterface& named_interface) { 883 for (const auto& method_info : named_interface.methods) { 884 if (!method_info.request) 885 continue; 886 std::vector<Member> request; 887 std::vector<Member> response; 888 GetMethodParameters(library_, method_info, &request, &response); 889 890 size_t count = CountSecondaryObjects(request); 891 size_t hcount = method_info.request->typeshape.MaxHandles(); 892 bool encode = ((count > 0) || (hcount > 0)); 893 894 EmitClientMethodDecl(&file_, method_info.c_name, request, response); 895 file_ << " {\n"; 896 file_ << kIndent << "uint32_t _wr_num_bytes = sizeof(" << method_info.request->c_name << ")"; 897 EmitMeasureInParams(&file_, request); 898 file_ << ";\n"; 899 file_ << kIndent << "FIDL_ALIGNDECL char _wr_bytes[_wr_num_bytes];\n"; 900 file_ << kIndent << method_info.request->c_name << "* _request = (" << method_info.request->c_name << "*)_wr_bytes;\n"; 901 file_ << kIndent << "memset(_wr_bytes, 0, sizeof(_wr_bytes));\n"; 902 file_ << kIndent << "_request->hdr.ordinal = " << method_info.ordinal << ";\n"; 903 EmitLinearizeMessage(&file_, "_request", "_wr_bytes", request); 904 if (encode) { 905 file_ << kIndent << "zx_handle_t _handles[ZX_CHANNEL_MAX_MSG_HANDLES];\n"; 906 file_ << kIndent << "uint32_t _wr_num_handles = 0u;\n"; 907 file_ << kIndent << "zx_status_t _status = fidl_encode(&" << method_info.request->coded_name 908 << ", _wr_bytes, _wr_num_bytes, _handles, ZX_CHANNEL_MAX_MSG_HANDLES" 909 << ", &_wr_num_handles, NULL);\n"; 910 file_ << kIndent << "if (_status != ZX_OK)\n"; 911 file_ << kIndent << kIndent << "return _status;\n"; 912 } else { 913 file_ << kIndent << "// OPTIMIZED AWAY fidl_encode() of POD-only request\n"; 914 } 915 if (!method_info.response) { 916 if (encode) { 917 file_ << kIndent << "return zx_channel_write(_channel, 0u, _wr_bytes, _wr_num_bytes, _handles, _wr_num_handles);\n"; 918 } else { 919 file_ << kIndent << "return zx_channel_write(_channel, 0u, _wr_bytes, _wr_num_bytes, NULL, 0);\n"; 920 } 921 } else { 922 file_ << kIndent << "uint32_t _rd_num_bytes = sizeof(" << method_info.response->c_name << ")"; 923 EmitMeasureOutParams(&file_, response); 924 file_ << ";\n"; 925 file_ << kIndent << "FIDL_ALIGNDECL char _rd_bytes[_rd_num_bytes];\n"; 926 if (!encode) { 927 file_ << kIndent << "zx_handle_t _handles[ZX_CHANNEL_MAX_MSG_HANDLES];\n"; 928 } 929 if (!response.empty()) 930 file_ << kIndent << method_info.response->c_name << "* _response = (" << method_info.response->c_name << "*)_rd_bytes;\n"; 931 file_ << kIndent << "zx_channel_call_args_t _args = {\n"; 932 file_ << kIndent << kIndent << ".wr_bytes = _wr_bytes,\n"; 933 if (encode) { 934 file_ << kIndent << kIndent << ".wr_handles = _handles,\n"; 935 } else { 936 file_ << kIndent << kIndent << ".wr_handles = NULL,\n"; 937 } 938 file_ << kIndent << kIndent << ".rd_bytes = _rd_bytes,\n"; 939 file_ << kIndent << kIndent << ".rd_handles = _handles,\n"; 940 file_ << kIndent << kIndent << ".wr_num_bytes = _wr_num_bytes,\n"; 941 if (encode) { 942 file_ << kIndent << kIndent << ".wr_num_handles = _wr_num_handles,\n"; 943 } else { 944 file_ << kIndent << kIndent << ".wr_num_handles = 0,\n"; 945 } 946 file_ << kIndent << kIndent << ".rd_num_bytes = _rd_num_bytes,\n"; 947 file_ << kIndent << kIndent << ".rd_num_handles = ZX_CHANNEL_MAX_MSG_HANDLES,\n"; 948 file_ << kIndent << "};\n"; 949 950 file_ << kIndent << "uint32_t _actual_num_bytes = 0u;\n"; 951 file_ << kIndent << "uint32_t _actual_num_handles = 0u;\n"; 952 if (encode) { 953 file_ << kIndent; 954 } else { 955 file_ << kIndent << "zx_status_t "; 956 } 957 file_ << "_status = zx_channel_call(_channel, 0u, ZX_TIME_INFINITE, &_args, &_actual_num_bytes, &_actual_num_handles);\n"; 958 file_ << kIndent << "if (_status != ZX_OK)\n"; 959 file_ << kIndent << kIndent << "return _status;\n"; 960 961 // We check that we have enough capacity to copy out the parameters 962 // before decoding the message so that we can close the handles 963 // using |_handles| rather than trying to find them in the decoded 964 // message. 965 count = CountSecondaryObjects(response); 966 if (count > 0u) { 967 file_ << kIndent << "if "; 968 if (count > 1u) 969 file_ << "("; 970 size_t i = 0; 971 for (const auto& member : response) { 972 if (member.kind == flat::Type::Kind::kVector) { 973 if (i++ > 0u) 974 file_ << " || "; 975 file_ << "(_response->" << member.name << ".count > " << member.name << "_capacity)"; 976 } else if (member.kind == flat::Type::Kind::kString) { 977 if (i++ > 0u) 978 file_ << " || "; 979 file_ << "(_response->" << member.name << ".size > " << member.name << "_capacity)"; 980 } else if (IsStoredOutOfLine(member)) { 981 if (i++ > 0u) 982 file_ << " || "; 983 file_ << "((uintptr_t)_response->" << member.name << " == FIDL_ALLOC_PRESENT && out_" << member.name << " == NULL)"; 984 } 985 } 986 if (count > 1u) 987 file_ << ")"; 988 file_ << " {\n"; 989 file_ << kIndent << kIndent << "zx_handle_close_many(_handles, _actual_num_handles);\n"; 990 file_ << kIndent << kIndent << "return ZX_ERR_BUFFER_TOO_SMALL;\n"; 991 file_ << kIndent << "}\n"; 992 } 993 994 hcount = method_info.response->typeshape.MaxHandles(); 995 if ((count == 0) && (hcount == 0)) { 996 file_ << kIndent << "// OPTIMIZED AWAY fidl_decode() of POD-only response\n"; 997 file_ << kIndent << "if (_actual_num_handles > 0) {\n"; 998 file_ << kIndent << kIndent << "zx_handle_close_many(_handles, _actual_num_handles);\n"; 999 file_ << kIndent << kIndent << "return ZX_ERR_INTERNAL;\n"; // WHAT ERROR? 1000 file_ << kIndent << "}\n"; 1001 } else { 1002 // TODO(FIDL-162): Validate the response ordinal. C++ bindings also need to do that. 1003 file_ << kIndent << "_status = fidl_decode(&" << method_info.response->coded_name 1004 << ", _rd_bytes, _actual_num_bytes, _handles, _actual_num_handles, NULL);\n"; 1005 file_ << kIndent << "if (_status != ZX_OK)\n"; 1006 file_ << kIndent << kIndent << "return _status;\n"; 1007 } 1008 1009 for (const auto& member : response) { 1010 const auto& name = member.name; 1011 switch (member.kind) { 1012 case flat::Type::Kind::kArray: 1013 file_ << kIndent << "memcpy(out_" << name << ", _response->" << name << ", sizeof(out_" << name << "));\n"; 1014 break; 1015 case flat::Type::Kind::kVector: 1016 file_ << kIndent << "memcpy(" << name << "_buffer, _response->" << name << ".data, sizeof(*" << name << "_buffer) * _response->" << name << ".count);\n"; 1017 file_ << kIndent << "*out_" << name << "_count = _response->" << name << ".count;\n"; 1018 break; 1019 case flat::Type::Kind::kString: 1020 file_ << kIndent << "memcpy(" << name << "_buffer, _response->" << name << ".data, _response->" << name << ".size);\n"; 1021 file_ << kIndent << "*out_" << name << "_size = _response->" << name << ".size;\n"; 1022 break; 1023 case flat::Type::Kind::kHandle: 1024 case flat::Type::Kind::kRequestHandle: 1025 case flat::Type::Kind::kPrimitive: 1026 file_ << kIndent << "*out_" << name << " = _response->" << name << ";\n"; 1027 break; 1028 case flat::Type::Kind::kIdentifier: 1029 switch (member.decl_kind) { 1030 case flat::Decl::Kind::kConst: 1031 assert(false && "bad decl kind for member"); 1032 break; 1033 case flat::Decl::Kind::kEnum: 1034 case flat::Decl::Kind::kInterface: 1035 file_ << kIndent << "*out_" << name << " = _response->" << name << ";\n"; 1036 break; 1037 case flat::Decl::Kind::kTable: 1038 assert(false && "c-codegen for tables not yet implemented"); 1039 break; 1040 case flat::Decl::Kind::kStruct: 1041 case flat::Decl::Kind::kUnion: 1042 switch (member.nullability) { 1043 case types::Nullability::kNullable: 1044 file_ << kIndent << "if (_response->" << name << ") {\n"; 1045 file_ << kIndent << kIndent << "*out_" << name << " = *(_response->" << name << ");\n"; 1046 file_ << kIndent << "} else {\n"; 1047 // We don't have a great way of signaling that the optional response member 1048 // was not in the message. That means these bindings aren't particularly 1049 // useful when the client needs to extract that bit. The best we can do is 1050 // zero out the value to make sure the client has defined behavior. 1051 // 1052 // In many cases, the response contains other information (e.g., a status code) 1053 // that lets the client do something reasonable. 1054 file_ << kIndent << kIndent << "memset(out_" << name << ", 0, sizeof(*out_" << name << "));\n"; 1055 file_ << kIndent << "}\n"; 1056 break; 1057 case types::Nullability::kNonnullable: 1058 file_ << kIndent << "*out_" << name << " = _response->" << name << ";\n"; 1059 break; 1060 } 1061 break; 1062 } 1063 break; 1064 } 1065 } 1066 1067 file_ << kIndent << "return ZX_OK;\n"; 1068 } 1069 file_ << "}\n\n"; 1070 } 1071} // namespace fidl 1072 1073void CGenerator::ProduceInterfaceServerDeclaration(const NamedInterface& named_interface) { 1074 file_ << "typedef struct " << named_interface.c_name << "_ops {\n"; 1075 for (const auto& method_info : named_interface.methods) { 1076 if (!method_info.request) 1077 continue; 1078 std::vector<Member> request; 1079 GetMethodParameters(library_, method_info, &request, nullptr); 1080 bool has_response = method_info.response != nullptr; 1081 file_ << kIndent; 1082 EmitServerMethodDecl(&file_, method_info.identifier, request, has_response); 1083 file_ << ";\n"; 1084 } 1085 file_ << "} " << named_interface.c_name << "_ops_t;\n\n"; 1086 1087 EmitServerDispatchDecl(&file_, named_interface.c_name); 1088 file_ << ";\n"; 1089 EmitServerTryDispatchDecl(&file_, named_interface.c_name); 1090 file_ << ";\n\n"; 1091 1092 for (const auto& method_info : named_interface.methods) { 1093 if (!method_info.request || !method_info.response) 1094 continue; 1095 std::vector<Member> response; 1096 GetMethodParameters(library_, method_info, nullptr, &response); 1097 EmitServerReplyDecl(&file_, method_info.c_name, response); 1098 file_ << ";\n"; 1099 } 1100 1101 EmitBlank(&file_); 1102} 1103 1104void CGenerator::ProduceInterfaceServerImplementation(const NamedInterface& named_interface) { 1105 EmitServerTryDispatchDecl(&file_, named_interface.c_name); 1106 file_ << " {\n"; 1107 file_ << kIndent << "if (msg->num_bytes < sizeof(fidl_message_header_t)) {\n"; 1108 file_ << kIndent << kIndent << "zx_handle_close_many(msg->handles, msg->num_handles);\n"; 1109 file_ << kIndent << kIndent << "return ZX_ERR_INVALID_ARGS;\n"; 1110 file_ << kIndent << "}\n"; 1111 file_ << kIndent << "fidl_message_header_t* hdr = (fidl_message_header_t*)msg->bytes;\n"; 1112 file_ << kIndent << "zx_status_t status = ZX_OK;\n"; 1113 file_ << kIndent << "switch (hdr->ordinal) {\n"; 1114 1115 for (const auto& method_info : named_interface.methods) { 1116 if (!method_info.request) 1117 continue; 1118 file_ << kIndent << "case " << method_info.ordinal_name << ": {\n"; 1119 file_ << kIndent << kIndent << "status = fidl_decode_msg(&" << method_info.request->coded_name << ", msg, NULL);\n"; 1120 file_ << kIndent << kIndent << "if (status != ZX_OK)\n"; 1121 file_ << kIndent << kIndent << kIndent << "break;\n"; 1122 std::vector<Member> request; 1123 GetMethodParameters(library_, method_info, &request, nullptr); 1124 if (!request.empty()) 1125 file_ << kIndent << kIndent << method_info.request->c_name << "* request = (" << method_info.request->c_name << "*)msg->bytes;\n"; 1126 file_ << kIndent << kIndent << "status = (*ops->" << method_info.identifier << ")(ctx"; 1127 for (const auto& member : request) { 1128 switch (member.kind) { 1129 case flat::Type::Kind::kArray: 1130 case flat::Type::Kind::kHandle: 1131 case flat::Type::Kind::kRequestHandle: 1132 case flat::Type::Kind::kPrimitive: 1133 file_ << ", request->" << member.name; 1134 break; 1135 case flat::Type::Kind::kVector: 1136 file_ << ", (" << member.element_type << "*)request->" << member.name << ".data" 1137 << ", request->" << member.name << ".count"; 1138 break; 1139 case flat::Type::Kind::kString: 1140 file_ << ", request->" << member.name << ".data" 1141 << ", request->" << member.name << ".size"; 1142 break; 1143 case flat::Type::Kind::kIdentifier: 1144 switch (member.decl_kind) { 1145 case flat::Decl::Kind::kConst: 1146 assert(false && "bad decl kind for member"); 1147 break; 1148 case flat::Decl::Kind::kEnum: 1149 case flat::Decl::Kind::kInterface: 1150 file_ << ", request->" << member.name; 1151 break; 1152 case flat::Decl::Kind::kTable: 1153 assert(false && "c-codegen for tables not yet implemented"); 1154 break; 1155 case flat::Decl::Kind::kStruct: 1156 case flat::Decl::Kind::kUnion: 1157 switch (member.nullability) { 1158 case types::Nullability::kNullable: 1159 file_ << ", request->" << member.name; 1160 break; 1161 case types::Nullability::kNonnullable: 1162 file_ << ", &(request->" << member.name << ")"; 1163 break; 1164 } 1165 break; 1166 } 1167 } 1168 } 1169 if (method_info.response != nullptr) 1170 file_ << ", txn"; 1171 file_ << ");\n"; 1172 file_ << kIndent << kIndent << "break;\n"; 1173 file_ << kIndent << "}\n"; 1174 } 1175 file_ << kIndent << "default: {\n"; 1176 file_ << kIndent << kIndent << "return ZX_ERR_NOT_SUPPORTED;\n"; 1177 file_ << kIndent << "}\n"; 1178 file_ << kIndent << "}\n"; 1179 file_ << kIndent << "if (" 1180 << "status != ZX_OK && " 1181 << "status != ZX_ERR_STOP && " 1182 << "status != ZX_ERR_NEXT && " 1183 << "status != ZX_ERR_ASYNC) {\n"; 1184 file_ << kIndent << kIndent << "return ZX_ERR_INTERNAL;\n"; 1185 file_ << kIndent << "} else {\n"; 1186 file_ << kIndent << kIndent << "return status;\n"; 1187 file_ << kIndent << "}\n"; 1188 file_ << "}\n\n"; 1189 1190 EmitServerDispatchDecl(&file_, named_interface.c_name); 1191 file_ << " {\n"; 1192 file_ << kIndent << "zx_status_t status = " 1193 << named_interface.c_name << "_try_dispatch(ctx, txn, msg, ops);\n"; 1194 file_ << kIndent << "if (status == ZX_ERR_NOT_SUPPORTED)\n"; 1195 file_ << kIndent << kIndent << "zx_handle_close_many(msg->handles, msg->num_handles);\n"; 1196 file_ << kIndent << "return status;\n"; 1197 file_ << "}\n\n"; 1198 1199 for (const auto& method_info : named_interface.methods) { 1200 if (!method_info.request || !method_info.response) 1201 continue; 1202 std::vector<Member> response; 1203 GetMethodParameters(library_, method_info, nullptr, &response); 1204 1205 size_t hcount = method_info.response->typeshape.MaxHandles(); 1206 bool encode = ((CountSecondaryObjects(response) > 0) || (hcount > 0)); 1207 1208 EmitServerReplyDecl(&file_, method_info.c_name, response); 1209 file_ << " {\n"; 1210 file_ << kIndent << "uint32_t _wr_num_bytes = sizeof(" << method_info.response->c_name << ")"; 1211 EmitMeasureInParams(&file_, response); 1212 file_ << ";\n"; 1213 file_ << kIndent << "char _wr_bytes[_wr_num_bytes];\n"; 1214 file_ << kIndent << method_info.response->c_name << "* _response = (" << method_info.response->c_name << "*)_wr_bytes;\n"; 1215 file_ << kIndent << "memset(_wr_bytes, 0, sizeof(_wr_bytes));\n"; 1216 file_ << kIndent << "_response->hdr.ordinal = " << method_info.ordinal << ";\n"; 1217 EmitLinearizeMessage(&file_, "_response", "_wr_bytes", response); 1218 if (encode) { 1219 file_ << kIndent << "zx_handle_t _handles[ZX_CHANNEL_MAX_MSG_HANDLES];\n"; 1220 } 1221 file_ << kIndent << "fidl_msg_t _msg = {\n"; 1222 file_ << kIndent << kIndent << ".bytes = _wr_bytes,\n"; 1223 if (encode) { 1224 file_ << kIndent << kIndent << ".handles = _handles,\n"; 1225 } else { 1226 file_ << kIndent << kIndent << ".handles = NULL,\n"; 1227 } 1228 file_ << kIndent << kIndent << ".num_bytes = _wr_num_bytes,\n"; 1229 if (encode) { 1230 file_ << kIndent << kIndent << ".num_handles = ZX_CHANNEL_MAX_MSG_HANDLES,\n"; 1231 } else { 1232 file_ << kIndent << kIndent << ".num_handles = 0,\n"; 1233 } 1234 file_ << kIndent << "};\n"; 1235 if (encode) { 1236 file_ << kIndent << "zx_status_t _status = fidl_encode_msg(&" 1237 << method_info.response->coded_name << ", &_msg, &_msg.num_handles, NULL);\n"; 1238 file_ << kIndent << "if (_status != ZX_OK)\n"; 1239 file_ << kIndent << kIndent << "return _status;\n"; 1240 } else { 1241 file_ << kIndent << "// OPTIMIZED AWAY fidl_encode() of POD-only reply\n"; 1242 } 1243 file_ << kIndent << "return _txn->reply(_txn, &_msg);\n"; 1244 file_ << "}\n\n"; 1245 } 1246} 1247 1248std::ostringstream CGenerator::ProduceHeader() { 1249 GeneratePrologues(); 1250 1251 std::map<const flat::Decl*, NamedConst> named_consts = 1252 NameConsts(library_->const_declarations_); 1253 std::map<const flat::Decl*, NamedEnum> named_enums = NameEnums(library_->enum_declarations_); 1254 std::map<const flat::Decl*, NamedInterface> named_interfaces = 1255 NameInterfaces(library_->interface_declarations_); 1256 std::map<const flat::Decl*, NamedStruct> named_structs = 1257 NameStructs(library_->struct_declarations_); 1258 std::map<const flat::Decl*, NamedTable> named_tables = 1259 NameTables(library_->table_declarations_); 1260 std::map<const flat::Decl*, NamedUnion> named_unions = 1261 NameUnions(library_->union_declarations_); 1262 1263 file_ << "\n// Forward declarations\n\n"; 1264 1265 for (const auto* decl : library_->declaration_order_) { 1266 switch (decl->kind) { 1267 case flat::Decl::Kind::kConst: { 1268 auto iter = named_consts.find(decl); 1269 if (iter != named_consts.end()) { 1270 ProduceConstForwardDeclaration(iter->second); 1271 } 1272 break; 1273 } 1274 case flat::Decl::Kind::kEnum: { 1275 auto iter = named_enums.find(decl); 1276 if (iter != named_enums.end()) { 1277 ProduceEnumForwardDeclaration(iter->second); 1278 } 1279 break; 1280 } 1281 case flat::Decl::Kind::kInterface: { 1282 auto iter = named_interfaces.find(decl); 1283 if (iter != named_interfaces.end()) { 1284 ProduceInterfaceForwardDeclaration(iter->second); 1285 } 1286 break; 1287 } 1288 case flat::Decl::Kind::kStruct: { 1289 auto iter = named_structs.find(decl); 1290 if (iter != named_structs.end()) { 1291 ProduceStructForwardDeclaration(iter->second); 1292 } 1293 break; 1294 } 1295 case flat::Decl::Kind::kTable: { 1296 auto iter = named_tables.find(decl); 1297 if (iter != named_tables.end()) { 1298 ProduceTableForwardDeclaration(iter->second); 1299 } 1300 break; 1301 } 1302 case flat::Decl::Kind::kUnion: { 1303 auto iter = named_unions.find(decl); 1304 if (iter != named_unions.end()) { 1305 ProduceUnionForwardDeclaration(iter->second); 1306 } 1307 break; 1308 } 1309 default: 1310 abort(); 1311 } 1312 } 1313 1314 file_ << "\n// Extern declarations\n\n"; 1315 1316 for (const auto* decl : library_->declaration_order_) { 1317 switch (decl->kind) { 1318 case flat::Decl::Kind::kConst: 1319 case flat::Decl::Kind::kEnum: 1320 case flat::Decl::Kind::kStruct: 1321 case flat::Decl::Kind::kTable: 1322 case flat::Decl::Kind::kUnion: 1323 // Only messages have extern fidl_type_t declarations. 1324 break; 1325 case flat::Decl::Kind::kInterface: { 1326 auto iter = named_interfaces.find(decl); 1327 if (iter != named_interfaces.end()) { 1328 ProduceInterfaceExternDeclaration(iter->second); 1329 } 1330 break; 1331 } 1332 default: 1333 abort(); 1334 } 1335 } 1336 1337 file_ << "\n// Declarations\n\n"; 1338 1339 for (const auto* decl : library_->declaration_order_) { 1340 switch (decl->kind) { 1341 case flat::Decl::Kind::kConst: { 1342 auto iter = named_consts.find(decl); 1343 if (iter != named_consts.end()) { 1344 ProduceConstDeclaration(iter->second); 1345 } 1346 break; 1347 } 1348 case flat::Decl::Kind::kEnum: 1349 // Enums can be entirely forward declared, as they have no 1350 // dependencies other than standard headers. 1351 break; 1352 case flat::Decl::Kind::kInterface: { 1353 auto iter = named_interfaces.find(decl); 1354 if (iter != named_interfaces.end()) { 1355 ProduceInterfaceDeclaration(iter->second); 1356 } 1357 break; 1358 } 1359 case flat::Decl::Kind::kStruct: { 1360 auto iter = named_structs.find(decl); 1361 if (iter != named_structs.end()) { 1362 ProduceStructDeclaration(iter->second); 1363 } 1364 break; 1365 } 1366 case flat::Decl::Kind::kTable: 1367 // Tables are entirely forward declared, and their body is defined only in 1368 // implementation files. 1369 break; 1370 case flat::Decl::Kind::kUnion: { 1371 auto iter = named_unions.find(decl); 1372 if (iter != named_unions.end()) { 1373 ProduceUnionDeclaration(iter->second); 1374 } 1375 break; 1376 } 1377 default: 1378 abort(); 1379 } 1380 } 1381 1382 file_ << "\n// Simple bindings \n\n"; 1383 1384 for (const auto* decl : library_->declaration_order_) { 1385 switch (decl->kind) { 1386 case flat::Decl::Kind::kConst: 1387 case flat::Decl::Kind::kEnum: 1388 case flat::Decl::Kind::kStruct: 1389 case flat::Decl::Kind::kTable: 1390 case flat::Decl::Kind::kUnion: 1391 // Only interfaces have client declarations. 1392 break; 1393 case flat::Decl::Kind::kInterface: { 1394 if (!HasSimpleLayout(decl)) 1395 break; 1396 auto iter = named_interfaces.find(decl); 1397 if (iter != named_interfaces.end()) { 1398 ProduceInterfaceClientDeclaration(iter->second); 1399 ProduceInterfaceServerDeclaration(iter->second); 1400 } 1401 break; 1402 } 1403 default: 1404 abort(); 1405 } 1406 } 1407 1408 GenerateEpilogues(); 1409 1410 return std::move(file_); 1411} 1412 1413std::ostringstream CGenerator::ProduceClient() { 1414 EmitFileComment(&file_); 1415 EmitIncludeHeader(&file_, "<lib/fidl/coding.h>"); 1416 EmitIncludeHeader(&file_, "<string.h>"); 1417 EmitIncludeHeader(&file_, "<zircon/syscalls.h>"); 1418 EmitIncludeHeader(&file_, "<" + NameLibraryCHeader(library_->name()) + ">"); 1419 EmitBlank(&file_); 1420 1421 std::map<const flat::Decl*, NamedInterface> named_interfaces = 1422 NameInterfaces(library_->interface_declarations_); 1423 1424 for (const auto* decl : library_->declaration_order_) { 1425 switch (decl->kind) { 1426 case flat::Decl::Kind::kConst: 1427 case flat::Decl::Kind::kEnum: 1428 case flat::Decl::Kind::kStruct: 1429 case flat::Decl::Kind::kTable: 1430 case flat::Decl::Kind::kUnion: 1431 // Only interfaces have client implementations. 1432 break; 1433 case flat::Decl::Kind::kInterface: { 1434 if (!HasSimpleLayout(decl)) 1435 break; 1436 auto iter = named_interfaces.find(decl); 1437 if (iter != named_interfaces.end()) { 1438 ProduceInterfaceClientImplementation(iter->second); 1439 } 1440 break; 1441 } 1442 default: 1443 abort(); 1444 } 1445 } 1446 1447 return std::move(file_); 1448} 1449 1450std::ostringstream CGenerator::ProduceServer() { 1451 EmitFileComment(&file_); 1452 EmitIncludeHeader(&file_, "<lib/fidl/coding.h>"); 1453 EmitIncludeHeader(&file_, "<string.h>"); 1454 EmitIncludeHeader(&file_, "<zircon/syscalls.h>"); 1455 EmitIncludeHeader(&file_, "<" + NameLibraryCHeader(library_->name()) + ">"); 1456 EmitBlank(&file_); 1457 1458 std::map<const flat::Decl*, NamedInterface> named_interfaces = 1459 NameInterfaces(library_->interface_declarations_); 1460 1461 for (const auto* decl : library_->declaration_order_) { 1462 switch (decl->kind) { 1463 case flat::Decl::Kind::kConst: 1464 case flat::Decl::Kind::kEnum: 1465 case flat::Decl::Kind::kStruct: 1466 case flat::Decl::Kind::kTable: 1467 case flat::Decl::Kind::kUnion: 1468 // Only interfaces have client implementations. 1469 break; 1470 case flat::Decl::Kind::kInterface: { 1471 if (!HasSimpleLayout(decl)) 1472 break; 1473 auto iter = named_interfaces.find(decl); 1474 if (iter != named_interfaces.end()) { 1475 ProduceInterfaceServerImplementation(iter->second); 1476 } 1477 break; 1478 } 1479 default: 1480 abort(); 1481 } 1482 } 1483 1484 return std::move(file_); 1485} 1486 1487} // namespace fidl 1488