diff --git a/autotest/stdlibtest.c b/autotest/stdlibtest.c index 2409c2b..84d3268 100644 --- a/autotest/stdlibtest.c +++ b/autotest/stdlibtest.c @@ -51,16 +51,15 @@ void heapcheck(void) for(i=0; iHeapStart + sta HeapNode + 1 + + // set size to size of heap + sec + lda #HeapEnd + sbc #>HeapStart + sta HeapStart + 3 + +hasHeap: + // remember address of pointer to this + // heap block, to correct if block is a + // perfect fit + + lda #HeapNode + sta accu + 3 + + // Now loop over free nodes, until we find a match +loop: + // next heap block + + ldy #0 + lda (accu + 2), y + sta accu + iny + lda (accu + 2), y + sta accu + 1 + + // exit if out of blocks + + beq done + // calculate remaining size of heap block + + ldy #2 + sec + lda (accu), y + sbc tmp + sta tmp + 2 + iny + lda (accu), y + sbc tmp + 1 + sta tmp + 3 + + // will fit + bcs avail + + // prev + lda accu + sta accu + 2 + lda accu + 1 + sta accu + 3 + jmp loop + +done: + // no more heap blocks + rts +avail: + // is it a perfect fit? + lda tmp + 2 + ora tmp + 3 + bne nofit + + // so adjust previous pointer to point to + // next heap block + ldy #0 + lda (accu), y + sta (accu + 2), y + iny + lda (accu), y + sta (accu + 2), y + jmp found + +nofit: + // adjust size of remaining heapblock + ldy #2 + lda tmp + 2 + sta (accu), y + iny + lda tmp + 3 + sta (accu), y + + // advance address to start of next heap block + + clc + lda accu + adc tmp + 2 + sta accu + lda accu + 1 + adc tmp + 3 + sta accu + 1 + +found: + // remember size of heap block for free without size + + ldy #0 + lda tmp + 4 + sta (accu), y + iny + lda tmp + 5 + sta (accu), y + + // advanve by two bytes to skip size + clc + lda accu + adc #2 + sta accu + bcc page + inc accu + 1 +page: + rts +} + +__asm inp_malloc +{ + sty tmpy + jsr malloc + ldy tmpy + jmp startup.exec +} + +#pragma bytecode(BC_MALLOC, inp_malloc) + +__asm free +{ + // check nullptr free + lda accu + ora accu + 1 + bne notnull + rts +notnull: + // two bytes back to fix size + sec + lda accu + sbc #2 + sta accu + bcs page + dec accu + 1 +page: + + // cache size and end of block + + clc + ldy #0 + lda (accu), y + adc #5 + and #$fc + sta tmp + iny + lda (accu), y + adc #0 + sta tmp + 1 + + clc + lda tmp + 0 + adc accu + sta accu + 2 + lda tmp + 1 + adc accu + 1 + sta accu + 3 + + // pointer to heap block, starting with + // dummy block + + lda #HeapNode + sta tmp + 3 + +loop: + // check if end of heap + + ldy #1 + lda (tmp + 2), y + beq noend + + // Check if behind this block + + cmp accu + 1 + bcc before + bne after + + dey + lda (tmp + 2), y + cmp accu + 0 + bcs after + +before: + ldy # 1 + lda (tmp + 2), y + tax + dey + lda (tmp + 2), y + sta tmp + 2 + stx tmp + 3 + jmp loop +after: + + // Merge with next block + + ldy #1 + lda accu + 3 + cmp (tmp + 2), y + bne noend + dey + lda accu + 2 + cmp (tmp + 2), y + bne noend + + // Pointer to next next block + ldy #0 + lda (accu + 2), y + sta (accu), y + iny + lda (accu + 2), y + sta (accu), y + + // Add size of next block to this + iny + clc + lda tmp + adc (accu + 2), y + sta tmp + iny + lda tmp + 1 + adc (accu + 2), y + sta tmp + 1 + + jmp start +noend: + // Link to next block + ldy #0 + lda (tmp + 2), y + sta (accu), y + iny + lda (tmp + 2), y + sta (accu), y + +start: + // Calculate end of free block + ldy #2 + clc + lda tmp + 2 + adc (tmp + 2), y + iny + tax + lda tmp + 3 + adc (tmp + 2), y + + // Matches start of new block + cmp accu + 1 + bne nostart + cpx accu + bne nostart + + // If so, increase the size and link + // to free block after + + ldy #0 + lda (accu), y + sta (tmp + 2), y + iny + lda (accu), y + sta (tmp + 2), y + + iny + clc + lda (tmp + 2), y + adc tmp + sta (tmp + 2), y + iny + lda (tmp + 2), y + adc tmp + 1 + sta (tmp + 2), y + + rts + +nostart: + // Link to new free block + + ldy #0 + lda accu + sta (tmp + 2), y + iny + lda accu + 1 + sta (tmp + 2), y + iny + + // Set size of free block + lda tmp + sta (accu), y + iny + lda tmp + 1 + sta (accu), y + rts +} + +__asm inp_free +{ + sty tmpy + jsr free + ldy tmpy + jmp startup.exec +} + +#pragma bytecode(BC_FREE, inp_free) + + +#pragma runtime(malloc, malloc) +#pragma runtime(free, free) + +#if 0 + +void * malloc(unsigned int size) +{ + size = (size + 7) & ~3; + if (!freeHeapInit) + { + freeHeap = (Heap *)&HeapStart; + freeHeap->next = nullptr; + freeHeap->size = (unsigned int)&HeapEnd - (unsigned int)&HeapStart; + freeHeapInit = true; + } + + Heap * pheap = nullptr, * heap = freeHeap; + while (heap) + { + if (size <= heap->size) + { + if (size == heap->size) + { + if (pheap) + pheap->next = heap->next; + else + freeHeap = heap->next; + } + else + { + Heap * nheap = (Heap *)((int)heap + size); + nheap->size = heap->size - size; + nheap->next = heap->next; + if (pheap) + pheap->next = nheap; + else + freeHeap = nheap; + heap->size = size; + } + + return (void *)((int)heap + 2); + } + pheap = heap; + heap = heap->next; + } + + return nullptr; +} + +void free(void * ptr) +{ + if (!ptr) + return; + + Heap * fheap = (Heap *)((int)ptr - 2); + Heap * eheap = (Heap *)((int)ptr - 2 + fheap->size); + + if (freeHeap) + { + if (eheap == freeHeap) + { + fheap->size += freeHeap->size; + fheap->next = freeHeap->next; + freeHeap = fheap; + } + else if (eheap < freeHeap) + { + fheap->next = freeHeap; + freeHeap = fheap; + } + else + { + Heap * pheap = freeHeap; + while (pheap->next && pheap->next < fheap) + pheap = pheap->next; + Heap * nheap = (Heap *)((int)pheap + pheap->size); + + if (nheap == fheap) + { + pheap->size += fheap->size; + if (pheap->next == eheap) + { + pheap->size += pheap->next->size; + pheap->next = pheap->next->next; + } + } + else if (pheap->next == eheap) + { + fheap->next = pheap->next->next; + fheap->size += pheap->next->size; + pheap->next = fheap; + } + else + { + fheap->next = pheap->next; + pheap->next = fheap; + } + } + } + else + { + freeHeap = fheap; + freeHeap->next = nullptr; + } +} +#endif diff --git a/include/crt.h b/include/crt.h index 5844f9c..2cc7fc0 100644 --- a/include/crt.h +++ b/include/crt.h @@ -142,8 +142,8 @@ enum ByteCode BC_BRANCHF_LE, BC_LOOP_U8, - BC_UNUSED_2, - BC_UNUSED_3, + BC_MALLOC, + BC_FREE, BC_UNUSED_4, BC_UNUSED_5, BC_UNUSED_6, diff --git a/include/stdlib.c b/include/stdlib.c index cfcbda6..a181c0a 100644 --- a/include/stdlib.c +++ b/include/stdlib.c @@ -524,6 +524,7 @@ void exit(int status) } } +#if 0 struct Heap { unsigned int size; Heap * next; @@ -636,6 +637,7 @@ void free(void * ptr) freeHeap->next = nullptr; } } +#endif void * calloc(int num, int size) { diff --git a/include/stdlib.h b/include/stdlib.h index 1761f40..7384454 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -47,6 +47,10 @@ unsigned int rand(void); void srand(unsigned int seed); +#pragma intrinsic(malloc) + +#pragma intrinsic(free) + #pragma compile("stdlib.c") #endif diff --git a/oscar64/ByteCodeGenerator.cpp b/oscar64/ByteCodeGenerator.cpp index 94181cc..cd17825 100644 --- a/oscar64/ByteCodeGenerator.cpp +++ b/oscar64/ByteCodeGenerator.cpp @@ -142,8 +142,8 @@ static const char* ByteCodeNames[] = { "BRANCHF_LE", "LOOP_U8", - nullptr, - nullptr, + "MALLOC", + "FREE", nullptr, nullptr, nullptr, @@ -565,6 +565,11 @@ bool ByteCodeInstruction::CheckAccuSize(uint32 & used) used = 0; break; + case BC_MALLOC: + case BC_FREE: + used = 0x0000ffff; + break; + case BC_BINOP_ADDA_16: used |= 0x0000ffff; break; @@ -779,6 +784,8 @@ bool ByteCodeInstruction::UsesRegister(uint32 reg) const return true; if (mCode == BC_BINOP_ADDA_16) return true; + if (mCode == BC_MALLOC || mCode == BC_FREE) + return true; } if (reg == BC_REG_ADDR) @@ -851,6 +858,8 @@ bool ByteCodeInstruction::ChangesRegister(uint32 reg) const return true; if (mCode == BC_LOOP_U8) return true; + if (mCode == BC_MALLOC || mCode == BC_FREE) + return true; } if (reg == BC_REG_ADDR) @@ -869,6 +878,8 @@ bool ByteCodeInstruction::ChangesRegister(uint32 reg) const { if (mCode == BC_JSR || mCode == BC_CALL_ADDR || mCode == BC_CALL_ABS) return true; + if (mCode == BC_MALLOC || mCode == BC_FREE) + return true; if (mCode == BC_BINOP_DIVR_I16 || mCode == BC_BINOP_DIVR_U16 || mCode == BC_BINOP_MODR_I16 || mCode == BC_BINOP_MODR_U16 || mCode == BC_BINOP_DIV_I32 || mCode == BC_BINOP_DIV_U32 || mCode == BC_BINOP_MOD_I32 || mCode == BC_BINOP_MOD_U32 || @@ -1149,6 +1160,8 @@ void ByteCodeInstruction::Assemble(ByteCodeGenerator* generator, ByteCodeBasicBl assert(false); break; + case BC_MALLOC: + case BC_FREE: case BC_CALL_ADDR: block->PutCode(generator, mCode); break; @@ -1578,6 +1591,49 @@ void ByteCodeBasicBlock::StrcpyValue(InterCodeProcedure* proc, const InterInstru mIns.Push(cins); } +void ByteCodeBasicBlock::CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins) +{ + if (ins->mSrc[0].mTemp < 0) + { + ByteCodeInstruction dins(BC_CONST_16); + dins.mRegister = BC_REG_ACCU; + dins.mValue = int(ins->mSrc[0].mIntConst & 0xffff); + mIns.Push(dins); + } + else + { + ByteCodeInstruction dins(BC_LOAD_REG_16); + dins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]; + dins.mRegisterFinal = ins->mSrc[0].mFinal; + mIns.Push(dins); + } + ByteCodeInstruction cins(BC_MALLOC); + mIns.Push(cins); + ByteCodeInstruction bins(BC_STORE_REG_16); + bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp]; + mIns.Push(bins); +} + +void ByteCodeBasicBlock::CallFree(InterCodeProcedure* proc, const InterInstruction* ins) +{ + if (ins->mSrc[0].mTemp < 0) + { + ByteCodeInstruction dins(BC_CONST_16); + dins.mRegister = BC_REG_ACCU; + dins.mValue = int(ins->mSrc[0].mIntConst & 0xffff); + mIns.Push(dins); + } + else + { + ByteCodeInstruction dins(BC_LOAD_REG_16); + dins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp]; + dins.mRegisterFinal = ins->mSrc[0].mFinal; + mIns.Push(dins); + } + ByteCodeInstruction cins(BC_FREE); + mIns.Push(cins); +} + void ByteCodeBasicBlock::StoreDirectValue(InterCodeProcedure* proc, const InterInstruction * ins) { if (ins->mSrc[0].mType == IT_FLOAT) @@ -4259,6 +4315,12 @@ void ByteCodeBasicBlock::Compile(InterCodeProcedure* iproc, ByteCodeProcedure* p case IC_STRCPY: StrcpyValue(iproc, ins); break; + case IC_MALLOC: + CallMalloc(iproc, ins); + break; + case IC_FREE: + CallFree(iproc, ins); + break; case IC_LOAD_TEMPORARY: { if (ins->mSrc[0].mTemp != ins->mDst.mTemp) diff --git a/oscar64/ByteCodeGenerator.h b/oscar64/ByteCodeGenerator.h index 19871bc..fac6acb 100644 --- a/oscar64/ByteCodeGenerator.h +++ b/oscar64/ByteCodeGenerator.h @@ -143,8 +143,8 @@ enum ByteCode BC_BRANCHF_LE, BC_LOOP_U8, - BC_UNUSED_2, - BC_UNUSED_3, + BC_MALLOC, + BC_FREE, BC_UNUSED_4, BC_UNUSED_5, BC_UNUSED_6, @@ -283,6 +283,8 @@ public: void FloatConstToWork(double val); void CopyValue(InterCodeProcedure* proc, const InterInstruction * ins); void StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins); + void CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins); + void CallFree(InterCodeProcedure* proc, const InterInstruction* ins); void LoadConstant(InterCodeProcedure* proc, const InterInstruction * ins); void StoreDirectValue(InterCodeProcedure* proc, const InterInstruction * ins); void LoadDirectValue(InterCodeProcedure* proc, const InterInstruction * ins); diff --git a/oscar64/Compiler.cpp b/oscar64/Compiler.cpp index c34aa31..7215372 100644 --- a/oscar64/Compiler.cpp +++ b/oscar64/Compiler.cpp @@ -669,6 +669,9 @@ bool Compiler::GenerateCode(void) RegisterRuntime(loc, Ident::Unique("mods32")); RegisterRuntime(loc, Ident::Unique("divu32")); RegisterRuntime(loc, Ident::Unique("modu32")); + + RegisterRuntime(loc, Ident::Unique("malloc")); + RegisterRuntime(loc, Ident::Unique("free")); } // Register extended byte code functions diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h index 6c161db..fab88ce 100644 --- a/oscar64/Declaration.h +++ b/oscar64/Declaration.h @@ -187,7 +187,7 @@ enum ExpressionType EX_ASSUME, EX_BANKOF, EX_CONSTRUCT, - EX_CLEANUP, + EX_CLEANUP }; class Expression diff --git a/oscar64/Disassembler.cpp b/oscar64/Disassembler.cpp index 042ce48..7f76623 100644 --- a/oscar64/Disassembler.cpp +++ b/oscar64/Disassembler.cpp @@ -476,6 +476,13 @@ void ByteCodeDisassembler::Disassemble(FILE* file, const uint8* memory, int bank fprintf(file, "CNVFS\tACCU"); break; + case BC_MALLOC: + fprintf(file, "MALLOC\tACCU"); + break; + case BC_FREE: + fprintf(file, "FREE\tACCU"); + break; + case BC_JUMPS: fprintf(file, "JUMP\t$%04X", start + i + 1 + int8(memory[start + i + 0])); i++; diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 6e4723b..2e22823 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -634,7 +634,7 @@ bool InterCodeBasicBlock::CanSwapInstructions(const InterInstruction* ins0, cons { if (ins0->mCode == IC_CALL || ins0->mCode == IC_CALL_NATIVE || ins0->mCode == IC_ASSEMBLER || ins0->mCode == IC_RETURN || ins0->mCode == IC_RETURN_STRUCT || ins0->mCode == IC_RETURN_VALUE || - ins0->mCode == IC_PUSH_FRAME || ins0->mCode == IC_POP_FRAME) + ins0->mCode == IC_PUSH_FRAME || ins0->mCode == IC_POP_FRAME || ins0->mCode == IC_MALLOC || ins0->mCode == IC_FREE) return false; if (ins0->mCode == IC_LOAD || ins0->mCode == IC_STORE || ins0->mCode == IC_COPY || ins0->mCode == IC_STRCPY) @@ -643,13 +643,30 @@ bool InterCodeBasicBlock::CanSwapInstructions(const InterInstruction* ins0, cons if (ins0->mCode == IC_CALL || ins0->mCode == IC_CALL_NATIVE || ins0->mCode == IC_ASSEMBLER) { if (ins1->mCode == IC_RETURN || ins1->mCode == IC_RETURN_STRUCT || ins1->mCode == IC_RETURN_VALUE || - ins1->mCode == IC_PUSH_FRAME || ins1->mCode == IC_POP_FRAME) + ins1->mCode == IC_PUSH_FRAME || ins1->mCode == IC_POP_FRAME || ins1->mCode == IC_MALLOC || ins1->mCode == IC_FREE) return false; if (ins1->mCode == IC_LOAD || ins1->mCode == IC_STORE || ins1->mCode == IC_COPY || ins1->mCode == IC_STRCPY) return false; } + if (ins0->mCode == IC_MALLOC || ins0->mCode == IC_FREE) + { + if (ins1->mCode == IC_MALLOC || ins1->mCode == IC_FREE) + return false; + } + + if (ins0->mCode == IC_FREE) + { + if (ins1->mCode == IC_LOAD || ins1->mCode == IC_STORE || ins1->mCode == IC_COPY || ins1->mCode == IC_STRCPY) + return false; + } + if (ins1->mCode == IC_FREE) + { + if (ins0->mCode == IC_LOAD || ins0->mCode == IC_STORE || ins0->mCode == IC_COPY || ins0->mCode == IC_STRCPY) + return false; + } + // Check frame pointer if (ins0->mCode == IC_PUSH_FRAME || ins0->mCode == IC_POP_FRAME) { @@ -1151,17 +1168,17 @@ void ValueSet::InsertValue(InterInstruction * ins) static bool HasSideEffect(InterCode code) { - return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER; + return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_MALLOC || code == IC_FREE; } static bool IsObservable(InterCode code) { - return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_STORE || code == IC_COPY || code == IC_STRCPY; + return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_STORE || code == IC_COPY || code == IC_STRCPY || code == IC_MALLOC || code == IC_FREE; } static bool IsMoveable(InterCode code) { - if (HasSideEffect(code) || code == IC_COPY || code == IC_STRCPY || code == IC_STORE || code == IC_BRANCH || code == IC_POP_FRAME || code == IC_PUSH_FRAME) + if (HasSideEffect(code) || code == IC_COPY || code == IC_STRCPY || code == IC_STORE || code == IC_BRANCH || code == IC_POP_FRAME || code == IC_PUSH_FRAME || code == IC_MALLOC || code == IC_FREE) return false; if (code == IC_RETURN || code == IC_RETURN_STRUCT || code == IC_RETURN_VALUE) return false; @@ -2762,12 +2779,43 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr case IC_BRANCH: if (ins->mSrc[0].mTemp >= 0 && tvalue[ins->mSrc[0].mTemp] && tvalue[ins->mSrc[0].mTemp]->mCode == IC_CONSTANT) { - if (tvalue[ins->mSrc[0].mTemp]->mConst.mIntConst) - ins->mCode = IC_JUMP; - else - ins->mCode = IC_JUMPF; - ins->mSrc[0].mTemp = -1; - ins->mNumOperands = 0; + InterInstruction* tins = tvalue[ins->mSrc[0].mTemp]; + if (IsIntegerType(tins->mConst.mType) || tins->mConst.mType == IT_BOOL) + { + if (tins->mConst.mIntConst) + ins->mCode = IC_JUMP; + else + ins->mCode = IC_JUMPF; + ins->mSrc[0].mTemp = -1; + ins->mNumOperands = 0; + } + else if (tins->mConst.mType == IT_POINTER) + { + if (tins->mConst.mMemory == IM_ABSOLUTE) + { + if (tins->mConst.mIntConst) + ins->mCode = IC_JUMP; + else + ins->mCode = IC_JUMPF; + ins->mSrc[0].mTemp = -1; + ins->mNumOperands = 0; + } + else if (tins->mConst.mMemory == IM_GLOBAL || tins->mConst.mMemory == IM_LOCAL || tins->mConst.mMemory == IM_PARAM || tins->mConst.mMemory == IM_FPARAM) + { + ins->mCode = IC_JUMP; + ins->mSrc[0].mTemp = -1; + ins->mNumOperands = 0; + } + } + else if (tins->mConst.mType == IT_FLOAT) + { + if (tins->mConst.mFloatConst) + ins->mCode = IC_JUMP; + else + ins->mCode = IC_JUMPF; + ins->mSrc[0].mTemp = -1; + ins->mNumOperands = 0; + } } break; case IC_PUSH_FRAME: @@ -4214,6 +4262,16 @@ void InterInstruction::Disassemble(FILE* file) else fprintf(file, "COPY%c%c", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory]); break; + + case IC_MALLOC: + assert(mNumOperands == 1); + fprintf(file, "MALLOC"); + break; + case IC_FREE: + assert(mNumOperands == 1); + fprintf(file, "FREE"); + break; + case IC_STRCPY: fprintf(file, "STRCPY%c%c", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory]); break; @@ -7696,7 +7754,7 @@ bool InterCodeBasicBlock::CalculateSingleAssignmentTemps(FastNumberSet& tassigne bool valid = j == ins->mNumOperands; if (valid) { - if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE || ins->mCode == IC_ASSEMBLER) + if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE || ins->mCode == IC_ASSEMBLER || ins->mCode == IC_MALLOC || ins->mCode == IC_FREE) valid = false; else if (ins->mCode == IC_LOAD) { @@ -16035,7 +16093,7 @@ void InterCodeProcedure::Close(void) { GrowingTypeArray tstack(IT_NONE); - CheckFunc = !strcmp(mIdent->mString, "test"); + CheckFunc = !strcmp(mIdent->mString, "main"); mEntryBlock = mBlocks[0]; diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index 0c7f5fd..8d45c16 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -24,6 +24,8 @@ enum InterCode IC_LEA, IC_COPY, IC_STRCPY, + IC_MALLOC, + IC_FREE, IC_TYPECAST, IC_CONSTANT, IC_BRANCH, diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index 4de30c7..6f34fd8 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -2429,6 +2429,30 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } mErrors->Error(exp->mLocation, ERRR_CANNOT_FIND_BANK_OF_EXPRESSION, "Cannot find bank of expressiohn"); } break; + + case TK_NEW: + { + ins->mCode = IC_MALLOC; + ins->mSrc[0].mType = InterTypeOf(vl.mType); + ins->mSrc[0].mTemp = vl.mTemp; + ins->mDst.mType = IT_POINTER; + ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); + block->Append(ins); + return ExValue(exp->mDecType, ins->mDst.mTemp, 0); + + } break; + + case TK_DELETE: + { + vl = Dereference(proc, exp, block, vl, 0); + + ins->mCode = IC_FREE; + ins->mSrc[0].mType = IT_POINTER; + ins->mSrc[0].mTemp = vl.mTemp; + block->Append(ins); + return ExValue(TheConstVoidTypeDeclaration, -1); + + } break; } ins->mSrc[0].mType = InterTypeOf(vl.mType); @@ -2611,6 +2635,42 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* return ExValue(TheFloatTypeDeclaration, ins->mDst.mTemp); } + else if (!strcmp(iname->mString, "malloc")) + { + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); + vr = Dereference(proc, exp, block, vr); + + if (decf->mBase->mParams->CanAssign(vr.mType)) + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); + vr = CoerceType(proc, exp, block, vr, decf->mBase->mParams); + + InterInstruction* ins = new InterInstruction(exp->mLocation, IC_MALLOC); + ins->mSrc[0].mType = IT_INT16; + ins->mSrc[0].mTemp = vr.mTemp; + ins->mNumOperands = 1; + ins->mDst.mType = IT_POINTER; + ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); + block->Append(ins); + + return ExValue(TheVoidPointerTypeDeclaration, ins->mDst.mTemp); + } + else if (!strcmp(iname->mString, "free")) + { + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); + vr = Dereference(proc, exp, block, vr); + + if (decf->mBase->mParams->CanAssign(vr.mType)) + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); + vr = CoerceType(proc, exp, block, vr, decf->mBase->mParams); + + InterInstruction* ins = new InterInstruction(exp->mLocation, IC_FREE); + ins->mSrc[0].mType = IT_POINTER; + ins->mSrc[0].mTemp = vr.mTemp; + ins->mNumOperands = 1; + block->Append(ins); + + return ExValue(TheVoidTypeDeclaration, 0); + } else if (!strcmp(iname->mString, "strcpy")) { if (exp->mRight->mType == EX_LIST) diff --git a/oscar64/Linker.cpp b/oscar64/Linker.cpp index fdf3317..c2a23cf 100644 --- a/oscar64/Linker.cpp +++ b/oscar64/Linker.cpp @@ -489,8 +489,8 @@ void Linker::Link(void) if (lsec->mType == LST_HEAP) { - lsec->mStart = lrgn->mStart + lrgn->mUsed; - lsec->mEnd = lrgn->mEnd; + lsec->mStart = (lrgn->mStart + lrgn->mUsed + 3) & ~3; + lsec->mEnd = lrgn->mEnd & ~3; if (lsec->mStart + lsec->mSize > lsec->mEnd) { diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index 166976a..1550a92 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -7346,6 +7346,54 @@ NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc, } } +void NativeCodeBasicBlock::CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc) +{ + if (ins->mSrc[0].mTemp < 0) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + } + else + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + } + + NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("malloc"))); + mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); + + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); +} + +void NativeCodeBasicBlock::CallFree(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc) +{ + if (ins->mSrc[0].mTemp < 0) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + } + else + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + } + + NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("free"))); + mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); +} + + NativeCodeBasicBlock* NativeCodeBasicBlock::StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc) { int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]; @@ -17338,10 +17386,13 @@ bool NativeCodeBasicBlock::CombineZPPair(int at, int r0, int r1, bool use0, bool } } } - else if (ins.ChangesZeroPage(r0)) - valid0 = false; - else if (ins.ChangesZeroPage(r1)) - valid1 = false; + else + { + if (ins.ChangesZeroPage(r0)) + valid0 = false; + if (ins.ChangesZeroPage(r1)) + valid1 = false; + } i++; } @@ -40093,7 +40144,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) { mInterProc = proc; - CheckFunc = !strcmp(mInterProc->mIdent->mString, "strlen"); + CheckFunc = !strcmp(mInterProc->mIdent->mString, "heapcheck"); int nblocks = proc->mBlocks.Size(); tblocks = new NativeCodeBasicBlock * [nblocks]; @@ -40881,7 +40932,7 @@ void NativeCodeProcedure::Optimize(void) } #endif - if (step == 5) + if (step == 5 && cnt < 10) { ResetVisited(); if (mEntryBlock->RemoveDoubleZPStore()) @@ -41703,6 +41754,14 @@ void NativeCodeProcedure::CompileInterBlock(InterCodeProcedure* iproc, InterCode case IC_STRCPY: block = block->StrcpyValue(iproc, ins, this); break; + + case IC_MALLOC: + block->CallMalloc(iproc, ins, this); + break; + case IC_FREE: + block->CallFree(iproc, ins, this); + break; + case IC_LOAD_TEMPORARY: { if (ins->mSrc[0].mTemp != ins->mDst.mTemp) diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 97e44bb..3cf5e56 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -336,6 +336,9 @@ public: NativeCodeBasicBlock * StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc); void AddAsrSignedByte(InterCodeProcedure* proc, const InterInstruction* ains, const InterInstruction* sins); + void CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc); + void CallFree(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc); + void LoadByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins); void StoreByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins); diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index 5f08de3..9fcdab6 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -4470,7 +4470,7 @@ Expression* Parser::ParsePrefixExpression(bool lhs) { if (mScanner->mToken == TK_SUB || mScanner->mToken == TK_BINARY_NOT || mScanner->mToken == TK_LOGICAL_NOT || mScanner->mToken == TK_MUL || mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC || mScanner->mToken == TK_BINARY_AND || - mScanner->mToken == TK_BANKOF) + mScanner->mToken == TK_BANKOF || mScanner->mToken == TK_NEW || mScanner->mToken == TK_DELETE) { Expression* nexp; if (mScanner->mToken == TK_LOGICAL_NOT) @@ -4487,6 +4487,127 @@ Expression* Parser::ParsePrefixExpression(bool lhs) nexp->mLeft = ParsePrefixExpression(false);; nexp->mDecType = nexp->mLeft->mDecType; } + else if (mScanner->mToken == TK_NEW) + { + nexp = new Expression(mScanner->mLocation, EX_PREFIX); + nexp->mToken = TK_NEW; + mScanner->NextToken(); + Declaration * dec = ParseBaseTypeDeclaration(0); + + Declaration* sconst = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); + sconst->mBase = TheUnsignedIntTypeDeclaration; + sconst->mInteger = dec->mSize; + + Expression* sexp = new Expression(mScanner->mLocation, EX_CONSTANT); + sexp->mDecValue = sconst; + sexp->mDecType = TheUnsignedIntTypeDeclaration; + + nexp->mLeft = sexp; + nexp->mDecType = dec->BuildPointer(mScanner->mLocation); + + if (mScanner->mToken == TK_OPEN_PARENTHESIS || dec->mDefaultConstructor) + { + Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE); + vdec->mVarIndex = mLocalIndex++; + vdec->mBase = nexp->mDecType; + vdec->mSize = 2; + + Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE); + vexp->mDecType = vdec->mBase; + vexp->mDecValue = vdec; + + Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION); + iexp->mToken = TK_ASSIGN; + iexp->mLeft = vexp; + iexp->mRight = nexp; + iexp->mDecType = nexp->mDecType; + + Declaration* mdec = dec->mDefaultConstructor; + Expression* pexp = iexp; + + if (ConsumeTokenIf(TK_OPEN_PARENTHESIS)) + { + if (!ConsumeTokenIf(TK_CLOSE_PARENTHESIS)) + { + pexp = ParseListExpression(); + + mdec = dec->mScope->Lookup(dec->mIdent); + + ConsumeToken(TK_CLOSE_PARENTHESIS); + + Expression* lexp = new Expression(mScanner->mLocation, EX_LIST); + lexp->mLeft = iexp; + lexp->mRight = pexp; + pexp = lexp; + } + } + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = mdec; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = pexp; + + ResolveOverloadCall(cexp, pexp); + + Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + + sexp->mLeft = dexp; + sexp->mRight = vexp; + + nexp = sexp; + } + } + else if (mScanner->mToken == TK_DELETE) + { + nexp = new Expression(mScanner->mLocation, EX_PREFIX); + nexp->mToken = TK_DELETE; + mScanner->NextToken(); + nexp->mLeft = ParsePrefixExpression(false); + nexp->mDecType = TheVoidTypeDeclaration; + if (nexp->mLeft->mDecType->mType == DT_TYPE_POINTER) + { + Declaration* dec = nexp->mLeft->mDecType->mBase; + if (dec->mDestructor) + { + Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE); + vdec->mVarIndex = mLocalIndex++; + vdec->mBase = nexp->mLeft->mDecType; + vdec->mSize = 2; + + Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE); + vexp->mDecType = vdec->mBase; + vexp->mDecValue = vdec; + + Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION); + iexp->mToken = TK_ASSIGN; + iexp->mLeft = vexp; + iexp->mRight = nexp->mLeft; + iexp->mDecType = nexp->mLeft->mDecType; + + Declaration* mdec = dec->mDestructor; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = mdec; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = iexp; + + Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + + sexp->mLeft = dexp; + sexp->mRight = nexp; + + nexp->mLeft = iexp; + + nexp = sexp; + } + } + } else { nexp = new Expression(mScanner->mLocation, EX_PREFIX); diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp index 1a5e293..c68fcba 100644 --- a/oscar64/Scanner.cpp +++ b/oscar64/Scanner.cpp @@ -158,6 +158,8 @@ const char* TokenNames[] = "'public'", "'protected'", "'private'", + "'new'", + "'delete'", }; @@ -1406,6 +1408,10 @@ void Scanner::NextRawToken(void) mToken = TK_PROTECTED; else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "private")) mToken = TK_PRIVATE; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "new")) + mToken = TK_NEW; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "delete")) + mToken = TK_DELETE; else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "operator")) { NextRawToken(); diff --git a/oscar64/Scanner.h b/oscar64/Scanner.h index a7474a3..580c5ee 100644 --- a/oscar64/Scanner.h +++ b/oscar64/Scanner.h @@ -157,6 +157,8 @@ enum Token TK_PUBLIC, TK_PROTECTED, TK_PRIVATE, + TK_NEW, + TK_DELETE, NUM_TOKENS };