浏览代码

Use computed goto to dispatch next opcode

On compulers that define __GNUC__ use computed goto to directly dispatch
the next instruction rather than going through another switch statement.
This saves a jump and some comparisons.

In tight loops this is is roughly 10% faster than the switch() method.
Hein-Pieter van Braam 8 年之前
父节点
当前提交
520d84e042
共有 1 个文件被更改,包括 183 次插入109 次删除
  1. 183 109
      modules/gdscript/gd_function.cpp

+ 183 - 109
modules/gdscript/gd_function.cpp

@@ -161,8 +161,71 @@ static String _get_var_type(const Variant *p_type) {
 	return basestr;
 }
 
+#if defined(__GNUC__) && !defined(__clang__)
+#define OPCODES_TABLE                         \
+	static const void *switch_table_ops[] = { \
+		&&OPCODE_OPERATOR,                    \
+		&&OPCODE_EXTENDS_TEST,                \
+		&&OPCODE_SET,                         \
+		&&OPCODE_GET,                         \
+		&&OPCODE_SET_NAMED,                   \
+		&&OPCODE_GET_NAMED,                   \
+		&&OPCODE_SET_MEMBER,                  \
+		&&OPCODE_GET_MEMBER,                  \
+		&&OPCODE_ASSIGN,                      \
+		&&OPCODE_ASSIGN_TRUE,                 \
+		&&OPCODE_ASSIGN_FALSE,                \
+		&&OPCODE_CONSTRUCT,                   \
+		&&OPCODE_CONSTRUCT_ARRAY,             \
+		&&OPCODE_CONSTRUCT_DICTIONARY,        \
+		&&OPCODE_CALL,                        \
+		&&OPCODE_CALL_RETURN,                 \
+		&&OPCODE_CALL_BUILT_IN,               \
+		&&OPCODE_CALL_SELF,                   \
+		&&OPCODE_CALL_SELF_BASE,              \
+		&&OPCODE_YIELD,                       \
+		&&OPCODE_YIELD_SIGNAL,                \
+		&&OPCODE_YIELD_RESUME,                \
+		&&OPCODE_JUMP,                        \
+		&&OPCODE_JUMP_IF,                     \
+		&&OPCODE_JUMP_IF_NOT,                 \
+		&&OPCODE_JUMP_TO_DEF_ARGUMENT,        \
+		&&OPCODE_RETURN,                      \
+		&&OPCODE_ITERATE_BEGIN,               \
+		&&OPCODE_ITERATE,                     \
+		&&OPCODE_ASSERT,                      \
+		&&OPCODE_BREAKPOINT,                  \
+		&&OPCODE_LINE,                        \
+		&&OPCODE_END                          \
+	};
+
+#define OPCODE(m_op) \
+	m_op:
+#define OPCODE_WHILE(m_test)
+#define OPCODES_END \
+	OPSEXIT:
+#define OPCODES_OUT \
+	OPSOUT:
+#define DISPATCH_OPCODE goto *switch_table_ops[_code_ptr[ip]]
+#define OPCODE_SWITCH(m_test) DISPATCH_OPCODE;
+#define OPCODE_BREAK goto OPSEXIT
+#define OPCODE_OUT goto OPSOUT
+#else
+#define OPCODES_TABLE
+#define OPCODE(m_op) case m_op:
+#define OPCODE_WHILE(m_test) while (m_test)
+#define OPCODES_END
+#define OPCODES_OUT
+#define DISPATCH_OPCODE continue
+#define OPCODE_SWITCH(m_test) switch (m_test)
+#define OPCODE_BREAK break
+#define OPCODE_OUT break
+#endif
+
 Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_argcount, Variant::CallError &r_err, CallState *p_state) {
 
+	OPCODES_TABLE;
+
 	if (!_code_ptr) {
 
 		return Variant();
@@ -271,16 +334,23 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 	if (ScriptDebugger::get_singleton())
 		GDScriptLanguage::get_singleton()->enter_function(p_instance, this, stack, &ip, &line);
 
-#define GD_ERR_BREAK(m_cond) ERR_BREAK(m_cond)
+#define GD_ERR_BREAK(m_cond)                                                                                           \
+	{                                                                                                                  \
+		if (unlikely(m_cond)) {                                                                                        \
+			_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Breaking..:"); \
+			OPCODE_BREAK;                                                                                              \
+		} else                                                                                                         \
+			_err_error_exists = false;                                                                                 \
+	}
 
 #define CHECK_SPACE(m_space) \
-	ERR_BREAK((ip + m_space) > _code_size)
+	GD_ERR_BREAK((ip + m_space) > _code_size)
 
 #define GET_VARIANT_PTR(m_v, m_code_ofs)                                                       \
 	Variant *m_v;                                                                              \
 	m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, _class, self, stack, err_text); \
 	if (unlikely(!m_v))                                                                        \
-		break;
+		OPCODE_BREAK;
 
 #else
 #define GD_ERR_BREAK(m_cond)
@@ -306,15 +376,15 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 	bool exit_ok = false;
 
 #ifdef DEBUG_ENABLED
-	while (ip < _code_size) {
+	OPCODE_WHILE(ip < _code_size) {
 		int last_opcode = _code_ptr[ip];
 #else
-	while (true) {
+	OPCODE_WHILE(true) {
 #endif
 
-		switch (_code_ptr[ip]) {
+		OPCODE_SWITCH(_code_ptr[ip]) {
 
-			case OPCODE_OPERATOR: {
+			OPCODE(OPCODE_OPERATOR) {
 
 				CHECK_SPACE(5);
 
@@ -343,14 +413,14 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 					} else {
 						err_text = "Invalid operands '" + Variant::get_type_name(a->get_type()) + "' and '" + Variant::get_type_name(b->get_type()) + "' in operator '" + Variant::get_operator_name(op) + "'.";
 					}
-					break;
+					OPCODE_BREAK;
 				}
 				*dst = ret;
 #endif
 				ip += 5;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_EXTENDS_TEST: {
+			OPCODE(OPCODE_EXTENDS_TEST) {
 
 				CHECK_SPACE(4);
 
@@ -362,12 +432,12 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 				if (a->get_type() != Variant::OBJECT || a->operator Object *() == NULL) {
 
 					err_text = "Left operand of 'is' is not an instance of anything.";
-					break;
+					OPCODE_BREAK;
 				}
 				if (b->get_type() != Variant::OBJECT || b->operator Object *() == NULL) {
 
 					err_text = "Right operand of 'is' is not a class.";
-					break;
+					OPCODE_BREAK;
 				}
 #endif
 				Object *obj_A = *a;
@@ -390,7 +460,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 							if (cmp == scr_B) {
 								//inherits from script, all ok
 								extends_ok = true;
-								break;
+								OPCODE_BREAK;
 							}
 
 							cmp = cmp->_base;
@@ -405,7 +475,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 					if (!nc) {
 
 						err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "').";
-						break;
+						OPCODE_BREAK;
 					}
 #endif
 					extends_ok = ClassDB::is_parent_class(obj_A->get_class_name(), nc->get_name());
@@ -413,9 +483,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 
 				*dst = extends_ok;
 				ip += 4;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_SET: {
+			OPCODE(OPCODE_SET) {
 
 				CHECK_SPACE(3);
 
@@ -435,13 +505,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 						v = "of type '" + _get_var_type(index) + "'";
 					}
 					err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "').";
-					break;
+					OPCODE_BREAK;
 				}
 #endif
 				ip += 4;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_GET: {
+			OPCODE(OPCODE_GET) {
 
 				CHECK_SPACE(3);
 
@@ -466,14 +536,14 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 						v = "of type '" + _get_var_type(index) + "'";
 					}
 					err_text = "Invalid get index " + v + " (on base: '" + _get_var_type(src) + "').";
-					break;
+					OPCODE_BREAK;
 				}
 				*dst = ret;
 #endif
 				ip += 4;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_SET_NAMED: {
+			OPCODE(OPCODE_SET_NAMED) {
 
 				CHECK_SPACE(3);
 
@@ -492,13 +562,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 				if (!valid) {
 					String err_type;
 					err_text = "Invalid set index '" + String(*index) + "' (on base: '" + _get_var_type(dst) + "').";
-					break;
+					OPCODE_BREAK;
 				}
 #endif
 				ip += 4;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_GET_NAMED: {
+			OPCODE(OPCODE_GET_NAMED) {
 
 				CHECK_SPACE(4);
 
@@ -525,14 +595,14 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 					} else {
 						err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "').";
 					}
-					break;
+					OPCODE_BREAK;
 				}
 				*dst = ret;
 #endif
 				ip += 4;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_SET_MEMBER: {
+			OPCODE(OPCODE_SET_MEMBER) {
 
 				CHECK_SPACE(3);
 				int indexname = _code_ptr[ip + 1];
@@ -545,16 +615,16 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 #ifdef DEBUG_ENABLED
 				if (!ok) {
 					err_text = "Internal error setting property: " + String(*index);
-					break;
+					OPCODE_BREAK;
 				} else if (!valid) {
 					err_text = "Error setting property '" + String(*index) + "' with value of type " + Variant::get_type_name(src->get_type()) + ".";
-					break;
+					OPCODE_BREAK;
 				}
 #endif
 				ip += 3;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_GET_MEMBER: {
+			OPCODE(OPCODE_GET_MEMBER) {
 
 				CHECK_SPACE(3);
 				int indexname = _code_ptr[ip + 1];
@@ -566,13 +636,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 #ifdef DEBUG_ENABLED
 				if (!ok) {
 					err_text = "Internal error getting property: " + String(*index);
-					break;
+					OPCODE_BREAK;
 				}
 #endif
 				ip += 3;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_ASSIGN: {
+			OPCODE(OPCODE_ASSIGN) {
 
 				CHECK_SPACE(3);
 				GET_VARIANT_PTR(dst, 1);
@@ -581,9 +651,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 				*dst = *src;
 
 				ip += 3;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_ASSIGN_TRUE: {
+			OPCODE(OPCODE_ASSIGN_TRUE) {
 
 				CHECK_SPACE(2);
 				GET_VARIANT_PTR(dst, 1);
@@ -591,9 +661,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 				*dst = true;
 
 				ip += 2;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_ASSIGN_FALSE: {
+			OPCODE(OPCODE_ASSIGN_FALSE) {
 
 				CHECK_SPACE(2);
 				GET_VARIANT_PTR(dst, 1);
@@ -601,9 +671,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 				*dst = false;
 
 				ip += 2;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_CONSTRUCT: {
+			OPCODE(OPCODE_CONSTRUCT) {
 
 				CHECK_SPACE(2);
 				Variant::Type t = Variant::Type(_code_ptr[ip + 1]);
@@ -623,15 +693,15 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 				if (err.error != Variant::CallError::CALL_OK) {
 
 					err_text = _get_call_error(err, "'" + Variant::get_type_name(t) + "' constructor", (const Variant **)argptrs);
-					break;
+					OPCODE_BREAK;
 				}
 #endif
 
 				ip += 4 + argc;
 				//construct a basic type
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_CONSTRUCT_ARRAY: {
+			OPCODE(OPCODE_CONSTRUCT_ARRAY) {
 
 				CHECK_SPACE(1);
 				int argc = _code_ptr[ip + 1];
@@ -649,9 +719,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 				*dst = array;
 
 				ip += 3 + argc;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_CONSTRUCT_DICTIONARY: {
+			OPCODE(OPCODE_CONSTRUCT_DICTIONARY) {
 
 				CHECK_SPACE(1);
 				int argc = _code_ptr[ip + 1];
@@ -671,10 +741,10 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 				*dst = dict;
 
 				ip += 3 + argc * 2;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_CALL_RETURN:
-			case OPCODE_CALL: {
+			OPCODE(OPCODE_CALL_RETURN)
+			OPCODE(OPCODE_CALL) {
 
 				CHECK_SPACE(4);
 				bool call_ret = _code_ptr[ip] == OPCODE_CALL_RETURN;
@@ -736,24 +806,24 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 
 							if (base->is_ref()) {
 								err_text = "Attempted to free a reference.";
-								break;
+								OPCODE_BREAK;
 							} else if (base->get_type() == Variant::OBJECT) {
 
 								err_text = "Attempted to free a locked object (calling or emitting).";
-								break;
+								OPCODE_BREAK;
 							}
 						}
 					}
 					err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs);
-					break;
+					OPCODE_BREAK;
 				}
 #endif
 
 				//_call_func(NULL,base,*methodname,ip,argc,p_instance,stack);
 				ip += argc + 1;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_CALL_BUILT_IN: {
+			OPCODE(OPCODE_CALL_BUILT_IN) {
 
 				CHECK_SPACE(4);
 
@@ -786,17 +856,17 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 					} else {
 						err_text = _get_call_error(err, "built-in function '" + methodstr + "'", (const Variant **)argptrs);
 					}
-					break;
+					OPCODE_BREAK;
 				}
 #endif
 				ip += argc + 1;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_CALL_SELF: {
+			OPCODE(OPCODE_CALL_SELF) {
 
-				break;
+				OPCODE_BREAK;
 			}
-			case OPCODE_CALL_SELF_BASE: {
+			OPCODE(OPCODE_CALL_SELF_BASE) {
 
 				CHECK_SPACE(2);
 				int self_fun = _code_ptr[ip + 1];
@@ -805,7 +875,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 				if (self_fun < 0 || self_fun >= _global_names_count) {
 
 					err_text = "compiler bug, function name not found";
-					break;
+					OPCODE_BREAK;
 				}
 #endif
 				const StringName *methodname = &_global_names_ptr[self_fun];
@@ -830,7 +900,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 					gds = gds->base.ptr();
 					E = gds->member_functions.find(*methodname);
 					if (E)
-						break;
+						OPCODE_BREAK;
 				}
 
 				Variant::CallError err;
@@ -865,14 +935,14 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 					String methodstr = *methodname;
 					err_text = _get_call_error(err, "function '" + methodstr + "'", (const Variant **)argptrs);
 
-					break;
+					OPCODE_BREAK;
 				}
 
 				ip += 4 + argc;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_YIELD:
-			case OPCODE_YIELD_SIGNAL: {
+			OPCODE(OPCODE_YIELD)
+			OPCODE(OPCODE_YIELD_SIGNAL) {
 
 				int ipofs = 1;
 				if (_code_ptr[ip] == OPCODE_YIELD_SIGNAL) {
@@ -913,11 +983,11 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 #ifdef DEBUG_ENABLED
 					if (argobj->get_type() != Variant::OBJECT) {
 						err_text = "First argument of yield() not of type object.";
-						break;
+						OPCODE_BREAK;
 					}
 					if (argname->get_type() != Variant::STRING) {
 						err_text = "Second argument of yield() not a string (for signal name).";
-						break;
+						OPCODE_BREAK;
 					}
 #endif
 					Object *obj = argobj->operator Object *();
@@ -926,18 +996,18 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 
 					if (!obj) {
 						err_text = "First argument of yield() is null.";
-						break;
+						OPCODE_BREAK;
 					}
 					if (ScriptDebugger::get_singleton()) {
 						if (!ObjectDB::instance_validate(obj)) {
 							err_text = "First argument of yield() is a previously freed instance.";
-							break;
+							OPCODE_BREAK;
 						}
 					}
 					if (signal.length() == 0) {
 
 						err_text = "Second argument of yield() is an empty string (for signal name).";
-						break;
+						OPCODE_BREAK;
 					}
 
 #endif
@@ -945,38 +1015,38 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 #ifdef DEBUG_ENABLED
 					if (err != OK) {
 						err_text = "Error connecting to signal: " + signal + " during yield().";
-						break;
+						OPCODE_BREAK;
 					}
 #endif
 				}
 
 				exit_ok = true;
-				break;
+				OPCODE_BREAK;
 			}
-			case OPCODE_YIELD_RESUME: {
+			OPCODE(OPCODE_YIELD_RESUME) {
 
 				CHECK_SPACE(2);
 #ifdef DEBUG_ENABLED
 				if (!p_state) {
 					err_text = ("Invalid Resume (bug?)");
-					break;
+					OPCODE_BREAK;
 				}
 #endif
 				GET_VARIANT_PTR(result, 1);
 				*result = p_state->result;
 				ip += 2;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_JUMP: {
+			OPCODE(OPCODE_JUMP) {
 
 				CHECK_SPACE(2);
 				int to = _code_ptr[ip + 1];
 
 				GD_ERR_BREAK(to < 0 || to > _code_size);
 				ip = to;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_JUMP_IF: {
+			OPCODE(OPCODE_JUMP_IF) {
 
 				CHECK_SPACE(3);
 
@@ -988,12 +1058,12 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 					int to = _code_ptr[ip + 2];
 					GD_ERR_BREAK(to < 0 || to > _code_size);
 					ip = to;
-					continue;
+					DISPATCH_OPCODE;
 				}
 				ip += 3;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_JUMP_IF_NOT: {
+			OPCODE(OPCODE_JUMP_IF_NOT) {
 
 				CHECK_SPACE(3);
 
@@ -1005,26 +1075,26 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 					int to = _code_ptr[ip + 2];
 					GD_ERR_BREAK(to < 0 || to > _code_size);
 					ip = to;
-					continue;
+					DISPATCH_OPCODE;
 				}
 				ip += 3;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_JUMP_TO_DEF_ARGUMENT: {
+			OPCODE(OPCODE_JUMP_TO_DEF_ARGUMENT) {
 
 				CHECK_SPACE(2);
 				ip = _default_arg_ptr[defarg];
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_RETURN: {
+			OPCODE(OPCODE_RETURN) {
 
 				CHECK_SPACE(2);
 				GET_VARIANT_PTR(r, 1);
 				retvalue = *r;
 				exit_ok = true;
-				break;
+				OPCODE_BREAK;
 			}
-			case OPCODE_ITERATE_BEGIN: {
+			OPCODE(OPCODE_ITERATE_BEGIN) {
 
 				CHECK_SPACE(8); //space for this a regular iterate
 
@@ -1036,13 +1106,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 #ifdef DEBUG_ENABLED
 					if (!valid) {
 						err_text = "Unable to iterate on object of type  " + Variant::get_type_name(container->get_type()) + "'.";
-						break;
+						OPCODE_BREAK;
 					}
 #endif
 					int jumpto = _code_ptr[ip + 3];
 					GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
 					ip = jumpto;
-					continue;
+					DISPATCH_OPCODE;
 				}
 				GET_VARIANT_PTR(iterator, 4);
 
@@ -1050,13 +1120,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 #ifdef DEBUG_ENABLED
 				if (!valid) {
 					err_text = "Unable to obtain iterator object of type  " + Variant::get_type_name(container->get_type()) + "'.";
-					break;
+					OPCODE_BREAK;
 				}
 #endif
 				ip += 5; //skip regular iterate which is always next
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_ITERATE: {
+			OPCODE(OPCODE_ITERATE) {
 
 				CHECK_SPACE(4);
 
@@ -1068,13 +1138,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 #ifdef DEBUG_ENABLED
 					if (!valid) {
 						err_text = "Unable to iterate on object of type  " + Variant::get_type_name(container->get_type()) + "' (type changed since first iteration?).";
-						break;
+						OPCODE_BREAK;
 					}
 #endif
 					int jumpto = _code_ptr[ip + 3];
 					GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
 					ip = jumpto;
-					continue;
+					DISPATCH_OPCODE;
 				}
 				GET_VARIANT_PTR(iterator, 4);
 
@@ -1082,13 +1152,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 #ifdef DEBUG_ENABLED
 				if (!valid) {
 					err_text = "Unable to obtain iterator object of type  " + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
-					break;
+					OPCODE_BREAK;
 				}
 #endif
 				ip += 5; //loop again
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_ASSERT: {
+			OPCODE(OPCODE_ASSERT) {
 				CHECK_SPACE(2);
 				GET_VARIANT_PTR(test, 1);
 
@@ -1098,23 +1168,23 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 				if (!result) {
 
 					err_text = "Assertion failed.";
-					break;
+					OPCODE_BREAK;
 				}
 
 #endif
 				ip += 2;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_BREAKPOINT: {
+			OPCODE(OPCODE_BREAKPOINT) {
 #ifdef DEBUG_ENABLED
 				if (ScriptDebugger::get_singleton()) {
 					GDScriptLanguage::get_singleton()->debug_break("Breakpoint Statement", true);
 				}
 #endif
 				ip += 1;
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_LINE: {
+			OPCODE(OPCODE_LINE) {
 				CHECK_SPACE(2);
 
 				line = _code_ptr[ip + 1];
@@ -1141,23 +1211,26 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 
 					ScriptDebugger::get_singleton()->line_poll();
 				}
-				continue;
+				DISPATCH_OPCODE;
 			}
-			case OPCODE_END: {
+			OPCODE(OPCODE_END) {
 
 				exit_ok = true;
-				break;
+				OPCODE_BREAK;
 			}
+#if 0
 			default: {
 
 				err_text = "Illegal opcode " + itos(_code_ptr[ip]) + " at address " + itos(ip);
-				break;
+				OPCODE_BREAK;
 			}
+#endif
 		}
 
+		OPCODES_END
 #ifdef DEBUG_ENABLED
 		if (exit_ok)
-			break;
+			OPCODE_OUT;
 		//error
 		// function, file, line, error, explanation
 		String err_file;
@@ -1182,9 +1255,10 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 		}
 
 #endif
-		break;
+		OPCODE_OUT;
 	}
 
+	OPCODES_OUT
 #ifdef DEBUG_ENABLED
 	if (GDScriptLanguage::get_singleton()->profiling) {
 		uint64_t time_taken = OS::get_singleton()->get_ticks_usec() - function_start_time;