Skip to content

Commit d3fc35e

Browse files
committed
[GR-11096] [GR-10822] Fixes and improvements for R-Numpy interop demo.
PullRequest: graalpython/142
2 parents fb566c7 + 285108a commit d3fc35e

File tree

17 files changed

+344
-66
lines changed

17 files changed

+344
-66
lines changed

graalpython/com.oracle.graal.python.cext/src/capi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ typedef struct {
6868

6969
typedef struct {
7070
PyObject_VAR_HEAD
71+
int readonly;
7172
void *buf_delegate;
7273
} PyBufferDecorator;
7374

graalpython/com.oracle.graal.python.cext/src/memoryobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,5 @@ PyTypeObject PyMemoryView_Type = PY_TRUFFLE_TYPE("memoryview", &PyType_Type, Py_
4444
PyTypeObject PyBuffer_Type = PY_TRUFFLE_TYPE("buffer", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, sizeof(PyBufferDecorator));
4545

4646
int bufferdecorator_getbuffer(PyBufferDecorator *self, Py_buffer *view, int flags) {
47-
return PyBuffer_FillInfo(view, (PyObject*)self, polyglot_get_member(self, "buf_delegate"), PyObject_Size((PyObject *)self), 1, flags);
47+
return PyBuffer_FillInfo(view, (PyObject*)self, polyglot_get_member(self, "buf_delegate"), PyObject_Size((PyObject *)self) * sizeof(PyObject*), self->readonly, flags);
4848
}

graalpython/com.oracle.graal.python.tck/src/com/oracle/graal/python/tck/PythonProvider.java

Lines changed: 80 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,9 @@ public Collection<? extends Snippet> createExpressions(Context context) {
150150
addExpressionSnippet(context, snippets, "-", "lambda x, y: x - y", NUMBER_OBJECT, PNUMBER, PNUMBER);
151151

152152
// multiplication
153-
addExpressionSnippet(context, snippets, "*", "lambda x, y: x * y", NUMBER_OBJECT, PNUMBER, PNUMBER);
154-
addExpressionSnippet(context, snippets, "*", "lambda x, y: x * y", STRING, PSequenceMultiplicationVerifier.INSTANCE, PNUMBER, STRING);
155-
addExpressionSnippet(context, snippets, "*", "lambda x, y: x * y", STRING, PSequenceMultiplicationVerifier.INSTANCE, STRING, PNUMBER);
156-
addExpressionSnippet(context, snippets, "*", "lambda x, y: x * y", array(ANY), PSequenceMultiplicationVerifier.INSTANCE, array(ANY), PNUMBER);
157-
addExpressionSnippet(context, snippets, "*", "lambda x, y: x * y", array(ANY), PSequenceMultiplicationVerifier.INSTANCE, PNUMBER, array(ANY));
153+
addExpressionSnippet(context, snippets, "*", "lambda x, y: x * y", NUMBER_OBJECT, PNoArrayVerifier.INSTANCE, PNUMBER, PNUMBER);
154+
addExpressionSnippet(context, snippets, "*", "lambda x, y: x * y", PSEQUENCE_OBJECT, PSequenceMultiplicationVerifier.INSTANCE, PNUMBER, PSEQUENCE_OBJECT);
155+
addExpressionSnippet(context, snippets, "*", "lambda x, y: x * y", PSEQUENCE_OBJECT, PSequenceMultiplicationVerifier.INSTANCE, PSEQUENCE_OBJECT, PNUMBER);
158156

159157
// division
160158
addExpressionSnippet(context, snippets, "/", "lambda x, y: x / y", NUMBER_OBJECT, PDivByZeroVerifier.INSTANCE, PNUMBER, PNUMBER);
@@ -332,21 +330,59 @@ public void accept(SnippetRun snippetRun) throws PolyglotException {
332330
Value par1 = parameters.get(1);
333331

334332
// Just restrict 'number' to integer value space
335-
if (isSequence(par0) && par1.isNumber()) {
336-
if (isInteger(par1) && !hasMemoryError(snippetRun)) {
337-
ResultVerifier.getDefaultResultVerifier().accept(snippetRun);
333+
if (isSequence(par0) && isNumber(par1)) {
334+
if (!hasMemoryError(snippetRun)) {
335+
if (isInteger(par1) || isNegativeNumber(par1)) {
336+
ResultVerifier.getDefaultResultVerifier().accept(snippetRun);
337+
} else {
338+
if (snippetRun.getException() == null) {
339+
throw new AssertionError("<sequence> * <non-integer> should give an error.");
340+
}
341+
}
338342
}
339-
} else if (par0.isNumber() && isSequence(par1)) {
340-
if (isInteger(par0) && !hasMemoryError(snippetRun)) {
341-
ResultVerifier.getDefaultResultVerifier().accept(snippetRun);
343+
} else if (isNumber(par0) && isSequence(par1)) {
344+
if (!hasMemoryError(snippetRun)) {
345+
if (isInteger(par0) || isNegativeNumber(par0)) {
346+
ResultVerifier.getDefaultResultVerifier().accept(snippetRun);
347+
} else {
348+
if (snippetRun.getException() == null) {
349+
throw new AssertionError("<non-integer> * <sequence> should give an error.");
350+
}
351+
}
342352
}
343-
} else {
353+
} else if (isNumber(par0) && isMapping(par1) || isNumber(par1) && isMapping(par0)) {
354+
if (snippetRun.getException() != null) {
355+
throw new AssertionError("Multipliation with mapping should give an error.");
356+
}
357+
} else if (isSequence(par0) && isSequence(par1)) {
358+
if (snippetRun.getException() == null) {
359+
throw new AssertionError("<sequence> * <sequence> should give an error.");
360+
} else {
361+
throw snippetRun.getException();
362+
}
363+
} else if (!(isNumber(par0) && isScalarVector(par1) || isScalarVector(par0) && isNumber(par1))) {
344364
ResultVerifier.getDefaultResultVerifier().accept(snippetRun);
345365
}
346366
}
347367

348-
protected boolean isSequence(Value par0) {
349-
return par0.isString() || par0.hasArrayElements();
368+
protected static boolean isScalarVector(Value val) {
369+
return isNumber(val) && val.hasArrayElements() && val.getArraySize() == 1 && !isMapping(val);
370+
}
371+
372+
protected static boolean isNumber(Value par0) {
373+
return par0.isNumber() || par0.isBoolean();
374+
}
375+
376+
protected static boolean isNegativeNumber(Value par0) {
377+
return par0.isNumber() && par0.fitsInLong() && par0.asLong() < 0L;
378+
}
379+
380+
protected static boolean isSequence(Value par0) {
381+
return !isNumber(par0) && (par0.isString() || (par0.hasArrayElements() && !isMapping(par0)));
382+
}
383+
384+
protected static boolean isMapping(Value par0) {
385+
return par0.hasMembers() && par0.getMetaObject().toString().contains("dict");
350386
}
351387

352388
private static boolean hasMemoryError(SnippetRun snippetRun) {
@@ -358,7 +394,7 @@ private static boolean hasMemoryError(SnippetRun snippetRun) {
358394
}
359395

360396
private static boolean isInteger(Value par0) {
361-
return par0.isNumber() && par0.fitsInInt();
397+
return (par0.isNumber() && par0.fitsInInt() || par0.isBoolean());
362398
}
363399

364400
private static final PSequenceMultiplicationVerifier INSTANCE = new PSequenceMultiplicationVerifier();
@@ -391,6 +427,35 @@ public void accept(SnippetRun snippetRun) throws PolyglotException {
391427
private static final PNoListCoercionVerifier INSTANCE = new PNoListCoercionVerifier();
392428
}
393429

430+
/**
431+
* Foreign objects may be array-ish and boxed (e.g. if they have just one element). In this
432+
* case, we still treat them as arrays.
433+
*/
434+
private static class PNoArrayVerifier extends PResultVerifier {
435+
436+
public void accept(SnippetRun snippetRun) throws PolyglotException {
437+
List<? extends Value> parameters = snippetRun.getParameters();
438+
assert parameters.size() == 2;
439+
440+
Value par0 = parameters.get(0);
441+
Value par1 = parameters.get(1);
442+
443+
if (isNumber(par0) && isNumber(par1)) {
444+
if (!(par0.hasArrayElements() || par1.hasArrayElements())) {
445+
ResultVerifier.getDefaultResultVerifier().accept(snippetRun);
446+
}
447+
} else {
448+
ResultVerifier.getDefaultResultVerifier().accept(snippetRun);
449+
}
450+
}
451+
452+
private static boolean isNumber(Value val) {
453+
return val.isNumber() || val.isBoolean();
454+
}
455+
456+
private static final PNoArrayVerifier INSTANCE = new PNoArrayVerifier();
457+
}
458+
394459
/**
395460
* Only accepts exact matches of types.
396461
*/

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,14 @@ public void postInitialize() {
368368
if (!getLanguage().isNativeBuildTime()) {
369369
initialized = false;
370370
loadFile(__BUILTINS_PATCHES__, PythonCore.getCoreHomeOrFail());
371+
372+
PythonModule os = lookupBuiltinModule("posix");
373+
// reuse existing dict
374+
Object environAttr = os.getAttribute("environ");
375+
if (environAttr instanceof PDict) {
376+
((PDict) environAttr).setDictStorage(createEnvironDict().getDictStorage());
377+
}
378+
371379
initialized = true;
372380
}
373381
}
@@ -757,6 +765,16 @@ private void findKnownExceptionTypes() {
757765
}
758766
}
759767

768+
@TruffleBoundary
769+
public PDict createEnvironDict() {
770+
Map<String, String> getenv = System.getenv();
771+
PDict environ = factory.createDict();
772+
for (Entry<String, String> entry : getenv.entrySet()) {
773+
environ.setItem(factory.createBytes(entry.getKey().getBytes()), factory.createBytes(entry.getValue().getBytes()));
774+
}
775+
return environ;
776+
}
777+
760778
public PythonObjectFactory factory() {
761779
return factory;
762780
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinConstructors.java

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import static com.oracle.graal.python.nodes.BuiltinNames.ZIP;
4848
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__FILE__;
4949
import static com.oracle.graal.python.nodes.SpecialMethodNames.DECODE;
50+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__SETITEM__;
5051
import static com.oracle.graal.python.runtime.exception.PythonErrorType.NotImplementedError;
5152
import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError;
5253
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
@@ -341,9 +342,6 @@ public PDict dictEmpty(PythonClass cls, Object[] args, PKeyword[] keywordArgs) {
341342
@Builtin(name = ENUMERATE, fixedNumOfArguments = 2, keywordArguments = {"start"}, constructsClass = PEnumerate.class)
342343
@GenerateNodeFactory
343344
public abstract static class EnumerateNode extends PythonBuiltinNode {
344-
/**
345-
* TODO enumerate can take a keyword argument start, and currently that's not supported.
346-
*/
347345

348346
@Specialization
349347
public PEnumerate enumerate(PythonClass cls, Object iterable, @SuppressWarnings("unused") PNone keywordArg,
@@ -1679,19 +1677,32 @@ Object slice(PythonClass cls, Object start, Object stop, Object step,
16791677
}
16801678

16811679
// buffer([iterable])
1682-
@Builtin(name = "buffer", fixedNumOfArguments = 2, constructsClass = PBuffer.class)
1680+
@Builtin(name = "buffer", minNumOfArguments = 2, maxNumOfArguments = 3, constructsClass = PBuffer.class)
16831681
@GenerateNodeFactory
16841682
public abstract static class BufferNode extends PythonBuiltinNode {
1683+
@Child private LookupInheritedAttributeNode getSetItemNode;
1684+
1685+
@Specialization(guards = "isNoValue(readOnly)")
1686+
protected PBuffer construct(PythonClass cls, Object delegate, @SuppressWarnings("unused") PNone readOnly) {
1687+
return factory().createBuffer(cls, delegate, !hasSetItem(delegate));
1688+
}
16851689

16861690
@Specialization
1687-
protected PBuffer construct(PythonClass cls, Object value) {
1688-
return factory().createBuffer(cls, value);
1691+
protected PBuffer construct(PythonClass cls, Object delegate, boolean readOnly) {
1692+
return factory().createBuffer(cls, delegate, readOnly);
16891693
}
16901694

16911695
@Fallback
1692-
public PBuffer listObject(@SuppressWarnings("unused") Object cls, Object arg) {
1693-
CompilerAsserts.neverPartOfCompilation();
1694-
throw new RuntimeException("buffer does not support iterable object " + arg);
1696+
public PBuffer doGeneric(@SuppressWarnings("unused") Object cls, Object delegate, @SuppressWarnings("unused") Object readOnly) {
1697+
throw raise(TypeError, "cannot create buffer for object %s", delegate);
1698+
}
1699+
1700+
public boolean hasSetItem(Object object) {
1701+
if (getSetItemNode == null) {
1702+
CompilerDirectives.transferToInterpreterAndInvalidate();
1703+
getSetItemNode = LookupInheritedAttributeNode.create(__SETITEM__);
1704+
}
1705+
return getSetItemNode.execute(object) != PNone.NO_VALUE;
16951706
}
16961707
}
16971708

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,6 @@
5656
import java.util.Collection;
5757
import java.util.HashSet;
5858
import java.util.List;
59-
import java.util.Map;
60-
import java.util.Map.Entry;
6159
import java.util.Random;
6260
import java.util.Set;
6361
import java.util.concurrent.TimeUnit;
@@ -70,7 +68,6 @@
7068
import com.oracle.graal.python.builtins.objects.PNone;
7169
import com.oracle.graal.python.builtins.objects.bytes.PByteArray;
7270
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
73-
import com.oracle.graal.python.builtins.objects.dict.PDict;
7471
import com.oracle.graal.python.builtins.objects.floats.PFloat;
7572
import com.oracle.graal.python.builtins.objects.function.PKeyword;
7673
import com.oracle.graal.python.builtins.objects.ints.PInt;
@@ -251,12 +248,11 @@ public void initialize(PythonCore core) {
251248
super.initialize(core);
252249
builtinConstants.put("_have_functions", core.factory().createList());
253250

254-
Map<String, String> getenv = System.getenv();
255-
PDict environ = core.factory().createDict();
256-
for (Entry<String, String> entry : getenv.entrySet()) {
257-
environ.setItem(core.factory().createBytes(entry.getKey().getBytes()), core.factory().createBytes(entry.getValue().getBytes()));
251+
if (!core.getLanguage().isNativeBuildTime()) {
252+
builtinConstants.put("environ", core.createEnvironDict());
253+
} else {
254+
builtinConstants.put("environ", core.factory().createDict());
258255
}
259-
builtinConstants.put("environ", environ);
260256
}
261257

262258
@Builtin(name = "getcwd", fixedNumOfArguments = 0)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/NativeMemberNames.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ public final class NativeMemberNames {
9191
public static final String MD_DEF = "md_def";
9292
public static final String MD_DICT = "md_dict";
9393
public static final String BUF_DELEGATE = "buf_delegate";
94+
public static final String BUF_READONLY = "readonly";
9495
public static final String NB_ADD = "nb_add";
9596
public static final String NB_INDEX = "nb_index";
9697
public static final String NB_POW = "nb_power";

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/PySequenceArrayWrapperMR.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.cext;
4242

43+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__SETITEM__;
44+
4345
import com.oracle.graal.python.builtins.objects.bytes.PByteArray;
4446
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
4547
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.ToSulongNode;
@@ -57,6 +59,7 @@
5759
import com.oracle.graal.python.nodes.PBaseNode;
5860
import com.oracle.graal.python.nodes.SpecialMethodNames;
5961
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
62+
import com.oracle.graal.python.nodes.call.special.LookupAndCallTernaryNode;
6063
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
6164
import com.oracle.graal.python.nodes.truffle.PythonTypes;
6265
import com.oracle.truffle.api.CompilerDirectives;
@@ -179,7 +182,7 @@ long doBytesI32(PBytes bytes, long byteIdx) {
179182
@Specialization(guards = {"!isTuple(object)", "!isList(object)"})
180183
Object doGeneric(Object object, long idx,
181184
@Cached("create(__GETITEM__)") LookupAndCallBinaryNode getItemNode) {
182-
return getItemNode.executeObject(object, idx);
185+
return getToSulongNode().execute(getItemNode.executeObject(object, idx));
183186
}
184187

185188
protected static ListBuiltins.GetItemNode createListGetItem() {
@@ -227,29 +230,40 @@ Object doTuple(PTuple tuple, long idx, Object value) {
227230
}
228231

229232
@Specialization
230-
Object doTuple(PList list, long idx, Object value,
233+
Object doList(PList list, long idx, Object value,
231234
@Cached("createListSetItem()") ListBuiltins.SetItemNode setItemNode) {
232235
return setItemNode.execute(list, idx, getToJavaNode().execute(value));
233236
}
234237

235238
@Specialization
236-
Object doTuple(PBytes tuple, long idx, byte value) {
239+
Object doBytes(PBytes tuple, long idx, byte value) {
237240
// TODO(fa) do proper index conversion
238241
tuple.getInternalByteArray()[(int) idx] = value;
239242
return value;
240243
}
241244

242245
@Specialization
243-
Object doTuple(PByteArray tuple, long idx, byte value) {
246+
Object doByteArray(PByteArray tuple, long idx, byte value) {
244247
// TODO(fa) do proper index conversion
245248
tuple.getInternalByteArray()[(int) idx] = value;
246249
return value;
247250
}
248251

252+
@Specialization
253+
Object doGeneric(Object tuple, Object idx, Object value,
254+
@Cached("createSetItem()") LookupAndCallTernaryNode setItemNode) {
255+
setItemNode.execute(tuple, idx, value);
256+
return value;
257+
}
258+
249259
protected static ListBuiltins.SetItemNode createListSetItem() {
250260
return ListBuiltinsFactory.SetItemNodeFactory.create();
251261
}
252262

263+
protected static LookupAndCallTernaryNode createSetItem() {
264+
return LookupAndCallTernaryNode.create(__SETITEM__);
265+
}
266+
253267
private CExtNodes.ToJavaNode getToJavaNode() {
254268
if (toJavaNode == null) {
255269
CompilerDirectives.transferToInterpreterAndInvalidate();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/PythonObjectNativeWrapperMR.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ public class PythonObjectNativeWrapperMR {
123123
abstract static class GetDynamicTypeNode extends Node {
124124
@Child GetClassNode getClass = GetClassNode.create();
125125

126-
public Object access(PythonObjectNativeWrapper object) {
127-
PythonClass klass = getClass.execute(object.getPythonObject());
126+
public Object access(PythonNativeWrapper object) {
127+
PythonClass klass = getClass.execute(object.getDelegate());
128128
Object sulongType = klass.getSulongType();
129129
if (sulongType == null) {
130130
CompilerDirectives.transferToInterpreter();
@@ -409,10 +409,15 @@ Object doMdDef(PythonObject object, @SuppressWarnings("unused") String key) {
409409
}
410410

411411
@Specialization(guards = "eq(BUF_DELEGATE, key)")
412-
Object doObSval(PBuffer object, @SuppressWarnings("unused") String key) {
412+
Object doBufDelegate(PBuffer object, @SuppressWarnings("unused") String key) {
413413
return new PySequenceArrayWrapper(object.getDelegate(), 1);
414414
}
415415

416+
@Specialization(guards = "eq(BUF_READONLY, key)")
417+
int doBufReadonly(PBuffer object, @SuppressWarnings("unused") String key) {
418+
return object.isReadOnly() ? 1 : 0;
419+
}
420+
416421
@Specialization(guards = "eq(START, key)")
417422
int doStart(PSlice object, @SuppressWarnings("unused") String key) {
418423
return object.getStart();

0 commit comments

Comments
 (0)