--- parser3/src/main/execute.C 2010/10/21 15:25:07 1.367 +++ parser3/src/main/execute.C 2016/09/29 18:49:43 1.385 @@ -1,12 +1,10 @@ /** @file Parser: executor part of request class. - Copyright (c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com) + Copyright (c) 2001-2015 Art. Lebedev Studio (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char * const IDENT_EXECUTE_C="$Date: 2010/10/21 15:25:07 $"; - #include "pa_opcode.h" #include "pa_array.h" #include "pa_request.h" @@ -23,6 +21,8 @@ static const char * const IDENT_EXECUTE_ #include "pa_vimage.h" #include "pa_wwrapper.h" +volatile const char * IDENT_EXECUTE_C="$Id: execute.C,v 1.385 2016/09/29 18:49:43 moko Exp $" IDENT_PA_OPCODE_H IDENT_PA_OPERATION_H IDENT_PA_VCODE_FRAME_H IDENT_PA_WWRAPPER_H; + //#define DEBUG_EXECUTE #ifdef DEBUG_EXECUTE @@ -60,6 +60,17 @@ char *opcode_name[]={ "WITH_SELF__VALUE__GET_ELEMENT", "WITH_SELF__VALUE__GET_ELEMENT__WRITE", #endif + +#ifdef FEATURE_GET_ELEMENT4CALL + "GET_ELEMENT4CALL", +#ifdef OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT + "GET_OBJECT_ELEMENT4CALL", +#endif +#ifdef OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT + "GET_OBJECT_VAR_ELEMENT4CALL", +#endif +#endif // FEATURE_GET_ELEMENT4CALL + "OBJECT_POOL", "STRING_POOL", "PREPARE_TO_CONSTRUCT_OBJECT", "CONSTRUCT_OBJECT", @@ -76,6 +87,10 @@ char *opcode_name[]={ "WITH_SELF__VALUE__CONSTRUCT_VALUE", #endif +#ifdef OPTIMIZE_BYTECODE_GET_ELEMENT__SPECIAL + "GET_ELEMENT__SPECIAL", + "GET_ELEMENT__SPECIAL__WRITE", +#endif // expression ops: unary "NEG", "INV", "NOT", "DEF", "IN", "FEXISTS", "DEXISTS", // expression ops: binary @@ -124,10 +139,16 @@ void debug_dump(SAPI_Info& sapi_info, in #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT || opcode==OP::OP_GET_OBJECT_ELEMENT || opcode==OP::OP_GET_OBJECT_ELEMENT__WRITE +#ifdef FEATURE_GET_ELEMENT4CALL + || opcode==OP::OP_GET_OBJECT_ELEMENT4CALL +#endif #endif #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT || opcode==OP::OP_GET_OBJECT_VAR_ELEMENT || opcode==OP::OP_GET_OBJECT_VAR_ELEMENT__WRITE +#ifdef FEATURE_GET_ELEMENT4CALL + || opcode==OP::OP_GET_OBJECT_VAR_ELEMENT4CALL +#endif #endif ){ i.next(); // skip origin @@ -164,6 +185,7 @@ void debug_dump(SAPI_Info& sapi_info, in opcode==OP::OP_VALUE || opcode==OP::OP_STRING__WRITE || opcode==OP::OP_VALUE__GET_CLASS + || opcode==OP::OP_VALUE__GET_BASE_CLASS #ifdef OPTIMIZE_BYTECODE_GET_ELEMENT || opcode==OP::OP_VALUE__GET_ELEMENT || opcode==OP::OP_VALUE__GET_ELEMENT__WRITE @@ -259,24 +281,67 @@ void Request::execute(ArrayOperation& op } case OP::OP_VALUE__GET_CLASS: { - // maybe they do ^class:method[] call, remember the fact - wcontext->set_somebody_entered_some_class(); + debug_origin=i.next().origin; + const String& name=*i.next().value->get_string(); debug_name=&name; + + DEBUG_PRINT_STRING(name) + + VStateless_class* vclass=get_class(name); + if(!vclass) + throw Exception(PARSER_RUNTIME, &name, "class is undefined"); + + stack.push(*vclass); + break; + } + + case OP::OP_VALUE__GET_BASE_CLASS: + { + // ^class:method[] call debug_origin=i.next().origin; - Value& value=*i.next().value; - const String& name=*value.get_string(); debug_name=&name; + const String& name=*i.next().value->get_string(); debug_name=&name; DEBUG_PRINT_STRING(name) - Value* class_value=get_class(name); - if(!class_value) - throw Exception(PARSER_RUNTIME, - &name, - "class is undefined"); + VStateless_class* vclass=get_class(name); + if(!vclass) + throw Exception(PARSER_RUNTIME, &name, "class is undefined"); - stack.push(*class_value); + stack.push(*new VBaseClassWrapper(*vclass, get_self())); break; } + +#ifdef OPTIMIZE_BYTECODE_GET_ELEMENT__SPECIAL + case OP::OP_GET_ELEMENT__SPECIAL: + case OP::OP_GET_ELEMENT__SPECIAL__WRITE: + { + const String& name=stack.pop().string(); debug_name=&name; + Value& ncontext=stack.pop().value(); + + Value* value=0; + if(VStateless_class* vclass=ncontext.get_class()){ + if(SYMBOLS_EQ(name,CLASS_SYMBOL)){ + value=vclass; + } else if(SYMBOLS_EQ(name,CLASS_NAME_SYMBOL)){ + value=new VString(*new String(vclass->type())); + } + } else { + // VJunction is without class, returning self + if(SYMBOLS_EQ(name,CLASS_SYMBOL)){ + value=&ncontext; + } else if(SYMBOLS_EQ(name,CLASS_NAME_SYMBOL)){ + value=new VString(*new String(ncontext.type())); + } + } + if(opcode==OP::OP_GET_ELEMENT__SPECIAL){ + stack.push(*value); + } else { + write_assign_lang(*value); + } + break; + } +#endif + // OP_WITH case OP::OP_WITH_ROOT: { @@ -296,9 +361,7 @@ void Request::execute(ArrayOperation& op case OP::OP_WITH_WRITE: { if(wcontext==method_frame) - throw Exception(PARSER_RUNTIME, - 0, - "$.name outside of $name[...]"); + throw Exception(PARSER_RUNTIME, 0, "$.name outside of $name[...]"); stack.push(*wcontext); break; @@ -397,11 +460,9 @@ void Request::execute(ArrayOperation& op const String& name=stack.pop().string(); debug_name=&name; Value& ncontext=stack.pop().value(); - if(const VJunction* vjunction=ncontext.put_element(name, &value, false)) + if(const VJunction* vjunction=ncontext.put_element(name, &value)) if(vjunction!=PUT_ELEMENT_REPLACED_ELEMENT) - throw Exception(PARSER_RUNTIME, - 0, - "property value can not be code, use [] or () brackets"); + throw Exception(PARSER_RUNTIME, 0, "property value can not be code, use [] or () brackets"); break; } @@ -476,59 +537,64 @@ void Request::execute(ArrayOperation& op #endif #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT - case OP::OP_GET_OBJECT_ELEMENT: - case OP::OP_GET_OBJECT_ELEMENT__WRITE: - { - debug_origin=i.next().origin; - const String& context_name=*i.next().value->get_string(); debug_name=&context_name; - - DEBUG_PRINT_STRING(context_name) - - Value& object=get_element(*rcontext, context_name); - debug_origin=i.next().origin; - const String& field_name=*i.next().value->get_string(); debug_name=&field_name; - - DEBUG_PRINT_STRING(field_name) +#define DO_GET_OBJECT_ELEMENT(code) {\ + debug_origin=i.next().origin; \ + const String& context_name=*i.next().value->get_string(); debug_name=&context_name; \ + DEBUG_PRINT_STRING(context_name) \ + Value& object=get_element(*rcontext, context_name); \ + debug_origin=i.next().origin; \ + const String& field_name=*i.next().value->get_string(); debug_name=&field_name; \ + DEBUG_PRINT_STRING(field_name) \ + code; \ + break; \ + } + case OP::OP_GET_OBJECT_ELEMENT: DO_GET_OBJECT_ELEMENT({ Value& value=get_element(object, field_name); - - if(opcode==OP::OP_GET_OBJECT_ELEMENT){ - stack.push(value); - } else { - write_assign_lang(value); - } - break; - } + stack.push(value); + }) + case OP::OP_GET_OBJECT_ELEMENT__WRITE: DO_GET_OBJECT_ELEMENT({ + Value& value=get_element(object, field_name); + write_assign_lang(value); + }) +#ifdef FEATURE_GET_ELEMENT4CALL + case OP::OP_GET_OBJECT_ELEMENT4CALL: DO_GET_OBJECT_ELEMENT({ + Value& value=get_element4call(object, field_name); + stack.push(value); + }) +#endif #endif #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT - case OP::OP_GET_OBJECT_VAR_ELEMENT: - case OP::OP_GET_OBJECT_VAR_ELEMENT__WRITE: - { - debug_origin=i.next().origin; - const String& context_name=*i.next().value->get_string(); debug_name=&context_name; - - DEBUG_PRINT_STRING(context_name) - Value& object=get_element(*rcontext, context_name); - - debug_origin=i.next().origin; - const String& var_name=*i.next().value->get_string(); debug_name=&var_name; - - DEBUG_PRINT_STRING(var_name) - - const String* field=&get_element(*rcontext, var_name).as_string(); +#define DO_GET_OBJECT_VAR_ELEMENT(code) {\ + debug_origin=i.next().origin; \ + const String& context_name=*i.next().value->get_string(); debug_name=&context_name; \ + DEBUG_PRINT_STRING(context_name) \ + Value& object=get_element(*rcontext, context_name); \ + debug_origin=i.next().origin; \ + const String& var_name=*i.next().value->get_string(); debug_name=&var_name; \ + DEBUG_PRINT_STRING(var_name) \ + const String* field=&get_element(*rcontext, var_name).as_string(); \ + code; \ + break; \ + } + case OP::OP_GET_OBJECT_VAR_ELEMENT: DO_GET_OBJECT_VAR_ELEMENT({ Value& value=get_element(object, *field); - - if(opcode==OP::OP_GET_OBJECT_VAR_ELEMENT){ - stack.push(value); - } else { - write_assign_lang(value); - } - break; - } + stack.push(value); + }) + case OP::OP_GET_OBJECT_VAR_ELEMENT__WRITE: DO_GET_OBJECT_VAR_ELEMENT({ + Value& value=get_element(object, *field); + write_assign_lang(value); + }) +#ifdef FEATURE_GET_ELEMENT4CALL + case OP::OP_GET_OBJECT_VAR_ELEMENT4CALL: DO_GET_OBJECT_VAR_ELEMENT({ + Value& value=get_element4call(object, *field); + stack.push(value); + }) +#endif #endif case OP::OP_GET_ELEMENT: @@ -540,6 +606,17 @@ void Request::execute(ArrayOperation& op break; } +#ifdef FEATURE_GET_ELEMENT4CALL + case OP::OP_GET_ELEMENT4CALL: + { + const String& name=stack.pop().string(); debug_name=&name; + Value& ncontext=stack.pop().value(); + Value& value=get_element4call(ncontext, name); + stack.push(value); + break; + } +#endif + case OP::OP_GET_ELEMENT__WRITE: { const String& name=stack.pop().string(); debug_name=&name; @@ -623,7 +700,7 @@ void Request::execute(ArrayOperation& op execute(local_ops); - stack.push(wcontext->result().as_value()); + stack.push(wcontext->result()); flang=saved_lang; wcontext=saved_wcontext; break; @@ -720,9 +797,14 @@ void Request::execute(ArrayOperation& op value.type()); } - VMethodFrame frame(*junction->method, method_frame, junction->self); - METHOD_FRAME_ACTION(op_call(frame)); - stack.push(frame.result().as_value()); + Value *result; + { + VMethodFrame frame(*junction->method, method_frame, junction->self); + METHOD_FRAME_ACTION(op_call(frame)); + result=&frame.result(); + // VMethodFrame desctructor deletes junctions in stack params here + } + stack.push(*result); DEBUG_PRINT_STR("<-returned") @@ -810,11 +892,9 @@ void Request::execute(ArrayOperation& op DEBUG_PRINT_STRING(class_name) - Value* class_value=get_class(class_name); - if(!class_value) - throw Exception(PARSER_RUNTIME, - &class_name, - "class is undefined"); + VStateless_class* vclass=get_class(class_name); + if(!vclass) + throw Exception(PARSER_RUNTIME, &class_name, "class is undefined"); debug_origin=i.next().origin; Value& vconstructor_name=*i.next().value; @@ -822,26 +902,28 @@ void Request::execute(ArrayOperation& op DEBUG_PRINT_STRING(constructor_name) - Junction* constructor_junction=get_element(*class_value, constructor_name).get_junction(); + Junction* constructor_junction=get_element(*vclass, constructor_name).get_junction(); if(!constructor_junction) - throw Exception(PARSER_RUNTIME, - &constructor_name, - "constructor must be declared in class '%s'", - class_value->get_class()->name_cstr()); + throw Exception(PARSER_RUNTIME, &constructor_name, "constructor must be declared in class '%s'", vclass->type()); ArrayOperation* local_ops=i.next().ops; DEBUG_PRINT_OPS(local_ops) DEBUG_PRINT_STR("->\n") - Value &object=construct(*class_value, *constructor_junction->method); - VConstructorFrame frame(*constructor_junction->method, method_frame, object); - METHOD_FRAME_ACTION(op_call(frame)); - object.enable_default_setter(); + Value *result; + { + Value& object=construct(*vclass, *constructor_junction->method); + VConstructorFrame frame(*constructor_junction->method, method_frame, object); + METHOD_FRAME_ACTION(op_call(frame)); + object.enable_default_setter(); + result=&frame.result(); + // VMethodFrame desctructor deletes junctions in stack params here + } if(opcode==OP::OP_CONSTRUCT_OBJECT) - stack.push(frame.result().as_value()); + stack.push(*result); else - write_pass_lang(frame.result()); + write_pass_lang(*result); DEBUG_PRINT_STR("<-returned") break; @@ -1179,8 +1261,7 @@ void Request::execute(ArrayOperation& op method_frame=saved_method_frame; -Value& Request::construct(Value &class_value, const Method &method){ - VStateless_class& called_class=*class_value.get_class(); +Value& Request::construct(VStateless_class &called_class, const Method &method){ if(method.call_type!=Method::CT_STATIC) { // this is a constructor call @@ -1191,7 +1272,7 @@ Value& Request::construct(Value &class_v throw Exception(PARSER_RUNTIME, 0, //&frame.name(), "is not a constructor, system class '%s' can be constructed only implicitly", - called_class.name().cstr()); + called_class.type()); } else throw Exception(PARSER_RUNTIME, 0, //&frame.name(), @@ -1253,22 +1334,20 @@ void Request::op_call_write(VMethodFrame } Value& Request::get_element(Value& ncontext, const String& name) { - if(wcontext->get_somebody_entered_some_class()) // ^class:method - if(VStateless_class *called_class=ncontext.get_class()) - if(VStateless_class *read_class=rcontext->get_class()) - if(read_class->derived_from(*called_class)){ // current derived from called - Value *value=called_class->get_element(get_self(), name); - return *(value ? &process_to_value(*value) : VVoid::get()); - } - Value* value=ncontext.get_element(name); + return *(value ? &process_to_value(*value) : VVoid::get()); +} +#ifdef FEATURE_GET_ELEMENT4CALL +Value& Request::get_element4call(Value& ncontext, const String& name) { + Value* value=ncontext.get_element4call(name); return *(value ? &process_to_value(*value) : VVoid::get()); } +#endif void Request::put_element(Value& ncontext, const String& name, Value* value) { // put_element can return property-setting-junction - if(const VJunction* vjunction=ncontext.put_element(name, value, false)) + if(const VJunction* vjunction=ncontext.put_element(name, value)) if(vjunction!=PUT_ELEMENT_REPLACED_ELEMENT) { const Junction& junction = vjunction->junction(); VConstructorFrame frame(*junction.method, method_frame /*caller*/, junction.self); @@ -1300,7 +1379,7 @@ void Request::put_element(Value& ncontex } } -StringOrValue Request::process_getter(Junction& junction) { +Value& Request::process_getter(Junction& junction) { VMethodFrame frame(*junction.method, method_frame/*caller*/, junction.self); size_t param_count=frame.method_params_count(); @@ -1345,16 +1424,16 @@ StringOrValue Request::process_getter(Ju using the fact it's either string_ or value_ result requested to speed up checkes */ -StringOrValue Request::process(Value& input_value, bool intercept_string) { +Value& Request::process(Value& input_value, bool intercept_string) { Junction* junction=input_value.get_junction(); if(junction) { if(junction->is_getter) { // is it a getter-junction? - return process_getter(*junction); + return process(process_getter(*junction), intercept_string); } if(junction->code) { // is it a code-junction? // process it - StringOrValue result; + ValueRef result; DEBUG_PRINT_STR("ja->\n") @@ -1411,10 +1490,8 @@ StringOrValue Request::process(Value& in void Request::process_write(Value& input_value) { Junction* junction=input_value.get_junction(); if(junction) { - if(junction->is_getter) { // is it a getter-junction? - write_pass_lang(process_getter(*junction)); - return; - } + // no getter-junction check as process_write is called + // to process method arguments, not from get_element if(junction->code) { // is it a code-junction? // process it @@ -1554,6 +1631,7 @@ const String* Request::get_method_filena case OP::OP_VALUE: case OP::OP_STRING__WRITE: case OP::OP_VALUE__GET_CLASS: + case OP::OP_VALUE__GET_BASE_CLASS: #ifdef OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT case OP::OP_GET_OBJECT_ELEMENT: case OP::OP_GET_OBJECT_ELEMENT__WRITE: @@ -1572,6 +1650,17 @@ const String* Request::get_method_filena case OP::OP_WITH_SELF__VALUE__GET_ELEMENT: case OP::OP_WITH_SELF__VALUE__GET_ELEMENT__WRITE: #endif + +#ifdef FEATURE_GET_ELEMENT4CALL + case OP::OP_GET_ELEMENT4CALL: +#ifdef OPTIMIZE_BYTECODE_GET_OBJECT_ELEMENT + case OP::OP_GET_OBJECT_ELEMENT4CALL: +#endif +#ifdef OPTIMIZE_BYTECODE_GET_OBJECT_VAR_ELEMENT + case OP::OP_GET_OBJECT_VAR_ELEMENT4CALL: +#endif +#endif // FEATURE_GET_ELEMENT4CALL + #ifdef OPTIMIZE_BYTECODE_CONSTRUCT case OP::OP_WITH_ROOT__VALUE__CONSTRUCT_EXPR: case OP::OP_WITH_ROOT__VALUE__CONSTRUCT_VALUE: @@ -1584,6 +1673,7 @@ const String* Request::get_method_filena origin=i.next().origin; break; } + default: break; } if(origin.file_no) return get_used_filename(origin.file_no);