bwerf's Blog

It's plukalicious
posts - 14, comments - 11, trackbacks - 0, articles - 0

Thursday, June 24, 2010

http://icfpcontest.org/

43th place, out of several hundred teams thats not bad. :) (teamname: pluk)

This year the contest was extra intresting for me because I decided to use Pluk instead of C# and in the end i never missed a thing from C#. The compiler needed some fixes and the library some extensions but nothing major.

Really using a language for 72 hours on a difficult challenge is the best way to learn I think.

posted @ 10:51 AM | Feedback (1)

Tuesday, February 23, 2010

Eric Grange talks about having an alternative to FreeAndNil that instead of zeroing the object pointer make it another value that signals that the reference is invalid.

http://delphitools.info/2010/02/06/dont-abuse-freeandnil-anymore/#comments

On which i commented:

Alternatively something we do is hook FreeInstance to change the v-table pointer on the heapobject just before the FreeMemory call inside it. This causes all virtual method calls on the now freed object to throw a CalledAMethodOnAFreedObject exception when the memory hasn’t yet been reused or pageprotected. The overhead is neglectible and works without replacing .Free or FreeAndNil calls.

unit ReferenceProtector;

interface

implementation

uses
  SysUtils,
  Windows;

type
  TObjectProc = procedure of Object;
  TGlobalProc = procedure;
  TMyProc = procedure(Obj: Pointer);
  TSmack = record
    case Integer of
      1:( A: TObjectProc;);
      2:( C, D: Pointer;);
      3:( F: TGlobalProc; E: Integer;);
      4:( G: TMyProc; H: Integer;);
  end;
  TIntRec = record
    case Integer of
      1: (A: Pointer);
      2: (W, X, Y, Z: Byte);
      3: (B: Integer);
  end;

var
  NewFreeInstance: TSmack;
  OldFreeInstance: Pointer;
  CleanupInstance: Pointer;
  OriginalCode: array[0..5] of Byte;
  Freemem: Pointer;
  PoisonedVTable: Pointer;
  PoisonVTable: array[0..272] of Pointer;
  Loaded: Boolean;

procedure RaiseReferenceProtector(Obj: Pointer);
var
  s: string;
begin
  s := 'ReferenceProtector: Called a virtual method on a free''ed object. '+IntToHex(Integer(Obj), 8);
  try
    s := s + ' of type ' + TObject(Pointer(Cardinal(Obj)+4)).ClassName + '('+IntToHex(Integer(PPointer(Cardinal(Obj)+4)^), 8)+')';
  except
    s := s + ' of unknown classtype.'
  end;
  OutputDebugString(@s[1]);
  raise Exception.Create(s);
end;

procedure TObjectFreeInstanceReplacement;
asm
//  CleanupInstance;
  push ebx
  mov ebx, eax
  mov ecx, CleanupInstance
  call dword ptr ecx
// Poison the vmt
  mov eax, ebx
  mov ecx, [eax]
  mov [eax+4], ecx  // delphi garuantees 8 bytes of memory minimum for any allocation
  mov ecx, PoisonedVTable
  mov [eax], ecx
//  _FreeMem(Self);
  mov ecx, FreeMem
  call dword ptr ecx
  pop ebx
end;

procedure SetupEnforce;
var
  Proc: TSmack;
  FreeInstance: TSmack;
  OldFree: ^Byte;
  NewFree: TIntRec;
  OldProtection, Temp: DWord;
  X: TObject;
{$WARN SYMBOL_DEPRECATED OFF}
  MemMgr: TMemoryManager;
{$WARN SYMBOL_DEPRECATED ON}
  i: Integer;
begin
  PoisonedVTable := @PoisonVTable[16];
  Proc.g := RaiseReferenceProtector;
  for i := 0 to 272 do
    PoisonVTable[i] := Proc.C;

  X := TObject.Create;
  FreeInstance.A := X.FreeInstance;
  Proc.A := X.CleanupInstance;
  X.Free;
  OldFreeInstance := FreeInstance.C;
  OldFree := OldFreeInstance;
  CleanupInstance := Proc.C;

{$WARN SYMBOL_DEPRECATED OFF}
  GetMemoryManager(MemMgr);
{$WARN SYMBOL_DEPRECATED ON}

  Freemem := @MemMgr.FreeMem;


  NewFreeInstance.F := TObjectFreeInstanceReplacement;
  NewFree.A := @NewFreeInstance;

  // allow modifying the code section
  if VirtualProtect(OldFree, 8, PAGE_EXECUTE_READWRITE, @OldProtection) then
  begin

    // call
    OriginalCode[0] := OldFree^;
    OldFree^ := $ff;
    Inc(OldFree);
    // but no return on stack, indirect from address
    OriginalCode[1] := OldFree^;
    OldFree^ := $25;
    Inc(OldFree);
    // and then the address, per byte, wasn't sure about the endianness, below is correct
    OriginalCode[2] := OldFree^;
    OldFree^ := NewFree.W;
    Inc(OldFree);
    OriginalCode[3] := OldFree^;
    OldFree^ := NewFree.X;
    Inc(OldFree);
    OriginalCode[4] := OldFree^;
    OldFree^ := NewFree.Y;
    Inc(OldFree);
    OriginalCode[5] := OldFree^;
    OldFree^ := NewFree.Z;

    // restore old rights to code section
    VirtualProtect(OldFree, 8, OldProtection, @Temp);
    Loaded := True;
  end
  else
    OutputDebugString('ReferenceProtector: Failed to set the protection of virtual calls to free''ed objects.'#13#10);
end;

procedure UnloadEnforce;
var
  OldFree: ^Byte;
  OldProtection, Temp: DWord;
begin
  if not Loaded then
    Exit;
  OldFree := OldFreeInstance;

  if VirtualProtect(OldFree, 8, PAGE_EXECUTE_READWRITE, @OldProtection) then
  begin
    OldFree^ := OriginalCode[0];
    Inc(OldFree);
    OldFree^ := OriginalCode[1];
    Inc(OldFree);
    OldFree^ := OriginalCode[2];
    Inc(OldFree);
    OldFree^ := OriginalCode[3];
    Inc(OldFree);
    OldFree^ := OriginalCode[4];
    Inc(OldFree);
    OldFree^ := OriginalCode[5];
    VirtualProtect(OldFree, 8, OldProtection, @Temp);
    Loaded := False;
  end
  else
    OutputDebugString('ReferenceProtector: Failed to reset the protection of virtual calls to free''ed objects.'#13#10);
end;

var
  OriginalMemManager: TMemoryManagerEx;
  MemManager: TMemoryManagerEx;

type
  ECheckingMemoryManagerException = class(Exception);
threadvar
  ///keep a counter per thread of number of recursive entries into AllocError
  AllocErrorCounter: Integer;

procedure AllocError(Size: Integer);
begin
  if (AllocErrorCounter = 0) then
  begin
    Inc(AllocErrorCounter);
    try
      // Raise an exception that the Exception logger can catch
      raise ECheckingMemoryManagerException.Create('Out of memory. Size: ' + IntToStr(Size));
    finally
      Dec(AllocErrorCounter);
    end;
  end;
end;

function CheckingGetMem(Size: Integer): Pointer;
begin
  Result := OriginalMemManager.GetMem((Size + 7) and $7ffffff8);
  if (not Assigned(Result) and (Size <> 0)) or (Size < 0)  then
    AllocError(Size);
end;

// returns zero'ed memory
function CheckingAllocMem(Size: Cardinal): Pointer;
begin
  if Size >= 8 then
  begin
    Result := OriginalMemManager.AllocMem(Size);
    if Assigned(Result) then
      Exit;
  end
  else
  begin
    if Size > 0 then
    begin
      Result := OriginalMemManager.AllocMem(8); // so that refprotector works with very small objects
      if Assigned(Result) then
        Exit;
    end
  end;
  Result := nil;
  if Size <> 0 then
    AllocError(Size);
end;

initialization
  GetMemoryManager(OriginalMemManager);
  MemManager := OriginalMemManager;
  MemManager.GetMem := CheckingGetMem;
  MemManager.AllocMem := CheckingAllocMem;
  SetMemoryManager(MemManager);

  Loaded := False;
  SetupEnforce;
finalization
  UnloadEnforce;
  SetMemoryManager(OriginalMemManager);
end.

posted @ 10:08 AM | Feedback (5)

Tuesday, September 15, 2009

http://bitbucket.org/bartwe/plukc/

https://www.ohloh.net/p/plukc

I've moved my compiler online and opensource after working on it for 2 years in private.It currently is in a state that should be good enough to start make it self compiling.

A quick look at the Ohloh statistics show that the project is missing source comments, which is completely true :) Also Ohloh seems to confuse .pluk files with xml or something.

The experience of the previous pluk language project ( http://pluk.sf.net/ ) shows that putting something online doesn't mean anything further will happen. But I hope it can help me build better software and make it easier to discuss language features with other compiler developers.

posted @ 11:49 AM | Feedback (1)

http://icfpcontest.org/

Allways fun to compete in the ICFP contest. This year it went very well and i ended up in 15th place. (teamname: pluk)

Big teams didn't seem to do well, possibly because the problem had few bits that could be developed in parallel.

Can't wait for next year's contest.

posted @ 11:43 AM | Feedback (1)

Wednesday, August 19, 2009

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Imager
{
    public class Optimizer
    {
        List<Parameter> parameters = new List<Parameter>();
        HashSet<Parameter> active = new HashSet<Parameter>();
        int index;
        public void RegisterParameter(double initial, double increment, bool optimize)
        {
            parameters.Add(new Parameter(initial, increment, optimize));
        }
        public void Run(Func<double[], double> lambda, Action<double[], double, int> bestSoFar)
        {
            int activeIndex;
            {
                Parameter p;
                while (true)
                {
                    if (index >= parameters.Count)
                        return; // no active parameters
                    p = parameters[index];
                    activeIndex = index;
                    if (p.Optimize) break;
                    index++;
                }
                active.Add(p);
            }
            var best = lambda(parameters.Select(x => x.Original).ToArray());
            if (double.IsNaN(best))
                return;
            while (true)
            {
                var r = lambda(parameters.Select(x => active.Contains(x) ? x.Value : x.Original).ToArray());
                if (double.IsNaN(r))
                    return;
                var d = best - r;
                foreach (var p in active)
                    p.ProcessResult(d);
                if (d >= 0)
                    best = r;
                if (d > 0)
                    bestSoFar(parameters.Select(x => x.Original).ToArray(), best, activeIndex);
                else
                {
                    active.Clear();
                    Parameter p;
                    while (true)
                    {
                        if (index == 0)
                        {
                            if (parameters.All(x=>x.Stagnated))
                                return; // no effect in optimizer
                        }
                        p = parameters[index];
                        activeIndex = index;
                        index++;
                        if (index >= parameters.Count)
                            index = 0;
                        if (p.Optimize) break;
                    }
                    active.Add(p);
                }
            }
        }
        private class Parameter
        {
            public double Value { get; private set; }
            public double Increment { get; private set; }
            public bool Optimize { get; private set; }
            public double Original { get; private set; }
            public bool Stagnated { get { return (!Optimize) || (reversals > 2); } }
            private double magnitude;
            private bool direction;
            private int reversals = 0;
            public Parameter(double value, double increment, bool optimize)
            {
                Increment = increment;
                Optimize = optimize;
                magnitude = Increment;
                direction = true;
                Original = value;
                Value = value + magnitude;
            }
            public void ProcessResult(double delta)
            {
                if (!Optimize) return;
                if (delta < 0.0d)
                {
                    magnitude *= 0.5d;
                    if (direction ? (magnitude < Increment) : (magnitude > -Increment))
                    {
                        direction = !direction;
                        magnitude = direction ? Increment : -Increment;
                        reversals++;
                    }
                    Value = Original + magnitude;
                }
                else
                {
                    if (delta > 0)
                        reversals = 0;
                    magnitude *= 2.0d;
                    Original = Value;
                    Value += magnitude;
                }
            }
        }
    }
}

posted @ 10:14 PM | Feedback (1)

Tuesday, January 20, 2009

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

using System.Threading;

 

namespace ConsoleApplication1

{

    class Program

    {

        static void Main(string[] args)

        {

            var @this = new Program();

            Console.WriteLine("Main before");

            try

            {

                @this.Outer().Invoke();

            }

            catch (Exception e)

            {

                Console.WriteLine("Main caught exception!");

                Console.WriteLine(e);

            }

            Console.WriteLine("Main after");

            Console.ReadLine();

        }

 

        IEnumerable<IContinuation> Outer()

        {

            Console.WriteLine("Outer before");

 

            /* what i want:

             * yield Inner2();

             */

 

            yield return Inner2().PrepareYield();

 

            /* What i want to type: (give me a way to extend the c# language and this is possible :)

             * try

             * {

             *     int result = yield Inner();

             * }

             * catch

             * {

                   Console.WriteLine("Caught exception!");

             * }

             *

             * This does two things, receiving exceptions thrown from a child continuation, and return values.

             */

 

            // What i needed to type:

            int result;

            Holder<int> r = new Holder<int>();

            var y = Inner(r).PrepareYieldAndComplete();

            yield return y;

            try

            {

                y.Complete();

                result = r.Value;

            }

            catch (Exception e)

            {

                Console.WriteLine("Outer caught exception!");

                Console.WriteLine(e);

                throw;

            }

            Console.WriteLine("Outer after");

        }

 

        IEnumerable<IContinuation> Inner(Holder<int> result)

        {

            Console.WriteLine("Inner before");

            if (result != null)

            throw new Exception();

            //Console.WriteLine("Inner after");

            yield break;

        }

 

        IEnumerable<IContinuation> Inner2()

        {

            Console.WriteLine("Inner2 before");

            Console.WriteLine("Inner2 after");

            yield break;

        }

    }

 

    class Holder<T>

    {

        public T Value { get; set; }

    }

 

    interface IContinuation

    {

        IEnumerable<WaitHandle> Handles();

        bool Process();

    }

 

    interface IPassThroughContinuation : IContinuation

    {

        void Complete();

    }

 

    static class ContinationExtensions

    {

        public static IPassThroughContinuation PrepareYieldAndComplete(this IEnumerable<IContinuation> self)

        {

            return new PassThroughContinuation(self);

        }

 

        public static IContinuation PrepareYield(this IEnumerable<IContinuation> self)

        {

            return new CombinedContinuation(self);

        }

 

        public static bool WaitAny(this IEnumerable<WaitHandle> self)

        {

            if (self == null)

                return true;

            foreach (var w in self)

                if (w.WaitOne(0, false))

                    return true;

            return false;

        }

 

        public static void Invoke(this IEnumerable<IContinuation> self)

        {

            var c = self.PrepareYield();

            while (true)

            {

                c.Handles().WaitAny();

                if (!c.Process())

                    break;

            }

        }

    }

 

    class PassThroughContinuation : IPassThroughContinuation

    {

        private IEnumerator<IContinuation> source;

        private Exception exception;

        private bool done;

        private IContinuation value;

 

        public PassThroughContinuation(IEnumerable<IContinuation> source)

        {

            this.source = source.GetEnumerator();

        }

 

        public IEnumerable<WaitHandle> Handles()

        {

            if (done||(value == null))

                return null;

            return value.Handles();

        }

 

        public bool Process()

        {

            if (done)

                return false;

            try

            {

                if (value != null)

                    if (value.Process())

                        return true;

                if (!source.MoveNext())

                {

                    done = true;

                    return false;

                }

                value = source.Current;

                return true;

            }

            catch (ContinuationException ce)

            {

                exception = ce.InnerException;

                done = true;

                return false;

            }

            catch (Exception e)

            {

                exception = e;

                done = true;

                return false;

            }

        }

 

        public void Complete()

        {

            if (!done)

                throw new InvalidOperationException();

            if (exception != null)

                throw new ContinuationException(exception);

        }

    }

 

    class CombinedContinuation : IContinuation

    {

        private IEnumerator<IContinuation> source;

        private bool done;

        private IContinuation value;

 

        public CombinedContinuation(IEnumerable<IContinuation> source)

        {

            this.source = source.GetEnumerator();

        }

 

        public IEnumerable<WaitHandle> Handles()

        {

            if (done || (value == null))

                return null;

            return value.Handles();

        }

 

        public bool Process()

        {

            if (done)

                return false;

            try

            {

                if (value != null)

                    if (value.Process())

                        return true;

                if (!source.MoveNext())

                {

                    done = true;

                    return false;

                }

                value = source.Current;

                return true;

            }

            catch

            {

                done = true;

                throw;

            }

        }

 

    }

 

    class ContinuationException : Exception

    {

        public ContinuationException(Exception exception)

            : base("Exception raised inside a continuation", exception)

        {

        }

    }

}

 

 

posted @ 9:50 PM | Feedback (0)

Friday, January 02, 2009

Blogging seems to be one of those things i feel i should be doing and with the new year I'm giving it some more attention.

Microsoft TechEd EMEA 2008 in Barcelona was interesting for me. Joe Duffy was there talking about his new concurrency book, a topic that I'm very interested in. A very small but fun session with a large group of core visual studio developers also gave some insights into their thought process.

But most of all a small presentation of CCR DSS, a system made for distributed and concurrent programming that isn't receiving nearly enough attention, mostly due to it having been developed within the robotics team.

One of the things i noticed in the presentation was that they used "yield return" in a way it wasn't designed for. (the best way to use a feature :)

"yield return" can be used to make a normal function turn into a generator:

http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx

The compiler does a lot of transformations for a piece of code that uses a yield return, transformations that can be used to construct continuations without too much pain.

http://en.wikipedia.org/wiki/Continuation

http://blogs.msdn.com/oldnewthing/archive/2008/08/12/8849519.aspx

When writing server-like programs it is often useful to use continuations to handle a protocol or asynchronous code, where the thread yields the continuation when an operation would have to wait for completion. To do this in c# you can yield return a waitable future of the operation that would block, a top level handler could then decide which continuation is runnable based on this future and execute it. This is more powerful than implementing this using reentrancy because the handler is free to run any continuation it can not just the top most, also the stack wont be exhausted because the continuations use the heap to store method scoped variables.

Example of yield return usage:

void Main() {
Handler.Invoke(Save);
Handler.Invoke(()=>Process("save"));
}

IEnumerable Save() {
using (var file = new File()) {
yield return file.BeginWrite();
file.EndWrite();
}
}

IEnumerable Process(string command) {
if (command == "save")
foreach (var y in Save()) yield return y;
}

Simply calling the Save method would construct an Ienumerable representing the continuation, but not actually invoke Save, this is a serious risk with this pattern, one that a language extension for c# could solve.

The use of the foreach with the yield return in Process is used to pump the waitables, a language extension, for example "yield Save();" would make this more usable.

In this implementation of Process the foreach yield pattern isn't needed, but it helps because it places the execution of Process and Save into the some model, if a simple return was used the Proces method would complete before Save would be invoked, now Save gets executed within the flow of Process in the place it is called.

Exception handling and try/finally is somewhat broken when using yield return, using seems to function, which is surprising since it uses try/finally internally too.

Some issues with the ordering, synchronization and locking start to arise when using this pattern, as with any other system that introduces some form of concurrency.

Clear advantage of this pattern over simply using threads is that it is explicit where the flow is interrupted, so it is easy to keep pre/post-conditions consistent.

The future that the continuation yields can be a task executing on another thread, very handy in places where CPU dependant tasks can be shown to be safely executable on multiple cores with little synchronization.

This made me wonder if the OS switches to another thread when a thread hits a hard page-fault and it needs to do disk IO, probably yes.

posted @ 9:56 PM | Feedback (0)

Saturday, January 26, 2008

Ugh, took me a day, but i got line numbers working from windbg.

This experience is really making me love open source, at least you have the source code of the receiving end of a system so you can debug where it is going wrong and what it expects.

The problem in this case is the the sstSrcModule documentation is wrong, both the start/end pairs aren't optional but need to have a value, and unlike the spec cannot be filled with zero's. so i now use 0 for start and 0xffffffff for end.

The filenames supposedly used a word for string length but actually uses a byte.

Big thanks to Digital Mars D for implementing a system that apparently ran into similar troubles and figured them out so i also could get past this point.

Also thanks to jaschaW from ddbg.

posted @ 3:24 PM | Feedback (0)

Wednesday, January 23, 2008

Always handy to have a list of stuff other people find handy in programming languages.

http://repinvariant.blogspot.com/2008/01/thoughts-on-lisp-things-that-other.html

personally i agree with the bignum point, pluk's default int implementation automatically starts to use bignums instead of int when an int overflows, at least that is what i want to implement if i get that far :)

Tail recursion as an optimization might be fun to implement, but what would the call stack look like, also how to detect this at all.

Multi methods is something i don't have a clue about, not sure how to put it into syntax, how to implement it efficiently, what to use it for.

 

D also has a lot of interest for me, pluk is somewhat similar to it.

http://www.unknownbrackets.com/tutorials/polishing-d

I'm not sure how D will ever become popular without all the fallout ruby is having currently.

This article starts with a slight criticisms that D isn't fully polished yet, but i don't see how an open project ever gets started by being complete and polished.

Looking at the work needed to get a language to the level that seems to be expected seems near impossible :)

 

 

posted @ 12:44 PM | Feedback (0)

Wednesday, January 16, 2008

After reading about collections in ruby and c#, i'm thinking about how to add collections to pluk.

Collection libraries seem to have become part of what people expect from a language, and seem to basicly consider it a part of it.

Not unreasonably seeing how things like foreach directly talk to its api.

So i'm designing the baseclass that will back most collections, and probably some other 'containers'.

abstract class Iteratable<T>
{
        Iterator<T> createIterator;
        Iteratable<T> copy();
        Iteratable<T> filter(Bool(T) predicate);
        Iteratable<U> map<U>(U(T) converter);
        Iteratable<T> take(Int count);
        Iteratable<T> drop(Int count);
        void foreach(void(T) action);
        U fold<U>(U(U, T) folder, U base);
        Bool exists(Bool(T) predicate);
        Bool all(Bool(T) predicate);
        Bool none(Bool(T) predicate);
}

Things like Sum / Min / Max / Average / Aggregate can be easily be used through the fold method, and so can exists/all/none. Inclusion of directer methods should depend on how commonly something is used, and if it actually saves work/thinking in the long run.

Methods like filter do not return an iteratable with the filtered data but an iteratable that when queried filters based on the filter function from the original iteratable on demand.

This way of lazy processing is more memory efficient generally.

This interface should allow additional syntax sugar like C# LINQ to work with pluk collections.

 

 

 

posted @ 10:07 PM | Feedback (0)

http://blog.micropledge.com/2008/01/ten-python-quirkies/

http://blogs.msdn.com/wesdyer/archive/2007/01/03/how-linq-to-objects-queries-work.aspx

posted @ 1:53 PM | Feedback (0)

It has some issues with shutting down that i'm too lazy to figure out, but it loads and adds a !dumpimage command to windbg that i used to feed a tool i use to find the number of objects in memory used to find memory leaks

library DrBart

// WinDbg plugin that dumps a 4G file named d:\dump\a containing the full memory space of the current open dump/process

// in windbg
// .load DrBart
// .dumpimage
 
uses
  SysUtils,
  Classes;
 
{$R *.res}
 
type
  TExtensionApis = record
    nSize: Cardinal;
    lpOutputRoutine: Pointer;
    lpGetExpressionRoutine: Pointer;
    lpGetSymbolRoutine: Pointer;
    lpDisasmRoutine: Pointer;
    lpCheckControlCRoutine: Pointer;
    lpReadProcessMemoryRoutine: Pointer;
    lpWriteProcessMemoryRoutine: Pointer;
    lpGetThreadContextRoutine: Pointer;
    lpSetThreadContextRoutine: Pointer;
    lpIoctlRoutine: Pointer;
    lpStackTraceRoutine: Pointer;
  end;
  PExtensionApis = ^ TExtensionApis;
  TPrint = procedure(c: PChar); stdcall;
  TEXT_API_VERSION = record
    Major, Minor, Rev, Res: Word;
    end;
  TReadMem = function (Ptr: Cardinal; Buffer: Pointer; BufLen: Cardinal; Read: Pointer): Cardinal; stdcall;
 
var
  ExtensionApis: TExtensionApis;
  ApiVersion: TEXT_API_VERSION;
 
function dumpimage: integer; Stdcall;
var
  I: Integer;
  Ptr: Cardinal;
  Buf: array[0..511] of Byte;
  Read: Cardinal;
  fOut: TFileStream;
begin
  fout := TFileStream.Create('d:\dump\a', fmCreate);
  for I := 0 to $7FFFFF do  // 4G / 512
  begin
    Ptr := I shl 9;
    TReadMem(ExtensionApis.lpReadProcessMemoryRoutine)(Ptr, @Buf[0], 512, @Read);
    fout.WriteBuffer(Buf[0], 512);
  end;
  fout.Free;
  Result := 0;
end;
 
procedure WinDbgExtensionDllInit(
    lpExtensionApis: PExtensionApis;
    MajorVersion: Word;
    MinorVersion: Word
    ); stdcall;
begin
    ExtensionApis := lpExtensionApis^;
end;
 

function
ExtensionApiVersion(): Pointer;
begin
  Result := @ApiVersion;
      //
    // ExtensionApiVersion should return EXT_API_VERSION_NUMBER64 in order for APIs
    // to recognize 64 bit addresses.  KDEXT_64BIT also has to be defined before including
    // wdbgexts.h to get 64 bit headers for WINDBG_EXTENSION_APIS
    //
    ApiVersion.Rev := 5;
    Result := @ApiVersion;
end;
 
//
// Routine called by debugger after load
//
procedure
CheckVersion; stdcall;begin end;
 
exports
  WinDbgExtensionDllInit,
  ExtensionApiVersion,
  CheckVersion,
 dumpimage;
 
begin
end.

posted @ 10:38 AM | Feedback (3)

Tuesday, January 15, 2008

Currently in Pluk i use  void(int) to denote the type of a lambda/method taking an int argument and returning nothing/void. This is a bit of a problem when defining a variable:

void(Int) x;

for example, is difficult to parse, both visually and practically, is it a function call statement followed by a typo, or a variable definition? This problem gets bigger when the type includes a templated part, or is a function type itself. So i decided to try wrapping types in [] when this is needed or helpful.

[void(Int)] x;

Int y;

[List<U>(List<T>, U,T)] converter;

and in the case of a function type that returns a function type

[void(String)](String) or with optionally [[void(String](String)] when needed.

 

posted @ 10:30 PM | Feedback (0)

1. blog.

2. .....

3. profit!

posted @ 8:46 PM | Feedback (0)