1 /*
2  * code.h - Virtual machine code
3  *
4  *   Copyright (c) 2005-2020  Shiro Kawai  <shiro@acm.org>
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *   1. Redistributions of source code must retain the above copyright
11  *      notice, this list of conditions and the following disclaimer.
12  *
13  *   2. Redistributions in binary form must reproduce the above copyright
14  *      notice, this list of conditions and the following disclaimer in the
15  *      documentation and/or other materials provided with the distribution.
16  *
17  *   3. Neither the name of the authors nor the names of its contributors
18  *      may be used to endorse or promote products derived from this
19  *      software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27  *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #ifndef GAUCHE_CODE_H
35 #define GAUCHE_CODE_H
36 
37 SCM_DECL_BEGIN
38 
39 #include <gauche/vm.h>
40 
41 /*
42  * Compiled code packet
43  */
44 
45 struct ScmCompiledCodeRec {
46     SCM_HEADER;
47     ScmWord *code;              /* Code vector (*1). This is allocated as
48                                    atomic, to prevent GC from scanning it.
49                                    (*2) */
50     ScmObj *constants;          /* Constant vector.  this isn't used during
51                                    execution, but kept here so that the
52                                    constants in the code vector won't be
53                                    GC-ed. (*2) */
54     int codeSize;               /* size of code vector */
55     int constantSize;           /* size of constant vector (*2) */
56     int maxstack;               /* maximum runtime stack depth */
57     u_short requiredArgs;       /* # of required args, if this code is the
58                                    body of a closure.  Otherwise 0. */
59     u_short optionalArgs;       /* 1 if this code is the body of a closure.
60                                    that takes rest arg.  Otherwise 0. */
61     ScmObj name;                /* If this is the body of a closure, holds
62                                    its name.  Otherwise #f. */
63     ScmObj debugInfo;           /* debug info, that associates instructions
64                                    and source code / other metainfo.  May be
65                                    () if no info is available. (*3) */
66     ScmObj signatureInfo;       /* signature info, a metainfo related to the
67                                    interface of this closure.   Maybe #f
68                                    if no info is available. (*4) */
69     ScmObj parent;              /* ScmCompiledCode if this code is compiled
70                                    within other code chunk.  #f otherwise. */
71     ScmObj intermediateForm;    /* A packed IForm of the body (see compile.scm
72                                    for the details of IForm).  It is used
73                                    to inline this procedure.  Only set if
74                                    the procedure is defined with define-inline.
75                                    #f otherwise. (*5) */
76     void *builder;              /* An opaque data used during consturcting
77                                    the code vector.  Usually NULL. */
78 };
79 
80 /* Footnotes on ScmCompiledCodeRec
81  *
82  *   *1) This may be NULL if this compiled code is "partially compiled"---
83  *       that is, the compiler only runs pass1 and put the intermediate
84  *       form in intermediateForm field.
85  *   *2) For the C-dumped code, the code vector is located in a static data
86  *       area, subject to GC scanning.  In that case, the constants pointer
87  *       is NULL.
88  *   *3) ((<offset> <info> ...) ...)
89  *       <offset> is either an instruction offset or 'definition (for the
90  *       entire closure).
91  *       At this moment, only used <info> is (source-info . <source>).
92  *   *4) (<signature> <info> ...)
93  *       <signature> is (<procedure-name> <formal> ...)
94  *       <procedure-name> may be just a symbol, or a list (in case of internal
95  *       function).  There's no precise definition for the format yet---it's
96  *       for debug information.  See Scm_CompiledCodeFullName().
97  *       <formal> ... is the formal argument list, as appears in the original
98  *       lambda form, including :key, :optional etc.
99  *       At this moment we don't use <info> ... yet; the plan is to put
100  *       metainfo about closure interface, e.g. types.
101  *   *5) This IForm is a direct result of Pass1, i.e. non-optimized form.
102  *       Pass2 scans it when IForm is inlined into the caller site.
103  */
104 
105 SCM_CLASS_DECL(Scm_CompiledCodeClass);
106 #define SCM_CLASS_COMPILED_CODE   (&Scm_CompiledCodeClass)
107 
108 #define SCM_COMPILED_CODE(obj)    ((ScmCompiledCode*)(obj))
109 #define SCM_COMPILED_CODE_P(obj)  SCM_XTYPEP(obj, SCM_CLASS_COMPILED_CODE)
110 #define SCM_COMPILED_CODE_ARG_INFO(obj) (SCM_COMPILED_CODE(obj)->argInfo)
111 #define SCM_COMPILED_CODE_REQUIRED_ARGS(obj) \
112     (SCM_COMPILED_CODE(obj)->requiredArgs)
113 #define SCM_COMPILED_CODE_OPTIONAL_ARGS(obj) \
114     (SCM_COMPILED_CODE(obj)->optionalArgs)
115 
116 #define SCM_COMPILED_CODE_CONST_INITIALIZER(code, codesize, maxstack, reqargs, optargs, name, debuginfo, signatureinfo, parent, iform) \
117     { { SCM_CLASS_STATIC_TAG(Scm_CompiledCodeClass) },   \
118       (code), NULL, (codesize), 0, (maxstack),           \
119       (reqargs), (optargs), (name), (debuginfo), (signatureinfo),   \
120       (parent), (iform), NULL /*builder*/ }
121 
122 SCM_EXTERN void   Scm_CompiledCodeCopyX(ScmCompiledCode *dest,
123                                         const ScmCompiledCode *src);
124 SCM_EXTERN void   Scm_CompiledCodeDump(ScmCompiledCode *cc);
125 SCM_EXTERN ScmObj Scm_CompiledCodeToList(ScmCompiledCode *cc);
126 SCM_EXTERN ScmObj Scm_CompiledCodeFullName(ScmCompiledCode *cc);
127 SCM_EXTERN void   Scm_VMExecuteToplevels(ScmCompiledCode *cv[]);
128 
129 /*
130  * VM instructions
131  */
132 #define SCM_VM_INSN_ARG_MAX          ((1L<<(32-13))-1)
133 #define SCM_VM_INSN_ARG_MIN          (-SCM_VM_INSN_ARG_MAX)
134 #define SCM_VM_INSN_ARG_FITS(k) \
135     (((k)<=SCM_VM_INSN_ARG_MAX)&&((k)>=SCM_VM_INSN_ARG_MIN))
136 
137 /* Macros for transition to the packed code vector of NVM.
138    In the packed code vector, VM insns are stored untagged.
139    It eliminates the shift in the dispatcher. */
140 #define SCM_VM_INSN_CODE(obj)       ((u_int)(SCM_WORD(obj)&0x0fff))
141 #define SCM_VM_INSN_ARG(obj)        ((signed long)SCM_WORD(obj) >> 12)
142 #define SCM_VM_INSN_ARG0(obj)       ((int)((SCM_WORD(obj) >> 12) & 0x03ff))
143 #define SCM_VM_INSN_ARG1(obj)       ((int)((SCM_WORD(obj) >> 22) & 0x03ff))
144 
145 #define SCM_VM_INSN(code)           SCM_WORD(code)
146 #define SCM_VM_INSN1(code, arg)     SCM_WORD((long)((arg)<<12) | (code))
147 #define SCM_VM_INSN2(code, arg0, arg1)  \
148     SCM_WORD((long)((arg1) << 22) | ((arg0) << 12) | (code))
149 
150 /* insn flags.  see vminsn.scm for details. */
151 enum ScmVMInsnFlag {
152     SCM_VM_INSN_OBSOLETED = (1L<<0),
153     SCM_VM_INSN_FOLD_LREF = (1L<<1)
154 };
155 
156 /* Operand type */
157 enum {
158     SCM_VM_OPERAND_NONE,        /* take no operand */
159     SCM_VM_OPERAND_OBJ,         /* take ScmObj */
160     SCM_VM_OPERAND_CODE,        /* take ScmCompiledCode */
161     SCM_VM_OPERAND_CODES,       /* take a list of ScmCompiledCodes */
162     SCM_VM_OPERAND_ADDR,        /* take address of next code */
163     SCM_VM_OPERAND_OBJ_ADDR     /* take an object and address of next code */
164 };
165 
166 SCM_EXTERN const char *Scm_VMInsnName(u_int code);
167 SCM_EXTERN int Scm_VMInsnNumParams(u_int code);
168 SCM_EXTERN int Scm_VMInsnOperandType(u_int code);
169 SCM_EXTERN int Scm_VMInsnNameToCode(ScmObj name);
170 SCM_EXTERN ScmWord Scm_VMInsnBuild(ScmObj insn);
171 
172 SCM_DECL_END
173 
174 #endif /* GAUCHE_CODE_H */
175