VM Maker: VMMaker.oscog-eem.2736.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

VM Maker: VMMaker.oscog-eem.2736.mcz

commits-2
 
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2736.mcz

==================== Summary ====================

Name: VMMaker.oscog-eem.2736
Author: eem
Time: 31 March 2020, 6:20:49.211408 pm
UUID: 1dd4c38f-c0b4-4edd-9165-f4a54a988fe7
Ancestors: VMMaker.oscog-eem.2735

Cog: fix genInvokeInterpretTrampoline; it must establish the var base.
Eliminate reenterInterpreter in the CoInterpreter (keeping it in the StackInterpreter; althoguh the success of the use in the CoInterpreter shows us that we should do the same, e.g. using assembler, in the StackInterpreter).

So now reentry into the interpreter from machine code does not use longjmp and we no longer use setjmp to establish the reentry-point.  We just use CFramePointer & CStackPointer.

Export the warning functions for Windows DLLs that want to use assertions.
Get rid of the preambleCCode implementation of invalidCompactClassError:

=============== Diff against VMMaker.oscog-eem.2735 ===============

Item was changed:
  ----- Method: CoInterpreter class>>declareCVarsIn: (in category 'translation') -----
  declareCVarsIn: aCCodeGenerator
  "Override to avoid repeating StackInterpreter's declarations and add our own extensions"
  self class == thisContext methodClass ifFalse: [^self]. "Don't duplicate decls in subclasses"
  aCCodeGenerator
  addHeaderFile:'"sqCogStackAlignment.h"';
  addHeaderFile:'"cogmethod.h"'.
  NewspeakVM ifTrue:
  [aCCodeGenerator addHeaderFile:'"nssendcache.h"'].
  aCCodeGenerator
  addHeaderFile: (aCCodeGenerator vmClass isThreadedVM
  ifTrue: ['"cointerpmt.h"']
  ifFalse: ['"cointerp.h"']);
  addHeaderFile:'"cogit.h"'.
  aCCodeGenerator vmClass
  declareInterpreterVersionIn: aCCodeGenerator
  defaultName: aCCodeGenerator interpreterVersion.
  aCCodeGenerator
  var: #heapBase type: #usqInt;
  var: #statCodeCompactionUsecs type: #usqLong;
  var: #maxLiteralCountForCompile
  declareC: 'sqInt maxLiteralCountForCompile = MaxLiteralCountForCompile /* ', MaxLiteralCountForCompile printString, ' */';
  var: #minBackwardJumpCountForCompile
  declareC: 'sqInt minBackwardJumpCountForCompile = MinBackwardJumpCountForCompile /* ', MinBackwardJumpCountForCompile printString, ' */'.
- aCCodeGenerator removeVariable: 'atCache'. "Way too much trouble than it's worth in the Cog VM"
  aCCodeGenerator
+ removeVariable: 'atCache'; "Way too much trouble than it's worth in the Cog VM"
+ removeVariable: 'reenterInterpreter'. "We can use the JIT and CFrame/StrackPointer for a lighter-weight solution."
+ aCCodeGenerator
  var: #primTraceLogIndex type: #'unsigned char';
  var: #primTraceLog declareC: 'sqInt primTraceLog[256]';
  var: #traceLog
  declareC: 'sqInt traceLog[TraceBufferSize /* ', TraceBufferSize printString, ' */]';
  var: #traceSources type: #'char *' array: TraceSources.
  aCCodeGenerator
  var: #CFramePointer type: #'volatile usqIntptr_t';
  var: #CStackPointer type: #'volatile usqIntptr_t'!

Item was added:
+ ----- Method: CoInterpreter>>activateFailingPrimitiveMethod (in category 'primitive support') -----
+ activateFailingPrimitiveMethod
+ "Assuming the primFailCode (and any other relevant failure state) has been set,
+ switch the VM to the interpreter if necessary (if in the CoInterpreter executing machine code),
+ and activate the newMethod (which is expected to have a primitive)."
+ self assert: primFailCode ~= 0.
+ self assert: (objectMemory addressCouldBeObj: newMethod).
+ self assert: (objectMemory isCompiledMethod: newMethod).
+ self assert: (self primitiveIndexOf: newMethod) ~= 0.
+ self justActivateNewMethod: true. "Frame must be interpreted"
+ cogit ceInvokeInterpret.
+ "NOTREACHED"
+ ^nil!

Item was changed:
  ----- Method: CoInterpreter>>callbackEnter: (in category 'callback support') -----
  callbackEnter: callbackID
  "Re-enter the interpreter for executing a callback"
+ | currentCStackPointer currentCFramePointer wasInMachineCode calledFromMachineCode |
- | currentCStackPointer currentCFramePointer savedReenterInterpreter
-  wasInMachineCode calledFromMachineCode |
  <volatile>
  <export: true>
  <var: #currentCStackPointer type: #usqIntptr_t>
  <var: #currentCFramePointer type: #usqIntptr_t>
  <var: #callbackID type: #'sqInt *'>
- <var: #savedReenterInterpreter type: #'jmp_buf'>
 
  "For now, do not allow a callback unless we're in a primitiveResponse"
  (self asserta: primitiveFunctionPointer ~= 0) ifFalse:
  [^false].
 
  self assert: primFailCode = 0.
 
  "Check if we've exceeded the callback depth"
  (self asserta: jmpDepth < MaxJumpBuf) ifFalse:
  [^false].
  jmpDepth := jmpDepth + 1.
 
  wasInMachineCode := self isMachineCodeFrame: framePointer.
  calledFromMachineCode := instructionPointer <= objectMemory startOfMemory.
 
  "Suspend the currently active process"
  suspendedCallbacks at: jmpDepth put: self activeProcess.
  "We need to preserve newMethod explicitly since it is not activated yet
  and therefore no context has been created for it. If the caller primitive
  for any reason decides to fail we need to make sure we execute the correct
  method and not the one 'last used' in the call back"
  suspendedMethods at: jmpDepth put: newMethod.
  self flag: 'need to debug this properly.  Conceptually it is the right thing to do but it crashes in practice'.
  false
  ifTrue:
  ["Signal external semaphores since a signalSemaphoreWithIndex: request may
   have been issued immediately prior to this callback before the VM has any
   chance to do a signalExternalSemaphores in checkForEventsMayContextSwitch:"
  self signalExternalSemaphores.
  "If no process is awakened by signalExternalSemaphores then transfer
   to the highest priority runnable one."
  (suspendedCallbacks at: jmpDepth) = self activeProcess ifTrue:
  [self transferTo: self wakeHighestPriority from: CSCallbackLeave]]
  ifFalse:
  [self transferTo: self wakeHighestPriority from: CSCallbackLeave].
 
  "Typically, invoking the callback means that some semaphore has been
  signaled to indicate the callback. Force an interrupt check as soon as possible."
  self forceInterruptCheck.
 
+ "Save the previous CStackPointers..."
- "Save the previous CStackPointers and interpreter entry jmp_buf."
  currentCStackPointer := CStackPointer.
  currentCFramePointer := CFramePointer.
- self memcpy: savedReenterInterpreter asVoidPointer
- _: reenterInterpreter
- _: (self sizeof: #'jmp_buf').
  cogit assertCStackWellAligned.
  (self setjmp: (jmpBuf at: jmpDepth)) = 0 ifTrue: "Fill in callbackID"
  [callbackID at: 0 put: jmpDepth.
  self enterSmalltalkExecutive.
  self assert: false "NOTREACHED"].
 
+ "Restore the previous CStackPointers..."
- "Restore the previous CStackPointers and interpreter entry jmp_buf."
  self setCFramePointer: currentCFramePointer setCStackPointer: currentCStackPointer.
- self memcpy: reenterInterpreter
- _: (self cCoerceSimple: savedReenterInterpreter to: #'void *')
- _: (self sizeof: #'jmp_buf').
 
  "Transfer back to the previous process so that caller can push result"
  self putToSleep: self activeProcess yieldingIf: preemptionYields.
  self transferTo: (suspendedCallbacks at: jmpDepth) from: CSCallbackLeave.
  newMethod := suspendedMethods at: jmpDepth. "see comment above"
  argumentCount := self argumentCountOf: newMethod.
  self assert: wasInMachineCode = (self isMachineCodeFrame: framePointer).
  calledFromMachineCode
  ifTrue:
  [instructionPointer asUnsignedInteger >= objectMemory startOfMemory ifTrue:
  [self iframeSavedIP: framePointer put: instructionPointer.
  instructionPointer := cogit ceReturnToInterpreterPC]]
  ifFalse:
  ["Even if the context was flushed to the heap and rebuilt in transferTo:from:
   above it will remain an interpreted frame because the context's pc would
   remain a bytecode pc.  So the instructionPointer must also be a bytecode pc."
  self assert: (self isMachineCodeFrame: framePointer) not.
  self assert: instructionPointer > objectMemory startOfMemory].
  self assert: primFailCode = 0.
  jmpDepth := jmpDepth-1.
  ^true!

Item was changed:
  ----- Method: CoInterpreter>>enterSmalltalkExecutiveImplementation (in category 'initialization') -----
  enterSmalltalkExecutiveImplementation
  "Main entry-point into the interpreter at each execution level, where an execution
  level is either the start of execution or reentry for a callback.  Capture the C stack
  pointers so that calls from machine-code into the C run-time occur at this level.
  This is the actual implementation, separated from enterSmalltalkExecutive so the
  simulator can wrap it in an exception handler and hence simulate the setjmp/longjmp."
  <inline: false>
  cogit assertCStackWellAligned.
  cogit ceCaptureCStackPointers.
- "Setjmp for reentry into interpreter from elsewhere, e.g. machine-code trampolines."
- self sigset: reenterInterpreter jmp: 0.
  (self isMachineCodeFrame: framePointer) ifTrue:
  [self returnToExecutive: false postContextSwitch: true
  "NOTREACHED"].
  self setMethod: (self iframeMethod: framePointer).
  instructionPointer = cogit ceReturnToInterpreterPC ifTrue:
  [instructionPointer := self iframeSavedIP: framePointer].
  self assertValidExecutionPointe: instructionPointer r: framePointer s: stackPointer imbar: true line: #'__LINE__'.
  self interpret.
  ^0!

Item was changed:
  ----- Method: CoInterpreter>>invokeInterpreterFromMachineCode (in category 'trampolines') -----
  invokeInterpreterFromMachineCode
  "This is just a rename for a send of interpret, but provides
  a simulation hook; see the CogVMSimulator subclass."
  <inline: #always>
+ cogit ceInvokeInterpret
- self interpret
 
  "NOTREACHED"!

Item was changed:
  ----- Method: CoInterpreter>>restoreCStackStateForCallbackContext: (in category 'callback support') -----
  restoreCStackStateForCallbackContext: vmCallbackContext
  <var: #vmCallbackContext type: #'VMCallbackContext *'>
+ <inline: #always>
+ self setCFramePointer: vmCallbackContext savedCFramePointer setCStackPointer: vmCallbackContext savedCStackPointer!
- self setCFramePointer: vmCallbackContext savedCFramePointer setCStackPointer: vmCallbackContext savedCStackPointer.
- self memcpy: reenterInterpreter
- _: vmCallbackContext savedReenterInterpreter asVoidPointer
- _: (self sizeof: #'jmp_buf')!

Item was changed:
  ----- Method: CoInterpreter>>saveCStackStateForCallbackContext: (in category 'callback support') -----
  saveCStackStateForCallbackContext: vmCallbackContext
  <var: #vmCallbackContext type: #'VMCallbackContext *'>
+ <inline: #always>
  vmCallbackContext
  savedCStackPointer: CStackPointer asVoidPointer;
+ savedCFramePointer: CFramePointer asVoidPointer!
- savedCFramePointer: CFramePointer asVoidPointer.
- super saveCStackStateForCallbackContext: vmCallbackContext!

Item was removed:
- ----- Method: CogVMSimulator>>invalidCompactClassError: (in category 'interpreter shell') -----
- invalidCompactClassError: name
- self error: 'Class ', name, ' does not have the required compact class index'!

Item was changed:
  ----- Method: Cogit>>genInvokeInterpretTrampoline (in category 'initialization') -----
  genInvokeInterpretTrampoline
  "Switch to the C stack (do *not* save the Smalltalk stack pointers;
  this is the caller's responsibility), and invoke interpret PDQ."
  | startAddress |
  <inline: false>
  startAddress := methodZoneBase.
  self zeroOpcodeIndex.
+ backEnd hasVarBaseRegister ifTrue:
+ [self MoveCq: self varBaseAddress R: VarBaseReg]. "Must happen first; value may be used in genLoadStackPointers"
  cFramePointerInUse
  ifTrue: [backEnd genLoadCStackPointers]
  ifFalse: [backEnd genLoadCStackPointer].
+ self CallFullRT: #interpret registersToBeSavedMask: self emptyRegisterMask.
- self
- compileCallFor: #interpret
- numArgs: 0 arg: nil arg: nil arg: nil arg: nil
- resultReg: NoReg
- regsToSave: self emptyRegisterMask.
  self outputInstructionsForGeneratedRuntimeAt: startAddress.
  self recordGeneratedRunTime: 'ceInvokeInterpret' address: startAddress.
  ^startAddress!

Item was removed:
- ----- Method: InterpreterSimulator>>invalidCompactClassError: (in category 'interpreter shell') -----
- invalidCompactClassError: name
- self error: 'Class ', name, ' does not have the required compact class index'!

Item was added:
+ ----- Method: ObjectMemory>>invalidCompactClassError: (in category 'initialization') -----
+ invalidCompactClassError: className
+ <inline: false>
+ self cCode:
+ ['\nClass %s does not have the required compact class index\n' printf: className.
+ self exit: -1]
+ inSmalltalk:
+ [self error: 'Class ', className, ' does not have the required compact class index']!

Item was added:
+ ----- Method: SpurMemoryManager>>invalidCompactClassError: (in category 'initialization') -----
+ invalidCompactClassError: className
+ <inline: false>
+ self cCode:
+ ['\nClass %s does not have the required class index\n' printf: className.
+ self exit: -1]
+ inSmalltalk:
+ [self error: 'Class ', className, ' does not have the required class index']!

Item was changed:
  ----- Method: StackInterpreter class>>preambleCCode (in category 'translation') -----
  preambleCCode
  ^
  '/* Disable Intel compiler inlining of warning which is used for breakpoints */
  #pragma auto_inline(off)
  sqInt warnpid, erroronwarn;
+ EXPORT(void)
- void
  warning(char *s) { /* Print an error message but don''t necessarily exit. */
  if (erroronwarn) error(s);
  if (warnpid)
  printf("\n%s pid %ld\n", s, (long)warnpid);
  else
  printf("\n%s\n", s);
  }
+ EXPORT(void)
- void
  warningat(char *s, int l) { /* ditto with line number. */
  /* use alloca to call warning so one does not have to remember to set two breakpoints... */
  char *sl = alloca(strlen(s) + 16);
  sprintf(sl, "%s %d", s, l);
  warning(sl);
  }
  #pragma auto_inline(on)
 
- void
- invalidCompactClassError(char *s) { /* Print a (compact) class index error message and exit. */
- #if SPURVM
- printf("\nClass %s does not have the required class index\n", s);
- #else
- printf("\nClass %s does not have the required compact class index\n", s);
- #endif
- exit(-1);
- }
-
  /*
   * Define sigsetjmp and siglongjmp to be the most minimal setjmp/longjmp available on the platform.
   * Note: on windows 64 via mingw-w64, the 2nd argument NULL to _setjmp prevents stack unwinding
+  * On windows 32 via MSVC _longjmpex prevents stack unwinding. Not supported on windows 64.
   */
  #undef sigsetjmp
  #undef siglongjmp
  #if _MSC_VER
+ # if _WIN64
+ # define sigsetjmp(jb,ssmf) _setjmp(jb)
+ # define siglongjmp(jb,v) longjmp(jb,v)
+ # else
+ # define sigsetjmp(jb,ssmf) _setjmp(jb)
+ # define siglongjmp(jb,v) _longjmpex(jb,v)
+ # endif
- # define sigsetjmp(jb,ssmf) _setjmp(jb)
- # define siglongjmp(jb,v) longjmp(jb,v)
  #elif _WIN64 && __GNUC__
  # define sigsetjmp(jb,ssmf) _setjmp(jb,NULL)
  # define siglongjmp(jb,v) longjmp(jb,v)
  #elif _WIN32
  # define sigsetjmp(jb,ssmf) setjmp(jb)
  # define siglongjmp(jb,v) longjmp(jb,v)
  #else
  # define sigsetjmp(jb,ssmf) _setjmp(jb)
  # define siglongjmp(jb,v) _longjmp(jb,v)
  #endif
 
  #define odd(v) ((int)(v)&1)
  #define even(v) (!!odd(v))
  '!

Item was removed:
- ----- Method: StackInterpreterSimulator>>invalidCompactClassError: (in category 'interpreter shell') -----
- invalidCompactClassError: name
- self error: 'Class ', name, ' does not have the required compact class index'!

Reply | Threaded
Open this post in threaded view
|

Re: VM Maker: VMMaker.oscog-eem.2736.mcz

timrowledge
 


> On 2020-03-31, at 6:21 PM, [hidden email] wrote:
>
>
> So now reentry into the interpreter from machine code does not use longjmp and we no longer use setjmp to establish the reentry-point.  We just use CFramePointer & CStackPointer.

Yay! I've always harted setjmp/longjmp for some reason.

tim
--
tim Rowledge; [hidden email]; http://www.rowledge.org/tim
Strange OpCodes: SDL: Shift Disk Left