void NodeTree::handleException(NodeID nodeID, const NodeSocketTracer& tracer) { // Exception dispatcher pattern try { _executeListDirty = true; throw; } catch(ExecutionError&) { // Dummy but a must - if not std::exception handler would catch it throw; } catch(BadConnectionException& ex) { if (tracer.isLastOutput()) // Means node tried to acquired socket // with different type than declared in config throw BadConfigException(); ex.node = tracer.lastNode(); ex.socket = tracer.lastSocket(); throw; } catch(cv::Exception& ex) { throw ExecutionError(nodeName(nodeID), nodeTypeName(nodeID), std::string("OpenCV exception - ") + ex.what()); } catch(std::exception& ex) { throw ExecutionError(nodeName(nodeID), nodeTypeName(nodeID), ex.what()); } }
/** * Checks whether the top 2 elements are of type boolean and then performs the OR operation on them. The boolean result replaces the result on the top of the stack. * @return none * @param stack the machine on which the addition is performed (StackMachine*) * @exception ExecutionError */ void Or::execute(StackMachine *stack) { // check if the stack contains at least two entries if(stack->fSP < 1) throw ExecutionError("instruction or: requires 2 stackelements to be present."); StackBoolean p1; if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction or: SP does not point to element of type boolean."); if(typeid(p1) != typeid(*(stack->fStore[stack->fSP - 1]))) throw ExecutionError("instruction or: SP - 1 does not point to element of type boolean."); // actual or-operation stack->fStore[stack->fSP - 1]->ori(stack->fStore[stack->fSP]); // SP := SP - 1 delete stack->fStore[stack->fSP]; stack->fStore[stack->fSP] = 0; stack->fStore.pop_back(); --stack->fSP; // adding cost of this instruction stack->fTime.count("or"); }
/** * Saves the PC at STORE[MP+4] and sets the PC to the right startaddress for the procedure * @return none * @param stack the machine on which the operation is performed (StackMachine*) * @exception ExecutionError */ void Cupi::execute(StackMachine *stack) { /* if(stack->fMP + 4 > stack->fSP) { for(int i = 0; i < stack->fMP + 4 - stack->fSP; ++i) { stack->fStore.push_back(new StackElement()); ++stack->fSP; } } else { delete stack->fStore[stack->fMP + 4]; stack->fStore[stack->fMP + 4] = 0; } */ stack->fStore[stack->fMP + 4] = new StackAddress(stack->fPC); if(stack->base(fP, stack->fStore[stack->fMP + 2]->getValue()) + fQ > stack->fSP) { throw ExecutionError("instruction cupi: trying to access a memorylocation above STORE[SP]"); } stack->fPC = stack->fStore[stack->base(fP, stack->fStore[stack->fMP + 2]->getValue()) + fQ]->getValue(); // adding cost of this instruction stack->fTime.count("cupi"); }
/** * Breaks down the stack and sets all internal variables of the stackmachine back to their previous state * @return none * @param stack the machine on which the addition is performed (StackMachine*) * @exception none */ void Retp::execute(StackMachine *stack) { StackAddress p; if((typeid(p) != typeid(*(stack->fStore[stack->fMP + 2])) || (typeid(p) != typeid(*(stack->fStore[stack->fMP + 3]))) || (typeid(p) != typeid(*(stack->fStore[stack->fMP + 4]))))) { throw ExecutionError("instruction retp: stackframe has been compromised."); } int oldSP = stack->fSP; // proper procedure with no results stack->fSP = stack->fMP - 1; // return branch stack->fPC = stack->fStore[stack->fMP + 4]->getValue(); // restore EP stack->fEP = stack->fStore[stack->fMP + 3]->getValue(); // dynamic link stack->fMP = stack->fStore[stack->fMP + 2]->getValue(); for(int i = oldSP; i > stack->fSP; --i) { delete stack->fStore[i]; stack->fStore.pop_back(); } // adding cost of this instruction stack->fTime.count("retp"); }
Value Interpreter::handleFunction(const SourceLocation &sourceLocation, const Value &value, Stack &stack, Bindings &bindings) { unsigned argc = getArgumentCount(value); if(stack.size() < argc + 1) { throw CompilerBug("Need " + str(argc + 1) + " values on stack to call function, but only have " + str(stack.size())); } Value top = pop(stack); if(!top.isFunction()) { throw ExecutionError(sourceLocation, "Call instruction expects top of the stack to be functional value, but got: " + str(top)); } Arguments arguments; while(argc --> 0) { arguments.push_back(pop(stack)); } const Function &function = top.function(); try { CallContext callContext(&globals_, arguments, this); return function.call(callContext); } catch (RaspError &error) { error.buildStackTrace(" at function: " + function.name(), function.sourceLocation()); throw; } }
/** * Checks the contents of the stack and then performs the addition. * @return none * @param stack the machine on which the addition is performed (StackMachine*) * @exception ExecutionError */ void Add::execute(StackMachine *stack) { // check if the stack contains at least two entries if(stack->fSP < 1) throw ExecutionError("instruction add: requires 2 stackelements to be present."); switch(fType) { case integer: { StackInteger p1; // check if the two uppermost stackentries are of type integer if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction add: SP does not point to element of type integer."); if(typeid(p1) != typeid(*(stack->fStore[stack->fSP - 1]))) throw ExecutionError("instruction add: SP - 1 does not point to element of type integer."); break; } case real: { StackReal p1; // check if the two uppermost stackentries are of type real if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction add: SP does not point to element of type real."); if(typeid(p1) != typeid(*(stack->fStore[stack->fSP - 1]))) throw ExecutionError("instruction add: SP - 1 does not point to element of type real."); break; } default: cerr << "operation not supported for this type" << endl; } // actual addition stack->fStore[stack->fSP - 1]->add(stack->fStore[stack->fSP]); // SP := SP - 1 delete stack->fStore[stack->fSP]; stack->fStore[stack->fSP] = 0; stack->fStore.pop_back(); --stack->fSP; // adding cost of this instruction stack->fTime.count("add"); }
/** * Reads from stdin and creates an appropriate StackElement-derived-class * @return none * @param stack the machine on which the operation is performed (StackMachine*) * @exception none */ void In::execute(StackMachine *stack) { switch(fType) { case integer: { int inputvalue; cin >> inputvalue; stack->fStore.push_back(new StackInteger(inputvalue)); break; } case real: { double inputvalue; cin >> inputvalue; stack->fStore.push_back(new StackReal(inputvalue)); break; } case character: { char inputvalue; cin >> inputvalue; stack->fStore.push_back(new StackCharacter(inputvalue)); break; } case boolean: { bool inputvalue; cin >> inputvalue; stack->fStore.push_back(new StackBoolean(inputvalue)); break; } case address: { throw ExecutionError("instruction in: input of address at runtime is not allowed"); } } // SP := SP + 1 ++stack->fSP; // adding cost of this instruction stack->fTime.count("in"); }
/** * Checks whether the element at STORE[SP] is of the right type and then increments it * @return none * @param stack the machine on which the operation is performed (StackMachine*) * @exception ExecutionError */ void Inc::execute(StackMachine *stack) { // check if the stack contains at least one entry if(stack->fSP < 0) throw ExecutionError("instruction inc: requires 1 stackelement to be present."); switch(fType) { case integer: { StackInteger p1; // check if the uppermost stackentry is of type integer if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction inc: SP does not point to element of type integer."); break; } case real: { StackReal p1; // check if the uppermost stackentry is of type real if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction inc: SP does not point to element of type real."); break; } case boolean: { StackBoolean p1; // check if the uppermost stackentry is of type boolean if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction inc: SP does not point to element of type boolean."); break; } case character: { StackCharacter p1; // check if the uppermost stackentriy is of type character if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction inc: SP does not point to element of type character."); break; } case address: { StackAddress p1; // check if the uppermost stackentry is of type address if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction inc: SP does not point to element of type address."); break; } } // actual increment stack->fStore[stack->fSP]->inc(fP); // adding cost of this instruction stack->fTime.count("inc"); }
/** * Checks whether the indicated type is the same as the loaded type and then loads it. * @return none * @param stack the machine on which the operation is performed (StackMachine*) * @exception ExecutionError */ void Ldc::execute(StackMachine *stack) { switch(fType) { case integer: { StackInteger p1; // check if constant is of type integer if(typeid(p1) != typeid(*fConstant)) { throw ExecutionError("instruction ldc: type of constant is not of type integer."); } else { stack->fStore.push_back(new StackInteger(*(dynamic_cast<StackInteger*>(fConstant)))); } break; } case real: { StackReal p1; // check if constant is of type real if(typeid(p1) != typeid(*fConstant)) { throw ExecutionError("instruction ldc: type of constant is not of type real."); } else { stack->fStore.push_back(new StackReal(*(dynamic_cast<StackReal*>(fConstant)))); } break; } case boolean: { StackBoolean p1; // check if constant is of type boolean if(typeid(p1) != typeid(*fConstant)) { throw ExecutionError("instruction ldc: type of constant is not of type boolean."); } else { stack->fStore.push_back(new StackBoolean(*(dynamic_cast<StackBoolean*>(fConstant)))); } break; } case character: { StackCharacter p1; // check if constant is of type character if(typeid(p1) != typeid(*fConstant)) { throw ExecutionError("instruction ldc: type of constant is not of type character."); } else { stack->fStore.push_back(new StackCharacter(*(dynamic_cast<StackCharacter*>(fConstant)))); } break; } case address: { StackAddress p1; // check if constant is of type address if(typeid(p1) != typeid(*fConstant)) { throw ExecutionError("instruction ldc: type of constant is not of type address."); } else { stack->fStore.push_back(new StackAddress(*(dynamic_cast<StackAddress*>(fConstant)))); } break; } } // fSP = fSP + 1 ++stack->fSP; // adding cost of this instruction stack->fTime.count("ldc"); }
/** * Checks whether the 2 uppermost stackpositions are of the right type and then performs the neq-operation. * @return none * @param stack the machine on which the operation is performed (StackMachine*) * @exception ExecutionError */ void Neq::execute(StackMachine *stack) { // check if the stack contains at least two entries if(stack->fSP < 1) throw ExecutionError("instruction neq: requires 2 stackelements to be present."); switch(fType) { case integer: { StackInteger p1; // check if the two uppermost stackentries are of type integer if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction neq: SP does not point to element of type integer."); if(typeid(p1) != typeid(*(stack->fStore[stack->fSP - 1]))) throw ExecutionError("instruction neq: SP - 1 does not point to element of type integer."); break; } case real: { StackReal p1; // check if the two uppermost stackentries are of type real if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction neq: SP does not point to element of type real."); if(typeid(p1) != typeid(*(stack->fStore[stack->fSP - 1]))) throw ExecutionError("instruction neq: SP - 1 does not point to element of type real."); break; } case boolean: { StackBoolean p1; // check if the two uppermost stackentries are of type real if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction neq: SP does not point to element of type boolean."); if(typeid(p1) != typeid(*(stack->fStore[stack->fSP - 1]))) throw ExecutionError("instruction neq: SP - 1 does not point to element of type boolean."); break; } case character: { StackCharacter p1; // check if the two uppermost stackentries are of type real if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction neq: SP does not point to element of type character."); if(typeid(p1) != typeid(*(stack->fStore[stack->fSP - 1]))) throw ExecutionError("instruction neq: SP - 1 does not point to element of type character."); break; } case address: { StackAddress p1; // check if the two uppermost stackentries are of type real if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) throw ExecutionError("instruction neq: SP does not point to element of type address."); if(typeid(p1) != typeid(*(stack->fStore[stack->fSP - 1]))) throw ExecutionError("instruction neq: SP - 1 does not point to element of type address."); break; } } // compare StackBoolean *result; if(*(stack->fStore[stack->fSP - 1]) != *(stack->fStore[stack->fSP])) result = new StackBoolean(true); else result = new StackBoolean(false); // remove operands delete stack->fStore[stack->fSP]; stack->fStore[stack->fSP] = 0; delete stack->fStore[stack->fSP - 1]; stack->fStore[stack->fSP - 1] = 0; stack->fStore.pop_back(); stack->fStore.pop_back(); --stack->fSP; // put result on top of stack stack->fStore.push_back(result); // adding cost of this instruction stack->fTime.count("neq"); }
void Executor::run() { int status; bool firstExec = false; /* construct arguments vector */ std::vector<char*> cargv; std::vector<std::string> eargv; cargv.push_back((char*)command.c_str()); if (argv.ptr() != Py_None) { int l = len(argv); for (int i=0;i<l;i++) { extract<std::string> str(argv[i]); eargv.push_back(str()); cargv.push_back((char*)eargv[i].c_str()); } } cargv.push_back(NULL); /* convert filenames into C strings */ const char* file_input = NULL; const char* file_output = NULL; const char* file_errput = NULL; if (input.ptr() != Py_None) { extract<std::string> str(input); file_input = str().c_str(); eargv.push_back(str); } if (output.ptr() != Py_None) { extract<std::string> str(output); file_output = str().c_str(); eargv.push_back(str); } if (errput.ptr() != Py_None) { extract<std::string> str(errput); file_errput = str().c_str(); eargv.push_back(str); } /* zapamietujemy startowy rusage */ if (getrusage(RUSAGE_CHILDREN, &startusage)) { throw ExecutionError("Could not get starter rusage"); } if ((proc = vfork()) == 0) { /* zamykamy wejscia / wyjscia */ /*if (data->flags & PLF_CLOSESTDIN) if (close(STDIN_FILENO) != 0) _exit(2); if (data->flags & PLF_CLOSESTDOUT) if (close(STDOUT_FILENO) != 0) _exit(2); if (data->flags & PLF_CLOSESTDERR) if (close(STDERR_FILENO) != 0) _exit(2);*/ /* przekierowanie wyjscia / wejscia */ int fd; if (file_input) { fd = open(file_input, O_RDONLY); if (fd < 0) _exit(2); dup2(fd, STDIN_FILENO); } if (file_output) { fd = open(file_output, O_RDWR | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR); if (fd < 0) _exit(2); dup2(fd, STDOUT_FILENO); } if (file_errput > 0) { fd = open(file_errput, O_RDWR | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR); if (fd < 0) _exit(2); dup2(fd, STDERR_FILENO); } /* ustawiamy limit pamieci wirtualnej jesli byl wskazany */ if (memoryLimit != -1) { struct rlimit vmlimit; if (getrlimit(RLIMIT_AS, &vmlimit) != 0) { _exit(1); } vmlimit.rlim_cur = memoryLimit; if (setrlimit(RLIMIT_AS, &vmlimit) != 0) { _exit(1); } } // TODO: mozna jeszcze ustawiac limity na stos /* limit wyjscia (laczna wielkosc wszystkich plikow po ktorych piszemy) */ if (outputLimit != -1) { struct rlimit foutlimit; if (getrlimit(RLIMIT_FSIZE, &foutlimit) != 0) { _exit(3); } foutlimit.rlim_cur = outputLimit; if (setrlimit(RLIMIT_FSIZE, &foutlimit) != 0) { _exit(3); } } /* ustawiamy limit czasu wkonania (jesli byl wybrany) */ if (timeLimit != -1) { struct rlimit tmlimit; if (getrlimit(RLIMIT_CPU, &tmlimit) != 0) { _exit(4); } tmlimit.rlim_cur = (timeLimit + 1000) / 1000; if (setrlimit(RLIMIT_CPU, &tmlimit) != 0) { _exit(4); } } /* ten proces bedzie sledzony: */ if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) { _exit(5); } /* wywolujemy program */ execv(command.c_str(), &(cargv.front())); _exit(3); } else if (proc > 0) { int waitflags = 0; if (flags & PYZA_TRACE_CHILDS) { waitflags = WUNTRACED | __WALL; ptrace(PTRACE_SETOPTIONS, proc, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC | PTRACE_O_TRACEVFORKDONE | PTRACE_O_TRACEEXIT); } try { while (1) { /* czekamy na kolejne zatrzymanie przez ptrace */ if ((pid = wait4(-1, &status, waitflags, 0)) <= 0) { throw ExecutionError("Wait fault"); } if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { /* pobieramy wartosci rejestrow */ if (ptrace(PTRACE_GETREGS, pid, NULL, ®s) != 0) { throw ExecutionError("Ptrace getregs fault"); } if (!firstExec) { /* czekamy na pierwszy execv */ if (regs.ORIG_REG == SYS_execve) firstExec = true; } else { if (callback.ptr() != Py_None) callback(regs.ORIG_REG); } } else if (WIFSTOPPED(status)) { int stopsig = WSTOPSIG(status); if (stopsig == SIGXCPU) { throw TimeLimitError(); } else if (stopsig == SIGXFSZ) { throw RuntimeError("OutputSizeLimit"); } else if (stopsig == SIGSEGV) { throw RuntimeError("SIGSEGV"); } else if (stopsig == SIGFPE) { throw RuntimeError("SIGFPE"); } } else if (WIFEXITED(status)) { if (!firstExec) { throw ExecutionError("Initial error"); } returnCode = WEXITSTATUS(status); if (pid == proc) break; else continue; } else { /* signalled */ throw RuntimeError("SIGNALLED"); } /* puszczamy proces sledzony dalej */ if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL) != 0) { throw ExecutionError("Ptrace syscall fault"); } } } catch (const TimeLimitError& ex) { cleanup(); throw ex; } catch (const RuntimeError& ex) { cleanup(); throw ex; } catch (const ExecutionError& ex) { cleanup(); throw ex; } catch(const error_already_set& ex) { cleanup(); throw ex; } cleanup(); if (timeLimit > -1 && executionTime > timeLimit) { throw TimeLimitError(); } } else { /* nie moze wykonac fork'a */ throw ExecutionError("Fork error"); } return; }
Value Interpreter::exec(const InstructionList &instructions, Bindings &bindings) { Stack stack; ClosureValues closureValues; for(InstructionList::const_iterator it = instructions.begin() ; it != instructions.end() ; ++it) { Instruction::Type type = it->type(); const Value &value = it->value(); switch(type) { case Instruction::PUSH: if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " push " << value << '\n'; } stack.push_back(value); break; case Instruction::CALL: { if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " call " << value << '\n'; } Value result = handleFunction(it->sourceLocation(), value, stack, bindings); stack.push_back(result); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " return value " << result << '\n'; } } break; case Instruction::JUMP: { int instructionsToSkip = getInstructionsToSkip(type, value); int remaining = instructions.end() - it; if(remaining < instructionsToSkip) { throw CompilerBug("insufficient instructions available to skip! (remaining: " + str(remaining) + " < instructionsToSkip: " + str(instructionsToSkip) + ")"); } if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " jumping back " << instructionsToSkip << '\n'; } it += instructionsToSkip; } break; case Instruction::LOOP: { int instructionsToSkip = getInstructionsToSkip(type, value); int instructionsAvailable = instructions.size(); // Note: signed type is important! if(instructionsAvailable < instructionsToSkip) { throw CompilerBug("insufficient instructions available to loop! (instructionsToSkip: " + str(instructionsToSkip) + " > instructions.size(): " + str(instructions.size()) + ")"); } if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " looping back " << instructionsToSkip << " instructions\n"; } it -= instructionsToSkip; } break; case Instruction::CLOSE: { if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " close " << value << '\n'; } Value result = handleClose(value, stack, closureValues, bindings); stack.push_back(result); } break; case Instruction::COND_JUMP: { if(stack.empty()) { throw CompilerBug("empty stack when testing conditional jump"); } int instructionsToSkip = getInstructionsToSkip(type, value); int remaining = instructions.end() - it; if(remaining < instructionsToSkip) { throw CompilerBug("insufficient instructions available to skip! (remaining: " + str(remaining) + " < instructionsToSkip: " + str(instructionsToSkip) + ")"); } Value top = pop(stack); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " jumping back " << instructionsToSkip << " if " << top << '\n'; } if(top.isFalsey()) { it += instructionsToSkip; } } break; case Instruction::REF_LOCAL: handleRef(Bindings::Local, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " local ref '" << value.string() << "' is " << stack.back() << '\n'; } break; case Instruction::INIT_LOCAL: { const Value &intialisedValue = handleInit(Bindings::Local, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " local init '" << value.string() << "' to " << intialisedValue << '\n'; } } break; case Instruction::ASSIGN_LOCAL: { const Value &assignedValue = handleAssign(Bindings::Local, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " local assign '" << value.string() << "' to " << assignedValue << '\n'; } } break; case Instruction::REF_GLOBAL: handleRef(Bindings::Global, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " global ref '" << value.string() << "' is " << stack.back() << '\n'; } break; case Instruction::INIT_GLOBAL: { const Value &intialisedValue = handleInit(Bindings::Global, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " global init '" << value.string() << "' to " << intialisedValue << '\n'; } } break; case Instruction::ASSIGN_GLOBAL: { const Value &assignedValue = handleAssign(Bindings::Global, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " global assign '" << value.string() << "' to " << assignedValue << '\n'; } } break; case Instruction::REF_CLOSURE: handleRef(Bindings::Closure, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " closure ref '" << value.string() << "' is " << stack.back() << '\n'; } break; case Instruction::INIT_CLOSURE: { Identifier identifier = Identifier(value.string()); Bindings::ValuePtr &binding = bindings.getPointer(identifier); closureValues.push_back(ClosedNameAndValue(identifier, binding)); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " closure init '" << value.string() << "' is " << *binding << '\n'; } } break; case Instruction::ASSIGN_CLOSURE: { const Value &assignedValue = handleAssign(Bindings::Closure, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " closure assign '" << value.string() << "' to " << assignedValue << '\n'; } } break; case Instruction::MEMBER_ACCESS: { if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " member access " << value << '\n'; } assert(value.isString()); const std::string &memberName = value.string(); Value top = pop(stack); if(!top.isObject()) { throw ExecutionError(it->sourceLocation(), "Member access instruction requires an object but got " + str(top)); } const Value::Object &object = top.object(); Value::Object::const_iterator memberIterator = object.find(memberName); if (memberIterator == object.end()) { throw ExecutionError(it->sourceLocation(), "Unknown member name " + memberName + " for " + str(top)); } if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " member access " << value.string() << "." << memberName << " was " << memberIterator->second << '\n'; } stack.push_back(memberIterator->second); } break; default: throw CompilerBug("unhandled instruction type: " + str(type)); } if (settings_.trace) { if (stack.empty()) { std::cout << "Stack is empty\n"; } else { std::cout << "Stack contains " << stack.size() << " entries:\n"; int index = 0; for(Stack::const_iterator it = stack.begin() ; it != stack.end() ; ++it) { ++index; std::cout << index << ": " << *it << '\n'; } } if (closureValues.empty()) { std::cout << "closureValues is empty\n"; } else { std::cout << "closureValues contains " << closureValues.size() << " entries:\n"; int index = 0; for(const ClosedNameAndValue &closedValue: closureValues) { ++index; std::cout << index << ": " << closedValue.first << " -> " << *closedValue.second << " @ " << closedValue.second << '\n'; } } } } return stack.empty() ? Value::nil() : pop(stack); }
/** * Checks the contents of the stack and then performs the store operation. * @return none * @param stack the machine on which the instruction is performed (StackMachine*) * @exception ExecutionError */ void Sto::execute(StackMachine *stack) { StackAddress p; if(stack->fSP < 1) throw ExecutionError("instruction sto: at least 2 stackelements are required for this operation"); if(typeid(p) != typeid(*(stack->fStore[stack->fSP - 1]))) throw ExecutionError("instruction sto: type pointed to by SP - 1 is not of type address."); switch(fType) { case integer: { StackInteger p1; if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) { throw ExecutionError("instruction sto: type pointed to by SP is not of type integer."); } break; } case real: { StackReal p1; if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) { throw ExecutionError("instruction sto: type pointed to by SP is not of type real."); } break; } case boolean: { StackBoolean p1; if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) { throw ExecutionError("instruction sto: type pointed to by SP is not of type boolean."); } break; } case character: { StackCharacter p1; if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) { throw ExecutionError("instruction sto: type pointed to by SP is not of type character."); } break; } case address: { StackAddress p1; if(typeid(p1) != typeid(*(stack->fStore[stack->fSP]))) { throw ExecutionError("instruction sto: type pointed to by SP is not of type address."); } break; } } if(stack->fStore[stack->fSP - 1]->heapAddress()) { if(stack->fStore[stack->fSP - 1]->getValue() < stack->fNP) { throw ExecutionError("instruction sto: invalid heap address."); } else { delete stack->fHeap[-stack->fStore[stack->fSP - 1]->getValue() - 1]; stack->fHeap[-stack->fStore[stack->fSP - 1]->getValue() - 1] = stack->fStore[stack->fSP]; } } else { if(stack->fStore[stack->fSP - 1]->getValue() > stack->fSP - 2) { // -2 because the SP will be decreased by 2 as a result of this operation throw ExecutionError("instruction sto: invalid stack address."); } else { delete stack->fStore[stack->fStore[stack->fSP - 1]->getValue()]; stack->fStore[stack->fStore[stack->fSP - 1]->getValue()] = stack->fStore[stack->fSP]; } } stack->fStore.pop_back(); delete stack->fStore[stack->fSP - 1]; stack->fStore[stack->fSP - 1] = 0; stack->fStore.pop_back(); stack->fSP -= 2; // adding cost of this instruction stack->fTime.count("sto"); }