1 /*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include <string.h>
10 #include <hcs_gener.h>
11 #include "hcs_compiler.h"
12 #include "hcs_file.h"
13 #include "hcs_opcode.h"
14 #include "hcs_log.h"
15 #include "hcs_option.h"
16
17 #define DEBUG_PRINT_TAB_SIZE 2
18
ByteCodeConvert(ParserObject * current,int32_t walkDepth)19 static int32_t ByteCodeConvert(ParserObject *current, int32_t walkDepth)
20 {
21 (void)walkDepth;
22 /* template should not output */
23 if (current->objectBase.type == PARSEROP_CONFNODE && current->configNode.nodeType == CONFIG_NODE_TEMPLATE) {
24 HcsAstRemoveChildLink(current->objectBase.parent, ¤t->objectBase);
25 HcsDeleteParserObjectTree(current);
26 return NOERR;
27 }
28 const OpCodeMapEntry *opcodeEntry = HcsParserObjectTypeToByteCode(current->objectBase.type);
29 if (opcodeEntry == NULL) {
30 return EFAIL;
31 }
32 current->objectBase.opCode = opcodeEntry->opCode;
33
34 /* calculate leaf size when forward walk */
35 HcsCalculateOpcodeSize(current);
36
37 return NOERR;
38 }
39
DumpParserObjectValue(const ParserObject * obj)40 static void DumpParserObjectValue(const ParserObject *obj)
41 {
42 switch (obj->objectBase.opCode) {
43 case HCS_BYTE_OP:
44 case HCS_WORD_OP:
45 case HCS_DWORD_OP:
46 case HCS_QWORD_OP:
47 HCS_PRINT("%"PRIu64, obj->objectBase.integerValue);
48 break;
49 case HCS_STRING_OP:
50 HCS_PRINT("%s", obj->objectBase.stringValue);
51 break;
52 default:
53 break;
54 }
55 }
56
OpCodeDumpPrint(ParserObject * current,int32_t walkDepth)57 static int32_t OpCodeDumpPrint(ParserObject *current, int32_t walkDepth)
58 {
59 int32_t printTab = walkDepth * DEBUG_PRINT_TAB_SIZE;
60 uint8_t opCode = current->objectBase.opCode;
61 uint32_t size = current->objectBase.size;
62 HCS_PRINT("%-10x%-15s%-10u%-10u%*c%-10s", opCode, HcsOpcodeToStr(current->objectBase.type), size,
63 current->objectBase.subSize, printTab, ' ', current->configNode.name);
64
65 DumpParserObjectValue(current);
66 HCS_PRINT("\n");
67 return NOERR;
68 }
69
DumpFinalAstWithOpCode()70 static void DumpFinalAstWithOpCode()
71 {
72 HCS_PRINT("\nDump final AST with OpCode\n");
73 HCS_PRINT("%-10s%-15s%-10s%-10s%*c%-20s\n", "OpCode", "OpCodeName", "Size", "SubSize", 1, ' ', "ObjectName");
74 HcsWalkAst(NULL, AST_WALK_FORWARD, OpCodeDumpPrint, NULL);
75 }
76
ByteCodeWriteWalk(ParserObject * current,int32_t walkDepth)77 static int32_t ByteCodeWriteWalk(ParserObject *current, int32_t walkDepth)
78 {
79 (void)walkDepth;
80 current->objectBase.hash = HcsGetOutputCurrentCount();
81 if (HcsOutputWriteAlign(¤t->objectBase.opCode, sizeof(current->objectBase.opCode))) {
82 return EOUTPUT;
83 }
84 int32_t ret = NOERR;
85 switch (current->objectBase.opCode) {
86 case HCS_BYTE_OP: /* fall-through */
87 case HCS_WORD_OP: /* fall-through */
88 case HCS_DWORD_OP: /* fall-through */
89 case HCS_QWORD_OP: {
90 const OpCodeMapEntry *byteCodeMap = HcsGetOpCodeMap();
91 ret = HcsOutputWriteAlign(¤t->objectBase.integerValue, byteCodeMap[current->objectBase.type].size);
92 break;
93 }
94 case HCS_STRING_OP:
95 ret = HcsOutputWriteAlign(current->objectBase.stringValue, strlen(current->objectBase.stringValue) + 1);
96 break;
97 case HCS_TERM_OP:
98 ret = HcsOutputWriteAlign((void *)current->objectBase.name, strlen(current->objectBase.name) + 1);
99 break;
100 case HCS_NODE_OP:
101 if (HcsOutputWriteAlign((void *)current->objectBase.name, strlen(current->objectBase.name) + 1)) {
102 return EOUTPUT;
103 }
104 ret = HcsOutputWriteAlign(¤t->objectBase.subSize, sizeof(current->objectBase.subSize));
105 break;
106 case HCS_ARRAY_OP: {
107 uint16_t size = HcsCountArraySize(current);
108 ret = HcsOutputWriteAlign(&size, sizeof(size));
109 }
110 break;
111 case HCS_NODEREF_OP: {
112 ParserObject *ref = (ParserObject *)current->objectBase.value;
113 uint32_t hashCode = ref->objectBase.hash;
114 ret = HcsOutputWriteAlign(&hashCode, sizeof(hashCode));
115 }
116 break;
117 default:
118 break;
119 }
120
121 return ret;
122 }
123
HcsBytecodeOutput(void)124 int32_t HcsBytecodeOutput(void)
125 {
126 ParserObject *astRoot = HcsGetParserRoot();
127 if (astRoot == NULL) {
128 return EFAIL;
129 }
130
131 /* generate OpCode for every object on AST and calculate size for each object */
132 int32_t ret = HcsWalkAst(astRoot, AST_WALK_BACKEND, NULL, ByteCodeConvert);
133 if (ret) {
134 return ret;
135 }
136
137 /* ast data is ready, do bindary output */
138 struct HcsFile *outputFIle = HcsOpenOutputFile(HCS_OUTPUT_FILE_SUFFIX);
139
140 HbcHeader header = {
141 .magicNumber = HBC_MAGIC_NUM,
142 .checkSum = 0,
143 .totalSize = HcsOptShouldAlign() ? -astRoot->objectBase.size : astRoot->objectBase.size,
144 .versionMajor = HCS_COMPILER_VERSION_MAJOR,
145 .versionMinor = HCS_COMPILER_VERSION_MINOR,
146 };
147
148 HcsMockOutPut(true);
149 /* Generate hashcode for each object */
150 if (HcsOutputWriteAlign(&header, sizeof(header))) {
151 HcsCloseOutput(outputFIle);
152 return EOUTPUT;
153 }
154 ret = HcsWalkAst(astRoot, AST_WALK_FORWARD, ByteCodeWriteWalk, NULL);
155 if (ret) {
156 HcsCloseOutput(outputFIle);
157 return ret;
158 }
159 HcsResetOutputCurrentCount();
160 HcsMockOutPut(false);
161
162 if (HcsVerbosePrint()) {
163 DumpFinalAstWithOpCode();
164 }
165
166 /* write bytecode to output file */
167 if (HcsOutputWriteAlign(&header, sizeof(header))) {
168 HcsCloseOutput(outputFIle);
169 return EOUTPUT;
170 }
171 ret = HcsWalkAst(astRoot, AST_WALK_FORWARD, ByteCodeWriteWalk, NULL);
172
173 /* verify file size */
174 uint64_t fileSize = HcsSourceFileGetSize(outputFIle);
175 if (fileSize != (sizeof(header) + abs(header.totalSize))) {
176 HCS_ERROR("output file size mismatch");
177 ret = EOUTPUT;
178 }
179
180 HcsCloseOutput(outputFIle);
181 HCS_DEBUG("Total size: %u ", astRoot->objectBase.size);
182 if (ret == NOERR && HcsOptShouldGenHexdump()) {
183 ret = HcsBinaryToHexdump(HcsGetOutPutFilePath());
184 }
185 return ret;
186 }
187