Optimize put result phase in the interpreter.

Skip put result phase for opcodes which put their
result onto the stack or they don't have result at all.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2016-06-10 00:26:59 -07:00
parent eed84a7dd9
commit 495b24eebc
+207 -149
View File
@@ -846,7 +846,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
case VM_OC_NONE: case VM_OC_NONE:
{ {
JERRY_ASSERT (opcode == CBC_EXT_DEBUGGER); JERRY_ASSERT (opcode == CBC_EXT_DEBUGGER);
break; continue;
} }
case VM_OC_POP: case VM_OC_POP:
{ {
@@ -856,59 +856,59 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
} }
case VM_OC_POP_BLOCK: case VM_OC_POP_BLOCK:
{ {
result = *(--stack_top_p); ecma_fast_free_value (block_result);
break; block_result = *(--stack_top_p);
continue;
} }
case VM_OC_PUSH: case VM_OC_PUSH:
{ {
*(stack_top_p++) = left_value; *stack_top_p++ = left_value;
continue; continue;
} }
case VM_OC_PUSH_TWO: case VM_OC_PUSH_TWO:
{ {
*(stack_top_p++) = left_value; *stack_top_p++ = left_value;
*(stack_top_p++) = right_value; *stack_top_p++ = right_value;
continue; continue;
} }
case VM_OC_PUSH_THREE: case VM_OC_PUSH_THREE:
{ {
uint16_t literal_index; uint16_t literal_index;
*(stack_top_p++) = left_value; *stack_top_p++ = left_value;
left_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); left_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
READ_LITERAL_INDEX (literal_index); READ_LITERAL_INDEX (literal_index);
READ_LITERAL (literal_index, left_value); READ_LITERAL (literal_index, left_value);
*(stack_top_p++) = right_value; *stack_top_p++ = right_value;
*(stack_top_p++) = left_value; *stack_top_p++ = left_value;
continue; continue;
} }
case VM_OC_PUSH_UNDEFINED: case VM_OC_PUSH_UNDEFINED:
case VM_OC_VOID:
{ {
result = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); *stack_top_p++ = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
break; continue;
} }
case VM_OC_PUSH_TRUE: case VM_OC_PUSH_TRUE:
{ {
result = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); *stack_top_p++ = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE);
break; continue;
} }
case VM_OC_PUSH_FALSE: case VM_OC_PUSH_FALSE:
{ {
result = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); *stack_top_p++ = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE);
break; continue;
} }
case VM_OC_PUSH_NULL: case VM_OC_PUSH_NULL:
{ {
result = ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL); *stack_top_p++ = ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL);
break; continue;
} }
case VM_OC_PUSH_THIS: case VM_OC_PUSH_THIS:
{ {
result = ecma_copy_value (frame_ctx_p->this_binding); *stack_top_p++ = ecma_copy_value (frame_ctx_p->this_binding);
break; continue;
} }
case VM_OC_PUSH_NUMBER_0: case VM_OC_PUSH_NUMBER_0:
{ {
@@ -933,9 +933,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
ecma_object_t *obj_p = ecma_create_object (prototype_p, ecma_object_t *obj_p = ecma_create_object (prototype_p,
true, true,
ECMA_OBJECT_TYPE_GENERAL); ECMA_OBJECT_TYPE_GENERAL);
result = ecma_make_object_value (obj_p);
ecma_deref_object (prototype_p); ecma_deref_object (prototype_p);
break; *stack_top_p++ = ecma_make_object_value (obj_p);
continue;
} }
case VM_OC_SET_PROPERTY: case VM_OC_SET_PROPERTY:
{ {
@@ -946,7 +946,6 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
if (ecma_is_value_string (right_value)) if (ecma_is_value_string (right_value))
{ {
prop_name_p = ecma_get_string_from_value (right_value); prop_name_p = ecma_get_string_from_value (right_value);
property_p = ecma_find_named_property (object_p, prop_name_p);
} }
else else
{ {
@@ -958,9 +957,10 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
} }
prop_name_p = ecma_get_string_from_value (result); prop_name_p = ecma_get_string_from_value (result);
property_p = ecma_find_named_property (object_p, prop_name_p);
} }
property_p = ecma_find_named_property (object_p, prop_name_p);
if (property_p != NULL && ECMA_PROPERTY_GET_TYPE (property_p) != ECMA_PROPERTY_TYPE_NAMEDDATA) if (property_p != NULL && ECMA_PROPERTY_GET_TYPE (property_p) != ECMA_PROPERTY_TYPE_NAMEDDATA)
{ {
ecma_delete_property (object_p, property_p); ecma_delete_property (object_p, property_p);
@@ -980,7 +980,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
ecma_deref_ecma_string (prop_name_p); ecma_deref_ecma_string (prop_name_p);
} }
break;
goto free_both_values;
} }
case VM_OC_SET_GETTER: case VM_OC_SET_GETTER:
case VM_OC_SET_SETTER: case VM_OC_SET_SETTER:
@@ -989,7 +990,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
stack_top_p[-1], stack_top_p[-1],
left_value, left_value,
right_value); right_value);
break;
goto free_both_values;
} }
case VM_OC_PUSH_ARRAY: case VM_OC_PUSH_ARRAY:
{ {
@@ -999,12 +1001,14 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
continue;
} }
case VM_OC_PUSH_ELISON: case VM_OC_PUSH_ELISON:
{ {
result = ecma_make_simple_value (ECMA_SIMPLE_VALUE_ARRAY_HOLE); *stack_top_p++ = ecma_make_simple_value (ECMA_SIMPLE_VALUE_ARRAY_HOLE);
break; continue;
} }
case VM_OC_APPEND_ARRAY: case VM_OC_APPEND_ARRAY:
{ {
@@ -1056,13 +1060,14 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
ecma_value_assign_uint32 (&ECMA_PROPERTY_VALUE_PTR (length_prop_p)->value, ecma_value_assign_uint32 (&ECMA_PROPERTY_VALUE_PTR (length_prop_p)->value,
length_num); length_num);
break; continue;
} }
case VM_OC_PUSH_UNDEFINED_BASE: case VM_OC_PUSH_UNDEFINED_BASE:
{ {
result = stack_top_p[-1]; stack_top_p[0] = stack_top_p[-1];
stack_top_p[-1] = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); stack_top_p[-1] = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
break; stack_top_p++;
continue;
} }
case VM_OC_IDENT_REFERENCE: case VM_OC_IDENT_REFERENCE:
{ {
@@ -1076,7 +1081,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
*stack_top_p++ = ecma_make_simple_value (ECMA_SIMPLE_VALUE_REGISTER_REF); *stack_top_p++ = ecma_make_simple_value (ECMA_SIMPLE_VALUE_REGISTER_REF);
*stack_top_p++ = literal_index; *stack_top_p++ = literal_index;
result = ecma_copy_value (frame_ctx_p->registers_p[literal_index]); *stack_top_p++ = ecma_copy_value (frame_ctx_p->registers_p[literal_index]);
} }
else else
{ {
@@ -1106,8 +1111,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
ecma_ref_object (ref_base_lex_env_p); ecma_ref_object (ref_base_lex_env_p);
*stack_top_p++ = ecma_make_object_value (ref_base_lex_env_p); *stack_top_p++ = ecma_make_object_value (ref_base_lex_env_p);
*stack_top_p++ = ecma_make_string_value (name_p); *stack_top_p++ = ecma_make_string_value (name_p);
*stack_top_p++ = result;
} }
break; continue;
} }
case VM_OC_PROP_REFERENCE: case VM_OC_PROP_REFERENCE:
{ {
@@ -1380,12 +1386,19 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
goto error; goto error;
} }
if (VM_OC_HAS_PUT_RESULT (opcode_data)) if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
{ {
break; ecma_fast_free_value (result);
}
else if (opcode_data & VM_OC_PUT_STACK)
{
*stack_top_p++ = result;
}
else
{
ecma_fast_free_value (block_result);
block_result = result;
} }
ecma_fast_free_value (result);
continue; continue;
} }
case VM_OC_NEW: case VM_OC_NEW:
@@ -1414,8 +1427,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
goto error; goto error;
} }
JERRY_ASSERT (VM_OC_HAS_PUT_RESULT (opcode_data)); *stack_top_p++ = result;
break; continue;
} }
case VM_OC_PROP_DELETE: case VM_OC_PROP_DELETE:
{ {
@@ -1425,7 +1438,11 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
JERRY_ASSERT (ecma_is_value_boolean (result));
*stack_top_p++ = result;
goto free_both_values;
} }
case VM_OC_DELETE: case VM_OC_DELETE:
{ {
@@ -1435,8 +1452,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
if (literal_index < register_end) if (literal_index < register_end)
{ {
result = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); *stack_top_p++ = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE);
break; continue;
} }
result = vm_op_delete_var (literal_start_p[literal_index], result = vm_op_delete_var (literal_start_p[literal_index],
@@ -1447,7 +1464,11 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
JERRY_ASSERT (ecma_is_value_boolean (result));
*stack_top_p++ = result;
continue;
} }
case VM_OC_JUMP: case VM_OC_JUMP:
{ {
@@ -1505,7 +1526,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_left_value;
} }
case VM_OC_MINUS: case VM_OC_MINUS:
{ {
@@ -1515,7 +1538,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_left_value;
} }
case VM_OC_NOT: case VM_OC_NOT:
{ {
@@ -1525,7 +1550,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_left_value;
} }
case VM_OC_BIT_NOT: case VM_OC_BIT_NOT:
{ {
@@ -1537,7 +1564,14 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_left_value;
}
case VM_OC_VOID:
{
*stack_top_p++ = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
goto free_left_value;
} }
case VM_OC_TYPEOF_IDENT: case VM_OC_TYPEOF_IDENT:
{ {
@@ -1559,16 +1593,15 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
if (ref_base_lex_env_p == NULL) if (ref_base_lex_env_p == NULL)
{ {
ecma_deref_ecma_string (name_p); result = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
ecma_string_t *string_p = ecma_get_magic_string (LIT_MAGIC_STRING_UNDEFINED);
result = ecma_make_string_value (string_p);
break;
} }
else
{
result = ecma_op_get_value_lex_env_base (ref_base_lex_env_p,
name_p,
is_strict);
result = ecma_op_get_value_lex_env_base (ref_base_lex_env_p, }
name_p,
is_strict);
ecma_deref_ecma_string (name_p); ecma_deref_ecma_string (name_p);
@@ -1589,7 +1622,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_left_value;
} }
case VM_OC_ADD: case VM_OC_ADD:
{ {
@@ -1657,7 +1692,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_both_values;
} }
case VM_OC_NOT_EQUAL: case VM_OC_NOT_EQUAL:
{ {
@@ -1667,7 +1704,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_both_values;
} }
case VM_OC_STRICT_EQUAL: case VM_OC_STRICT_EQUAL:
{ {
@@ -1675,7 +1714,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
result = ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE result = ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE
: ECMA_SIMPLE_VALUE_FALSE); : ECMA_SIMPLE_VALUE_FALSE);
break;
*stack_top_p++ = result;
goto free_both_values;
} }
case VM_OC_STRICT_NOT_EQUAL: case VM_OC_STRICT_NOT_EQUAL:
{ {
@@ -1683,7 +1724,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
result = ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE result = ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE
: ECMA_SIMPLE_VALUE_TRUE); : ECMA_SIMPLE_VALUE_TRUE);
break;
*stack_top_p++ = result;
goto free_both_values;
} }
case VM_OC_BIT_OR: case VM_OC_BIT_OR:
{ {
@@ -1765,7 +1808,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_both_values;
} }
case VM_OC_GREATER: case VM_OC_GREATER:
{ {
@@ -1775,7 +1820,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_both_values;
} }
case VM_OC_LESS_EQUAL: case VM_OC_LESS_EQUAL:
{ {
@@ -1785,7 +1832,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_both_values;
} }
case VM_OC_GREATER_EQUAL: case VM_OC_GREATER_EQUAL:
{ {
@@ -1795,7 +1844,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_both_values;
} }
case VM_OC_IN: case VM_OC_IN:
{ {
@@ -1805,7 +1856,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_both_values;
} }
case VM_OC_INSTANCEOF: case VM_OC_INSTANCEOF:
{ {
@@ -1815,7 +1868,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{ {
goto error; goto error;
} }
break;
*stack_top_p++ = result;
goto free_both_values;
} }
case VM_OC_WITH: case VM_OC_WITH:
{ {
@@ -1891,7 +1946,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
context_top_p[-2] = chunk_p->next_chunk_cp; context_top_p[-2] = chunk_p->next_chunk_cp;
ecma_dealloc_collection_chunk (chunk_p); ecma_dealloc_collection_chunk (chunk_p);
break;
*stack_top_p++ = result;
continue;
} }
case VM_OC_FOR_IN_HAS_NEXT: case VM_OC_FOR_IN_HAS_NEXT:
{ {
@@ -2024,7 +2081,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
} }
JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p);
break; continue;
} }
case VM_OC_JUMP_AND_EXIT_CONTEXT: case VM_OC_JUMP_AND_EXIT_CONTEXT:
{ {
@@ -2052,111 +2109,112 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
default: default:
{ {
JERRY_UNREACHABLE (); JERRY_UNREACHABLE ();
break; continue;
} }
} }
if (VM_OC_HAS_PUT_RESULT (opcode_data)) JERRY_ASSERT (VM_OC_HAS_PUT_RESULT (opcode_data));
if (opcode_data & VM_OC_PUT_IDENT)
{ {
if (opcode_data & VM_OC_PUT_IDENT) uint16_t literal_index;
READ_LITERAL_INDEX (literal_index);
if (literal_index < register_end)
{ {
uint16_t literal_index; ecma_fast_free_value (frame_ctx_p->registers_p[literal_index]);
READ_LITERAL_INDEX (literal_index); frame_ctx_p->registers_p[literal_index] = result;
if (literal_index < register_end) if (opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK))
{ {
ecma_fast_free_value (frame_ctx_p->registers_p[literal_index]); result = ecma_fast_copy_value (result);
frame_ctx_p->registers_p[literal_index] = result;
if (opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK))
{
result = ecma_fast_copy_value (result);
}
}
else
{
ecma_string_t *var_name_str_p;
ecma_object_t *ref_base_lex_env_p;
var_name_str_p = ecma_new_ecma_string_from_lit_cp (literal_start_p[literal_index]);
ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p,
var_name_str_p);
ecma_value_t put_value_result = ecma_op_put_value_lex_env_base (ref_base_lex_env_p,
var_name_str_p,
is_strict,
result);
ecma_deref_ecma_string (var_name_str_p);
if (ecma_is_value_error (put_value_result))
{
ecma_free_value (result);
result = put_value_result;
goto error;
}
if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
{
ecma_fast_free_value (result);
}
} }
} }
else if (opcode_data & VM_OC_PUT_REFERENCE) else
{ {
ecma_value_t property = *(--stack_top_p); ecma_string_t *var_name_str_p;
ecma_value_t object = *(--stack_top_p); ecma_object_t *ref_base_lex_env_p;
if (object == ecma_make_simple_value (ECMA_SIMPLE_VALUE_REGISTER_REF)) var_name_str_p = ecma_new_ecma_string_from_lit_cp (literal_start_p[literal_index]);
ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p,
var_name_str_p);
ecma_value_t put_value_result = ecma_op_put_value_lex_env_base (ref_base_lex_env_p,
var_name_str_p,
is_strict,
result);
ecma_deref_ecma_string (var_name_str_p);
if (ecma_is_value_error (put_value_result))
{ {
ecma_fast_free_value (frame_ctx_p->registers_p[property]); ecma_free_value (result);
result = put_value_result;
frame_ctx_p->registers_p[property] = result; goto error;
if (opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK))
{
result = ecma_fast_copy_value (result);
}
} }
else
if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
{ {
ecma_value_t set_value_result = vm_op_set_value (object, ecma_fast_free_value (result);
property,
result,
is_strict);
ecma_free_value (object);
ecma_free_value (property);
if (ecma_is_value_error (set_value_result))
{
ecma_free_value (result);
result = set_value_result;
goto error;
}
if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
{
ecma_fast_free_value (result);
}
} }
} }
}
else if (opcode_data & VM_OC_PUT_REFERENCE)
{
ecma_value_t property = *(--stack_top_p);
ecma_value_t object = *(--stack_top_p);
if (opcode_data & VM_OC_PUT_STACK) if (object == ecma_make_simple_value (ECMA_SIMPLE_VALUE_REGISTER_REF))
{ {
*stack_top_p++ = result; ecma_fast_free_value (frame_ctx_p->registers_p[property]);
frame_ctx_p->registers_p[property] = result;
if (opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK))
{
result = ecma_fast_copy_value (result);
}
} }
else if (opcode_data & VM_OC_PUT_BLOCK) else
{ {
ecma_fast_free_value (block_result); ecma_value_t set_value_result = vm_op_set_value (object,
block_result = result; property,
result,
is_strict);
ecma_free_value (object);
ecma_free_value (property);
if (ecma_is_value_error (set_value_result))
{
ecma_free_value (result);
result = set_value_result;
goto error;
}
if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
{
ecma_fast_free_value (result);
}
} }
} }
ecma_fast_free_value (left_value); if (opcode_data & VM_OC_PUT_STACK)
{
*stack_top_p++ = result;
}
else if (opcode_data & VM_OC_PUT_BLOCK)
{
ecma_fast_free_value (block_result);
block_result = result;
}
free_both_values:
ecma_fast_free_value (right_value); ecma_fast_free_value (right_value);
free_left_value:
ecma_fast_free_value (left_value);
} }
error: error: