static KMETHOD TypeCheck_Getter(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck2(stmt, expr, ns, reqc); kToken *fieldToken = expr->NodeList->TokenItems[0]; ksymbol_t fn = fieldToken->symbol; kNode *self = KLIB TypeCheckNodeAt(kctx, expr, 1, ns, KClass_INFER, 0); if(self != K_NULLNODE) { kMethod *mtd = KLIB kNameSpace_GetGetterMethodNULL(kctx, ns, KClass_(self->typeAttr), fn); if(mtd != NULL) { KFieldSet(expr->NodeList, expr->NodeList->MethodItems[0], mtd); KReturn(KLIB TypeCheckMethodParam(kctx, mtd, expr, ns, reqc)); } else { // dynamic field o.name => o.get(name) kparamtype_t p[1] = {{KType_Symbol}}; kparamId_t paramdom = KLIB Kparamdom(kctx, 1, p); mtd = KLIB kNameSpace_GetMethodBySignatureNULL(kctx, ns, KClass_(self->typeAttr), KMethodNameAttr_Getter, paramdom, 1, p); if(mtd != NULL) { KFieldSet(expr->NodeList, expr->NodeList->MethodItems[0], mtd); KLIB kArray_Add(kctx, expr->NodeList, new_UnboxConstNode(kctx, ns, KType_Symbol, KSymbol_Unmask(fn))); KReturn(KLIB TypeCheckMethodParam(kctx, mtd, expr, ns, reqc)); } } KLIB MessageNode(kctx, stmt, fieldToken, ns, ErrTag, "undefined field: %s", kString_text(fieldToken->text)); } }
static kbool_t MiniVM_VisitNullNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk) { if(KType_Is(UnboxType, node->typeAttr)) { ASM(NSET, NC_(builder->stackbase), 0, KClass_(node->typeAttr)); } else { ASM(NUL, OC_(builder->stackbase), KClass_(node->typeAttr)); } builder->Value = builder->stackbase; return true; }
static kbool_t KBuilder_VisitNullNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk) { kshort_t a = AssignStack(thunk); if(KType_Is(UnboxType, expr->attrTypeId)) { ASM(NSET, NC_(a), 0, KClass_(expr->attrTypeId)); } else { ASM(NUL, OC_(a), KClass_(expr->attrTypeId)); } return true; }
static kbool_t MiniVM_VisitMethodCallNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk) { kMethod *mtd = CallNode_getMethod(node); /* * [CallExpr] := this.method(arg1, arg2, ...) * node->NodeList = [method, this, arg1, arg2, ...] **/ intptr_t stackbase, thisidx; int i, s, argc = CallNode_getArgCount(node); DBG_ASSERT(IS_Method(mtd)); s = kMethod_Is(Static, mtd) ? 2 : 1; if(kMethod_Is(Static, mtd)) { KClass *selfTy = KClass_(mtd->typeId); kObject *obj = KLIB Knull(kctx, selfTy); ASM(NSET, OC_(builder->stackbase), (uintptr_t) obj, selfTy); } stackbase = builder->stackbase; thisidx = stackbase + K_CALLDELTA; for (i = s; i < argc + 2; i++) { kUntypedNode *exprN = kUntypedNode_At(node, i); builder->stackbase = thisidx + i - 1; DBG_ASSERT(IS_Node(exprN)); KLIB VisitNode(kctx, builder, exprN, thunk); if(builder->Value != builder->stackbase) { KClass *ty = KClass_(exprN->typeAttr); ASM_NMOV(kctx, builder, ty, builder->stackbase, builder->Value); } } if(kMethod_Is(Final, mtd) || !kMethod_Is(Virtual, mtd)) { ASM(NSET, NC_(thisidx-1), (intptr_t)mtd, KClass_Method); if(kMethod_Is(Virtual, mtd)) { // set namespace to enable method lookups ASM(NSET, OC_(thisidx-2), (intptr_t)kUntypedNode_ns(node), KClass_NameSpace); } } else { ASM(NSET, OC_(thisidx-2), (intptr_t)kUntypedNode_ns(node), KClass_NameSpace); ASM(LOOKUP, SFP_(thisidx), kUntypedNode_ns(node), mtd); } ASM(CALL, kUntypedNode_uline(node), SFP_(thisidx), SFP_(thisidx + argc + 1), KLIB Knull(kctx, KClass_(node->typeAttr))); builder->stackbase = stackbase; builder->Value = builder->stackbase; return true; }
static KMETHOD Statement_ConstDecl(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck(stmt, ns, reqc); kToken *symbolToken = SUGAR kNode_GetToken(kctx, stmt, KSymbol_SymbolPattern, NULL); ksymbol_t unboxKey = symbolToken->symbol; kNode *constNode = SUGAR TypeCheckNodeByName(kctx, stmt, KSymbol_ExprPattern, ns, KClass_INFER, TypeCheckPolicy_CONST); if(!kNode_IsError(constNode)) { KClass *constClass = KClass_(constNode->attrTypeId); ktypeattr_t type = constClass->typeId; uintptr_t unboxValue; kbool_t result = false; if(kNode_node(constNode) == KNode_Null) { // const C = String type = VirtualType_KClass; unboxValue = (uintptr_t)constClass; result = true; } else if(kNode_node(constNode) == KNode_Const) { // const C = "1" unboxValue = (uintptr_t)constNode->ObjectConstValue; result = true; } else if(kNode_node(constNode) == KNode_UnboxConst) { // const c = 1 unboxValue = constNode->unboxConstValue; result = true; } if(result) { KMakeTraceUL(trace, sfp, kNode_uline(stmt)); result = KLIB kNameSpace_SetConstData(kctx, ns, unboxKey, type, unboxValue, trace); } else { kNode_Message(kctx, stmt, ErrTag, "constant value is expected: %s%s", KSymbol_Fmt2(unboxKey)); } constNode = kNode_Type(kctx, stmt, KNode_Done, KType_void); } KReturn(constNode); }
// @SmartReturn Object Prototype.get(Symbol symbol) static KMETHOD Prototype_get(KonohaContext *kctx, KonohaStack *sfp) { KClass *targetClass = KGetReturnType(sfp); DBG_P("requesting type=%s", KClass_text(targetClass)); ksymbol_t symbol = sfp[1].intValue; KKeyValue *kvs = KLIB kObjectProto_GetKeyValue(kctx, sfp[0].asObject, symbol); if(kvs != NULL) { KClass *c = KClass_(kvs->attrTypeId); if(targetClass == c) { if(KClass_Is(UnboxType, targetClass)) { KReturnUnboxValue(kvs->unboxValue); } else { KReturnField(kvs->ObjectValue); } } DBG_P("requesting type=%s instanceof %s ? %d", KClass_text(c), KClass_text(targetClass), c->isSubType(kctx, c, targetClass)); if(c->isSubType(kctx, c, targetClass)) { if(KClass_Is(UnboxType, c)) { if(KClass_Is(UnboxType, targetClass)) { KReturnUnboxValue(kvs->unboxValue); } else { DBG_P("boxing type=%s instanceof %s ? %d", KClass_text(c), KClass_text(targetClass), c->isSubType(kctx, c, targetClass)); KReturn(KLIB new_kObject(kctx, OnStack, c, kvs->unboxValue)); } } KReturnField(kvs->ObjectValue); } } KReturnUnboxValue(0); // return default value }
static kbool_t KBuilder_VisitMethodCallNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk) { kshort_t a = AssignStack(thunk), espidx = expr->stackbase, thisidx = espidx + K_CALLDELTA; DBG_ASSERT(a <= espidx); kMethod *mtd = CallNode_getMethod(expr); DBG_ASSERT(IS_Method(mtd)); int i, s = kMethod_Is(Static, mtd) ? 2 : 1; int argc = CallNode_getArgCount(expr); for (i = s; i < argc + 2; i++) { intptr_t a = thisidx + i - 1; kNode *paramNode = kNode_At(expr, i); if(!kNode_IsValue(paramNode) && paramNode->stackbase != a) { DBG_P("a=%d, stackbase=%d", a, paramNode->stackbase); DBG_ASSERT(paramNode->stackbase == a); } SUGAR VisitNode(kctx, builder, paramNode, &a); } if(kMethod_Is(Final, mtd) || !kMethod_Is(Virtual, mtd)) { ASM(NSET, NC_(thisidx-1), (intptr_t)mtd, KClass_Method); if(kMethod_Is(Virtual, mtd)) { // set namespace to enable method lookups ASM(NSET, OC_(thisidx-2), (intptr_t)kNode_ns(expr), KClass_NameSpace); } } else { ASM(NSET, OC_(thisidx-2), (intptr_t)kNode_ns(expr), KClass_NameSpace); ASM(LOOKUP, SFP_(thisidx), kNode_ns(expr), mtd); } int esp_ = SFP_(espidx + argc + K_CALLDELTA + 1); ASM(CALL, builder->common.uline, SFP_(thisidx), esp_, KLIB Knull(kctx, KClass_(expr->attrTypeId))); ReAssignNonValueNode(kctx, builder, a, expr); return true; }
static struct KVirtualCode *FuelVM_GenerateVirtualCode(KonohaContext *kctx, kMethod *mtd, kNode *block, int option) { if(unlikely(AbstractMethodPtr == 0)) { AbstractMethodPtr = mtd->invokeKMethodFunc; } kNameSpace *ns = kNode_ns(block); KBuilder builderbuf = {}, *builder = &builderbuf; FuelIRBuilder Builder = {}; INIT_GCSTACK(); IRBuilder_Init(&Builder, kctx, ns); builder->builder = &Builder; builder->common.api = ns->builderApi; Block *EntryBlock = CreateBlock(BLD(builder)); IRBuilder_setBlock(BLD(builder), EntryBlock); INode *Self = SetUpArguments(kctx, &Builder, mtd); SUGAR VisitNode(kctx, builder, block, NULL); if(!Block_HasTerminatorInst(BLD(builder)->Current)) { if(mtd->mn == MN_new) { INode *Ret = CreateReturn(BLD(builder), Self); INode_setType(Ret, ConvertToTypeId(kctx, mtd->typeId)); } else { ktypeattr_t retTy = kMethod_GetReturnType(mtd)->typeId; if(retTy == KType_void) { CreateReturn(BLD(builder), 0); } else { enum TypeId Type = ConvertToTypeId(kctx, retTy); INode *Ret; if(KType_Is(UnboxType, retTy)) { SValue V; V.bits = 0; Ret = CreateConstant(BLD(builder), Type, V); } else { kObject *obj = KLIB Knull(kctx, KClass_(retTy)); Ret = CreateObject(BLD(builder), Type, (void *)obj); } Ret = CreateReturn(BLD(builder), Ret); INode_setType(Ret, Type); CreateReturn(BLD(builder), 0); } } } RESET_GCSTACK(); IMethod Mtd = {kctx, mtd, EntryBlock, ns}; BLD(builder)->Method = &Mtd; bool JITCompiled = false; union ByteCode *code = IRBuilder_Compile(BLD(builder), &Mtd, option, &JITCompiled); if(mtd->invokeKMethodFunc == FuelVM_RunVirtualMachine) { mtd->virtualCodeApi_plus1[-1]->FreeVirtualCode(kctx, mtd->vcode_start); } KLIB kMethod_SetFunc(kctx, mtd, 0); if(JITCompiled) { KLIB kMethod_SetFunc(kctx, mtd, (KMethodFunc) code); } KFieldSet(mtd, ((kMethodVar *)mtd)->CompiledNode, block); IRBuilder_Exit(&Builder); return (struct KVirtualCode *) code; }
static kbool_t KBuilder_VisitConstNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk) { DBG_ASSERT(!KType_Is(UnboxType, expr->attrTypeId)); kObject *v = KBuilder_AddConstPool(kctx, builder, expr->ObjectConstValue); kshort_t a = AssignStack(thunk); ASM(NSET, OC_(a), (uintptr_t)v, KClass_(expr->attrTypeId)); return true; }
static kbool_t MiniVM_VisitConstNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk) { kObject *v = MiniVM_AddConstPool(kctx, builder, node->ObjectConstValue); DBG_ASSERT(!KType_Is(UnboxType, node->typeAttr)); ASM(NSET, OC_(builder->stackbase), (uintptr_t) v, KClass_(node->typeAttr)); builder->Value = builder->stackbase; return true; }
static kbool_t MiniVM_VisitUnboxConstNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk) { uintptr_t Val = node->unboxConstValue; DBG_ASSERT(KType_Is(UnboxType, node->typeAttr)); ASM(NSET, NC_(builder->stackbase), Val, KClass_(node->typeAttr)); builder->Value = builder->stackbase; return true; }
static kbool_t KBuilder_VisitFieldNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk) { kshort_t a = AssignStack(thunk); kshort_t index = (kshort_t)expr->index; kshort_t xindex = (kshort_t)(expr->index >> (sizeof(kshort_t)*8)); KClass *ty = KClass_(expr->attrTypeId); ASM(NMOVx, TC_(a, ty), OC_(index), xindex, ty); return true; }
static KMETHOD TypeCheck_as(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck2(stmt, expr, ns, reqc); kNode *targetNode = SUGAR TypeCheckNodeAt(kctx, expr, 2, ns, KClass_INFER, 0); kNode *selfNode = SUGAR TypeCheckNodeAt(kctx, expr, 1, ns, KClass_(targetNode->attrTypeId), TypeCheckPolicy_NoCheck); if(selfNode != K_NULLNODE && targetNode != K_NULLNODE) { KClass *selfClass = KClass_(selfNode->attrTypeId), *targetClass = KClass_(targetNode->attrTypeId); if(selfClass->typeId == targetClass->typeId || selfClass->isSubType(kctx, selfClass, targetClass)) { KReturn(selfNode); } if(selfClass->isSubType(kctx, targetClass, selfClass)) { kNameSpace *ns = kNode_ns(stmt); kMethod *mtd = KLIB kNameSpace_GetMethodByParamSizeNULL(kctx, ns, KClass_Object, KMethodName_("as"), 0, KMethodMatch_CamelStyle); DBG_ASSERT(mtd != NULL); KReturn(SUGAR TypeCheckMethodParam(kctx, mtd, expr, ns, targetClass)); } KReturn(SUGAR MessageNode(kctx, selfNode, NULL, ns, ErrTag, "unable to downcast: %s as %s", KType_text(selfNode->attrTypeId), KType_text(targetNode->attrTypeId))); } }
static kbool_t MiniVM_VisitBoxNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk) { /* * [box] := box(this) **/ KLIB VisitNode(kctx, builder, node->NodeToPush, thunk); ASM(BOX, OC_(builder->stackbase), NC_(MiniVM_getExpression(builder)), KClass_(node->typeAttr)); builder->Value = builder->stackbase; return true; }
static kbool_t MiniVM_VisitReturnNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk) { kUntypedNode *expr = KLIB kUntypedNode_GetNode(kctx, node, KSymbol_ExprPattern, NULL); if(expr != NULL && IS_Node(expr) && expr->typeAttr != KType_void) { KLIB VisitNode(kctx, builder, expr, thunk); ASM_NMOV(kctx, builder, KClass_(expr->typeAttr), K_RTNIDX, MiniVM_getExpression(builder)); } MiniVMBuilder_JumpTo(kctx, builder, builder->bbReturnId); return false; }
static void inline ReAssignNonValueNode(KonohaContext *kctx, KBuilder *builder, intptr_t localStack, kNode *node) { DBG_ASSERT(!kNode_IsValue(node)); if(node->attrTypeId != KType_void && localStack != node->stackbase) { if(!(localStack < node->stackbase)) { DBG_P("localStack=%d, stackbase=%d", localStack, node->stackbase); DBG_ASSERT(localStack < node->stackbase); } AsmMOV(kctx, builder, localStack, KClass_(node->attrTypeId), node->stackbase); } }
static kbool_t MiniVM_VisitAssignNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk) { /* * [LetExpr] := lhs = rhs * expr->NodeList = [NULL, lhs, rhs] **/ intptr_t dst = -1; kUntypedNode *left = kUntypedNode_At(node, 1); kUntypedNode *right = kUntypedNode_At(node, 2); ktypeattr_t type = left->typeAttr; ksymbol_t symbol; assert(IS_Token(left->TermToken)); symbol = left->TermToken->symbol; if(kUntypedNode_node(left) == KNode_Local) { if((dst = MiniVMBuilder_FindLocalVar(kctx, builder, symbol, type, left->index)) == -1) { dst = AddLocal(kctx, builder, left->index, symbol, type); } KLIB VisitNode(kctx, builder, right, thunk); CreateUpdate(kctx, builder, type, dst, MiniVM_getExpression(builder)); builder->Value = dst; } else { khalfword_t index = (khalfword_t)left->index; khalfword_t xindex = (khalfword_t)(left->index >> (sizeof(khalfword_t)*8)); KClass *lhsClass = KClass_(left->typeAttr); KClass *rhsClass = KClass_(right->typeAttr); assert(kUntypedNode_node(left) == KNode_Field); if((dst = MiniVMBuilder_FindLocalVar(kctx, builder, symbol, KType_Object, index)) == -1) { dst = AddLocal(kctx, builder, index, symbol, KType_Object); } KLIB VisitNode(kctx, builder, right, thunk); ASM(XNMOV, OC_(index), xindex, TC_(MiniVM_getExpression(builder), rhsClass), lhsClass); if(node->typeAttr != KType_void) { builder->Value = builder->stackbase; ASM(NMOVx, TC_(builder->stackbase, rhsClass), OC_(index), xindex, lhsClass); } } return true; }
static kbool_t FuelVM_VisitNullNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk) { SValue Val = {}; ktypeattr_t type = expr->attrTypeId; if(KType_Is(UnboxType, type)) { Val.bits = 0; } else { Val.ptr = (void *) KLIB Knull(kctx, KClass_(type)); } builder->Value = CreateConstant(BLD(builder), ConvertToTypeId(kctx, expr->attrTypeId), Val); return true; }
static kbool_t object_PackupNameSpace(KonohaContext *kctx, kNameSpace *ns, int option, KTraceInfo *trace) { // KRequirePackage("konoha.subtype", trace); KDEFINE_INT_CONST ClassData[] = { // add Object as available {"Object", VirtualType_KClass, (uintptr_t)KClass_(KType_Object)}, {NULL}, }; KLIB kNameSpace_LoadConstData(kctx, ns, KConst_(ClassData), trace); object_defineMethod(kctx, ns, trace); subtype_defineSyntax(kctx, ns, trace); return true; }
static KMETHOD TypeCheck_InstanceOf(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck2(stmt, expr, ns, reqc); /* selfNode and targetNode allow void type * e.g. "'a' instanceof void" */ kNode *selfNode = SUGAR TypeCheckNodeAt(kctx, expr, 1, ns, KClass_INFER, TypeCheckPolicy_AllowVoid); kNode *targetNode = SUGAR TypeCheckNodeAt(kctx, expr, 2, ns, KClass_INFER, TypeCheckPolicy_AllowVoid); if(selfNode != K_NULLNODE && targetNode != K_NULLNODE) { KClass *selfClass = KClass_(selfNode->attrTypeId), *targetClass = KClass_(targetNode->attrTypeId); if(KClass_Is(Final, selfClass)) { kbool_t staticSubType = (selfClass == targetClass || selfClass->isSubType(kctx, selfClass, targetClass)); KReturn(SUGAR kNode_SetUnboxConst(kctx, expr, KType_Boolean, staticSubType)); } kNameSpace *ns = kNode_ns(stmt); kMethod *mtd = KLIB kNameSpace_GetMethodByParamSizeNULL(kctx, ns, KClass_Object, KMethodName_("instanceof"), 1, KMethodMatch_NoOption); DBG_ASSERT(mtd != NULL); kNode *classValue = SUGAR kNode_SetConst(kctx, expr->NodeList->NodeVarItems[2], NULL, KLIB Knull(kctx, targetClass)); KFieldSet(expr->NodeList, expr->NodeList->NodeItems[2], classValue); KReturn(SUGAR TypeCheckMethodParam(kctx, mtd, expr, ns, KClass_Boolean)); } }
static kbool_t process_PackupNameSpace(KonohaContext *kctx, kNameSpace *ns, int option, KTraceInfo *trace) { kparamtype_t p = {KType_Int}; KClass *cintArray = KLIB KClass_Generics(kctx, KClass_(KType_Array), KType_void, 1, &p); #define KType_IntArray (cintArray->typeId) KDEFINE_METHOD MethodData[] = { _Public|_Static, _F(System_getpid), KType_Int, KType_System, KMethodName_("getpid"), 0, _Public|_Static, _F(System_getppid), KType_Int, KType_System, KMethodName_("getppid"), 0, _Public|_Static, _F(System_getuid), KType_Int, KType_System, KMethodName_("getuid"), 0, _Public|_Static, _F(System_geteuid), KType_Int, KType_System, KMethodName_("geteuid"), 0, _Public|_Static, _F(System_getgid), KType_Int, KType_System, KMethodName_("getgid"), 0, _Public|_Static, _F(System_getegid), KType_Int, KType_System, KMethodName_("getegid"), 0, _Public|_Static, _F(System_getpgid), KType_Int, KType_System, KMethodName_("getpgid"), 1, KType_Int, KFieldName_("pid"), _Public|_Static, _F(System_Setpgid), KType_Int, KType_System, KMethodName_("setpgid"), 2, KType_Int, KFieldName_("pid"), KType_Int, KFieldName_("pgid"), _Public|_Static, _F(System_getpriority), KType_Int, KType_System, KMethodName_("getpriority"), 2, KType_Int, KFieldName_("which"), KType_Int, KFieldName_("who"), _Public|_Static, _F(System_Setpriority), KType_Int, KType_System, KMethodName_("setpriority"), 3, KType_Int, KFieldName_("which"), KType_Int, KFieldName_("who"), KType_Int, KFieldName_("priority"), _Public|_Static, _F(System_getgroups), KType_Int, KType_System, KMethodName_("getgroups"), 2, KType_Int, KFieldName_("size"), KType_IntArray, KFieldName_("list[]"), _Public|_Static, _F(System_Setgroups), KType_Int, KType_System, KMethodName_("setgroups"), 2, KType_Int, KFieldName_("size"), KType_IntArray, KFieldName_("*list"), _Public|_Static, _F(System_fork), KType_Int, KType_System, KMethodName_("fork"), 0, _Public|_Static, _F(System_wait), KType_Int, KType_System, KMethodName_("wait"), 0, _Public|_Static, _F(System_waitpid), KType_Int, KType_System, KMethodName_("wait"), 2, KType_Int, KFieldName_("pid"), KType_Int, KFieldName_("options"), _Public|_Static, _F(System_Setuid), KType_Int, KType_System, KMethodName_("setuid"), 1, KType_Int, KFieldName_("uid"), _Public|_Static, _F(System_Seteuid), KType_Int, KType_System, KMethodName_("seteuid"), 1, KType_Int, KFieldName_("euid"), _Public|_Static, _F(System_Setreuid), KType_Int, KType_System, KMethodName_("setreuid"), 2, KType_Int, KFieldName_("ruid"), KType_Int, KFieldName_("euid"), _Public|_Static, _F(System_Setgid), KType_Int, KType_System, KMethodName_("setgid"), 1, KType_Int, KFieldName_("gid"), _Public|_Static, _F(System_Setegid), KType_Int, KType_System, KMethodName_("setguid"), 1, KType_Int, KFieldName_("egid"), _Public|_Static, _F(System_Setregid), KType_Int, KType_System, KMethodName_("setrguid"), 2, KType_Int, KFieldName_("rgid"), KType_Int, KFieldName_("egid"), _Public|_Static, _F(System_Setsid), KType_Int, KType_System, KMethodName_("setsid"), 0, _Public|_Static, _F(System_getsid), KType_Int, KType_System, KMethodName_("getsid"), 1, KType_Int, KFieldName_("pid"), _Public|_Static, _F(System_sleep), KType_Int, KType_System, KMethodName_("sleep"), 1, KType_Int, KFieldName_("sec"), _Public|_Static, _F(System_usleep), KType_Boolean, KType_System, KMethodName_("usleep"), 1, KType_Int, KFieldName_("usec"), _Public|_Static, _F(System_system), KType_Int, KType_System, KMethodName_("system"), 1, KType_String, KFieldName_("command"), _Public|_Static, _F(System_getenv), KType_String, KType_System, KMethodName_("getenv"), 1, KType_String, KFieldName_("name"), DEND, }; KLIB kNameSpace_LoadMethodData(kctx, ns, MethodData, trace); KDEFINE_INT_CONST intData[] = { {KDefineConstInt(SIGHUP)}, {KDefineConstInt(SIGINT)}, {KDefineConstInt(SIGABRT)}, {KDefineConstInt(SIGKILL)}, /*for System.setpriority*/ {KDefineConstInt(PRIO_PROCESS)}, {KDefineConstInt(PRIO_PGRP)}, {KDefineConstInt(PRIO_USER)}, {} }; KLIB kNameSpace_LoadConstData(kctx, ns, KConst_(intData), trace); return true; }
static KMETHOD TypeCheck_to(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck2(stmt, expr, ns, reqc); kNode *targetNode = SUGAR TypeCheckNodeAt(kctx, expr, 2, ns, KClass_INFER, 0); kNode *selfNode = SUGAR TypeCheckNodeAt(kctx, expr, 1, ns, KClass_(targetNode->attrTypeId), TypeCheckPolicy_NoCheck); if(selfNode != K_NULLNODE && targetNode != K_NULLNODE) { KClass *selfClass = KClass_(selfNode->attrTypeId), *targetClass = KClass_(targetNode->attrTypeId); if(selfNode->attrTypeId == targetNode->attrTypeId || selfClass->isSubType(kctx, selfClass, targetClass)) { SUGAR MessageNode(kctx, selfNode, NULL, ns, InfoTag, "no need: %s to %s", KType_text(selfNode->attrTypeId), KType_text(targetNode->attrTypeId)); KReturn(selfNode); } kNameSpace *ns = kNode_ns(stmt); kMethod *mtd = KLIB kNameSpace_GetCoercionMethodNULL(kctx, ns, selfClass, targetClass); if(mtd == NULL) { mtd = KLIB kNameSpace_GetMethodByParamSizeNULL(kctx, ns, selfClass, KMethodName_("to"), 0, KMethodMatch_CamelStyle); DBG_ASSERT(mtd != NULL); // because Object.to is found. if(mtd->typeId != selfClass->typeId) { KReturn(SUGAR MessageNode(kctx, selfNode, NULL, ns, ErrTag, "undefined coercion: %s to %s", KClass_text(selfClass), KClass_text(targetClass))); } } KReturn(SUGAR TypeCheckMethodParam(kctx, mtd, expr, ns, targetClass)); } }
static struct KVirtualCode *MiniVM_GenerateVirtualCode(KonohaContext *kctx, kMethod *mtd, kUntypedNode *block, int option) { KVirtualCode *vcode; KBuffer wb; KBuilder builderbuf = {{0}}, *builder = &builderbuf; kNameSpace *ns = kUntypedNode_ns(block); INIT_GCSTACK(); KLIB KBuffer_Init(&(kctx->stack->cwb), &wb); builder->common.api = ns->builderApi; builder->constPools = ns->NameSpaceConstList; builder->bbBeginId = new_BasicBlockLABEL(kctx); builder->bbReturnId = new_BasicBlockLABEL(kctx); builder->bbMainId = builder->bbBeginId; builder->currentMtd = mtd; builder->Value = 0; builder->stackbase = 0; builder->InstructionSize = 0; builder->common.api = &CollectLocalVar_BuilderAPI; KLIB VisitNode(kctx, builder, block, NULL); builder->stackbase += builder->localVarSize + 1/* == this object */; builder->common.api = ns->builderApi; KLIB KArray_Init(kctx, &builder->localVar, sizeof(LocalVarInfo) * builder->stackbase); ASM(THCODE, 0, _THCODE); ASM(CHKSTACK, 0); KLIB VisitNode(kctx, builder, block, NULL); if(!Block_HasTerminatorInst(kctx, builder->bbMainId)) { MiniVMBuilder_JumpTo(kctx, builder, builder->bbReturnId); } MiniVMBuilder_setBlock(kctx, builder, builder->bbReturnId); if(mtd->mn == MN_new) { // FIXME: Type 'This' must be resolved ASM(NMOV, OC_(K_RTNIDX), OC_(0), KClass_(mtd->typeId)); } ASM(RET); vcode = CompileVirtualCode(kctx, builder, builder->bbBeginId, builder->bbReturnId); KLIB KArray_Free(kctx, &builder->localVar); RESET_GCSTACK(); KLIB KBuffer_Free(&wb); return vcode; }
static kbool_t KBuilder_VisitAssignNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk) { kNode *leftHandNode = kNode_At(expr, 1); kNode *rightHandNode = kNode_At(expr, 2); //DBG_P("LET (%s) a=%d, shift=%d, espidx=%d", KType_text(expr->attrTypeId), a, shift, espidx); if(kNode_node(leftHandNode) == KNode_Local) { kshort_t a = AssignStack(thunk); SUGAR VisitNode(kctx, builder, rightHandNode, &(leftHandNode->index)); if(expr->attrTypeId != KType_void && a != leftHandNode->index) { AsmMOV(kctx, builder, a, KClass_(leftHandNode->attrTypeId), leftHandNode->index); } } else if(kNode_node(leftHandNode) == KNode_Field) { intptr_t espidx = expr->stackbase; SUGAR VisitNode(kctx, builder, rightHandNode, &espidx); kshort_t index = (kshort_t)leftHandNode->index; kshort_t xindex = (kshort_t)(leftHandNode->index >> (sizeof(kshort_t)*8)); KClass *lhsClass = KClass_(leftHandNode->attrTypeId), *rhClass = KClass_(rightHandNode->attrTypeId); ASM(XNMOV, OC_(index), xindex, TC_(espidx, rhClass), lhsClass); if(expr->attrTypeId != KType_void) { kshort_t a = AssignStack(thunk); ASM(NMOVx, TC_(a, rhClass), OC_(index), xindex, lhsClass); } }
static kbool_t FuelVM_VisitMethodCallNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk) { kMethod *mtd = CallNode_getMethod(expr); DBG_ASSERT(IS_Method(mtd)); enum TypeId Type = ConvertToTypeId(kctx, expr->attrTypeId); if(mtd->mn == KMethodName_("box")) { Type = ToBoxType(Type); } /* * [CallExpr] := this.method(arg1, arg2, ...) * expr->NodeList = [method, this, arg1, arg2, ...] **/ INode *Inst; if((Inst = CreateSpecialInstruction(kctx, builder, mtd, expr, thunk)) != 0) { INode_setType(Inst, Type); builder->Value = Inst; return true; } int i, s = kMethod_Is(Static, mtd) ? 2 : 1; int argc = CallExpr_getArgCount(expr); INode *Params[argc+2]; if(kMethod_Is(Static, mtd)) { kObject *obj = KLIB Knull(kctx, KClass_(mtd->typeId)); INode *Self = CreateObject(BLD(builder), mtd->typeId, (void *) obj); Params[1] = Self; } for (i = s; i < argc + 2; i++) { kNode *exprN = kNode_At(expr, i); DBG_ASSERT(IS_Node(exprN)); SUGAR VisitNode(kctx, builder, exprN, thunk); INode *Node = FuelVM_getExpression(builder); assert(Node->Type != TYPE_void); Params[i] = Node; } INode *MtdObj = CreateObject(BLD(builder), KType_Method, (void *) mtd); enum CallOp Op = (kMethod_Is(Virtual, mtd)) ? VirtualCall : DefaultCall; Params[0] = MtdObj; kNode *stmt = expr->Parent; assert(IS_Node(stmt)); Inst = CreateICall(BLD(builder), Type, Op, kNode_uline(stmt), Params, argc + 2); builder->Value = Inst; return true; }
static void KStackDynamicTypeCheck(KonohaContext *kctx, KonohaStack *sfp, kMethod *mtd, KClass *thisClass) { kushort_t i; kParam *pa = kMethod_GetParam(mtd); for(i = 0; i < pa->psize; i++) { KClass *objectType = kObject_class(sfp[i+1].asObject); KClass *paramType = KClass_(pa->paramtypeItems[i].attrTypeId); paramType = paramType->realtype(kctx, paramType, thisClass); if(objectType == paramType || objectType->isSubType(kctx, objectType, paramType)) { if(KClass_Is(UnboxType, paramType)) { KStackSetUnboxValue(sfp[i+1].unboxValue, kObject_Unbox(sfp[i+1].asObject)); } continue; // OK } ThrowTypeError(kctx, sfp, i + 1); } }
//## Prototype Prototype.(Object o); static KMETHOD Prototype_(KonohaContext *kctx, KonohaStack *sfp) { ksymbol_t symbol = KDynamicCallSymbol(sfp); KKeyValue *kvs = KLIB kObjectProto_GetKeyValue(kctx, sfp[0].asObject, symbol); if(kvs != NULL) { KClass *c = KClass_(kvs->attrTypeId); kParam *cparam = KClass_cparam(c); if(KClass_isFunc(c) && cparam->psize <= KDynamicCallArgument(sfp)) { KClass *thisClass = kObject_class(sfp[0].asObject), *returnType = KGetReturnType(sfp); kFunc *fo = (kFunc *)kvs->FuncValue; KStackSetFunc(sfp, fo); KStackDynamicTypeCheck(kctx, sfp, fo->method, thisClass); KStackCall(sfp); KStackReturnTypeCheck(kctx, sfp, fo->method, thisClass, returnType); } } }
static KMETHOD Statement_class(KonohaContext *kctx, KonohaStack *sfp) { VAR_TypeCheck(stmt, ns, reqc); kToken *tokenClassName = SUGAR kNode_GetToken(kctx, stmt, KSymbol_("$ClassName"), NULL); int isNewlyDefinedClass = false; KClassVar *definedClass = (KClassVar *)KLIB kNameSpace_GetClassByFullName(kctx, ns, kString_text(tokenClassName->text), kString_size(tokenClassName->text), NULL); if(definedClass == NULL) { // Already defined kshortflag_t cflag = kNode_ParseClassFlag(kctx, stmt, KClassFlag_Virtual); KMakeTraceUL(trace, sfp, kNode_uline(stmt)); definedClass = kNameSpace_DefineClassName(kctx, ns, cflag, tokenClassName->text, trace); isNewlyDefinedClass = true; } kNode *block = kNode_ParseClassNodeNULL(kctx, stmt, tokenClassName); size_t declsize = kNode_countFieldSize(kctx, block); if(isNewlyDefinedClass) { // Already defined KClass *superClass = KClass_Object; kToken *tokenSuperClass= SUGAR kNode_GetToken(kctx, stmt, KSymbol_("extends"), NULL); if(tokenSuperClass != NULL) { DBG_ASSERT(Token_isVirtualTypeLiteral(tokenSuperClass)); superClass = KClass_(Token_typeLiteral(tokenSuperClass)); if(KClass_Is(Final, superClass)) { KReturn(SUGAR MessageNode(kctx, stmt, NULL, ns, ErrTag, "%s is final", KClass_text(superClass))); } if(KClass_Is(Virtual, superClass)) { KReturn(SUGAR MessageNode(kctx, stmt, NULL, ns, ErrTag, "%s is still virtual", KClass_text(superClass))); } } size_t initsize = (block != NULL) ? declsize : initFieldSizeOfVirtualClass(superClass); KClass_InitField(kctx, definedClass, superClass, initsize); } else { if(declsize > 0 && !KClass_Is(Virtual, definedClass)) { KReturn(SUGAR MessageNode(kctx, stmt, NULL, ns, ErrTag, "%s has already defined", KClass_text(definedClass))); } } if(block != NULL) { if(!kNode_declClassField(kctx, block, ns, definedClass)) { KReturnUnboxValue(false); } KClass_Set(Virtual, definedClass, false); } kToken_SetTypeId(kctx, tokenClassName, ns, definedClass->typeId); kNode_AddMethodDeclNode(kctx, block, tokenClassName, stmt); KReturn(kNode_Type(kctx, stmt, KNode_Done, KType_void)); }
static kbool_t MiniVM_VisitFieldNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk) { ksymbol_t symbol; intptr_t src; KClass *ty; khalfword_t index = (khalfword_t)(node->index); khalfword_t xindex = (khalfword_t)(node->index >> (sizeof(khalfword_t)*8)); assert(IS_Token(node->TermToken)); symbol = node->TermToken->symbol; if((src = MiniVMBuilder_FindLocalVar(kctx, builder, symbol, KType_Object, index)) == -1) { src = AddLocal(kctx, builder, index, symbol, KType_Object); } ty = KClass_(node->typeAttr); ASM(NMOVx, TC_(builder->stackbase, ty), OC_(src), xindex, ty); builder->Value = builder->stackbase; return true; }
static kbool_t KClass_AddField(KonohaContext *kctx, KClass *ct, ktypeattr_t typeattr, ksymbol_t sym) { kuhalfword_t pos = ct->fieldsize; if(unlikely(ct->classMethodList == K_EMPTYARRAY)) { ((KClassVar *)ct)->classMethodList = new_(MethodArray, 8, OnGlobalConstList); /*FIXME WriteBarrier */ } INIT_GCSTACK(); if(pos < ct->fieldAllocSize) { KClassVar *definedClass = (KClassVar *)ct; definedClass->fieldsize += 1; definedClass->fieldItems[pos].name = sym; if(KType_Is(UnboxType, typeattr)) { definedClass->defaultNullValueVar->fieldUnboxItems[pos] = 0; definedClass->fieldItems[pos].typeAttr = typeattr; } else { kObjectVar *o = definedClass->defaultNullValueVar; KFieldSet(o, o->fieldObjectItems[pos], KLIB Knull(kctx, KClass_(typeattr))); definedClass->fieldItems[pos].typeAttr = typeattr | KTypeAttr_Boxed; } if(1/*KHalfFlag_Is(flag, kField_Getter)*/) { kMethod *mtd = new_FieldGetter(kctx, _GcStack, definedClass->typeId, sym, KTypeAttr_Unmask(typeattr), pos); KLIB kArray_Add(kctx, ct->classMethodList, mtd); } if(!KTypeAttr_Is(ReadOnly, typeattr)/*KHalfFlag_Is(flag, kField_Setter)*/) { kMethod *mtd = new_FieldSetter(kctx, _GcStack, definedClass->typeId, sym, KTypeAttr_Unmask(typeattr), pos); KLIB kArray_Add(kctx, ct->classMethodList, mtd); } } else { if(1/*KHalfFlag_Is(flag, kField_Getter)*/) { kMethod *mtd = new_PrototypeGetter(kctx, _GcStack, ct->typeId, sym, KTypeAttr_Unmask(typeattr)); KLIB kArray_Add(kctx, ct->classMethodList, mtd); } if(!KTypeAttr_Is(ReadOnly, typeattr)/*KHalfFlag_Is(flag, kField_Setter)*/) { kMethod *mtd = new_PrototypeSetter(kctx, _GcStack, ct->typeId, sym, KTypeAttr_Unmask(typeattr)); KLIB kArray_Add(kctx, ct->classMethodList, mtd); } } RESET_GCSTACK(); return true; }