Skip to content

Commit e9cc687

Browse files
committed
cache the code object inside the function / generator. Additionally initialize the code object members lazily when a rootnode is passed
1 parent f0546c1 commit e9cc687

File tree

6 files changed

+120
-82
lines changed

6 files changed

+120
-82
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/PCode.java

Lines changed: 80 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -64,65 +64,48 @@
6464

6565
public class PCode extends PythonBuiltinObject {
6666
private final RootNode rootNode;
67+
private final PythonCore core;
68+
6769
// number of arguments (not including keyword only arguments, * or ** args)
68-
private final int argcount;
70+
private int argcount = -1;
6971
// number of keyword only arguments (not including ** arg)
70-
private final int kwonlyargcount;
72+
private int kwonlyargcount = -1;
7173
// number of local variables
72-
private final int nlocals;
74+
private int nlocals = -1;
7375
// is the required stack size (including local variables)
74-
private final int stacksize;
76+
private int stacksize = -1;
7577
// is an integer encoding a number of flags for the interpreter.
76-
//
7778
// The following flag bits are defined for co_flags: bit 0x04 is set if the function uses the
7879
// *arguments syntax to accept an arbitrary number of positional arguments; bit 0x08 is set if
7980
// the function uses the **keywords syntax to accept arbitrary keyword arguments; bit 0x20 is
8081
// set if the function is a generator.
81-
private final int flags;
82+
private int flags = -1;
8283
// is a string representing the sequence of bytecode instructions
83-
private final String codestring;
84+
private String codestring;
8485
// tuple of constants used in the bytecode
85-
private final Object constants;
86+
private Object constants;
8687
// tuple containing the literals used by the bytecode
87-
private final Object names;
88+
private Object names;
8889
// is a tuple containing the names of the local variables (starting with the argument names)
89-
private final Object[] varnames;
90+
private Object[] varnames;
9091
// name of file in which this code object was created
91-
private final String filename;
92+
private String filename;
9293
// name with which this code object was defined
93-
private final String name;
94+
private String name;
9495
// number of first line in Python source code
95-
private final int firstlineno;
96+
private int firstlineno = -1;
9697
// is a string encoding the mapping from bytecode offsets to line numbers
97-
private final Object lnotab;
98+
private Object lnotab;
9899
// tuple of names of free variables (referenced via a function’s closure)
99-
private final Object[] freevars;
100+
private Object[] freevars;
100101
// tuple of names of cell variables (referenced by containing scopes)
101-
private final Object[] cellvars;
102+
private Object[] cellvars;
102103

103104
@TruffleBoundary
104105
public PCode(PythonClass cls, RootNode rootNode, PythonCore core) {
105106
super(cls);
106107
this.rootNode = rootNode;
107-
// file stats
108-
this.filename = getFileName(this.rootNode);
109-
this.name = getName(this.rootNode);
110-
this.firstlineno = getFirstLineno(this.rootNode);
111-
// arg stats
112-
ArgStats argStats = getArgStats(this.rootNode, core);
113-
this.argcount = argStats.argCnt;
114-
this.kwonlyargcount = argStats.kwOnlyArgCnt;
115-
this.freevars = argStats.freeVars;
116-
this.cellvars = argStats.cellVars;
117-
this.varnames = argStats.varNames;
118-
this.nlocals = argStats.nLocals;
119-
this.flags = argStats.flags;
120-
121-
this.stacksize = getStackSize(rootNode);
122-
this.codestring = null;
123-
this.constants = null;
124-
this.names = null;
125-
this.lnotab = null;
108+
this.core = core;
126109
}
127110

128111
public PCode(PythonClass cls, int argcount, int kwonlyargcount,
@@ -133,6 +116,8 @@ public PCode(PythonClass cls, int argcount, int kwonlyargcount,
133116
Object lnotab) {
134117
super(cls);
135118
this.rootNode = null;
119+
this.core = null;
120+
136121
this.argcount = argcount;
137122
this.kwonlyargcount = kwonlyargcount;
138123
this.nlocals = nlocals;
@@ -174,7 +159,7 @@ private static String[] getCellVars(RootNode rootNode) {
174159
}
175160
}
176161

177-
private static String getFileName(RootNode rootNode) {
162+
private static String extractFileName(RootNode rootNode) {
178163
SourceSection src = rootNode.getSourceSection();
179164
if (src != null) {
180165
return src.getSource().getName();
@@ -185,12 +170,12 @@ private static String getFileName(RootNode rootNode) {
185170
}
186171
}
187172

188-
private static int getFirstLineno(RootNode rootNode) {
173+
private static int extractFirstLineno(RootNode rootNode) {
189174
SourceSection sourceSection = rootNode.getSourceSection();
190175
return (sourceSection != null) ? sourceSection.getStartLine() : 1;
191176
}
192177

193-
private static String getName(RootNode rootNode) {
178+
private static String extractName(RootNode rootNode) {
194179
String name;
195180
if (rootNode instanceof ModuleRootNode) {
196181
name = "<module>";
@@ -224,31 +209,15 @@ private static Set<String> getArgumentNames(List<ReadIndexedArgumentNode> readIn
224209
return argNames;
225210
}
226211

227-
private final static class ArgStats {
228-
final int argCnt;
229-
final int kwOnlyArgCnt;
230-
final Object[] varNames;
231-
final Object[] freeVars;
232-
final Object[] cellVars;
233-
final int flags;
234-
final int nLocals;
235-
236-
private ArgStats(int argCnt, int kwOnlyArgCnt, Object[] varNames, Object[] freeVars, Object[] cellVars, int flags) {
237-
this.argCnt = argCnt;
238-
this.kwOnlyArgCnt = kwOnlyArgCnt;
239-
this.varNames = varNames;
240-
this.freeVars = freeVars;
241-
this.cellVars = cellVars;
242-
this.nLocals = varNames.length;
243-
this.flags = flags;
244-
}
212+
private static int extractStackSize(RootNode rootNode) {
213+
return rootNode.getFrameDescriptor().getSize();
245214
}
246215

247-
private static ArgStats getArgStats(RootNode rootNode, PythonCore core) {
248-
String[] freeVars = getFreeVars(rootNode);
249-
String[] cellVars = getCellVars(rootNode);
250-
Set<String> freeVarsSet = asSet(freeVars);
251-
Set<String> cellVarsSet = asSet(cellVars);
216+
private void extractArgStats() {
217+
String[] freevars = getFreeVars(rootNode);
218+
String[] cellvars = getCellVars(rootNode);
219+
Set<String> freeVarsSet = asSet(freevars);
220+
Set<String> cellVarsSet = asSet(cellvars);
252221

253222
List<ReadKeywordNode> readKeywordNodes = NodeUtil.findAllNodeInstances(rootNode, ReadKeywordNode.class);
254223
List<ReadIndexedArgumentNode> readIndexedArgumentNodes = NodeUtil.findAllNodeInstances(rootNode, ReadIndexedArgumentNode.class);
@@ -260,26 +229,26 @@ private static ArgStats getArgStats(RootNode rootNode, PythonCore core) {
260229
allArgNames.addAll(kwNames);
261230
allArgNames.addAll(argNames);
262231

263-
int argC = readIndexedArgumentNodes.size();
264-
int kwOnlyArgC = 0;
232+
int argcount = readIndexedArgumentNodes.size();
233+
int kwonlyargcount = 0;
265234
int flags = 0;
266235

267236
for (ReadKeywordNode kwNode : readKeywordNodes) {
268237
if (!kwNode.canBePositional()) {
269-
kwOnlyArgC++;
238+
kwonlyargcount++;
270239
}
271240
}
272241

273-
Set<String> varNames = new HashSet<>();
242+
Set<String> varnames = new HashSet<>();
274243
for (Object identifier : rootNode.getFrameDescriptor().getIdentifiers()) {
275244
if (identifier instanceof String) {
276245
String varName = (String) identifier;
277246

278247
if (core.getParser().isIdentifier(core, varName)) {
279248
if (allArgNames.contains(varName)) {
280-
varNames.add(varName);
249+
varnames.add(varName);
281250
} else if (!freeVarsSet.contains(varName) && !cellVarsSet.contains(varName)) {
282-
varNames.add(varName);
251+
varnames.add(varName);
283252
}
284253
}
285254
}
@@ -299,57 +268,96 @@ private static ArgStats getArgStats(RootNode rootNode, PythonCore core) {
299268
flags |= (1 << 5);
300269
}
301270

302-
return new ArgStats(argC, kwOnlyArgC, varNames.toArray(), freeVars, cellVars, flags);
303-
}
304-
305-
private static int getStackSize(RootNode rootNode) {
306-
return rootNode.getFrameDescriptor().getSize();
271+
this.argcount = argcount;
272+
this.kwonlyargcount = kwonlyargcount;
273+
this.freevars = freevars;
274+
this.cellvars = cellvars;
275+
this.varnames = varnames.toArray();
276+
this.nlocals = varnames.size();
277+
this.flags = flags;
307278
}
308279

309280
public RootNode getRootNode() {
310281
return rootNode;
311282
}
312283

313284
public Object[] getFreeVars() {
285+
if (freevars == null && rootNode != null) {
286+
extractArgStats();
287+
}
314288
return freevars;
315289
}
316290

317291
public Object[] getCellVars() {
292+
if (freevars == null && rootNode != null) {
293+
extractArgStats();
294+
}
318295
return cellvars;
319296
}
320297

321298
public String getFilename() {
299+
if (filename == null && rootNode != null) {
300+
filename = extractFileName(rootNode);
301+
}
322302
return filename;
323303
}
324304

325305
public int getFirstLineNo() {
306+
if (firstlineno == -1 && rootNode != null) {
307+
firstlineno = extractFirstLineno(rootNode);
308+
}
326309
return firstlineno;
327310
}
328311

329312
public String getName() {
313+
if (name == null && rootNode != null) {
314+
name = extractName(rootNode);
315+
}
330316
return name;
331317
}
332318

333319
public int getArgcount() {
320+
if (argcount == -1 && rootNode != null) {
321+
extractArgStats();
322+
}
334323
return argcount;
335324
}
336325

337326
public int getKwonlyargcount() {
327+
if (kwonlyargcount == -1 && rootNode != null) {
328+
extractArgStats();
329+
}
338330
return kwonlyargcount;
339331
}
340332

341333
public int getNlocals() {
334+
if (nlocals == -1 && rootNode != null) {
335+
extractArgStats();
336+
}
342337
return nlocals;
343338
}
344339

345340
public int getStacksize() {
341+
if (stacksize == -1 && rootNode != null) {
342+
stacksize = extractStackSize(rootNode);
343+
}
346344
return stacksize;
347345
}
348346

349347
public long getFlags() {
348+
if (flags == -1 && rootNode != null) {
349+
extractArgStats();
350+
}
350351
return flags;
351352
}
352353

354+
public Object[] getVarnames() {
355+
if (varnames == null && rootNode != null) {
356+
extractArgStats();
357+
}
358+
return varnames;
359+
}
360+
353361
public String getCodestring() {
354362
return codestring;
355363
}
@@ -362,10 +370,6 @@ public Object getNames() {
362370
return names;
363371
}
364372

365-
public Object[] getVarnames() {
366-
return varnames;
367-
}
368-
369373
public Object getLnotab() {
370374
return lnotab;
371375
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/AbstractFunctionBuiltins.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import com.oracle.truffle.api.dsl.NodeFactory;
6767
import com.oracle.truffle.api.dsl.Specialization;
6868
import com.oracle.truffle.api.dsl.TypeSystemReference;
69+
import com.oracle.truffle.api.profiles.ConditionProfile;
6970

7071
@CoreFunctions(extendClasses = {PFunction.class, PBuiltinFunction.class})
7172
public class AbstractFunctionBuiltins extends PythonBuiltins {
@@ -213,8 +214,14 @@ Object getModule(PBuiltinFunction self, Object value) {
213214
@GenerateNodeFactory
214215
public abstract static class GetCodeNode extends PythonBuiltinNode {
215216
@Specialization(guards = {"!isBuiltinFunction(self)", "isNoValue(none)"})
216-
Object getCode(PFunction self, @SuppressWarnings("unused") PNone none) {
217-
return factory().createCode(self.getFunctionRootNode());
217+
Object getCode(PFunction self, @SuppressWarnings("unused") PNone none,
218+
@Cached("createBinaryProfile()") ConditionProfile hasCodeProfile) {
219+
PCode code = self.getCode();
220+
if (hasCodeProfile.profile(code == null)) {
221+
code = factory().createCode(self.getFunctionRootNode());
222+
self.setCode(code);
223+
}
224+
return code;
218225
}
219226

220227
@SuppressWarnings("unused")

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PFunction.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__QUALNAME__;
3030

3131
import com.oracle.graal.python.builtins.objects.cell.PCell;
32+
import com.oracle.graal.python.builtins.objects.code.PCode;
3233
import com.oracle.graal.python.builtins.objects.object.PythonObject;
3334
import com.oracle.graal.python.builtins.objects.type.PythonClass;
3435
import com.oracle.graal.python.nodes.SpecialMethodNames;
@@ -49,6 +50,7 @@ public class PFunction extends PythonObject implements PythonCallable {
4950
private final PythonObject globals;
5051
private final PCell[] closure;
5152
private final boolean isStatic;
53+
private PCode code;
5254

5355
public PFunction(PythonClass clazz, String name, String enclosingClassName, Arity arity, RootCallTarget callTarget, FrameDescriptor frameDescriptor, PythonObject globals, PCell[] closure) {
5456
super(clazz);
@@ -120,4 +122,12 @@ public final String toString() {
120122
return String.format("<function %s.%s at 0x%x>", enclosingClassName, name, hashCode());
121123
}
122124
}
125+
126+
public PCode getCode() {
127+
return code;
128+
}
129+
130+
public void setCode(PCode code) {
131+
this.code = code;
132+
}
123133
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/GeneratorBuiltins.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.oracle.graal.python.builtins.CoreFunctions;
3737
import com.oracle.graal.python.builtins.PythonBuiltins;
3838
import com.oracle.graal.python.builtins.objects.PNone;
39+
import com.oracle.graal.python.builtins.objects.code.PCode;
3940
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
4041
import com.oracle.graal.python.builtins.objects.function.PArguments;
4142
import com.oracle.graal.python.builtins.objects.traceback.PTraceback;
@@ -178,8 +179,14 @@ Object sendThrow(PGenerator self, @SuppressWarnings("unused") PythonClass typ, P
178179
@GenerateNodeFactory
179180
public abstract static class GetCodeNode extends PythonBuiltinNode {
180181
@Specialization
181-
Object getCode(PGenerator self) {
182-
return factory().createCode(self.getGeneratorRootNode());
182+
Object getCode(PGenerator self,
183+
@Cached("createBinaryProfile()") ConditionProfile hasCodeProfile) {
184+
PCode code = self.getCode();
185+
if (hasCodeProfile.profile(code == null)) {
186+
code = factory().createCode(self.getGeneratorRootNode());
187+
self.setCode(code);
188+
}
189+
return code;
183190
}
184191
}
185192
}

0 commit comments

Comments
 (0)