Skip to content

Commit

Permalink
not looking good, some more work on #1558
Browse files Browse the repository at this point in the history
this time simlifying the detach routine to be less prone to graal issues
not able to avoid the synchronize for recurseAndAttach()
had to add a coupld more but thankfully only for the callonce / callsingle flows
but still saw a failure once in a while
  • Loading branch information
ptrthomas committed Jun 19, 2021
1 parent b12a4ff commit e7b3888
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,7 @@ protected void recurseAndAttach(Object o) {

private Object recurseAndAttach(Object o, Set<Object> seen) {
if (o instanceof Value) {
Value value = (Value) o;
Value value = Value.asValue(o);
try {
if (value.canExecute()) {
if (value.isMetaObject()) { // js function
Expand All @@ -1114,7 +1114,7 @@ private Object recurseAndAttach(Object o, Set<Object> seen) {
return new JsExecutable(value);
}
} else { // anything else, including java-type references
return Value.asValue(value);
return value;
}
} catch (Exception e) {
logger.warn("[attach] failed to attach js value: {}", e.getMessage());
Expand Down Expand Up @@ -1152,17 +1152,19 @@ private Object recurseAndAttach(Object o, Set<Object> seen) {
}
}

// called only by result processing of callonce / callSingle
protected Object recurseAndAttachAndDeepClone(Object o) {
Set<Object> seen = Collections.newSetFromMap(new IdentityHashMap());
return recurseAndAttachAndDeepClone(o, seen);
synchronized (runtime.featureRuntime.suite) {
return recurseAndAttachAndDeepClone(o, seen);
}
}

private Object recurseAndAttachAndDeepClone(Object o, Set<Object> seen) {
if (o instanceof Value) {
// will happen only for java "class" and java functions (static methods)
Value value = (Value) o;
try {
return Value.asValue(value);
return Value.asValue(o);
} catch (Exception e) {
logger.warn("[attach deep] failed to attach graal value: {}", e.getMessage());
return null;
Expand All @@ -1175,7 +1177,7 @@ private Object recurseAndAttachAndDeepClone(Object o, Set<Object> seen) {
if (seen.add(o)) {
List list = (List) o;
List copy = new ArrayList(list.size());
list.forEach(v -> copy.add(recurseAndAttachAndDeepClone(v)));
list.forEach(v -> copy.add(recurseAndAttachAndDeepClone(v, seen)));
return copy;
} else {
return o;
Expand All @@ -1184,7 +1186,7 @@ private Object recurseAndAttachAndDeepClone(Object o, Set<Object> seen) {
if (seen.add(o)) {
Map<String, Object> map = (Map) o;
Map<String, Object> copy = new LinkedHashMap(map.size());
map.forEach((k, v) -> copy.put(k, recurseAndAttachAndDeepClone(v)));
map.forEach((k, v) -> copy.put(k, recurseAndAttachAndDeepClone(v, seen)));
return copy;
} else {
return o;
Expand All @@ -1204,12 +1206,18 @@ protected Object recurseAndDetachAndDeepClone(Object o) {

private Object recurseAndDetachAndDeepClone(Object o, Set<Object> seen) {
if (o instanceof Value) {
Value value = (Value) o;
if (!value.isHostObject() && value.canExecute()) {
return new JsFunction(value);
}
Value value = Value.asValue(o);
try {
o = JsValue.toJava(value);
if (value.canExecute()) {
if (value.isMetaObject()) { // js function
o = new JsFunction(value);
} else { // java function
o = new JsExecutable(value);
}
} else {
// everything else including java-type references that do not need special attach handling
o = value;
}
} catch (Exception e) {
logger.warn("[detach] unsupported value in callonce / callSingle: {}", e.getMessage());
return null;
Expand Down
109 changes: 57 additions & 52 deletions karate-core/src/main/java/com/intuit/karate/graal/JsValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,62 +62,67 @@ public static enum Type {

public JsValue(Value v) {
this.original = v;
if (v.isNull()) { // apparently this can be a "host object" as well !
value = null;
type = Type.NULL;
} else if (v.isProxyObject()) {
Object o = v.asProxyObject();
if (o instanceof JsXml) {
value = ((JsXml) o).getNode();
type = Type.XML;
} else if (o instanceof JsMap) {
value = ((JsMap) o).getMap();
type = Type.OBJECT;
} else if (o instanceof JsList) {
value = ((JsList) o).getList();
try {
if (v.isNull()) { // apparently this can be a "host object" as well !
value = null;
type = Type.NULL;
} else if (v.isProxyObject()) {
Object o = v.asProxyObject();
if (o instanceof JsXml) {
value = ((JsXml) o).getNode();
type = Type.XML;
} else if (o instanceof JsMap) {
value = ((JsMap) o).getMap();
type = Type.OBJECT;
} else if (o instanceof JsList) {
value = ((JsList) o).getList();
type = Type.ARRAY;
} else if (o instanceof JsExecutable) {
value = (JsExecutable) o;
type = Type.FUNCTION;
} else { // e.g. custom bridge, e.g. Request
value = v.as(Object.class);
type = Type.OTHER;
}
} else if (v.isHostObject()) { // java object
if (v.isMetaObject()) { // java.lang.Class !
value = v; // special case, keep around as graal value
} else {
value = v.asHostObject();
}
type = Type.OTHER;
} else if (v.canExecute()) {
if (v.isMetaObject()) { // js function
value = v; // special case, keep around as graal value
} else { // java function reference
value = new JsExecutable(v);
}
type = Type.FUNCTION;
} else if (v.hasArrayElements()) {
int size = (int) v.getArraySize();
List list = new ArrayList(size);
for (int i = 0; i < size; i++) {
Value child = v.getArrayElement(i);
list.add(new JsValue(child).value);
}
value = list;
type = Type.ARRAY;
} else if (o instanceof JsExecutable) {
value = (JsExecutable) o;
type = Type.FUNCTION;
} else { // e.g. custom bridge, e.g. Request
} else if (v.hasMembers()) {
Set<String> keys = v.getMemberKeys();
Map<String, Object> map = new LinkedHashMap(keys.size());
for (String key : keys) {
Value child = v.getMember(key);
map.put(key, new JsValue(child).value);
}
value = map;
type = Type.OBJECT;
} else {
value = v.as(Object.class);
type = Type.OTHER;
}
} else if (v.isHostObject()) { // java object
if (v.isMetaObject()) { // java.lang.Class !
value = v; // special case, keep around as graal value
} else {
value = v.asHostObject();
}
type = Type.OTHER;
} else if (v.canExecute()) {
if (v.isMetaObject()) { // js function
value = v; // special case, keep around as graal value
} else { // java function reference
value = new JsExecutable(v);
}
type = Type.FUNCTION;
} else if (v.hasArrayElements()) {
int size = (int) v.getArraySize();
List list = new ArrayList(size);
for (int i = 0; i < size; i++) {
Value child = v.getArrayElement(i);
list.add(new JsValue(child).value);
}
value = list;
type = Type.ARRAY;
} else if (v.hasMembers()) {
Set<String> keys = v.getMemberKeys();
Map<String, Object> map = new LinkedHashMap(keys.size());
for (String key : keys) {
Value child = v.getMember(key);
map.put(key, new JsValue(child).value);
}
value = map;
type = Type.OBJECT;
} else {
value = v.as(Object.class);
type = Type.OTHER;
} catch (Exception e) {
logger.debug("js conversion failed", e);
throw e;
}
}

Expand Down

0 comments on commit e7b3888

Please sign in to comment.