1 // [AsmJit]
2 // Complete JIT Assembler for C++ Language.
3 //
4 // [License]
5 // Zlib - See COPYING file in this package.
6
7 #define ASMJIT_EXPORTS
8
9 // [Dependencies - AsmJit]
10 #include "../core/assert.h"
11 #include "../core/intutil.h"
12 #include "../core/stringutil.h"
13
14 #include "../x86/x86defs.h"
15 #include "../x86/x86func.h"
16 #include "../x86/x86util.h"
17
18 // [Api-Begin]
19 #include "../core/apibegin.h"
20
21 namespace AsmJit {
22
23 // ============================================================================
24 // [AsmJit::X86FuncDecl - Accessors]
25 // ============================================================================
26
findArgumentByRegCode(uint32_t regCode) const27 uint32_t X86FuncDecl::findArgumentByRegCode(uint32_t regCode) const
28 {
29 uint32_t type = regCode & kRegTypeMask;
30 uint32_t idx = regCode & kRegIndexMask;
31
32 uint32_t clazz;
33
34 switch (type)
35 {
36 case kX86RegTypeGpd:
37 case kX86RegTypeGpq:
38 clazz = kX86VarClassGp;
39 break;
40
41 case kX86RegTypeX87:
42 clazz = kX86VarClassX87;
43 break;
44
45 case kX86RegTypeMm:
46 clazz = kX86VarClassMm;
47 break;
48
49 case kX86RegTypeXmm:
50 clazz = kX86VarClassXmm;
51 break;
52
53 default:
54 return kInvalidValue;
55 }
56
57 for (uint32_t i = 0; i < _argumentsCount; i++)
58 {
59 const FuncArg& arg = _arguments[i];
60
61 if (arg.getRegIndex() == idx && (X86Util::getVarClassFromVarType(arg.getVarType()) & clazz) != 0)
62 return i;
63 }
64
65 return kInvalidValue;
66 }
67
68 // ============================================================================
69 // [AsmJit::X86FuncDecl - SetPrototype - InitCallingConvention]
70 // ============================================================================
71
X86FuncDecl_initCallingConvention(X86FuncDecl * self,uint32_t convention)72 static void X86FuncDecl_initCallingConvention(X86FuncDecl* self, uint32_t convention)
73 {
74 uint32_t i;
75
76 // --------------------------------------------------------------------------
77 // [Inir]
78 // --------------------------------------------------------------------------
79
80 self->_convention = convention;
81 self->_calleePopsStack = false;
82 self->_argumentsDirection = kFuncArgsRTL;
83
84 for (i = 0; i < ASMJIT_ARRAY_SIZE(self->_gpList); i++)
85 self->_gpList[i] = kRegIndexInvalid;
86
87 for (i = 0; i < ASMJIT_ARRAY_SIZE(self->_xmmList); i++)
88 self->_xmmList[i] = kRegIndexInvalid;
89
90 self->_gpListMask = 0x0;
91 self->_mmListMask = 0x0;
92 self->_xmmListMask = 0x0;
93
94 self->_gpPreservedMask = 0x0;
95 self->_mmPreservedMask = 0x0;
96 self->_xmmPreservedMask = 0x0;
97
98 // --------------------------------------------------------------------------
99 // [X86 Calling Conventions]
100 // --------------------------------------------------------------------------
101
102 #if defined(ASMJIT_X86)
103 self->_gpPreservedMask = static_cast<uint16_t>(
104 IntUtil::maskFromIndex(kX86RegIndexEbx) |
105 IntUtil::maskFromIndex(kX86RegIndexEsp) |
106 IntUtil::maskFromIndex(kX86RegIndexEbp) |
107 IntUtil::maskFromIndex(kX86RegIndexEsi) |
108 IntUtil::maskFromIndex(kX86RegIndexEdi));
109 self->_xmmPreservedMask = 0;
110
111 switch (convention)
112 {
113 // ------------------------------------------------------------------------
114 // [CDecl]
115 // ------------------------------------------------------------------------
116
117 case kX86FuncConvCDecl:
118 break;
119
120 // ------------------------------------------------------------------------
121 // [StdCall]
122 // ------------------------------------------------------------------------
123
124 case kX86FuncConvStdCall:
125 self->_calleePopsStack = true;
126 break;
127
128 // ------------------------------------------------------------------------
129 // [MS-ThisCall]
130 // ------------------------------------------------------------------------
131
132 case kX86FuncConvMsThisCall:
133 self->_calleePopsStack = true;
134
135 self->_gpList[0] = kX86RegIndexEcx;
136
137 self->_gpListMask = static_cast<uint16_t>(
138 IntUtil::maskFromIndex(kX86RegIndexEcx));
139 break;
140
141 // ------------------------------------------------------------------------
142 // [MS-FastCall]
143 // ------------------------------------------------------------------------
144
145 case kX86FuncConvMsFastCall:
146 self->_calleePopsStack = true;
147
148 self->_gpList[0] = kX86RegIndexEcx;
149 self->_gpList[1] = kX86RegIndexEdx;
150
151 self->_gpListMask = static_cast<uint16_t>(
152 IntUtil::maskFromIndex(kX86RegIndexEcx) |
153 IntUtil::maskFromIndex(kX86RegIndexEdx));
154 break;
155
156 // ------------------------------------------------------------------------
157 // [Borland-FastCall]
158 // ------------------------------------------------------------------------
159
160 case kX86FuncConvBorlandFastCall:
161 self->_calleePopsStack = true;
162 self->_argumentsDirection = kFuncArgsLTR;
163
164 self->_gpList[0] = kX86RegIndexEax;
165 self->_gpList[1] = kX86RegIndexEdx;
166 self->_gpList[2] = kX86RegIndexEcx;
167
168 self->_gpListMask = static_cast<uint16_t>(
169 IntUtil::maskFromIndex(kX86RegIndexEax) |
170 IntUtil::maskFromIndex(kX86RegIndexEdx) |
171 IntUtil::maskFromIndex(kX86RegIndexEcx));
172 break;
173
174 // ------------------------------------------------------------------------
175 // [Gcc-FastCall]
176 // ------------------------------------------------------------------------
177
178 case kX86FuncConvGccFastCall:
179 self->_calleePopsStack = true;
180
181 self->_gpList[0] = kX86RegIndexEcx;
182 self->_gpList[1] = kX86RegIndexEdx;
183
184 self->_gpListMask = static_cast<uint16_t>(
185 IntUtil::maskFromIndex(kX86RegIndexEcx) |
186 IntUtil::maskFromIndex(kX86RegIndexEdx));
187 break;
188
189 // ------------------------------------------------------------------------
190 // [Gcc-Regparm(1)]
191 // ------------------------------------------------------------------------
192
193 case kX86FuncConvGccRegParm1:
194 self->_calleePopsStack = false;
195
196 self->_gpList[0] = kX86RegIndexEax;
197 self->_gpListMask = static_cast<uint16_t>(
198 IntUtil::maskFromIndex(kX86RegIndexEax));
199 break;
200
201 // ------------------------------------------------------------------------
202 // [Gcc-Regparm(2)]
203 // ------------------------------------------------------------------------
204
205 case kX86FuncConvGccRegParm2:
206 self->_calleePopsStack = false;
207
208 self->_gpList[0] = kX86RegIndexEax;
209 self->_gpList[1] = kX86RegIndexEdx;
210
211 self->_gpListMask = static_cast<uint16_t>(
212 IntUtil::maskFromIndex(kX86RegIndexEax) |
213 IntUtil::maskFromIndex(kX86RegIndexEdx));
214 break;
215
216 // ------------------------------------------------------------------------
217 // [Gcc-Regparm(3)]
218 // ------------------------------------------------------------------------
219
220 case kX86FuncConvGccRegParm3:
221 self->_calleePopsStack = false;
222
223 self->_gpList[0] = kX86RegIndexEax;
224 self->_gpList[1] = kX86RegIndexEdx;
225 self->_gpList[2] = kX86RegIndexEcx;
226
227 self->_gpListMask = static_cast<uint16_t>(
228 IntUtil::maskFromIndex(kX86RegIndexEax) |
229 IntUtil::maskFromIndex(kX86RegIndexEdx) |
230 IntUtil::maskFromIndex(kX86RegIndexEcx));
231 break;
232
233 // ------------------------------------------------------------------------
234 // [Illegal]
235 // ------------------------------------------------------------------------
236
237 default:
238 // Illegal calling convention.
239 ASMJIT_ASSERT(0);
240 }
241 #endif // ASMJIT_X86
242
243 // --------------------------------------------------------------------------
244 // [X64 Calling Conventions]
245 // --------------------------------------------------------------------------
246
247 #if defined(ASMJIT_X64)
248 switch (convention)
249 {
250 // ------------------------------------------------------------------------
251 // [X64-Windows]
252 // ------------------------------------------------------------------------
253
254 case kX86FuncConvX64W:
255 self->_gpList[0] = kX86RegIndexRcx;
256 self->_gpList[1] = kX86RegIndexRdx;
257 self->_gpList[2] = kX86RegIndexR8;
258 self->_gpList[3] = kX86RegIndexR9;
259
260 self->_xmmList[0] = kX86RegIndexXmm0;
261 self->_xmmList[1] = kX86RegIndexXmm1;
262 self->_xmmList[2] = kX86RegIndexXmm2;
263 self->_xmmList[3] = kX86RegIndexXmm3;
264
265 self->_gpListMask = static_cast<uint16_t>(
266 IntUtil::maskFromIndex(kX86RegIndexRcx ) |
267 IntUtil::maskFromIndex(kX86RegIndexRdx ) |
268 IntUtil::maskFromIndex(kX86RegIndexR8 ) |
269 IntUtil::maskFromIndex(kX86RegIndexR9 ));
270
271 self->_xmmListMask = static_cast<uint16_t>(
272 IntUtil::maskFromIndex(kX86RegIndexXmm0 ) |
273 IntUtil::maskFromIndex(kX86RegIndexXmm1 ) |
274 IntUtil::maskFromIndex(kX86RegIndexXmm2 ) |
275 IntUtil::maskFromIndex(kX86RegIndexXmm3 ));
276
277 self->_gpPreservedMask = static_cast<uint16_t>(
278 IntUtil::maskFromIndex(kX86RegIndexRbx ) |
279 IntUtil::maskFromIndex(kX86RegIndexRsp ) |
280 IntUtil::maskFromIndex(kX86RegIndexRbp ) |
281 IntUtil::maskFromIndex(kX86RegIndexRsi ) |
282 IntUtil::maskFromIndex(kX86RegIndexRdi ) |
283 IntUtil::maskFromIndex(kX86RegIndexR12 ) |
284 IntUtil::maskFromIndex(kX86RegIndexR13 ) |
285 IntUtil::maskFromIndex(kX86RegIndexR14 ) |
286 IntUtil::maskFromIndex(kX86RegIndexR15 ));
287
288 self->_xmmPreservedMask = static_cast<uint16_t>(
289 IntUtil::maskFromIndex(kX86RegIndexXmm6 ) |
290 IntUtil::maskFromIndex(kX86RegIndexXmm7 ) |
291 IntUtil::maskFromIndex(kX86RegIndexXmm8 ) |
292 IntUtil::maskFromIndex(kX86RegIndexXmm9 ) |
293 IntUtil::maskFromIndex(kX86RegIndexXmm10) |
294 IntUtil::maskFromIndex(kX86RegIndexXmm11) |
295 IntUtil::maskFromIndex(kX86RegIndexXmm12) |
296 IntUtil::maskFromIndex(kX86RegIndexXmm13) |
297 IntUtil::maskFromIndex(kX86RegIndexXmm14) |
298 IntUtil::maskFromIndex(kX86RegIndexXmm15));
299 break;
300
301 // ------------------------------------------------------------------------
302 // [X64-Unix]
303 // ------------------------------------------------------------------------
304
305 case kX86FuncConvX64U:
306 self->_gpList[0] = kX86RegIndexRdi;
307 self->_gpList[1] = kX86RegIndexRsi;
308 self->_gpList[2] = kX86RegIndexRdx;
309 self->_gpList[3] = kX86RegIndexRcx;
310 self->_gpList[4] = kX86RegIndexR8;
311 self->_gpList[5] = kX86RegIndexR9;
312
313 self->_xmmList[0] = kX86RegIndexXmm0;
314 self->_xmmList[1] = kX86RegIndexXmm1;
315 self->_xmmList[2] = kX86RegIndexXmm2;
316 self->_xmmList[3] = kX86RegIndexXmm3;
317 self->_xmmList[4] = kX86RegIndexXmm4;
318 self->_xmmList[5] = kX86RegIndexXmm5;
319 self->_xmmList[6] = kX86RegIndexXmm6;
320 self->_xmmList[7] = kX86RegIndexXmm7;
321
322 self->_gpListMask = static_cast<uint16_t>(
323 IntUtil::maskFromIndex(kX86RegIndexRdi ) |
324 IntUtil::maskFromIndex(kX86RegIndexRsi ) |
325 IntUtil::maskFromIndex(kX86RegIndexRdx ) |
326 IntUtil::maskFromIndex(kX86RegIndexRcx ) |
327 IntUtil::maskFromIndex(kX86RegIndexR8 ) |
328 IntUtil::maskFromIndex(kX86RegIndexR9 ));
329
330 self->_xmmListMask = static_cast<uint16_t>(
331 IntUtil::maskFromIndex(kX86RegIndexXmm0 ) |
332 IntUtil::maskFromIndex(kX86RegIndexXmm1 ) |
333 IntUtil::maskFromIndex(kX86RegIndexXmm2 ) |
334 IntUtil::maskFromIndex(kX86RegIndexXmm3 ) |
335 IntUtil::maskFromIndex(kX86RegIndexXmm4 ) |
336 IntUtil::maskFromIndex(kX86RegIndexXmm5 ) |
337 IntUtil::maskFromIndex(kX86RegIndexXmm6 ) |
338 IntUtil::maskFromIndex(kX86RegIndexXmm7 ));
339
340 self->_gpPreservedMask = static_cast<uint16_t>(
341 IntUtil::maskFromIndex(kX86RegIndexRbx ) |
342 IntUtil::maskFromIndex(kX86RegIndexRsp ) |
343 IntUtil::maskFromIndex(kX86RegIndexRbp ) |
344 IntUtil::maskFromIndex(kX86RegIndexR12 ) |
345 IntUtil::maskFromIndex(kX86RegIndexR13 ) |
346 IntUtil::maskFromIndex(kX86RegIndexR14 ) |
347 IntUtil::maskFromIndex(kX86RegIndexR15 ));
348 break;
349
350 // ------------------------------------------------------------------------
351 // [Illegal]
352 // ------------------------------------------------------------------------
353
354 default:
355 // Illegal calling convention.
356 ASMJIT_ASSERT(0);
357 }
358 #endif // ASMJIT_X64
359 }
360
361 // ============================================================================
362 // [AsmJit::X86FuncDecl - SetPrototype - InitDefinition]
363 // ============================================================================
364
X86FuncDecl_initDefinition(X86FuncDecl * self,uint32_t returnType,const uint32_t * argumentsData,uint32_t argumentsCount)365 static void X86FuncDecl_initDefinition(X86FuncDecl* self,
366 uint32_t returnType, const uint32_t* argumentsData, uint32_t argumentsCount)
367 {
368 ASMJIT_ASSERT(argumentsCount <= kFuncArgsMax);
369
370 // --------------------------------------------------------------------------
371 // [Init]
372 // --------------------------------------------------------------------------
373
374 int32_t i = 0;
375 int32_t gpPos = 0;
376 int32_t xmmPos = 0;
377 int32_t stackOffset = 0;
378
379 self->_returnType = returnType;
380 self->_argumentsCount = static_cast<uint8_t>(argumentsCount);
381
382 while (i < static_cast<int32_t>(argumentsCount))
383 {
384 FuncArg& arg = self->_arguments[i];
385
386 arg._varType = static_cast<uint8_t>(argumentsData[i]);
387 arg._regIndex = kRegIndexInvalid;
388 arg._stackOffset = kFuncStackInvalid;
389
390 i++;
391 }
392
393 while (i < kFuncArgsMax)
394 {
395 FuncArg& arg = self->_arguments[i];
396 arg.reset();
397
398 i++;
399 }
400
401 self->_argumentsStackSize = 0;
402 self->_gpArgumentsMask = 0x0;
403 self->_mmArgumentsMask = 0x0;
404 self->_xmmArgumentsMask = 0x0;
405
406 if (self->_argumentsCount == 0)
407 return;
408
409 // --------------------------------------------------------------------------
410 // [X86 Calling Conventions (32-bit)]
411 // --------------------------------------------------------------------------
412
413 #if defined(ASMJIT_X86)
414 // Register arguments (Integer), always left-to-right.
415 for (i = 0; i != argumentsCount; i++)
416 {
417 FuncArg& arg = self->_arguments[i];
418 uint32_t varType = arg.getVarType();
419
420 if (X86Util::isVarTypeInt(varType) && gpPos < 16 && self->_gpList[gpPos] != kRegIndexInvalid)
421 {
422 arg._regIndex = self->_gpList[gpPos++];
423 self->_gpArgumentsMask |= static_cast<uint16_t>(IntUtil::maskFromIndex(arg.getRegIndex()));
424 }
425 }
426
427 // Stack arguments.
428 int32_t iStart = static_cast<int32_t>(argumentsCount - 1);
429 int32_t iEnd = -1;
430 int32_t iStep = -1;
431
432 if (self->_argumentsDirection == kFuncArgsLTR)
433 {
434 iStart = 0;
435 iEnd = static_cast<int32_t>(argumentsCount);
436 iStep = 1;
437 }
438
439 for (i = iStart; i != iEnd; i += iStep)
440 {
441 FuncArg& arg = self->_arguments[i];
442 uint32_t varType = arg.getVarType();
443
444 if (arg.hasRegIndex())
445 continue;
446
447 if (X86Util::isVarTypeInt(varType))
448 {
449 stackOffset -= 4;
450 arg._stackOffset = static_cast<int16_t>(stackOffset);
451 }
452 else if (X86Util::isVarTypeFloat(varType))
453 {
454 int32_t size = static_cast<int32_t>(x86VarInfo[varType].getSize());
455 stackOffset -= size;
456 arg._stackOffset = static_cast<int16_t>(stackOffset);
457 }
458 }
459 #endif // ASMJIT_X86
460
461 // --------------------------------------------------------------------------
462 // [X64 Calling Conventions (64-bit)]
463 // --------------------------------------------------------------------------
464
465 #if defined(ASMJIT_X64)
466 // Windows 64-bit specific.
467 if (self->_convention == kX86FuncConvX64W)
468 {
469 int32_t max = argumentsCount < 4 ? argumentsCount : 4;
470
471 // Register arguments (Integer / FP), always left-to-right.
472 for (i = 0; i != max; i++)
473 {
474 FuncArg& arg = self->_arguments[i];
475 uint32_t varType = arg.getVarType();
476
477 if (X86Util::isVarTypeInt(varType))
478 {
479 arg._regIndex = self->_gpList[i];
480 self->_gpArgumentsMask |= static_cast<uint16_t>(IntUtil::maskFromIndex(arg.getRegIndex()));
481 }
482 else if (X86Util::isVarTypeFloat(varType))
483 {
484 arg._regIndex = self->_xmmList[i];
485 self->_xmmArgumentsMask |= static_cast<uint16_t>(IntUtil::maskFromIndex(arg.getRegIndex()));
486 }
487 }
488
489 // Stack arguments (always right-to-left).
490 for (i = argumentsCount - 1; i != -1; i--)
491 {
492 FuncArg& arg = self->_arguments[i];
493 uint32_t varType = arg.getVarType();
494
495 if (arg.isAssigned())
496 continue;
497
498 if (X86Util::isVarTypeInt(varType))
499 {
500 stackOffset -= 8; // Always 8 bytes.
501 arg._stackOffset = stackOffset;
502 }
503 else if (X86Util::isVarTypeFloat(varType))
504 {
505 int32_t size = static_cast<int32_t>(x86VarInfo[varType].getSize());
506 stackOffset -= size;
507 arg._stackOffset = stackOffset;
508 }
509 }
510
511 // 32 bytes shadow space (X64W calling convention specific).
512 stackOffset -= 4 * 8;
513 }
514 // Linux/Unix 64-bit (AMD64 calling convention).
515 else
516 {
517 // Register arguments (Integer), always left-to-right.
518 for (i = 0; i != static_cast<int32_t>(argumentsCount); i++)
519 {
520 FuncArg& arg = self->_arguments[i];
521 uint32_t varType = arg.getVarType();
522
523 if (X86Util::isVarTypeInt(varType) && gpPos < 32 && self->_gpList[gpPos] != kRegIndexInvalid)
524 {
525 arg._regIndex = self->_gpList[gpPos++];
526 self->_gpArgumentsMask |= static_cast<uint16_t>(IntUtil::maskFromIndex(arg.getRegIndex()));
527 }
528 }
529
530 // Register arguments (FP), always left-to-right.
531 for (i = 0; i != static_cast<int32_t>(argumentsCount); i++)
532 {
533 FuncArg& arg = self->_arguments[i];
534 uint32_t varType = arg.getVarType();
535
536 if (X86Util::isVarTypeFloat(varType))
537 {
538 arg._regIndex = self->_xmmList[xmmPos++];
539 self->_xmmArgumentsMask |= static_cast<uint16_t>(IntUtil::maskFromIndex(arg.getRegIndex()));
540 }
541 }
542
543 // Stack arguments.
544 for (i = argumentsCount - 1; i != -1; i--)
545 {
546 FuncArg& arg = self->_arguments[i];
547 uint32_t varType = arg.getVarType();
548
549 if (arg.isAssigned())
550 continue;
551
552 if (X86Util::isVarTypeInt(varType))
553 {
554 stackOffset -= 8;
555 arg._stackOffset = static_cast<int16_t>(stackOffset);
556 }
557 else if (X86Util::isVarTypeFloat(varType))
558 {
559 int32_t size = (int32_t)x86VarInfo[varType].getSize();
560
561 stackOffset -= size;
562 arg._stackOffset = static_cast<int16_t>(stackOffset);
563 }
564 }
565 }
566 #endif // ASMJIT_X64
567
568 // Modify stack offset (all function parameters will be in positive stack
569 // offset that is never zero).
570 for (i = 0; i < (int32_t)argumentsCount; i++)
571 {
572 FuncArg& arg = self->_arguments[i];
573 if (!arg.hasRegIndex())
574 {
575 arg._stackOffset += static_cast<uint16_t>(static_cast<int32_t>(sizeof(uintptr_t)) - stackOffset);
576 }
577 }
578
579 self->_argumentsStackSize = (uint32_t)(-stackOffset);
580 }
581
setPrototype(uint32_t convention,uint32_t returnType,const uint32_t * arguments,uint32_t argumentsCount)582 void X86FuncDecl::setPrototype(uint32_t convention, uint32_t returnType, const uint32_t* arguments, uint32_t argumentsCount)
583 {
584 // Limit maximum function arguments to kFuncArgsMax.
585 if (argumentsCount > kFuncArgsMax)
586 argumentsCount = kFuncArgsMax;
587
588 X86FuncDecl_initCallingConvention(this, convention);
589 X86FuncDecl_initDefinition(this, returnType, arguments, argumentsCount);
590 }
591
592 // ============================================================================
593 // [AsmJit::X86FuncDecl - Reset]
594 // ============================================================================
595
reset()596 void X86FuncDecl::reset()
597 {
598 uint32_t i;
599
600 // --------------------------------------------------------------------------
601 // [Core]
602 // --------------------------------------------------------------------------
603
604 _returnType = kVarTypeInvalid;
605 _argumentsCount = 0;
606
607 _reserved0[0] = 0;
608 _reserved0[1] = 0;
609
610 for (i = 0; i < ASMJIT_ARRAY_SIZE(_arguments); i++)
611 _arguments[i].reset();
612
613 _argumentsStackSize = 0;
614 _gpArgumentsMask = 0x0;
615 _mmArgumentsMask = 0x0;
616 _xmmArgumentsMask = 0x0;
617
618 // --------------------------------------------------------------------------
619 // [Convention]
620 // --------------------------------------------------------------------------
621
622 _convention = kFuncConvNone;
623 _calleePopsStack = false;
624 _argumentsDirection = kFuncArgsRTL;
625 _reserved1 = 0;
626
627 for (i = 0; i < ASMJIT_ARRAY_SIZE(_gpList); i++)
628 _gpList[i] = kRegIndexInvalid;
629
630 for (i = 0; i < ASMJIT_ARRAY_SIZE(_xmmList); i++)
631 _xmmList[i] = kRegIndexInvalid;
632
633 _gpListMask = 0x0;
634 _mmListMask = 0x0;
635 _xmmListMask = 0x0;
636
637 _gpPreservedMask = 0x0;
638 _mmPreservedMask = 0x0;
639 _xmmPreservedMask = 0x0;
640 }
641
642 } // AsmJit namespace
643
644 // [Api-Begin]
645 #include "../core/apiend.h"
646