/* * Copyright (c) 2017-2020 Software Architecture Group, Hasso Plattner Institute * * Licensed under the MIT License. */ package de.hpi.swa.trufflesqueak.nodes.context; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.CachedContext; import com.oracle.truffle.api.dsl.Specialization; import de.hpi.swa.trufflesqueak.SqueakLanguage; import de.hpi.swa.trufflesqueak.exceptions.Returns.TopLevelReturn; import de.hpi.swa.trufflesqueak.image.SqueakImageContext; import de.hpi.swa.trufflesqueak.model.AbstractSqueakObject; import de.hpi.swa.trufflesqueak.model.ContextObject; import de.hpi.swa.trufflesqueak.model.NilObject; import de.hpi.swa.trufflesqueak.nodes.AbstractNode; public abstract class UnwindContextChainNode extends AbstractNode { public static UnwindContextChainNode create() { return UnwindContextChainNodeGen.create(); } public abstract ContextObject executeUnwind(Object startContext, Object targetContext, Object returnValue); @SuppressWarnings("unused") @Specialization protected static final ContextObject doTopLevelReturn(final NilObject startContext, final Object targetContext, final Object returnValue) { throw new TopLevelReturn(returnValue); } @Specialization(guards = {"startContext == targetContext", "startContext.isPrimitiveContext()"}) protected static final ContextObject doUnwindPrimitiveContext(@SuppressWarnings("unused") final ContextObject startContext, final ContextObject targetContext, final Object returnValue) { final ContextObject sender = (ContextObject) targetContext.getSender(); return doUnwindQuick(sender, sender, returnValue); // Skip primitive contexts. } @Specialization(guards = {"startContext == targetContext", "!startContext.isPrimitiveContext()"}) protected static final ContextObject doUnwindQuick(@SuppressWarnings("unused") final ContextObject startContext, final ContextObject targetContext, final Object returnValue) { targetContext.push(returnValue); return targetContext; } @Specialization(guards = {"startContext != targetContext"}) protected static final ContextObject doUnwind(final ContextObject startContext, final ContextObject targetContext, final Object returnValue, @CachedContext(SqueakLanguage.class) final SqueakImageContext image) { ContextObject context = startContext; while (context != targetContext) { final AbstractSqueakObject sender = context.getSender(); if (sender == NilObject.SINGLETON) { CompilerDirectives.transferToInterpreter(); image.printToStdErr("Unwind error: sender of", context, "is nil, unwinding towards", targetContext, "with return value:", returnValue); break; } context.terminate(); context = (ContextObject) sender; } targetContext.push(returnValue); return targetContext; } }