# HG changeset patch # User Andreas Woess # Date 1416308931 -3600 # Node ID 997bc9764a9ae72704f74bef8e5f7d05a2b940a4 # Parent dc2e000bed40a72e89ba0f63960691162475914d SL: use the truffle object storage model to represent SL objects diff -r dc2e000bed40 -r 997bc9764a9a graal/com.oracle.truffle.sl.test/tests/Object.sl --- a/graal/com.oracle.truffle.sl.test/tests/Object.sl Tue Nov 18 23:02:58 2014 +0100 +++ b/graal/com.oracle.truffle.sl.test/tests/Object.sl Tue Nov 18 12:08:51 2014 +0100 @@ -15,6 +15,14 @@ obj3 = new(); obj3.fn = mkobj; println(obj3.fn().z); + + obj4 = new(); + write(obj4, 1); + read(obj4); + write(obj4, 2); + read(obj4); + write(obj4, "three"); + read(obj4); } function mkobj() { @@ -22,3 +30,11 @@ newobj.z = "zzz"; return newobj; } + +function read(obj) { + return obj.prop; +} + +function write(obj, value) { + return obj.prop = value; +} diff -r dc2e000bed40 -r 997bc9764a9a graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLNewObjectBuiltin.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLNewObjectBuiltin.java Tue Nov 18 23:02:58 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLNewObjectBuiltin.java Tue Nov 18 12:08:51 2014 +0100 @@ -22,8 +22,6 @@ */ package com.oracle.truffle.sl.builtins; -import java.util.*; - import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.nodes.*; @@ -48,6 +46,6 @@ @Specialization public Object newObject() { - return new HashMap<>(); + return getContext().createObject(); } } diff -r dc2e000bed40 -r 997bc9764a9a graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyCacheNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyCacheNode.java Tue Nov 18 12:08:51 2014 +0100 @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.sl.nodes.access; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.object.*; +import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * The node for accessing a property of an object. When executed, this node first evaluates the + * object expression on the left side of the dot operator and then reads the named property. + */ +public abstract class SLReadPropertyCacheNode extends Node { + + public static SLReadPropertyCacheNode create(String propertyName) { + return new SLUninitializedReadObjectPropertyNode(propertyName); + } + + public abstract Object executeObject(DynamicObject receiver); + + public abstract long executeLong(DynamicObject receiver) throws UnexpectedResultException; + + protected abstract static class SLReadPropertyCacheChainNode extends SLReadPropertyCacheNode { + protected final Shape shape; + @Child protected SLReadPropertyCacheNode next; + + public SLReadPropertyCacheChainNode(Shape shape, SLReadPropertyCacheNode next) { + this.shape = shape; + this.next = next; + } + + @Override + public final Object executeObject(DynamicObject receiver) { + try { + // if this assumption fails, the object needs to be updated to a valid shape + shape.getValidAssumption().check(); + } catch (InvalidAssumptionException e) { + return this.replace(next).executeObject(receiver); + } + + boolean condition = shape.check(receiver); + + if (condition) { + return executeObjectUnchecked(receiver, condition); + } else { + return next.executeObject(receiver); + } + } + + @Override + public final long executeLong(DynamicObject receiver) throws UnexpectedResultException { + try { + // if this assumption fails, the object needs to be updated to a valid shape + shape.getValidAssumption().check(); + } catch (InvalidAssumptionException e) { + return this.replace(next).executeLong(receiver); + } + + boolean condition = shape.check(receiver); + + if (condition) { + return executeLongUnchecked(receiver, condition); + } else { + return next.executeLong(receiver); + } + } + + protected abstract Object executeObjectUnchecked(DynamicObject receiver, boolean condition); + + protected long executeLongUnchecked(DynamicObject receiver, boolean condition) throws UnexpectedResultException { + return SLTypesGen.SLTYPES.expectLong(executeObjectUnchecked(receiver, condition)); + } + } + + protected static class SLReadObjectPropertyNode extends SLReadPropertyCacheChainNode { + private final Location location; + + protected SLReadObjectPropertyNode(Shape shape, Location location, SLReadPropertyCacheNode next) { + super(shape, next); + this.location = location; + } + + @Override + protected Object executeObjectUnchecked(DynamicObject receiver, boolean condition) { + return location.get(receiver, condition); + } + } + + protected static class SLReadBooleanPropertyNode extends SLReadPropertyCacheChainNode { + private final BooleanLocation location; + + protected SLReadBooleanPropertyNode(Shape shape, BooleanLocation location, SLReadPropertyCacheNode next) { + super(shape, next); + this.location = location; + } + + @Override + protected Object executeObjectUnchecked(DynamicObject receiver, boolean condition) { + return location.getBoolean(receiver, condition); + } + } + + protected static class SLReadLongPropertyNode extends SLReadPropertyCacheChainNode { + private final LongLocation location; + + protected SLReadLongPropertyNode(Shape shape, LongLocation location, SLReadPropertyCacheNode next) { + super(shape, next); + this.location = location; + } + + @Override + protected Object executeObjectUnchecked(DynamicObject receiver, boolean condition) { + return location.getLong(receiver, condition); + } + + @Override + protected long executeLongUnchecked(DynamicObject receiver, boolean condition) throws UnexpectedResultException { + return location.getLong(receiver, condition); + } + } + + protected static class SLReadMissingPropertyNode extends SLReadPropertyCacheChainNode { + protected SLReadMissingPropertyNode(Shape shape, SLReadPropertyCacheNode next) { + super(shape, next); + } + + @Override + protected Object executeObjectUnchecked(DynamicObject receiver, boolean condition) { + // The property was not found in the object, return null + return SLNull.SINGLETON; + } + } + + protected static class SLUninitializedReadObjectPropertyNode extends SLReadPropertyCacheNode { + protected final String propertyName; + + protected SLUninitializedReadObjectPropertyNode(String propertyName) { + this.propertyName = propertyName; + } + + @Override + public Object executeObject(DynamicObject receiver) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + + receiver.updateShape(); + + Shape shape = receiver.getShape(); + Property property = shape.getProperty(propertyName); + + final SLReadPropertyCacheNode resolvedNode; + if (property == null) { + resolvedNode = new SLReadMissingPropertyNode(shape, this); + } else if (property.getLocation() instanceof LongLocation) { + resolvedNode = new SLReadLongPropertyNode(shape, (LongLocation) property.getLocation(), this); + } else if (property.getLocation() instanceof BooleanLocation) { + resolvedNode = new SLReadBooleanPropertyNode(shape, (BooleanLocation) property.getLocation(), this); + } else { + resolvedNode = new SLReadObjectPropertyNode(shape, property.getLocation(), this); + } + + return this.replace(resolvedNode, "resolved '" + propertyName + "'").executeObject(receiver); + } + + @Override + public long executeLong(DynamicObject receiver) throws UnexpectedResultException { + return SLTypesGen.SLTYPES.expectLong(executeObject(receiver)); + } + } +} diff -r dc2e000bed40 -r 997bc9764a9a graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyNode.java Tue Nov 18 23:02:58 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyNode.java Tue Nov 18 12:08:51 2014 +0100 @@ -22,13 +22,13 @@ */ package com.oracle.truffle.sl.nodes.access; -import java.util.*; - import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; +import com.oracle.truffle.api.utilities.*; import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.runtime.*; /** * The node for accessing a property of an object. When executed, this node first evaluates the @@ -43,18 +43,21 @@ @Child protected SLExpressionNode receiverNode; protected final String propertyName; + @Child protected SLReadPropertyCacheNode cacheNode; + private final ConditionProfile receiverTypeCondition = ConditionProfile.createBinaryProfile(); private SLReadPropertyNode(SourceSection src, SLExpressionNode receiverNode, String propertyName) { super(src); this.receiverNode = receiverNode; this.propertyName = propertyName; + this.cacheNode = SLReadPropertyCacheNode.create(propertyName); } @Override public Object executeGeneric(VirtualFrame frame) { Object object = receiverNode.executeGeneric(frame); - if (object instanceof Map) { - return ((Map) object).get(propertyName); + if (receiverTypeCondition.profile(SLContext.isSLObject(object))) { + return cacheNode.executeObject(SLContext.castSLObject(object)); } else { throw new SLException("unexpected receiver type"); } diff -r dc2e000bed40 -r 997bc9764a9a graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java Tue Nov 18 12:08:51 2014 +0100 @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.sl.nodes.access; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.object.*; + +/** + * The node for accessing a property of an object. When executed, this node first evaluates the + * object expression on the left side of the dot operator and then reads the named property. + */ +public abstract class SLWritePropertyCacheNode extends Node { + + public static SLWritePropertyCacheNode create(String propertyName) { + return new SLUninitializedWritePropertyNode(propertyName); + } + + public abstract void executeObject(DynamicObject receiver, Object value); + + public abstract void executeLong(DynamicObject receiver, long value); + + public abstract void executeBoolean(DynamicObject receiver, boolean value); + + protected abstract static class SLWritePropertyCacheChainNode extends SLWritePropertyCacheNode { + protected final Shape oldShape; + protected final Shape newShape; + @Child protected SLWritePropertyCacheNode next; + + public SLWritePropertyCacheChainNode(Shape oldShape, Shape newShape, SLWritePropertyCacheNode next) { + this.oldShape = oldShape; + this.newShape = newShape; + this.next = next; + } + + @Override + public final void executeObject(DynamicObject receiver, Object value) { + try { + // if this assumption fails, the object needs to be updated to a valid shape + oldShape.getValidAssumption().check(); + newShape.getValidAssumption().check(); + } catch (InvalidAssumptionException e) { + this.replace(next).executeObject(receiver, value); + return; + } + + boolean condition = oldShape.check(receiver) && checkValue(receiver, value); + + if (condition) { + executeObjectUnchecked(receiver, value); + } else { + next.executeObject(receiver, value); + } + } + + @Override + public final void executeLong(DynamicObject receiver, long value) { + try { + // if this assumption fails, the object needs to be updated to a valid shape + oldShape.getValidAssumption().check(); + newShape.getValidAssumption().check(); + } catch (InvalidAssumptionException e) { + this.replace(next).executeLong(receiver, value); + return; + } + + boolean condition = oldShape.check(receiver) && checkValue(receiver, value); + + if (condition) { + executeLongUnchecked(receiver, value); + } else { + next.executeLong(receiver, value); + } + } + + @Override + public final void executeBoolean(DynamicObject receiver, boolean value) { + try { + // if this assumption fails, the object needs to be updated to a valid shape + oldShape.getValidAssumption().check(); + newShape.getValidAssumption().check(); + } catch (InvalidAssumptionException e) { + this.replace(next).executeBoolean(receiver, value); + return; + } + + boolean condition = oldShape.check(receiver) && checkValue(receiver, value); + + if (condition) { + executeBooleanUnchecked(receiver, value); + } else { + next.executeBoolean(receiver, value); + } + } + + @SuppressWarnings("unused") + protected boolean checkValue(DynamicObject receiver, Object value) { + return true; + } + + protected abstract void executeObjectUnchecked(DynamicObject receiver, Object value); + + protected void executeLongUnchecked(DynamicObject receiver, long value) { + executeObjectUnchecked(receiver, value); + } + + protected void executeBooleanUnchecked(DynamicObject receiver, boolean value) { + executeObjectUnchecked(receiver, value); + } + } + + protected static class SLWriteObjectPropertyNode extends SLWritePropertyCacheChainNode { + private final Location location; + + protected SLWriteObjectPropertyNode(Shape oldShape, Shape newShape, Location location, SLWritePropertyCacheNode next) { + super(oldShape, newShape, next); + this.location = location; + } + + @Override + protected void executeObjectUnchecked(DynamicObject receiver, Object value) { + try { + if (oldShape == newShape) { + location.set(receiver, value, oldShape); + } else { + location.set(receiver, value, oldShape, newShape); + } + } catch (IncompatibleLocationException | FinalLocationException e) { + replace(next).executeObject(receiver, value); + } + } + + @Override + protected boolean checkValue(DynamicObject receiver, Object value) { + return location.canSet(receiver, value); + } + } + + protected static class SLWriteBooleanPropertyNode extends SLWritePropertyCacheChainNode { + private final BooleanLocation location; + + protected SLWriteBooleanPropertyNode(Shape oldShape, Shape newShape, BooleanLocation location, SLWritePropertyCacheNode next) { + super(oldShape, newShape, next); + this.location = location; + } + + @Override + protected void executeObjectUnchecked(DynamicObject receiver, Object value) { + try { + if (oldShape == newShape) { + location.set(receiver, value, oldShape); + } else { + location.set(receiver, value, oldShape, newShape); + } + } catch (IncompatibleLocationException | FinalLocationException e) { + replace(next).executeObject(receiver, value); + } + } + + @Override + protected void executeBooleanUnchecked(DynamicObject receiver, boolean value) { + try { + if (oldShape == newShape) { + location.setBoolean(receiver, value, oldShape); + } else { + location.setBoolean(receiver, value, oldShape, newShape); + } + } catch (FinalLocationException e) { + replace(next).executeBoolean(receiver, value); + } + } + + @Override + protected boolean checkValue(DynamicObject receiver, Object value) { + return value instanceof Boolean; + } + } + + protected static class SLWriteLongPropertyNode extends SLWritePropertyCacheChainNode { + private final LongLocation location; + + protected SLWriteLongPropertyNode(Shape oldShape, Shape newShape, LongLocation location, SLWritePropertyCacheNode next) { + super(oldShape, newShape, next); + this.location = location; + } + + @Override + protected void executeObjectUnchecked(DynamicObject receiver, Object value) { + try { + if (oldShape == newShape) { + location.set(receiver, value, oldShape); + } else { + location.set(receiver, value, oldShape, newShape); + } + } catch (IncompatibleLocationException | FinalLocationException e) { + replace(next).executeObject(receiver, value); + } + } + + @Override + protected void executeLongUnchecked(DynamicObject receiver, long value) { + try { + if (oldShape == newShape) { + location.setLong(receiver, value, oldShape); + } else { + location.setLong(receiver, value, oldShape, newShape); + } + } catch (FinalLocationException e) { + replace(next).executeLong(receiver, value); + } + } + + @Override + protected boolean checkValue(DynamicObject receiver, Object value) { + return value instanceof Long; + } + } + + protected static class SLUninitializedWritePropertyNode extends SLWritePropertyCacheNode { + protected final String propertyName; + + protected SLUninitializedWritePropertyNode(String propertyName) { + this.propertyName = propertyName; + } + + @Override + public void executeObject(DynamicObject receiver, Object value) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + + if (receiver.updateShape()) { + // shape changed, retry cache again + getTopNode().executeObject(receiver, value); + return; + } + + Shape oldShape = receiver.getShape(); + Shape newShape; + Property property = oldShape.getProperty(propertyName); + + final SLWritePropertyCacheNode resolvedNode; + if (property != null && property.getLocation().canSet(receiver, value)) { + newShape = oldShape; + } else { + receiver.define(propertyName, value, 0); + newShape = receiver.getShape(); + property = newShape.getProperty(propertyName); + } + + if (property.getLocation() instanceof LongLocation) { + resolvedNode = new SLWriteLongPropertyNode(oldShape, newShape, (LongLocation) property.getLocation(), this); + } else if (property.getLocation() instanceof BooleanLocation) { + resolvedNode = new SLWriteBooleanPropertyNode(oldShape, newShape, (BooleanLocation) property.getLocation(), this); + } else { + resolvedNode = new SLWriteObjectPropertyNode(oldShape, newShape, property.getLocation(), this); + } + + this.replace(resolvedNode, "resolved '" + propertyName + "'").executeObject(receiver, value); + } + + private SLWritePropertyCacheNode getTopNode() { + SLWritePropertyCacheNode top = this; + while (top.getParent() instanceof SLWritePropertyCacheNode) { + top = (SLWritePropertyCacheNode) top.getParent(); + } + return top; + } + + @Override + public void executeLong(DynamicObject receiver, long value) { + executeObject(receiver, value); + } + + @Override + public void executeBoolean(DynamicObject receiver, boolean value) { + executeObject(receiver, value); + } + } +} diff -r dc2e000bed40 -r 997bc9764a9a graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyNode.java Tue Nov 18 23:02:58 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyNode.java Tue Nov 18 12:08:51 2014 +0100 @@ -22,13 +22,13 @@ */ package com.oracle.truffle.sl.nodes.access; -import java.util.*; - import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; +import com.oracle.truffle.api.utilities.*; import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.runtime.*; /** * The node for setting a property of an object. When executed, this node first evaluates the value @@ -46,21 +46,23 @@ @Child protected SLExpressionNode receiverNode; protected final String propertyName; @Child protected SLExpressionNode valueNode; + @Child protected SLWritePropertyCacheNode cacheNode; + private final ConditionProfile receiverTypeCondition = ConditionProfile.createBinaryProfile(); private SLWritePropertyNode(SourceSection src, SLExpressionNode receiverNode, String propertyName, SLExpressionNode valueNode) { super(src); this.receiverNode = receiverNode; this.propertyName = propertyName; this.valueNode = valueNode; + this.cacheNode = SLWritePropertyCacheNode.create(propertyName); } - @SuppressWarnings("unchecked") @Override public Object executeGeneric(VirtualFrame frame) { Object value = valueNode.executeGeneric(frame); Object object = receiverNode.executeGeneric(frame); - if (object instanceof Map) { - ((Map) object).put(propertyName, value); + if (receiverTypeCondition.profile(SLContext.isSLObject(object))) { + cacheNode.executeObject(SLContext.castSLObject(object), value); } else { throw new SLException("unexpected receiver type"); } diff -r dc2e000bed40 -r 997bc9764a9a graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Tue Nov 18 23:02:58 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Tue Nov 18 12:08:51 2014 +0100 @@ -30,6 +30,7 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.object.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.builtins.*; @@ -49,9 +50,12 @@ * context. Therefore, the context is not a singleton. */ public final class SLContext extends ExecutionContext { + private static final Layout LAYOUT = Layout.createLayout(); + private final BufferedReader input; private final PrintStream output; private final SLFunctionRegistry functionRegistry; + private final Shape emptyShape; private SourceCallback sourceCallback = null; public SLContext(BufferedReader input, PrintStream output) { @@ -59,6 +63,8 @@ this.output = output; this.functionRegistry = new SLFunctionRegistry(); installBuiltins(); + + this.emptyShape = LAYOUT.createShape(new ObjectType()); } @Override @@ -180,4 +186,16 @@ } main.getCallTarget().call(); } + + public DynamicObject createObject() { + return LAYOUT.newInstance(emptyShape); + } + + public static boolean isSLObject(Object value) { + return LAYOUT.getType().isInstance(value); + } + + public static DynamicObject castSLObject(Object value) { + return LAYOUT.getType().cast(value); + } } diff -r dc2e000bed40 -r 997bc9764a9a mx/suite.py --- a/mx/suite.py Tue Nov 18 23:02:58 2014 +0100 +++ b/mx/suite.py Tue Nov 18 12:08:51 2014 +0100 @@ -1162,7 +1162,10 @@ "com.oracle.truffle.sl" : { "subDir" : "graal", "sourceDirs" : ["src"], - "dependencies" : ["com.oracle.truffle.api.dsl"], + "dependencies" : [ + "com.oracle.truffle.api.dsl", + "com.oracle.truffle.api.object", + ], "checkstyle" : "com.oracle.graal.graph", "javaCompliance" : "1.8", "annotationProcessors" : ["com.oracle.truffle.dsl.processor"],