@@ -529,6 +529,140 @@ ecma_builtin_array_prototype_object_index_of (ecma_value_t this_arg, /**< this a
529529 return ret_value;
530530} /* ecma_builtin_array_prototype_object_index_of */
531531
532+ /* *
533+ * The Array.prototype object's 'lastIndexOf' routine
534+ *
535+ * See also:
536+ * ECMA-262 v5, 15.4.4.15
537+ *
538+ * @return completion value
539+ * Returned value must be freed with ecma_free_completion_value.
540+ */
541+ static ecma_completion_value_t
542+ ecma_builtin_array_prototype_object_last_index_of (ecma_value_t this_arg, /* *< this argument */
543+ ecma_value_t arg1, /* *< searchElement */
544+ ecma_value_t arg2) /* *< fromIndex */
545+ {
546+ ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
547+
548+ /* 1. */
549+ ECMA_TRY_CATCH (obj_this,
550+ ecma_op_to_object (this_arg),
551+ ret_value);
552+
553+ ecma_object_t *obj_p = ecma_get_object_from_value (obj_this);
554+ ecma_string_t *magic_string_length_p = ecma_get_magic_string (ECMA_MAGIC_STRING_LENGTH);
555+
556+ /* 2. */
557+ ECMA_TRY_CATCH (len_value,
558+ ecma_op_object_get (obj_p, magic_string_length_p),
559+ ret_value);
560+
561+ ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value);
562+
563+ /* 3. */
564+ uint32_t len = ecma_number_to_uint32 (len_number);
565+
566+ ecma_number_t * num_p = ecma_alloc_number ();
567+ *num_p = ecma_int32_to_number (-1 );
568+
569+ /* 4. */
570+ if (len == 0 )
571+ {
572+ ret_value = ecma_make_normal_completion_value (ecma_make_number_value (num_p));
573+ }
574+ else
575+ {
576+ uint32_t k = len - 1 ;
577+
578+ /* 5. */
579+ if (!ecma_is_value_undefined (arg2))
580+ {
581+ ECMA_OP_TO_NUMBER_TRY_CATCH (arg_from_idx, arg2, ret_value);
582+ int32_t n = ecma_number_to_int32 (arg_from_idx);
583+
584+ /* 6. */
585+ if (n >= 0 )
586+ {
587+ /* min(n, len - 1)*/
588+ if ((uint32_t ) n > len - 1 )
589+ {
590+ k = len - 1 ;
591+ }
592+ else
593+ {
594+ k = (uint32_t ) n;
595+ }
596+ }
597+ /* 7. */
598+ else
599+ {
600+ n = -n;
601+
602+ /* We prevent k from being negative, so that we can use an uint32 */
603+ if ((uint32_t ) n <= len)
604+ {
605+ k = len - (uint32_t ) n;
606+ }
607+ else
608+ {
609+ /*
610+ * If k would be negative, we set it to UINT_MAX. See reasoning for this in the comment
611+ * at the for loop below.
612+ */
613+ k = (uint32_t ) -1 ;
614+ }
615+ }
616+
617+ ECMA_OP_TO_NUMBER_FINALIZE (arg_from_idx);
618+ }
619+
620+ /* 8.
621+ * We should break from the loop when k < 0. We can still use an uint32_t for k, and check
622+ * for an underflow instead. This is safe, because k will always start in [0, len - 1],
623+ * and len is in [0, UINT_MAX], so k >= len means we've had an underflow, and should stop.
624+ */
625+ for (;k < len && *num_p < 0 && ecma_is_completion_value_empty (ret_value); k--)
626+ {
627+ /* 8.a */
628+ ecma_string_t *idx_str_p = ecma_new_ecma_string_from_uint32 (k);
629+
630+ /* 8.a */
631+ if (ecma_op_object_get_property (obj_p, idx_str_p) != NULL )
632+ {
633+ /* 8.b.i */
634+ ECMA_TRY_CATCH (get_value, ecma_op_object_get (obj_p, idx_str_p), ret_value);
635+
636+ /* 8.b.ii */
637+ if (ecma_op_strict_equality_compare (arg1, get_value))
638+ {
639+ *num_p = ecma_uint32_to_number (k);
640+ }
641+
642+ ECMA_FINALIZE (get_value);
643+ }
644+
645+ ecma_deref_ecma_string (idx_str_p);
646+ }
647+
648+ if (ecma_is_completion_value_empty (ret_value))
649+ {
650+ ret_value = ecma_make_normal_completion_value (ecma_make_number_value (num_p));
651+ }
652+ else
653+ {
654+ ecma_dealloc_number (num_p);
655+ }
656+ }
657+
658+ ECMA_OP_TO_NUMBER_FINALIZE (len_number);
659+ ECMA_FINALIZE (len_value);
660+ ecma_deref_ecma_string (magic_string_length_p);
661+ ECMA_FINALIZE (obj_this);
662+
663+ return ret_value;
664+ } /* ecma_builtin_array_prototype_object_last_index_of */
665+
532666/* *
533667 * The Array.prototype object's 'shift' routine
534668 *
0 commit comments