@@ -125,7 +125,7 @@ DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) {
125125 return DUK_EXEC_ERROR ; /* unreachable */
126126 }
127127
128- /* awkward; we assume there is space for this */
128+ /* Rely on the internal value stack reserve for these operations. */
129129 duk_push_undefined (ctx );
130130 duk_insert (ctx , idx_func + 1 );
131131
@@ -230,205 +230,21 @@ DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function fu
230230}
231231
232232DUK_EXTERNAL void duk_new (duk_context * ctx , duk_idx_t nargs ) {
233- /*
234- * There are two [[Construct]] operations in the specification:
235- *
236- * - E5 Section 13.2.2: for Function objects
237- * - E5 Section 15.3.4.5.2: for "bound" Function objects
238- *
239- * The chain of bound functions is resolved in Section 15.3.4.5.2,
240- * with arguments "piling up" until the [[Construct]] internal
241- * method is called on the final, actual Function object. Note
242- * that the "prototype" property is looked up *only* from the
243- * final object, *before* calling the constructor.
244- *
245- * Since Duktape 2.2 bound functions are represented with the
246- * duk_hboundfunc internal type, and bound function chains are
247- * collapsed when a bound function is created. As a result, the
248- * direct target of a duk_hboundfunc is always non-bound and the
249- * this/argument lists have been resolved.
250- *
251- * When constructing new Array instances, an unnecessary object is
252- * created and discarded now: the standard [[Construct]] creates an
253- * object, and calls the Array constructor. The Array constructor
254- * returns an Array instance, which is used as the result value for
255- * the "new" operation; the object created before the Array constructor
256- * call is discarded.
257- *
258- * This would be easy to fix, e.g. by knowing that the Array constructor
259- * will always create a replacement object and skip creating the fallback
260- * object in that case.
261- *
262- * Note: functions called via "new" need to know they are called as a
263- * constructor. For instance, built-in constructors behave differently
264- * depending on how they are called.
265- */
266-
267- /* XXX: merge this with duk_js_call.c, as this function implements
268- * core semantics (or perhaps merge the two files altogether).
269- */
270-
271233 duk_hthread * thr = (duk_hthread * ) ctx ;
272- duk_hobject * proto ;
273- duk_hobject * cons ;
274- duk_hobject * fallback ;
275- duk_idx_t idx_cons ;
276- duk_small_uint_t call_flags ;
234+ duk_idx_t idx_func ;
277235
278236 DUK_ASSERT_CTX_VALID (ctx );
279237
280- /* [... constructor arg1 ... argN] */
281-
282- idx_cons = duk_require_normalize_index (ctx , - nargs - 1 );
283-
284- DUK_DDD (DUK_DDDPRINT ("top=%ld, nargs=%ld, idx_cons=%ld" ,
285- (long ) duk_get_top (ctx ), (long ) nargs , (long ) idx_cons ));
286-
287- /* XXX: code duplication */
288-
289- /*
290- * Figure out the final, non-bound constructor, to get "prototype"
291- * property.
292- */
293-
294- duk_dup (ctx , idx_cons );
295- duk_resolve_nonbound_function (ctx );
296- duk_require_callable (ctx , -1 );
297- cons = duk_get_hobject (ctx , -1 );
298-
299- /* Result is a lightfunc or a callable actual function. */
300- DUK_ASSERT (cons == NULL || DUK_HOBJECT_IS_CALLABLE (cons ));
301- if (cons != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE (cons )) {
302- /* Check constructability from the final, non-bound object.
303- * The constructable flag is 1:1 for the bound function and
304- * its target so this should be sufficient. Lightfuncs are
305- * always constructable.
306- */
307- goto not_constructable ;
308- }
309-
310- DUK_ASSERT (duk_is_callable (ctx , -1 ));
311- DUK_ASSERT (duk_is_lightfunc (ctx , -1 ) ||
312- (duk_get_hobject (ctx , -1 ) != NULL && !DUK_HOBJECT_HAS_BOUNDFUNC (duk_get_hobject (ctx , -1 ))));
313-
314- /* [... constructor arg1 ... argN final_cons] */
315-
316- /*
317- * Create "fallback" object to be used as the object instance,
318- * unless the constructor returns a replacement value.
319- * Its internal prototype needs to be set based on "prototype"
320- * property of the constructor.
321- */
322-
323- duk_push_object (ctx ); /* class Object, extensible */
324-
325- /* [... constructor arg1 ... argN final_cons fallback] */
326-
327- duk_get_prop_stridx_short (ctx , -2 , DUK_STRIDX_PROTOTYPE );
328- proto = duk_get_hobject (ctx , -1 );
329- if (!proto ) {
330- DUK_DDD (DUK_DDDPRINT ("constructor has no 'prototype' property, or value not an object "
331- "-> leave standard Object prototype as fallback prototype" ));
332- } else {
333- DUK_DDD (DUK_DDDPRINT ("constructor has 'prototype' property with object value "
334- "-> set fallback prototype to that value: %!iO" , (duk_heaphdr * ) proto ));
335- fallback = duk_known_hobject (ctx , -2 );
336- DUK_ASSERT (fallback != NULL );
337- DUK_HOBJECT_SET_PROTOTYPE_UPDREF (thr , fallback , proto );
338- }
339- duk_pop (ctx );
340-
341- #if 0 /* XXX: smaller alternative */
342- if (duk_is_object (ctx , -1 )) {
343- DUK_DDD (DUK_DDDPRINT ("constructor has 'prototype' property with object value "
344- "-> set fallback prototype to that value: %!iT" , duk_get_tval (ctx , -1 )));
345- duk_set_prototype (ctx , -2 );
346- } else {
347- DUK_DDD (DUK_DDDPRINT ("constructor has no 'prototype' property, or value not an object "
348- "-> leave standard Object prototype as fallback prototype" ));
349- duk_pop (ctx );
350- }
351- #endif
352-
353- /* [... constructor arg1 ... argN final_cons fallback] */
354-
355- /*
356- * Manipulate value stack for the call.
357- */
358-
359- duk_dup_top (ctx );
360- duk_insert (ctx , idx_cons + 1 ); /* use fallback as 'this' value */
361- duk_insert (ctx , idx_cons ); /* also stash it before constructor,
362- * in case we need it (as the fallback value)
363- */
364- duk_pop (ctx ); /* pop final_cons */
365-
366-
367- /* [... fallback constructor fallback(this) arg1 ... argN];
368- * Note: idx_cons points to first 'fallback', not 'constructor'.
369- */
370-
371- DUK_DDD (DUK_DDDPRINT ("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, "
372- "nargs=%ld, top=%ld" ,
373- (duk_tval * ) duk_get_tval (ctx , idx_cons + 1 ),
374- (duk_tval * ) duk_get_tval (ctx , idx_cons + 2 ),
375- (long ) nargs ,
376- (long ) duk_get_top (ctx )));
377-
378- /*
379- * Call the constructor function (called in "constructor mode").
380- */
381-
382- call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL ; /* not protected, respect reclimit, is a constructor call */
383-
384- duk_handle_call_unprotected (thr , /* thread */
385- nargs , /* num_stack_args */
386- call_flags ); /* call_flags */
387-
388- /* [... fallback retval] */
389-
390- DUK_DDD (DUK_DDDPRINT ("constructor call finished, fallback=%!iT, retval=%!iT" ,
391- (duk_tval * ) duk_get_tval (ctx , -2 ),
392- (duk_tval * ) duk_get_tval (ctx , -1 )));
393-
394- /*
395- * Determine whether to use the constructor return value as the created
396- * object instance or not.
397- */
398-
399- if (duk_check_type_mask (ctx , -1 , DUK_TYPE_MASK_OBJECT |
400- DUK_TYPE_MASK_BUFFER |
401- DUK_TYPE_MASK_LIGHTFUNC )) {
402- duk_remove_m2 (ctx );
403- } else {
404- duk_pop (ctx );
238+ idx_func = duk_get_top (ctx ) - nargs - 1 ;
239+ if (idx_func < 0 || nargs < 0 ) {
240+ /* note that we can't reliably pop anything here */
241+ DUK_ERROR_TYPE_INVALID_ARGS (thr );
405242 }
406243
407- /*
408- * Augment created errors upon creation (not when they are thrown or
409- * rethrown). __FILE__ and __LINE__ are not desirable here; the call
410- * stack reflects the caller which is correct.
411- */
412-
413- #if defined(DUK_USE_AUGMENT_ERROR_CREATE )
414- duk_hthread_sync_currpc (thr );
415- duk_err_augment_error_create (thr , thr , NULL , 0 , 1 /*noblame_fileline*/ );
416- #endif
417-
418- /* [... retval] */
419-
420- return ;
244+ duk_push_object (ctx ); /* default instance; internal proto updated by call handling */
245+ duk_insert (ctx , idx_func + 1 );
421246
422- not_constructable :
423- #if defined(DUK_USE_VERBOSE_ERRORS )
424- #if defined(DUK_USE_PARANOID_ERRORS )
425- DUK_ERROR_FMT1 (thr , DUK_ERR_TYPE_ERROR , "%s not constructable" , duk_get_type_name (ctx , -1 ));
426- #else
427- DUK_ERROR_FMT1 (thr , DUK_ERR_TYPE_ERROR , "%s not constructable" , duk_push_string_readable (ctx , -1 ));
428- #endif
429- #else
430- DUK_ERROR_TYPE (thr , "not constructable" );
431- #endif
247+ duk_handle_call_unprotected ((duk_hthread * ) ctx , nargs , DUK_CALL_FLAG_CONSTRUCTOR_CALL );
432248}
433249
434250DUK_LOCAL duk_ret_t duk__pnew_helper (duk_context * ctx , void * udata ) {
@@ -447,11 +263,8 @@ DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) {
447263 DUK_ASSERT_CTX_VALID (ctx );
448264
449265 /* For now, just use duk_safe_call() to wrap duk_new(). We can't
450- * simply use a protected duk_handle_call() because there's post
451- * processing which might throw. It should be possible to ensure
452- * the post processing never throws (except in internal errors and
453- * out of memory etc which are always allowed) and then remove this
454- * wrapper.
266+ * simply use a protected duk_handle_call() because pushing the
267+ * default instance might throw.
455268 */
456269
457270 rc = duk_safe_call (ctx , duk__pnew_helper , (void * ) & nargs /*udata*/ , nargs + 1 /*nargs*/ , 1 /*nrets*/ );
0 commit comments