@@ -113,6 +113,50 @@ DUK_EXTERNAL void duk_concat(duk_context *ctx, duk_idx_t count) {
113113 duk__concat_and_join_helper (ctx , count , 0 /*is_join*/ );
114114}
115115
116+ #if defined(DUK_USE_PREFER_SIZE )
117+ DUK_INTERNAL void duk_concat_2 (duk_context * ctx ) {
118+ duk_concat (ctx , 2 );
119+ }
120+ #else /* DUK_USE_PREFER_SIZE */
121+ DUK_INTERNAL void duk_concat_2 (duk_context * ctx ) {
122+ duk_hthread * thr = (duk_hthread * ) ctx ;
123+ duk_hstring * h1 ;
124+ duk_hstring * h2 ;
125+ duk_uint8_t * buf ;
126+ duk_size_t len1 ;
127+ duk_size_t len2 ;
128+ duk_size_t len ;
129+
130+ DUK_ASSERT_CTX_VALID (ctx );
131+ DUK_ASSERT (duk_get_top (ctx ) >= 2 ); /* Trusted caller. */
132+
133+ h1 = duk_to_hstring (ctx , -2 );
134+ h2 = duk_to_hstring (ctx , -1 );
135+ len1 = (duk_size_t ) DUK_HSTRING_GET_BYTELEN (h1 );
136+ len2 = (duk_size_t ) DUK_HSTRING_GET_BYTELEN (h2 );
137+ len = len1 + len2 ;
138+ if (DUK_UNLIKELY (len < len1 || /* wrapped */
139+ len > (duk_size_t ) DUK_HSTRING_MAX_BYTELEN )) {
140+ goto error_overflow ;
141+ }
142+ buf = (duk_uint8_t * ) duk_push_fixed_buffer_nozero (ctx , len );
143+ DUK_ASSERT (buf != NULL );
144+
145+ DUK_MEMCPY ((void * ) buf , (const void * ) DUK_HSTRING_GET_DATA (h1 ), (size_t ) len1 );
146+ DUK_MEMCPY ((void * ) (buf + len1 ), (const void * ) DUK_HSTRING_GET_DATA (h2 ), (size_t ) len2 );
147+ (void ) duk_buffer_to_string (ctx , -1 ); /* Safe if inputs are safe. */
148+
149+ /* [ ... str1 str2 buf ] */
150+
151+ duk_replace (ctx , -3 );
152+ duk_pop_unsafe (ctx );
153+ return ;
154+
155+ error_overflow :
156+ DUK_ERROR_RANGE (thr , DUK_STR_RESULT_TOO_LONG );
157+ }
158+ #endif /* DUK_USE_PREFER_SIZE */
159+
116160DUK_EXTERNAL void duk_join (duk_context * ctx , duk_idx_t count ) {
117161 DUK_ASSERT_CTX_VALID (ctx );
118162
0 commit comments