Skip to content

Commit 99c0fa3

Browse files
committed
[GR-36883] Fix multiple bases with instance lay-out conflict.
PullRequest: graalpython/2143
2 parents 2ecb3ef + 5daff2b commit 99c0fa3

File tree

3 files changed

+82
-28
lines changed

3 files changed

+82
-28
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_type.py

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -153,6 +153,7 @@ class C(A, B): pass
153153
# assert raised
154154
# assert C.__bases__ == [object]
155155

156+
156157
def test_namespace_with_non_string_keys():
157158
class MyStr(str):
158159
pass
@@ -162,6 +163,7 @@ class MyStr(str):
162163
})
163164
assert any(type(k) == MyStr for k in A.__dict__.keys())
164165

166+
165167
def test_mro():
166168
class M(type):
167169
def mro(cls):
@@ -173,7 +175,8 @@ class B: pass
173175
class C(A, B, metaclass = M): pass
174176

175177
assert C.__mro__ == (C, B, A, object)
176-
178+
179+
177180
def test_dir_sorted():
178181
class C:
179182
b = 1
@@ -253,6 +256,7 @@ class MyDict(dict):
253256
]:
254257
assert type(x).__flags__ & flag, "masked __flags__ = {}, expected {}".format(type(x).__flags__ & flag, flag)
255258

259+
256260
def test_dict():
257261
def dict_element_raises(o, err):
258262
raised = False
@@ -295,7 +299,8 @@ class SubSlots(BaseSlots, Base):
295299

296300
str(type(SubSlots.__dict__['__dict__'])) == "<class 'get_set_desc'>"
297301
assert SubSlots().__dict__ == {}
298-
302+
303+
299304
def test_itemsize():
300305
assert object.__itemsize__ == 0
301306
assert list.__itemsize__ == 0
@@ -330,7 +335,8 @@ class C():
330335
class C(tuple):
331336
__itemsize__ = 42
332337
assert C.__itemsize__ == 8
333-
338+
339+
334340
def test_descr_name_qualname():
335341
assert float.real.__qualname__ == 'float.real'
336342
assert float.real.__name__ == 'real'
@@ -349,7 +355,8 @@ class C: __slots__ = ['a']
349355
except AttributeError:
350356
raised = True
351357
assert raised
352-
358+
359+
353360
def test_cant_set_builtin_attributes():
354361
raised = False
355362
try:
@@ -392,3 +399,41 @@ def test_cant_set_builtin_attributes():
392399
except TypeError:
393400
raised = True
394401
assert raised
402+
403+
404+
def test_slots_no_instance_layout_conflict():
405+
# with slots
406+
class A(object):
407+
__slots__ = ("a", "b")
408+
409+
class B(A):
410+
pass
411+
412+
class C(A):
413+
pass
414+
415+
raised = False
416+
try:
417+
class D(B, C):
418+
pass
419+
except TypeError:
420+
raised = True
421+
assert not raised
422+
423+
# without slots
424+
class A(object):
425+
pass
426+
427+
class B(A):
428+
pass
429+
430+
class C(A):
431+
pass
432+
433+
raised = False
434+
try:
435+
class D(B, C):
436+
pass
437+
except TypeError:
438+
raised = True
439+
assert not raised

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SequenceStorageNodes.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2021, Oracle and/or its affiliates.
2+
* Copyright (c) 2018, 2022, Oracle and/or its affiliates.
33
* Copyright (c) 2013, Regents of the University of California
44
*
55
* All rights reserved.
@@ -3624,6 +3624,10 @@ private static Object[] materializeGeneric(SequenceStorage s, int len, GetItemSc
36243624
}
36253625
return barr;
36263626
}
3627+
3628+
public static GetInternalObjectArrayNode getUncached() {
3629+
return SequenceStorageNodesFactory.GetInternalObjectArrayNodeGen.getUncached();
3630+
}
36273631
}
36283632

36293633
@GenerateUncached

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,30 +1104,29 @@ static GetSolidBaseNode getUncached() {
11041104
protected Object getSolid(Object type,
11051105
@Cached GetBaseClassNode getBaseClassNode,
11061106
@Cached("createForceType()") ReadAttributeFromObjectNode readAttr,
1107-
@Cached GetInternalObjectArrayNode getArrayNode,
11081107
@Cached BranchProfile typeIsNotBase,
11091108
@Cached BranchProfile hasBase,
11101109
@Cached BranchProfile hasNoBase) {
1111-
return solidBase(type, getBaseClassNode, PythonContext.get(this), readAttr, getArrayNode, typeIsNotBase, hasBase,
1110+
return solidBase(type, getBaseClassNode, PythonContext.get(this), readAttr, typeIsNotBase, hasBase,
11121111
hasNoBase, 0);
11131112
}
11141113

11151114
@TruffleBoundary
1116-
protected Object solidBaseTB(Object type, GetBaseClassNode getBaseClassNode, PythonContext context, GetInternalObjectArrayNode getArrayNode, int depth) {
1117-
return solidBase(type, getBaseClassNode, context, ReadAttributeFromObjectNode.getUncachedForceType(), getArrayNode, BranchProfile.getUncached(),
1115+
protected Object solidBaseTB(Object type, GetBaseClassNode getBaseClassNode, PythonContext context, int depth) {
1116+
return solidBase(type, getBaseClassNode, context, ReadAttributeFromObjectNode.getUncachedForceType(), BranchProfile.getUncached(),
11181117
BranchProfile.getUncached(), BranchProfile.getUncached(), depth);
11191118
}
11201119

11211120
protected Object solidBase(Object type, GetBaseClassNode getBaseClassNode, PythonContext context, ReadAttributeFromObjectNode readAttr,
1122-
GetInternalObjectArrayNode getArrayNode, BranchProfile typeIsNotBase, BranchProfile hasBase, BranchProfile hasNoBase, int depth) {
1121+
BranchProfile typeIsNotBase, BranchProfile hasBase, BranchProfile hasNoBase, int depth) {
11231122
CompilerAsserts.partialEvaluationConstant(depth);
11241123
Object base = getBaseClassNode.execute(type);
11251124
if (base != null) {
11261125
hasBase.enter();
11271126
if (depth > 3) {
1128-
base = solidBaseTB(base, getBaseClassNode, context, getArrayNode, depth);
1127+
base = solidBaseTB(base, getBaseClassNode, context, depth);
11291128
} else {
1130-
base = solidBase(base, getBaseClassNode, context, readAttr, getArrayNode, typeIsNotBase, hasBase,
1129+
base = solidBase(base, getBaseClassNode, context, readAttr, typeIsNotBase, hasBase,
11311130
hasNoBase, depth + 1);
11321131
}
11331132
} else {
@@ -1141,18 +1140,16 @@ protected Object solidBase(Object type, GetBaseClassNode getBaseClassNode, Pytho
11411140
typeIsNotBase.enter();
11421141

11431142
Object typeSlots = getSlotsFromType(type, readAttr);
1144-
Object baseSlots = getSlotsFromType(base, readAttr);
1145-
if (extraivars(type, base, typeSlots, baseSlots, getArrayNode)) {
1143+
if (extraivars(type, base, typeSlots)) {
11461144
return type;
11471145
} else {
11481146
return base;
11491147
}
11501148
}
11511149

11521150
@TruffleBoundary
1153-
private static boolean extraivars(Object type, Object base, Object typeSlots, Object baseSlots, GetInternalObjectArrayNode getArrayNode) {
1154-
if (typeSlots == null && baseSlots != null && length(((PSequence) baseSlots).getSequenceStorage(), getArrayNode) != 0 ||
1155-
baseSlots == null && typeSlots != null && length(((PSequence) typeSlots).getSequenceStorage(), getArrayNode) != 0) {
1151+
private static boolean extraivars(Object type, Object base, Object typeSlots) {
1152+
if (typeSlots != null && length(typeSlots) != 0) {
11561153
return true;
11571154
}
11581155
Object typeNewMethod = LookupAttributeInMRONode.lookup(type, __NEW__, GetMroStorageNode.getUncached(), ReadAttributeFromObjectNode.getUncached(), true);
@@ -1161,18 +1158,26 @@ private static boolean extraivars(Object type, Object base, Object typeSlots, Ob
11611158
}
11621159

11631160
@TruffleBoundary
1164-
private static int length(SequenceStorage storage, GetInternalObjectArrayNode getArrayNode) {
1165-
int result = 0;
1166-
int length = storage.length();
1167-
Object[] slots = getArrayNode.execute(storage);
1168-
for (int i = 0; i < length; i++) {
1169-
// omit __DICT__ and __WEAKREF__, they cause no class layout conflict
1170-
// see also test_slts.py#test_no_bases_have_class_layout_conflict
1171-
if (!(slots[i].equals(__DICT__) || slots[i].equals(__WEAKREF__))) {
1172-
result++;
1161+
private static int length(Object slotsObject) {
1162+
assert PGuards.isString(slotsObject) || PGuards.isPSequence(slotsObject) : "slotsObject must be either a String or a PSequence";
1163+
1164+
if (PGuards.isString(slotsObject)) {
1165+
return (slotsObject.equals(__DICT__) || slotsObject.equals(__WEAKREF__)) ? 0 : 1;
1166+
} else {
1167+
SequenceStorage storage = ((PSequence) slotsObject).getSequenceStorage();
1168+
1169+
int count = 0;
1170+
int length = storage.length();
1171+
Object[] slots = GetInternalObjectArrayNode.getUncached().execute(storage);
1172+
for (int i = 0; i < length; i++) {
1173+
// omit __DICT__ and __WEAKREF__, they cause no class layout conflict
1174+
// see also test_slts.py#test_no_bases_have_class_layout_conflict
1175+
if (!(slots[i].equals(__DICT__) || slots[i].equals(__WEAKREF__))) {
1176+
count++;
1177+
}
11731178
}
1179+
return count;
11741180
}
1175-
return result;
11761181
}
11771182

11781183
private static Object getSlotsFromType(Object type, ReadAttributeFromObjectNode readAttr) {

0 commit comments

Comments
 (0)