Class* Class::s_allocate(STATE) { Class* klass = as<Class>(state->memory()->new_object<Class>(state, G(klass))); klass->type_info(state->memory()->type_info[ObjectType]); return klass; }
static void emit(Class& emitter, R(Class::*function)(FArgs...), Args&&... args) { emitter.invoke(function, std::forward<Args>(args)...); }
int main() { // Basic usage as function parameters that are return values. { int i = 0; byref(i); assert(i == 1); } /* References have the same address of the variables. Therefore: - if declared inside the same function as the value, no extra memory / dereferencing needs to be used for references, the compiler can figure everything out at compile time. - if declared as function arguments, references may be implemented as implicit pointers passing, sharing therefore the disadvantages of pointers. Therefore, if you want to be sure of efficiency, pass built-in types by value and not by reference. */ { // They have the same address. { int i = 0; //int& ia = i; int& ia = i; ia = 1; assert(i == 1); assert(&i == &ia); } /* For the same reason, it is possible to initialize a reference from another reference. */ { int i = 0; int& ia = i; int& ia2 = ia; ia2 = 2; assert(i == 2); } } /* ERROR: Must not initialize non-const ref with a rvalue. Can however do that for const references. The same goes for function parameters. */ { //int& ia = 0; //std::string& s = getString(); const std::string& s = getString(); //byref(1); } /* ERROR: references must be initialized imediatelly otherwise, how can they be initalized in the future? For references in constructors, they must be initialized at the initialization list. */ { //int& ia; } /* It is possible to get references from pointers. */ { int i = 0; int* ip = &i; int& ia = *ip; ia = 1; assert(i == 1); // ERROR: & must get a variable/dereferenced pointer, not pointers themselves! { //int& ia = &i; } } /* It is not possible to make an array of references. */ { int i = 1; int j = 2; // ERROR: array of references forbidden //int& is[2] = {i,i}; } /* # const references References that do not allow one to modify the value of the variable. */ { // It is possible to make a const reference from a non-const object. { int i = 1; const int& cia = i; // ERROR: const references cannot be modified //cia = 2; } // It is possible to make a const reference form a const object. { const int ci = 1; const int& cia = ci; // ERROR: const references cannot be modified //cia = 2; } // The rules imposed by the compiler make sure that it is hard // or impossible to cheat references by mistake. { int i = 1; const int& cia = i; // ERROR: invalid conversion //int& ia = cia; // ERROR: invalid conversion //int *ip = &cia; } /* const references can be initialized by rvalues! This cannot be wrong since they cannot be modified, so it is not possible to modify the non-existent variable. In this case what happens is that a simple copy takes place. One case in which this rule is very important is parameter passing to functions. For exapmle, the following would be bad: void f(int& i) { i++; } ... f(1); //does not compile and is impossible, but: void f(const int& i) { //i++; //impossible } f(1); is ok, since it is impossible to change i in the function if it is const */ { // Initialization from a literal. { const int& i = 1; assert(i == 1); } /* Initialization from a non-reference function return. Functions that return references return lvalues, so an example with such a function would not be meaningful. */ { const int& i = getInt(); assert(i == 0); } /* # Lifetime extension If you assign a const reference to the return of a function, it extends the lifetime of the returned object. Note that not every const reference extends lifetime, e.g. arguments don't. - http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ - http://stackoverflow.com/questions/2784262/does-a-const-reference-prolong-the-life-of-a-temporary - http://stackoverflow.com/questions/2615162/return-value-not-a-reference-from-the-function-bound-to-a-const-reference-in */ { struct C { static std::string f() { return "abc"; } }; const std::string& s = C::f(); assert(s == "abc"); } } } /* # Reference to pointer Like for other variable, references can be made to pointer variables. */ { { int i = 0; int j = 1; int *ip = &i; int *jp = &j; int*& ipa = ip; int*& jpa = jp; jpa = ip; //now `jp` is the same as `ip`! *jp = 2; assert(i == 2); //therefore modifying what `jp` points to modifies `i`! // ERROR: makes no sense: cannot have a pointer to `int&` //int&* ipaBad = ip; // ERROR: `&i` is an rvalue. Cannot initialize a non const reference to it. //int&* ipaBad = &i; } /* # Reference to pointer and const Just like for pointers to pointers in C, the rules prevent `const` variables from being modified. */ { /* Obviously, cannot remove const qualifiers, or it would be easy to modify constants. */ { const int c = 0; const int *ip = &c; //int *&ipa = ip; //int *ipa = ip; //*ipa = 1; } /* `const int*& = int*` initialization fails for the same reason that `const int* = (int*)` fails in C: this would allow for constant modification. */ { //If (1) were possible below, then it would be possible to change the value of the constant c. { /* int *ip = NULL; const int*& ipa = ip; // (1) THIS is not possible const int c = 0; ipa = &c; // OK because ipa is const. `ip` points to `c` *ip = 1; // OK because ip is not const */ } /* This is different without the reference, because in this case it would not be possible to change the const variable. Just like in C, the issues only show up in pointer dimensions > 1, and the reference behaves like a pointer. */ { int *ip = NULL; const int* ipa = ip; // (1) THIS is ok without the reference, a new pointer is created const int c = 0; ipa = &c; // OK because ipa is const. ip still points to NULL //*ip = 1; // does not change the constant, ip still points to NULL } } } /* What to do if: - a function modifies what pointers point to but not the object pointed to. It therefore takes - we want to pass pointers to that function, modify what they point to, and then outside of the function modify the object being pointed to? Is this a valid use case for `const_cast`? */ { // The motivation: functions. { int i = 0; int j = 1; int *ip = &i; int *jp = &j; // If those were const, the function call would work, // but not the `*ip = 2`; //const int *ip = &i; //const int *jp = &j; // Cannot initialize `const int*&` with `int*&`. //bypointerConst(ip, jp); *ip = 2; //assert(j == 2); } // Same problem simplified without functions. { int i = 0; int *ip = &i; // Possible. //int*& ipa = ip; // TODO why is this not possible. //const int*& ipa = ip; } // But this is possible? { int i = 0; const int& ia = i; } } } /* Single line initialization syntax. Like the pointer symbol `*`, the reference symbol `&` needs to be duplicated for each new reference variable. */ { // OK: both ia and ja are references { int i = 1; int j = 2; int &ia = i, &ja = j; ia = -1; ja = -2; assert(i == -1); assert(j == -2); } // Bad: ja is a new int, not a reference { int i = 1; int j = 2; int& ia = i, ja = j; ia = -1; ja = -2; assert(i == -1); assert(j == 2); } // With references to pointers it looks like this. { int i = 0; int j = 1; int *ip = &i; int *jp = &j; int *& ipa = ip, *& jpa = jp; jpa = ip; *jp = 2; assert(i == 2); } } /* # return reference from function Just like for pointers, you have to watch scope. If the original object dies, you get a dangling reference. - http://stackoverflow.com/questions/752658/is-the-practice-of-returning-a-c-reference-variable-evil There is also some rule about const local references: - http://stackoverflow.com/questions/2784262/does-a-const-reference-prolong-the-life-of-a-temporary */ { /* One simple case in which lifetime is simple to guarantee is returning members from objects which the callee owns. For example: */ { Class c; int& ia = c.getRefIPublic(); ia = 0; assert(c.iPublic == 0); ia = 1; assert(c.iPublic == 1); } // You can modify a private if you non-const reference to it { Class c; int& ia = c.getPrivateRef(); ia = 0; assert(c.getPrivateRef() == 0); ia = 1; assert(c.getPrivateRef() == 1); } // If the reference is const it does not work anymore. { Class c; { const int& ia = c.getPrivateConstRef(); //ia = 1; } // ERROR: invalid initialization { //int& ia = c.getPrivateConstRef(); } } /* In C, all functions return rvalues, although if a function returns a pointer and that pointer is dereferenced it becomes an lvalue, so the following works: (*ret_int_ptr()) = 1; In C++, there is an exception: all functions that return references return lvalues directly. */ { // OK the returned i reference is not local struct C { static int& f(int& i) { i++; return i; } }; int i = 0; (C::f(i)) = 2; assert(i == 2); } } }
void JIT_execute_method_default(JIT_Handle jh, jmethodID methodID, jvalue *return_value, jvalue *args) { //assert(("Doesn't compile", 0)); //abort(); #if 1 Method *meth = (Method*) methodID; assert(!hythread_is_suspend_enabled()); void *entry_point = meth->get_code_addr(); int nargs = meth->get_num_args(); uint64 arg_words[255]; int double_nargs = 0; double double_args[8]; int num_arg_words = 0; int arg_num = 0; int num_ref_args = 0; Arg_List_Iterator iter = meth->get_argument_list(); uint64 i64; Java_Type typ; char msg[300]; if(!meth->is_static()) { ObjectHandle h = (ObjectHandle) args[arg_num++].l; // this pointer i64 = 0; if (h) i64 = (uint64) h->object; if (VM_Global_State::loader_env->compress_references) { // 20030318 We are in unmanaged code where null is represented by 0/NULL. Convert a null reference // to the representation of null in managed code (heap_base). if (i64 == 0) { i64 = (uint64)VM_Global_State::loader_env->heap_base; } } arg_words[num_arg_words++] = i64; num_ref_args++; } while((typ = curr_arg(iter)) != JAVA_TYPE_END) { ObjectHandle h; *msg = '\0'; switch(typ) { case JAVA_TYPE_LONG: i64 = args[arg_num++].j; arg_words[num_arg_words++] = i64; break; case JAVA_TYPE_CLASS: case JAVA_TYPE_ARRAY: h = (ObjectHandle) args[arg_num++].l; i64 = 0; if (h) i64 = (uint64) h->object; if (VM_Global_State::loader_env->compress_references) { // 20030318 We are in unmanaged code where null is represented by 0/NULL. Convert a null reference // to the representation of null in managed code (heap_base). if (i64 == 0) { i64 = (uint64)VM_Global_State::loader_env->heap_base; } } arg_words[num_arg_words++] = i64; num_ref_args++; #ifdef _DEBUG { if (! VM_Global_State::loader_env->compress_references || i64 != (uint64)VM_Global_State::loader_env->heap_base) { ManagedObject *object = (ManagedObject *)i64; if(object) { Class *clss = object->vt()->clss; sprintf(msg, " of class '%s'", clss->get_name()->bytes); } } } #endif break; case JAVA_TYPE_SHORT: i64 = (uint64)args[arg_num++].s; arg_words[num_arg_words++] = i64; break; case JAVA_TYPE_CHAR: i64 = (uint64)args[arg_num++].c; arg_words[num_arg_words++] = i64; break; case JAVA_TYPE_BYTE: i64 = (uint64)args[arg_num++].b; arg_words[num_arg_words++] = i64; break; case JAVA_TYPE_BOOLEAN: i64 = (uint64)args[arg_num++].z; arg_words[num_arg_words++] = i64; break; case JAVA_TYPE_DOUBLE: double_args[double_nargs] = args[arg_num++].d; double_nargs++; break; case JAVA_TYPE_FLOAT: double_args[double_nargs] = (double)args[arg_num++].f; double_nargs++; break; default: i64 = (uint64)args[arg_num++].i; arg_words[num_arg_words++] = i64; break; } iter = advance_arg_iterator(iter); } // assert(nargs <= 8); double double_result; static void* addr_execute = get_vm_execute_java_method(); struct{ void* fun; void* gp; } fptr; fptr.fun = addr_execute; fptr.gp = get_vm_gp_value(); // gashiman - changed _cdecl to __cdecl to work on linux uint64 (__cdecl *fpp_exec)(void *entry_point, int nargs, uint64 args[], double *double_result_addr, int double_nargs, double double_args[], void *thread_pointer, uint64 tid) = (uint64 (__cdecl * )(void *entry_point, int nargs, uint64 args[], double *double_result_addr, int double_nargs, double double_args[], void *thread_pointer, uint64 tid))&fptr; IDATA id = hythread_get_self_id(); uint64 int_result = (uint64)fpp_exec(entry_point, nargs, arg_words, &double_result, double_nargs, double_args, p_TLS_vmthread, id); // Save the result Java_Type ret_type = meth->get_return_java_type(); switch(ret_type) { case JAVA_TYPE_VOID: break; case JAVA_TYPE_ARRAY: case JAVA_TYPE_CLASS: { ObjectHandle h = 0; if (VM_Global_State::loader_env->compress_references) { // 20030318 Convert a null reference in managed code (represented by heap_base) // to the representation of null in unmanaged code (0 or NULL). if ((uint64)int_result == (uint64)VM_Global_State::loader_env->heap_base) { int_result = 0; } } if (int_result) { h = oh_allocate_local_handle(); h->object = (ManagedObject*) int_result; } return_value->l = h; } break; case JAVA_TYPE_LONG: return_value->j = int_result; break; case JAVA_TYPE_INT: *((I_32 *)return_value) = (I_32) int_result; break; case JAVA_TYPE_SHORT: *((int16 *)return_value) = (int16) int_result; break; case JAVA_TYPE_CHAR: *((uint16 *)return_value) = (uint16) int_result; break; case JAVA_TYPE_BYTE: *((I_8 *)return_value) = (I_8) int_result; break; case JAVA_TYPE_BOOLEAN: *((U_8 *)return_value) = (U_8) int_result; break; case JAVA_TYPE_DOUBLE: *((double *)return_value) = double_result; break; case JAVA_TYPE_FLOAT: *((float *)return_value) = (float) double_result; break; default: #ifdef _DEBUG std::clog << "Returned to C from " << meth->get_class()->get_name()->bytes << "." << meth->get_name()->bytes << meth->get_descriptor()->bytes << "\n"; #endif //DIE("Return type ");// << (int)ret_type << " is not implemented\n"); std::clog << "Return type " << (int)ret_type << " is not implemented\n"; } #endif } //vm_execute_java_method_array
static inline StrNR ctxClassName() { Class* ctx = g_context->getContextClass(); return ctx ? ctx->nameStr() : StrNR(staticEmptyString()); }
void Converter::init(STATE) { Class* cls = ontology::new_class_under(state, "Converter", G(encoding)); cls->set_const(state, "INVALID_MASK", Fixnum::from(ECONV_INVALID_MASK)); cls->set_const(state, "INVALID_REPLACE", Fixnum::from(ECONV_INVALID_REPLACE)); cls->set_const(state, "UNDEF_MASK", Fixnum::from(ECONV_UNDEF_MASK)); cls->set_const(state, "UNDEF_REPLACE", Fixnum::from(ECONV_UNDEF_REPLACE)); cls->set_const(state, "UNDEF_HEX_CHARREF", Fixnum::from(ECONV_UNDEF_HEX_CHARREF)); cls->set_const(state, "PARTIAL_INPUT", Fixnum::from(ECONV_PARTIAL_INPUT)); cls->set_const(state, "AFTER_OUTPUT", Fixnum::from(ECONV_AFTER_OUTPUT)); cls->set_const(state, "UNIVERSAL_NEWLINE_DECORATOR", Fixnum::from(ECONV_UNIVERSAL_NEWLINE_DECORATOR)); cls->set_const(state, "CRLF_NEWLINE_DECORATOR", Fixnum::from(ECONV_CRLF_NEWLINE_DECORATOR)); cls->set_const(state, "CR_NEWLINE_DECORATOR", Fixnum::from(ECONV_CR_NEWLINE_DECORATOR)); cls->set_const(state, "XML_TEXT_DECORATOR", Fixnum::from(ECONV_XML_TEXT_DECORATOR)); cls->set_const(state, "XML_ATTR_CONTENT_DECORATOR", Fixnum::from(ECONV_XML_ATTR_CONTENT_DECORATOR)); cls->set_const(state, "XML_ATTR_QUOTE_DECORATOR", Fixnum::from(ECONV_XML_ATTR_QUOTE_DECORATOR)); }
void ClassTestSuite::testClass() { //Class test = ClassOf<Test1>(); Class test = Class::lookup("ClassTest::Test1"); TS_ASSERT_EQUALS(test.simpleName(), "Test1"); #ifndef NO_RTTI TS_ASSERT(test.describes<ClassTest::Test1>()) Class test2 = Class::lookup(typeid(ClassTest::Test1)); TS_ASSERT_EQUALS(test2.simpleName(), "Test1"); TS_ASSERT_EQUALS(test, test2); #endif Class::ClassList superClasses = test.superclasses(); TS_ASSERT_EQUALS(superClasses.size(), 2); Class base1; Class base2; TS_ASSERT_THROWS(base1.simpleName(), std::runtime_error); // uninitialized handle for(const Class& c: superClasses) { if (c.fullyQualifiedName() == "ClassTest::TestBase1") { base1 = c; } else if (c.fullyQualifiedName() == "ClassTest::TestBase2") { base2 = c; } } TS_ASSERT_EQUALS(base1.fullyQualifiedName(), "ClassTest::TestBase1"); TS_ASSERT_EQUALS(base1.simpleName(), "TestBase1"); TS_ASSERT_EQUALS(base2.fullyQualifiedName(), "ClassTest::TestBase2"); TS_ASSERT_EQUALS(base2.simpleName(), "TestBase2"); TS_ASSERT(inheritanceRelation(test, base1)); TS_ASSERT(inherits(test, base1)); TS_ASSERT(inheritedBy(base1, test)); TS_ASSERT(inheritanceRelation(test, base2)); TS_ASSERT(inherits(test, base2)); TS_ASSERT(inheritedBy(base2, test)); TS_ASSERT(!inheritanceRelation(base1, base2)); Class::ConstructorList base1Constructors = base1.constructors(); TS_ASSERT_EQUALS(base1.constructors().size(), 1); Constructor base1Constructor = base1Constructors.front(); TS_ASSERT_EQUALS(base1Constructor.numberOfArguments(), 0); TS_ASSERT_THROWS(base1Constructor.call(), std::runtime_error); // abstract class Class::ConstructorList base2Constructors = base2.constructors(); TS_ASSERT_EQUALS(base2.constructors().size(), 1); Constructor base2Constructor = base2Constructors.front(); TS_ASSERT_EQUALS(base2Constructor.numberOfArguments(), 0); VariantValue b2Inst = base2Constructor.call(); TS_ASSERT(b2Inst.isValid()); TS_ASSERT_EQUALS(base2.attributes().size(), 0); Class::MethodList base2Methods = base2.methods(); TS_ASSERT_EQUALS(base2Methods.size(), 1); Method base2Method1 = base2Methods.front(); TS_ASSERT_EQUALS(base2Method1.name(), "base2Method1"); TS_ASSERT(base2Method1.isConst()); TS_ASSERT(!base2Method1.isVolatile()); TS_ASSERT(!base2Method1.isStatic()); TS_ASSERT_EQUALS(base2Method1.numberOfArguments(), 0); TS_ASSERT_EQUALS(base2Method1.call(b2Inst).value<int>(), 6); Class::ConstructorList testConstructors = test.constructors(); Class::AttributeList attributes = test.attributes(); TS_ASSERT_EQUALS(attributes.size(), 2); Attribute attr = attributes.front(); WITH_RTTI(TS_ASSERT(attr.type() == typeid(int))); TS_ASSERT_EQUALS(testConstructors.size(), 3); Constructor defaultConstr; Constructor intConstr; TS_ASSERT_THROWS(defaultConstr.argumentSpellings(), std::runtime_error); for (const Constructor& c: testConstructors) { if (c.numberOfArguments() == 0) { defaultConstr = c; } else if (c.numberOfArguments() == 1 && c.argumentSpellings()[0] == "int"){ intConstr = c; } } TS_ASSERT_EQUALS(defaultConstr.numberOfArguments(), 0); TS_ASSERT_EQUALS(intConstr.numberOfArguments(), 1); VariantValue testInst1 = defaultConstr.call(); TS_ASSERT(testInst1.isA<Test1>()); #ifndef NO_RTTI Class test3 = Class::lookup(testInst1.typeId()); TS_ASSERT_EQUALS(test3.simpleName(), "Test1"); TS_ASSERT_EQUALS(test, test3); #endif TS_ASSERT_EQUALS(attr.get(testInst1).value<const int&>(), 3); VariantValue testInst2 = intConstr.call(77); TS_ASSERT(testInst2.isA<Test1>()); TS_ASSERT_EQUALS(attr.get(testInst2).value<const int&>(), 77); Class::MethodList methods = test.methods(); TS_ASSERT_EQUALS(methods.size(), 9); Method base1Method1; Method method1; Method method2; Method staticMethod; for (const Method& m: methods) { if (m.name() == "base1Method1") { base1Method1 = m; } else if (m.name() == "base2Method1") { base2Method1 = m; } else if (m.name() == "method1") { method1 = m; } else if (m.name() == "method2") { method2 = m; } else if (m.name() == "staticMethod") { staticMethod = m; } } TS_ASSERT_EQUALS(base1Method1.name(), "base1Method1"); TS_ASSERT(!base1Method1.isConst()); TS_ASSERT(!base1Method1.isStatic()); TS_ASSERT(!base1Method1.isVolatile()); WITH_RTTI(TS_ASSERT(base1Method1.returnType() == typeid(int))); TS_ASSERT_EQUALS(base1Method1.numberOfArguments(), 0); TS_ASSERT_EQUALS(base1Method1.call(testInst2).value<int>(), 5); TS_ASSERT_EQUALS(base2Method1.name(), "base2Method1"); TS_ASSERT(base2Method1.isConst()); TS_ASSERT(!base2Method1.isStatic()); TS_ASSERT(!base2Method1.isVolatile()); WITH_RTTI(TS_ASSERT(base2Method1.returnType() == typeid(int))); TS_ASSERT_EQUALS(base2Method1.numberOfArguments(), 0); TS_ASSERT_EQUALS(base2Method1.call(testInst2).value<int>(), 6); TS_ASSERT_EQUALS(method2.name(), "method2"); TS_ASSERT(!method2.isConst()); TS_ASSERT(!method2.isStatic()); TS_ASSERT(!method2.isVolatile()); WITH_RTTI(TS_ASSERT(method2.returnType() == typeid(double))); TS_ASSERT_EQUALS(method2.numberOfArguments(), 1); WITH_RTTI(TS_ASSERT(*method2.argumentTypes()[0] == typeid(double))); TS_ASSERT_EQUALS(method2.call(testInst2, 2).value<double>(), 6.28); TS_ASSERT_EQUALS(staticMethod.name(), "staticMethod"); TS_ASSERT(!staticMethod.isConst()); TS_ASSERT(staticMethod.isStatic()); TS_ASSERT(!staticMethod.isVolatile()); WITH_RTTI(TS_ASSERT(staticMethod.returnType() == typeid(double))); TS_ASSERT_EQUALS(staticMethod.numberOfArguments(), 0); TS_ASSERT_EQUALS(staticMethod.call().value<double>(), 3.14); ClassTest::Test1 t(666); VariantValue inst3; inst3.construct<ClassTest::TestBase1&>(t); TS_ASSERT_THROWS_ANYTHING(method1.call(inst3).value<string>()); VariantValue inst4 = test.castUp(inst3, base1); TS_ASSERT(inst4.isValid()); bool success = false; ClassTest::Test1& derivedRef = inst4.convertTo<ClassTest::Test1&>(&success); TS_ASSERT(success); TS_ASSERT_EQUALS(derivedRef.attribute1, 666); TS_ASSERT_EQUALS(method1.call(inst4).value<string>(), "this is a test"); Class test_3 = Class::lookup("ClassTest::Test3"); ClassTest::Test3 t2(666); TS_ASSERT_EQUALS(t2.attribute1, 333); TS_ASSERT_EQUALS(t2.attribute3, 666); VariantValue inst5; inst5.construct<ClassTest::TestBase1&>(t2); VariantValue inst6 = test_3.castUp(inst5, base1); TS_ASSERT(inst6.isValid()); success = false; ClassTest::Test3& derivedRef2 = inst6.convertTo<ClassTest::Test3&>(&success); TS_ASSERT(success); TS_ASSERT_EQUALS(derivedRef2.attribute1, 333); TS_ASSERT_EQUALS(derivedRef2.attribute3, 666); t2.attribute1 = 787; t2.attribute3 = 13; TS_ASSERT_EQUALS(derivedRef2.attribute1, 787); TS_ASSERT_EQUALS(derivedRef2.attribute3, 13); ClassTest::Test1 t3(666); VariantValue inst7; inst7.construct<ClassTest::TestBase1&>(t3); VariantValue inst8 = test_3.castUp(inst7, base1); TS_ASSERT(!inst8.isValid()); Class test_2 = Class::lookup("ClassTest::Test2"); VariantValue inst9 = test_2.castUp(inst7, base1); TS_ASSERT(!inst9.isValid()); }
void ClassLoader::resolvePool(Class * thisClass, int nameptr) { int constant_pool_size = thisClass->constantPool->GetSize(); for (int i = 1; i < constant_pool_size; i++) { int item_tag = thisClass->constantPool->get(i)->tag; //DEBUG_PRINT("resolve pool %d %d\n",i,item_tag); switch (item_tag) { case ConstantPoolTag::CONSTANT_Class: { if (thisClass->constantPool->get(i)->classInfo.classPtr == nullptr) { resolveClassPointer(thisClass, i, nameptr); } break;} case ConstantPoolTag::CONSTANT_Fieldref: { //classptr int class_index = thisClass->constantPool->get(i)->fieldInfo.class_index; if (thisClass->constantPool->get(class_index)->classInfo.classPtr == nullptr) { resolveClassPointer(thisClass, class_index, nameptr); } Class * myClass = thisClass->constantPool->get(class_index)->classInfo.classPtr; thisClass->constantPool->setClassPtr(i, myClass); //field ptr //if (myClass != nullptr) //{ int name_index = thisClass->constantPool->get(i)->fieldInfo.name_and_type_index; int descriptor_index = thisClass->constantPool->get(name_index)->nameAndTypeInfo.descriptor_index; name_index = thisClass->constantPool->get(name_index)->nameAndTypeInfo.name_index; Utf8String item_name = Utf8String(thisClass->constantPool->get(name_index)->utf8Info.bytes, thisClass->constantPool->get(name_index)->utf8Info.length); Utf8String item_descriptor = Utf8String(thisClass->constantPool->get(descriptor_index)->utf8Info.bytes, thisClass->constantPool->get(descriptor_index)->utf8Info.length); Field* field = myClass->getField(item_name, item_descriptor); thisClass->constantPool->setFieldPtr(i, field); //} } break; case ConstantPoolTag::CONSTANT_Methodref: { //classptr int class_index = thisClass->constantPool->get(i)->methodInfo.class_index; if (thisClass->constantPool->get(class_index)->classInfo.classPtr == nullptr) { resolveClassPointer(thisClass, class_index , nameptr); } Class * myClass = thisClass->constantPool->get(class_index)->classInfo.classPtr; thisClass->constantPool->setClassPtr(i, myClass); //merhod ptr int name_index = thisClass->constantPool->get(i)->methodInfo.name_and_type_index; int descriptor_index = thisClass->constantPool->get(name_index)->nameAndTypeInfo.descriptor_index; name_index = thisClass->constantPool->get(name_index)->nameAndTypeInfo.name_index; Utf8String item_name = Utf8String(thisClass->constantPool->get(name_index)->utf8Info.bytes, thisClass->constantPool->get(name_index)->utf8Info.length); Utf8String item_descriptor = Utf8String(thisClass->constantPool->get(descriptor_index)->utf8Info.bytes, thisClass->constantPool->get(descriptor_index)->utf8Info.length); if (thisClass->methodArea.getMethod(item_name, item_descriptor) != nullptr) { thisClass->constantPool->setMethodPtr(i, thisClass->methodArea.getMethod(item_name, item_descriptor)); } else if (myClass != nullptr && myClass->methodArea.getMethod(item_name, item_descriptor) != nullptr) { thisClass->constantPool->setMethodPtr(i, myClass->methodArea.getMethod(item_name, item_descriptor)); } break;} case ConstantPoolTag::CONSTANT_InterfaceMethodref: { //classptr int class_index = thisClass->constantPool->get(i)->interfaceMethodInfo.class_index; if (thisClass->constantPool->get(class_index)->classInfo.classPtr == nullptr) { resolveClassPointer(thisClass, class_index,nameptr); } Class * myClass = thisClass->constantPool->get(class_index)->classInfo.classPtr; thisClass->constantPool->setClassPtr(i, myClass); //method ptr //if (myClass != nullptr) //{ int name_index = thisClass->constantPool->get(i)->interfaceMethodInfo.name_and_type_index; int descriptor_index = thisClass->constantPool->get(name_index)->nameAndTypeInfo.descriptor_index; name_index = thisClass->constantPool->get(name_index)->nameAndTypeInfo.name_index; Utf8String item_name = Utf8String(thisClass->constantPool->get(name_index)->utf8Info.bytes, thisClass->constantPool->get(name_index)->utf8Info.length); Utf8String item_descriptor = Utf8String(thisClass->constantPool->get(descriptor_index)->utf8Info.bytes, thisClass->constantPool->get(descriptor_index)->utf8Info.length); if (thisClass->methodArea.getMethod(item_name, item_descriptor) != nullptr) { thisClass->constantPool->setMethodPtr(i, thisClass->methodArea.getMethod(item_name, item_descriptor)); } else if (myClass != nullptr && myClass->methodArea.getMethod(item_name, item_descriptor) != nullptr) { thisClass->constantPool->setMethodPtr(i, myClass->methodArea.getMethod(item_name, item_descriptor)); } //} break;} case ConstantPoolTag::CONSTANT_Double: case ConstantPoolTag::CONSTANT_Long: i++; break; default: break; } } //DEBUG_PRINT("resolving finnished\n"); }
bool doFetchLesson(Class t, ThreadSafeQueue<Class> *classList, std::atomic<int> *totalLessons) { std::string buffer; CURL *curl; CURLcode res; weekAmountList.lock(); int weekAmount = -1; for (int i = 0; i < weekAmountList.size(); i++) { if (weekAmountList.at(i).departmentStringId == t.departmentString() && weekAmountList.at(i).cpath == t.cpath()) { weekAmount = weekAmountList.at(i).amountOfWeeks; break; } } if(weekAmount == -1) printf("ERROR: NOT FOUND: %s - %s\n", t.departmentString().c_str(), t.cpath().c_str()); weekAmountList.unlock(); char postFields[1024] = ""; for (int i = 1; i < weekAmount+1; i++) { int n = sprintf(postFields, "%sweken[]=%d&", postFields, i); postFields[n] = '\0'; } int n = sprintf(postFields, "%ssleutelveld=%s&object=%s&filter=%s", postFields, t.classIdString().c_str(), t.cpath().c_str(), t.departmentString().c_str()); postFields[n] = '\0'; //printf("%s\n", postFields); curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, "https://rooster.nhl.nl/1516/rooster.php"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields); //curl_easy_setopt(curl, CURLOPT_REFERER, NHL_REFERER); curl_easy_setopt(curl, CURLOPT_TIMEOUT, CURL_TIMEOUT); // 5 sec time out on whole request curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, CURL_CONNECT_TIMEOUT); // 10 sec connect time out res = curl_easy_perform(curl); //printf("------\n%s------\n\n", buffer.c_str()); if (res == CURLE_OK) { GumboOutput* output = gumbo_parse(buffer.c_str()); GumboNode* node = GetTBodyNode(output->root); if (node == NULL) { if (t.cpath() == "ttstud"){ printf("[%s] FAIL(%s-%s-%s)\n", currentDateTime().c_str(), t.className().c_str(), t.departmentString().c_str(), t.cpath().c_str()); curl_easy_cleanup(curl); } else{ printf("[%s] FAIL(%s-%s-%s), aborting program\n", currentDateTime().c_str(), t.className().c_str(), t.departmentString().c_str(), t.cpath().c_str()); curl_easy_cleanup(curl); exit(1); } return true; } GumboVector* children = &node->v.element.children; bool newDay = false; int lessonAmount = 0; int yearOffset = -1; int titleOffset = -1; int locationOffset = -1; int teacherOffset = -1; int typeOffset = -1; int commentOffset = -1; int endOffset = -1; std::string date; char dayName[128]; int day; int month; int year; for (unsigned int i = 0; i < children->length; ++i) { GumboNode *node1 = static_cast<GumboNode*>(children->data[i]); if (node1->v.element.tag == GUMBO_TAG_TR){ GumboAttribute *att = gumbo_get_attribute(&node1->v.element.attributes, "class"); if (att) { //printf("TR CLASS: %s\n", att->value); std::string value = att->value; if (value == "datarij") { std::string yearType = ""; GumboNode *startTimeNode = static_cast<GumboNode*>(node1->v.element.children.data[0]); std::string endDate = ""; if (endOffset != -1) { GumboNode *endTimeNode = static_cast<GumboNode*>(node1->v.element.children.data[endOffset]); endDate = GetTextFromElement(endTimeNode); } if (yearOffset != -1) { GumboNode *yearNode = static_cast<GumboNode*>(node1->v.element.children.data[yearOffset]); // optional if (yearNode) yearType = GetTextFromElement(yearNode); } std::string typeStr = ""; GumboNode *titleNode = static_cast<GumboNode*>(node1->v.element.children.data[titleOffset]); GumboNode *locationNode = static_cast<GumboNode*>(node1->v.element.children.data[locationOffset]); std::string teacher = ""; if (teacherOffset != -1) { GumboNode *teacherNode = static_cast<GumboNode*>(node1->v.element.children.data[teacherOffset]); teacher = GetTextFromElement(teacherNode); } //if(teacher == "" && t.departmentString() == "TEE" && t.cpath() == "stud"){ //printf("Teacher empty: %s - %s\n", GetTextFromElement(titleNode).c_str(), GetTextFromElement(startTimeNode).c_str()); //printf("Buffer:\n%s\n----\n", buffer.c_str()); //} //printf("%s\n", teacher.c_str()); if (typeOffset != -1) { GumboNode *typeNode = static_cast<GumboNode*>(node1->v.element.children.data[typeOffset]); typeStr = GetTextFromElement(typeNode); } GumboNode *commentsNode = static_cast<GumboNode*>(node1->v.element.children.data[commentOffset]); std::string startDate = GetTextFromElement(startTimeNode); int startHour; int startMinute; sscanf(startDate.c_str(), "%02d:%02d", &startHour, &startMinute); char newStartDate[128]; //YYYY-MM-DDTHH:MM:SS int n = sprintf(newStartDate, "%04d-%02d-%02dT%02d:%02d:00", year, month, day, startHour, startMinute); newStartDate[n] = '\0'; char newEndDate[128]; if (endDate != "") { int endHour; int endMinute; sscanf(endDate.c_str(), "%02d:%02d", &endHour, &endMinute); //YYYY-MM-DDTHH:MM:SS int ne = sprintf(newEndDate, "%04d-%02d-%02dT%02d:%02d:00", year, month, day, endHour, endMinute); newEndDate[ne] = '\0'; }else newEndDate[0] = '\0'; //printf("%s - %s - %s - %s - %s (YEAR: %s)\n", GetTextFromElement(titleNode).c_str(), newStartDate, newEndDate, GetTextFromElement(teacherNode).c_str(), GetTextFromElement(locationNode).c_str(), yearType.c_str()); int weekNr = getWeekNrFromDate(newStartDate); // Calculate time difference to remove old lessons time_t timeStampThisWeek = getTimeStampFromDate(newStartDate); time_t timeStampCurrentWeek; time(&timeStampCurrentWeek); //printf("Current week: %d - Lesson week: %d\n", getCurrentWeekNumber(), weekNr); double diff = difftime(timeStampThisWeek, timeStampCurrentWeek); double weeks = diff / 604800; //printf("Time difference: %.f\n", weeks); if (weeks > -2) { // ignore old lessons t.addLesson(shared_ptr<Lesson>(new Lesson(GetTextFromElement(titleNode), GetTextFromElement(commentsNode), teacher, replaceAll(GetTextFromElement(locationNode), " ", ", "), newStartDate, newEndDate, weekNr, yearType, typeStr))); ++*totalLessons; } lessonAmount++; } else if (value == "weekheader") { yearOffset = -1; titleOffset = -1; locationOffset = -1; teacherOffset = -1; typeOffset = -1; commentOffset = -1; GumboVector* children = &node1->v.element.children; for (unsigned int i = 0; i < children->length; ++i) { GumboNode *child = static_cast<GumboNode*>(children->data[i]); std::string text = GetTextFromElement(child); if (text == "jaar") yearOffset = i; else if (text == "activiteit") titleOffset = i; else if (text == "lokaal") locationOffset = i; else if (text == "docent(en)" || text == "klas(en)") teacherOffset = i; else if (text == "werkvorm") typeOffset = i; else if (text == "opmerkingen") commentOffset = i; else if (text == "eind") endOffset = i; } } } else { // no class GumboNode *td = static_cast<GumboNode*>(node1->v.element.children.data[0]); if (td->v.element.tag == GUMBO_TAG_TD) { GumboAttribute *classAtt = gumbo_get_attribute(&td->v.element.attributes, "class"); if (classAtt) { std::string dayRow = classAtt->value; if (dayRow == "dagrij") { GumboNode *dateNode = static_cast<GumboNode*>(td->v.element.children.data[0]); date = dateNode->v.text.text; // get date with sscanf sscanf(date.c_str(), "%s %02d-%02d-%04d", &dayName, &day, &month, &year); //printf("New day @ %s\n", date.c_str()); } } } } } } //printf("Lessons: %d\n", lessonAmount); gumbo_destroy_output(&kGumboDefaultOptions, output); curl_easy_cleanup(curl); classList->lock(); classList->push(t); classList->unlock(); return true; } else{ //printf("[%s] Fail: %s, aborting program", currentDateTime().c_str(), curl_easy_strerror(res)); curl_easy_cleanup(curl); //exit(1); return false; } /* New ICAL style as of semester starting at 01-09-2015 */ /* icalcomponent *rootNode = icalparser_parse_string(cstr); icalcomponent *comp = icalcomponent_get_first_component(rootNode, ICAL_VEVENT_COMPONENT); //icalcomponent *zoneComp = icalcomponent_get_first_component(rootNode, ICAL_VTIMEZONE_COMPONENT); //icaltimezone *zone = icaltimezone_get_builtin_timezone("Europe/Amsterdam"); //icalcomponent *next = icalcomponent_get_next_component(rootNode, ICAL_VEVENT_COMPONENT); while (comp != NULL){ //printf("%s\n", icalcomponent_as_ical_string(comp)); std::string summary = icalcomponent_get_summary(comp); icaltimetype dtstart = icalcomponent_get_dtstart(comp); std::string starttime = formatDateTime(getTimeStampFromDateAlt(icaltime_as_ical_string(dtstart))); icaltimetype dtend = icalcomponent_get_dtend(comp); std::string endtime = formatDateTime(getTimeStampFromDateAlt(icaltime_as_ical_string(dtend))); const char *locationStr = icalcomponent_get_location(comp); // can be null std::string location = ""; if (locationStr){ location = locationStr; location = replaceAll(location, " ", ", "); } std::string commentStr = (char *)icalcomponent_get_comment(comp); printf("Comment: %s\n", commentStr.c_str()); char *comment = (char *)commentStr.c_str(); char *line = strtok(comment, "\n"); std::string docenten; while (line != NULL){ if (strstr(line, "Docent(en): ")){ line += 12; // 12 is length of Docent(en) int length = strlen(line); docenten = line; } line = strtok(NULL, "\n"); } int weekNr = getWeekNrFromDate(starttime); //printf("%s - %s\n", summary.c_str(), starttime.c_str()); if (weekNr > getCurrentWeekNumber() - 2) { // ignore old lessons t.addLesson(shared_ptr<Lesson>(new Lesson(summary, summary, docenten, location, starttime, endtime, weekNr))); printf("1Add Lesson(%s): %s - %s - %s - %s(%s)\n", t.className().c_str(), summary.c_str(), starttime.c_str(), endtime.c_str(), docenten.c_str(), commentStr.c_str()); } icalcomponent_free(comp); comp = icalcomponent_get_next_component(rootNode, ICAL_VEVENT_COMPONENT); } icalcomponent_free(comp); icalcomponent_free(rootNode); classList->lock(); classList->push(t); classList->unlock(); */ // delete our garbage //delete[] refererUrlBuffer; //delete[] urlBuffer; //delete[] cstr; //curl_free(classIdStringEscaped); //curl_easy_cleanup(curl); //return true; /* Old XML Style xml_document<> doc; doc.parse<0>(cstr); xml_node<> *pRoot = doc.first_node(); if (pRoot == 0) { std::cout << "doFetchLesson() ERROR: Invalid rootnode" << std::endl; exit(1); // Immediately abort program as the document is unreadable } else if (pRoot != NULL) { pRoot = pRoot->first_node(); if (pRoot == 0) { std::cout << "doFetchLesson() ERROR: Rootnode has an invalid first node" << std::endl; exit(1); // Immediately abort program as the document is unreadable } } for (xml_node<> *pNode = pRoot->first_node("item"); pNode; pNode = pNode->next_sibling()) { std::string title = pNode->first_node("title") ? pNode->first_node("title")->value() : ""; if (title.length() > 2) title = title.substr(title.find(": ") + 2, title.length()); std::string description = pNode->first_node("description") ? pNode->first_node("description")->value() : ""; std::string teacher = getStringBetween(" - ", " -", description, "([a-zA-Z,. ]+)"); std::string location = pNode->first_node("ev:location") ? pNode->first_node("ev:location")->value() : ""; location = trim(location); char *locationDecoded = curl_easy_unescape(curl, location.c_str(), 0, NULL); location = std::string(locationDecoded); curl_free(locationDecoded); std::string startdate = pNode->first_node("ev:startdate") ? pNode->first_node("ev:startdate")->value() : ""; std::string enddate = pNode->first_node("ev:enddate") ? pNode->first_node("ev:enddate")->value() : ""; int weekNr = getWeekNrFromDate(startdate); if (weekNr > getCurrentWeekNumber() - 2) // ignore old lessons t.addLesson(shared_ptr<Lesson>(new Lesson(title, description, teacher, location, startdate, enddate, weekNr))); } // ready to push back the class classList->lock(); classList->push_back(t); classList->unlock(); // delete our garbage delete[] refererUrlBuffer; delete[] urlBuffer; delete[] cstr; curl_free(classIdStringEscaped); curl_easy_cleanup(curl); return true;*/ }
void Util::preparse(QSet<Type*> *usedTypes, QSet<const Class*> *superClasses, const QList<QString>& keys) { Class& globalSpace = classes["QGlobalSpace"]; globalSpace.setName("QGlobalSpace"); globalSpace.setKind(Class::Kind_Class); globalSpace.setIsNameSpace(true); // add all functions as methods to a class called 'QGlobalSpace' or a class that represents a namespace for (QHash<QString, Function>::const_iterator it = functions.constBegin(); it != functions.constEnd(); it++) { const Function& fn = it.value(); QString fnString = fn.toString(); // gcc doesn't like this function... for whatever reason if (fn.name() == "_IO_ftrylockfile" // functions in named namespaces are covered by the class list - only check for top-level functions here || (fn.nameSpace().isEmpty() && !Options::functionNameIncluded(fn.qualifiedName()) && !Options::functionSignatureIncluded(fnString)) || Options::typeExcluded(fnString)) { // we don't want that function... continue; } Class* parent = &globalSpace; if (!fn.nameSpace().isEmpty()) { parent = &classes[fn.nameSpace()]; if (parent->name().isEmpty()) { parent->setName(fn.nameSpace()); parent->setKind(Class::Kind_Class); parent->setIsNameSpace(true); } } Method meth = Method(parent, fn.name(), fn.type(), Access_public, fn.parameters()); meth.setFlag(Method::Static); parent->appendMethod(meth); // map this method to the function, so we can later retrieve the header it was defined in globalFunctionMap[&parent->methods().last()] = &fn; int methIndex = parent->methods().size() - 1; addOverloads(meth); // handle the methods appended by addOverloads() for (int i = parent->methods().size() - 1; i > methIndex; --i) globalFunctionMap[&parent->methods()[i]] = &fn; (*usedTypes) << meth.type(); foreach (const Parameter& param, meth.parameters()) (*usedTypes) << param.type(); } // all enums that don't have a parent are put under QGlobalSpace, too for (QHash<QString, Enum>::iterator it = enums.begin(); it != enums.end(); it++) { Enum& e = it.value(); if (!e.parent()) { Class* parent = &globalSpace; if (!e.nameSpace().isEmpty()) { parent = &classes[e.nameSpace()]; if (parent->name().isEmpty()) { parent->setName(e.nameSpace()); parent->setKind(Class::Kind_Class); parent->setIsNameSpace(true); } } Type *t = 0; if (e.name().isEmpty()) { // unnamed enum Type longType = Type("long"); longType.setIsIntegral(true); t = Type::registerType(longType); } else { t = Type::registerType(Type(&e)); } (*usedTypes) << t; parent->appendChild(&e); } } foreach (const QString& key, keys) { Class& klass = classes[key]; foreach (const Class::BaseClassSpecifier base, klass.baseClasses()) { superClasses->insert(base.baseClass); } if (!klass.isNameSpace()) { addDefaultConstructor(&klass); addCopyConstructor(&klass); addDestructor(&klass); checkForAbstractClass(&klass); foreach (const Method& m, klass.methods()) { if (m.access() == Access_private) continue; if ((m.type()->getClass() && m.type()->getClass()->access() == Access_private) || Options::typeExcluded(m.toString(false, true))) { klass.methodsRef().removeOne(m); continue; } addOverloads(m); (*usedTypes) << m.type(); foreach (const Parameter& param, m.parameters()) (*usedTypes) << param.type(); } foreach (const Field& f, klass.fields()) { if (f.access() == Access_private) continue; if (Options::typeExcluded(f.toString(false, true))) { klass.fieldsRef().removeOne(f); continue; } } foreach (const Field& f, klass.fields()) { if (f.access() == Access_private) continue; addAccessorMethods(f, usedTypes); } }
Class& Symbols::enterClassScope(const string name) { Class *c = new Class(name, currentScope()); define(*c); enterScope(c->scope()); return *c; }
void ClassInfoModel::SetClassItem(const Class &cClass) { const Class *pClass = &cClass; beginResetModel(); DeleteChilds(m_pCommonCategory); DeleteChilds(m_pAttributeCategory); DeleteChilds(m_pSlotsCategory); DeleteChilds(m_pSignalsCategory); DeleteChilds(m_pPropertiesCategory); DeleteChilds(m_pConstructorsCategory); DeleteChilds(m_pMethodsCategory); // Add common information items new ClassListItem(pClass, NameRole, m_pCommonCategory); new ClassListItem(pClass, DescriptionRole, m_pCommonCategory); // Add attributes const List<VarDesc*> &attr = cClass.GetAttributes(); for (uint32 i=0; i<attr.GetNumOfElements(); ++i) { VarDesc *pVarDesc = attr[i]; new ClassInfoAttributeTreeItem(*pVarDesc, m_pAttributeCategory); } // Add slots const List<EventHandlerDesc*> &cSlots = cClass.GetSlots(); for (uint32 i=0; i<cSlots.GetNumOfElements(); ++i) { EventHandlerDesc *pVarDesc = cSlots[i]; new ClassInfoMemberWithSignatureDescTreeItem<EventHandlerDesc>(tr("Slot"), *pVarDesc, m_pSlotsCategory); } // Add signals const List<EventDesc*> &cSignals = cClass.GetSignals(); for (uint32 i=0; i<cSignals.GetNumOfElements(); ++i) { EventDesc *pVarDesc = cSignals[i]; new ClassInfoMemberWithSignatureDescTreeItem<EventDesc>(tr("Signal"), *pVarDesc, m_pSignalsCategory); } // Add properties const HashMap<String, String> &cProps = cClass.GetProperties(); Iterator<String> cIterator = cProps.GetKeyIterator(); while (cIterator.HasNext()) { const String sName = cIterator.Next(); const String sValue = cProps.Get(sName); new ClassInfoPropertyTreeItem(QtStringAdapter::PLToQt(sName), QtStringAdapter::PLToQt(sValue), m_pPropertiesCategory); } // Add constructors const List<ConstructorDesc*> &cConstructors = cClass.GetConstructors(); for (uint32 i=0; i<cConstructors.GetNumOfElements(); ++i) { ConstructorDesc *pVarDesc = cConstructors[i]; new ClassInfoMemberWithSignatureDescTreeItem<ConstructorDesc>(tr("Constructor"), *pVarDesc, m_pConstructorsCategory); } // Add methods const List<FuncDesc*> &cMethods = cClass.GetMethods(); for (uint32 i=0; i<cMethods.GetNumOfElements(); ++i) { FuncDesc *pVarDesc = cMethods[i]; new ClassInfoMemberWithSignatureDescTreeItem<FuncDesc>(tr("Method"), *pVarDesc, m_pMethodsCategory); } endResetModel(); }
String f_hphp_get_original_class_name(CStrRef name) { Class* cls = Unit::loadClass(name.get()); if (!cls) return empty_string; return cls->nameRef(); }
bool UmlAttribute::manage_enum_item(WrapperStr name, UmlClass * cl #ifdef ROUNDTRIP , bool roundtrip, QList<UmlItem *> & expected_order #endif ) { WrapperStr comment = Lex::get_comments(); WrapperStr description = Lex::get_description(); UmlAttribute * item = 0; // initialize to avoid warning #ifdef ROUNDTRIP Class * container = 0; // initialize to avoid warning bool created = FALSE; // initialize to avoid warning #endif if (!Package::scanning()) { #ifdef ROUNDTRIP container = cl->get_class(); if (!roundtrip || ((item = search_attr(container, name)) == 0)) { #endif if ((item = UmlBaseAttribute::create(cl, name)) == 0) { JavaCatWindow::trace(WrapperStr("<font face=helvetica><b>cannot add enum item <i>") + name + "</i> in <i>" + cl->name() + "</i></b></font><br>"); return FALSE; } item->set_Visibility(PublicVisibility); #ifdef ROUNDTRIP if (roundtrip) container->set_updated(); created = TRUE; } #endif } Lex::mark(); WrapperStr aux; WrapperStr s; if ((s = Lex::read_word()).isEmpty()) { if (! Package::scanning()) Lex::premature_eof(); return FALSE; } else if ((s == ";") || (s == "}")) { aux = Lex::region(); Lex::unread_word(s); } else if (s == ",") { aux = Lex::region(); Lex::finish_line(); comment = Lex::get_comments(comment); description = Lex::get_description(description); } else if ((s == "(") || (s == "{")) { char c = UmlOperation::skip_expr(1); // goes after opt init and body if (c == 0) { if (! Package::scanning()) Lex::premature_eof(); return FALSE; } // c is ',' or ';' if (c == ';') Lex::unread_word(";"); aux = Lex::region(); } else { if (! Package::scanning()) Lex::error_near(s); return FALSE; } if (!Package::scanning()) { // here aux = opt init and body + final character , ; or } WrapperStr decl = JavaSettings::enumItemDecl(); int index; if ((decl.find("${name}") == -1) || ((index = decl.find("${value}")) == -1)) { decl = " ${name}${value},${comment}"; index = decl.find("${value}"); } //aux.resize(aux.length()); // remove , ; or }, warning resize count \000 //warn_WrapperStr if (!aux.stripWhiteSpace().isEmpty()) decl.replace(index, 8, aux); #ifdef ROUNDTRIP if (roundtrip && !created) { if (decl.find("${description}") != -1) { if (nequal(item->description(), description)) { item->set_Description(description); container->set_updated(); } } else if (nequal(item->description(), Lex::simplify_comment(comment))) { item->set_Description(comment); // comment was changed container->set_updated(); } if (neq(item->javaDecl(), decl)) { item->set_JavaDecl(decl); container->set_updated(); } item->set_usefull(); expected_order.append(item); } else { #endif if (!comment.isEmpty()) item->set_Description((decl.find("${description}") != -1) ? description : Lex::simplify_comment(comment)); item->set_JavaDecl(decl); #ifdef ROUNDTRIP if (roundtrip) expected_order.append(item); } #endif } return TRUE; }
void unserializeVariant(Variant& self, VariableUnserializer *uns, UnserializeMode mode /* = UnserializeMode::Value */) { // NOTE: If you make changes to how serialization and unserialization work, // make sure to update the reserialize() method in "runtime/ext/ext_apc.cpp" // and to update test_apc_reserialize() in "test/ext/test_ext_apc.cpp". char type = uns->readChar(); char sep = uns->readChar(); if (type != 'R') { uns->add(&self, mode); } if (type == 'N') { if (sep != ';') throw Exception("Expected ';' but got '%c'", sep); self.setNull(); // NULL *IS* the value, without we get undefined warnings return; } if (sep != ':') { throw Exception("Expected ':' but got '%c'", sep); } switch (type) { case 'r': { int64_t id = uns->readInt(); Variant *v = uns->getByVal(id); if (v == nullptr) { throw Exception("Id %" PRId64 " out of range", id); } self = *v; } break; case 'R': { int64_t id = uns->readInt(); Variant *v = uns->getByRef(id); if (v == nullptr) { throw Exception("Id %" PRId64 " out of range", id); } self.assignRef(*v); } break; case 'b': { int64_t v = uns->readInt(); self = (bool)v; } break; case 'i': { int64_t v = uns->readInt(); self = v; } break; case 'd': { double v; char ch = uns->peek(); bool negative = false; char buf[4]; if (ch == '-') { negative = true; ch = uns->readChar(); ch = uns->peek(); } if (ch == 'I') { uns->read(buf, 3); buf[3] = '\0'; if (strcmp(buf, "INF")) { throw Exception("Expected 'INF' but got '%s'", buf); } v = atof("inf"); } else if (ch == 'N') { uns->read(buf, 3); buf[3] = '\0'; if (strcmp(buf, "NAN")) { throw Exception("Expected 'NAN' but got '%s'", buf); } v = atof("nan"); } else { v = uns->readDouble(); } self = negative ? -v : v; } break; case 's': { String v; v.unserialize(uns); self = std::move(v); if (!uns->endOfBuffer()) { // Semicolon *should* always be required, // but PHP's implementation allows omitting it // and still functioning. // Worse, it throws it away without any check. // So we'll do the same. Sigh. uns->readChar(); } } return; case 'S': if (uns->type() == VariableUnserializer::Type::APCSerialize) { union { char buf[8]; StringData *sd; } u; uns->read(u.buf, 8); self = u.sd; } else { throw Exception("Unknown type '%c'", type); } break; case 'a': { // Check stack depth to avoid overflow. check_recursion_throw(); auto v = Array::Create(); v.unserialize(uns); self = std::move(v); } return; // array has '}' terminating case 'L': { int64_t id = uns->readInt(); uns->expectChar(':'); String rsrcName; rsrcName.unserialize(uns); uns->expectChar('{'); uns->expectChar('}'); auto rsrc = makeSmartPtr<DummyResource>(); rsrc->o_setResourceId(id); rsrc->m_class_name = rsrcName; self = std::move(rsrc); } return; // resource has '}' terminating case 'O': case 'V': case 'K': { String clsName; clsName.unserialize(uns); uns->expectChar(':'); int64_t size = uns->readInt(); uns->expectChar(':'); uns->expectChar('{'); const bool allowObjectFormatForCollections = true; Class* cls; // If we are potentially dealing with a collection, we need to try to // load the collection class under an alternate name so that we can // deserialize data that was serialized before the migration of // collections to the HH namespace. if (type != 'O') { // Collections are CPP builtins; don't attempt to autoload cls = Unit::getClass(clsName.get(), /* autoload */ false); if (!cls) { cls = tryAlternateCollectionClass(clsName.get()); } } else if (allowObjectFormatForCollections) { // In order to support the legacy {O|V}:{Set|Vector|Map} // serialization, we defer autoloading until we know that there's // no alternate (builtin) collection class. cls = Unit::getClass(clsName.get(), /* autoload */ false); if (!cls) { cls = tryAlternateCollectionClass(clsName.get()); } if (!cls) { cls = Unit::loadClass(clsName.get()); // with autoloading } } else { cls = Unit::loadClass(clsName.get()); // with autoloading } Object obj; if (RuntimeOption::UnserializationWhitelistCheck && (type == 'O') && !uns->isWhitelistedClass(clsName)) { const char* err_msg = "The object being unserialized with class name '%s' " "is not in the given whitelist. " "See http://fburl.com/SafeSerializable for more detail"; if (RuntimeOption::UnserializationWhitelistCheckWarningOnly) { raise_warning(err_msg, clsName.c_str()); } else { raise_error(err_msg, clsName.c_str()); } } if (cls) { // Only unserialize CPP extension types which can actually // support it. Otherwise, we risk creating a CPP object // without having it initialized completely. if (cls->instanceCtor() && !cls->isCppSerializable()) { assert(obj.isNull()); throw_null_pointer_exception(); } else { obj = Object{cls}; if (UNLIKELY(collections::isType(cls, CollectionType::Pair) && (size != 2))) { throw Exception("Pair objects must have exactly 2 elements"); } } } else { obj = Object{SystemLib::s___PHP_Incomplete_ClassClass}; obj->o_set(s_PHP_Incomplete_Class_Name, clsName); } assert(!obj.isNull()); self = obj; if (size > 0) { // Check stack depth to avoid overflow. check_recursion_throw(); if (type == 'O') { // Collections are not allowed if (obj->isCollection()) { throw Exception("%s does not support the 'O' serialization " "format", clsName.data()); } Variant serializedNativeData = init_null(); bool hasSerializedNativeData = false; /* Count backwards so that i is the number of properties remaining (to be used as an estimate for the total number of dynamic properties when we see the first dynamic prop). see getVariantPtr */ for (int64_t i = size; i--; ) { Variant v; unserializeVariant(v, uns, UnserializeMode::Key); String key = v.toString(); int ksize = key.size(); const char *kdata = key.data(); int subLen = 0; if (key == ObjectData::s_serializedNativeDataKey) { unserializeVariant(serializedNativeData, uns); hasSerializedNativeData = true; } else if (kdata[0] == '\0') { if (UNLIKELY(!ksize)) { raise_error("Cannot access empty property"); } // private or protected subLen = strlen(kdata + 1) + 2; if (UNLIKELY(subLen >= ksize)) { if (subLen == ksize) { raise_error("Cannot access empty property"); } else { throw Exception("Mangled private object property"); } } String k(kdata + subLen, ksize - subLen, CopyString); Class* ctx = (Class*)-1; if (kdata[1] != '*') { ctx = Unit::lookupClass( String(kdata + 1, subLen - 2, CopyString).get()); } unserializeProp(uns, obj.get(), k, ctx, key, i + 1); } else { unserializeProp(uns, obj.get(), key, nullptr, key, i + 1); } if (i > 0) { auto lastChar = uns->peekBack(); if ((lastChar != ';') && (lastChar != '}')) { throw Exception("Object property not terminated properly"); } } } // nativeDataWakeup is called last to ensure that all properties are // already unserialized. We also ensure that nativeDataWakeup is // invoked regardless of whether or not serialized native data exists // within the serialized content. if (obj->getAttribute(ObjectData::HasNativeData) && obj->getVMClass()->getNativeDataInfo()->isSerializable()) { Native::nativeDataWakeup(obj.get(), serializedNativeData); } else if (hasSerializedNativeData) { raise_warning("%s does not expect any serialized native data.", clsName.data()); } } else { assert(type == 'V' || type == 'K'); if (!obj->isCollection()) { throw Exception("%s is not a collection class", clsName.data()); } collections::unserialize(obj.get(), uns, size, type); } } uns->expectChar('}'); if (uns->type() != VariableUnserializer::Type::DebuggerSerialize || (cls && cls->instanceCtor() && cls->isCppSerializable())) { // Don't call wakeup when unserializing for the debugger, except for // natively implemented classes. obj->invokeWakeup(); } check_request_surprise_unlikely(); } return; // object has '}' terminating case 'C': { if (uns->type() == VariableUnserializer::Type::DebuggerSerialize) { raise_error("Debugger shouldn't call custom unserialize method"); } String clsName; clsName.unserialize(uns); uns->expectChar(':'); String serialized; serialized.unserialize(uns, '{', '}'); auto const obj = [&]() -> Object { if (auto const cls = Unit::loadClass(clsName.get())) { return Object::attach(g_context->createObject(cls, init_null_variant, false /* init */)); } if (!uns->allowUnknownSerializableClass()) { raise_error("unknown class %s", clsName.data()); } Object ret = create_object_only(s_PHP_Incomplete_Class); ret->o_set(s_PHP_Incomplete_Class_Name, clsName); ret->o_set("serialized", serialized); return ret; }(); if (!obj->instanceof(SystemLib::s_SerializableClass)) { raise_warning("Class %s has no unserializer", obj->getClassName().data()); } else { obj->o_invoke_few_args(s_unserialize, 1, serialized); obj.get()->clearNoDestruct(); } self = std::move(obj); } return; // object has '}' terminating default: throw Exception("Unknown type '%c'", type); } uns->expectChar(';'); }
void ClassTestSuite::testClass() { //Class test = ClassOf<Test1>(); Class test = Class::lookup("ClassTest::Test1"); TS_ASSERT_EQUALS(test.simpleName(), "Test1"); Class::ClassList superClasses = test.superclasses(); TS_ASSERT_EQUALS(superClasses.size(), 2); Class base1; Class base2; TS_ASSERT_THROWS(base1.simpleName(), std::runtime_error); // uninitialized handle for(const Class& c: superClasses) { if (c.fullyQualifiedName() == "ClassTest::TestBase1") { base1 = c; } else if (c.fullyQualifiedName() == "ClassTest::TestBase2") { base2 = c; } } TS_ASSERT_EQUALS(base1.fullyQualifiedName(), "ClassTest::TestBase1"); TS_ASSERT_EQUALS(base1.simpleName(), "TestBase1"); TS_ASSERT_EQUALS(base2.fullyQualifiedName(), "ClassTest::TestBase2"); TS_ASSERT_EQUALS(base2.simpleName(), "TestBase2"); Class::ConstructorList base1Constructors = base1.constructors(); TS_ASSERT_EQUALS(base1.constructors().size(), 1); Constructor base1Constructor = base1Constructors.front(); TS_ASSERT_EQUALS(base1Constructor.numberOfArguments(), 0); TS_ASSERT_THROWS(base1Constructor.call(), std::runtime_error); // abstract class Class::ConstructorList base2Constructors = base2.constructors(); TS_ASSERT_EQUALS(base2.constructors().size(), 1); Constructor base2Constructor = base2Constructors.front(); TS_ASSERT_EQUALS(base2Constructor.numberOfArguments(), 0); VariantValue b2Inst = base2Constructor.call(); TS_ASSERT(b2Inst.isValid()); TS_ASSERT_EQUALS(base2.attributes().size(), 0); Class::MethodList base2Methods = base2.methods(); TS_ASSERT_EQUALS(base2Methods.size(), 1); Method base2Method1 = base2Methods.front(); TS_ASSERT_EQUALS(base2Method1.name(), "base2Method1"); TS_ASSERT(base2Method1.isConst()); TS_ASSERT(!base2Method1.isVolatile()); TS_ASSERT(!base2Method1.isStatic()); TS_ASSERT_EQUALS(base2Method1.numberOfArguments(), 0); TS_ASSERT_EQUALS(base2Method1.call(b2Inst).value<int>(), 6); Class::ConstructorList testConstructors = test.constructors(); Class::AttributeList attributes = test.attributes(); TS_ASSERT_EQUALS(attributes.size(), 2); Attribute attr = attributes.front(); WITH_RTTI(TS_ASSERT(attr.type() == typeid(int))); TS_ASSERT_EQUALS(testConstructors.size(), 3); Constructor defaultConstr; Constructor intConstr; TS_ASSERT_THROWS(defaultConstr.argumentSpellings(), std::runtime_error); for (const Constructor& c: testConstructors) { if (c.numberOfArguments() == 0) { defaultConstr = c; } else if (c.numberOfArguments() == 1 && c.argumentSpellings()[0] == "int") { intConstr = c; } } TS_ASSERT_EQUALS(defaultConstr.numberOfArguments(), 0); TS_ASSERT_EQUALS(intConstr.numberOfArguments(), 1); VariantValue testInst1 = defaultConstr.call(); TS_ASSERT(testInst1.isA<Test1>()); TS_ASSERT_EQUALS(attr.get(testInst1).value<int>(), 3); VariantValue testInst2 = intConstr.call(77); TS_ASSERT(testInst2.isA<Test1>()); TS_ASSERT_EQUALS(attr.get(testInst2).value<int>(), 77); Class::MethodList methods = test.methods(); TS_ASSERT_EQUALS(methods.size(), 7); Method base1Method1; Method method1; Method method2; Method staticMethod; for (const Method& m: methods) { if (m.name() == "base1Method1") { base1Method1 = m; } else if (m.name() == "base2Method1") { base2Method1 = m; } else if (m.name() == "method1") { method1 = m; } else if (m.name() == "method2") { method2 = m; } else if (m.name() == "staticMethod") { staticMethod = m; } } TS_ASSERT_EQUALS(base1Method1.name(), "base1Method1"); TS_ASSERT(!base1Method1.isConst()); TS_ASSERT(!base1Method1.isStatic()); TS_ASSERT(!base1Method1.isVolatile()); WITH_RTTI(TS_ASSERT(base1Method1.returnType() == typeid(int))); TS_ASSERT_EQUALS(base1Method1.numberOfArguments(), 0); TS_ASSERT_EQUALS(base1Method1.call(testInst2).value<int>(), 5); TS_ASSERT_EQUALS(base2Method1.name(), "base2Method1"); TS_ASSERT(base2Method1.isConst()); TS_ASSERT(!base2Method1.isStatic()); TS_ASSERT(!base2Method1.isVolatile()); WITH_RTTI(TS_ASSERT(base2Method1.returnType() == typeid(int))); TS_ASSERT_EQUALS(base2Method1.numberOfArguments(), 0); TS_ASSERT_EQUALS(base2Method1.call(testInst2).value<int>(), 6); TS_ASSERT_EQUALS(method2.name(), "method2"); TS_ASSERT(!method2.isConst()); TS_ASSERT(!method2.isStatic()); TS_ASSERT(!method2.isVolatile()); WITH_RTTI(TS_ASSERT(method2.returnType() == typeid(double))); TS_ASSERT_EQUALS(method2.numberOfArguments(), 1); WITH_RTTI(TS_ASSERT(*method2.argumentTypes()[0] == typeid(double))); TS_ASSERT_EQUALS(method2.call(testInst2, 2).value<double>(), 6.28); TS_ASSERT_EQUALS(staticMethod.name(), "staticMethod"); TS_ASSERT(!staticMethod.isConst()); TS_ASSERT(staticMethod.isStatic()); TS_ASSERT(!staticMethod.isVolatile()); WITH_RTTI(TS_ASSERT(staticMethod.returnType() == typeid(double))); TS_ASSERT_EQUALS(staticMethod.numberOfArguments(), 0); TS_ASSERT_EQUALS(staticMethod.call().value<double>(), 3.14); }
int main(int argc, char**argv) { Arguments info; if(!parseOptions (argc, argv, info)) return 1; ESMReader esm; esm.setEncoding(info.encoding); string filename = info.filename; cout << "\nFile: " << filename << endl; try { if(info.raw_given) { cout << "RAW file listing:\n"; esm.openRaw(filename); printRaw(esm); return 0; } bool quiet = info.quiet_given; bool loadCells = info.loadcells_given; esm.open(filename); cout << "Author: " << esm.getAuthor() << endl; cout << "Description: " << esm.getDesc() << endl; cout << "File format version: " << esm.getFVer() << endl; cout << "Special flag: " << esm.getSpecial() << endl; cout << "Masters:\n"; ESMReader::MasterList m = esm.getMasters(); for(unsigned int i=0;i<m.size();i++) cout << " " << m[i].name << ", " << m[i].size << " bytes\n"; // Loop through all records while(esm.hasMoreRecs()) { NAME n = esm.getRecName(); esm.getRecHeader(); string id = esm.getHNOString("NAME"); if(!quiet) cout << "\nRecord: " << n.toString() << " '" << id << "'\n"; switch(n.val) { case REC_ACTI: { Activator ac; ac.load(esm); if(quiet) break; cout << " Name: " << ac.name << endl; cout << " Mesh: " << ac.model << endl; cout << " Script: " << ac.script << endl; break; } case REC_ALCH: { Potion p; p.load(esm); if(quiet) break; cout << " Name: " << p.name << endl; break; } case REC_APPA: { Apparatus p; p.load(esm); if(quiet) break; cout << " Name: " << p.name << endl; break; } case REC_ARMO: { Armor am; am.load(esm); if(quiet) break; cout << " Name: " << am.name << endl; cout << " Mesh: " << am.model << endl; cout << " Icon: " << am.icon << endl; cout << " Script: " << am.script << endl; cout << " Enchantment: " << am.enchant << endl; cout << " Type: " << am.data.type << endl; cout << " Weight: " << am.data.weight << endl; break; } case REC_BODY: { BodyPart bp; bp.load(esm); if(quiet) break; cout << " Name: " << bp.name << endl; cout << " Mesh: " << bp.model << endl; break; } case REC_BOOK: { Book b; b.load(esm); if(quiet) break; cout << " Name: " << b.name << endl; cout << " Mesh: " << b.model << endl; break; } case REC_BSGN: { BirthSign bs; bs.load(esm); if(quiet) break; cout << " Name: " << bs.name << endl; cout << " Texture: " << bs.texture << endl; cout << " Description: " << bs.description << endl; break; } case REC_CELL: { Cell b; b.load(esm); if(!quiet) { cout << " Name: " << b.name << endl; cout << " Region: " << b.region << endl; } if(loadCells) loadCell(b, esm, quiet); break; } case REC_CLAS: { Class b; b.load(esm); if(quiet) break; cout << " Name: " << b.name << endl; cout << " Description: " << b.description << endl; break; } case REC_CLOT: { Clothing b; b.load(esm); if(quiet) break; cout << " Name: " << b.name << endl; break; } case REC_CONT: { Container b; b.load(esm); if(quiet) break; cout << " Name: " << b.name << endl; break; } case REC_CREA: { Creature b; b.load(esm, id); if(quiet) break; cout << " Name: " << b.name << endl; break; } case REC_DIAL: { Dialogue b; b.load(esm); break; } case REC_DOOR: { Door d; d.load(esm); if(quiet) break; cout << " Name: " << d.name << endl; cout << " Mesh: " << d.model << endl; cout << " Script: " << d.script << endl; cout << " OpenSound: " << d.openSound << endl; cout << " CloseSound: " << d.closeSound << endl; break; } case REC_ENCH: { Enchantment b; b.load(esm); break; } case REC_GMST: { GameSetting b; b.id = id; b.load(esm); if(quiet) break; cout << " Value: "; if(b.type == VT_String) cout << "'" << b.str << "' (string)"; else if(b.type == VT_Float) cout << b.f << " (float)"; else if(b.type == VT_Int) cout << b.i << " (int)"; cout << "\n Dirty: " << b.dirty << endl; break; } case REC_INFO: { DialInfo p; p.load(esm); if(quiet) break; cout << " Id: " << p.id << endl; cout << " Text: " << p.response << endl; break; } case REC_SOUN: { Sound d; d.load(esm); if(quiet) break; cout << " Sound: " << d.sound << endl; cout << " Volume: " << (int)d.data.volume << endl; break; } case REC_SPEL: { Spell s; s.load(esm); if(quiet) break; cout << " Name: " << s.name << endl; break; } default: esm.skipRecord(); if(quiet) break; cout << " Skipping\n"; } } } catch(exception &e) { cout << "\nERROR:\n\n " << e.what() << endl; return 1; } return 0; }
/* Look at this class and it's superclass contents (which includes * included modules) and calculate out how to allocate the slots. * * This locks the class so that construction is serialized. */ void Class::auto_pack(STATE, GCToken gct, CallFrame* call_frame) { Class* self = this; OnStack<1> os(state, self); hard_lock(state, gct, call_frame); // If another thread did this work while we were waiting on the lock, // don't redo it. if(self->type_info_->type == PackedObject::type) { self->hard_unlock(state, gct, call_frame); return; } size_t slots = 0; LookupTable* lt = LookupTable::create(state); // If autopacking is enabled, figure out how many slots to use. if(state->shared().config.gc_autopack) { Module* mod = self; int slot = 0; while(!mod->nil_p()) { Array* info = 0; if(Class* cls = try_as<Class>(mod)) { info = cls->seen_ivars(); } else if(IncludedModule* im = try_as<IncludedModule>(mod)) { info = im->module()->seen_ivars(); } if(info && !info->nil_p()) { for(native_int i = 0; i < info->size(); i++) { if(Symbol* sym = try_as<Symbol>(info->get(state, i))) { bool found = false; lt->fetch(state, sym, &found); if(!found) { lt->store(state, sym, Fixnum::from(slot++)); } } // Limit the number of packed ivars to 25. if(slot > 25) break; } } mod = mod->superclass(); } slots = lt->entries()->to_native(); } self->set_packed_size(sizeof(Object) + (slots * sizeof(Object*))); self->packed_ivar_info(state, lt); atomic::memory_barrier(); self->set_object_type(state, PackedObject::type); self->hard_unlock(state, gct, call_frame); }
void Context::create_classes() { // Construct classes Class *obc = new Class( 0 ); obc->set_name("Object"); Class *clc = new Class( 0 ); clc->set_name("Class"); clc->clas = obc->clas = clc; Class *nic = new Class(clc); nic->set_name("Nil"); Class *inc = new Class(clc); inc->set_name("Integer"); Class *nac = new Class(clc); nac->set_name("Native"); Class *stc = new Class(clc); stc->set_name("String"); Class *trc = new Class(clc); trc->set_name("True"); Class *fac = new Class(clc); fac->set_name("False"); obc->set_base( 0 , TYPE_OBJECT); clc->set_base(obc, TYPE_CLASS); nic->set_base(obc, TYPE_NIL); inc->set_base(obc, TYPE_INTEGER); nac->set_base(obc, TYPE_NATIVE); stc->set_base(obc, TYPE_STRING); trc->set_base(obc, TYPE_TRUE); fac->set_base(obc, TYPE_FALSE); // Add classes this->object_class = obc; this->class_class = clc; this->nil_class = nic; this->integer_class = inc; this->native_class = nac; this->string_class = stc; this->true_class = trc; this->false_class = fac; // Add objects this->true_obj = Value(new True(trc)); this->false_obj = Value(new False(fac)); this->nil_obj = Value((Object*)0); // Finally (!), add methods to classes. Object::install_methods(obc); True::install_methods(trc); False::install_methods(fac); Nil::install_methods(nic); Class::install_methods(clc); Native::install_methods(nac); String::install_methods(stc); Integer::install_methods(inc); }
bool Class::load_ancestors(Global_Env* env) { m_state = ST_LoadingAncestors; const String* superName = get_super_class_name(); if(superName == NULL) { if(env->InBootstrap() || get_name() != env->JavaLangClass_String) { // This class better be java.lang.Object if(get_name() != env->JavaLangObject_String) { // ClassFormatError std::stringstream ss; ss << get_name()->bytes << ": class does not have superclass " << "but the class is not java.lang.Object"; REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError", ss.str().c_str()); return false; } } } else { // Load super class Class* superClass; m_super_class.name = NULL; superClass = m_class_loader->LoadVerifyAndPrepareClass(env, superName); if(superClass == NULL) { assert(exn_raised()); return false; } if(superClass->is_interface()) { REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/IncompatibleClassChangeError", "class " << m_name->bytes << " has interface " << superClass->get_name()->bytes << " as super class"); return false; } if(superClass->is_final()) { REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/VerifyError", m_name->bytes << " cannot inherit from final class " << superClass->get_name()->bytes); return false; } // super class was successfully loaded m_super_class.clss = superClass; if(m_super_class.cp_index) { m_const_pool.resolve_entry(m_super_class.cp_index, superClass); } // if it's an interface, its superclass must be java/lang/Object if(is_interface()) { if((env->JavaLangObject_Class != NULL) && (superClass != env->JavaLangObject_Class)) { std::stringstream ss; ss << get_name()->bytes << ": interface superclass is not java.lang.Object"; REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/ClassFormatError", ss.str().c_str()); return false; } } // Update the cha_first_child and cha_next_sibling fields. m_cha_first_child = NULL; if(has_super_class()) { m_cha_next_sibling = get_super_class()->m_cha_first_child; get_super_class()->m_cha_first_child = this; } } // // load in super interfaces // for(unsigned i = 0; i < m_num_superinterfaces; i++ ) { const String* intfc_name = m_superinterfaces[i].name; Class* intfc = m_class_loader->LoadVerifyAndPrepareClass(env, intfc_name); if(intfc == NULL) { assert(exn_raised()); return false; } if(!intfc->is_interface()) { REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/IncompatibleClassChangeError", get_name()->bytes << ": " << intfc->get_name()->bytes << " is not an interface"); return false; } // superinterface was successfully loaded m_superinterfaces[i].clss = intfc; if(m_superinterfaces[i].cp_index != 0) { // there are no constant pool entries for array classes m_const_pool.resolve_entry(m_superinterfaces[i].cp_index, intfc); } } // class, superclass, and superinterfaces successfully loaded m_state = ST_Loaded; if(!is_array()) m_package = m_class_loader->ProvidePackage(env, m_name, NULL); return true; }
static bool Snapshot(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector *props) { IdSet ht(cx); if (!ht.init(32)) return NULL; JSObject *pobj = obj; do { Class *clasp = pobj->getClass(); if (pobj->isNative() && !pobj->getOps()->enumerate && !(clasp->flags & JSCLASS_NEW_ENUMERATE)) { if (!clasp->enumerate(cx, pobj)) return false; if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) return false; } else if (pobj->isDenseArray()) { if (!EnumerateDenseArrayProperties(cx, obj, pobj, flags, ht, props)) return false; } else { if (pobj->isProxy()) { AutoIdVector proxyProps(cx); if (flags & JSITER_OWNONLY) { if (flags & JSITER_HIDDEN) { if (!JSProxy::getOwnPropertyNames(cx, pobj, proxyProps)) return false; } else { if (!JSProxy::keys(cx, pobj, proxyProps)) return false; } } else { if (!JSProxy::enumerate(cx, pobj, proxyProps)) return false; } for (size_t n = 0, len = proxyProps.length(); n < len; n++) { if (!Enumerate(cx, obj, pobj, proxyProps[n], true, flags, ht, props)) return false; } /* Proxy objects enumerate the prototype on their own, so we are done here. */ break; } Value state; JSIterateOp op = (flags & JSITER_HIDDEN) ? JSENUMERATE_INIT_ALL : JSENUMERATE_INIT; if (!pobj->enumerate(cx, op, &state, NULL)) return false; if (state.isMagic(JS_NATIVE_ENUMERATE)) { if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) return false; } else { while (true) { jsid id; if (!pobj->enumerate(cx, JSENUMERATE_NEXT, &state, &id)) return false; if (state.isNull()) break; if (!Enumerate(cx, obj, pobj, id, true, flags, ht, props)) return false; } } } if ((flags & JSITER_OWNONLY) || pobj->isXML()) break; } while ((pobj = pobj->getProto()) != NULL); return true; }
void COutputStreamSerializer::SavePackage (std::ostream *s, void *rootObj, Class *rootObjClass) { PackageHeader ph; stream = s; unsigned startOffset = stream->tellp(); stream->seekp (startOffset + sizeof (PackageHeader)); ph.objDataOffset = (int)stream->tellp(); // Insert the first object that will provide references to everything ObjectID obj; obj.class_ = rootObjClass; obj.isEmbedded = false; obj.id = 0; ptrToID[rootObj] = obj; pendingObjects.push_back (ptrToID.find(rootObj)); objects.push_back (&ptrToID[rootObj]); // Save until all the referenced objects have been stored while (!pendingObjects.empty ()) { vector <ObjIDmap::iterator> po = pendingObjects; pendingObjects.clear (); for (vector<ObjIDmap::iterator>::iterator i=po.begin();i!=po.end();++i) { ObjectID& obj = (*i)->second; obj.class_->SerializeInstance (this, (*i)->first); } } // Collect a set of all used classes map<creg::Class *,ClassRef> classMap; vector <ClassRef*> classRefs; for (ObjIDmap::iterator oi = ptrToID.begin(); oi != ptrToID.end(); ++oi) { //printf ("Obj: %s\n", oi->second.class_->name.c_str()); map<creg::Class*,ClassRef>::iterator cr = classMap.find (oi->second.class_); if (cr == classMap.end()) { ClassRef *pRef = &classMap[oi->second.class_]; pRef->index = classRefs.size(); pRef->class_ = oi->second.class_; classRefs.push_back (pRef); oi->second.classIndex = pRef->index; } else oi->second.classIndex = cr->second.index; } // Write the class references ph.numObjClassRefs = classRefs.size(); ph.objClassRefOffset = (int)stream->tellp(); for (uint a=0;a<classRefs.size();a++) { WriteZStr (*stream, classRefs[a]->class_->name); // write a checksum (unused atm) int checksum = swabdword(0); stream->write ((char*)&checksum, sizeof(int)); } // Write object info ph.objTableOffset = (int)stream->tellp(); ph.numObjects = objects.size(); for (uint a=0;a<objects.size();a++) { ObjectID *o = objects[a]; PackageObject d; d.classRefIndex = o->classIndex; d.isEmbedded = o->isEmbedded ? 1 : 0; d.SwapBytes (); stream->write ((char*)&d, sizeof(PackageObject)); } // Calculate a checksum for metadata verification ph.metadataChecksum = 0; for (uint a=0;a<classRefs.size();a++) { Class *c = classRefs[a]->class_; c->CalculateChecksum (ph.metadataChecksum); } printf("Checksum: %d\n", ph.metadataChecksum); stream->seekp (startOffset); memcpy(ph.magic, CREG_PACKAGE_FILE_ID, 4); ph.SwapBytes (); stream->write ((const char *)&ph, sizeof(PackageHeader)); objects.clear(); ptrToID.clear(); }
xdebug_xml_node* xdebug_var_export_xml_node(const char* name, const char* fullName, const char* facet, const Variant& var, XDebugExporter& exporter) { // Setup the node. Each const cast is necessary due to xml api xdebug_xml_node* node = xdebug_xml_node_init("property"); if (name != nullptr) { xdebug_xml_add_attribute_ex(node, "name", const_cast<char*>(name), 0, 1); } if (fullName != nullptr) { xdebug_xml_add_attribute_ex(node, "fullname", const_cast<char*>(fullName), 0, 1); } if (facet != nullptr) { xdebug_xml_add_attribute_ex(node, "facet", const_cast<char*>(facet), 0, 1); } xdebug_xml_add_attribute_ex(node, "address", xdebug_sprintf("%ld", (long) &var), 0, 1); // Case on the type for the rest if (var.isBoolean()) { xdebug_xml_add_attribute(node, "type", "bool"); xdebug_xml_add_text(node, xdebug_sprintf("%d", var.toBoolean())); } else if (var.isNull()) { xdebug_xml_add_attribute(node, "type", "null"); } else if (var.isInteger()) { xdebug_xml_add_attribute(node, "type", "int"); xdebug_xml_add_text(node, xdebug_sprintf("%ld", var.toInt64())); } else if (var.isDouble()) { xdebug_xml_add_attribute(node, "type", "float"); xdebug_xml_add_text(node, xdebug_sprintf("%lG", var.toDouble())); } else if (var.isString()) { // Add the type and the original size String str = var.toString(); xdebug_xml_add_attribute(node, "type", "string"); xdebug_xml_add_attribute_ex(node, "size", xdebug_sprintf("%d", str.size()), 0, 1); // Possibly shrink the string, then add it to the node if (exporter.max_data != 0 && str.size() > exporter.max_data) { str = str.substr(0, exporter.max_data); } xdebug_xml_add_text_encodel(node, xdstrdup(str.data()), str.size()); } else if (var.isArray()) { Array arr = var.toArray(); xdebug_xml_add_attribute(node, "type", "array"); xdebug_xml_add_attribute(node, "children", const_cast<char*>(arr.size() > 0 ? "1" : "0")); // If we've already seen this object, return if (exporter.counts[arr.get()]++ > 0) { xdebug_xml_add_attribute(node, "recursive", "1"); return node; } // Write the # of children then short-circuit if we are too deep xdebug_xml_add_attribute_ex(node, "numchildren", xdebug_sprintf("%d", arr.size()), 0, 1); if (exporter.level++ >= exporter.max_depth) { return node; } // Compute the page and the start/end indices // Note that php xdebug doesn't support pages except for at the top level uint32_t page = exporter.level == 0 ? exporter.page : 0; uint32_t start = page * exporter.max_children; uint32_t end = (page + 1) * exporter.max_children; xdebug_xml_add_attribute_ex(node, "page", xdebug_sprintf("%d", page), 0, 1); xdebug_xml_add_attribute_ex(node, "pagesize", xdebug_sprintf("%d", exporter.max_children), 0, 1); // Add each child ArrayIter iter(arr); iter.setPos(start); for (uint32_t i = start; i < end && iter; i++, ++iter) { xdebug_array_element_export_xml_node(*node, name, iter.first(), iter.second(), exporter); } // Done at this level exporter.level--; exporter.counts[arr.get()]--; } else if (var.isObject()) { // TODO(#4489053) This could be merged into the above array code. For now, // it's separate as this was pulled originally from xdebug ObjectData* obj = var.toObject().get(); Class* cls = obj->getVMClass(); Array props = get_object_props(obj); // Add object info xdebug_xml_add_attribute(node, "type", "object"); xdebug_xml_add_attribute_ex(node, "classname", xdstrdup(cls->name()->data()), 0, 1); xdebug_xml_add_attribute(node, "children", const_cast<char*>(props.size() ? "1" : "0")); // If we've already seen this object, return if (exporter.counts[obj]++ > 0) { return node; } // Add the # of props then short circuit if we are too deep xdebug_xml_add_attribute_ex(node, "numchildren", xdebug_sprintf("%d", props.size()), 0, 1); if (exporter.level++ >= exporter.max_depth) { return node; } // Compute the page and the start/end indices // Note that php xdebug doesn't support pages except for at the top level uint32_t page = exporter.level == 1 ? exporter.page : 0; uint32_t start = page * exporter.max_children; uint32_t end = (page + 1) * exporter.max_children; xdebug_xml_add_attribute_ex(node, "page", xdebug_sprintf("%d", page), 0, 1); xdebug_xml_add_attribute_ex(node, "pagesize", xdebug_sprintf("%d", exporter.max_children), 0, 1); // Add each property ArrayIter iter(props); iter.setPos(start); for (uint32_t i = start; i < end && iter; i++, ++iter) { xdebug_object_element_export_xml_node(*node, name, obj, iter.first(), iter.second(), exporter); } // Done at this level exporter.level--; exporter.counts[(void*) obj]--; } else if (var.isResource()) { ResourceData* res = var.toResource().get(); xdebug_xml_add_attribute(node, "type", "resource"); const char* text = xdebug_sprintf("resource id='%ld' type='%s'", res->o_getId(), res->o_getResourceName().data()); xdebug_xml_add_text(node, const_cast<char*>(text)); } else { xdebug_xml_add_attribute(node, "type", "null"); } return node; }
static inline const String& ctxClassName() { Class* ctx = g_vmContext->getContextClass(); return ctx ? ctx->nameRef() : empty_string; }
JS_GetPropertyDescArray(JSContext *cx, JSObject *obj_, JSPropertyDescArray *pda) { RootedObject obj(cx, obj_); assertSameCompartment(cx, obj); uint32_t i = 0; JSPropertyDesc *pd = NULL; if (obj->isDebugScope()) { AutoIdVector props(cx); if (!Proxy::enumerate(cx, obj, props)) return false; pd = (JSPropertyDesc *)cx->calloc_(props.length() * sizeof(JSPropertyDesc)); if (!pd) return false; for (i = 0; i < props.length(); ++i) { pd[i].id = JSVAL_NULL; pd[i].value = JSVAL_NULL; if (!js_AddRoot(cx, &pd[i].id, NULL)) goto bad; pd[i].id = IdToValue(props[i]); if (!js_AddRoot(cx, &pd[i].value, NULL)) goto bad; if (!Proxy::get(cx, obj, obj, props.handleAt(i), MutableHandleValue::fromMarkedLocation(&pd[i].value))) goto bad; } pda->length = props.length(); pda->array = pd; return true; } Class *clasp; clasp = obj->getClass(); if (!obj->isNative() || (clasp->flags & JSCLASS_NEW_ENUMERATE)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_DESCRIBE_PROPS, clasp->name); return false; } if (!clasp->enumerate(cx, obj)) return false; /* Return an empty pda early if obj has no own properties. */ if (obj->nativeEmpty()) { pda->length = 0; pda->array = NULL; return true; } pd = (JSPropertyDesc *)cx->malloc_(obj->propertyCount() * sizeof(JSPropertyDesc)); if (!pd) return false; for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) { pd[i].id = JSVAL_NULL; pd[i].value = JSVAL_NULL; pd[i].alias = JSVAL_NULL; if (!js_AddRoot(cx, &pd[i].id, NULL)) goto bad; if (!js_AddRoot(cx, &pd[i].value, NULL)) goto bad; Shape *shape = const_cast<Shape *>(&r.front()); if (!GetPropertyDesc(cx, obj, shape, &pd[i])) goto bad; if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL)) goto bad; if (++i == obj->propertyCount()) break; } pda->length = i; pda->array = pd; return true; bad: pda->length = i + 1; pda->array = pd; JS_PutPropertyDescArray(cx, pda); return false; }
llvm::Value* FunctionCall::load(Context &context) { std::vector<Type*> actual_type; for (std::list<Expression*>::iterator it = arg_list.begin(); it != arg_list.end(); it++) actual_type.push_back((*it)->getType(context)); Symbol *symbol = NULL; Class *targetClass = NULL; if (target == NULL) { // static call or self call if (identifier->getName().rfind("::") != std::string::npos) { // static call // find class targetClass = context.findClass(identifier->getName().substr(0, identifier->getName().rfind("::"))); if (!targetClass) throw SymbolNotFound("Class '" + identifier->getName().substr(0, identifier->getName().rfind("::")) + "'"); // find function symbol = targetClass->findSymbol(identifier->getName().substr(identifier->getName().rfind("::") + 2)); if (!symbol) throw SymbolNotFound("Function '" + identifier->getName() + "'"); // match the best override symbol = bestMatch(symbol, actual_type, context); if (!symbol) throw SymbolNotFound("No matching call for '" + Function::genName(identifier->getName(), actual_type) + "'"); // check symbol is static function if (symbol->type != Symbol::STATIC_FUNCTION) throw InvalidType("'" + symbol->data.function.function->getName() + "' is not a static function"); // check symbol's permission if (symbol->data.static_function.isPrivate && targetClass != context.currentClass) throw CompileException("function '" + symbol->data.static_function.function->getName() + "' is private"); if (symbol->data.static_function.isProtected && !Class::isA(context.currentClass, targetClass)) throw CompileException("function '" + symbol->data.static_function.function->getName() + "' is protected"); } else { // self call targetClass = context.currentClass; // find function symbol = targetClass->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound("'" + identifier->getName() + "'"); symbol = bestMatch(symbol, actual_type, context); if (!symbol) throw SymbolNotFound("No matching call for '" + Function::genName(identifier->getName(), actual_type) + "'"); } } else { // member function call targetClass = target->getType(context)->getClass(); // find function symbol = targetClass->findSymbol(identifier->getName()); if (!symbol) throw SymbolNotFound("Function '" + identifier->getName() + "'"); symbol = bestMatch(symbol, actual_type, context); if (!symbol) throw SymbolNotFound("No matching call for '" + Function::genName(identifier->getName(), actual_type) + "'"); // check symbol is normal function if (symbol->type != Symbol::FUNCTION) throw InvalidType("function '" + symbol->data.static_function.function->getName() + "' is not a member function"); // check symbol's permission if (symbol->data.static_function.isPrivate && targetClass != context.currentClass) throw CompileException("function '" + symbol->data.static_function.function->getName() + "' is private"); if (symbol->data.static_function.isProtected && !Class::isA(context.currentClass, targetClass)) throw CompileException("function '" + symbol->data.static_function.function->getName() + "' is protected"); } llvm::Value *function; std::vector<llvm::Value*> arg_code; switch (symbol->type) { case Symbol::FUNCTION: { Expression *tmpTarget = target ? target : new Identifier("this"); if (!tmpTarget->getType(context)->isObject()) throw InvalidType(std::string("calling a function of ") + tmpTarget->getType(context)->getName()); llvm::Value *thisval = tmpTarget->load(context); if (!target) delete tmpTarget; if (targetClass->getMangleName()[0] == 'J') { // locate vtable function = addDebugLoc( context, context.getBuilder().CreateLoad( thisval ), loc ); // for interface call, we have to recalculate the object base address // load offset from vtable llvm::Value *baseOffset = addDebugLoc( context, context.getBuilder().CreateLoad( addDebugLoc( context, context.getBuilder().CreateStructGEP( nullptr, function, 0 ), loc ) ), loc ); // calculate the base address thisval = addDebugLoc( context, context.getBuilder().CreateIntToPtr( addDebugLoc( context, context.getBuilder().CreateSub( addDebugLoc( context, context.getBuilder().CreatePtrToInt( thisval, context.getBuilder().getInt32Ty() ), loc ), baseOffset ), loc ), context.getBuilder().getInt8PtrTy(0) ), loc ); } else { // locate vtable function = addDebugLoc( context, context.getBuilder().CreateLoad( addDebugLoc( context, context.getBuilder().CreateStructGEP( nullptr, thisval, symbol->data.function.vtableOffset ), loc ) ), loc ); // for object call, we only need type cast thisval = context.getBuilder().CreatePointerCast( thisval, context.getBuilder().getInt8PtrTy(0) ); } // add thisval as the first argument arg_code.push_back(thisval); // load function pointer from vtable function = addDebugLoc( context, context.getBuilder().CreateLoad( addDebugLoc( context, context.getBuilder().CreateStructGEP( nullptr, function, symbol->data.function.funcPtrOffset ), loc ) ), loc ); break; } case Symbol::STATIC_FUNCTION: function = symbol->data.static_function.function->getLLVMFunction(context); if (target) throw CompileException("Calling a static function of an object"); break; default: throw InvalidType("calling a symbol which is not a function"); } // load remaining arguments { Function *func = symbol->type == Symbol::FUNCTION ? symbol->data.function.function : symbol->data.static_function.function; Function::arg_iterator it2 = func->arg_begin(); for (std::list<Expression*>::iterator it = arg_list.begin(); it != arg_list.end(); it++, it2++) arg_code.push_back(Type::cast(context, (*it)->getType(context), (*it)->load(context), it2->first)); } // do the call llvm::Value *ans = addDebugLoc( context, context.getBuilder().CreateCall(function, llvm::ArrayRef<llvm::Value*>(arg_code)), loc); return ans; }
Array createBacktrace(const BacktraceArgs& btArgs) { Array bt = Array::Create(); // If there is a parser frame, put it at the beginning of // the backtrace if (btArgs.m_parserFrame) { bt.append( make_map_array( s_file, btArgs.m_parserFrame->filename, s_line, btArgs.m_parserFrame->lineNumber ) ); } VMRegAnchor _; if (!vmfp()) { // If there are no VM frames, we're done return bt; } int depth = 0; ActRec* fp = nullptr; Offset pc = 0; // Get the fp and pc of the top frame (possibly skipping one frame) { if (btArgs.m_skipTop) { fp = g_context->getPrevVMState(vmfp(), &pc); if (!fp) { // We skipped over the only VM frame, we're done return bt; } } else { fp = vmfp(); Unit *unit = vmfp()->m_func->unit(); assert(unit); pc = unit->offsetOf(vmpc()); } // Handle the top frame if (btArgs.m_withSelf) { // Builtins don't have a file and line number if (!fp->m_func->isBuiltin()) { Unit* unit = fp->m_func->unit(); assert(unit); const char* filename = fp->m_func->filename()->data(); Offset off = pc; ArrayInit frame(btArgs.m_parserFrame ? 4 : 2, ArrayInit::Map{}); frame.set(s_file, filename); frame.set(s_line, unit->getLineNumber(off)); if (btArgs.m_parserFrame) { frame.set(s_function, s_include); frame.set(s_args, Array::Create(btArgs.m_parserFrame->filename)); } bt.append(frame.toVariant()); depth++; } } } // Handle the subsequent VM frames Offset prevPc = 0; for (ActRec* prevFp = g_context->getPrevVMState(fp, &prevPc); fp != nullptr && (btArgs.m_limit == 0 || depth < btArgs.m_limit); fp = prevFp, pc = prevPc, prevFp = g_context->getPrevVMState(fp, &prevPc)) { // do not capture frame for HPHP only functions if (fp->m_func->isNoInjection()) { continue; } ArrayInit frame(7, ArrayInit::Map{}); auto const curUnit = fp->m_func->unit(); auto const curOp = *reinterpret_cast<const Op*>(curUnit->at(pc)); auto const isReturning = curOp == Op::RetC || curOp == Op::RetV || curOp == Op::CreateCont || curOp == Op::Await || fp->localsDecRefd(); // Builtins and generators don't have a file and line number if (prevFp && !prevFp->m_func->isBuiltin() && !fp->resumed()) { auto const prevUnit = prevFp->m_func->unit(); auto prevFile = prevUnit->filepath(); if (prevFp->m_func->originalFilename()) { prevFile = prevFp->m_func->originalFilename(); } assert(prevFile); frame.set(s_file, const_cast<StringData*>(prevFile)); // In the normal method case, the "saved pc" for line number printing is // pointing at the cell conversion (Unbox/Pop) instruction, not the call // itself. For multi-line calls, this instruction is associated with the // subsequent line which results in an off-by-n. We're subtracting one // in order to look up the line associated with the FCall/FCallArray // instruction. Exception handling and the other opcodes (ex. BoxR) // already do the right thing. The emitter associates object access with // the subsequent expression and this would be difficult to modify. auto const opAtPrevPc = *reinterpret_cast<const Op*>(prevUnit->at(prevPc)); Offset pcAdjust = 0; if (opAtPrevPc == OpPopR || opAtPrevPc == OpUnboxR) { pcAdjust = 1; } frame.set(s_line, prevFp->m_func->unit()->getLineNumber(prevPc - pcAdjust)); } // check for include String funcname = const_cast<StringData*>(fp->m_func->name()); if (fp->m_func->isClosureBody()) { static StringData* s_closure_label = makeStaticString("{closure}"); funcname = s_closure_label; } // check for pseudomain if (funcname.empty()) { if (!prevFp) continue; funcname = s_include; } frame.set(s_function, funcname); if (!funcname.same(s_include)) { // Closures have an m_this but they aren't in object context Class* ctx = arGetContextClass(fp); if (ctx != nullptr && !fp->m_func->isClosureBody()) { frame.set(s_class, ctx->name()->data()); if (fp->hasThis() && !isReturning) { if (btArgs.m_withThis) { frame.set(s_object, Object(fp->getThis())); } frame.set(s_type, "->"); } else { frame.set(s_type, "::"); } } } Array args = Array::Create(); if (btArgs.m_ignoreArgs) { // do nothing } else if (funcname.same(s_include)) { if (depth) { args.append(const_cast<StringData*>(curUnit->filepath())); frame.set(s_args, args); } } else if (!RuntimeOption::EnableArgsInBacktraces || isReturning) { // Provide an empty 'args' array to be consistent with hphpc frame.set(s_args, args); } else { const int nparams = fp->m_func->numNonVariadicParams(); int nargs = fp->numArgs(); int nformals = std::min(nparams, nargs); if (UNLIKELY(fp->hasVarEnv() && fp->getVarEnv()->getFP() != fp)) { // VarEnv is attached to eval or debugger frame, other than the current // frame. Access locals thru VarEnv. auto varEnv = fp->getVarEnv(); auto func = fp->func(); for (int i = 0; i < nformals; i++) { TypedValue *arg = varEnv->lookup(func->localVarName(i)); args.append(tvAsVariant(arg)); } } else { for (int i = 0; i < nformals; i++) { TypedValue *arg = frame_local(fp, i); args.append(tvAsVariant(arg)); } } /* builtin extra args are not stored in varenv */ if (nargs > nparams && fp->hasExtraArgs()) { for (int i = nparams; i < nargs; i++) { TypedValue *arg = fp->getExtraArg(i - nparams); args.append(tvAsVariant(arg)); } } frame.set(s_args, args); } bt.append(frame.toVariant()); depth++; } return bt; }
void SourceFile::parse() { bool any = false; Parser p( contents() ); p.scan( "/*" "!" ); while ( !p.atEnd() ) { any = true; p.whitespace(); Function * f = 0; Class * c = 0; Intro * i = 0; EString d; uint l = p.line(); if ( p.lookingAt( "\\fn " ) ) { p.scan( " " ); f = function( &p ); d = p.textUntil( "*/" ); } else if ( p.lookingAt( "\\chapter " ) ) { p.scan( " " ); EString name = p.word(); if ( name.isEmpty() ) (void)new Error( this, p.line(), "\\chapter must be followed by name" ); i = new Intro( name ); p.whitespace(); d = p.textUntil( "*/" ); } else if ( p.lookingAt( "\\class " ) ) { p.scan( " " ); EString className = p.identifier(); if ( className.isEmpty() ) { (void)new Error( this, l, "\\class must be followed by a class name" ); } c = Class::find( className ); if ( !c ) c = new Class( className, 0, 0 ); p.whitespace(); EString hn = p.word(); while ( p.lookingAt( "." ) ) { p.step(); hn.append( "." ); hn.append( p.word() ); } if ( hn.length() < 2 || hn.mid( hn.length() - 2) != ".h" ) { (void)new Error( this, l, "Missing header file name" ); } else { if ( !contents().contains( "\n#include \"" + hn + "\"" ) && !contents().contains( "\n#include <" + hn + ">" ) ) (void)new Error( this, l, "File does not include " + hn ); HeaderFile * h = HeaderFile::find( hn ); if ( !h ) { if ( name().contains( "/" ) ) { EString dir = name(); uint i = dir.length()-1; while ( i > 0 && dir[i] != '/' ) i--; hn = dir.mid( 0, i+1 ) + hn; } h = new HeaderFile( hn ); if ( !h->valid() ) (void)new Error( this, l, "Cannot find header file " + hn + " (for class " + className + ")" ); } if ( !c->members() || c->members()->isEmpty() ) (void)new Error( this, l, "Cannot find any " + className + " members in " + hn ); } d = p.textUntil( "*/" ); } else if ( p.lookingAt( "\\nodoc" ) ) { any = true; d = "hack"; } else { d = p.textUntil( "*/" ); f = function( &p ); } if ( d.isEmpty() ) (void)new Error( this, l, "Comment contains no documentation" ); else if ( f ) (void)new DocBlock( this, l, d, f ); else if ( c ) (void)new DocBlock( this, l, d, c ); else if ( i ) (void)new DocBlock( this, l, d, i ); p.scan( "/" /* udoc must not see that as one string */ "*!" ); } if ( !any ) { Parser p( contents() ); p.scan( "::" ); // any source in this file at all? if ( !p.atEnd() ) (void)new Error( this, p.line(), "File contains no documentation" ); } }
void PRMDisplay::RBNToGraph(const double attributeWeight, const double FKWeight) { Class aClass; VertexDescriptor vd; std::map<std::string, VertexDescriptor> container; positionMap = boost::get(&VertexProperties::point, graph); vertexIdPropertyMap = boost::get(&VertexProperties::index, graph); WeightPropertyMap weightPropertyMap = boost::get(&EdgeProperty::weight, graph); RelationalSchema schema = rbn->getSchema(); std::vector<std::string> classnames = schema.getClassNames(); for(std::vector<std::string>::iterator it = classnames.begin(); it != classnames.end(); ++it) { std::string classname = *it; aClass = schema.getClass(classname); std::vector<std::string> attributesName = aClass.getAttributeNames(); //std::vector<std::string>::iterator it2 = attributesName.begin(); //pour chaque attribut, ajout d'un nouveau sommet aux coordonnée (1,1) for(std::vector<std::string>::iterator it1 = attributesName.begin(); it1!=attributesName.end(); it1++) { std::stringstream ss; ss << classname << "." << *it1; vd = boost::add_vertex(graph); vertexIdPropertyMap[vd] = ss.str(); container[ss.str()] = vd; positionMap[vd][0]=1; positionMap[vd][1]=1; // si l'itérateur est différent de begin, alors on itere pour ajouter une arête jusqu'à l'itérateur it1 actuel if(attributesName.begin() != it1) { //Ajout d'arête entre le nouveau sommet et ceux du graphe qui appartiennent à la même classe. Le poid est de 2 for(std::vector<std::string>::iterator it3 = attributesName.begin(); it3 != it1; it3++) { std::stringstream ss2; ss2 << classname << "." << *it3; boost::add_edge(container[ss.str()], container[ss2.str()], EdgeProperty(attributeWeight), graph); } } } } /***** ajout d'arête pour chaque clé étrangère ****/ RefSlotsMultimap foreignKeys = schema.getRefSlots(); std::string attPK; std::string classPK; std::string classFK; for(RefSlotsMultimap::iterator rb = foreignKeys.begin(); rb != foreignKeys.end(); ++rb){ classPK=rb->second.second->getName().c_str(); attPK= rbn->getSchema().getClass(classPK).getPK().front(); classPK.append("."); classPK.append(attPK); //std::cout << "\t primaryKey "<<classPK; classFK=rb->first.c_str();; classFK.append("."); classFK.append(rb->second.first.getName()); //std::cout << "\t foriegnKey "<<classFK; boost::add_edge(container[classFK], container[classPK], EdgeProperty(FKWeight), graph); } }
void Variant::unserialize(VariableUnserializer *uns, Uns::Mode mode /* = Uns::Mode::Value */) { // NOTE: If you make changes to how serialization and unserialization work, // make sure to update the reserialize() method in "runtime/ext/ext_apc.cpp" // and to update test_apc_reserialize() in "test/ext/test_ext_apc.cpp". char type, sep; type = uns->readChar(); sep = uns->readChar(); if (type != 'R') { uns->add(this, mode); } if (type == 'N') { if (sep != ';') throw Exception("Expected ';' but got '%c'", sep); setNull(); // NULL *IS* the value, without we get undefined warnings return; } if (sep != ':') { throw Exception("Expected ':' but got '%c'", sep); } switch (type) { case 'r': { int64_t id = uns->readInt(); Variant *v = uns->getByVal(id); if (v == nullptr) { throw Exception("Id %" PRId64 " out of range", id); } operator=(*v); } break; case 'R': { int64_t id = uns->readInt(); Variant *v = uns->getByRef(id); if (v == nullptr) { throw Exception("Id %" PRId64 " out of range", id); } assignRef(*v); } break; case 'b': { int64_t v = uns->readInt(); operator=((bool)v); } break; case 'i': { int64_t v = uns->readInt(); operator=(v); } break; case 'd': { double v; char ch = uns->peek(); bool negative = false; char buf[4]; if (ch == '-') { negative = true; ch = uns->readChar(); ch = uns->peek(); } if (ch == 'I') { uns->read(buf, 3); buf[3] = '\0'; if (strcmp(buf, "INF")) { throw Exception("Expected 'INF' but got '%s'", buf); } v = atof("inf"); } else if (ch == 'N') { uns->read(buf, 3); buf[3] = '\0'; if (strcmp(buf, "NAN")) { throw Exception("Expected 'NAN' but got '%s'", buf); } v = atof("nan"); } else { v = uns->readDouble(); } operator=(negative ? -v : v); } break; case 's': { String v; v.unserialize(uns); operator=(v); } break; case 'S': if (uns->getType() == VariableUnserializer::Type::APCSerialize) { union { char buf[8]; StringData *sd; } u; uns->read(u.buf, 8); operator=(u.sd); } else { throw Exception("Unknown type '%c'", type); } break; case 'a': { Array v = Array::Create(); v.unserialize(uns); operator=(v); return; // array has '}' terminating } break; case 'L': { int64_t id = uns->readInt(); sep = uns->readChar(); if (sep != ':') { throw Exception("Expected ':' but got '%c'", sep); } String rsrcName; rsrcName.unserialize(uns); sep = uns->readChar(); if (sep != '{') { throw Exception("Expected '{' but got '%c'", sep); } sep = uns->readChar(); if (sep != '}') { throw Exception("Expected '}' but got '%c'", sep); } DummyResource* rsrc = NEWOBJ(DummyResource); rsrc->o_setResourceId(id); rsrc->m_class_name = rsrcName; operator=(rsrc); return; // resource has '}' terminating } break; case 'O': case 'V': case 'K': { String clsName; clsName.unserialize(uns); sep = uns->readChar(); if (sep != ':') { throw Exception("Expected ':' but got '%c'", sep); } int64_t size = uns->readInt(); char sep = uns->readChar(); if (sep != ':') { throw Exception("Expected ':' but got '%c'", sep); } sep = uns->readChar(); if (sep != '{') { throw Exception("Expected '{' but got '%c'", sep); } const bool allowObjectFormatForCollections = true; Class* cls; // If we are potentially dealing with a collection, we need to try to // load the collection class under an alternate name so that we can // deserialize data that was serialized before the migration of // collections to the HH namespace. if (type != 'O') { // Collections are CPP builtins; don't attempt to autoload cls = Unit::getClass(clsName.get(), /* autoload */ false); if (!cls) { cls = tryAlternateCollectionClass(clsName.get()); } } else if (allowObjectFormatForCollections) { // In order to support the legacy {O|V}:{Set|Vector|Map} // serialization, we defer autoloading until we know that there's // no alternate (builtin) collection class. cls = Unit::getClass(clsName.get(), /* autoload */ false); if (!cls) { cls = tryAlternateCollectionClass(clsName.get()); } if (!cls) { cls = Unit::loadClass(clsName.get()); // with autoloading } } else { cls = Unit::loadClass(clsName.get()); // with autoloading } Object obj; if (RuntimeOption::UnserializationWhitelistCheck && (type == 'O') && !uns->isWhitelistedClass(clsName)) { const char* err_msg = "The object being unserialized with class name '%s' " "is not in the given whitelist. " "See http://fburl.com/SafeSerializable for more detail"; if (RuntimeOption::UnserializationWhitelistCheckWarningOnly) { raise_warning(err_msg, clsName.c_str()); } else { raise_error(err_msg, clsName.c_str()); } } if (cls) { // Only unserialize CPP extension types which can actually // support it. Otherwise, we risk creating a CPP object // without having it initialized completely. if (cls->instanceCtor() && !cls->isCppSerializable()) { assert(obj.isNull()); } else { obj = ObjectData::newInstance(cls); if (UNLIKELY(cls == c_Pair::classof() && size != 2)) { throw Exception("Pair objects must have exactly 2 elements"); } } } else { obj = ObjectData::newInstance( SystemLib::s___PHP_Incomplete_ClassClass); obj->o_set(s_PHP_Incomplete_Class_Name, clsName); } operator=(obj); if (size > 0) { if (type == 'O') { // Collections are not allowed if (obj->isCollection()) { if (size > 0) { throw Exception("%s does not support the 'O' serialization " "format", clsName.data()); } // Be lax and tolerate the 'O' serialization format for collection // classes if there are 0 properties. raise_warning("%s does not support the 'O' serialization " "format", clsName.data()); } /* Count backwards so that i is the number of properties remaining (to be used as an estimate for the total number of dynamic properties when we see the first dynamic prop). see getVariantPtr */ for (int64_t i = size; i--; ) { String key = uns->unserializeKey().toString(); int ksize = key.size(); const char *kdata = key.data(); int subLen = 0; if (kdata[0] == '\0') { if (UNLIKELY(!ksize)) { throw EmptyObjectPropertyException(); } // private or protected subLen = strlen(kdata + 1) + 2; if (UNLIKELY(subLen >= ksize)) { if (subLen == ksize) { throw EmptyObjectPropertyException(); } else { throw Exception("Mangled private object property"); } } String k(kdata + subLen, ksize - subLen, CopyString); Class* ctx = (Class*)-1; if (kdata[1] != '*') { ctx = Unit::lookupClass( String(kdata + 1, subLen - 2, CopyString).get()); } unserializeProp(uns, obj.get(), k, ctx, key, i + 1); } else { unserializeProp(uns, obj.get(), key, nullptr, key, i + 1); } } } else { assert(type == 'V' || type == 'K'); if (!obj->isCollection()) { throw Exception("%s is not a collection class", clsName.data()); } collectionUnserialize(obj.get(), uns, size, type); } } sep = uns->readChar(); if (sep != '}') { throw Exception("Expected '}' but got '%c'", sep); } obj->invokeWakeup(); return; // object has '}' terminating } break; case 'C': { String clsName; clsName.unserialize(uns); sep = uns->readChar(); if (sep != ':') { throw Exception("Expected ':' but got '%c'", sep); } String serialized; serialized.unserialize(uns, '{', '}'); Object obj; try { obj = create_object_only(clsName); } catch (ClassNotFoundException &e) { if (!uns->allowUnknownSerializableClass()) { throw; } obj = create_object_only(s_PHP_Incomplete_Class); obj->o_set(s_PHP_Incomplete_Class_Name, clsName); obj->o_set("serialized", serialized); } if (!obj->instanceof(SystemLib::s_SerializableClass)) { raise_warning("Class %s has no unserializer", obj->o_getClassName().data()); } else { obj->o_invoke_few_args(s_unserialize, 1, serialized); obj.get()->clearNoDestruct(); } operator=(obj); return; // object has '}' terminating } break; default: throw Exception("Unknown type '%c'", type); } sep = uns->readChar(); if (sep != ';') { throw Exception("Expected ';' but got '%c'", sep); } }