FMOD_RESULT F_CALLBACK FMOD_FILE_OPENCALLBACK_BRIDGE(const char * name, int unicode, unsigned int * filesize, void ** handle, void ** userdata) { JNIEnv *java_env/* = 0*/; bool attached = acquire_jenv(&java_env); jstring jname = 0; if(name) { jname = java_env->NewStringUTF((const char *)name); } jobject jfilesize = 0; if(filesize) { jfilesize = java_env->NewDirectByteBuffer((int *)filesize, 4); } jobject jhandle = newPointer(java_env); jobject juserdata = newPointer(java_env); jint result_ = java_env->CallStaticIntMethod(caller, callbackId[22], jname, (jint)unicode, jfilesize, jhandle, juserdata); if(jhandle) { POINTER_TYPE jhandleAddress = getPointerAddress(java_env, jhandle); if(jhandleAddress) { *handle = N2J_CAST_PTR(jhandleAddress, void *); } } if(juserdata) { POINTER_TYPE juserdataAddress = getPointerAddress(java_env, juserdata); if(juserdataAddress) { *userdata = N2J_CAST_PTR(juserdataAddress, void *); } } leave_jenv(attached); return (FMOD_RESULT)result_; }
void SmalltalkVM::doSendBinary(TVMExecutionContext& ec) { // Loading the operand objects TObject* rightObject = ec.stackPop(); TObject* leftObject = ec.stackPop(); // If operands are both small integers, we may handle it ourselves if (isSmallInteger(leftObject) && isSmallInteger(rightObject)) { // Loading actual operand values int32_t rightOperand = TInteger(rightObject); int32_t leftOperand = TInteger(leftObject); bool unusedCondition; // Performing an operation switch ( static_cast<binaryBuiltIns::Operator>(ec.instruction.getArgument()) ) { case binaryBuiltIns::operatorLess: ec.returnedValue = (leftOperand < rightOperand) ? globals.trueObject : globals.falseObject; break; case binaryBuiltIns::operatorLessOrEq: ec.returnedValue = (leftOperand <= rightOperand) ? globals.trueObject : globals.falseObject; break; case binaryBuiltIns::operatorPlus: ec.returnedValue = callSmallIntPrimitive(primitive::smallIntAdd, leftOperand, rightOperand, unusedCondition); break; default: std::fprintf(stderr, "VM: Invalid opcode %d passed to sendBinary\n", ec.instruction.getArgument()); std::exit(1); } ec.stackPush( ec.returnedValue ); m_messagesSent++; } else { // This binary operator is performed on an ordinary object. // We do not know how to handle it, thus send the message to the receiver // Protecting pointers in case if GC occurs hptr<TObject> pRightObject = newPointer(rightObject); hptr<TObject> pLeftObject = newPointer(leftObject); hptr<TObjectArray> messageArguments = newObject<TObjectArray>(2/*, false*/); messageArguments[1] = pRightObject; messageArguments[0] = pLeftObject; TSymbol* messageSelector = static_cast<TSymbol*>( globals.binaryMessages[ec.instruction.getArgument()] ); doSendMessage(ec, messageSelector, messageArguments); } }
TByteObject* SmalltalkVM::newBinaryObject(TClass* klass, std::size_t dataSize) { // Class may be moved during GC in allocation, // so we need to protect the pointer hptr<TClass> pClass = newPointer(klass); // All binary objects are descendants of ByteObject // They could not have ordinary fields, so we may use it uint32_t slotSize = sizeof(TByteObject) + dataSize; void* objectSlot = m_memoryManager->allocate(correctPadding(slotSize), &m_lastGCOccured); if (!objectSlot) { std::fprintf(stderr, "VM: memory manager failed to allocate %d bytes\n", slotSize); return static_cast<TByteObject*>(globals.nilObject); } // VM need to perform some actions if collection was occured. // First of all we need to invalidate the method cache if (m_lastGCOccured) onCollectionOccured(); TByteObject* instance = new (objectSlot) TByteObject(dataSize, pClass); return instance; }
TObject* SmalltalkVM::newOrdinaryObject(TClass* klass, std::size_t slotSize) { // Class may be moved during GC in allocation, // so we need to protect the pointer hptr<TClass> pClass = newPointer(klass); void* objectSlot = m_memoryManager->allocate(correctPadding(slotSize), &m_lastGCOccured); if (!objectSlot) { std::fprintf(stderr, "VM: memory manager failed to allocate %u bytes\n", slotSize); return globals.nilObject; } // VM need to perform some actions if collection was occured. // First of all we need to invalidate the method cache if (m_lastGCOccured) onCollectionOccured(); // Object size stored in the TSize field of any ordinary object contains // number of pointers except for the first two fields std::size_t fieldsCount = slotSize / sizeof(TObject*) - 2; TObject* instance = new (objectSlot) TObject(fieldsCount, pClass); for (uint32_t index = 0; index < fieldsCount; index++) instance->putField(index, globals.nilObject); return instance; }
int readRuleSetFromLocalFile( const char *ruleBaseName, const char *rulesFileName, RuleSet *ruleSet, Env *funcDesc, int *errloc, rError_t *errmsg, Region *r ) { FILE *file; char errbuf[ERR_MSG_LEN]; file = fopen( rulesFileName, "r" ); if ( file == NULL ) { snprintf( errbuf, ERR_MSG_LEN, "readRuleSetFromFile() could not open rules file %s\n", rulesFileName ); addRErrorMsg( errmsg, RULES_FILE_READ_ERROR, errbuf ); return RULES_FILE_READ_ERROR; } Pointer *e = newPointer( file, ruleBaseName ); int ret = parseRuleSet( e, ruleSet, funcDesc, errloc, errmsg, r ); deletePointer( e ); if ( ret < 0 ) { return ret; } Node *errnode{}; ExprType *restype = typeRuleSet( ruleSet, errmsg, &errnode, r ); if ( getNodeType( restype ) == T_ERROR ) { if ( NULL != errnode ) { *errloc = NODE_EXPR_POS( errnode ); } return RE_TYPE_ERROR; } return 0; }
InternalVariantProperty::Pointer InternalVariantProperty::create(const PropertyName &name, const InternalNodePointer &propertyOwner) { InternalVariantProperty *newPointer(new InternalVariantProperty(name, propertyOwner)); InternalVariantProperty::Pointer smartPointer(newPointer); newPointer->setInternalWeakPointer(smartPointer); return smartPointer; }
InternalBindingProperty::Pointer InternalBindingProperty::create(const QString &name, const InternalNodePointer &propertyOwner) { InternalBindingProperty *newPointer(new InternalBindingProperty(name, propertyOwner)); InternalBindingProperty::Pointer smartPointer(newPointer); newPointer->setInternalWeakPointer(smartPointer); return smartPointer; }
static void como_compile_ast(ast_node *p, const char *filename) { Object *main_code = newArray(4); global_frame = create_frame(main_code); global_frame->filename = newString(filename); mapInsertEx(global_frame->cf_symtab, "__FUNCTION__", newString("__main__")); (void)como_compile(p, global_frame); arrayPushEx(main_code, newPointer((void *)create_op(HALT, NULL))); (void)como_execute(global_frame, NULL); }
void SmalltalkVM::setupVarsForDoesNotUnderstand(hptr<TMethod>& method, hptr<TObjectArray>& arguments, TSymbol* selector, TClass* receiverClass) { // Looking up the #doesNotUnderstand: method: method = newPointer(lookupMethod(globals.badMethodSymbol, receiverClass)); if (method == 0) { // Something goes really wrong. // We could not continue the execution std::fprintf(stderr, "Could not locate #doesNotUnderstand:\n"); //exit(1); } // Protecting the selector pointer because it may be invalidated later hptr<TSymbol> failedSelector = newPointer(selector); // We're replacing the original call arguments with custom one hptr<TObjectArray> errorArguments = newObject<TObjectArray>(2); // Filling in the failed call context information errorArguments[0] = arguments[0]; // receiver object errorArguments[1] = failedSelector; // message selector that failed // Replacing the arguments with newly created one arguments = errorArguments; }
TObject* SmalltalkVM::performPrimitive(uint8_t opcode, hptr<TProcess>& process, TVMExecutionContext& ec, bool& failed) { switch (opcode) { // FIXME opcodes 253-255 are not standard case 255: // Debug trap std::printf("Debug trap\n"); break; case 254: m_memoryManager->collectGarbage(); break; #if defined(LLVM) case primitive::LLVMsendMessage: { //252 TObjectArray* args = ec.stackPop<TObjectArray>(); TSymbol* selector = ec.stackPop<TSymbol>(); try { return sendMessage(ec.currentContext, selector, args, 0); } catch(TBlockReturn& blockReturn) { //When we catch blockReturn we change the current context to block.creatingContext. //The post processing code will change 'block.creatingContext' to the previous one // and the result of blockReturn will be injected on the stack ec.currentContext = blockReturn.targetContext; return blockReturn.value; } catch(TContext* errorContext) { //context is thrown by LLVM:throwError primitive //that means that it was not caught by LLVM:executeProcess function //so we have to stop execution of the current process and return returnError process->context = errorContext; failed = true; return globals.nilObject; } } break; case 247: { // Jit once: aBlock try { TBlock* const block = ec.stackPop<TBlock>(); return JITRuntime::Instance()->invokeBlock(block, ec.currentContext, true); } catch(TBlockReturn& blockReturn) { ec.currentContext = blockReturn.targetContext; return blockReturn.value; } catch(TContext* errorContext) { process->context = errorContext; failed = true; return globals.nilObject; } } #endif case 251: { // TODO Unicode support TString* prompt = ec.stackPop<TString>(); std::string strPrompt(reinterpret_cast<const char*>(prompt->getBytes()), prompt->getSize()); std::string input; bool userInsertedAnything = CompletionEngine::Instance()->readline(strPrompt, input); if ( userInsertedAnything ) { if ( !input.empty() ) CompletionEngine::Instance()->addHistory(input); TString* result = static_cast<TString*>( newBinaryObject(globals.stringClass, input.size()) ); std::memcpy(result->getBytes(), input.c_str(), input.size()); return result; } else return globals.nilObject; } break; #if defined(LLVM) case 250: // patchHotMethods JITRuntime::Instance()->patchHotMethods(); break; case 249: { // printMethod TMethod* method = ec.stackPop<TMethod>(); JITRuntime::Instance()->printMethod(method); } break; case 248: JITRuntime::Instance()->printStat(); break; #endif case primitive::startNewProcess: { // 6 TInteger ticks = ec.stackPop(); TProcess* newProcess = ec.stackPop<TProcess>(); // FIXME possible stack overflow due to recursive call TExecuteResult result = this->execute(newProcess, ticks); return TInteger(result); } break; case primitive::allocateObject: { // 7 // Taking object's size and class from the stack TObject* size = ec.stackPop(); TClass* klass = ec.stackPop<TClass>(); uint32_t fieldsCount = TInteger(size); // Instantinating the object. Each object has size and class fields return newOrdinaryObject(klass, sizeof(TObject) + fieldsCount * sizeof(TObject*)); } break; case primitive::blockInvoke: { // 8 TBlock* block = ec.stackPop<TBlock>(); uint32_t argumentLocation = block->argumentLocation; // Amount of arguments stored on the stack except the block itself uint32_t argCount = ec.instruction.getArgument() - 1; // Checking the passed temps size TObjectArray* blockTemps = block->temporaries; if (argCount > (blockTemps ? blockTemps->getSize() - argumentLocation : 0) ) { ec.stackTop -= (argCount + 1); // unrolling stack failed = true; break; } // Loading temporaries array for (uint32_t index = argCount - 1, count = argCount; count > 0; index--, count--) (*blockTemps)[argumentLocation + index] = ec.stackPop(); // Switching execution context to the invoking block block->previousContext = ec.currentContext->previousContext; ec.currentContext = static_cast<TContext*>(block); ec.stackTop = 0; // resetting stack // Block is bound to the method's bytecodes, so it's // first bytecode will not be zero but the value specified ec.bytePointer = block->blockBytePointer; return block; } break; case primitive::throwError: // 19 process->context = ec.currentContext; process->result = ec.returnedValue; break; case primitive::allocateByteArray: { // 20 TInteger dataSize = ec.stackPop(); TClass* klass = ec.stackPop<TClass>(); return newBinaryObject(klass, dataSize); } break; case primitive::arrayAt: // 24 case primitive::arrayAtPut: { // 5 TObject* indexObject = ec.stackPop(); TObjectArray* array = ec.stackPop<TObjectArray>(); TObject* valueObject = 0; // If the method is Array:at:put then pop a value from the stack if (opcode == primitive::arrayAtPut) valueObject = ec.stackPop(); if (! isSmallInteger(indexObject) ) { failed = true; break; } // Smalltalk indexes arrays starting from 1, not from 0 // So we need to recalculate the actual array index before uint32_t actualIndex = TInteger(indexObject) - 1; // Checking boundaries if (actualIndex >= array->getSize()) { failed = true; break; } if (opcode == primitive::arrayAt) { return array->getField(actualIndex); } else { // Array:at:put TObject** objectSlot = &( array->getFields()[actualIndex] ); // Checking whether we need to register current object slot in the GC checkRoot(valueObject, objectSlot); // Storing the value into the array array->putField(actualIndex, valueObject); // Return self return static_cast<TObject*>(array); } } break; case primitive::cloneByteObject: { // 23 TClass* klass = ec.stackPop<TClass>(); hptr<TByteObject> original = newPointer( ec.stackPop<TByteObject>() ); // Creating clone uint32_t dataSize = original->getSize(); TByteObject* clone = newBinaryObject(klass, dataSize); // Cloning data std::memcpy(clone->getBytes(), original->getBytes(), dataSize); return static_cast<TObject*>(clone); } break; // case primitive::integerDiv: // Integer / // case primitive::integerMod: // Integer % // case primitive::integerAdd: // Integer + // case primitive::integerMul: // Integer * // case primitive::integerSub: // Integer - // case primitive::integerLess: // Integer < // case primitive::integerEqual: // Integer == // //TODO integer operations // break; case primitive::integerNew: { // 32 TObject* object = ec.stackPop(); if (! isSmallInteger(object)) { failed = true; break; } return object; // FIXME long integer } break; case primitive::flushCache: // 34 flushMethodCache(); break; case primitive::bulkReplace: { // 38 //Implementation of replaceFrom:to:with:startingAt: as a primitive // Array replaceFrom: start to: stop with: replacement startingAt: repStart // <38 start stop replacement repStart self>. // Current stack contents (top is the top) // self // repStart // replacement // stop // start TObject* destination = ec.stackPop(); TObject* sourceStartOffset = ec.stackPop(); TObject* source = ec.stackPop(); TObject* destinationStopOffset = ec.stackPop(); TObject* destinationStartOffset = ec.stackPop(); bool isSucceeded = doBulkReplace( destination, destinationStartOffset, destinationStopOffset, source, sourceStartOffset ); if (! isSucceeded) { failed = true; break; } return destination; } break; // TODO cases 33, 35, 40 // TODO case 18 // turn on debugging case primitive::objectsAreEqual: // 1 case primitive::getClass: // 2 case primitive::getSize: // 4 case primitive::ioGetChar: // 9 case primitive::ioPutChar: // 3 case primitive::ioFileOpen: // 100 case primitive::ioFileClose: // 103 case primitive::ioFileSetStatIntoArray: // 105 case primitive::ioFileReadIntoByteArray: // 106 case primitive::ioFileWriteFromByteArray: // 107 case primitive::ioFileSeek: // 108 case primitive::stringAt: // 21 case primitive::stringAtPut: // 22 case primitive::smallIntAdd: // 10 case primitive::smallIntDiv: // 11 case primitive::smallIntMod: // 12 case primitive::smallIntLess: // 13 case primitive::smallIntEqual: // 14 case primitive::smallIntMul: // 15 case primitive::smallIntSub: // 16 case primitive::smallIntBitOr: // 36 case primitive::smallIntBitAnd: // 37 case primitive::smallIntBitShift: // 39 case primitive::getSystemTicks: //253 default: { uint32_t argCount = ec.instruction.getArgument(); hptr<TObjectArray> args = newObject<TObjectArray>(argCount); uint32_t i = argCount; while (i > 0) args[--i] = ec.stackPop(); TObject* result = callPrimitive(opcode, args, failed); return result; } } return globals.nilObject; }
void SmalltalkVM::doSendMessage(TVMExecutionContext& ec, TSymbol* selector, TObjectArray* arguments, TClass* receiverClass /*= 0*/ ) { hptr<TObjectArray> messageArguments = newPointer(arguments); if (!receiverClass) { TObject* receiver = messageArguments[0]; assert(receiver != 0); receiverClass = isSmallInteger(receiver) ? globals.smallIntClass : receiver->getClass(); assert(receiverClass != 0); } hptr<TMethod> receiverMethod = newPointer(lookupMethod(selector, receiverClass)); // Checking whether we found a method if (receiverMethod == 0) { // Oops. Method was not found. In this case we should send #doesNotUnderstand: message to the receiver setupVarsForDoesNotUnderstand(receiverMethod, messageArguments, selector, receiverClass); // Continuing the execution just as if #doesNotUnderstand: was the actual selector that we wanted to call } // Save stack and opcode pointers ec.storePointers(); // Create a new context for the giving method and arguments hptr<TContext> newContext = newObject<TContext>(); hptr<TObjectArray> newStack = newObject<TObjectArray>(receiverMethod->stackSize); hptr<TObjectArray> newTemps = newObject<TObjectArray>(receiverMethod->temporarySize); newContext->stack = newStack; newContext->temporaries = newTemps; newContext->arguments = messageArguments; newContext->method = receiverMethod; newContext->stackTop = 0; newContext->bytePointer = 0; // Suppose that current send message operation is last operation in the current context. // If it is true then next instruction will be either stackReturn or blockReturn. // // VM will switch to the newContext, perform it and then switch back to the current context // for the single one return instruction. This is pretty dumb to load the whole context // just to exit it immediately. Therefore, we looking one instruction ahead to see if it is // a return instruction. If it is, we may skip our context and set our previousContext as // previousContext for the newContext. In case of blockReturn it will be the previousContext // of the wrapping method context. uint8_t nextInstruction = ec.currentContext->method->byteCodes->getByte(ec.bytePointer); if (nextInstruction == (opcode::doSpecial * 16 + special::stackReturn)) { // Optimizing stack return newContext->previousContext = ec.currentContext->previousContext; } else if (nextInstruction == (opcode::doSpecial * 16 + special::blockReturn) && (ec.currentContext->getClass() == globals.blockClass)) { // Optimizing block return newContext->previousContext = ec.currentContext.cast<TBlock>()->creatingContext->previousContext; } else { newContext->previousContext = ec.currentContext; } // Replace current context with the new one. On the next iteration, // VM will start interpreting instructions from the new context. ec.currentContext = newContext; ec.loadPointers(); m_messagesSent++; }
SmalltalkVM::TExecuteResult SmalltalkVM::execute(TProcess* p, uint32_t ticks) { // Protecting the process pointer hptr<TProcess> currentProcess = newPointer(p); assert(currentProcess->context != 0); assert(currentProcess->context->method != 0); // Initializing an execution context TVMExecutionContext ec(m_memoryManager, this); ec.currentContext = currentProcess->context; ec.loadPointers(); // Loads bytePointer & stackTop while (true) { assert(ec.currentContext != 0); assert(ec.currentContext->method != 0); assert(ec.currentContext->stack != 0); assert(ec.bytePointer <= ec.currentContext->method->byteCodes->getSize()); assert(ec.currentContext->arguments->getSize() >= 1); assert(ec.currentContext->arguments->getField(0) != 0); // Initializing helper references TByteObject& byteCodes = * ec.currentContext->method->byteCodes; TObjectArray& temporaries = * ec.currentContext->temporaries; TObjectArray& arguments = * ec.currentContext->arguments; TObjectArray& instanceVariables = * arguments.getField<TObjectArray>(0); TSymbolArray& literals = * ec.currentContext->method->literals; if (ticks && (--ticks == 0)) { // Time frame expired ec.storePointers(); currentProcess->context = ec.currentContext; currentProcess->result = ec.returnedValue; return returnTimeExpired; } // Decoding the instruction const uint16_t lastBytePointer = ec.bytePointer; ec.instruction = st::InstructionDecoder::decodeAndShiftPointer(byteCodes, ec.bytePointer); // And executing it switch (ec.instruction.getOpcode()) { case opcode::pushInstance: ec.stackPush(instanceVariables[ec.instruction.getArgument()]); break; case opcode::pushArgument: ec.stackPush(arguments[ec.instruction.getArgument()]); break; case opcode::pushTemporary: ec.stackPush(temporaries[ec.instruction.getArgument()]); break; case opcode::pushLiteral: ec.stackPush(literals[ec.instruction.getArgument()]); break; case opcode::pushConstant: doPushConstant(ec); break; case opcode::pushBlock: doPushBlock(ec); break; case opcode::assignTemporary: temporaries[ec.instruction.getArgument()] = ec.stackLast(); break; case opcode::assignInstance: { TObject* newValue = ec.stackLast(); TObject** objectSlot = & instanceVariables[ec.instruction.getArgument()]; // Checking whether we need to register current object slot in the GC checkRoot(newValue, objectSlot); // Performing the assignment *objectSlot = newValue; } break; case opcode::markArguments: doMarkArguments(ec); break; case opcode::sendMessage: doSendMessage(ec); break; case opcode::sendUnary: doSendUnary(ec); break; case opcode::sendBinary: doSendBinary(ec); break; case opcode::doPrimitive: { TExecuteResult result = doPrimitive(currentProcess, ec); if (result != returnNoReturn) return result; } break; case opcode::doSpecial: { TExecuteResult result = doSpecial(currentProcess, ec); if (result != returnNoReturn) return result; } break; default: std::fprintf(stderr, "VM: Invalid opcode %d at offset %d in method ", ec.instruction.getOpcode(), lastBytePointer); std::fprintf(stderr, "'%s'\n", ec.currentContext->method->name->toString().c_str() ); std::exit(1); } } }
static void como_compile(ast_node* p, ComoFrame *frame) { assert(p); switch(p->type) { default: printf("%s(): invalid node type(%d)\n", __func__, p->type); exit(1); break; case AST_NODE_TYPE_STRING: arrayPushEx(frame->code, newPointer((void *)create_op(LOAD_CONST, newString(p->u1.string_value.value)))); break; case AST_NODE_TYPE_PRINT: como_compile(p->u1.print_node.expr, frame); arrayPushEx(frame->code, newPointer((void *)create_op(IPRINT, NULL))); break; case AST_NODE_TYPE_NUMBER: arrayPushEx(frame->code, newPointer((void *)create_op(LOAD_CONST, newLong((long)p->u1.number_value)))); break; case AST_NODE_TYPE_ID: arrayPushEx(frame->code, newPointer((void *)create_op(LOAD_NAME, newString(p->u1.string_value.value)))); break; case AST_NODE_TYPE_RET: if(p->u1.return_node.expr != NULL) { como_compile(p->u1.return_node.expr, frame); arrayPushEx(frame->code, newPointer((void *)create_op(IRETURN, newLong(1L)))); } else { arrayPushEx(frame->code, newPointer((void *)create_op(IRETURN, newLong(0L)))); } break; case AST_NODE_TYPE_STATEMENT_LIST: { size_t i; for(i = 0; i < p->u1.statements_node.count; i++) { ast_node* stmt = p->u1.statements_node.statement_list[i]; como_compile(stmt, frame); } } break; case AST_NODE_TYPE_WHILE: { Object *l = newLong((long)(O_AVAL(frame->code)->size)); arrayPushEx(frame->code, newPointer((void *)create_op(LABEL, l))); Object *l2 = newLong(0); como_compile(p->u1.while_node.condition, frame); arrayPushEx(frame->code, newPointer((void *)create_op(JZ, l2))); como_compile(p->u1.while_node.body, frame); arrayPushEx(frame->code, newPointer((void *)create_op(JMP, newLong(O_LVAL(l))))); Object *l3 = newLong((long)(O_AVAL(frame->code)->size)); arrayPushEx(frame->code, newPointer((void *)create_op(LABEL, l3))); O_LVAL(l2) = O_LVAL(l3); } break; case AST_NODE_TYPE_FOR: { Object *l = newLong((long)(O_AVAL(frame->code)->size)); arrayPushEx(frame->code, newPointer((void *)create_op(LABEL, l))); Object *l2 = newLong(0); como_compile(p->u1.for_node.initialization, frame); como_compile(p->u1.for_node.condition, frame); arrayPushEx(frame->code, newPointer((void *)create_op(JZ, l2))); Object *l4 = newLong((long)(O_AVAL(frame->code)->size)); /* label for the body */ arrayPushEx(frame->code, newPointer((void *)create_op(LABEL, l4))); como_compile(p->u1.for_node.body, frame); como_compile(p->u1.for_node.final_expression, frame); como_compile(p->u1.for_node.condition, frame); arrayPushEx(frame->code, newPointer((void *)create_op(JZ, l2))); arrayPushEx(frame->code, newPointer((void *)create_op(JMP, newLong(O_LVAL(l4))))); Object *l3 = newLong((long)(O_AVAL(frame->code)->size)); arrayPushEx(frame->code, newPointer((void *)create_op(LABEL, l3))); O_LVAL(l2) = O_LVAL(l3); } break; case AST_NODE_TYPE_IF: { Object *l2 = newLong(0); Object *l4 = newLong(0); como_compile(p->u1.if_node.condition, frame); arrayPushEx(frame->code, newPointer((void *)create_op(JZ, l2))); como_compile(p->u1.if_node.b1, frame); arrayPushEx(frame->code, newPointer((void *)create_op(JMP, l4))); Object *l3 = newLong((long)(O_AVAL(frame->code)->size)); arrayPushEx(frame->code, newPointer((void *)create_op(LABEL, l3))); if(p->u1.if_node.b2 != NULL) { como_compile(p->u1.if_node.b2, frame); } O_LVAL(l2) = O_LVAL(l3); O_LVAL(l4) = (long)(O_AVAL(frame->code)->size); arrayPushEx(frame->code, newPointer((void *)create_op(LABEL, newLong((long)(O_AVAL(frame->code)->size))))); } break; case AST_NODE_TYPE_FUNC_DECL: { const char *name = p->u1.function_node.name; Object *func_decl = newArray(4); Object *func_decl_parameters = newArray(2); ComoFrame *func_decl_frame = create_frame(func_decl); func_decl_frame->namedparameters = func_decl_parameters; if(frame->filename != NULL) { func_decl_frame->filename = copyObject(frame->filename); } else { func_decl_frame->filename = newString("<unknown>"); } size_t i; ast_node_statements *parameters = &p->u1.function_node .parameter_list->u1 .statements_node; for(i = 0; i < parameters->count; i++) { arrayPushEx(func_decl_parameters, newString( AST_NODE_AS_ID( parameters->statement_list[i] ) ) ); } arrayPushEx(func_decl_frame->code, newPointer((void *)create_op(LOAD_CONST, newString(name)))); arrayPushEx(func_decl_frame->code, newPointer((void *)create_op(STORE_NAME, newString("__FUNCTION__")))); como_compile(p->u1.function_node.body, func_decl_frame); Array *temp = O_AVAL(func_decl_frame->code); Object *temp2 = temp->table[temp->size - 1]; ComoOpCode *opcode = (ComoOpCode *)(O_PTVAL(temp2)); if(opcode->op_code != IRETURN) { //como_debug("automatically inserting IRETURN for function %s", name); arrayPushEx(func_decl_frame->code, newPointer( (void *)create_op(LOAD_CONST, newLong(0L)))); arrayPushEx(func_decl_frame->code, newPointer( (void *)create_op(IRETURN, newLong(1L)))); } mapInsertEx(global_frame->cf_symtab, name, newPointer( (void *)func_decl_frame)); break; } case AST_NODE_TYPE_CALL: { const char *name = p->u1.call_node.id->u1.id_node.name; const long argcount = (long)p->u1 .call_node .arguments->u1 .statements_node .count; como_compile(p->u1.call_node.arguments, frame); arrayPushEx(frame->code, newPointer( (void *)create_op(LOAD_CONST, newLong(argcount)))); arrayPushEx(frame->code, newPointer( (void *)create_op(LOAD_NAME, newString(name)))); arrayPushEx(frame->code, newPointer( (void *)create_op(CALL_FUNCTION, newString(name)))); break; } case AST_NODE_TYPE_POSTFIX: { Object *name = newString(AST_NODE_AS_ID(p->u1.postfix_node.expr)); switch(p->u1.postfix_node.type) { case AST_POSTFIX_OP_INC: arrayPushEx(frame->code, newPointer( (void *)create_op(POSTFIX_INC, name))); break; case AST_POSTFIX_OP_DEC: arrayPushEx(frame->code, newPointer( (void *)create_op(POSTFIX_DEC, name))); break; } break; } case AST_NODE_TYPE_UNARY_OP: { switch(p->u1.unary_node.type) { case AST_UNARY_OP_MINUS: como_compile(p->u1.unary_node.expr, frame); arrayPushEx(frame->code, newPointer( (void *)create_op(UNARY_MINUS, NULL))); break; } } break; case AST_NODE_TYPE_BIN_OP: { if(p->u1.binary_node.type != AST_BINARY_OP_ASSIGN) { como_compile(p->u1.binary_node.left, frame); como_compile(p->u1.binary_node.right, frame); } switch(p->u1.binary_node.type) { case AST_BINARY_OP_REM: arrayPushEx(frame->code, newPointer( (void *)create_op(IREM, NULL))); break; case AST_BINARY_OP_LTE: arrayPushEx(frame->code, newPointer( (void *)create_op(IS_LESS_THAN_OR_EQUAL, NULL))); break; case AST_BINARY_OP_GTE: arrayPushEx(frame->code, newPointer( (void *)create_op(IS_GREATER_THAN_OR_EQUAL, NULL))); break; case AST_BINARY_OP_LT: arrayPushEx(frame->code, newPointer( (void *)create_op(IS_LESS_THAN, NULL))); break; case AST_BINARY_OP_GT: arrayPushEx(frame->code, newPointer( (void *)create_op(IS_GREATER_THAN, NULL))); break; case AST_BINARY_OP_CMP: arrayPushEx(frame->code, newPointer( (void *)create_op(IS_EQUAL, NULL))); break; case AST_BINARY_OP_NEQ: arrayPushEx(frame->code, newPointer( (void *)create_op(IS_NOT_EQUAL, NULL))); break; case AST_BINARY_OP_MINUS: arrayPushEx(frame->code, newPointer( (void *)create_op(IMINUS, NULL))); break; case AST_BINARY_OP_DIV: arrayPushEx(frame->code, newPointer( (void *)create_op(IDIV, NULL))); break; case AST_BINARY_OP_ADD: arrayPushEx(frame->code, newPointer( (void *)create_op(IADD, NULL))); break; case AST_BINARY_OP_TIMES: arrayPushEx(frame->code, newPointer( (void *)create_op(ITIMES, NULL))); break; case AST_BINARY_OP_ASSIGN: como_compile(p->u1.binary_node.right, frame); arrayPushEx(frame->code, newPointer( (void *)create_op(STORE_NAME, newString( p->u1.binary_node.left->u1.id_node.name)))); break; } } break; } }
int processXMsg( int streamId, char *readmsg, RuleEngineEventParam *param, Node *node, Env *env, ruleExecInfo_t *rei ) { char myhdr[HEADER_TYPE_LEN]; char mymsg[MAX_NAME_LEN]; char *outStr = NULL; int i, n; int iLevel, wCnt; int ruleInx = 0; Region *r; Res *res; rError_t errmsg; errmsg.len = 0; errmsg.errMsg = NULL; r = make_region( 0, NULL ); ParserContext *context = newParserContext( &errmsg, r ); Pointer *e = newPointer2( readmsg ); int rulegen = 1; int found; int grdf[2]; int cmd = 0; int smallW; snprintf( myhdr, HEADER_TYPE_LEN - 1, "idbug:%s", param->actionName ); memset( mymsg, 0, sizeof( mymsg ) ); PARSER_BEGIN( DbgCmd ) TRY( DbgCmd ) TTEXT2( "n", "next" ); cmd = REDEBUG_STEP_OVER; OR( DbgCmd ) TTEXT2( "s", "step" ); cmd = REDEBUG_NEXT; OR( DbgCmd ) TTEXT2( "f", "finish" ); cmd = REDEBUG_STEP_OUT; OR( DbgCmd ) TTEXT2( "b", "break" ); TRY( Param ) TTYPE( TK_TEXT ); int breakPointsInx2; for ( breakPointsInx2 = 0; breakPointsInx2 < 100; breakPointsInx2++ ) { if ( breakPoints[breakPointsInx2].actionName == NULL ) { break; } } if ( breakPointsInx2 == 100 ) { _writeXMsg( streamId, myhdr, "Maximum breakpoint count reached. Breakpoint not set.\n" ); cmd = REDEBUG_WAIT; } else { breakPoints[breakPointsInx2].actionName = strdup( token->text ); char * base_ptr = NULL; TRY( loc ) TTYPE( TK_TEXT ); base_ptr = ( char * ) malloc( sizeof( token->text ) + 2 ); base_ptr[0] = 'f'; strcpy( base_ptr + 1, token->text ); TTEXT( ":" ); TTYPE( TK_INT ); breakPoints[breakPointsInx2].base = strdup( base_ptr ); breakPoints[breakPointsInx2].line = atoi( token->text ); rodsLong_t range[2]; char rulesFileName[MAX_NAME_LEN]; getRuleBasePath( base_ptr, rulesFileName ); FILE *file; /* char errbuf[ERR_MSG_LEN]; */ file = fopen( rulesFileName, "r" ); if ( file == NULL ) { free( context ); deletePointer( e ); free( base_ptr ); return RULES_FILE_READ_ERROR; } Pointer *p = newPointer( file, base_ptr ); if ( getLineRange( p, breakPoints[breakPointsInx2].line, range ) == 0 ) { breakPoints[breakPointsInx2].start = range[0]; breakPoints[breakPointsInx2].finish = range[1]; } else { breakPoints[breakPointsInx2].actionName = NULL; } deletePointer( p ); OR( loc ) TTYPE( TK_INT ); if ( node != NULL ) { breakPoints[breakPointsInx2].base = strdup( node->base ); breakPoints[breakPointsInx2].line = atoi( token->text ); rodsLong_t range[2]; Pointer *p = newPointer2( breakPoints[breakPointsInx2].base ); if ( getLineRange( p, breakPoints[breakPointsInx2].line, range ) == 0 ) { breakPoints[breakPointsInx2].start = range[0]; breakPoints[breakPointsInx2].finish = range[1]; } else { breakPoints[breakPointsInx2].actionName = NULL; } deletePointer( p ); } else { breakPoints[breakPointsInx2].actionName = NULL; } OR( loc ) /* breakPoints[breakPointsInx].base = NULL; */ END_TRY( loc ) free( base_ptr ); if ( breakPoints[breakPointsInx2].actionName != NULL ) snprintf( mymsg, MAX_NAME_LEN, "Breakpoint %i set at %s\n", breakPointsInx2, breakPoints[breakPointsInx2].actionName ); else { snprintf( mymsg, MAX_NAME_LEN, "Cannot set breakpoint, source not available\n" ); } _writeXMsg( streamId, myhdr, mymsg ); if ( breakPointsInx <= breakPointsInx2 ) { breakPointsInx = breakPointsInx2 + 1; } cmd = REDEBUG_WAIT; } OR( Param ) NEXT_TOKEN_BASIC; _writeXMsg( streamId, myhdr, "Unknown parameter type.\n" ); cmd = REDEBUG_WAIT; OR( Param ) _writeXMsg( streamId, myhdr, "Debugger command \'break\' requires at least one argument.\n" ); cmd = REDEBUG_WAIT; END_TRY( Param ) OR( DbgCmd ) TRY( Where ) TTEXT2( "w", "where" ); smallW = 1; OR( Where ) TTEXT2( "W", "Where" ); smallW = 0; END_TRY( Where ) wCnt = 20; OPTIONAL_BEGIN( Param ) TTYPE( TK_INT ); wCnt = atoi( token->text ); OPTIONAL_END( Param ) iLevel = 0; i = reDebugStackCurrPtr - 1; while ( i >= 0 && wCnt > 0 ) { if ( !smallW || ( reDebugPCType( ( RuleEngineEvent ) reDebugStackCurr[i].label ) & 1 ) != 0 ) { snprintf( myhdr, HEADER_TYPE_LEN - 1, "idbug: Level %3i", iLevel ); char msg[HEADER_TYPE_LEN - 1]; RuleEngineEventParam param; param.ruleIndex = 0; param.actionName = reDebugStackCurr[i].step; printRuleEngineEventLabel( msg, HEADER_TYPE_LEN - 1, ( RuleEngineEvent ) reDebugStackCurr[i].label, ¶m ); _writeXMsg( streamId, myhdr, msg ); if ( reDebugStackCurr[i].label != EXEC_ACTION_BEGIN ) { iLevel++; } wCnt--; } i--; } OR( DbgCmd ) TTEXT2( "l", "list" ); TRY( Param ) TTEXT2( "r", "rule" ); TRY( ParamParam ) TTYPE( TK_TEXT ); mymsg[0] = '\n'; mymsg[1] = '\0'; snprintf( myhdr, HEADER_TYPE_LEN - 1, "idbug: Listing %s", token->text ); RuleIndexListNode *node; found = 0; while ( findNextRule2( token->text, ruleInx, &node ) != NO_MORE_RULES_ERR ) { found = 1; if ( node->secondaryIndex ) { n = node->condIndex->valIndex->len; int i; for ( i = 0; i < n; i++ ) { Bucket *b = node->condIndex->valIndex->buckets[i]; while ( b != NULL ) { RuleDesc *rd = getRuleDesc( *( int * )b->value ); char buf[MAX_RULE_LEN]; ruleToString( buf, MAX_RULE_LEN, rd ); snprintf( mymsg + strlen( mymsg ), MAX_NAME_LEN - strlen( mymsg ), "%i: %s\n%s\n", node->ruleIndex, rd->node->base[0] == 's' ? "<source>" : rd->node->base + 1, buf ); b = b->next; } } } else { RuleDesc *rd = getRuleDesc( node->ruleIndex ); char buf[MAX_RULE_LEN]; ruleToString( buf, MAX_RULE_LEN, rd ); snprintf( mymsg + strlen( mymsg ), MAX_NAME_LEN - strlen( mymsg ), "\n %i: %s\n%s\n", node->ruleIndex, rd->node->base[0] == 's' ? "<source>" : rd->node->base + 1, buf ); } ruleInx ++; } if ( !found ) { snprintf( mymsg, MAX_NAME_LEN, "Rule %s not found\n", token->text ); } _writeXMsg( streamId, myhdr, mymsg ); cmd = REDEBUG_WAIT; OR( ParamParam ) _writeXMsg( streamId, myhdr, "Debugger command \'list rule\' requires one argument.\n" ); cmd = REDEBUG_WAIT; END_TRY( ParamParam ) OR( Param ) TTEXT2( "b", "breakpoints" ); snprintf( myhdr, HEADER_TYPE_LEN - 1, "idbug: Listing %s", token->text ); mymsg[0] = '\n'; mymsg[1] = '\0'; for ( i = 0; i < breakPointsInx; i++ ) { if ( breakPoints[i].actionName != NULL ) { if ( breakPoints[i].base != NULL ) { snprintf( mymsg + strlen( mymsg ), MAX_NAME_LEN - strlen( mymsg ), "Breaking at BreakPoint %i:%s %s:%d\n", i , breakPoints[i].actionName, breakPoints[i].base[0] == 's' ? "<source>" : breakPoints[i].base + 1, breakPoints[i].line ); } else { snprintf( mymsg + strlen( mymsg ), MAX_NAME_LEN - strlen( mymsg ), "Breaking at BreakPoint %i:%s\n", i , breakPoints[i].actionName ); } } } _writeXMsg( streamId, myhdr, mymsg ); cmd = REDEBUG_WAIT; OR( Param ) TTEXT( "*" ); snprintf( myhdr, HEADER_TYPE_LEN - 1, "idbug: Listing %s", token->text ); Env *cenv = env; mymsg[0] = '\n'; mymsg[1] = '\0'; found = 0; while ( cenv != NULL ) { n = cenv->current->size; for ( i = 0; i < n; i++ ) { Bucket *b = cenv->current->buckets[i]; while ( b != NULL ) { if ( b->key[0] == '*' ) { /* skip none * variables */ found = 1; char typeString[128]; typeToString( ( ( Res * )b->value )->exprType, NULL, typeString, 128 ); snprintf( mymsg + strlen( mymsg ), MAX_NAME_LEN - strlen( mymsg ), "%s of type %s\n", b->key, typeString ); } b = b->next; } } cenv = cenv->previous; } if ( !found ) { snprintf( mymsg + strlen( mymsg ), MAX_NAME_LEN - strlen( mymsg ), "<empty>\n" ); } _writeXMsg( streamId, myhdr, mymsg ); cmd = REDEBUG_WAIT; OR( Param ) syncTokenQueue( e, context ); skipWhitespace( e ); ABORT( lookAhead( e, 0 ) != '$' ); snprintf( myhdr, HEADER_TYPE_LEN - 1, "idbug: Listing %s", token->text ); mymsg[0] = '\n'; mymsg[1] = '\0'; Hashtable *vars = newHashTable( 100 ); for ( i = 0; i < coreRuleVarDef .MaxNumOfDVars; i++ ) { if ( lookupFromHashTable( vars, coreRuleVarDef.varName[i] ) == NULL ) { snprintf( &mymsg[strlen( mymsg )], MAX_NAME_LEN - strlen( mymsg ), "$%s\n", coreRuleVarDef.varName[i] ); insertIntoHashTable( vars, coreRuleVarDef.varName[i], coreRuleVarDef.varName[i] ); } } deleteHashTable( vars, NULL ); _writeXMsg( streamId, myhdr, mymsg ); cmd = REDEBUG_WAIT; OR( Param ) NEXT_TOKEN_BASIC; _writeXMsg( streamId, myhdr, "Unknown parameter type.\n" ); cmd = REDEBUG_WAIT; OR( Param ) _writeXMsg( streamId, myhdr, "Debugger command \'list\' requires at least one argument.\n" ); cmd = REDEBUG_WAIT; END_TRY( Param ) OR( DbgCmd ) TTEXT2( "c", "continue" ); cmd = REDEBUG_STEP_CONTINUE; OR( DbgCmd ) TTEXT2( "C", "Continue" ); cmd = REDEBUG_CONTINUE_VERBOSE; OR( DbgCmd ) TTEXT2( "del", "delete" ); TRY( Param ) TTYPE( TK_INT ); n = atoi( token->text ); if ( breakPoints[n].actionName != NULL ) { free( breakPoints[n].actionName ); if ( breakPoints[n].base != NULL ) { free( breakPoints[n].base ); } breakPoints[n].actionName = NULL; breakPoints[n].base = NULL; snprintf( mymsg, MAX_NAME_LEN, "Breakpoint %i deleted\n", n ); } else { snprintf( mymsg, MAX_NAME_LEN, "Breakpoint %i has not been defined\n", n ); } _writeXMsg( streamId, myhdr, mymsg ); cmd = REDEBUG_WAIT; OR( Param ) _writeXMsg( streamId, myhdr, "Debugger command \'delete\' requires one argument.\n" ); cmd = REDEBUG_WAIT; END_TRY( Param ) OR( DbgCmd ) TTEXT2( "p", "print" ); Node *n = parseTermRuleGen( e, 1, context ); if ( getNodeType( n ) == N_ERROR ) { errMsgToString( context->errmsg, mymsg + strlen( mymsg ), MAX_NAME_LEN - strlen( mymsg ) ); } else { snprintf( myhdr, HEADER_TYPE_LEN - 1, "idbug: Printing " ); char * ptr = myhdr + strlen( myhdr ); i = HEADER_TYPE_LEN - 1 - strlen( myhdr ); termToString( &ptr, &i, 0, MIN_PREC, n, 0 ); snprintf( ptr, i, "\n" ); if ( env != NULL ) { disableReDebugger( grdf ); res = computeNode( n, NULL, regionRegionCpEnv( env, r, ( RegionRegionCopyFuncType * ) regionRegionCpNode ), rei, 0, &errmsg, r ); enableReDebugger( grdf ); outStr = convertResToString( res ); snprintf( mymsg, MAX_NAME_LEN, "%s\n", outStr ); free( outStr ); if ( getNodeType( res ) == N_ERROR ) { errMsgToString( &errmsg, mymsg + strlen( mymsg ), MAX_NAME_LEN - strlen( mymsg ) ); } } else { snprintf( mymsg, MAX_NAME_LEN, "Runtime environment: <empty>\n" ); } } _writeXMsg( streamId, myhdr, mymsg ); cmd = REDEBUG_WAIT; OR( DbgCmd ) TTEXT2( "d", "discontinue" ); cmd = REDEBUG_WAIT; OR( DbgCmd ) snprintf( mymsg, MAX_NAME_LEN, "Unknown Action: %s", readmsg ); _writeXMsg( streamId, myhdr, mymsg ); cmd = REDEBUG_WAIT; END_TRY( DbgCmd ) PARSER_END( DbgCmd ) freeRErrorContent( &errmsg ); region_free( r ); deletePointer( e ); free( context ); return cmd; }