-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfunction_draft.go
More file actions
140 lines (127 loc) · 3.82 KB
/
Copy pathfunction_draft.go
File metadata and controls
140 lines (127 loc) · 3.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package ember
import "fmt"
type functionDraft struct {
constants []Value
assembly assembledBytecodeIR
children []*functionDraft
upvalues []upvalueDesc
registers int
params int
variadic bool
sourceName string
functionName string
}
func newFunctionDraft(constants []Value, assembly assembledBytecodeIR, children []*functionDraft, upvalues []upvalueDesc, registers int, params int, variadic bool) *functionDraft {
return &functionDraft{
constants: constants,
assembly: assembly,
children: children,
upvalues: upvalues,
registers: registers,
params: params,
variadic: variadic,
}
}
func (c *compiler) addFunctionDraft(draft *functionDraft) int {
index := len(c.prototypeDrafts)
c.prototypeDrafts = append(c.prototypeDrafts, draft)
return index
}
func (c *compiler) optimizeFunction(options optimizationOptions) {
c.ir = optimizeBytecodeIRWithFacts(c.ir, bytecodeIROptimizationFacts{
constants: c.constants,
capturedRegisters: functionDraftCapturedRegisters(c.prototypeDrafts),
constantPool: &c.bytecodeBuilder,
}, options)
}
func functionDraftCapturedRegisters(children []*functionDraft) []bool {
var captured []bool
for _, child := range children {
if child == nil {
continue
}
for _, desc := range child.upvalues {
if !desc.local || desc.copy || desc.index < 0 {
continue
}
for len(captured) <= desc.index {
captured = append(captured, false)
}
captured[desc.index] = true
}
}
return captured
}
func sealFunctionDraft(draft *functionDraft) (*Proto, error) {
proto, err := sealFunctionDraftNode(draft)
if err != nil {
return nil, err
}
return proto, nil
}
func sealFunctionDraftNode(draft *functionDraft) (*Proto, error) {
if draft == nil {
return nil, fmt.Errorf("invalid finalized prototype: nil function draft")
}
var children []*Proto
if len(draft.children) != 0 {
children = make([]*Proto, len(draft.children))
}
for index, childDraft := range draft.children {
child, err := sealFunctionDraftNode(childDraft)
if err != nil {
return nil, err
}
children[index] = child
}
proto := &Proto{
constants: draft.constants,
prototypes: children,
upvalues: draft.upvalues,
lines: draft.assembly.lines,
registers: draft.registers,
params: draft.params,
variadic: draft.variadic,
debugInfo: &protoDebugInfo{
sourceName: draft.sourceName,
functionName: draft.functionName,
},
}
if err := sealFunctionProto(proto, &draft.assembly); err != nil {
return nil, fmt.Errorf("invalid finalized prototype: %w", err)
}
return proto, nil
}
func sealFunctionProto(proto *Proto, assembly *assembledBytecodeIR) error {
assignProtoGlobalSlots(proto, assembly.code)
assembly.code = normalizeOpenResultCallMarkers(assembly.code)
assembly.code = normalizeOpenArgumentCallMarkers(assembly.code)
assembly.code = normalizeFixedMultiResultCounts(assembly.code, proto.registers)
artifact := buildExecutionArtifact(proto, assembly.code)
artifact.apply(proto)
assembly.code = markBorrowableFixedCallWindows(assembly.code, proto.registers, artifact.capturedLocals)
markReusableZeroCaptureClosures(proto, assembly.code)
proto.verifyErr = verifyFunctionProtoWithCode(proto, assembly.code)
if proto.verifyErr != nil {
return proto.verifyErr
}
if err := encodeProtoWords(proto, assembly.code); err != nil {
proto.verifyErr = err
return err
}
return proto.verifyErr
}
func verifyFunctionProto(proto *Proto) error {
code, err := protoDecodedInstructions(proto)
if err != nil {
return err
}
return verifyFunctionProtoWithCode(proto, code)
}
func verifyFunctionProtoWithCode(proto *Proto, code []instruction) error {
sealedChildren := make(map[*Proto]bool, len(proto.prototypes))
for _, child := range proto.prototypes {
sealedChildren[child] = true
}
return verifyProtoSeenWithCode(proto, sealedChildren, code)
}