
I always liked Smalltalk. With its clinical simplicity (forgive me, lispers and forters) and no less clinically wide opportunities. I believe that it is undeservedly forgotten by the programmer community, although in the 21st century you can get a lot of benefit from it. However, the existing industrial implementations are too cumbersome for the first acquaintance and do not shine with the beauty of their forms. Meet, as you know, on clothes. A newcomer who first saw such an interface is unlikely to treat it as something modern and groundbreaking.case PushBlock: DBG0("PushBlock"); /* create a block object */ /* low is arg location */ /* next byte is goto value */ high = VAL; bytePointer += VALSIZE; rootStack[rootTop++] = context; op = rootStack[rootTop++] = gcalloc(x = integerValue(method->data[stackSizeInMethod])); op->class = ArrayClass; memoryClear(bytePtr(op), x * BytesPerWord); returnedValue = gcalloc(blockSize); returnedValue->class = BlockClass; returnedValue->data[bytePointerInContext] = returnedValue->data[stackTopInBlock] = returnedValue->data[previousContextInBlock] = NULL; returnedValue->data[bytePointerInBlock] = newInteger(bytePointer); returnedValue->data[argumentLocationInBlock] = newInteger(low); returnedValue->data[stackInBlock] = rootStack[--rootTop]; context = rootStack[--rootTop]; if(CLASS(context) == BlockClass) { returnedValue->data[creatingContextInBlock] = context->data[creatingContextInBlock]; } else { returnedValue->data[creatingContextInBlock] = context; } method = returnedValue->data[methodInBlock] = context->data[methodInBlock]; arguments = returnedValue->data[argumentsInBlock] = context->data[argumentsInBlock]; temporaries = returnedValue->data[temporariesInBlock] = context->data[temporariesInBlock]; stack = context->data[stackInContext]; bp = bytePtr(method->data[byteCodesInMethod]); stack->data[stackTop++] = returnedValue; /* zero these out just in case GC occurred */ literals = instanceVariables = 0; bytePointer = high; break; void SmalltalkVM::doPushBlock(TVMExecutionContext& ec) { hptr<TByteObject> byteCodes = newPointer(ec.currentContext->method->byteCodes); hptr<TObjectArray> stack = newPointer(ec.currentContext->stack); // Block objects are usually inlined in the wrapping method code // pushBlock operation creates a block object initialized // with the proper bytecode, stack, arguments and the wrapping context. // Blocks are not executed directly. Instead they should be invoked // by sending them a 'value' method. Thus, all we need to do here is initialize // the block object and then skip the block body by incrementing the bytePointer // to the block's bytecode' size. After that bytePointer will point to the place // right after the block's body. There we'll probably find the actual invoking code // such as sendMessage to a receiver (with our block as a parameter) or something similar. // Reading new byte pointer that points to the code right after the inline block uint16_t newBytePointer = byteCodes[ec.bytePointer] | (byteCodes[ec.bytePointer+1] << 8); // Skipping the newBytePointer's data ec.bytePointer += 2; // Creating block object hptr<TBlock> newBlock = newObject<TBlock>(); // Allocating block's stack uint32_t stackSize = getIntegerValue(ec.currentContext->method->stackSize); newBlock->stack = newObject<TObjectArray>(stackSize, false); newBlock->argumentLocation = newInteger(ec.instruction.low); newBlock->blockBytePointer = newInteger(ec.bytePointer); // Assigning creatingContext depending on the hierarchy // Nested blocks inherit the outer creating context if (ec.currentContext->getClass() == globals.blockClass) newBlock->creatingContext = ec.currentContext.cast<TBlock>()->creatingContext; else newBlock->creatingContext = ec.currentContext; // Inheriting the context objects newBlock->method = ec.currentContext->method; newBlock->arguments = ec.currentContext->arguments; newBlock->temporaries = ec.currentContext->temporaries; // Setting the execution point to a place right after the inlined block, // leaving the block object on top of the stack: ec.bytePointer = newBytePointer; stack[ec.stackTop++] = newBlock; }
This device has an onboard MC68020 + DSP processor. The control code is written in Smalltalk, critical sections in assembly language. The image consists of approximately 250 classes and is entirely placed in the ROM. It requires less than 64 KB of DRAM.
Dolphin Smalltalk is the only one out of Squeak, Pharo and other Visual Ages that was originally designed for tight integration with the OS.ia32-libs in the case of Ubuntu), as well as the g++-multilib . sudo apt-get install ia32-libs g++-multilib ~ $ git clone https://github.com/0x7CFE/llst.git ~ $ cd llst ~/llst $ mkdir build && cd build ~/llst/build $ cmake .. ~/llst/build $ make llst build$ ./llst Image read complete. Loaded 4678 objects Running CompareTest equal (1) OK equal (2) OK greater (int int) OK greater (int symbol) ERROR true (class True): does not understand asSmallInt VM: error trap on context 0xf728d8a4 Backtrace: error: (True, String) doesNotUnderstand: (True, Symbol) = (SmallInt, True) assertEq: withComment: (Block, True, String) assertWithComment: (Block, String) greater (CompareTest) less (int int) OK less (symbol int) OK nilEqNil OK nilIsNil OK Running SmallIntTest add OK div OK mul OK negated (1) OK negated (2) OK negative (1) OK negative (2) OK quo (1) OK quo (2) OK sub OK Running LoopTest loopCount OK sum ok symbolStressTest OK Running ClassTest className (1) OK className (2) OK sendSuper OK Running MethodLookupTest newline (Char) OK newline (string) OK parentMethods (1) OK parentMethods (2) OK Running StringTest asNumber OK asSymbol OK at (f) OK at (o) OK at (x) ok at (b) OK at (A) OK at (r) OK copy OK indexOf OK lowerCase OK plus (operator +. 1) OK plus (2) OK plus (3) OK plus (4) OK plus (5) OK plus (6) OK plus (7) OK plus (8) OK plus (9) OK reverse OK size (1) OK size (2) OK size (3) OK size (4) OK Running arraytest at (int) OK at (char) OK atPut OK Running gctest copy OK Running ContextTest backtrace (1) OK backtrace (2) OK instanceClass OK Running PrimitiveTest SmallIntAdd OK SmallIntDiv OK SmallIntEqual OK SmallIntLess OK SmallIntMod OK SmallIntMul OK SmallIntSub OK bulkReplace OK objectClass (SmallInt) OK objectClass (Object) OK objectSize (SmallInt) OK objectSize (Char) OK objectSize (Object) OK objectsAreEqual (1) OK objectsAreEqual (2) OK smallIntBitAnd OK smallIntBitOr OK smallIntShiftLeft OK smallIntShiftRight OK ->
-> 2 + 3 5 -> (2+3) class SmallInt -> (2+3) class parent Number -> Object class MetaObject -> Object class class Class -> 1 to: 10 do: [ :x | (x * 2) print. $ print ] 2 4 6 8 10 12 14 16 18 20 1 listMethods , viewMethod and allMethods methods are also allMethods : -> Collection viewMethod: #collect: collect: transformBlock | newList | newList <- List new. self do: [:element | newList addLast: (transformBlock value: element)]. ^ newList parent ) and the descendants: -> Collection subclasses Array ByteArray MyArray OrderedArray String Dictionary MyDict Interval List Set IdentitySet Tree Collection -> -> Exited normally GC count: 717, average allocations per gc: 25963, microseconds spent in GC: 375509 9047029 messages sent, cache hits: 4553006, misses: 53201, hit ratio 98.85 %
PS: At the moment I am looking for a place for the paid application of my strength (work, that is). If you have interesting projects (especially a similar plan), please knock on the PM. I myself am in the Novosibirsk Academgorodok.Source: https://habr.com/ru/post/164153/
All Articles