def testSurprisingMapCorruption(self): d = monteMap() d[IntObject(1)] = IntObject(2) m = ConstMap(d) f = m.call(u"diverge", []) f.call(u"removeKey", [IntObject(1)]) result = m.call(u"get", [IntObject(1)]) self.assertEqual(result.getInt(), 2)
def buildMap(self, index): # XXX monteMap() d = monteMap() for i in range(index): # Yikes, the order of operations here is dangerous. d[self.pop()] = self.pop() self.push(ConstMap(d))
def packLocalNamedRefs(namedArgs, targetVat, originVat): from typhon.objects.collections.maps import ConstMap, monteMap # XXX monteMap() namedRefs = monteMap() for k, v in namedArgs.objectMap.items(): namedRefs[packLocalRef(k, targetVat, originVat)] = packLocalRef( v, targetVat, originVat) return ConstMap(namedRefs)
def recv(self, atom, args): if atom is IMPORT_1: path = unwrapStr(args[0]) # this is a hack, but the whole class is a hack :) if path == u"unittest": d = monteMap() d[args[0]] = self.importList.call(u"get", args) return ConstMap(d) return self.importer.performModule(path, self.importList) raise Refused(self, atom, args)
def tieMirandaKnot(): """ Tie a knot needed for Miranda named arguments. """ global MIRANDA_ARGS global MIRANDA_MAP from typhon.objects.collections.maps import ConstMap MIRANDA_ARGS = makeMirandaArgs() MIRANDA_MAP = ConstMap(MIRANDA_ARGS)
def callAtom(self, atom, arguments, namedArgsMap=None, span=None): """ This method is used to reuse atoms without having to rebuild them. This is the correct method to call if you have an atom. """ # Promote the atom, on the basis that atoms are generally reused. atom = promote(atom) # Log the atom to the JIT log. Don't do this if the atom's not # promoted; it'll be slow. jit_debug(atom.repr) if namedArgsMap is None or namedArgsMap.isEmpty(): namedArgsMap = MIRANDA_MAP else: from typhon.objects.collections.maps import ConstMap namedArgsMap = ConstMap(namedArgsMap._or(MIRANDA_ARGS)) try: return self.recvNamed(atom, arguments, namedArgsMap) except Refused as r: r.addTrail(self, atom, arguments, span) raise except UserException as ue: ue.addTrail(self, atom, arguments, span) raise except MemoryError: ue = userError(u"Memory corruption or exhausted heap") ue.addTrail(self, atom, arguments, span) raise ue except StackOverflow: check_stack_overflow() ue = userError(u"Stack overflow") ue.addTrail(self, atom, arguments, span) raise ue
def evalToPair(code, topLocals, envMap, bindingNames=False): environment = {} if bindingNames: for k, v in unwrapMap(envMap).items(): s = unwrapStr(k) if not s.startswith("&&"): raise userError(u"evalMonteFile scope map must be of the " "form '[\"&&name\" => binding]'") environment[s[2:]] = v else: for k, v in unwrapMap(envMap).items(): environment[unwrapStr(k)] = v # Don't catch user exceptions; on traceback, we'll have a trail # auto-added that indicates that the exception came through # eval() or whatnot. result, newEnv = evaluateRaise([code], environment) if newEnv is not None: # XXX monteMap() d = monteMap() for k, vi in topLocals.items(): d[StrObject(k)] = newEnv.local[vi] addendum = ConstMap(d) envMap = addendum._or(envMap) return result, envMap
def recv(self, atom, args): if atom is GETBUCKETS_0: d = monteMap() for name, count in self.buckets.items(): size = self.sizes.get(name, -1) d[StrObject(name)] = ConstList( [IntObject(size), IntObject(count)]) return ConstMap(d) if atom is GETMEMORYUSAGE_0: return IntObject(self.memoryUsage) if atom is GETOBJECTCOUNT_0: return IntObject(self.objectCount) raise Refused(self, atom, args)
def recv(self, atom, args): if atom is GETARGUMENTS_0: return ConstList( [StrObject(arg.decode("utf-8")) for arg in self.config.argv]) if atom is GETENVIRONMENT_0: # XXX monteMap() d = monteMap() for key, value in os.environ.items(): k = StrObject(key.decode("utf-8")) v = StrObject(value.decode("utf-8")) d[k] = v return ConstMap(d) if atom is GETPID_0: return IntObject(os.getpid()) if atom is INTERRUPT_0: os.kill(os.getpid(), signal.SIGINT) return NullObject raise Refused(self, atom, args)
def recv(self, atom, args): if atom is GETARGUMENTS_0: return ConstList([BytesObject(arg) for arg in self.argv]) if atom is GETENVIRONMENT_0: # XXX monteMap() d = monteMap() for key, value in self.env.items(): k = BytesObject(key) v = BytesObject(value) d[k] = v return ConstMap(d) if atom is GETPID_0: return IntObject(self.pid) if atom is INTERRUPT_0: os.kill(self.pid, signal.SIGINT) return NullObject if atom is WAIT_0: return self.makeWaiter() raise Refused(self, atom, args)
def takeTurn(self): from typhon.objects.refs import Promise, resolution with self._pendingLock: resolver, target, atom, args, namedArgs = self._pending.pop(0) # If the target is a promise, then we should send to it instead of # calling. Try to resolve it as much as possible first, though. target = resolution(target) self.log( u"Taking turn: %s<-%s(%s) (resolver: %s)" % (target.toQuote(), atom.verb, u", ".join( [arg.toQuote() for arg in args]), u"yes" if resolver is not None else u"no")) if resolver is None: try: # callOnly/sendOnly. if isinstance(target, Promise): target.sendOnly(atom, args, namedArgs) else: # Oh, that's right; we don't do callOnly since it's silly. target.callAtom(atom, args, namedArgs) except UserException as ue: self.log(u"Uncaught user exception while taking turn" u" (and no resolver): %s" % ue.formatError().decode("utf-8"), tags=["serious"]) except VatCheckpointed: self.log(u"Ran out of checkpoints while taking turn", tags=["serious"]) except Ejecting: self.log(u"Ejector tried to escape vat turn boundary", tags=["serious"]) else: from typhon.objects.collections.maps import ConstMap, monteMap from typhon.objects.exceptions import sealException from typhon.objects.refs import Smash # XXX monteMap() _d = monteMap() _d[StrObject(u"FAIL")] = Smash(resolver) MIRANDA_ARGS = ConstMap(_d) namedArgs = namedArgs._or(MIRANDA_ARGS) try: # call/send. if isinstance(target, Promise): result = target.send(atom, args, namedArgs) else: result = target.callAtom(atom, args, namedArgs) # Resolver may be invoked from the code in this turn, so # strict=False to skip this if already resolved. resolver.resolve(result, strict=False) except UserException as ue: resolver.smash(sealException(ue)) except VatCheckpointed: self.log( u"Ran out of checkpoints while taking turn; breaking resolver", tags=["serious"]) resolver.smash( sealException(userError(u"Vat ran out of checkpoints"))) except Ejecting: self.log(u"Ejector tried to escape vat turn boundary", tags=["serious"]) resolver.smash( sealException( userError(u"Ejector tried to escape from vat")))
def runTyphon(argv): # Start metrics. recorder = globalRecorder() recorder.start() # Initialize libsodium. if rsodium.init() < 0: print "Couldn't initialize libsodium!" return 1 config = Configuration(argv) if config.verbose: enableDebugPrint() config.enableLogging() if len(config.argv) < 2: print "No file provided?" return 1 # Pass user configuration to the JIT. set_user_param(None, config.jit) # Intialize our loop. uv_loop = ruv.alloc_loop() # Usurp SIGPIPE, as libuv does not handle it. rsignal.pypysig_ignore(rsignal.SIGPIPE) # Initialize our first vat. It shall be immortal. vatManager = VatManager() vat = Vat(vatManager, uv_loop, checkpoints=-1) vatManager.vats.append(vat) # Update loop timing information. Until the loop really gets going, we # have to do this ourselves in order to get the timing correct for early # timers. ruv.update_time(uv_loop) try: with scopedVat(vat) as vat: prelude = loadPrelude(config, recorder, vat) except LoadFailed as lf: print lf return 1 except CompilerFailed as cf: debug_print("Caught exception while importing prelude:", cf.formatError()) return 1 except UserException as ue: debug_print("Caught exception while importing prelude:", ue.formatError()) return 1 registerGlobals(prelude) scope = safeScope() scope.update(prelude) ss = scope.copy() reflectedSS = monteMap() for k, b in ss.iteritems(): reflectedSS[StrObject(u"&&" + k)] = b ss[u"safeScope"] = finalBinding(ConstMap(reflectedSS), deepFrozenGuard) reflectedSS[StrObject(u"&&safeScope")] = ss[u"safeScope"] scope[u"safeScope"] = ss[u"safeScope"] scope.update(unsafeScope(config)) # The initial vat is included as `currentVat` to the first level of # loading and such. scope[u"currentVat"] = finalBinding(vat, anyGuard) reflectedUnsafeScope = monteMap() unsafeScopeDict = {} for k, b in scope.iteritems(): reflectedUnsafeScope[StrObject(u"&&" + k)] = b unsafeScopeDict[k] = b rus = finalBinding(ConstMap(reflectedUnsafeScope), anyGuard) reflectedUnsafeScope[StrObject(u"&&unsafeScope")] = rus unsafeScopeDict[u"unsafeScope"] = rus try: module = obtainModule([""], recorder, config.argv[1]) except LoadFailed as lf: print lf return 1 if config.loadOnly: # We are finished. return 0 if not config.benchmark: benchmarkSettings.disable() with profiling("vmprof.log", config.profile): # Update loop timing information. ruv.update_time(uv_loop) debug_print("Taking initial turn in script...") result = NullObject try: with recorder.context("Time spent in vats"): with scopedVat(vat): result = module.eval(unsafeScopeDict)[0] if result is None: return 1 except UserException as ue: debug_print("Caught exception while taking initial turn:", ue.formatError()) return 1 # Exit status code. exitStatus = 0 # Update loop timing information. ruv.update_time(uv_loop) try: runUntilDone(vatManager, uv_loop, recorder) rv = resolution(result) if result is not None else NullObject if isinstance(rv, IntObject): exitStatus = rv.getInt() except SystemExit: pass # Huh, apparently this doesn't work. Wonder why/why not. # exitStatus = se.code finally: recorder.stop() recorder.printResults() # Clean up and exit. cleanUpEverything() return exitStatus
def mkMirandaArgs(): # XXX monteMap() _d = monteMap() _d[StrObject(u"FAIL")] = theThrower return ConstMap(_d)
def testUnwrapMapPromise(self): with scopedVat(testingVat()): p = makeNear(ConstMap({})) self.assertEqual(unwrapMap(p).items(), [])
def takeTurn(self): from typhon.objects.refs import Promise, resolution with self._pendingLock: resolver, target, atom, args, namedArgs = self._pending.pop(0) # If the target is a promise, then we should send to it instead of # calling. Try to resolve it as much as possible first, though. target = resolution(target) # self.log(u"Taking turn: %s<-%s(%s) (resolver: %s)" % # (target.toQuote(), atom.verb, # u", ".join([arg.toQuote() for arg in args]), # u"yes" if resolver is not None else u"no")) if resolver is None: try: # callOnly/sendOnly. if isinstance(target, Promise): target.sendOnly(atom, args, namedArgs) else: # Oh, that's right; we don't do callOnly since it's silly. target.callAtom(atom, args, namedArgs) except UserException as ue: self.log(u"Uncaught user exception while taking turn" u" (and no resolver): %s" % ue.formatError().decode("utf-8"), tags=["serious"]) except VatCheckpointed: self.log(u"Ran out of checkpoints while taking turn", tags=["serious"]) except Ejecting: self.log(u"Ejector tried to escape vat turn boundary", tags=["serious"]) else: from typhon.objects.collections.maps import ConstMap, monteMap from typhon.objects.exceptions import sealException from typhon.objects.refs import Smash # XXX monteMap() mirandaArgs = monteMap() mirandaArgs[StrObject(u"FAIL")] = Smash(resolver) namedArgs = ConstMap(namedArgs._or(mirandaArgs)) try: # call/send. if isinstance(target, Promise): result = target.send(atom, args, namedArgs) else: result = target.callAtom(atom, args, namedArgs) # The resolver may have already been invoked, so we'll use # .resolveRace/1 instead of .resolve/1. ~ C. resolver.resolveRace(result) except UserException as ue: resolver.smash(sealException(ue)) except VatCheckpointed: self.log(u"Ran out of checkpoints while taking turn; breaking resolver", tags=["serious"]) resolver.smash(sealException(userError(u"Vat ran out of checkpoints"))) except Ejecting: self.log(u"Ejector tried to escape vat turn boundary", tags=["serious"]) resolver.smash(sealException(userError(u"Ejector tried to escape from vat")))
def makeMap(pairs): """ Given a `List[Pair]`, produce a `Map`. """ return ConstMap.fromPairs(pairs)
def testContains(self): d = monteMap() d[IntObject(42)] = IntObject(5) m = ConstMap(d) self.assertTrue(m.contains(IntObject(42))) self.assertFalse(m.contains(IntObject(7)))
def testToString(self): d = monteMap() self.assertEqual(ConstMap(d).toString(), u"[].asMap()")
def _recv(self, atom, args): if atom is _UNCALL_0: from typhon.objects.collections.maps import EMPTY_MAP return ConstList([ self.snapshot(), StrObject(u"diverge"), ConstList([]), EMPTY_MAP ]) if atom is ADD_1: other = args[0] return ConstList(self.strategy.fetch_all(self) + unwrapList(other)) if atom is ASMAP_0: from typhon.objects.collections.maps import ConstMap return ConstMap(self.asMap()) if atom is ASSET_0: from typhon.objects.collections.sets import ConstSet return ConstSet(self.asSet()) if atom is DIVERGE_0: return FlexList(self.strategy.fetch_all(self)) if atom is EXTEND_1: from typhon.objects.refs import resolution l = resolution(args[0]) # The early exits are essential here; without them, we might pass # an empty list to strategy.append(), which causes a crash. ~ C. if isinstance(l, ConstList): if l.size() == 0: return NullObject data = l.strategy.fetch_all(l) elif isinstance(l, FlexList): if l.size() == 0: return NullObject data = l.strategy.fetch_all(l) else: data = listFromIterable(l)[:] self.strategy.append(self, data) return NullObject if atom is GET_1: # Lookup by index. index = unwrapInt(args[0]) if index >= self.strategy.size(self) or index < 0: raise userError(u"Index %d is out of bounds" % index) return self.strategy.fetch(self, index) if atom is INDEXOF_1: return IntObject(self.indexOf(args[0])) if atom is INSERT_2: index = unwrapInt(args[0]) value = args[1] if index < 0: raise userError(u"Index %d is out of bounds" % index) self.strategy.insert(self, index, [value]) return NullObject if atom is LAST_0: size = self.strategy.size(self) if size: return self.strategy.fetch(self, size - 1) raise userError(u"Empty list has no last element") if atom is MULTIPLY_1: # multiply/1: Create a new list by repeating this list's contents. index = unwrapInt(args[0]) return ConstList(self.strategy.fetch_all(self) * index) if atom is POP_0: try: return self.strategy.pop(self, self.strategy.size(self) - 1) except IndexError: raise userError(u"pop/0: Pop from empty list") if atom is PUSH_1: self.strategy.append(self, args) return NullObject if atom is PUT_2: # Replace by index. index = unwrapInt(args[0]) return self.put(index, args[1]) if atom is REVERSE_0: new = self.strategy.fetch_all(self)[:] new.reverse() return ConstList(new) if atom is REVERSEINPLACE_0: new = self.strategy.fetch_all(self)[:] new.reverse() self.strategy.store_all(self, new) return NullObject if atom is WITH_1: # with/1: Create a new list with an appended object. return ConstList(self.strategy.fetch_all(self) + args) if atom is WITH_2: # Make a new ConstList. return self.snapshot().put(unwrapInt(args[0]), args[1]) raise Refused(self, atom, args)
def _recv(self, atom, args): if atom is ADD_1: other = unwrapList(args[0]) if len(other): return ConstList(self.strategy.fetch_all(self) + other) else: return self if atom is ASMAP_0: from typhon.objects.collections.maps import ConstMap return ConstMap(self.asMap()) if atom is ASSET_0: from typhon.objects.collections.sets import ConstSet return ConstSet(self.asSet()) if atom is DIVERGE_0: return FlexList(self.strategy.fetch_all(self)[:]) if atom is GET_1: # Lookup by index. index = unwrapInt(args[0]) if index < 0: raise userError(u"Index %d cannot be negative" % index) if index >= self.strategy.size(self): raise userError(u"Index %d is out of bounds" % index) return self.strategy.fetch(self, index) if atom is INDEXOF_1: return IntObject(self.indexOf(args[0])) if atom is LAST_0: size = self.strategy.size(self) if size: return self.strategy.fetch(self, size - 1) raise userError(u"Empty list has no last element") if atom is MULTIPLY_1: # multiply/1: Create a new list by repeating this list's contents. count = unwrapInt(args[0]) if count < 0: raise userError(u"Can't multiply list %d times" % count) elif count == 0: return ConstList([]) return ConstList(self.strategy.fetch_all(self) * count) if atom is OP__CMP_1: other = unwrapList(args[0]) return IntObject(self.cmp(other)) if atom is REVERSE_0: # This might seem slightly inefficient, and it might be, but I # want to make it very clear to RPython that we are not mutating # the list after we assign it to the new object. new = self.strategy.fetch_all(self)[:] new.reverse() return ConstList(new) if atom is SORT_0: return self.sort() if atom is STARTOF_1: return IntObject(self.startOf(unwrapList(args[0]))) if atom is STARTOF_2: start = unwrapInt(args[1]) if start < 0: raise userError(u"startOf/2: Negative start %d not permitted" % start) return IntObject(self.startOf(unwrapList(args[0]), start)) if atom is WITH_1: # with/1: Create a new list with an appended object. return ConstList(self.strategy.fetch_all(self) + args) if atom is WITH_2: # Replace by index. index = unwrapInt(args[0]) return self.put(index, args[1]) if atom is _UNCALL_0: from typhon.scopes.safe import theMakeList from typhon.objects.collections.maps import EMPTY_MAP return ConstList([theMakeList, StrObject(u"run"), self, EMPTY_MAP]) raise Refused(self, atom, args)