-
-
Notifications
You must be signed in to change notification settings - Fork 323
Expand file tree
/
Copy pathplan_session.go
More file actions
174 lines (147 loc) · 4.23 KB
/
Copy pathplan_session.go
File metadata and controls
174 lines (147 loc) · 4.23 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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package ferret
import (
"context"
"errors"
"github.com/MontFerret/ferret/v2/pkg/bytecode"
"github.com/MontFerret/ferret/v2/pkg/debugger"
"github.com/MontFerret/ferret/v2/pkg/logging"
"github.com/MontFerret/ferret/v2/pkg/runtime"
"github.com/MontFerret/ferret/v2/pkg/vm"
)
type (
planSessionSetup struct {
requiresDebugInfo bool
}
planSessionDependencies struct {
program *bytecode.Program
host *host
hooks sessionHooks
limiter *sessionLimiter
pool *vm.Pool
options *sessionOptions
logger logging.Logger
}
)
func newPlanSession[T any](
plan *Plan,
ctx context.Context,
setters []SessionOption,
setup planSessionSetup,
build func(planSessionDependencies) (T, error),
) (session T, err error) {
if plan == nil {
return session, runtime.Error(runtime.ErrInvalidOperation, "plan is closed")
}
if ctx == nil {
ctx = context.Background()
}
plan.mu.RLock()
if plan.closed {
plan.mu.RUnlock()
return session, runtime.Error(runtime.ErrInvalidOperation, "plan is closed")
}
program := plan.prog
h := plan.host
hooks := plan.sessionHooks
limiter := plan.limiter
pool := plan.pool
plan.mu.RUnlock()
if setup.requiresDebugInfo && len(program.Metadata.DebugPoints) == 0 {
return session, runtime.Error(runtime.ErrInvalidOperation, "plan was not compiled for debugging")
}
options, err := newSessionOptions(setters)
if err != nil {
return session, err
}
if err = limiter.Acquire(ctx); err != nil {
return session, err
}
releaseOnReturn := true
defer func() {
// Construction errors and panics retain ownership here. Successful
// construction transfers the permit release to the returned session.
if releaseOnReturn {
limiter.Release()
}
}()
session, err = build(planSessionDependencies{
program: program,
host: h,
hooks: hooks,
limiter: limiter,
pool: pool,
options: options,
logger: logging.NewFrom(h.logger, options.logger...),
})
if err == nil {
releaseOnReturn = false
}
return session, err
}
func buildSession(dependencies planSessionDependencies) (*Session, error) {
environment, err := newPlanSessionEnvironment(dependencies.host, dependencies.options)
if err != nil {
return nil, err
}
instance, err := dependencies.pool.Acquire()
if err != nil {
if errors.Is(err, vm.ErrPoolClosed) {
return nil, runtime.Error(runtime.ErrInvalidOperation, "plan is closed")
}
return nil, err
}
return &Session{
vm: instance,
env: environment,
logger: dependencies.logger,
fs: dependencies.host.fs,
network: dependencies.host.network,
encoding: dependencies.host.encoding,
outputContentType: dependencies.options.outputContentType,
hooks: dependencies.hooks,
release: newSessionPermitRelease(dependencies.limiter, dependencies.pool),
}, nil
}
func buildDebugSession(dependencies planSessionDependencies) (*DebugSession, error) {
environment, err := newPlanSessionEnvironment(dependencies.host, dependencies.options)
if err != nil {
return nil, err
}
instance, err := vm.New(dependencies.program)
if err != nil {
return nil, err
}
execution, err := vm.NewDebugExecution(instance, environment)
if err != nil {
_ = instance.Close()
return nil, err
}
session, err := debugger.NewSession(debugger.Config{
Execution: execution,
Values: vm.NewDebugValueAccess(),
Services: &debugSessionServices{
hooks: dependencies.hooks,
releasePermit: newSessionPermitRelease(dependencies.limiter, nil),
encoding: dependencies.host.encoding,
outputContentType: dependencies.options.outputContentType,
logger: dependencies.logger,
fs: dependencies.host.fs,
network: dependencies.host.network,
},
Source: dependencies.program.Source,
DebugPoints: dependencies.program.Metadata.DebugPoints,
Params: dependencies.program.Params,
Format: dependencies.options.debugFormat,
})
if err != nil {
_ = execution.Close()
return nil, err
}
return session, nil
}
func newPlanSessionEnvironment(h *host, options *sessionOptions) (*vm.Environment, error) {
return vm.ExtendEnvironment(&vm.Environment{
Functions: h.functions,
Params: h.params,
}, options.env)
}