private void setSlowCase(DynamicObject store, Object value) { Shape oldShape = store.getShape(); Shape newShape = oldShape.defineProperty(getKey(), value, getFlags()); if (store.updateShape()) { oldShape = store.getShape(); } assert newShape.isValid() && oldShape.isValid(); Property newProperty = newShape.getProperty(getKey()); newProperty.setSafe(store, value, oldShape, newShape); }
protected Location getLocation(DynamicObject object, Object value) { object.updateShape(); final Shape oldShape = object.getShape(); final Property property = oldShape.getProperty(name); if (property != null && property.getLocation().canSet(object, value)) { return property.getLocation(); } else { return null; } }
@TruffleBoundary @Specialization public void writeUncached(DynamicObject object, Object value) { object.updateShape(); final Shape shape = object.getShape(); final Property property = shape.getProperty(name); if (property == null) { object.define(name, value, 0); } else { property.setGeneric(object, value, shape); } }
@Override public Object executeDispatch( final VirtualFrame frame, final Object receiverObject, final Object methodName, DynamicObject blockObject, final Object[] argumentsObjects) { CompilerDirectives.transferToInterpreterAndInvalidate(); // Make sure to have an up-to-date Shape. if (receiverObject instanceof DynamicObject) { ((DynamicObject) receiverObject).updateShape(); } final DispatchNode dispatch = atomic( new Callable<DispatchNode>() { @Override public DispatchNode call() throws Exception { final DispatchNode first = getHeadNode().getFirstDispatchNode(); // First try to see if we did not a miss a specialization added by another thread. DispatchNode lookupDispatch = first; while (lookupDispatch != null) { if (lookupDispatch.guard(methodName, receiverObject)) { // This one worked, no need to rewrite anything. return lookupDispatch; } lookupDispatch = lookupDispatch.getNext(); } // We need a new node to handle this case. final DispatchNode newDispathNode; if (depth == getContext().getOptions().DISPATCH_CACHE) { newDispathNode = new UncachedDispatchNode( getContext(), ignoreVisibility, getDispatchAction(), missingBehavior); } else { depth++; if (RubyGuards.isForeignObject(receiverObject)) { newDispathNode = createForeign(argumentsObjects, first, methodName); } else if (RubyGuards.isRubyBasicObject(receiverObject)) { newDispathNode = doDynamicObject(frame, first, receiverObject, methodName, argumentsObjects); } else { newDispathNode = doUnboxedObject(frame, first, receiverObject, methodName); } } first.replace(newDispathNode); return newDispathNode; } }); return dispatch.executeDispatch( frame, receiverObject, methodName, blockObject, argumentsObjects); }
@Override public final void set(DynamicObject store, Object value, Shape oldShape, Shape newShape) throws IncompatibleLocationException { assert store.getShape() == oldShape : "wrong shape"; assert newShape.isValid(); assert getLocation() != null; getLocation().set(store, value, oldShape, newShape); }
public static DynamicObject createRubyClass( RubyContext context, DynamicObject classClass, DynamicObject lexicalParent, DynamicObject superclass, String name, boolean isSingleton, DynamicObject attached) { final ModuleFields model = new ModuleFields(context, lexicalParent, name); final DynamicObject rubyClass = Layouts.CLASS.createClass( Layouts.CLASS.getInstanceFactory(classClass), model, isSingleton, attached, null); assert RubyGuards.isRubyClass(rubyClass) : classClass.getShape().getObjectType().getClass(); assert RubyGuards.isRubyModule(rubyClass) : classClass.getShape().getObjectType().getClass(); model.rubyModuleObject = rubyClass; if (model.lexicalParent == null) { // bootstrap or anonymous module Layouts.MODULE.getFields(rubyClass).name = Layouts.MODULE.getFields(rubyClass).givenBaseName; } else { Layouts.MODULE .getFields(rubyClass) .getAdoptedByLexicalParent(model.lexicalParent, model.givenBaseName, null); } if (superclass != null) { assert RubyGuards.isRubyClass(superclass); assert RubyGuards.isRubyClass(Layouts.MODULE.getFields(rubyClass).rubyModuleObject); Layouts.MODULE.getFields(rubyClass).parentModule = Layouts.MODULE.getFields(superclass).start; Layouts.MODULE .getFields(superclass) .addDependent(Layouts.MODULE.getFields(rubyClass).rubyModuleObject); Layouts.MODULE.getFields(rubyClass).newVersion(); } DynamicObjectFactory factory = Layouts.CLASS.getInstanceFactory(superclass); factory = Layouts.BASIC_OBJECT.setLogicalClass(factory, rubyClass); factory = Layouts.BASIC_OBJECT.setMetaClass(factory, rubyClass); Layouts.CLASS.setInstanceFactoryUnsafe(rubyClass, factory); return rubyClass; }
@Override public final void setSafe(DynamicObject store, Object value, Shape shape) { assert shape == null || store.getShape() == shape : "wrong shape"; try { getLocation().set(store, value, shape); } catch (IncompatibleLocationException | FinalLocationException ex) { throw new IllegalStateException(); } }
@Override public final void setGeneric(DynamicObject store, Object value, Shape shape) { assert shape == null || store.getShape() == shape : "wrong shape"; try { set(store, value, shape); } catch (IncompatibleLocationException | FinalLocationException ex) { setSlowCase(store, value); } }
@Override public String toString() { return String.format( "CachedBoxedDispatchNode(:%s, %s@%x, %s)", getCachedNameAsSymbol().toString(), expectedReceiver, expectedReceiver.hashCode(), method == null ? "null" : method.toString()); }
private void setWithShapeSlowCase( DynamicObject store, Object value, Shape currentShape, Shape nextShape) { Shape oldShape = currentShape; if (store.updateShape()) { oldShape = store.getShape(); } LayoutStrategy strategy = ((LayoutImpl) currentShape.getLayout()).getStrategy(); LayoutStrategy.ShapeAndProperty newShapeAndProperty = strategy.generalizeProperty(this, value, (ShapeImpl) oldShape, (ShapeImpl) nextShape); if (store.updateShape()) { oldShape = store.getShape(); } Shape newNextShape = newShapeAndProperty.getShape(); Property newProperty = newShapeAndProperty.getProperty(); assert newNextShape.isValid() && oldShape.isValid(); newProperty.setSafe(store, value, oldShape, newNextShape); }
@Override public final void setGeneric(DynamicObject store, Object value, Shape oldShape, Shape newShape) { assert store.getShape() == oldShape : "wrong old shape"; assert newShape.isValid(); assert getLocation() != null; try { getLocation().set(store, value, oldShape, newShape); } catch (IncompatibleLocationException ex) { setWithShapeSlowCase(store, value, oldShape, newShape); } }
@Override public final void setSafe(DynamicObject store, Object value, Shape oldShape, Shape newShape) { assert store.getShape() == oldShape : "wrong old shape"; assert newShape.isValid(); assert getLocation() != null; try { getLocation().set(store, value, oldShape, newShape); } catch (IncompatibleLocationException ex) { throw new IllegalStateException(); } }
protected Shape transitionWithNewField(Shape oldShape, Object value) { // This duplicates quite a bit of DynamicObject.define(), but should be fixed in Truffle soon. final Property oldProperty = oldShape.getProperty(name); if (oldProperty != null) { if (oldProperty.getFlags() == 0 && oldProperty.getLocation().canSet(null, value)) { return oldShape; // already the right shape } else { DynamicObject copy = oldShape.getLayout().newInstance(oldShape); copy.define(name, value, 0); return copy.getShape(); } } else { final Location location = oldShape .allocator() .locationForValue( value, EnumSet.of(LocationModifier.Final, LocationModifier.NonNull)); final Property newProperty = Property.create(name, location, 0); return oldShape.addProperty(newProperty); } }
/** * This constructor supports initialization and solves boot-order problems and should not normally * be used from outside this class. */ public static DynamicObject createBootClass( DynamicObject classClass, DynamicObject superclass, String name) { assert RubyGuards.isRubyClass(classClass); assert superclass == null || RubyGuards.isRubyClass(superclass); final ModuleFields model = new ModuleFields( Layouts.MODULE.getFields(Layouts.BASIC_OBJECT.getLogicalClass(classClass)).getContext(), null, name); final DynamicObject rubyClass = Layouts.CLASS.createClass( Layouts.CLASS.getInstanceFactory(classClass), model, false, null, null); assert RubyGuards.isRubyClass(rubyClass) : classClass.getShape().getObjectType().getClass(); assert RubyGuards.isRubyModule(rubyClass) : classClass.getShape().getObjectType().getClass(); model.rubyModuleObject = rubyClass; if (model.lexicalParent == null) { // bootstrap or anonymous module Layouts.MODULE.getFields(rubyClass).name = Layouts.MODULE.getFields(rubyClass).givenBaseName; } else { Layouts.MODULE .getFields(rubyClass) .getAdoptedByLexicalParent(model.lexicalParent, model.givenBaseName, null); } if (superclass != null) { assert RubyGuards.isRubyClass(superclass); assert RubyGuards.isRubyClass(Layouts.MODULE.getFields(rubyClass).rubyModuleObject); Layouts.MODULE.getFields(rubyClass).parentModule = Layouts.MODULE.getFields(superclass).start; Layouts.MODULE .getFields(superclass) .addDependent(Layouts.MODULE.getFields(rubyClass).rubyModuleObject); Layouts.MODULE.getFields(rubyClass).newVersion(); } return rubyClass; }
/** Special constructor for class Class */ public static DynamicObject createClassClass(RubyContext context) { final ModuleFields model = new ModuleFields(context, null, "Class"); final DynamicObject rubyClass = LAYOUT.newInstance(LAYOUT.createShape(new ObjectType())); final DynamicObjectFactory factory = Layouts.CLASS.createClassShape(rubyClass, rubyClass); rubyClass.setShapeAndGrow(rubyClass.getShape(), factory.getShape()); assert RubyGuards.isRubyModule(rubyClass); assert RubyGuards.isRubyClass(rubyClass); model.rubyModuleObject = rubyClass; Layouts.CLASS.setInstanceFactoryUnsafe(rubyClass, factory); Layouts.MODULE.setFields(rubyClass, model); model.name = model.givenBaseName; assert RubyGuards.isRubyModule(rubyClass); assert RubyGuards.isRubyClass(rubyClass); assert Layouts.MODULE.getFields(rubyClass) == model; assert Layouts.BASIC_OBJECT.getLogicalClass(rubyClass) == rubyClass; return rubyClass; }
@Specialization(guards = "isRubyString(index)") public Object getIndexString(DynamicObject matchData, DynamicObject index, NotProvided length) { CompilerDirectives.transferToInterpreter(); try { final int i = getBackrefNumber(matchData, Layouts.STRING.getByteList(index)); return getIndex(matchData, i, NotProvided.INSTANCE); } catch (final ValueException e) { CompilerDirectives.transferToInterpreter(); throw new RaiseException( getContext() .getCoreLibrary() .indexError( String.format("undefined group name reference: %s", index.toString()), this)); } }
/** Set the value of a constant, possibly redefining it. */ @CompilerDirectives.TruffleBoundary public void setConstant(Node currentNode, String name, Object value) { if (getContext().getCoreLibrary().isLoadingRubyCore()) { final RubyConstant currentConstant = constants.get(name); if (currentConstant != null) { return; } } if (RubyGuards.isRubyModule(value)) { Layouts.MODULE .getFields(((DynamicObject) value)) .getAdoptedByLexicalParent(rubyModuleObject, name, currentNode); } else { setConstantInternal(currentNode, name, value, false); } }
@Specialization( guards = "object.getShape() == cachedShape", assumptions = "cachedShape.getValidAssumption()", limit = "CACHE_LIMIT") @ExplodeLoop protected void shareCached( DynamicObject object, @Cached("ensureSharedClasses(object.getShape())") Shape cachedShape, @Cached("createShareInternalFieldsNode()") ShareInternalFieldsNode shareInternalFieldsNode, @Cached("createReadAndShareFieldNodes(getObjectProperties(cachedShape))") ReadAndShareFieldNode[] readAndShareFieldNodes, @Cached("createSharedShape(object)") Shape sharedShape) { assert !SharedObjects.isShared(cachedShape); // Mark the object as shared first to avoid recursion object.setShapeAndGrow(cachedShape, sharedShape); shareInternalFieldsNode.executeShare(object); for (ReadAndShareFieldNode readAndShareFieldNode : readAndShareFieldNodes) { readAndShareFieldNode.executeReadFieldAndShare(object); } }
public static boolean updateShape(DynamicObject object) { CompilerDirectives.transferToInterpreter(); return object.updateShape(); }
protected static Shape createSharedShape(DynamicObject object) { object.updateShape(); final Shape oldShape = object.getShape(); return oldShape.makeSharedShape(); }
@Override Object execute(DynamicObject receiver, String name, Object value) { Property property = receiver.getShape().getProperty(name); return receiver.set(property.getKey(), value); }
@Specialization public DynamicObject exceptionErrnoError(DynamicObject message, int errno) { return getContext().getCoreLibrary().errnoError(errno, message.toString(), this); }
@Override public final void set(DynamicObject store, Object value, Shape shape) throws IncompatibleLocationException, FinalLocationException { assert shape == null || store.getShape() == shape : "wrong shape"; getLocation().set(store, value, shape); }