Skip to content

Commit bbe2716

Browse files
committed
Pass the prototype at lookup depth via parameter to avoid redundant prototype walk.
1 parent 82438b3 commit bbe2716

File tree

4 files changed

+72
-72
lines changed

4 files changed

+72
-72
lines changed

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/HasPropertyCacheNode.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -334,15 +334,15 @@ protected boolean hasProperty(Object thisObj, HasPropertyCacheNode root) {
334334
* @param property The particular entry of the property being accessed.
335335
*/
336336
@Override
337-
protected HasCacheNode createCachedPropertyNode(Property property, Object thisObj, int depth, Object value, HasCacheNode currentHead) {
337+
protected HasCacheNode createCachedPropertyNode(Property property, Object thisObj, JSDynamicObject proto, int depth, Object value, HasCacheNode currentHead) {
338338
assert !isOwnProperty() || depth == 0;
339339
ReceiverCheckNode check;
340340
if (JSDynamicObject.isJSDynamicObject(thisObj)) {
341341
JSDynamicObject thisJSObj = (JSDynamicObject) thisObj;
342342
Shape cacheShape = thisJSObj.getShape();
343-
check = createShapeCheckNode(cacheShape, thisJSObj, depth, false, false);
343+
check = createShapeCheckNode(cacheShape, thisJSObj, proto, depth, false, false);
344344
} else {
345-
check = createPrimitiveReceiverCheck(thisObj, depth);
345+
check = createPrimitiveReceiverCheck(thisObj, proto, depth);
346346
}
347347
if (hasOwnProperty && JSProperty.isModuleNamespaceExport(property)) {
348348
return new ModuleNamespaceHasOwnPropertyNode(check, property);
@@ -351,32 +351,32 @@ protected HasCacheNode createCachedPropertyNode(Property property, Object thisOb
351351
}
352352

353353
@Override
354-
protected HasCacheNode createUndefinedPropertyNode(Object thisObj, Object store, int depth, Object value) {
355-
HasCacheNode specialized = createJavaPropertyNodeMaybe(thisObj, depth);
354+
protected HasCacheNode createUndefinedPropertyNode(Object thisObj, Object store, JSDynamicObject proto, int depth, Object value) {
355+
HasCacheNode specialized = createJavaPropertyNodeMaybe(thisObj, proto, depth);
356356
if (specialized != null) {
357357
return specialized;
358358
}
359359
if (JSDynamicObject.isJSDynamicObject(thisObj)) {
360360
JSDynamicObject thisJSObj = (JSDynamicObject) thisObj;
361361
Shape cacheShape = thisJSObj.getShape();
362362
if (JSAdapter.isJSAdapter(store)) {
363-
return new JSAdapterHasPropertyCacheNode(key, createJSClassCheck(thisObj, depth));
363+
return new JSAdapterHasPropertyCacheNode(key, createJSClassCheck(thisObj, proto, depth));
364364
} else if (JSProxy.isJSProxy(store)) {
365-
return new JSProxyDispatcherPropertyHasNode(context, key, createJSClassCheck(thisObj, depth), isOwnProperty());
365+
return new JSProxyDispatcherPropertyHasNode(context, key, createJSClassCheck(thisObj, proto, depth), isOwnProperty());
366366
} else {
367-
return new AbsentHasPropertyCacheNode(createShapeCheckNode(cacheShape, thisJSObj, depth, false, false));
367+
return new AbsentHasPropertyCacheNode(createShapeCheckNode(cacheShape, thisJSObj, proto, depth, false, false));
368368
}
369369
} else {
370370
return new AbsentHasPropertyCacheNode(new InstanceofCheckNode(thisObj.getClass()));
371371
}
372372
}
373373

374374
@Override
375-
protected HasCacheNode createJavaPropertyNodeMaybe(Object thisObj, int depth) {
375+
protected HasCacheNode createJavaPropertyNodeMaybe(Object thisObj, JSDynamicObject proto, int depth) {
376376
if (JavaPackage.isJavaPackage(thisObj)) {
377-
return new PresentHasPropertyCacheNode(createJSClassCheck(thisObj, depth));
377+
return new PresentHasPropertyCacheNode(createJSClassCheck(thisObj, proto, depth));
378378
} else if (JavaImporter.isJavaImporter(thisObj)) {
379-
return new UnspecializedHasPropertyCacheNode(createJSClassCheck(thisObj, depth));
379+
return new UnspecializedHasPropertyCacheNode(createJSClassCheck(thisObj, proto, depth));
380380
}
381381
return null;
382382
}

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyCacheNode.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -893,11 +893,11 @@ public final Object getKey() {
893893

894894
protected abstract T createGenericPropertyNode();
895895

896-
protected abstract T createCachedPropertyNode(Property entry, Object thisObj, int depth, Object value, T currentHead);
896+
protected abstract T createCachedPropertyNode(Property entry, Object thisObj, JSDynamicObject proto, int depth, Object value, T currentHead);
897897

898-
protected abstract T createUndefinedPropertyNode(Object thisObj, Object store, int depth, Object value);
898+
protected abstract T createUndefinedPropertyNode(Object thisObj, Object store, JSDynamicObject proto, int depth, Object value);
899899

900-
protected abstract T createJavaPropertyNodeMaybe(Object thisObj, int depth);
900+
protected abstract T createJavaPropertyNodeMaybe(Object thisObj, JSDynamicObject proto, int depth);
901901

902902
protected abstract T createTruffleObjectPropertyNode();
903903

@@ -1027,13 +1027,13 @@ protected T createSpecialization(Object thisObj, T currentHead, int cachedCount,
10271027
}
10281028

10291029
if (property != null) {
1030-
specialized = createCachedPropertyNode(property, thisObj, depth, value, currentHead);
1030+
specialized = createCachedPropertyNode(property, thisObj, store, depth, value, currentHead);
10311031
if (specialized == null) {
10321032
return null;
10331033
}
10341034
break;
10351035
} else if (alwaysUseStore(store, key)) {
1036-
specialized = createUndefinedPropertyNode(thisObj, store, depth, value);
1036+
specialized = createUndefinedPropertyNode(thisObj, store, store, depth, value);
10371037
break;
10381038
} else if (isOwnProperty()) {
10391039
break;
@@ -1053,7 +1053,7 @@ protected T createSpecialization(Object thisObj, T currentHead, int cachedCount,
10531053
// e.g. depth == 3 for obj0 -> proto1 -> proto2 -> null.
10541054

10551055
if (specialized == null) {
1056-
specialized = createUndefinedPropertyNode(thisObj, thisObj, depth, value);
1056+
specialized = createUndefinedPropertyNode(thisObj, thisObj, Null.instance, depth, value);
10571057
}
10581058

10591059
if (cachedCount >= context.getPropertyCacheLimit() || specialized.isGeneric()) {
@@ -1248,11 +1248,11 @@ protected static final JSDynamicObject wrapPrimitive(Object thisObject) {
12481248
return JSObject.isJSObject(wrapper) ? ((JSObject) wrapper) : null;
12491249
}
12501250

1251-
protected final AbstractShapeCheckNode createShapeCheckNode(Shape shape, JSDynamicObject thisObj, int depth, boolean isConstantObjectFinal, boolean isDefine) {
1251+
protected final AbstractShapeCheckNode createShapeCheckNode(Shape shape, JSDynamicObject thisObj, JSDynamicObject proto, int depth, boolean isConstantObjectFinal, boolean isDefine) {
12521252
if (depth == 0) {
12531253
return createShapeCheckNodeDepth0(shape, thisObj, isConstantObjectFinal, isDefine);
12541254
} else {
1255-
return createShapeCheckNodeDeeper(shape, thisObj, depth, isConstantObjectFinal);
1255+
return createShapeCheckNodeDeeper(shape, thisObj, proto, depth, isConstantObjectFinal);
12561256
}
12571257
}
12581258

@@ -1267,9 +1267,9 @@ private AbstractShapeCheckNode createShapeCheckNodeDepth0(Shape shape, JSDynamic
12671267
}
12681268
}
12691269

1270-
private AbstractShapeCheckNode createShapeCheckNodeDeeper(Shape shape, JSDynamicObject thisObj, int depth, boolean isConstantObjectFinal) {
1270+
private AbstractShapeCheckNode createShapeCheckNodeDeeper(Shape shape, JSDynamicObject thisObj, JSDynamicObject protoAtDepth, int depth, boolean isConstantObjectFinal) {
12711271
assert depth >= 1;
1272-
JSDynamicObject protoAtDepth = getPrototypeAtDepth(thisObj, depth);
1272+
assert protoAtDepth == getPrototypeAtDepth(thisObj, depth);
12731273
boolean allPrototypesInShape = prototypesInShape(thisObj, 0, depth);
12741274
if (JSConfig.SkipPrototypeShapeCheck && allPrototypesInShape && propertyAssumptionsValid(thisObj, depth, isConstantObjectFinal)) {
12751275
if (isConstantObjectFinal) {
@@ -1355,14 +1355,14 @@ protected final boolean propertyAssumptionsValid(JSDynamicObject thisObj, int de
13551355
return true;
13561356
}
13571357

1358-
protected final ReceiverCheckNode createPrimitiveReceiverCheck(Object thisObj, int depth) {
1358+
protected final ReceiverCheckNode createPrimitiveReceiverCheck(Object thisObj, JSDynamicObject protoAtDepth, int depth) {
13591359
Class<?> valueClass = thisObj.getClass();
13601360
if (depth == 0) {
13611361
return new InstanceofCheckNode(valueClass);
13621362
} else {
13631363
assert JSRuntime.isJSPrimitive(thisObj) || thisObj instanceof Long;
13641364
JSDynamicObject wrapped = wrapPrimitive(thisObj);
1365-
JSDynamicObject protoAtDepth = getPrototypeAtDepth(wrapped, depth);
1365+
assert protoAtDepth == getPrototypeAtDepth(wrapped, depth);
13661366
boolean allPrototypesInShape = prototypesInShape(wrapped, 0, depth);
13671367
if (JSConfig.SkipPrototypeShapeCheck && allPrototypesInShape && propertyAssumptionsValid(wrapped, depth, false)) {
13681368
return ValuePrototypeChainCheckNode.create(valueClass, wrapped.getShape(), wrapped, key, depth, context);
@@ -1376,12 +1376,12 @@ protected final ReceiverCheckNode createPrimitiveReceiverCheck(Object thisObj, i
13761376
}
13771377
}
13781378

1379-
protected final ReceiverCheckNode createJSClassCheck(Object thisObj, int depth) {
1379+
protected final ReceiverCheckNode createJSClassCheck(Object thisObj, JSDynamicObject proto, int depth) {
13801380
JSDynamicObject jsobject = (JSDynamicObject) thisObj;
13811381
if (depth == 0) {
13821382
return new InstanceofCheckNode(jsobject.getClass());
13831383
} else {
1384-
return createShapeCheckNode(jsobject.getShape(), jsobject, depth, false, false);
1384+
return createShapeCheckNode(jsobject.getShape(), jsobject, proto, depth, false, false);
13851385
}
13861386
}
13871387

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyGetNode.java

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,10 +1857,10 @@ protected Object getValue(Object thisObj, Object receiver, Object defaultValue,
18571857
* @param property The particular entry of the property being accessed.
18581858
*/
18591859
@Override
1860-
protected GetCacheNode createCachedPropertyNode(Property property, Object thisObj, int depth, Object value, GetCacheNode currentHead) {
1860+
protected GetCacheNode createCachedPropertyNode(Property property, Object thisObj, JSDynamicObject proto, int depth, Object value, GetCacheNode currentHead) {
18611861
assert !isOwnProperty() || depth == 0;
18621862
if (!(JSDynamicObject.isJSDynamicObject(thisObj))) {
1863-
return createCachedPropertyNodeNotJSObject(property, thisObj, depth);
1863+
return createCachedPropertyNodeNotJSObject(property, thisObj, proto, depth);
18641864
}
18651865

18661866
JSDynamicObject thisJSObj = (JSDynamicObject) thisObj;
@@ -1898,16 +1898,16 @@ protected GetCacheNode createCachedPropertyNode(Property property, Object thisOb
18981898

18991899
if (JSProperty.isData(property) && !JSProperty.isDataSpecial(property)) {
19001900
if (isEligibleForFinalSpecialization(cacheShape, thisJSObj, depth, isConstantObjectFinal)) {
1901-
return createFinalDataPropertySpecialization(property, cacheShape, thisJSObj, depth, isConstantObjectFinal);
1901+
return createFinalDataPropertySpecialization(property, cacheShape, thisJSObj, proto, depth, isConstantObjectFinal);
19021902
}
19031903
} else if (JSProperty.isAccessor(property)) {
19041904
if (isEligibleForFinalSpecialization(cacheShape, thisJSObj, depth, isConstantObjectFinal)) {
1905-
return createFinalAccessorSpecialization(property, cacheShape, thisJSObj, depth, isConstantObjectFinal);
1905+
return createFinalAccessorSpecialization(property, cacheShape, thisJSObj, proto, depth, isConstantObjectFinal);
19061906
}
19071907
}
19081908
}
19091909

1910-
AbstractShapeCheckNode shapeCheck = createShapeCheckNode(cacheShape, thisJSObj, depth, false, false);
1910+
AbstractShapeCheckNode shapeCheck = createShapeCheckNode(cacheShape, thisJSObj, proto, depth, false, false);
19111911
if (JSProperty.isData(property)) {
19121912
return createSpecializationFromDataProperty(property, shapeCheck, context);
19131913
} else {
@@ -1928,15 +1928,15 @@ private boolean isEligibleForFinalSpecialization(Shape cacheShape, JSDynamicObje
19281928
}
19291929
}
19301930

1931-
private GetCacheNode createCachedPropertyNodeNotJSObject(Property property, Object thisObj, int depth) {
1931+
private GetCacheNode createCachedPropertyNodeNotJSObject(Property property, Object thisObj, JSDynamicObject proto, int depth) {
19321932
final ReceiverCheckNode receiverCheck;
19331933
if (depth == 0) {
19341934
if (isMethod() && Strings.isTString(thisObj) && context.isOptionNashornCompatibilityMode()) {
19351935
// This hack ensures we get the Java method instead of the JavaScript property
19361936
// for length in s.length() where s is a java.lang.String. Required by Nashorn.
19371937
// We do this only for depth 0, because JavaScript prototype functions in turn
19381938
// are preferred over Java methods with the same name.
1939-
GetCacheNode javaPropertyNode = createJavaPropertyNodeMaybe(thisObj, depth);
1939+
GetCacheNode javaPropertyNode = createJavaPropertyNodeMaybe(thisObj, proto, depth);
19401940
if (javaPropertyNode != null) {
19411941
return javaPropertyNode;
19421942
}
@@ -1948,7 +1948,7 @@ private GetCacheNode createCachedPropertyNodeNotJSObject(Property property, Obje
19481948
return new StringLengthPropertyGetNode(property, receiverCheck);
19491949
}
19501950
} else {
1951-
receiverCheck = createPrimitiveReceiverCheck(thisObj, depth);
1951+
receiverCheck = createPrimitiveReceiverCheck(thisObj, proto, depth);
19521952
}
19531953

19541954
if (JSProperty.isData(property)) {
@@ -1996,8 +1996,8 @@ private static GetCacheNode createSpecializationFromDataProperty(Property proper
19961996
}
19971997
}
19981998

1999-
private GetCacheNode createFinalDataPropertySpecialization(Property property, Shape cacheShape, JSDynamicObject thisObj, int depth, boolean isConstantObjectFinal) {
2000-
AbstractShapeCheckNode finalShapeCheckNode = createShapeCheckNode(cacheShape, thisObj, depth, isConstantObjectFinal, false);
1999+
private GetCacheNode createFinalDataPropertySpecialization(Property property, Shape cacheShape, JSDynamicObject thisObj, JSDynamicObject proto, int depth, boolean isConstantObjectFinal) {
2000+
AbstractShapeCheckNode finalShapeCheckNode = createShapeCheckNode(cacheShape, thisObj, proto, depth, isConstantObjectFinal, false);
20012001
finalShapeCheckNode.adoptChildren();
20022002
JSDynamicObject store = finalShapeCheckNode.getStore(thisObj);
20032003

@@ -2024,8 +2024,8 @@ private GetCacheNode createFinalDataPropertySpecialization(Property property, Sh
20242024
}
20252025
}
20262026

2027-
private GetCacheNode createFinalAccessorSpecialization(Property property, Shape cacheShape, JSDynamicObject thisObj, int depth, boolean isConstantObjectFinal) {
2028-
AbstractShapeCheckNode finalShapeCheckNode = createShapeCheckNode(cacheShape, thisObj, depth, isConstantObjectFinal, false);
2027+
private GetCacheNode createFinalAccessorSpecialization(Property property, Shape cacheShape, JSDynamicObject thisObj, JSDynamicObject proto, int depth, boolean isConstantObjectFinal) {
2028+
AbstractShapeCheckNode finalShapeCheckNode = createShapeCheckNode(cacheShape, thisObj, proto, depth, isConstantObjectFinal, false);
20292029
finalShapeCheckNode.adoptChildren();
20302030
JSDynamicObject store = finalShapeCheckNode.getStore(thisObj);
20312031
Accessor accessor = (Accessor) property.getLocation().get(store, null);
@@ -2034,47 +2034,47 @@ private GetCacheNode createFinalAccessorSpecialization(Property property, Shape
20342034
}
20352035

20362036
@Override
2037-
protected GetCacheNode createJavaPropertyNodeMaybe(Object thisObj, int depth) {
2037+
protected GetCacheNode createJavaPropertyNodeMaybe(Object thisObj, JSDynamicObject proto, int depth) {
20382038
if (JavaPackage.isJavaPackage(thisObj)) {
2039-
return new JavaPackagePropertyGetNode(createJSClassCheck(thisObj, depth));
2039+
return new JavaPackagePropertyGetNode(createJSClassCheck(thisObj, proto, depth));
20402040
} else if (JavaImporter.isJavaImporter(thisObj)) {
2041-
return new UnspecializedPropertyGetNode(createJSClassCheck(thisObj, depth));
2041+
return new UnspecializedPropertyGetNode(createJSClassCheck(thisObj, proto, depth));
20422042
}
20432043
if (JSConfig.SubstrateVM) {
20442044
return null;
20452045
}
20462046
if (context.isOptionNashornCompatibilityMode() && getRealm().isJavaInteropEnabled()) {
20472047
if (Strings.isTString(thisObj) && isMethod()) {
2048-
return new JavaStringMethodGetNode(createPrimitiveReceiverCheck(thisObj, depth));
2048+
return new JavaStringMethodGetNode(createPrimitiveReceiverCheck(thisObj, proto, depth));
20492049
}
20502050
}
20512051
return null;
20522052
}
20532053

20542054
@Override
2055-
protected GetCacheNode createUndefinedPropertyNode(Object thisObj, Object store, int depth, Object value) {
2056-
GetCacheNode javaPropertyNode = createJavaPropertyNodeMaybe(thisObj, depth);
2055+
protected GetCacheNode createUndefinedPropertyNode(Object thisObj, Object store, JSDynamicObject proto, int depth, Object value) {
2056+
GetCacheNode javaPropertyNode = createJavaPropertyNodeMaybe(thisObj, proto, depth);
20572057
if (javaPropertyNode != null) {
20582058
return javaPropertyNode;
20592059
}
20602060

20612061
if (JSDynamicObject.isJSDynamicObject(thisObj)) {
20622062
JSDynamicObject jsobject = (JSDynamicObject) thisObj;
20632063
if (JSAdapter.isJSAdapter(store)) {
2064-
return new JSAdapterPropertyGetNode(createJSClassCheck(thisObj, depth));
2064+
return new JSAdapterPropertyGetNode(createJSClassCheck(thisObj, proto, depth));
20652065
} else if (JSProxy.isJSProxy(store) && JSRuntime.isPropertyKey(key)) {
2066-
return createJSProxyCache(createJSClassCheck(thisObj, depth));
2066+
return createJSProxyCache(createJSClassCheck(thisObj, proto, depth));
20672067
} else {
2068-
return createUndefinedJSObjectPropertyNode(jsobject, depth);
2068+
return createUndefinedJSObjectPropertyNode(jsobject, proto, depth);
20692069
}
20702070
} else if (JSProxy.isJSProxy(store)) {
2071-
ReceiverCheckNode receiverCheck = createPrimitiveReceiverCheck(thisObj, depth);
2071+
ReceiverCheckNode receiverCheck = createPrimitiveReceiverCheck(thisObj, proto, depth);
20722072
return createJSProxyCache(receiverCheck);
20732073
} else {
20742074
if (thisObj == null) {
20752075
return new TypeErrorPropertyGetNode(new NullCheckNode());
20762076
} else {
2077-
ReceiverCheckNode receiverCheck = createPrimitiveReceiverCheck(thisObj, depth);
2077+
ReceiverCheckNode receiverCheck = createPrimitiveReceiverCheck(thisObj, proto, depth);
20782078
return createUndefinedOrErrorPropertyNode(receiverCheck);
20792079
}
20802080
}
@@ -2101,8 +2101,8 @@ private boolean isProxyHandlerGetNode() {
21012101
return (parent instanceof JSProxyPropertyGetNode);
21022102
}
21032103

2104-
private GetCacheNode createUndefinedJSObjectPropertyNode(JSDynamicObject jsobject, int depth) {
2105-
AbstractShapeCheckNode shapeCheck = createShapeCheckNode(jsobject.getShape(), jsobject, depth, false, false);
2104+
private GetCacheNode createUndefinedJSObjectPropertyNode(JSDynamicObject jsobject, JSDynamicObject proto, int depth) {
2105+
AbstractShapeCheckNode shapeCheck = createShapeCheckNode(jsobject.getShape(), jsobject, proto, depth, false, false);
21062106
if (JSRuntime.isObject(jsobject)) {
21072107
if (context.isOptionNashornCompatibilityMode() && !(key instanceof Symbol)) {
21082108
if ((!context.getNoSuchMethodUnusedAssumption().isValid() && JSObject.hasProperty(jsobject, JSObject.NO_SUCH_METHOD_NAME)) ||

0 commit comments

Comments
 (0)